20260904232445
This commit is contained in:
1 parent
4e167df0f0
commit
1b01a31252
19 files changed
+1099
-1013
No files matched your search
@@ -1,122 +1,22 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import NProgress from 'nprogress'
|
||||
import 'nprogress/nprogress.css'
|
||||
import DefaultLayout from '@/layouts/DefaultLayout.vue'
|
||||
import { routes } from './routes'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { usePermissionStore } from '@/stores/permissions'
|
||||
import { useMenuStore } from '@/stores/menus'
|
||||
import { useI18nStore } from '@/stores/i18n'
|
||||
|
||||
NProgress.configure({ showSpinner: false })
|
||||
|
||||
/**
|
||||
* 路由实例。
|
||||
* 路由表本身在 ./routes.js(菜单管理的「路由地址」下拉也要读它),
|
||||
* 本文件只保留实例创建与全局守卫,避免页面组件反向依赖守卫逻辑。
|
||||
*/
|
||||
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' },
|
||||
},
|
||||
// 附件组件演示
|
||||
{
|
||||
path: '/file-demo',
|
||||
name: 'file-demo',
|
||||
component: () => import('@/views/file-demo/index.vue'),
|
||||
meta: { title: '附件组件演示', componentName: 'FileDemo' },
|
||||
},
|
||||
// 详情页:同一组件按参数复用,但每个 fullPath 独立缓存、关闭即销毁
|
||||
// (per-param 的命名组件由 DefaultLayout 的 getPageWrapper 按路由动态生成)
|
||||
{
|
||||
path: '/detail/:id',
|
||||
name: 'detail',
|
||||
component: () => import('@/views/detail/DetailPage.vue'),
|
||||
meta: { title: '详情', cacheByKey: true },
|
||||
},
|
||||
// 模块管理:元数据驱动的模块配置中心(先静态路由,权限/动态菜单后续接入)
|
||||
{
|
||||
path: '/module/module-management',
|
||||
name: 'module-module-management',
|
||||
component: () => import('@/views/module/module-management/index.vue'),
|
||||
meta: { title: '模块管理', componentName: 'ModuleManagement' },
|
||||
},
|
||||
// 菜单管理:占位页面,待实现
|
||||
{
|
||||
path: '/module/menu-management',
|
||||
name: 'module-menu-management',
|
||||
component: () => import('@/views/module/menu-management/index.vue'),
|
||||
meta: { title: '菜单管理', componentName: 'MenuManagement' },
|
||||
},
|
||||
// 多语言类型:系统支持的语言清单维护(s_i18n_type)
|
||||
{
|
||||
path: '/module/i18n-type',
|
||||
name: 'module-i18n-type',
|
||||
component: () => import('@/views/module/i18n-type/index.vue'),
|
||||
meta: { title: '多语言类型', componentName: 'I18nTypeManagement' },
|
||||
},
|
||||
// 业务页面后续在此追加,配置 meta.moduleId 后自动走权限校验
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
redirect: '/dashboard',
|
||||
},
|
||||
],
|
||||
routes,
|
||||
})
|
||||
|
||||
// 登录守卫:未登录访问受保护页跳 /login?redirect=xxx;已登录访问 /login 跳 /dashboard
|
||||
@@ -135,10 +35,14 @@ router.beforeEach(async (to) => {
|
||||
return { path: '/login', query: { redirect: to.fullPath } }
|
||||
}
|
||||
|
||||
// 统一在路由守卫加载权限:首屏(/dashboard)与业务页都在挂载前 await 完成,
|
||||
// 统一在路由守卫加载权限与动态菜单:首屏(/dashboard)与业务页都在挂载前 await 完成,
|
||||
// 菜单一次性到位、不会“跳出”;load 内部按主体去重,重复进入同一主体不重复请求
|
||||
const permissionStore = usePermissionStore()
|
||||
await permissionStore.load().catch(() => {})
|
||||
const menuStore = useMenuStore()
|
||||
await Promise.all([
|
||||
permissionStore.load().catch(() => {}),
|
||||
menuStore.load().catch(() => {}),
|
||||
])
|
||||
|
||||
// 业务数据多语言配置(s_i18n_type 语言清单):随权限一并加载,
|
||||
// 供菜单/模块等多语言编辑读取;内部去重、失败不阻断页面
|
||||
@@ -149,6 +53,13 @@ router.beforeEach(async (to) => {
|
||||
if (moduleId && !permissionStore.canAccess(moduleId)) {
|
||||
return '/dashboard'
|
||||
}
|
||||
|
||||
// 模块中心(/module/*)是系统管理员的专用页面:非 g3soft 一律拦回工作台。
|
||||
// 这是路由层的特殊判断,与菜单树无关(菜单隐藏与路由放行由同一管理员判定决定),
|
||||
// 避免「菜单上看不见、手输地址却能进」的越权。
|
||||
if (to.path.startsWith('/module/') && !permissionStore.isG3soft) {
|
||||
return '/dashboard'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in new issue
Block a user