import router from '@/router' import NProgress from 'nprogress' import 'nprogress/nprogress.css' import { ElMessage } from 'element-plus' import { usePermissionStore, useUserStore } from '@/store' import { getAccessToken } from '@/utils/auth' import { APP_TITLE, HOME_PATH, LOGIN_PATH } from '@/config' /** * 路由守卫 * * 流程: * 1. 无 token → 白名单放行,其余跳登录页并带 redirect * 2. 有 token 但还没拉过用户信息 → 调 getPermissionInfo,动态注册路由后原地重定向 * 3. 拉取失败(token 失效/后端不可用)→ 清状态回登录页 */ NProgress.configure({ showSpinner: false, trickleSpeed: 120 }) // 无需登录即可访问 const whiteList = [LOGIN_PATH, '/404'] router.beforeEach(async (to, _from, next) => { NProgress.start() document.title = to.meta?.title ? `${to.meta.title} - ${APP_TITLE}` : APP_TITLE const token = getAccessToken() if (!token) { if (whiteList.includes(to.path)) { next() } else { next({ path: LOGIN_PATH, query: { redirect: to.fullPath } }) } NProgress.done() return } // 已登录还去登录页 → 回首页 if (to.path === LOGIN_PATH) { next({ path: '/' }) NProgress.done() return } const userStore = useUserStore() if (!userStore.isUserInfoLoaded) { try { await userStore.getInfo() const permissionStore = usePermissionStore() // 落点修正:`/` 与 HOME_PATH('/dashboard') 都是「有首页菜单时」的默认落点, // 而 /dashboard 是动态路由,账号没被授权「首页」菜单时它并不存在, // 直接放行会命中 404 兜底。此时改送该账号实际可用的第一个页面。 const isLanding = to.path === '/' || to.path === HOME_PATH const fallback = permissionStore.getDefaultPath() if (isLanding && !permissionStore.canReach(to.fullPath) && fallback !== to.path) { next({ path: fallback, replace: true }) return } // 路由是刚注册的,必须用 replace 重新解析一次目标地址 next({ ...to, replace: true }) } catch (e: any) { userStore.resetState() ElMessage.error(e?.message || '获取用户信息失败,请重新登录') next({ path: LOGIN_PATH, query: { redirect: to.fullPath } }) NProgress.done() } return } next() }) router.afterEach(() => { NProgress.done() }) router.onError(() => { NProgress.done() })