wujingjing
2024-04-22 f106e4dffb8279cb90726e83e7edd631f4c77699
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
import request, { getToken } from '/@/utils/request';
import { GetUserMenuTree } from '/@/api/login/index.js';
import { MenuTypeEnum } from '/@/api/menu/type';
import { PathRouteType } from '/@/router/pathMap';
/**
 * 以下为模拟接口地址,gitee 的不通,就换自己的真实接口地址
 *
 * (不建议写成 request.post(xxx),因为这样 post 时,无法 params 与 data 同时传参)
 *
 * 后端控制菜单模拟json,路径在 https://gitee.com/lyt-top/vue-next-admin-images/tree/master/menu
 * 后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
 * @method getAdminMenu 获取后端动态路由菜单(admin)
 * @method getTestMenu 获取后端动态路由菜单(test)
 */
export function useMenuApi() {
    return {
        // getAdminMenu: (params?: object) => {
        //     return request({
        //         url: '/src/api/istation/menuData.js',
        //         method: 'get',
        //         params,
        //     });
        // },
        getAdminMenu: GetUserMenuTree,
 
        getTestMenu: (params?: object) => {
            return request({
                url: '/gitee/lyt-top/vue-next-admin-images/raw/master/menu/testMenu.json',
                method: 'get',
                params,
            });
        },
    };
}
 
const menuProps = {
    ID: 'id',
    ParentID: 'pid',
    Type: 'type',
    Name: 'title',
    Path: 'path',
    Component: 'component',
    Redirect: 'redirect',
    Permission: 'permission',
    Icon: 'icon',
    IsIframe: 'isIframe',
    OutLink: 'isLink',
    IsHide: 'isHide',
    IsKeepAlive: 'isKeepAlive',
    IsAffix: 'isAffix',
    Weight: 'weight',
    SortCode: 'orderNo',
    Description: 'remark',
    Children: 'children',
};
 
const metaProps = ['Name', 'Icon', 'IsIframe', 'OutLink', 'IsHide', 'IsKeepAlive', 'IsAffix'];
// 找到类型为菜单的菜单,用于跳转
const findPathMenu = (menu) => {
    if (menu.type === MenuTypeEnum.Catalogue) {
        if (menu.children && menu.children.length > 0) {
            return findPathMenu(menu.children[0]);
            // 目录下面还没有子菜单
        } else {
            return '/notFound';
        }
    } else if (menu.type === MenuTypeEnum.Menu) {
        return menu.path || '/notFound';
        // 其余菜单类型
    } else {
        return '/notFound';
    }
};
 
const setCataloguePaths = (treeData: any[]) => {
    for (const item of treeData) {
        if (item.type === MenuTypeEnum.Catalogue) {
            if (item.children && item.children.length !== 0) {
                setCataloguePaths(item.children);
            }
            // 顶部菜单跳转至下层
            if (item.rootId === item.id) {
                item.path = findPathMenu(item);
                // 底部左侧菜单,保证唯一性
            } else {
                const firstChildIsHide = item?.children?.[0]?.meta?.isHide;
                // 下层有个隐藏菜单,它的 path 应该就是指向它
                if (firstChildIsHide) {
                    item.path = findPathMenu(item);
                } else {
                    item.path = '/' + item.id;
                }
            }
        } else {
            item.path = findPathMenu(item);
        }
    }
};
/**
 * 检查 outLink 上是否有关键字,比如 {token},将其替换为实际的 token
 * @param menu
 */
const handleLinkMenu = (menu) => {
    const splitArr = menu.OutLink.split('?');
    const params = splitArr.at(-1);
    const urlArr = splitArr.slice(0, -1);
    if (params) {
        if (/{\s*token\s*\}/.test(params)) {
            const token = getToken();
            const newParams = params.replace(/(?<=\s*=\s*)\{\s*token\s*\}/, token);
            urlArr.push(newParams);
            const newOutLink = urlArr.join('?');
            menu.OutLink = newOutLink;
        }
    }
};
 
export const parseMenuTree = (menuTree: any[], pathMap: Map<String, PathRouteType>) => {
    // rootId 记录根菜单的 ID,根菜单本身的 rootId 为自己
    const travelMenuTree = (menuTreeList: any[], rootId = null) => {
        return menuTreeList.map((item) => {
            const result = { meta: {} };
            // 检查带外链的网页,替换 url 参数中的特殊标志
            if (item.OutLink) {
                handleLinkMenu(item);
            }
            for (const itemKey in item) {
                if (metaProps.includes(itemKey)) {
                    result.meta[menuProps[itemKey]] = item[itemKey];
                } else {
                    result[menuProps[itemKey]] = item[itemKey];
                }
            }
            const resultAny = result as any;
 
            // 记录当前根菜单的路由 id
            resultAny.rootId = rootId === null ? item.ID : rootId;
            switch (item.Type) {
                case MenuTypeEnum.Menu:
                    if (!item.Path) {
                        break;
                    }
                    // 给菜单加入其对应的 component 等属性
                    const pathRoute = pathMap.get(item.Path);
                    if (pathRoute) {
                        resultAny.component = pathRoute.component;
                        // 命名路由
                        resultAny.name = pathRoute.name;
                        resultAny.redirect = pathRoute.redirect;
 
                        resultAny.meta.isAffix = pathRoute.isAffix;
                        resultAny.meta.isKeepAlive = pathRoute.isKeepAlive;
 
                        // 将 pathMap 的 value 置为当前 result
                        pathMap.set(item.Path, result as any);
                    }
                    break;
                case MenuTypeEnum.Catalogue:
                    if (item.Children && item.Children.length !== 0) {
                        resultAny.children = travelMenuTree(item.Children, resultAny.rootId);
                    }
                    break;
                default:
                    break;
            }
 
            return result;
        });
    };
    const treeData = travelMenuTree(menuTree);
    setCataloguePaths(treeData);
    return treeData;
};