This commit is contained in:
2026-08-14 14:27:03 +08:00
parent 724848feb6
commit a81af4a664
64 changed files with 961 additions and 176 deletions
+26 -4
View File
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Bell, FileText, LogOut, Mail, Menu } from '@lucide/vue'
@@ -20,12 +20,22 @@ const auth = useAuthStore()
const access = useAccessPreviewStore()
const unsaved = useUnsavedWorkStore()
const workspace = useWorkspaceTabsStore()
const mobileViewportQuery = '(max-width: 720px)'
const collapsed = ref(false)
const mobileMenuOpen = ref(false)
const isMobileViewport = ref(false)
let mobileViewportMedia: MediaQueryList | undefined
const pageTitle = computed(() => route.meta.title || '管理后台')
const pageDescription = computed(() => route.meta.description || '')
const showPageHeading = computed(() => route.meta.showPageHeading !== false)
const menuCollapsed = computed(() => collapsed.value && !mobileMenuOpen.value)
const menuButtonLabel = computed(() => {
if (isMobileViewport.value) return mobileMenuOpen.value ? '关闭菜单' : '打开菜单'
return collapsed.value ? '展开导航' : '收起导航'
})
const menuExpanded = computed(() => (
isMobileViewport.value ? mobileMenuOpen.value : !collapsed.value
))
const canOpenNotificationManagement = computed(() => (
access.can('platform:notification:task:list')
|| access.can('platform:notification:template:list')
@@ -89,15 +99,27 @@ async function handleLogout() {
}
function handleMenuToggle() {
if (window.matchMedia('(max-width: 720px)').matches) {
if (isMobileViewport.value) {
mobileMenuOpen.value = !mobileMenuOpen.value
return
}
collapsed.value = !collapsed.value
}
function syncMobileViewport(event: MediaQueryList | MediaQueryListEvent) {
isMobileViewport.value = event.matches
if (!event.matches) mobileMenuOpen.value = false
}
function openNotificationPage(path: string) { void router.push(path) }
onMounted(() => {
mobileViewportMedia = window.matchMedia(mobileViewportQuery)
syncMobileViewport(mobileViewportMedia)
mobileViewportMedia.addEventListener('change', syncMobileViewport)
})
onBeforeUnmount(() => mobileViewportMedia?.removeEventListener('change', syncMobileViewport))
watch(() => route.fullPath, () => {
mobileMenuOpen.value = false
syncCurrentRoute()
@@ -129,8 +151,8 @@ watch(() => auth.user?.id || auth.user?.account || '', (userId, previousUserId)
<button
class="shell-menu-button"
type="button"
:aria-label="mobileMenuOpen ? '关闭菜单' : collapsed ? '展开导航' : '收起导航'"
:aria-expanded="mobileMenuOpen || !collapsed"
:aria-label="menuButtonLabel"
:aria-expanded="menuExpanded"
@click="handleMenuToggle"
><Menu :size="22" /></button>
<div v-if="showPageHeading" class="page-heading"><h1>{{ pageTitle }}</h1><p v-if="pageDescription">{{ pageDescription }}</p></div>