import { to as tos } from 'await-to-js'; import router from './router'; import NProgress from 'nprogress'; import 'nprogress/nprogress.css'; import { getToken } from '@/utils/auth'; import { isHttp, isPathMatch } from '@/utils/validate'; import { isRelogin } from '@/utils/request'; import { useUserStore } from '@/store/modules/user'; import { useSettingsStore } from '@/store/modules/settings'; import { usePermissionStore } from '@/store/modules/permission'; import { ElMessage } from 'element-plus/es'; NProgress.configure({ showSpinner: false }); // 白名单:不需要登录就能访问的页面 const whiteList = ['/login', '/register', '/social-callback', '/register*', '/register/*']; // 全局标记:动态路由是否已经添加过(只加载一次!) let isDynamicRoutesAdded = false; // ✅ 新增:导航锁,防止多个路由导航并发执行 let isNavigating = false; // ✅ 关键修改:记录当前已添加的动态路由名称列表 let currentDynamicRouteNames: string[] = []; // ✅ 关键修改:清除所有已记录的动态路由 const removeDynamicRoutes = () => { currentDynamicRouteNames.forEach((name) => { if (name && router.hasRoute(name)) { router.removeRoute(name); } }); currentDynamicRouteNames = []; }; // 判断是否在白名单 const isWhiteList = (path: string) => { return whiteList.some((pattern) => isPathMatch(pattern, path)); }; router.beforeEach(async (to, from) => { // ========== 导航锁核心 ========== // 如果正在导航,直接终止本次跳转,防止并发多个守卫 if (isNavigating) { NProgress.done(); return false; } isNavigating = true; NProgress.start(); const hasToken = getToken(); const userStore = useUserStore(); const permissionStore = usePermissionStore(); try { if (hasToken) { // 设置标题 to.meta.title && useSettingsStore().setTitle(to.meta.title as string); // 已登录 且 去登录页 → 跳首页 if (to.path === '/login') { return '/'; } // 白名单页面直接放行 if (isWhiteList(to.path)) { return; } // roles为空,需要拉取用户信息+构建动态路由(只执行一次) if (userStore.roles.length === 0) { isRelogin.show = true; removeDynamicRoutes(); // 获取用户信息 const [err] = await tos(userStore.getInfo()); if (err) { await userStore.logout(); ElMessage.error(err); isDynamicRoutesAdded = false; return '/'; } isRelogin.show = false; permissionStore.resetRoutes(); // 生成动态路由 const accessRoutes = await permissionStore.generateRoutes(); // 添加路由(避免重复添加) accessRoutes.forEach((route) => { if (route.name && router.hasRoute(route.name)) { router.removeRoute(route.name); } if (!isHttp(route.path) && !router.hasRoute(route.name)) { router.addRoute(route); // 记录顶层路由名称 if (route.name) { currentDynamicRouteNames.push(route.name as string); } } }); isDynamicRoutesAdded = true; // 登录页跳转进来,直接跳首页;其他情况重新触发导航加载动态路由 if (from.path === '/login') { return '/community/communitylist'; } else { // 这里replace仅在首次加载路由时执行;后续菜单切换不会走到这里 return { ...to, replace: true }; } } // ✅ 已经有角色、动态路由已经构建完成:直接放行菜单切换,不会再走上面的动态路由构建逻辑 return; } else { // 未登录 isDynamicRoutesAdded = false; if (isWhiteList(to.path)) { return; } else { return `/login`; } } } catch (err) { console.error('路由守卫异常:', err); return false; } finally { // ✅ 无论成功失败,必须释放导航锁 isNavigating = false; } }); router.afterEach(() => { NProgress.done(); }); // ✅ 导航发生错误的时候,也要释放锁(路由跳转报错时afterEach不一定执行) router.onError(() => { isNavigating = false; NProgress.done(); });