Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | 1x 1x 1x 1x 1x 1x 14x 14x 14x 6x 6x 8x 8x 1x 7x 7x 7x 7x 1x 1x 12x | import { createRouter, createWebHistory } from 'vue-router'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import DefaultLayout from '@/layouts/DefaultLayout.vue'
import { useAuthStore } from '@/stores/auth'
import { usePermissionStore } from '@/stores/permissions'
NProgress.configure({ showSpinner: false })
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/login',
name: 'login',
component: () => import('@/views/login/index.vue'),
meta: { title: '登录' },
},
{
path: '/',
component: DefaultLayout,
redirect: '/dashboard',
meta: { requiresAuth: true },
children: [
{
path: '/dashboard',
name: 'dashboard',
component: () => import('@/views/dashboard/index.vue'),
meta: { title: '工作台', componentName: 'Dashboard' },
},
// 测试页:用于演练 Tabs 导航(无需权限,纯布局验证)
{
path: '/test/list',
name: 'test-list',
component: () => import('@/views/test/TestPage.vue'),
meta: { title: '测试-列表', componentName: 'TestPage' },
},
{
path: '/test/form',
name: 'test-form',
component: () => import('@/views/test/TestPage.vue'),
meta: { title: '测试-表单', componentName: 'TestPage' },
},
{
path: '/test/detail',
name: 'test-detail',
component: () => import('@/views/test/TestPage.vue'),
meta: { title: '测试-详情', componentName: 'TestPage' },
},
{
path: '/test/chart',
name: 'test-chart',
component: () => import('@/views/test/TestPage.vue'),
meta: { title: '测试-图表', componentName: 'TestPage' },
},
{
path: '/test/table',
name: 'test-table',
component: () => import('@/views/test/TestPage.vue'),
meta: { title: '测试-表格', componentName: 'TestPage' },
},
{
path: '/test/settings',
name: 'test-settings',
component: () => import('@/views/test/TestPage.vue'),
meta: { title: '测试-设置', componentName: 'TestPage' },
},
// 组件库演练场:纳入业务布局(带侧栏 / 顶栏 / Tabs)
{
path: '/demo',
name: 'demo',
component: () => import('@/views/demo/index.vue'),
meta: { title: '组件库', componentName: 'Demo' },
},
// 详情页:同一组件按参数复用,但每个 fullPath 独立缓存、关闭即销毁
// (per-param 的命名组件由 DefaultLayout 的 getPageWrapper 按路由动态生成)
{
path: '/detail/:id',
name: 'detail',
component: () => import('@/views/detail/DetailPage.vue'),
meta: { title: '详情', cacheByKey: true },
},
// 业务页面后续在此追加,配置 meta.moduleId 后自动走权限校验
],
},
{
path: '/:pathMatch(.*)*',
redirect: '/dashboard',
},
],
})
// 登录守卫:未登录访问受保护页跳 /login?redirect=xxx;已登录访问 /login 跳 /dashboard
// 权限守卫:路由配置 meta.moduleId 时校验访问权限,无权限跳 /dashboard
router.beforeEach(async (to) => {
NProgress.start()
const authStore = useAuthStore()
if (to.path === '/login') {
Iif (authStore.isAuthenticated) return '/dashboard'
return
}
Eif (to.matched.some((r) => r.meta.requiresAuth)) {
if (!authStore.isAuthenticated) {
return { path: '/login', query: { redirect: to.fullPath } }
}
// 统一在路由守卫加载权限:首屏(/dashboard)与业务页都在挂载前 await 完成,
// 菜单一次性到位、不会“跳出”;load 内部按主体去重,重复进入同一主体不重复请求
const permissionStore = usePermissionStore()
await permissionStore.load().catch(() => {})
const moduleId = to.meta.moduleId
if (moduleId && !permissionStore.canAccess(moduleId)) {
return '/dashboard'
}
}
})
router.afterEach(() => {
NProgress.done()
})
export default router
|