67 lines
2.6 KiB
Markdown
67 lines
2.6 KiB
Markdown
# 9.5 路由与动态菜单
|
||
|
||
:::tip 概述
|
||
路由分两层:constant.ts 常量路由(login/redirect/403/404,登录前可访问)与动态菜单路由(登录后由 /api/index/getMenus 返回的菜单树经 generator-routers 生成)。守卫统一处理 token 校验与动态注入。
|
||
:::
|
||
|
||
## 两层路由
|
||
|
||
```text
|
||
常量路由(router/constant.ts):
|
||
login / redirect / 403 / 404 / iframe 等——无需权限,始终注册
|
||
|
||
动态菜单路由(router/generator-routers.ts):
|
||
登录 → userStore.GetInfo() → asyncRouteStore.generateRoutes(userInfo)
|
||
→ 消费 getMenus 菜单树 → 生成路由记录(component 按 path 动态 import)
|
||
→ addRoute 注入
|
||
未授权菜单不出现;超管返回全量菜单
|
||
```
|
||
|
||
## 守卫流程(router-guards.ts,真实逻辑)
|
||
|
||
```text
|
||
beforeEach:
|
||
1. URL 带 ?token= → 直接写入 ACCESS_TOKEN(免登直达场景)
|
||
2. NProgress 进度条启动
|
||
3. 白名单(login)且无 token → 放行
|
||
4. 无 token 且非 ignoreAuth → 跳登录(redirect 记录来源路径)
|
||
5. 已是动态路由已添加 → 放行
|
||
6. 首次:setDynamicAddedRoute(true) → GetInfo() → generateRoutes
|
||
→ 动态路由注入 → next(to fullPath) 重进
|
||
```
|
||
|
||
## 菜单 → 路由 → 页面的映射
|
||
|
||
```text
|
||
后端 menu 表(type=0 菜单):
|
||
path = "/{domain}/{moduleCamel}" 如 /content/article
|
||
component = path + "/index" 如 /content/article/index
|
||
icon / name / sort / hide
|
||
|
||
前端 generator-routers:
|
||
path 匹配 → component 动态 import(views/{path}.vue)
|
||
hide=1 的菜单不渲染
|
||
sort 控制侧栏顺序
|
||
```
|
||
|
||
生成器创建菜单(createMenu 副作用)保证 path/component 与前端文件路径一致——这是"生成即可用"的前提。
|
||
|
||
## 路由图标与菜单辅助
|
||
|
||
```text
|
||
router-icons.ts 图标解析(menu.icon → 组件映射)
|
||
router/menus/ 菜单数据结构辅助
|
||
base.ts ErrorPageRoute / AboutPageRoute / SettingPageRoute 等基础路由
|
||
findFirstRoutePath 首个可达路由定位(登录后跳转首页)
|
||
```
|
||
|
||
## 排障
|
||
|
||
| 症状 | 原因 |
|
||
|------|------|
|
||
| 登录后 404 | 动态路由 component 路径与实际文件不符(菜单 component 值错) |
|
||
| 菜单空白 | getMenus 返回空(无角色/未勾选菜单);超管应全量 |
|
||
| 刷新页面 404 | 动态路由未重新注入——守卫应重跑 generateRoutes;检查 isDynamicAddedRoute 状态 |
|
||
| 直接访问子路由被踢登录 | 无 token;守卫 redirect 记录来源 |
|
||
| 新模块菜单点了 404 | 生成器菜单 component 与前端产出路径不一致;对照 path/domain |
|