Files
workspace/code/fms/fms-vue/src/router/index.js
T
2026-09-04 23:24:45 +08:00

71 lines
2.5 KiB
JavaScript

import { createRouter, createWebHistory } from 'vue-router'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
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,
})
// 登录守卫:未登录访问受保护页跳 /login?redirect=xxx;已登录访问 /login 跳 /dashboard
// 权限守卫:路由配置 meta.moduleId 时校验访问权限,无权限跳 /dashboard
router.beforeEach(async (to) => {
NProgress.start()
const authStore = useAuthStore()
if (to.path === '/login') {
if (authStore.isAuthenticated) return '/dashboard'
return
}
if (to.matched.some((r) => r.meta.requiresAuth)) {
if (!authStore.isAuthenticated) {
return { path: '/login', query: { redirect: to.fullPath } }
}
// 统一在路由守卫加载权限与动态菜单:首屏(/dashboard)与业务页都在挂载前 await 完成,
// 菜单一次性到位、不会“跳出”;load 内部按主体去重,重复进入同一主体不重复请求
const permissionStore = usePermissionStore()
const menuStore = useMenuStore()
await Promise.all([
permissionStore.load().catch(() => {}),
menuStore.load().catch(() => {}),
])
// 业务数据多语言配置(s_i18n_type 语言清单):随权限一并加载,
// 供菜单/模块等多语言编辑读取;内部去重、失败不阻断页面
const languagesStore = useI18nStore()
await languagesStore.loadLanguages().catch(() => {})
const moduleId = to.meta.moduleId
if (moduleId && !permissionStore.canAccess(moduleId)) {
return '/dashboard'
}
// 模块中心(/module/*)是系统管理员的专用页面:非 g3soft 一律拦回工作台。
// 这是路由层的特殊判断,与菜单树无关(菜单隐藏与路由放行由同一管理员判定决定),
// 避免「菜单上看不见、手输地址却能进」的越权。
if (to.path.startsWith('/module/') && !permissionStore.isG3soft) {
return '/dashboard'
}
}
})
router.afterEach(() => {
NProgress.done()
})
export default router