| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 |
- <template>
- <div :class="['web-app', layoutClass]">
- <template v-if="isAppLayout">
- <div class="app-shell">
- <TopNavBar @logout="onLogout" />
- <div :class="['app-body', { 'no-sidebar': !hasSidebar }]">
- <SideNav />
- <main class="content">
- <router-view />
- </main>
- </div>
- </div>
- </template>
- <router-view v-else />
- <ToastHost />
- </div>
- </template>
- <script setup>
- import { computed, watch } from 'vue'
- import { useRoute, useRouter } from 'vue-router'
- import { useAuth } from '@/store/auth'
- import { useMenu } from '@/store/menu'
- import { useSyncDocumentTitle } from '@/composables/useSyncDocumentTitle'
- import TopNavBar from '@/components/TopNavBar.vue'
- import SideNav from '@/components/SideNav.vue'
- import ToastHost from '@/components/common/ToastHost.vue'
- const route = useRoute()
- const router = useRouter()
- const { logout } = useAuth()
- const { state: menuState, sidebarDepth, reset: resetMenu, syncActiveFromPath } = useMenu()
- // 跟随路由同步浏览器 title
- useSyncDocumentTitle()
- // meta.layout: 'blank' => 全屏独立布局(登录页);其他 => 带侧边栏的业务布局
- const isAppLayout = computed(() => route.meta?.layout !== 'blank')
- const layoutClass = computed(() => (isAppLayout.value ? 'layout-app' : 'layout-blank'))
- // 仅当菜单存在最后一层时显示侧边栏(深度 = 1 时不显示)
- const hasSidebar = computed(() => sidebarDepth.value > 0)
- // 路由变化时,把一级菜单的 active 状态切到当前路径所属的菜单组
- watch(
- () => route.path,
- (path) => {
- if (menuState.loaded) syncActiveFromPath(path)
- },
- { immediate: true },
- )
- function onLogout() {
- resetMenu()
- logout()
- router.replace('/login')
- }
- </script>
|