accessible.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import type {
  2. AccessModeType,
  3. GenerateMenuAndRoutesOptions,
  4. RouteRecordRaw,
  5. } from '@vben/types';
  6. import {
  7. cloneDeep,
  8. generateMenus,
  9. generateRoutesByBackend,
  10. generateRoutesByFrontend,
  11. mapTree,
  12. setObjToUrlParams,
  13. } from '@vben/utils';
  14. async function generateAccessible(
  15. mode: AccessModeType,
  16. options: GenerateMenuAndRoutesOptions,
  17. ) {
  18. const { router } = options;
  19. options.routes = cloneDeep(options.routes);
  20. // 生成路由
  21. const accessibleRoutes = await generateRoutes(mode, options);
  22. // 动态添加到router实例内
  23. accessibleRoutes.forEach((route) => {
  24. /**
  25. * 外链不应该被添加到路由 由menu处理
  26. */
  27. if (/^https?:\/\//.test(route.path)) {
  28. return;
  29. }
  30. router.addRoute(route);
  31. });
  32. // 生成菜单
  33. const accessibleMenus = await generateMenus(accessibleRoutes, options.router);
  34. return { accessibleMenus, accessibleRoutes };
  35. }
  36. /**
  37. * Generate routes
  38. * @param mode
  39. * @param options
  40. */
  41. async function generateRoutes(
  42. mode: AccessModeType,
  43. options: GenerateMenuAndRoutesOptions,
  44. ) {
  45. const { forbiddenComponent, roles, routes } = options;
  46. let resultRoutes: RouteRecordRaw[] = routes;
  47. switch (mode) {
  48. case 'backend': {
  49. resultRoutes = await generateRoutesByBackend(options);
  50. break;
  51. }
  52. case 'frontend': {
  53. resultRoutes = await generateRoutesByFrontend(
  54. routes,
  55. roles || [],
  56. forbiddenComponent,
  57. );
  58. break;
  59. }
  60. }
  61. /**
  62. * 调整路由树,做以下处理:
  63. * 1. 对未添加redirect的路由添加redirect
  64. */
  65. resultRoutes = mapTree(resultRoutes, (route) => {
  66. // 如果有redirect或者没有子路由,则直接返回
  67. if (route.redirect || !route.children || route.children.length === 0) {
  68. return route;
  69. }
  70. const firstChild = route.children[0];
  71. // 如果子路由不是以/开头,则直接返回,这种情况需要计算全部父级的path才能得出正确的path,这里不做处理
  72. if (!firstChild?.path || !firstChild.path.startsWith('/')) {
  73. return route;
  74. }
  75. // 第一个路由如果有query参数 需要加上参数
  76. const fistChildQuery = route.children[0]?.meta?.query;
  77. // 根目录菜单固定只有一个children 且path为/ 不需要添加redirect
  78. route.redirect =
  79. fistChildQuery && route.children.length !== 1 && route.path !== '/'
  80. ? setObjToUrlParams(firstChild.path, fistChildQuery)
  81. : firstChild.path;
  82. return route;
  83. });
  84. return resultRoutes;
  85. }
  86. export { generateAccessible };