77 lines
3.0 KiB
JavaScript
77 lines
3.0 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 时校验访问权限,无权限跳 /403 缺省页
|
|
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 语言清单 + s_i18n 译文):随权限一并加载,
|
|
// 供菜单/模块等多语言编辑读取;内部去重、失败不阻断页面。
|
|
// 译文在这里兜一次底:App.vue 的 watcher 负责语言切换,这里负责登录后首次进入
|
|
const languagesStore = useI18nStore()
|
|
await languagesStore.loadLanguages().catch(() => {})
|
|
await languagesStore.loadMessages().catch(() => {})
|
|
|
|
const moduleId = to.meta.moduleId
|
|
if (moduleId && !permissionStore.canAccess(moduleId)) {
|
|
return '/403'
|
|
}
|
|
|
|
// 菜单入口:路由命中 s_menu 里的页面菜单时,必须有该菜单的 menu.* 授权。
|
|
// 侧栏已按授权裁剪(stores/menus),这里兜住「手输地址直接访问」。
|
|
const menu = menuStore.findMenuByRoute(to.path)
|
|
if (menu && !permissionStore.canEnterMenu(menu.b_id)) {
|
|
return '/403'
|
|
}
|
|
|
|
// 系统管理员专用页面(meta.adminOnly,当前为模块中心 /module/*):
|
|
// 非 g3soft 一律拦到 403 页。按路由标记而非路径前缀判断,避免「菜单上看不见、
|
|
// 手输地址却能进」的越权;侧栏入口同样仅对 g3soft 渲染(AppSidebar)。
|
|
if (to.matched.some((r) => r.meta.adminOnly) && !permissionStore.isG3soft) {
|
|
return '/403'
|
|
}
|
|
}
|
|
})
|
|
|
|
router.afterEach(() => {
|
|
NProgress.done()
|
|
})
|
|
|
|
export default router
|