import type { Router } from 'vue-router' import { HOME_PATH, LOGIN_PATH, PATHS } from '@vben/constants' import { preferences } from '@vben/preferences' import { useAccessStore } from '@vben/stores' import { startProgress, stopProgress } from '@vben/utils' import { accessRoutes, coreRouteNames } from '#/router/routes' import hud from '#/utils/hud' import { generateAccess } from './access' /** * 通用守卫配置 * @param router */ const setupCommonGuard = (router: Router) => { // 记录已经加载的页面 const loadedPaths = new Set() router.beforeEach((to) => { to.meta.loaded = loadedPaths.has(to.path) // 页面加载进度条 if (!to.meta.loaded && preferences.transition.progress) { startProgress() } return true }) router.afterEach((to) => { // 记录页面是否加载,如果已经加载,后续的页面切换动画等效果不在重复执行 loadedPaths.add(to.path) // 关闭页面加载进度条 if (preferences.transition.progress) { stopProgress() } }) } /** * 权限访问守卫配置 * @param router */ const setupAccessGuard = (router: Router) => { router.beforeEach(async (to, from) => { const accessStore = useAccessStore() // 生成路由表 // 基本路由,这些路由不需要进入权限拦截 if (coreRouteNames.includes(to.name as string)) { if (to.path === LOGIN_PATH && accessStore.accessToken) { return decodeURIComponent( (to.query?.redirect as string) || PATHS.homePath, ) } return true } // accessToken 检查 if (!accessStore.accessToken) { // 明确声明忽略权限访问权限,则可以访问 if (to.meta.ignoreAccess) { return true } // 没有访问权限,跳转登录页面 if (to.fullPath !== LOGIN_PATH) { return { path: LOGIN_PATH, // 如不需要,直接删除 query query: to.fullPath === PATHS.homePath ? {} : { redirect: encodeURIComponent(to.fullPath) }, // 携带当前跳转的页面,登录后重新跳转该页面 replace: true, } } return to } // 是否已经生成过动态路由 if (accessStore.isAccessChecked) { return true } if (from.path !== PATHS.loginPath) { // 登录那里已经获取到了用户信息,这里不需要再次获取 const authStore = useAuthStore() // 当前登录用户拥有的角色标识列表 await authStore.fetchUserInfo() } // 生成菜单和路由 const { accessibleMenus, accessibleRoutes } = await generateAccess({ roles: [], router, // 则会在菜单中显示,但是访问会被重定向到403 routes: accessRoutes, }) // 保存菜单信息和路由信息 accessStore.setAccessMenus(accessibleMenus) accessStore.setAccessRoutes(accessibleRoutes) accessStore.setIsAccessChecked(true) let redirectPath: string if (from.query.redirect) { redirectPath = from.query.redirect as string } else if (to.path === PATHS.homePath || to.path === HOME_PATH) { redirectPath = PATHS.homePath } else { redirectPath = to.fullPath } return { ...router.resolve(decodeURIComponent(redirectPath)), replace: true, } }) } /** * 项目守卫配置 * @param router */ const createRouterGuard = (router: Router) => { /** 通用 */ setupCommonGuard(router) /** 权限访问 */ setupAccessGuard(router) router.onError((error) => { // 关闭全局弹框 hud.hide() hud.hideToast() if (error.message.includes('Failed to fetch dynamically imported module')) { hud.alert({ title: '提示', content: '发现新版本,请刷新页面', onConfirm: () => { window.location.reload() }, }) } }) } export { createRouterGuard }