vue-vben-admin/src/router/helper/menuHelper.ts

107 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { AppRouteModule } from '/@/router/types';
import type { MenuModule, Menu, AppRouteRecordRaw } from '/@/router/types';
import { findPath, treeMap } from '/@/utils/helper/treeHelper';
import { cloneDeep } from 'lodash-es';
import { isUrl } from '/@/utils/is';
import { RouteParams } from 'vue-router';
import { toRaw } from 'vue';
export function getAllParentPath<T = Recordable>(treeData: T[], path: string) {
const menuList = findPath(treeData, (n) => n.path === path) as Menu[];
return (menuList || []).map((item) => item.path);
}
// 路径处理
function joinParentPath(menus: Menu[], parentPath = '') {
for (let index = 0; index < menus.length; index++) {
const menu = menus[index];
// https://next.router.vuejs.org/guide/essentials/nested-routes.html
// Note that nested paths that start with / will be treated as a root path.
// 请注意,以 / 开头的嵌套路径将被视为根路径。
// This allows you to leverage the component nesting without having to use a nested URL.
// 这允许你利用组件嵌套,而无需使用嵌套 URL。
if (!(menu.path.startsWith('/') || isUrl(menu.path))) {
// path doesn't start with /, nor is it a url, join parent path
// 路径不以 / 开头,也不是 url加入父路径
menu.path = `${parentPath}/${menu.path}`;
}
if (menu?.children?.length) {
joinParentPath(menu.children, menu.meta?.hidePathForChildren ? parentPath : menu.path);
}
}
}
// Parsing the menu module
export function transformMenuModule(menuModule: MenuModule): Menu {
const { menu } = menuModule;
const menuList = [menu];
joinParentPath(menuList);
return menuList[0];
}
// 将路由转换成菜单
export function transformRouteToMenu(routeModList: AppRouteModule[], routerMapping = false) {
// 借助 lodash 深拷贝
const cloneRouteModList = cloneDeep(routeModList);
const routeList: AppRouteRecordRaw[] = [];
// 对路由项进行修改
cloneRouteModList.forEach((item) => {
if (routerMapping && item.meta.hideChildrenInMenu && typeof item.redirect === 'string') {
item.path = item.redirect;
}
if (item.meta?.single) {
const realItem = item?.children?.[0];
realItem && routeList.push(realItem);
} else {
routeList.push(item);
}
});
// 提取树指定结构
const list = treeMap(routeList, {
conversion: (node: AppRouteRecordRaw) => {
const { meta: { title, hideMenu = false } = {} } = node;
return {
...(node.meta || {}),
meta: node.meta,
name: title,
hideMenu,
path: node.path,
...(node.redirect ? { redirect: node.redirect } : {}),
};
},
});
// 路径处理
joinParentPath(list);
return cloneDeep(list);
}
/**
* config menu with given params
*/
const menuParamRegex = /(?::)([\s\S]+?)((?=\/)|$)/g;
export function configureDynamicParamsMenu(menu: Menu, params: RouteParams) {
const { path, paramPath } = toRaw(menu);
let realPath = paramPath ? paramPath : path;
const matchArr = realPath.match(menuParamRegex);
matchArr?.forEach((it) => {
const realIt = it.substr(1);
if (params[realIt]) {
realPath = realPath.replace(`:${realIt}`, params[realIt] as string);
}
});
// save original param path.
if (!paramPath && matchArr && matchArr.length > 0) {
menu.paramPath = path;
}
menu.path = realPath;
// children
menu.children?.forEach((item) => configureDynamicParamsMenu(item, params));
}