ny
昨天 282fbc6488f4e8ceb5fda759f963ee88fbf7b999
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
import type { Component, DefineComponent } from 'vue';
 
import type {
  AccessModeType,
  GenerateMenuAndRoutesOptions,
  RouteRecordRaw,
} from '@vben/types';
 
import { defineComponent, h } from 'vue';
 
import { preferences, usePreferences } from '@vben/preferences';
import {
  cloneDeep,
  generateMenus,
  generateRoutesByBackend,
  generateRoutesByFrontend,
  isFunction,
  isString,
  mapTree,
} from '@vben/utils';
 
async function generateAccessible(
  mode: AccessModeType,
  options: GenerateMenuAndRoutesOptions,
) {
  const { router } = options;
 
  options.routes = cloneDeep(options.routes);
  // 生成路由
  const accessibleRoutes = await generateRoutes(mode, options);
 
  const root = router.getRoutes().find((item) => item.path === '/');
 
  // 获取已有的路由名称列表
  const names = root?.children?.map((item) => item.name) ?? [];
 
  // 动态添加到router实例内
  accessibleRoutes.forEach((route) => {
    if (root && !route.meta?.noBasicLayout) {
      // 如果包含子路由,则将component移除,以免出现多层BasicLayout
      if (route.children && route.children.length > 0) {
        delete route.component;
      }
      // 根据router name判断,如果路由已经存在,则不再添加
      if (names?.includes(route.name)) {
        // 找到已存在的路由索引并更新,不更新会造成切换用户时,一级目录未更新,homePath 在二级目录导致的404问题
        const index = root.children?.findIndex(
          (item) => item.name === route.name,
        );
        if (index !== undefined && index !== -1 && root.children) {
          root.children[index] = route;
        }
      } else {
        root.children?.push(route);
      }
    } else {
      router.addRoute(route);
    }
  });
 
  if (root) {
    if (root.name) {
      router.removeRoute(root.name);
    }
    router.addRoute(root);
  }
 
  // 生成菜单
  const accessibleMenus = generateMenus(accessibleRoutes, options.router);
 
  if (options.isAddHomeToMenu) {
    const homeItem = {
      icon: 'icon-ym icon-ym-nav-home-fill',
      i18nCode: 'routes.basic.dashboard',
      name: '控制台',
      order: undefined,
      parent: undefined,
      parents: undefined,
      path: preferences.app.defaultHomePath,
      show: true,
    };
    accessibleMenus.unshift(homeItem);
  }
 
  return { accessibleMenus, accessibleRoutes };
}
 
/**
 * Generate routes
 * @param mode
 * @param options
 */
async function generateRoutes(
  mode: AccessModeType,
  options: GenerateMenuAndRoutesOptions,
) {
  const { forbiddenComponent, roles, routes = [] } = options;
 
  let resultRoutes: RouteRecordRaw[] = [];
  switch (mode) {
    case 'backend': {
      resultRoutes = await generateRoutesByBackend(options);
      break;
    }
    case 'frontend': {
      resultRoutes = await generateRoutesByFrontend(
        routes,
        roles || [],
        forbiddenComponent,
      );
      break;
    }
    case 'mixed': {
      const [frontend_resultRoutes, backend_resultRoutes] = await Promise.all([
        generateRoutesByFrontend(routes, roles || [], forbiddenComponent),
        generateRoutesByBackend(options),
      ]);
 
      resultRoutes = [...frontend_resultRoutes, ...backend_resultRoutes];
      break;
    }
  }
 
  /**
   * 调整路由树,做以下处理:
   * 1. 对未添加redirect的路由添加redirect
   * 2. 将懒加载的组件名称修改为当前路由的名称(如果启用了keep-alive的话)
   */
 
  const { keepAlive } = usePreferences();
  resultRoutes = mapTree(resultRoutes, (route) => {
    // 重新包装component,使用与路由名称相同的name以支持keep-alive的条件缓存。
    if (
      keepAlive.value &&
      isFunction(route.component) &&
      route.name &&
      isString(route.name)
    ) {
      const originalComponent = route.component as () => Promise<{
        default: Component | DefineComponent;
      }>;
      route.component = async () => {
        const component = await originalComponent();
        if (!component.default) return component;
        return defineComponent({
          name: route.name as string,
          setup(props, { attrs, slots }) {
            return () => h(component.default, { ...props, ...attrs }, slots);
          },
        });
      };
    }
 
    // 如果有redirect或者没有子路由,则直接返回
    if (route.redirect || !route.children || route.children.length === 0) {
      return route;
    }
 
    const progenyList = getProgenyList(route.children);
    if (progenyList.length === 0) {
      return route;
    }
    const firstChild = progenyList[0];
 
    // 如果子路由不是以/开头,则直接返回,这种情况需要计算全部父级的path才能得出正确的path,这里不做处理
    if (!firstChild?.path || !firstChild.path.startsWith('/')) {
      return route;
    }
 
    route.redirect = firstChild.path;
    return route;
  });
 
  return resultRoutes;
}
 
// 获取符合条件的子集
function getProgenyList(data: any) {
  const list: any = [];
  mapTree(data, (route: any) => {
    const meta = route.meta;
    if (![0, 1, 6].includes(meta.type) || (meta.type == 7 && meta.iframeSrc)) {
      list.push(route);
    }
    return route;
  });
  return list;
}
 
export { generateAccessible };