wangzhibo
6 天以前 da0230346106bc810664488a2b152bc24f853a44
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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
import { ElMessage } from 'element-plus';
import {
    createRouter,
    createRouterMatcher,
    createWebHashHistory,
    createWebHistory,
    type RouteRecordRaw
} from 'vue-router';
import { type Router, storage, module } from '/@/cool';
import { isArray } from 'lodash-es';
import { useBase } from '/$/base';
import { Loading } from '../utils';
import { config, isDev } from '/@/config';
 
// 基本路径
const baseUrl = import.meta.env.BASE_URL;
 
// 扫描文件
const files = import.meta.glob(['/src/modules/*/{views,pages}/**/*', '!**/components']);
 
// 默认路由
const routes: RouteRecordRaw[] = [
    {
        path: '/',
        name: 'index',
        component: () => import('/$/base/pages/main/index.vue'),
        children: []
    },
    {
        path: '/:catchAll(.*)',
        name: '404',
        component: () => import('/$/base/pages/error/404.vue')
    }
];
 
// 创建路由器
const router = createRouter({
    history:
        config.app.router.mode == 'history'
            ? createWebHistory(baseUrl)
            : createWebHashHistory(baseUrl),
    routes
}) as Router;
 
// 组件加载后
router.beforeResolve(() => {
    Loading.close();
});
 
let lock = false;
 
// 错误监听
router.onError((error: Error) => {
    if (!lock) {
        lock = true;
 
        // 显示错误信息
        ElMessage.error(`页面存在错误:${error.message}`);
        console.error(error);
 
        // 如果是动态加载模块失败的错误,且非开发环境,则刷新页面
        if (error.message?.includes('Failed to fetch dynamically imported module')) {
            if (!isDev) {
                window.location.reload();
            }
        }
 
        // 短暂延迟后解锁,允许后续错误处理
        setTimeout(() => {
            lock = false;
        }, 0);
    }
});
 
// 添加视图,页面路由
router.append = function (routeData) {
    if (!routeData) {
        return false; // 如果没有路由数据,直接返回
    }
 
    // 确保 routeData 是数组
    const routeList = isArray(routeData) ? routeData : [routeData];
 
    routeList.forEach(route => {
        if (!route.meta) {
            route.meta = {}; // 初始化 meta 对象
        }
 
        // 如果没有指定组件路径
        if (!route.component) {
            const viewPath = route.viewPath;
 
            if (viewPath) {
                if (viewPath.startsWith('http')) {
                    // 如果是外部链接,使用 iframe 组件
                    route.meta.iframeUrl = viewPath;
                    route.component = () => import('/$/base/views/frame.vue');
                } else {
                    // 从文件系统中动态导入组件
                    route.component = files['/src/' + viewPath.replace('cool/', '')];
                }
            } else if (!route.redirect) {
                // 如果没有组件路径且没有重定向,默认重定向到 404
                route.redirect = '/404';
            }
        }
 
        // 支持 props 接收参数
        route.props = true;
 
        // 标记为动态添加的路由
        route.meta.dynamic = true;
 
        // 判断是页面还是视图,并添加到相应的路由
        if (route.isPage || route.viewPath?.includes('/pages/')) {
            router.addRoute(route);
        } else {
            router.addRoute('index', route);
        }
    });
};
 
// 删除路由
router.del = function (routeName) {
    const allRoutes = router.getRoutes();
 
    allRoutes.forEach(route => {
        if (route.name === routeName) {
            router.removeRoute(routeName); // 移除指定名称的路由
        }
    });
};
 
// 清空路由
router.clear = function () {
    const allRoutes = router.getRoutes();
 
    allRoutes.forEach(route => {
        if (route.name && route.meta?.dynamic) {
            router.removeRoute(route.name); // 移除所有动态添加的路由
        }
    });
};
 
// 找路由
router.find = function (path: string) {
    const { menu } = useBase();
 
    // 获取已注册的路由
    const registeredRoutes = router.getRoutes();
 
    // 构建路由列表,包括已注册的路由、菜单配置和模块自定义路由
    const routeList: any[] = [
        ...registeredRoutes.map(route => ({
            ...route,
            isReg: true
        })),
        ...menu.routes,
        ...module.list.flatMap(module => (module.views || []).concat(module.pages || []))
    ];
 
    let isRegistered = false;
    let matchedRoute: (typeof routeList)[number] | undefined;
 
    // 创建路由匹配器
    const matcher = createRouterMatcher(routeList, {});
 
    // 查找匹配的路由
    matcher.getRoutes().find(route => {
        const routeRegex = new RegExp(route.re);
 
        if (routeRegex.test(path)) {
            if (path === '/') {
                // 如果路径是根路径,查找标记为首页的路由
                matchedRoute = routeList.find(route => route.meta?.isHome);
            } else {
                // 否则查找路径匹配且名称不是 'index' 的路由
                matchedRoute = routeList.find(
                    r => r.path === route.record.path && r.name !== 'index'
                );
            }
 
            if (matchedRoute) {
                isRegistered = !!matchedRoute.isReg; // 检查路由是否已注册
            }
 
            return true;
        }
        return false;
    });
 
    return {
        route: matchedRoute,
        isReg: isRegistered
    };
};
 
// 路由守卫
router.beforeEach(async (to, from, next) => {
    // 等待应用配置加载完
    await Loading.wait();
 
    // 获取用户和进程数据
    const { user, process } = useBase();
 
    // 查找路由信息
    const { isReg, route } = router.find(to.path);
 
    // 如果路由不存在
    if (!route) {
        next(user.token ? '/404' : '/login'); // 根据用户登录状态重定向
        return;
    }
 
    // 如果路由未注册
    if (!isReg) {
        router.append(route); // 注册路由
        next(to.fullPath); // 重定向到原路径
        return;
    }
 
    // 如果用户已登录
    if (user.token) {
        if (to.path.includes('/login')) {
            // 如果在登录页且 Token 未过期,重定向到首页
            if (!storage.isExpired('token')) {
                next('/');
                return;
            }
        } else {
            process.add(to); // 添加路由进程
        }
    } else {
        // 清除用户信息
        user.clear();
 
        // 如果路径不在忽略 Token 验证的列表中,重定向到登录页
        if (!config.ignore.token.some(ignorePath => to.path === ignorePath)) {
            next('/login');
            return;
        }
    }
 
    next(); // 继续导航
});
 
export { router };