Files
cpms_operation_platform/src/router/guard.ts
T

54 lines
1.8 KiB
TypeScript
Raw Normal View History

2026-07-23 11:27:33 +08:00
import router from '@/router';
2026-07-23 15:00:19 +08:00
import { auth } from '@/hooks/useAuth';
2026-07-23 11:27:33 +08:00
/**
* 全局路由守卫
* 核心流程:
2026-07-23 15:00:19 +08:00
* 1. /login → 已登录则跳首页,未登录则放行
* 2. 未登录 → 跳转 /login
* 3. 已登录但菜单未加载 → 加载菜单+权限 → 重新导航(确保动态路由生效)
* 4. 已登录且菜单已加载 → 放行
*
* 关键:当 loadMenu 动态注册路由后,必须用 next({ path, replace: true })
* 重新触发导航,否则当前导航仍使用旧路由表,会匹配到 404。
* 注意:不能用 next({ ...to, replace: true }),因为展开 to 会把旧的
* matched 信息带过去,导致仍然匹配到 /:pathMatch(.*)*。
2026-07-23 11:27:33 +08:00
*/
router.beforeEach(async (to, _from, next) => {
// 设置页面标题
const appTitle = import.meta.env.VITE_APP_TITLE || 'CPMS 运营平台';
document.title = to.meta.title ? `${to.meta.title} - ${appTitle}` : appTitle;
2026-07-23 15:00:19 +08:00
// ── /login 特殊处理 ──
if (to.path === '/login') {
if (auth.isLoggedIn()) {
2026-07-23 11:27:33 +08:00
const { homePath } = await import('@/stores/menuStore').then((m) => m.useMenuStore());
next(homePath.value);
2026-07-23 15:00:19 +08:00
} else {
next();
2026-07-23 11:27:33 +08:00
}
2026-07-23 15:00:19 +08:00
return;
}
// ── 未登录 → 跳转登录页 ──
if (!auth.isLoggedIn()) {
next('/login');
return;
2026-07-23 11:27:33 +08:00
}
2026-07-23 15:00:19 +08:00
// ── 已登录:确保菜单和动态路由已加载 ──
const { loadMenu, loaded } = await import('@/stores/menuStore').then((m) => m.useMenuStore());
if (!loaded.value) {
const { loadPermissions } = await import('@/stores/permissionStore').then((m) =>
m.usePermissionStore(),
);
await Promise.all([loadMenu(), loadPermissions()]);
// 动态路由刚注册,需要用新路由表重新匹配当前路径
next({ path: to.fullPath, replace: true });
return;
}
next();
2026-07-23 11:27:33 +08:00
});