修复路由和主题
This commit is contained in:
+141
-69
@@ -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") {
|
||||
|
||||
Reference in New Issue
Block a user