feat(admin, admin-ui): 实现RuoYi风格后台菜单管理,优化媒体资源处理

新增服务端菜单校验与归一化逻辑,完善菜单相关Schema;前端实现条件渲染的菜单编辑器,支持搜索式图标选择器与父级树过滤。新增媒体URL统一处理工具修复管理端本地静态资源路径映射问题,更新全部相关文档、技术决策记录与测试用例。本次变更不影响WonderQ-MiniAPP端。
This commit is contained in:
duanshuwen
2026-08-27 09:08:05 +08:00
parent 6245159e7c
commit 4c245f0d1f
28 changed files with 625 additions and 36 deletions

View File

@@ -31,7 +31,7 @@ MiniAPP 或 Public API 联调:
| `detail-api.md` | 路线详情管理 API | 后端、管理前端 |
| `concierge-api.md` | 管家顾问管理 API | 后端、管理前端 |
| `public-api.md` | MiniAPP 使用的 Public API 唯一契约 | 后端、MiniAPP |
| `decisions/` | 当前重要技术决策记录 | 全部 |
| `decisions/` | 当前重要技术决策记录,包括菜单父子层级和编辑器约束 | 全部 |
## 文档边界

View File

@@ -180,6 +180,20 @@ type SiteModule =
后端先按当前管理员角色计算可见菜单,再过滤停用菜单与不可见目录/页面;按钮菜单作为页面节点的 `children` 返回,但不会被前端注册为页面路由。`profile.menus` 继续保留以兼容旧管理端,`routers` 才是 `WonderQ-Admin-UI-Vue` 动态导航和动态路由注册的权威来源。前端只能将 `component` 映射到预注册组件白名单,未知组件不得执行或加载。
### 菜单管理新增/编辑
`GET /api/admin/system/menus` 返回平铺 `items` 和按 `parentId` 组装的 `tree`。每个节点包含 `parentId``name``type``path``component``permission``icon``sortOrder``isVisible``isActive``children`,用于菜单工作台、角色授权树和新增/编辑菜单的父级选择。
`POST /api/admin/system/menus``PATCH /api/admin/system/menus/{id}` 使用以下菜单类型规则:
- `directory`(目录):必须有路由地址;不使用组件路径和权限标识。
- `page`(页面):必须有路由地址和预注册组件路径;可填写权限标识。
- `button`(按钮):必须填写权限标识;路由地址、组件路径和菜单图标必须为空,按钮不能作为其他菜单的父级。
顶级菜单的 `parentId``null`。父级必须存在且为目录或页面;更新菜单时不能选择自身或其子孙节点,服务端也会重复校验该规则。名称和文本字段会去除首尾空格;权限标识重复返回 `409`,类型字段缺失或不符合规则返回 `422`。菜单新增、编辑、删除和排序继续写入审计日志并清理权限菜单缓存。
Vue 管理端的父级树只展示目录/页面,编辑当前菜单时排除当前分支;图标选择器使用 `@element-plus/icons-vue` 的受控白名单,支持名称搜索、清空和未知值回退默认图标,不执行服务端返回的组件或图标路径。
角色数据范围使用以下五个编码:`all`(全部)、`dept`(当前部门)、`dept_and_children`(当前部门及子部门)、`custom_dept`(自定义部门)、`self`(本人)。运营资源通过 `deptId``createdById` 归属字段执行查询过滤。
登录按 IP 与账号组合执行 Redis 限流,默认 60 秒最多 5 次;权限菜单缓存默认 300 秒。Redis 故障不能放行权限检查,缓存不可用时只能重新读取数据库,认证会话和限流不可用时返回 `503`

View File

@@ -0,0 +1,25 @@
# 0003 后台菜单父子树与 RuoYi 风格编辑器
## 状态
已采纳。
## 决策
WonderQ 菜单继续使用服务端 `AdminMenu.parentId` 自引用关系,并由 `GET /api/admin/system/menus` 同时提供平铺数据和树形数据。管理端新增/编辑菜单按 RuoYi 的目录、页面、按钮模式展示条件字段:目录只维护路由,页面维护路由、预注册组件和权限标识,按钮只维护权限标识。
父级菜单只能选择目录或页面;编辑时前端从选择树中移除当前分支,后端再次校验父级存在、父级类型和循环归属。权限标识冲突返回 `409`,非法类型字段返回 `422`,避免仅依赖前端校验造成脏数据。
菜单图标使用 `@element-plus/icons-vue` 的静态白名单映射。编辑器提供可搜索图标网格和清空操作;服务端或历史数据中的未知图标统一回退默认图标,不能动态执行任意组件或图标路径。
## 原因
- 保留 RuoYi 用户熟悉的菜单层级、条件字段和操作流程。
- 用服务端树约束保证角色授权、动态路由和菜单编辑看到同一套父子关系。
- 将图标输入限制在 Element Plus 组件白名单,降低动态组件注入和版本漂移风险。
## 影响范围
- `WonderQ-Admin`:菜单请求 schema、父子关系/类型/权限冲突校验、动态菜单树字段。
- `WonderQ-Admin-UI-Vue`:菜单编辑器条件字段、父级树和可搜索图标选择器。
- `WonderQ-MiniAPP`:不使用后台菜单接口,不需要改动。