Files
iot-device-management-frontend/packages/utils/src/helpers/generate-menus.ts

168 lines
4.2 KiB
TypeScript
Raw Normal View History

import type { Router, RouteRecordRaw } from 'vue-router';
2024-06-02 15:04:37 +08:00
import type {
AppRouteRecordRaw,
ExRouteRecordRaw,
MenuRecordRaw,
RouteMeta,
RouteRecordStringComponent,
} from '@vben-core/typings';
import { filterTree, isHttpUrl, mapTree } from '@vben-core/shared/utils';
2024-06-02 15:04:37 +08:00
/**
* routes
* @param routes -
* @param router - Vue Router
* @returns
2024-06-02 15:04:37 +08:00
*/
function generateMenus(
2024-06-02 15:04:37 +08:00
routes: RouteRecordRaw[],
router: Router,
): MenuRecordRaw[] {
2024-06-02 15:04:37 +08:00
// 将路由列表转换为一个以 name 为键的对象映射
const finalRoutesMap: { [key: string]: string } = Object.fromEntries(
router.getRoutes().map(({ name, path }) => [name, path]),
);
let menus = mapTree<ExRouteRecordRaw, MenuRecordRaw>(routes, (route) => {
// 获取最终的路由路径
const path = finalRoutesMap[route.name as string] ?? route.path ?? '';
2024-06-02 15:04:37 +08:00
const {
meta = {} as RouteMeta,
name: routeName,
redirect,
children = [],
} = route;
2024-06-02 15:04:37 +08:00
const {
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 = '',
} = meta;
2024-06-02 15:04:37 +08:00
// 确保菜单名称不为空
2024-06-02 15:04:37 +08:00
const name = (title || routeName || '') as string;
// 处理子菜单
2024-06-02 15:04:37 +08:00
const resultChildren = hideChildrenInMenu
? []
: ((children as MenuRecordRaw[]) ?? []);
2024-06-02 15:04:37 +08:00
// 设置子菜单的父子关系
if (resultChildren.length > 0) {
2024-06-02 15:04:37 +08:00
resultChildren.forEach((child) => {
child.parents = [...(route.parents ?? []), path];
2024-06-02 15:04:37 +08:00
child.parent = path;
});
}
// 确定最终路径
2024-06-08 20:14:04 +08:00
const resultPath = hideChildrenInMenu ? redirect || path : link || path;
2024-06-02 15:04:37 +08:00
return {
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,
path: resultPath,
show: !meta.hideInMenu,
children: resultChildren,
2024-06-02 15:04:37 +08:00
};
});
// 对菜单进行排序避免order=0时被替换成999的问题
menus = menus.sort((a, b) => (a?.order ?? 999) - (b?.order ?? 999));
// 过滤掉隐藏的菜单项
return filterTree(menus, (menu) => !!menu.show);
2024-06-02 15:04:37 +08:00
}
/**
*
* @param menuList
* @param parent
* @returns
*/
function convertServerMenuToRouteRecordStringComponent(
menuList: AppRouteRecordRaw[],
parent = '',
): RouteRecordStringComponent[] {
const menus: RouteRecordStringComponent[] = [];
menuList.forEach((menu) => {
// 处理顶级链接菜单
if (isHttpUrl(menu.path) && menu.parentId === 0) {
const urlMenu: RouteRecordStringComponent = {
component: 'IFrameView',
meta: {
hideInMenu: !menu.visible,
icon: menu.icon,
link: menu.path,
orderNo: menu.sort,
title: menu.name,
},
name: menu.name,
path: `/${menu.path}/index`,
};
menus.push(urlMenu);
return;
} else if (menu.children && menu.parentId === 0) {
menu.component = 'BasicLayout';
} else if (!menu.children) {
menu.component = menu.component as string;
}
if (menu.component === 'Layout') {
menu.component = 'BasicLayout';
}
if (menu.children && menu.parentId !== 0) {
menu.component = '';
}
// path
if (parent) {
menu.path = `${parent}/${menu.path}`;
}
if (!menu.path.startsWith('/')) {
menu.path = `/${menu.path}`;
}
const buildMenu: RouteRecordStringComponent = {
component: menu.component,
meta: {
hideInMenu: !menu.visible,
icon: menu.icon,
keepAlive: menu.keepAlive,
orderNo: menu.sort,
title: menu.name,
},
name: menu.name + menu.id, // add by 芋艿:防止 name 重复,加上 id
path: menu.path,
};
if (menu.children && menu.children.length > 0) {
buildMenu.children = convertServerMenuToRouteRecordStringComponent(
menu.children,
menu.path,
);
}
menus.push(buildMenu);
});
return menus;
}
export { convertServerMenuToRouteRecordStringComponent, generateMenus };