2024-07-23 00:03:59 +08:00
|
|
|
|
import type { Router, RouteRecordRaw } from 'vue-router';
|
2024-06-02 15:04:37 +08:00
|
|
|
|
|
2025-05-03 18:05:26 +08:00
|
|
|
|
import type {
|
|
|
|
|
ExRouteRecordRaw,
|
|
|
|
|
MenuRecordRaw,
|
|
|
|
|
RouteMeta,
|
|
|
|
|
} from '@vben-core/typings';
|
2025-01-01 11:39:49 +08:00
|
|
|
|
|
2024-09-10 21:48:51 +08:00
|
|
|
|
import { filterTree, mapTree } from '@vben-core/shared/utils';
|
2024-06-02 15:04:37 +08:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据 routes 生成菜单列表
|
2025-05-03 18:05:26 +08:00
|
|
|
|
* @param routes - 路由配置列表
|
|
|
|
|
* @param router - Vue Router 实例
|
|
|
|
|
* @returns 生成的菜单列表
|
2024-06-02 15:04:37 +08:00
|
|
|
|
*/
|
2025-05-03 18:05:26 +08:00
|
|
|
|
function generateMenus(
|
2024-06-02 15:04:37 +08:00
|
|
|
|
routes: RouteRecordRaw[],
|
|
|
|
|
router: Router,
|
2025-05-03 18:05:26 +08:00
|
|
|
|
): MenuRecordRaw[] {
|
2024-06-02 15:04:37 +08:00
|
|
|
|
// 将路由列表转换为一个以 name 为键的对象映射
|
|
|
|
|
const finalRoutesMap: { [key: string]: string } = Object.fromEntries(
|
|
|
|
|
router.getRoutes().map(({ name, path }) => [name, path]),
|
|
|
|
|
);
|
|
|
|
|
|
2024-06-02 21:33:31 +08:00
|
|
|
|
let menus = mapTree<ExRouteRecordRaw, MenuRecordRaw>(routes, (route) => {
|
2025-05-03 18:05:26 +08:00
|
|
|
|
// 获取最终的路由路径
|
|
|
|
|
const path = finalRoutesMap[route.name as string] ?? route.path ?? '';
|
2024-06-02 15:04:37 +08:00
|
|
|
|
|
2025-05-03 18:05:26 +08:00
|
|
|
|
const {
|
|
|
|
|
meta = {} as RouteMeta,
|
|
|
|
|
name: routeName,
|
|
|
|
|
redirect,
|
|
|
|
|
children = [],
|
|
|
|
|
} = route;
|
2024-06-02 15:04:37 +08:00
|
|
|
|
const {
|
2024-07-28 14:29:05 +08:00
|
|
|
|
activeIcon,
|
2024-06-02 15:04:37 +08:00
|
|
|
|
badge,
|
|
|
|
|
badgeType,
|
|
|
|
|
badgeVariants,
|
|
|
|
|
hideChildrenInMenu = false,
|
|
|
|
|
icon,
|
2024-06-08 20:14:04 +08:00
|
|
|
|
link,
|
2024-06-02 23:46:18 +08:00
|
|
|
|
order,
|
2024-06-02 15:04:37 +08:00
|
|
|
|
title = '',
|
2025-05-03 18:05:26 +08:00
|
|
|
|
} = meta;
|
2024-06-02 15:04:37 +08:00
|
|
|
|
|
2025-05-03 18:05:26 +08:00
|
|
|
|
// 确保菜单名称不为空
|
2024-06-02 15:04:37 +08:00
|
|
|
|
const name = (title || routeName || '') as string;
|
|
|
|
|
|
2025-05-03 18:05:26 +08:00
|
|
|
|
// 处理子菜单
|
2024-06-02 15:04:37 +08:00
|
|
|
|
const resultChildren = hideChildrenInMenu
|
|
|
|
|
? []
|
|
|
|
|
: (children as MenuRecordRaw[]);
|
|
|
|
|
|
2025-05-03 18:05:26 +08:00
|
|
|
|
// 设置子菜单的父子关系
|
|
|
|
|
if (resultChildren.length > 0) {
|
2024-06-02 15:04:37 +08:00
|
|
|
|
resultChildren.forEach((child) => {
|
2025-05-03 18:05:26 +08:00
|
|
|
|
child.parents = [...(route.parents ?? []), path];
|
2024-06-02 15:04:37 +08:00
|
|
|
|
child.parent = path;
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-05-03 18:05:26 +08:00
|
|
|
|
|
|
|
|
|
// 确定最终路径
|
2024-06-08 20:14:04 +08:00
|
|
|
|
const resultPath = hideChildrenInMenu ? redirect || path : link || path;
|
2025-05-03 18:05:26 +08:00
|
|
|
|
|
2024-06-02 15:04:37 +08:00
|
|
|
|
return {
|
2024-07-28 14:29:05 +08:00
|
|
|
|
activeIcon,
|
2024-06-02 15:04:37 +08:00
|
|
|
|
badge,
|
|
|
|
|
badgeType,
|
|
|
|
|
badgeVariants,
|
|
|
|
|
icon,
|
|
|
|
|
name,
|
2024-06-02 23:46:18 +08:00
|
|
|
|
order,
|
2024-06-02 15:04:37 +08:00
|
|
|
|
parent: route.parent,
|
|
|
|
|
parents: route.parents,
|
2025-05-03 18:05:26 +08:00
|
|
|
|
path: resultPath,
|
|
|
|
|
show: !meta.hideInMenu,
|
|
|
|
|
children: resultChildren,
|
2024-06-02 15:04:37 +08:00
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
2025-03-20 19:41:46 +08:00
|
|
|
|
// 对菜单进行排序,避免order=0时被替换成999的问题
|
|
|
|
|
menus = menus.sort((a, b) => (a?.order ?? 999) - (b?.order ?? 999));
|
2024-07-19 01:26:13 +08:00
|
|
|
|
|
2025-05-03 18:05:26 +08:00
|
|
|
|
// 过滤掉隐藏的菜单项
|
|
|
|
|
return filterTree(menus, (menu) => !!menu.show);
|
2024-06-02 15:04:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-30 15:03:37 +08:00
|
|
|
|
export { generateMenus };
|