fix:调试后端菜单数据问题

This commit is contained in:
liangdong
2025-12-31 20:50:58 +08:00
parent f22b0dfcbc
commit bd2a143db8
3 changed files with 133 additions and 115 deletions

View File

@@ -1,30 +1,34 @@
import { createWebHistory, createRouter, type RouteRecordRaw } from 'vue-router'
import { useUserStore } from '@/store'
import { getRouteMenus } from '@/api'
import TokenManager from '@/utils/storage';
import {
createWebHistory,
createRouter,
type RouteRecordRaw,
} from "vue-router";
import { useUserStore } from "@/store";
import { getRouteMenus } from "@/api";
import TokenManager from "@/utils/storage";
import Login from '@/pages/Login/index.vue';
import HomeView from '@/pages/Layout/index.vue';
import Login from "@/pages/Login/index.vue";
import HomeView from "@/pages/Layout/index.vue";
const tokenManager = TokenManager.getInstance();
// 基础路由(不需要权限验证)
const constantRoutes: RouteRecordRaw[] = [
{
path: '/login',
name: 'Login',
{
path: "/login",
name: "Login",
component: Login,
meta: {
title: '登录',
requiresAuth: false
}
meta: {
title: "登录",
requiresAuth: false,
},
},
]
];
// 动态路由(需要权限验证)
const asyncRoutes: RouteRecordRaw[] = [
{
path: '/',
name: 'Layout',
path: "/",
name: "Layout",
component: HomeView,
// redirect: '/home',
meta: {
@@ -32,61 +36,81 @@ const asyncRoutes: RouteRecordRaw[] = [
},
children: [] as RouteRecordRaw[],
},
]
];
const router = createRouter({
history: createWebHistory(),
routes: [...constantRoutes, ...asyncRoutes],
})
});
// 白名单路由(不需要登录即可访问)
const whiteList = ['/login']
const whiteList = ["/login"];
// 1. 预先加载所有可能的页面组件
// 这里的路径模式要覆盖到你所有的业务组件
const modules = import.meta.glob('@/pages/**/*.vue')
const modules = import.meta.glob("@/pages/**/*.vue");
const loadComponent = (componentPath: string) => {
if (!componentPath) return null
if (!componentPath) return null;
// 统一路径格式处理
let fullPath = ''
let fullPath = "";
if (componentPath.startsWith('@/')) {
fullPath = componentPath
} else if (componentPath.includes('/')) {
if (componentPath.startsWith("@/")) {
fullPath = componentPath;
} else if (componentPath.includes("/")) {
// 补全路径,确保以 @/pages 开头
fullPath = componentPath.startsWith('pages/') ? `@/${componentPath}` : `@/pages/${componentPath}/index.vue`
fullPath = componentPath.startsWith("pages/")
? `@/${componentPath}`
: `@/pages/${componentPath}/index.vue`;
} else {
// 补全 index.vue
fullPath = `@/pages/${componentPath}/index.vue`
fullPath = `@/pages/${componentPath}/index.vue`;
}
// 重点:将 @/ 转换为 /src/,因为 glob 默认生成的 key 是相对于项目根目录的
const key = fullPath.replace('@/', '/src/')
const key = fullPath.replace("@/", "/src/");
// 从 modules 中查找对应的导入函数
if (modules[key]) {
return modules[key]
return modules[key];
} else {
console.error(`未找到组件文件: ${key}. 请检查路径或大小写。`)
return null
console.error(`未找到组件文件: ${key}. 请检查路径或大小写。`);
return null;
}
}
};
// 将后端返回的路由数据转换为 Vue Router 路由
const transformRoutes = (routes: any[], parentCode: string = ''): RouteRecordRaw[] => {
const transformRoutes = (
routes: any[],
parentCode: string = ""
): RouteRecordRaw[] => {
console.log("transformRoutes", routes);
return routes.flatMap((route) => {
const fullCode = parentCode ? `${parentCode}/${route.code}` : route.code;
// 如果当前路由有子路由,说明它是一个路由前缀,不需要组件
if (route.children && route.children.length > 0) {
// 将子路由的路径加上当前路由的前缀,然后递归处理
return transformRoutes(route.children, fullCode);
const childRoutes = transformRoutes(route.children, fullCode);
if (route.code) {
// 创建一个父路由,将子路由作为其 children
const parentRoute: RouteRecordRaw = {
path: `/${fullCode}`,
name: route.code,
meta: {
title: route.name,
icon: route.icon,
...route.meta,
},
children: childRoutes,
};
return parentRoute;
} else {
return childRoutes;
}
} else {
// 叶子节点才需要组件和路由配置
const component = fullCode ? loadComponent(fullCode) : undefined;
const routeRecord: any = {
path: route.code,
name: route.code,
@@ -95,7 +119,7 @@ const transformRoutes = (routes: any[], parentCode: string = ''): RouteRecordRaw
icon: route.icon,
...route.meta,
},
}
};
if (component) {
routeRecord.component = component;
@@ -104,135 +128,117 @@ const transformRoutes = (routes: any[], parentCode: string = ''): RouteRecordRaw
return routeRecord as RouteRecordRaw;
}
});
}
};
// 添加动态路由
const addDynamicRoutes = async () => {
const userStore = useUserStore()
const userStore = useUserStore();
// 如果路由已加载,直接返回
if (userStore.isRoutesLoaded) {
return
return;
}
try {
// TODO:从后端获取路由菜单数据 (这边需要区分 后台的菜单 和用户的菜单)
let response:any;
// 从后端获取路由菜单数据 (这边需要区分 后台的菜单 和用户的菜单)
let allRoutes:any[] = [];
if (userStore.isBackendUser) {
const backendResponse = await getRouteMenus();
response = [{
code: 'stage',
name: '后台管理',
icon: '',
children: backendResponse,
}];
}else{
const backendResponse = await getRouteMenus();
allRoutes = [
{
code: "stage",
name: "后台管理",
icon: "",
children: backendResponse,
},
];
} else {
// TODO:获取用户端的数据信息
// response = await getUserMenus();
response = [];
allRoutes = [];
}
if (response) {
const processRoutes = (routes: any[], prefix: string = ''): RouteRecordRaw[] => {
return routes.flatMap(route => {
const currentPath = prefix ? `${prefix}/${route.code}` : route.code;
if (route.children && route.children.length > 0) {
// 如果有子路由,递归处理并添加当前路径作为前缀
return processRoutes(route.children, currentPath);
} else {
// 叶子节点,创建路由记录
const component = loadComponent(currentPath);
return {
path: route.code,
name: route.code,
component: component || HomeView, // 使用Layout的组件
meta: {
title: route.name,
icon: route.icon,
...route.meta,
}
} as RouteRecordRaw;
}
});
};
if (allRoutes) {
// 转换路由数据
// const dynamicRoutes = transformRoutes(Array.isArray(response) ? response : [response])
const dynamicRoutes = processRoutes(Array.isArray(response) ? response : [response])
const dynamicRoutes = transformRoutes(
Array.isArray(allRoutes) ? allRoutes : [allRoutes]
);
// 将动态路由添加到 Layout 的 children 中
const layoutRoute = router.getRoutes().find(route => route.name === 'Layout')
const layoutRoute = router
.getRoutes()
.find((route) => route.name === "Layout");
if (layoutRoute) {
dynamicRoutes.forEach(route => {
router.addRoute('Layout', route)
})
dynamicRoutes.forEach((route) => {
router.addRoute("Layout", route);
});
} else {
// 如果找不到 Layout 路由,直接添加到根路由
dynamicRoutes.forEach(route => {
router.addRoute(route)
})
dynamicRoutes.forEach((route) => {
router.addRoute(route);
});
}
console.log('Layout route:', router.getRoutes())
// 保存路由数据到 store
userStore.setRoutes(response)
userStore.setRoutes(dynamicRoutes);
// 标记路由已加载
userStore.isRoutesLoaded = true
userStore.isRoutesLoaded = true;
}
} catch (error) {
// 如果获取路由失败,清除用户数据并跳转到登录页
userStore.clearUserData()
router.push('/login')
userStore.clearUserData();
router.push("/login");
}
}
};
// 路由导航守卫
router.beforeEach(async (to, _from, next) => {
const userStore = useUserStore()
const accessToken = tokenManager.getToken('accessToken');
const userStore = useUserStore();
const accessToken = tokenManager.getToken("accessToken");
// 获取 token
const token = accessToken || userStore.token
const token = accessToken || userStore.token;
// 如果已登录,更新 store 中的 token
if (token) {
userStore.setToken(token)
userStore.setToken(token);
}
// 判断是否在白名单中
if (whiteList.includes(to.path)) {
// 如果在白名单中且已登录,重定向到首页
if (token) {
next('/')
next("/");
} else {
next()
next();
}
return
return;
}
// 需要登录验证
if (!token) {
// 未登录,重定向到登录页
next({
path: '/login',
path: "/login",
query: { redirect: to.fullPath }, // 保存当前路径,登录后可以跳转回来
})
return
});
return;
}
// 已登录,检查路由是否已加载
if (!userStore.isRoutesLoaded) {
try {
// 加载动态路由
await addDynamicRoutes()
await addDynamicRoutes();
// 路由加载完成后,重新导航到目标路由
next({ ...to, replace: true })
next({ ...to, replace: true });
} catch (error) {
console.error('Route loading error:', error)
next('/login')
console.error("Route loading error:", error);
next("/login");
}
} else {
// 路由已加载,直接放行
next()
next();
}
})
});
export default router
export default router;