办学质量监测教学评价系统
康鲁杰
6 天以前 5d25c5c99bd13ffeb4750c029ebf84adf099681b
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
import type { Component, DefineComponent } from 'vue';
 
import type {
  AccessModeType,
  GenerateMenuAndRoutesOptions,
  RouteRecordRaw,
} from '@vben/types';
 
import { defineComponent, h } from 'vue';
 
import {
  cloneDeep,
  generateMenus,
  generateRoutesByBackend,
  generateRoutesByFrontend,
  isFunction,
  isString,
  mapTree,
  setObjToUrlParams,
} 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 === '/');
 
  // 动态添加到router实例内
  accessibleRoutes.forEach((route) => {
    /**
     * 外链不应该被添加到路由 由menu处理
     */
    if (/^https?:\/\//.test(route.path)) {
      return;
    }
    if (root && !route.meta?.noBasicLayout) {
      // 为了兼容之前的版本用法,如果包含子路由,则将component移除,以免出现多层BasicLayout
      // 如果你的项目已经跟进了本次修改,移除了所有自定义菜单首级的BasicLayout,可以将这段if代码删除
      // TODO: 这里后期需要follow更新
      if (route.children && route.children.length > 0) {
        delete route.component;
      }
      root.children?.push(route);
    } else {
      router.addRoute(route);
    }
  });
 
  if (root) {
    if (root.name) {
      router.removeRoute(root.name);
    }
    router.addRoute(root);
  }
 
  // 生成菜单
  const accessibleMenus = await generateMenus(accessibleRoutes, options.router);
 
  return { accessibleMenus, accessibleRoutes };
}
 
/**
 * Generate routes
 * @param mode
 * @param options
 */
async function generateRoutes(
  mode: AccessModeType,
  options: GenerateMenuAndRoutesOptions,
) {
  const { forbiddenComponent, roles, routes } = options;
 
  let resultRoutes: RouteRecordRaw[] = routes;
  switch (mode) {
    case 'backend': {
      resultRoutes = await generateRoutesByBackend(options);
      break;
    }
    case 'frontend': {
      resultRoutes = await generateRoutesByFrontend(
        routes,
        roles || [],
        forbiddenComponent,
      );
      break;
    }
  }
 
  /**
   * 调整路由树,做以下处理:
   * 1. 对未添加redirect的路由添加redirect
   * 2. 将懒加载的组件名称修改为当前路由的名称(如果启用了keep-alive的话)
   */
  resultRoutes = mapTree(resultRoutes, (route) => {
    // 重新包装component,使用与路由名称相同的name以支持keep-alive的条件缓存。
    if (
      route.meta?.keepAlive &&
      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 firstChild = route.children[0];
 
    // 如果子路由不是以/开头,则直接返回,这种情况需要计算全部父级的path才能得出正确的path,这里不做处理
    if (!firstChild?.path || !firstChild.path.startsWith('/')) {
      return route;
    }
 
    // 第一个路由如果有query参数 需要加上参数
    const fistChildQuery = route.children[0]?.meta?.query;
    // 根目录菜单固定只有一个children 且path为/ 不需要添加redirect
    route.redirect =
      fistChildQuery && route.children.length !== 1 && route.path !== '/'
        ? setObjToUrlParams(firstChild.path, fistChildQuery)
        : firstChild.path;
 
    return route;
  });
 
  return resultRoutes;
}
 
export { generateAccessible };