签入版本
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
# 9.5 路由与动态菜单
|
||||
|
||||
:::tip 概述
|
||||
前端路由采用动态生成机制,从后端 `/index/getMenus` 接口获取菜单数据,自动转换为 Vue Router 路由。
|
||||
前端路由采用动态生成机制,从后端 `/api/index/getMenus` 接口获取菜单数据,自动转换为 Vue Router 路由。菜单数据由后端按用户权限过滤——**用户只能看到有权限的菜单**。
|
||||
:::
|
||||
|
||||
## 路由架构
|
||||
|
||||
```text
|
||||
静态路由(固定,src/router/index.ts + src/router/base.ts)
|
||||
静态路由(固定,ui/src/router/index.ts + ui/src/router/base.ts)
|
||||
├── /login 登录页(LoginRoute)
|
||||
├── / 根路径,重定向到首页(RootRoute)
|
||||
├── /redirect/:path 重定向路由(RedirectRoute)
|
||||
@@ -28,7 +28,8 @@
|
||||
```text
|
||||
1. 用户登录 → 获取 Token
|
||||
2. 路由守卫检测到 Token
|
||||
3. 调用 /index/getMenus 获取菜单树
|
||||
3. 调用 GET /api/index/getMenus 获取菜单树
|
||||
(后端过滤:type=0 可导航菜单、status=0 启用、hide=0 可见、is_delete=0)
|
||||
4. generator-routers.ts 将菜单树转换为路由表
|
||||
5. router.addRoute() 动态注入路由
|
||||
6. 渲染侧边栏菜单
|
||||
@@ -37,11 +38,11 @@
|
||||
## 核心代码
|
||||
|
||||
```typescript
|
||||
// src/router/generator-routers.ts
|
||||
// ui/src/router/generator-routers.ts
|
||||
|
||||
/**
|
||||
* 动态生成菜单
|
||||
* 调用后端 /index/getMenus 接口获取菜单数据
|
||||
* 调用后端 /api/index/getMenus 接口获取菜单数据
|
||||
*/
|
||||
export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -81,14 +82,18 @@ export const routerGenerator = (routerMap): any[] => {
|
||||
};
|
||||
```
|
||||
|
||||
:::tip component 映射
|
||||
后端菜单的 `component` 字段(如 `system/user/index`)由前端映射到 `views/system/user/index.vue`——菜单管理中组件路径写错会导致页面空白。见 [6.3 菜单管理](/zh/modules/menu.html)。
|
||||
:::
|
||||
|
||||
## 路由守卫
|
||||
|
||||
:::tip 动态路由流程
|
||||
详见上方 [动态路由生成流程](#动态路由生成流程) 章节,路由守卫中实现了该流程的第 2~6 步。
|
||||
上方[动态路由生成流程](#动态路由生成流程)的第 2~6 步均在路由守卫中实现。
|
||||
:::
|
||||
|
||||
```typescript
|
||||
// src/router/router-guards.ts
|
||||
// ui/src/router/router-guards.ts
|
||||
|
||||
const LOGIN_PATH = PageEnum.BASE_LOGIN;
|
||||
const whitePathList = [LOGIN_PATH]; // no redirect whitelist
|
||||
@@ -200,7 +205,7 @@ export function createRouterGuards(router: Router) {
|
||||
|
||||
## 后端菜单数据结构
|
||||
|
||||
后端 `/index/getMenus` 返回的菜单树:
|
||||
`GET /api/index/getMenus` 返回的菜单树(仅 `type=0` 可导航节点):
|
||||
|
||||
```json
|
||||
[
|
||||
@@ -221,4 +226,17 @@ export function createRouterGuards(router: Router) {
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
```
|
||||
|
||||
:::info 权限节点不进菜单树
|
||||
`type=1` 的权限节点(`permission` 非空)只参与后端接口鉴权(`Authenticate` 中间件),不会出现在 `getMenus` 返回中——前端菜单树与后端权限表是同一份 `laravel_menu` 数据的两个视图。
|
||||
:::
|
||||
|
||||
## 常见问题
|
||||
|
||||
| 现象 | 原因 | 处理 |
|
||||
|------|------|------|
|
||||
| 登录后菜单为空 | 用户无角色或角色无菜单 | 角色管理分配菜单 |
|
||||
| 点击菜单白屏 | `component` 路径错误 / views 下无对应文件 | 核对组件路径 |
|
||||
| 改了菜单不生效 | 动态路由已缓存 | 重新登录或刷新页面 |
|
||||
| 404 页覆盖真实路由 | 动态路由未加载完成就跳转 | 检查守卫第 5 步是否执行 |
|
||||
|
||||
Reference in New Issue
Block a user