修复路由和主题

This commit is contained in:
2025-11-02 11:47:51 +08:00
parent bfba8d7ad6
commit 01c47ccbd4
13 changed files with 561 additions and 254 deletions
+141 -69
View File
@@ -47,67 +47,91 @@ const router = createRouter({
// 动态路由加载状态
let dynamicRoutesAdded = false;
// 路由加载 Promise,用于确保路由加载完成
let routesLoadingPromise = null;
// 从 API 加载并添加动态路由
export async function loadAndAddDynamicRoutes() {
// 如果已经有加载中的 Promise,直接返回它
if (routesLoadingPromise) {
return routesLoadingPromise;
}
// 如果已经加载过,直接返回
if (dynamicRoutesAdded) {
return Promise.resolve();
}
try {
const { getAllMenus } = await import("@/api/menu");
const res = await getAllMenus();
if (res && res.success && res.data) {
// 保存菜单到 localStorage
localStorage.setItem('menus', JSON.stringify(res.data));
// 添加动态路由
addDynamicRoutes(res.data);
return Promise.resolve();
} else {
// 如果 API 失败,尝试从 localStorage 加载
const cachedMenus = JSON.parse(localStorage.getItem('menus') || '[]');
if (cachedMenus.length) {
addDynamicRoutes(cachedMenus);
// 创建加载 Promise
routesLoadingPromise = (async () => {
try {
console.log('[路由加载] 开始从 API 加载动态路由...');
// 直接从 API 获取菜单数据
const { getAllMenus } = await import("@/api/menu");
const res = await getAllMenus();
if (res && res.success && res.data) {
console.log('[路由加载] API 返回菜单数量:', res.data.length);
// 添加动态路由
addDynamicRoutes(res.data);
console.log('[路由加载] 动态路由加载完成');
dynamicRoutesAdded = true;
routesLoadingPromise = null;
return Promise.resolve();
} else {
console.warn('[路由加载] API 返回数据格式异常:', res);
dynamicRoutesAdded = true;
routesLoadingPromise = null;
return Promise.resolve();
}
} catch (error) {
console.error('[路由加载] 加载动态路由失败:', error);
// 即使出错也标记为已加载,避免无限重试
dynamicRoutesAdded = true;
routesLoadingPromise = null;
return Promise.resolve();
}
} catch (error) {
console.error('加载动态路由失败:', error);
// 如果 API 失败,尝试从 localStorage 加载
const cachedMenus = JSON.parse(localStorage.getItem('menus') || '[]');
if (cachedMenus.length) {
addDynamicRoutes(cachedMenus);
return Promise.resolve();
}
return Promise.resolve();
}
})();
return routesLoadingPromise;
}
// 添加动态路由到 Main 的 children 中
function addDynamicRoutes(menus) {
if (dynamicRoutesAdded || !menus?.length) {
if (!menus?.length) {
console.warn('[路由加载] 菜单数据为空,跳过添加动态路由');
return;
}
console.log('[路由加载] 开始添加动态路由,菜单数量:', menus.length);
// 如果已经添加过,先移除旧路由(刷新时可能需要重新添加)
if (dynamicRoutesAdded) {
console.log('[路由加载] 检测到已添加的路由,先移除旧路由');
// 移除 Main 路由以便重新添加
if (router.hasRoute('Main')) {
router.removeRoute('Main');
}
dynamicRoutesAdded = false;
}
// 过滤掉 ID 为 1 的仪表盘菜单,因为它是静态路由
const filteredMenus = menus.filter(menu => menu.id !== 1);
const dynamicRoutes = convertMenusToRoutes(filteredMenus);
// 打印路由树结构(只打印路径信息,不序列化组件)
// console.log('生成的路由树:', dynamicRoutes.map(r => ({
// path: r.path,
// name: r.name,
// hasComponent: !!r.component,
// childrenCount: r.children?.length || 0
// })));
console.log('[路由加载] 转换后的动态路由数量:', dynamicRoutes.length);
console.log('[路由加载] 动态路由列表:', dynamicRoutes.map(r => ({
path: r.path,
name: r.name,
hasComponent: !!r.component,
childrenCount: r.children?.length || 0
})));
// 获取主路由
const mainRoute = router.getRoutes().find(r => r.name === 'Main');
if (!mainRoute) {
console.error('找不到 Main 路由');
console.error('[路由加载] 找不到 Main 路由');
return;
}
@@ -116,10 +140,12 @@ function addDynamicRoutes(menus) {
const dashboardRoute = staticChildren.find(r => r.name === 'Dashboard');
// 移除旧的主路由
router.removeRoute('Main');
if (router.hasRoute('Main')) {
router.removeRoute('Main');
}
// 重新添加主路由,仪表盘路由放在第一个,后面跟动态路由
router.addRoute({
const newMainRoute = {
...mainRoute,
redirect: "/dashboard", // 始终重定向到仪表盘
children: [
@@ -128,7 +154,10 @@ function addDynamicRoutes(menus) {
// 动态路由跟在后面
...dynamicRoutes
]
});
};
router.addRoute(newMainRoute);
console.log('[路由加载] Main 路由已更新,子路由总数:', newMainRoute.children.length);
// 添加知识库的子路由(详情页和编辑页)
// 直接在 Main 路由下添加完整路径的子路由
@@ -152,30 +181,6 @@ function addDynamicRoutes(menus) {
});
dynamicRoutesAdded = true;
// 打印路由信息用于调试
const finalMainRoute = router.getRoutes().find(r => r.name === 'Main');
// console.log('动态路由已添加:', {
// redirect: "/dashboard",
// staticRoutesCount: dashboardRoute ? 1 : 0,
// dynamicRoutesCount: dynamicRoutes.length,
// totalChildrenCount: (dashboardRoute ? 1 : 0) + dynamicRoutes.length,
// childrenPaths: finalMainRoute?.children?.map(c => ({
// path: c.path,
// name: c.name,
// isStatic: c.meta?.isStatic || false,
// metaPath: c.meta?.menuPath
// }))
// });
// 测试路由解析(使用完整路径)
const testResolve = router.resolve('/dashboard');
// console.log('测试路由解析 /dashboard:', {
// matched: testResolve.matched.map(m => ({ name: m.name, path: m.path })),
// fullPath: testResolve.fullPath,
// name: testResolve.name,
// hasMatched: testResolve.matched.length > 0
// });
}
// 查找第一个有效的路由(有组件的路由)
@@ -222,16 +227,83 @@ router.beforeEach(async (to, from, next) => {
// 3. 已登录,确保动态路由已加载(必须在检查 404 之前)
if (!dynamicRoutesAdded) {
console.log('[路由守卫] 开始加载动态路由, 目标路径:', to.path);
await loadAndAddDynamicRoutes();
// 路由加载后,使用原始路径重新导航(确保路由表已更新)
// 如果 to 已经是 404,使用原始路径而不是 404 路由对象
const targetPath = to.matched.length === 0 || to.name === "NotFound"
? to.path // 如果匹配失败或者是 404,使用原始路径
: to.fullPath;
next({ path: targetPath, replace: true });
console.log('[路由守卫] 动态路由加载完成, dynamicRoutesAdded:', dynamicRoutesAdded);
// 如果路由加载后仍然未添加(API 失败)
if (!dynamicRoutesAdded) {
console.warn('[路由守卫] 路由加载失败,可能是 API 错误或 token 无效');
// 重新检查 token,如果 token 不存在或无效,跳转到登录页
const currentToken = localStorage.getItem('token');
if (!currentToken) {
console.log('[路由守卫] 未找到 token,跳转到登录页');
next({ path: "/login", query: { redirect: to.path } });
return;
}
// 如果 token 存在但路由加载失败,可能是 token 过期或无效,清除 token 并跳转登录
console.warn('[路由守卫] Token 存在但路由加载失败,清除 token 并跳转登录页');
localStorage.removeItem('token');
localStorage.removeItem('userInfo');
next({ path: "/login", query: { redirect: to.path } });
return;
}
// 路由加载完成后,等待一个tick确保Vue Router内部路由表已更新
await new Promise(resolve => setTimeout(resolve, 0));
// 重新解析路径检查是否能匹配
const resolved = router.resolve(to.path);
console.log('[路由守卫] 路由解析结果:', {
path: to.path,
resolved: resolved.path,
matched: resolved.matched.length,
name: resolved.name,
matchedRoutes: resolved.matched.map(m => ({ name: m.name, path: m.path }))
});
// 如果能匹配到路由,使用完整路径重新导航(确保Vue Router正确更新)
if (resolved.matched.length > 0 && resolved.name !== "NotFound") {
console.log('[路由守卫] 路由匹配成功,重新导航确保正确加载');
next({ path: to.fullPath || to.path, replace: true });
return;
}
// 如果无法匹配,使用原始路径重新导航
console.log('[路由守卫] 路由未匹配,重新导航到:', to.path);
next({ path: to.fullPath || to.path, replace: true });
return;
}
// 3.5 如果路由已加载但当前路径未匹配,可能是刷新问题
// 注意:这里需要排除根路径和已知的静态路由
if (to.matched.length === 0 && to.name !== "NotFound" && to.path !== "/" && to.path !== "/dashboard") {
console.log('[路由守卫] 路由已加载但未匹配,尝试重新解析:', to.path);
// 重新解析路径,看看是否能够匹配
const resolved = router.resolve(to.path);
console.log('[路由守卫] 重新解析结果:', {
matched: resolved.matched.length,
name: resolved.name,
matchedRoutes: resolved.matched.map(m => ({ name: m.name, path: m.path }))
});
if (resolved.matched.length > 0 && resolved.name !== "NotFound") {
// 能够匹配,说明路由表正常,使用路径重新导航
console.log('[路由守卫] 重新解析匹配成功,重新导航');
next({ path: to.path, replace: true });
return;
} else {
console.warn('[路由守卫] 路由确实无法匹配,可能是路径错误:', to.path);
// 打印所有已注册的路由用于调试
const allRoutes = router.getRoutes();
console.log('[路由守卫] 所有已注册的路由:', allRoutes.map(r => ({
name: r.name,
path: r.path,
children: r.children?.map(c => ({ name: c.name, path: c.path }))
})));
}
}
// 4. 已登录且路由已加载,检查是否是 404
// 注意:这里要在路由加载完成后才能正确判断是否是 404
if (to.name === "NotFound") {