route.js
import { routes, asyncRoutes } from '@/router';
import { permissionList } from '@/api/login';
const usePremissionStore = defineStore('Premission', {
state: () => ({
addRouters: [],
}),
actions: {
SET_ADD_ROUTERS(data) {
this.addRouters = data;
},
async GET_PERMISSION() {
const { result: list } = await permissionList();
let commonRouter = buildAccessibleRoutes(list, asyncRoutes);
this.SET_ADD_ROUTERS(commonRouter);
},
},
});
export default usePremissionStore;
/**
* ⚠️ 新的实现方案,支持无限层级路由
* 以后端返回的路由树为准,构建权限路由表
* @param {Array} backendRoutes - 后端返回的完整路由树
* @param {Array} frontendRoutes - 前端定义的所有异步路由配置
* @returns {Array} 过滤和排序后的最终路由表
*/
function buildAccessibleRoutes(backendRoutes, frontendRoutes) {
// 1. 为了方便快速查找,将前端路由拍平并存入 Map
// 键是路由的 path,值是完整的路由对象
const frontendRouteMap = new Map();
frontendRoutes.forEach((route) => {
// 使用递归函数来拍平任意层级的路由
const flattenRoutes = (r) => {
if (r.children && r.children.length > 0) {
frontendRouteMap.set(r.path.split('/')[1], r);
r.children.forEach((child) => flattenRoutes(child));
} else {
frontendRouteMap.set(r.path, r);
}
};
flattenRoutes(route);
});
// 2. 核心:递归函数,根据后端路由树构建新的路由表
const buildTree = (backendTree) => {
const accessibleRoutes = [];
for (const backendRoute of backendTree) {
// 从 Map 中查找对应的组件配置
const frontendRouteConfig = frontendRouteMap.get(backendRoute.path); // 假设后端路由的path字段与前端一致
// 如果前端存在该路由的配置
if (frontendRouteConfig) {
// 创建一个新的路由对象,避免直接修改原始的 asyncRoutes
const newRoute = {
...frontendRouteConfig, // 复制前端配置 (component, meta, etc.)
children: [], // 准备接收子路由
};
// 处理 xxx 的特殊逻辑
if (backendRoute.api) {
if (import.meta.env.VITE_APP_ENV === 'development') {
newRoute.meta.thirdLink = import.meta.env.VITE_APP_BASE_URL + '/' + backendRoute.api;
} else {
newRoute.meta.thirdLink = location.origin + '/' + backendRoute.api;
}
}
// 如果后端路由有子节点,则递归构建子路由
if (backendRoute.children && backendRoute.children.length > 0) {
newRoute.children = buildTree(backendRoute.children);
}
accessibleRoutes.push(newRoute);
} else {
// 如果在前端找不到对应配置,可以选择在这里打印一个警告,方便排查问题
console.warn(`后端返回了路由 "${backendRoute.path}",但在前端 asyncRoutes 中未找到对应配置。`);
}
}
return accessibleRoutes;
};
return buildTree(backendRoutes);
}
可以在全局路由守卫中调用
// 添加有权限的菜单
premissionStore.addRouters.forEach((ele) => {
router.addRoute(ele);
});
flattenRoutes函数中要注意一级菜单的"/"处理,要保证能匹配上,我们后台权限树中一级菜单没有"/"所以这里做了特殊处理