feat(admin): 实现动态路由菜单并修复rbac菜单树构建问题

- 修复rbac.py中菜单树构建逻辑,将`elif not menu.parentId`改为`else`,避免父菜单不存在时子菜单丢失
- 新增后端`/api/admin/system/routers`接口,作为动态路由菜单的API
- 前端新增`getRouters` API并整合到用户信息加载流程
- 添加菜单扁平化工具函数,更新路由注册逻辑以支持嵌套路由
- 新增相关测试用例并更新API和集成文档
This commit is contained in:
duanshuwen committed 2026-08-27 00:02:33 +08:00
1 parent f087663b5b
commit 2c8c327de7
12 files changed
+108 -5

No files matched your search

+35
View File
@@ -31,6 +31,7 @@
| `POST` | `/api/admin/auth/logout` | 撤销当前后台会话 |
| `GET` | `/api/admin/me` | 当前后台用户 |
| `GET` | `/api/admin/system/profile` | 当前用户、角色、权限码和动态菜单 |
| `GET` | `/api/admin/system/routers` | 按当前管理员权限返回 RuoYi 风格动态路由树 |
| `GET` | `/api/admin/system/users` | 查询后台用户 |
| `POST` | `/api/admin/system/users` | 新增后台用户 |
| `PATCH` | `/api/admin/system/users/{userId}` | 更新后台用户 |
@@ -110,6 +111,40 @@ type SiteModule =
`/api/admin/system/profile` 返回 `roles`、`permissions`、`menus`、`dataScopes` 和 `deptIds`。菜单只返回启用且可见的目录/页面,按钮菜单保留在页面节点的 `children` 中;前端组件只能从预注册组件白名单加载 `component`。
`GET /api/admin/system/routers` 是管理端对应 RuoYi `getRouters` 的独立接口。接口只要求当前管理员会话,不要求调用者拥有 `system:menu:read`,否则普通运营角色会因无法读取菜单管理页面而无法加载自己的导航。响应为:
```json
{
"code": 200,
"msg": "success",
"data": [
{
"id": "menu-id",
"name": "系统管理",
"type": "directory",
"path": "/system",
"component": null,
"permission": null,
"icon": "Setting",
"sortOrder": 60,
"children": [
{
"id": "page-id",
"name": "用户管理",
"type": "page",
"path": "/system/users",
"component": "SystemUsers",
"permission": "system:user:read",
"children": []
}
]
}
]
}
```
后端先按当前管理员角色计算可见菜单,再过滤停用菜单与不可见目录/页面;按钮菜单作为页面节点的 `children` 返回,但不会被前端注册为页面路由。`profile.menus` 继续保留以兼容旧管理端,`routers` 才是 `WonderQ-Admin-UI-Vue` 动态导航和动态路由注册的权威来源。前端只能将 `component` 映射到预注册组件白名单,未知组件不得执行或加载。
角色数据范围使用以下五个编码:`all`(全部)、`dept`(当前部门)、`dept_and_children`(当前部门及子部门)、`custom_dept`(自定义部门)、`self`(本人)。运营资源通过 `deptId` 和 `createdById` 归属字段执行查询过滤。
登录按 IP 与账号组合执行 Redis 限流,默认 60 秒最多 5 次;权限菜单缓存默认 300 秒。Redis 故障不能放行权限检查,缓存不可用时只能重新读取数据库,认证会话和限流不可用时返回 `503`。