menuHelper.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import { AppRouteModule } from '@/router/types';
  2. import type { MenuModule, Menu, AppRouteRecordRaw } from '@/router/types';
  3. import { findPath, treeMap } from '@/utils/helper/treeHelper';
  4. import { cloneDeep } from 'lodash-es';
  5. import { isHttpUrl } from '@/utils/is';
  6. import { RouteParams } from 'vue-router';
  7. import { toRaw } from 'vue';
  8. export function getAllParentPath<T = Recordable>(treeData: T[], path: string) {
  9. const menuList = findPath(treeData, (n) => n.path === path) as Menu[];
  10. return (menuList || []).map((item) => item.path);
  11. }
  12. // 路径处理
  13. function joinParentPath(menus: Menu[], parentPath = '') {
  14. for (let index = 0; index < menus.length; index++) {
  15. const menu = menus[index];
  16. // https://next.router.vuejs.org/guide/essentials/nested-routes.html
  17. // Note that nested paths that start with / will be treated as a root path.
  18. // 请注意,以 / 开头的嵌套路径将被视为根路径。
  19. // This allows you to leverage the component nesting without having to use a nested URL.
  20. // 这允许你利用组件嵌套,而无需使用嵌套 URL。
  21. if (!(menu.path.startsWith('/') || isHttpUrl(menu.path))) {
  22. // path doesn't start with /, nor is it a url, join parent path
  23. // 路径不以 / 开头,也不是 url,加入父路径
  24. menu.path = `${parentPath}/${menu.path}`;
  25. }
  26. if (menu?.children?.length) {
  27. joinParentPath(menu.children, menu.meta?.hidePathForChildren ? parentPath : menu.path);
  28. }
  29. }
  30. }
  31. // Parsing the menu module
  32. export function transformMenuModule(menuModule: MenuModule): Menu {
  33. const { menu } = menuModule;
  34. const menuList = [menu];
  35. joinParentPath(menuList);
  36. return menuList[0];
  37. }
  38. // 将路由转换成菜单
  39. export function transformRouteToMenu(routeModList: AppRouteModule[], routerMapping = false) {
  40. // 借助 lodash 深拷贝
  41. const cloneRouteModList = cloneDeep(routeModList);
  42. const routeList: AppRouteRecordRaw[] = [];
  43. // 对路由项进行修改
  44. cloneRouteModList.forEach((item) => {
  45. if (routerMapping && item.meta.hideChildrenInMenu && typeof item.redirect === 'string') {
  46. item.path = item.redirect;
  47. }
  48. if (item.meta?.single) {
  49. const realItem = item?.children?.[0];
  50. realItem && routeList.push(realItem);
  51. } else {
  52. routeList.push(item);
  53. }
  54. });
  55. // 提取树指定结构
  56. const list = treeMap(routeList, {
  57. conversion: (node: AppRouteRecordRaw) => {
  58. const { meta: { title, hideMenu = false } = {} } = node;
  59. return {
  60. ...(node.meta || {}),
  61. meta: node.meta,
  62. name: title,
  63. hideMenu,
  64. path: node.path,
  65. ...(node.redirect ? { redirect: node.redirect } : {}),
  66. };
  67. },
  68. });
  69. // 路径处理
  70. joinParentPath(list);
  71. return cloneDeep(list);
  72. }
  73. /**
  74. * config menu with given params
  75. */
  76. const menuParamRegex = /(?::)([\s\S]+?)((?=\/)|$)/g;
  77. export function configureDynamicParamsMenu(menu: Menu, params: RouteParams) {
  78. const { path, paramPath } = toRaw(menu);
  79. let realPath = paramPath ? paramPath : path;
  80. const matchArr = realPath.match(menuParamRegex);
  81. matchArr?.forEach((it) => {
  82. const realIt = it.substr(1);
  83. if (params[realIt]) {
  84. realPath = realPath.replace(`:${realIt}`, params[realIt] as string);
  85. }
  86. });
  87. // save original param path.
  88. if (!paramPath && matchArr && matchArr.length > 0) {
  89. menu.paramPath = path;
  90. }
  91. menu.path = realPath;
  92. // children
  93. menu.children?.forEach((item) => configureDynamicParamsMenu(item, params));
  94. }