Skip to main content

Sprint 3 接口文档 — 菜单权限 & 操作日志

TDD 流程:先定接口 → QA 出用例 → 后端按用例开发 → Code Review → QA 验收

版本:v1.0 Draft | 日期:2026-03-15 | 作者:小虎


0. 约定

沿用 Sprint 2 通用约定(响应格式、认证、分页、角色层级、防提权原则),此处不重复。

新增错误码

含义说明
10101菜单不存在目标 menu_id 无效或已删除
10102菜单层级过深最多 3 级(目录/菜单/按钮)
10103父菜单不存在parent_id 指向无效记录
10104菜单有子节点删除前需先删除子菜单
10201权限不存在目标 perm_id 无效或已删除
10202权限 key 已存在permission_key 唯一约束冲突
10203权限已被引用删除前需先解绑关联的菜单和群组
10301日志不存在目标 log_id 无效

菜单类型

menu_type含义说明
1目录仅用于分组,不关联路由
2菜单对应前端路由页面
3按钮页面内操作按钮(权限粒度)

菜单层级约束

目录(1) → 菜单(2) → 按钮(3)
  • 最多 3 级
  • 目录下只能放菜单或目录
  • 菜单下只能放按钮
  • 按钮不能有子节点

1. 菜单管理(T-BE-15)

1.1 获取菜单树

GET /api/v1/menus/tree

权限:admin+ | 权限 key:system:menu:list

Query 参数

参数类型必填说明
statusint0=禁用 1=启用,不传返回全部

响应

{
"code": 0,
"data": [
{
"menu_id": 1,
"parent_id": 0,
"perm_id": 0,
"menu_name": "系统管理",
"menu_type": 1,
"path": "/system",
"component": "Layout",
"icon": "setting",
"is_visible": 1,
"is_cache": 0,
"sort_order": 1,
"status": 1,
"created_at": "2026-03-12T10:00:29Z",
"children": [
{
"menu_id": 2,
"parent_id": 1,
"perm_id": 1,
"menu_name": "用户管理",
"menu_type": 2,
"path": "/system/users",
"component": "system/user/index",
"icon": "user",
"is_visible": 1,
"is_cache": 0,
"sort_order": 10,
"status": 1,
"created_at": "2026-03-12T10:00:29Z",
"children": []
}
]
}
]
}

说明

  • 返回完整树形结构,按 sort_order ASC 排序
  • 不包含 is_deleted=1 的记录
  • 按钮节点也在树中(供权限配置使用)

1.2 获取菜单详情

GET /api/v1/menus/:id

权限:admin+ | 权限 key:system:menu:list

响应

{
"code": 0,
"data": {
"menu_id": 2,
"parent_id": 1,
"perm_id": 1,
"menu_name": "用户管理",
"menu_type": 2,
"path": "/system/users",
"component": "system/user/index",
"icon": "user",
"is_visible": 1,
"is_cache": 0,
"sort_order": 10,
"status": 1,
"permission": {
"perm_id": 1,
"permission_key": "system:user:list",
"permission_name": "查看用户列表"
},
"created_at": "2026-03-12T10:00:29Z",
"updated_at": "2026-03-12T10:00:29Z"
}
}

1.3 创建菜单

POST /api/v1/menus

权限:superadmin | 权限 key:system:menu:create

请求体

{
"parent_id": 1,
"menu_name": "角色管理",
"menu_type": 2,
"path": "/system/roles",
"component": "system/role/index",
"icon": "peoples",
"perm_id": 0,
"is_visible": 1,
"is_cache": 0,
"sort_order": 25,
"status": 1
}

校验规则

字段规则
parent_id必填,0=顶级目录
menu_name必填,1-64 字符
menu_type必填,1=目录 2=菜单 3=按钮
path目录/菜单必填;按钮可空
component菜单必填(Vue 组件路径);目录传 Layout;按钮可空
icon可选
perm_id可选,关联的权限 ID
is_visible可选,默认 1
is_cache可选,默认 0
sort_order可选,默认 0
status可选,默认 1

层级校验

  • parent_id=0 时 menu_type 只能是 1(目录)
  • parent 是目录 → 子节点只能是菜单(2)或目录(1)
  • parent 是菜单 → 子节点只能是按钮(3)
  • parent 是按钮 → 不允许(10102)

响应

{
"code": 0,
"data": { "menu_id": 8 }
}

1.4 更新菜单

PUT /api/v1/menus/:id

权限:superadmin | 权限 key:system:menu:update

请求体:同创建(除 menu_type 创建后不可变)

注意

  • menu_type 不可修改(防止树结构异常)
  • parent_id 可修改(拖拽排序),需重新校验层级约束
  • 修改 perm_idstatus 后,所有拥有该菜单权限的用户 auth_version + 1

1.5 删除菜单

DELETE /api/v1/menus/:id

权限:superadmin | 权限 key:system:menu:delete

规则

  • 有子节点时不允许删除(10104),需先删子菜单
  • 软删除:is_deleted = 1
  • 删除后相关用户 auth_version + 1

响应

{ "code": 0, "data": { "deleted": true } }

1.6 菜单排序(批量更新排序)

PUT /api/v1/menus/sort

权限:superadmin | 权限 key:system:menu:update

请求体

{
"items": [
{ "menu_id": 2, "sort_order": 10 },
{ "menu_id": 3, "sort_order": 20 },
{ "menu_id": 4, "sort_order": 30 }
]
}

响应

{ "code": 0, "data": { "updated": 3 } }

2. 权限管理(T-BE-16)

2.1 获取权限列表(按模块分组)

GET /api/v1/permissions

权限:admin+ | 权限 key:system:permission:list

Query 参数

参数类型必填说明
modulestring按模块筛选
keywordstring搜索 permission_name / permission_key
statusint0=禁用 1=启用

响应

{
"code": 0,
"data": {
"modules": [
{
"module": "system",
"permissions": [
{
"perm_id": 1,
"permission_key": "system:user:list",
"permission_name": "查看用户列表",
"description": "查看和搜索用户列表及详情",
"status": 1,
"sort_order": 10,
"ref_count": {
"menus": 1,
"groups": 3
},
"created_at": "2026-03-12T10:00:29Z"
}
]
}
],
"total": 24
}
}

说明

  • ref_count.menus:关联该权限的菜单数
  • ref_count.groups:关联该权限的群组数
  • 用于前端展示引用情况,防止误删

2.2 获取权限详情

GET /api/v1/permissions/:id

权限:admin+ | 权限 key:system:permission:list

响应

{
"code": 0,
"data": {
"perm_id": 1,
"permission_key": "system:user:list",
"permission_name": "查看用户列表",
"module": "system",
"description": "查看和搜索用户列表及详情",
"status": 1,
"sort_order": 10,
"menus": [
{ "menu_id": 2, "menu_name": "用户管理" }
],
"groups": [
{ "group_id": 1, "group_name": "运营组" }
],
"created_at": "2026-03-12T10:00:29Z",
"updated_at": "2026-03-12T10:00:29Z"
}
}

2.3 创建权限

POST /api/v1/permissions

权限:superadmin | 权限 key:system:permission:create

请求体

{
"permission_key": "order:list",
"permission_name": "查看订单列表",
"module": "order",
"description": "查看和搜索订单列表",
"status": 1,
"sort_order": 100
}

校验规则

字段规则
permission_key必填,格式 module:resource:action,1-128 字符,唯一
permission_name必填,1-128 字符
module必填,1-64 字符
description可选,最多 256 字符
status可选,默认 1
sort_order可选,默认 0

响应

{
"code": 0,
"data": { "perm_id": 25 }
}

2.4 更新权限

PUT /api/v1/permissions/:id

权限:superadmin | 权限 key:system:permission:update

请求体

{
"permission_name": "查看订单列表(更新)",
"description": "更新描述",
"status": 1,
"sort_order": 101
}

注意

  • permission_key 创建后不可修改(被中间件引用)
  • module 创建后不可修改
  • 修改 status 后,所有拥有该权限的用户 auth_version + 1

2.5 删除权限

DELETE /api/v1/permissions/:id

权限:superadmin | 权限 key:system:permission:delete

规则

  • 有菜单或群组引用时不允许删除(10203),需先解绑
  • 软删除:is_deleted = 1
  • 删除后相关用户 auth_version + 1

3. 当前用户菜单与权限(T-BE-18)

前端动态路由的核心依赖

3.1 获取当前用户菜单树

GET /api/v1/auth/menus

权限:已登录 | 无需额外权限 key

响应

{
"code": 0,
"data": [
{
"menu_id": 1,
"parent_id": 0,
"menu_name": "系统管理",
"menu_type": 1,
"path": "/system",
"component": "Layout",
"icon": "setting",
"is_visible": 1,
"is_cache": 0,
"sort_order": 1,
"children": [
{
"menu_id": 2,
"parent_id": 1,
"menu_name": "用户管理",
"menu_type": 2,
"path": "/system/users",
"component": "system/user/index",
"icon": "user",
"is_visible": 1,
"is_cache": 0,
"sort_order": 10,
"children": []
}
]
}
]
}

逻辑

  • superadmin:返回所有 status=1 的菜单
  • 其他角色:通过 sys_user_group → sys_group_permission → sys_permission → sys_menu 链路,返回有权限的菜单
  • 只返回 is_deleted=0 AND status=1 的记录
  • 按钮(menu_type=3) 不在树中返回(前端通过 permissions 列表判断按钮权限)

3.2 获取当前用户权限列表

GET /api/v1/auth/permissions

权限:已登录 | 无需额外权限 key

响应

{
"code": 0,
"data": {
"role_type": "admin",
"permissions": [
"system:user:list",
"system:user:create",
"system:user:update",
"system:user:delete",
"group:list",
"group:create",
"group:update"
]
}
}

说明

  • superadmin 返回 ["*"](前端通配符,代表所有权限)
  • 其他角色返回实际的 permission_key 列表
  • 前端用此列表做按钮级 v-permission 指令控制

4. 操作日志(T-BE-19)

4.1 获取操作日志列表

GET /api/v1/logs/operations

权限:admin+ | 权限 key:system:log:list

Query 参数

参数类型必填说明
pageint页码
page_sizeint每页条数
operator_idint按操作人筛选
modulestring按模块筛选(user/group/permission/menu)
actionstring按操作类型筛选(create/update/delete/login/logout)
target_typestring按目标类型筛选
start_timeint开始时间(unix 秒)
end_timeint结束时间(unix 秒)
keywordstring搜索 description / operator_name

响应

{
"code": 0,
"data": {
"items": [
{
"log_id": 1178,
"trace_id": "abc123",
"operator_id": 1,
"operator_name": "superadmin",
"target_type": "user",
"target_id": 5,
"action": "update",
"module": "user",
"description": "修改用户 alice 的角色为 admin",
"ip": "192.168.1.100",
"user_agent": "Mozilla/5.0 ...",
"request_method": "PUT",
"request_path": "/api/v1/users/5",
"response_code": 0,
"duration_ms": 45,
"created_at": "2026-03-14T15:30:00Z"
}
],
"total": 1178,
"page": 1,
"page_size": 20
}
}

排序create_time DESC(最新在前)


4.2 获取操作日志详情

GET /api/v1/logs/operations/:id

权限:admin+ | 权限 key:system:log:list

响应

{
"code": 0,
"data": {
"log_id": 1178,
"trace_id": "abc123",
"operator_id": 1,
"operator_name": "superadmin",
"target_type": "user",
"target_id": 5,
"action": "update",
"module": "user",
"description": "修改用户 alice 的角色为 admin",
"before_snapshot": {
"role_type": "user",
"status": 1
},
"after_snapshot": {
"role_type": "admin",
"status": 1
},
"ip": "192.168.1.100",
"user_agent": "Mozilla/5.0 ...",
"request_method": "PUT",
"request_path": "/api/v1/users/5",
"request_body": "{\"role_type\":\"admin\"}",
"response_code": 0,
"duration_ms": 45,
"created_at": "2026-03-14T15:30:00Z"
}
}

说明

  • before_snapshot / after_snapshot:变更前后的关键字段快照(JSON)
  • request_body:原始请求体(敏感字段如 password 已脱敏)
  • 操作日志只读,不提供修改和删除接口

5. 前端动态路由方案(T-FE-06)

不涉及后端接口,但需要在文档中明确技术方案

5.1 路由加载流程

用户登录成功
→ 调用 GET /api/v1/auth/menus 获取菜单树
→ 调用 GET /api/v1/auth/permissions 获取权限列表
→ 前端将菜单树转为 vue-router 路由配置
→ router.addRoute() 注册动态路由
→ 将 permissions 列表存入 Pinia

5.2 路由守卫改造

当前 src/router/permissions.ts 需要改造:

  1. constantRoutes 只保留:login、403、404、dashboard
  2. 其他所有业务路由(用户管理、群组管理等)从后端菜单树动态生成
  3. setRoutes() 方法调用 /auth/menus + /auth/permissions
  4. 缓存在 Pinia,刷新页面时重新拉取

5.3 按钮权限指令

<!-- v-permission 指令 -->
<el-button v-permission="'system:user:create'" @click="handleAdd">新增用户</el-button>

<!-- 无权限时按钮不渲染(v-if 语义) -->

实现

  • 注册全局指令 v-permission
  • 从 Pinia 读取当前用户 permissions 列表
  • ["*"] 表示全部权限(superadmin)
  • 不在列表中的 permission_key → el.parentNode.removeChild(el)

5.4 Component 映射

后端 sys_menu.component 字段存的是相对路径,前端需要映射:

// 动态导入映射
const modules = import.meta.glob('@/views/**/*.vue')

function resolveComponent(component: string): Component {
if (component === 'Layout') return Layout
const path = `/src/views/${component}.vue`
return modules[path] || (() => import('@/views/404.vue'))
}

6. 接口总览

#方法路径权限 key任务Phase
1GET/api/v1/menus/treesystem:menu:listT-BE-151
2GET/api/v1/menus/:idsystem:menu:listT-BE-151
3POST/api/v1/menussystem:menu:createT-BE-151
4PUT/api/v1/menus/:idsystem:menu:updateT-BE-151
5DELETE/api/v1/menus/:idsystem:menu:deleteT-BE-151
6PUT/api/v1/menus/sortsystem:menu:updateT-BE-151
7GET/api/v1/permissionssystem:permission:listT-BE-161
8GET/api/v1/permissions/:idsystem:permission:listT-BE-161
9POST/api/v1/permissionssystem:permission:createT-BE-161
10PUT/api/v1/permissions/:idsystem:permission:updateT-BE-161
11DELETE/api/v1/permissions/:idsystem:permission:deleteT-BE-161
12GET/api/v1/auth/menus(已登录)T-BE-182
13GET/api/v1/auth/permissions(已登录)T-BE-182
14GET/api/v1/logs/operationssystem:log:listT-BE-193
15GET/api/v1/logs/operations/:idsystem:log:listT-BE-193

Sprint 3 新增接口:15 个(不含 Sprint 4 延后的 API 管理模块)


7. 任务分配总览

Phase 1(3/16 - 3/22):后端 CRUD + 菜单管理前端

任务 ID任务角色优先级接口
T-BE-15菜单 CRUD Controller后端侠P0#1-6
T-BE-16权限 CRUD Controller后端侠P0#7-11
T-FE-04菜单管理页面前端匠P0依赖 #1-6

Phase 2(3/23 - 3/29):动态路由 + 权限管理前端

任务 ID任务角色优先级接口
T-BE-18当前用户菜单树 + 权限列表后端侠P0#12-13
T-FE-05权限管理页面前端匠P0依赖 #7-11
T-FE-06动态路由改造 + v-permission前端匠P0依赖 #12-13

Phase 3(3/30 - 4/5):操作日志 + QA

任务 ID任务角色优先级接口
T-BE-19操作日志查询 Controller后端侠P1#14-15
T-FE-07操作日志页面前端匠P1依赖 #14-15
T-QA-08全量测试质检官P0全部

8. 技术评审待确认

#决策项建议待确认
1菜单管理仅 superadmin 可操作✅ 建议是否开放给 admin?
2permission_key 创建后不可改✅ 建议
3按钮权限粒度v-permission 指令是否需要更细粒度?
4操作日志保留策略只增不删是否需要自动归档/清理?
5前端路由缓存策略Pinia + 刷新重拉是否需要 localStorage 持久化?