import type { Router } from 'vue-router' import { useAccountStore } from '@/stores' /** 无需登录即可访问的路由路径前缀 */ const PUBLIC_PATHS = ['/auth'] /** * 判断目标路由是否为公开路由(无需登录) * @param path - 目标路由路径 */ function isPublicPath(path: string): boolean { return PUBLIC_PATHS.some((prefix) => path.startsWith(prefix)) } /** * 通用路由守卫 * - 首次导航时验证 token 是否有效 * - 未登录用户访问非公开路由 → 跳转登录页 * - 已登录用户访问登录相关页面 → 跳转首页 */ function setupCommonGuard(router: Router) { router.beforeEach(async (to) => { const accountStore = useAccountStore() // 已登录用户访问公开路由(如登录页),直接跳转首页 if (!!accountStore.accessToken && isPublicPath(to.path)) { return '/' } // 有 token 但未加载用户信息(页面刷新后 Pinia 只持久化了 token) if (accountStore.accessToken && !accountStore.accountInfo) { try { await accountStore.fetchUserInfo() } catch { // 获取失败(token 过期等),由刷新拦截器处理,此处静默 } } // accessToken 检查 if (!accountStore.accessToken) { // 明确声明忽略权限访问权限,则可以访问 if (to.meta.ignoreAccess) { return true } // 未登录用户访问非公开路由,跳转登录页 if (!isPublicPath(to.path)) { // 将原本要访问的路径作为 redirect 参数传递,登录后可跳回 return { path: '/auth/login', query: { redirect: to.fullPath }, replace: true } } // 没有访问权限,跳转登录页面(使用 to.path 而非 to.fullPath,避免 query 参数导致无限重定向) if (to.path !== '/auth/login') { return { path: '/auth/login', query: { redirect: to.fullPath }, // 携带当前跳转的页面,登录后重新跳转该页面 replace: true } } // 登录页面且已带 redirect 参数(由上面逻辑设置),允许进入 return true } return true }) } // 路由守卫 function createRouterGuard(router: Router) { setupCommonGuard(router) } export { createRouterGuard }