6.3 KiB
6.3 KiB
用户管理接口适配设计规范
工单: #2 - 用户管理接口变更通知
日期: 2026-06-07
方案: 方案 B(完整适配)
1. 背景
后端已完成用户管理模块接口重构(提交 dbd04d8),支持部门、角色联表查询和聚合信息返回。前端需要适配以:
- 减少请求次数(从 3 个请求合并为 1 个)
- 支持部门/角色筛选
- 在列表和详情中展示部门、角色信息
2. 后端变更摘要
2.1 用户实体扩展字段
{
"id": 1,
"username": "admin",
"phone": "13800138000",
"depts": [
{
"deptId": 1,
"deptCode": "TECH",
"deptName": "技术部",
"main": true
}
],
"roles": [
{
"roleId": 1,
"roleCode": "admin",
"roleName": "管理员",
"dataScope": 1
}
]
}
2.2 新增接口
GET /user/admin/user/{id}/aggregate- 聚合查询(基础信息 + 部门列表 + 角色列表)
2.3 增强接口
GET /user/admin/user/page- 自动返回depts和rolesGET /user/admin/user/list- 自动返回depts和roles- 支持筛选参数:
deptId、roleId
3. 前端适配范围
3.1 用户列表页 (views/user/info/Index.vue)
新增列:
- 部门列:显示用户所属部门名称(多个部门用逗号分隔,主部门加粗)
- 角色列:显示用户角色名称(多个角色用标签展示)
新增筛选条件:
- 部门筛选:树形选择器(
el-tree-select),支持多选 - 角色筛选:树形选择器(
el-tree-select),支持多选
数据流:
- 列表接口自动返回
depts和roles,无需额外请求 - 筛选参数通过
queryParams传递给userService.page()
3.2 用户详情弹窗 (views/user/info/UserDetailDialog.vue)
改造:
- 使用新的聚合接口
GET /user/admin/user/{id}/aggregate - 展示部门列表(部门名称 + 是否主部门标记)
- 展示角色列表(角色名称 + 数据范围)
数据流:
打开弹窗 → 调用 aggregate 接口 → 展示完整信息
3.3 用户表单 (views/user/info/UserFormDialog.vue)
优化:
- 编辑时从
row.depts解析deptIds(替代调用userDeptService.listDeptIdsByUserId) - 编辑时从
row.roles解析roleIds(替代调用userService.getRoles) - 保留
userDeptService.assignDepts和userPostService.assignPosts用于保存
3.4 Service 层扩展 (service/user/userService.ts)
新增方法:
aggregate(userId)- 调用聚合查询接口
4. 组件设计
4.1 部门/角色展示组件
无需新增组件,直接在表格列中使用 slot 渲染:
<!-- 部门列 -->
<template #column-depts="{ row }">
<el-tag
v-for="dept in row.depts"
:key="dept.deptId"
:type="dept.main ? 'primary' : 'info'"
size="small"
class="mr-1"
>
{{ dept.deptName }}
</el-tag>
</template>
<!-- 角色列 -->
<template #column-roles="{ row }">
<el-tag
v-for="role in row.roles"
:key="role.roleId"
type="success"
size="small"
class="mr-1"
>
{{ role.roleName }}
</el-tag>
</template>
4.2 筛选区域
<template #search="{ query: q, search, reset }">
<!-- 现有筛选条件... -->
<!-- 新增:部门筛选 -->
<el-form-item label="所属部门">
<el-tree-select
v-model="q.deptId"
:data="deptTree"
check-strictly
node-key="id"
:props="{ label: 'deptName', children: 'children' }"
placeholder="请选择部门"
clearable
style="width: 200px"
/>
</el-form-item>
<!-- 新增:角色筛选 -->
<el-form-item label="角色">
<el-tree-select
v-model="q.roleId"
:data="roleTree"
check-strictly
node-key="id"
:props="{ label: 'roleName', children: 'children' }"
placeholder="请选择角色"
clearable
style="width: 200px"
/>
</el-form-item>
</template>
5. 数据类型定义
// 部门信息(嵌套在用户中)
interface UserDept {
deptId: number
deptCode: string
deptName: string
main: boolean
}
// 角色信息(嵌套在用户中)
interface UserRole {
roleId: number
roleCode: string
roleName: string
dataScope: number
}
// 扩展用户类型
interface User {
id: number
username: string
// ... 其他字段
depts?: UserDept[]
roles?: UserRole[]
}
6. 接口调用变更
6.1 列表页
变更前:
- 调用
userService.page(params)- 仅返回基础信息
变更后:
- 调用
userService.page(params)- 自动包含depts和roles - 支持
deptId和roleId筛选参数
6.2 详情弹窗
变更前:
- 直接使用
props.row数据
变更后:
- 打开时调用
userService.aggregate(props.row.id) - 使用返回的完整数据渲染
6.3 编辑表单
变更前:
// 需要额外请求获取部门和角色
const deptIds = await userDeptService.listDeptIdsByUserId(userId)
const roleIds = await userService.getRoles(userId)
变更后:
// 直接从 row 中解析
const deptIds = props.row.depts?.map((d: any) => d.deptId) || []
const roleIds = props.row.roles?.map((r: any) => r.roleId) || []
7. 错误处理
- 聚合接口失败时,回退到使用
props.row基础信息 - 部门/角色数据缺失时,显示 "-" 或空标签
- 筛选条件不影响现有查询逻辑
8. 兼容性
- 原有接口保持不变
- 新增字段通过
@TableField(exist = false)添加,不影响旧逻辑 - 保留
userDeptService和userPostService用于分配功能
9. 测试要点
- 列表页是否正确显示部门和角色信息
- 部门/角色筛选是否生效
- 详情弹窗是否正确展示聚合数据
- 编辑表单是否正确解析已选部门/角色
- 保存后数据是否正确刷新
10. 文件变更清单
| 文件 | 变更类型 | 说明 |
|---|---|---|
views/user/info/Index.vue |
修改 | 添加部门/角色列和筛选条件 |
views/user/info/UserDetailDialog.vue |
修改 | 使用聚合接口,展示部门/角色详情 |
views/user/info/UserFormDialog.vue |
修改 | 从 row 解析 deptIds/roleIds |
service/user/userService.ts |
修改 | 添加 aggregate 方法 |
设计评审状态: 待评审
下一步: 用户评审通过后,编写实施计划