This commit is contained in:
Zy
2026-09-20 08:57:53 +08:00
parent 292ee1a6dd
commit f6a7eb1b4e
41 changed files with 864 additions and 608 deletions

View File

@@ -17,13 +17,12 @@ const whiteList = ['/login', '/register', '/social-callback', '/register*', '/re
// 全局标记:动态路由是否已经添加过(只加载一次!)
let isDynamicRoutesAdded = false;
// ✅ 新增:导航锁,防止多个路由导航并发执行
let isNavigating = false;
// 判断是否在白名单
const isWhiteList = (path: string) => {
return whiteList.some((pattern) => isPathMatch(pattern, path));
};
// ✅ 关键修改:记录当前已添加的动态路由名称列表
let currentDynamicRouteNames: string[] = [];
// ✅ 关键修改:清除所有已记录的动态路由
const removeDynamicRoutes = () => {
currentDynamicRouteNames.forEach((name) => {
@@ -31,85 +30,111 @@ const removeDynamicRoutes = () => {
router.removeRoute(name);
}
});
// 清空记录数组
currentDynamicRouteNames = [];
};
router.beforeEach(async (to, from) => {
NProgress.start();
// 判断是否在白名单
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();
if (hasToken) {
// 设置标题
to.meta.title && useSettingsStore().setTitle(to.meta.title as string);
try {
if (hasToken) {
// 设置标题
to.meta.title && useSettingsStore().setTitle(to.meta.title as string);
// 已登录 且 去登录页 → 跳首页
if (to.path === '/login') {
NProgress.done();
return '/';
}
// 白名单页面直接放行
if (isWhiteList(to.path)) {
return;
}
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;
// 已登录 且 去登录页 → 跳首页
if (to.path === '/login') {
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 { path: '/community/communitylist', replace: true };
} else {
// 重新进入当前路由(让新添加的路由生效)
return { ...to, replace: true };
// 白名单页面直接放行
if (isWhiteList(to.path)) {
return;
}
}
return;
} else {
// 未登录
isDynamicRoutesAdded = false;
if (isWhiteList(to.path)) {
// 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 {
NProgress.done();
return `/login`;
// 未登录
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();
});