实现系统管理菜单树增强接口

This commit is contained in:
andy
2026-07-16 11:57:25 +07:00
parent 93ecfb08a9
commit 5390b8f71b
12 changed files with 1042 additions and 10 deletions

View File

@@ -4,9 +4,9 @@
| 项目 | 内容 |
| --- | --- |
| 文档版本 | 0.4 |
| 日期 | 2026-07-10 |
| 状态 | V1 已按当前代码实现更新 |
| 文档版本 | 0.6 |
| 日期 | 2026-07-16 |
| 状态 | V1 已按当前代码实现更新CP4-4a 菜单树增强接口已完成 |
| 适用范围 | 用户、角色、权限、菜单、酒店和用户酒店授权的后台维护 |
| 依赖前置 | M003 登录权限与酒店菜单底座、M005 酒店上下文统一收口 |
| 主要读者 | 产品、后端、前端、测试、后续协作 agent |
@@ -255,6 +255,8 @@ platform.hotel.control
| 编辑菜单 | 修改名称、图标、排序、可见性、状态、权限码 |
| 新增菜单 | 第一版允许新增菜单配置,包括当前前端尚未注册的菜单 |
| 菜单排序 | 支持保存排序号 |
| 菜单树查询 | 返回完整菜单树,用于前端左侧树形菜单管理 |
| 批量调整父级和排序 | 支持一次性保存菜单父子关系和同级排序 |
建议限制:
@@ -262,6 +264,8 @@ platform.hotel.control
- 第一版允许新增未知菜单,但未知 `route_path` 不能被视为已可用页面;前端路由不存在时需要展示安全兜底或跳转到无权限 / 未找到页面。
- 新增菜单如果配置了未知路由,建议默认 `visible=false``menu_status=DISABLED`,由管理员在前端支持到位后再开放。
- 菜单只决定入口可见性,不替代后端接口权限。
- 批量调整菜单树时只允许修改 `parent_id``sort_order`,不能顺带修改路由、权限、可见性或状态。
- 后端必须校验父级存在、禁止把自己设为父级、禁止形成循环树;失败时返回受控业务错误。
### 6.5 酒店管理后端能力
@@ -400,6 +404,181 @@ client/src/types/systemAdmin.ts
前端请求仍统一复用当前 `httpClient`,由它自动携带 Bearer token。
### 7.7 当前前端交互问题
当前 `/system` 页面已经接通 V1 后端接口,但页面交互仍偏“开发调试式 CRUD”主要问题如下
- 系统设置入口只有横向子路由 tab缺少设置中心的信息分组用户不容易理解“账号权限、菜单导航、酒店配置、审计日志”之间的关系。
- 用户、角色、菜单、酒店页面把筛选、新建、列表、详情和编辑堆在同一页,管理员容易迷失当前操作上下文。
- 角色、酒店、权限分配使用原生多选框,数据量稍大时难以搜索、比对和确认变更。
- 菜单天然是树形导航配置,目前以表格平铺展示,父子关系、排序、可见性和未知路由风险不够直观。
- 高风险操作缺少清晰确认,例如重置密码、禁用用户、启用 / 禁用酒店、修改角色权限和开放菜单。
- 保存中、保存成功、保存失败、未保存离开、只读原因等状态反馈不够明显。
### 7.8 系统设置整体低保真结构
系统设置建议从“每页堆表单”调整为“设置中心 + 模块列表 + 详情抽屉 / 专用编辑区”。除菜单树查询和批量树排序这两个已确认增强点外,其他第一阶段交互调整尽量复用当前 `/api/admin/**` 能力。
```text
┌──────────────────────────────────────────────────────────────┐
│ 系统设置 │
│ 管理账号、权限、菜单导航、酒店配置和后台审计。 │
├──────────────────────────────────────────────────────────────┤
│ 分组导航 │
│ [账号与权限] [菜单与导航] [酒店配置] [审计日志] │
├──────────────────────────────────────────────────────────────┤
│ 当前模块标题 [主要操作按钮] │
│ 简短说明 / 权限提示 / 当前酒店或系统状态 │
├──────────────────────────────────────────────────────────────┤
│ 筛选栏:关键词、状态、业务分组、刷新 │
├──────────────────────────────┬───────────────────────────────┤
│ 列表 / 树 / 审计时间线 │ 详情抽屉 / 编辑面板 │
│ - 行选中态 │ - 基础信息 │
│ - 状态标签 │ - 授权配置 │
│ - 操作入口 │ - 变更摘要 │
│ │ - 保存 / 取消 / 高风险确认 │
└──────────────────────────────┴───────────────────────────────┘
```
交互规则:
- 默认进入 `/system` 时仍按当前权限跳转到第一个可访问子页面;后续可以增加 `/system/overview`,但不是 V1 必需项。
- 新建动作优先使用抽屉或弹窗,不再常驻占用页面首屏。
- 列表行点击后在右侧抽屉展示详情;窄屏下抽屉改为全屏面板。
- 编辑和详情放在同一个抽屉里,通过“查看 / 编辑”状态切换,避免页面底部出现第二个编辑表单。
- 写操作提交前展示变更摘要;涉及权限、酒店、菜单可见性和密码重置时展示二次确认。
- 接口 401 / 403 / 409 / 5xx 使用模块内错误态,不静默失败。
### 7.9 各模块低保真结构
#### 用户管理
```text
┌ 用户管理 ─────────────────────────────────────────────────────┐
│ [关键词] [状态] [角色] [酒店] [新建用户] │
├──────────────────────────────┬───────────────────────────────┤
│ 用户列表 │ 用户详情抽屉 │
│ 用户名 / 展示名 / 状态 │ 基础信息 │
│ 角色摘要 / 默认酒店 / 更新时间 │ 角色授权 │
│ 操作:查看 │ 酒店授权与默认酒店 │
│ │ 安全操作:重置密码 / 禁用 │
└──────────────────────────────┴───────────────────────────────┘
```
建议:
- 角色和酒店授权改为可搜索多选列表,已选项以标签展示。
- 默认酒店只能从已授权酒店中选择;未满足时禁用保存并给出明确提示。
- 重置密码只在详情抽屉的“安全操作”区域展示,结果只展示一次,不写入普通日志或 URL。
#### 角色权限
```text
┌ 角色权限 ─────────────────────────────────────────────────────┐
│ [关键词] [状态] [新建角色] │
├──────────────────────────────┬───────────────────────────────┤
│ 角色列表 │ 角色详情抽屉 │
│ 角色名 / 角色代码 / 内置标记 │ 基础信息 │
│ 权限数量 / 使用人数 │ 权限矩阵 │
│ │ 变更摘要:新增 / 移除权限 │
└──────────────────────────────┴───────────────────────────────┘
```
权限矩阵建议:
```text
[搜索权限码或名称]
SYSTEM
[ ] 用户管理 SYSTEM_USER_MANAGE
[ ] 角色管理 SYSTEM_ROLE_MANAGE
[ ] 菜单管理 SYSTEM_MENU_MANAGE
RESERVATION
[ ] 订单读取 RESERVATION_ORDER_READ
[ ] 任务确认 RESERVATION_TASK_CONFIRM
```
建议:
- 使用 `permission_group` 分组展示,权限码作为次要信息,不让管理员只面对代码列表。
- 内置角色只读时,整块权限矩阵禁用,并展示“内置角色由系统同步,不允许页面修改”。
- 保存前展示“将新增 N 个权限、移除 M 个权限”,降低误操作风险。
#### 菜单管理
菜单管理建议优先改成树形结构,因为它直接影响侧边栏和子菜单的真实体验。
```text
┌ 菜单管理 ─────────────────────────────────────────────────────┐
│ [搜索菜单 / 路由] [状态] [只看可见] [新建菜单] │
├──────────────────────────────┬───────────────────────────────┤
│ 菜单树 │ 菜单配置面板 │
│ ▾ 系统设置 │ 基础配置 │
│ ├─ 用户管理 可见 ACTIVE │ 路由与组件 │
│ ├─ 角色权限 可见 ACTIVE │ 权限与可见性 │
│ ├─ 菜单管理 可见 ACTIVE │ 排序与状态 │
│ ▾ 订单处理 │ 影响预览 / 未知路由提示 │
└──────────────────────────────┴───────────────────────────────┘
```
菜单配置面板建议字段:
| 区域 | 字段 | 交互建议 |
| --- | --- | --- |
| 基础配置 | 菜单名称、菜单代码、父级菜单、图标 | 菜单代码新增后不建议修改;图标使用可搜索选择器 |
| 路由与组件 | `route_path``component_key``known_route` | 未知路由展示风险提示,默认不建议设为可见启用 |
| 权限与可见性 | `permission_code``visible``menu_status` | 明确提示“菜单可见不等于接口授权” |
| 排序与预览 | `sort_order`、侧边栏预览 | 保存前预览菜单在侧边栏中的位置 |
当前 `AdminMenuResult` 已包含 `parent_id``sort_order``visible``known_route`。为避免分页列表导致前端树不完整,菜单管理交互升级时建议后端补 `GET /api/admin/menus/tree`;前端树形管理页优先使用后端完整树接口,不再依赖分页列表自行拼完整树。
#### 酒店管理
```text
┌ 酒店管理 ─────────────────────────────────────────────────────┐
│ [关键词] [状态] [新建酒店] │
├──────────────────────────────┬───────────────────────────────┤
│ 酒店列表 │ 酒店详情抽屉 │
│ 酒店名 / 状态 / 时区 │ 基础信息 │
│ 授权用户数 / 更新时间 │ 启用 / 禁用确认 │
└──────────────────────────────┴───────────────────────────────┘
```
建议:
- 单酒店阶段把“只能有一家 ACTIVE 酒店”作为常驻提示,不放在表单底部。
- 启用第二家 ACTIVE 酒店、禁用最后一家 ACTIVE 酒店会由后端返回 409前端需要把错误展示成可理解的业务提示。
#### 审计日志
```text
┌ 审计日志 ─────────────────────────────────────────────────────┐
│ [对象类型] [对象 ID] [操作类型] [时间范围] [刷新] │
├──────────────────────────────┬───────────────────────────────┤
│ 审计列表 / 时间线 │ 审计详情抽屉 │
│ 操作 / 对象 / 操作人 / 时间 │ 操作前快照 │
│ │ 操作后快照 │
└──────────────────────────────┴───────────────────────────────┘
```
建议:
- 审计页保持只读,不出现编辑控件。
- `before_snapshot_json` / `after_snapshot_json` 可用折叠 JSON 或差异视图展示但不要展示密码、token、secret。
- 如果后端暂不支持时间范围筛选,前端不伪造筛选,只保留当前接口已支持的对象类型、对象 ID 和操作类型。
### 7.10 动效和状态反馈建议
动效只服务可用性,建议控制在 160ms - 220ms
- 子导航 active indicator 平移动效,帮助用户识别当前模块。
- 列表行 hover / selected 使用轻微背景和边框变化。
- 详情抽屉进入、关闭、切换编辑状态使用短过渡。
- 保存按钮展示 loading成功后出现短暂 success 状态;失败时在表单顶部固定展示错误。
- 权限勾选、菜单可见性开关、酒店状态切换提供明确即时反馈。
- 支持 `prefers-reduced-motion`,用户关闭系统动效时前端应降低或取消动画。
## 8. 接口草案
正式开发前需要再细化字段、分页格式和错误码。第一版接口前缀建议统一使用 `/api/admin`,先按以下方向设计。
@@ -445,11 +624,77 @@ GET /api/admin/permissions
```text
GET /api/admin/menus
GET /api/admin/menus/{menuId}
GET /api/admin/menus/tree
POST /api/admin/menus
PUT /api/admin/menus/{menuId}
PUT /api/admin/menus/tree-order
```
说明:菜单排序第一版通过单条菜单的 `sort_order` 字段保存;路由选项接口未做,前端允许手工输入未知路由并通过兜底页保护。
说明:菜单排序第一版可以继续通过单条菜单的 `sort_order` 字段保存;树形菜单管理升级后,前端优先使用 `GET /api/admin/menus/tree` 获取完整树,使用 `PUT /api/admin/menus/tree-order` 批量保存父级和排序。路由选项接口未做,前端允许手工输入未知路由并通过兜底页保护。
菜单树查询建议:
```text
GET /api/admin/menus/tree
```
返回完整菜单树,不分页;默认包含 `ACTIVE` / `DISABLED``visible=true` / `false` 的全部菜单。同级排序按 `sort_order` 升序,其次按 `menu_name``id` 稳定排序。
建议节点结构沿用现有菜单结果并增加 `children[]`
```json
{
"items": [
{
"id": "10001",
"parent_id": null,
"menu_code": "SYSTEM_SETTINGS",
"menu_name": "系统设置",
"route_path": "/system",
"permission_code": "SYSTEM_ADMIN_CONSOLE_ACCESS",
"sort_order": 900,
"visible": true,
"menu_status": "ACTIVE",
"known_route": true,
"children": []
}
],
"warnings": []
}
```
批量调整父级和排序建议:
```text
PUT /api/admin/menus/tree-order
```
请求体建议:
```json
{
"items": [
{
"menu_id": "10002",
"parent_id": "10001",
"sort_order": 100
}
]
}
```
要求:
- 必须登录并拥有 `SYSTEM_MENU_MANAGE`
- 只允许修改 `parent_id``sort_order`
- 使用事务保存。
- 校验 `menu_id` 存在。
- 校验 `parent_id` 为空或存在。
- 禁止把自己设为自己的父级。
- 禁止形成循环菜单树。
- `sort_order` 可为空;为空时后端按请求 `items[]` 顺序生成稳定排序号 `100``200``300`...
- 成功后返回更新后的完整菜单树,方便前端立即刷新。
- 写操作必须写 `platform_admin_audit_log`,审计中记录调整前后的 `parent_id` / `sort_order`
### 8.4 酒店管理
@@ -554,6 +799,27 @@ GET /api/admin/audits
当前实现状态:已完成。菜单支持新增和编辑;酒店支持新增、编辑和状态切换;前端提供未知路由兜底页。
### CP4-4a菜单树增强接口
目标:支撑前端菜单管理从表格交互升级为“左侧菜单树 + 右侧配置面板”。
范围:
- 后端新增 `GET /api/admin/menus/tree`,返回完整菜单树,不分页。
- 后端新增 `PUT /api/admin/menus/tree-order`,批量保存菜单父级和排序。
- 批量保存时校验父级存在、禁止自引用、禁止循环树。
- 批量保存只修改 `parent_id``sort_order`
- 批量保存写入 `platform_admin_audit_log`
验收标准:
- 前端可以不依赖分页菜单列表,直接渲染完整菜单树。
- 拖拽排序或批量调整层级后,前端可以一次性保存并刷新完整树。
- 无 token 返回 401`SYSTEM_MENU_MANAGE` 返回 403。
- 循环树、自引用、不存在的菜单或父级返回受控业务错误。
当前实现状态:已完成。后端已提供完整菜单树查询和批量树排序保存;批量保存 `sort_order` 允许为空,后端按请求 `items[]` 顺序生成 `100``200``300`... 的稳定排序号。
### CP4-4b管理操作审计页
目标:系统管理员可以查看管理后台写操作审计。