import { createComponentLoader } from '@/utils/pathResolver'; // 工具函数:将扁平菜单转换为嵌套路由 export function convertMenusToRoutes(menus) { // 1. 构建父子关系映射 const menuMap = {}; const routes = []; // 先将所有菜单存入映射表 menus.forEach(menu => { // 处理路径:去掉前导斜杠,因为是子路由 let routePath = menu.path.startsWith('/') ? menu.path.substring(1) : menu.path; menuMap[menu.id] = { path: routePath, name: `menu_${menu.id}`, // 使用唯一名称 meta: { icon: menu.icon, title: menu.name, id: menu.id, parentId: menu.parentId, menuPath: menu.path // 保存原始路径(完整路径,如 /dashboard) }, // 有组件路径才添加 component(目录菜单可能没有) // componentPath 格式: /dashboard/index.vue (来自数据库) // 使用通用工具自动转换为别名路径并加载 ...(menu.componentPath ? { component: createComponentLoader(menu.componentPath) } : {}) }; }); // 2. 构建嵌套关系,并修正子路由路径 menus.forEach(menu => { const currentRoute = menuMap[menu.id]; if (menu.parentId === 0) { // 顶级菜单直接加入路由 routes.push(currentRoute); } else { // 子菜单添加到父菜单的 children 中 const parentRoute = menuMap[menu.parentId]; if (parentRoute) { // 修正子路由路径:使用原始菜单路径来准确匹配 // 使用原始路径(menuPath)来准确计算相对路径 const parentOriginalPath = parentRoute.meta?.menuPath || parentRoute.path; const childOriginalPath = currentRoute.meta?.menuPath || currentRoute.path; // 确保路径格式一致(去掉前导斜杠) const parentPath = parentOriginalPath.startsWith('/') ? parentOriginalPath.substring(1) : parentOriginalPath; const childFullPath = childOriginalPath.startsWith('/') ? childOriginalPath.substring(1) : childOriginalPath; // 如果子路径以父路径开头,则只保留剩余部分 if (childFullPath.startsWith(parentPath + '/')) { currentRoute.path = childFullPath.substring(parentPath.length + 1); // "users" 或 "knowledge/category" } else { // 如果子路径不以父路径开头,尝试直接使用子路径的最后一部分 // 这处理了路径不连续的情况 const pathParts = childFullPath.split('/'); const parentPathParts = parentPath.split('/'); // 找到子路径相对于父路径的部分 if (pathParts.length > parentPathParts.length) { currentRoute.path = pathParts.slice(parentPathParts.length).join('/'); } else { // 如果无法确定相对路径,使用最后一个路径段 currentRoute.path = pathParts[pathParts.length - 1]; } } // 特殊处理:知识库的编辑和详情页需要支持动态参数 // 如果最终路径是 edit 或 detail,转换为支持参数的路由 if (currentRoute.path === 'edit') { currentRoute.path = 'edit/:id'; } else if (currentRoute.path === 'detail') { currentRoute.path = 'detail/:id'; } if (!parentRoute.children) { parentRoute.children = []; } parentRoute.children.push(currentRoute); } else { // 如果找不到父路由,作为顶级路由处理 routes.push(currentRoute); } } }); // 2.5. 为有子路由但没有 component 的父路由自动添加默认组件 const addDefaultComponent = (routeList) => { routeList.forEach(route => { // 如果路由有子路由但没有组件,尝试添加默认组件 if (route.children && route.children.length > 0 && !route.component) { // 使用原始菜单路径(menuPath)来推断组件路径,而不是修正后的路径 const originalPath = route.meta?.menuPath || route.path; // 确保路径以 / 开头 const normalizedPath = originalPath.startsWith('/') ? originalPath : `/${originalPath}`; const defaultComponentPath = `${normalizedPath}/index.vue`; const defaultComponent = createComponentLoader(defaultComponentPath); if (defaultComponent) { route.component = defaultComponent; } } // 递归处理子路由 if (route.children && route.children.length > 0) { addDefaultComponent(route.children); } }); }; addDefaultComponent(routes); // 3. 按 order 排序 const sortRoutes = (routesList) => { routesList.sort((a, b) => { const orderA = menus.find(m => m.id === a.meta.id)?.order || 0; const orderB = menus.find(m => m.id === b.meta.id)?.order || 0; return orderA - orderB; }); routesList.forEach(route => { if (route.children && route.children.length > 0) { sortRoutes(route.children); } }); }; sortRoutes(routes); return routes; }