Files
xh-medical-sign-web/clinical-web/docs/users-permissions-api.md
T

266 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 用户与权限页面接口核验与后端缺口
> 核验基准:MEDISIGN 患者电子签 API 文档([https://ipad.shenynet.com/doc.html#/home](https://ipad.shenynet.com/doc.html#/home))。
## 1. 核验结论
当前页面已经可以使用后端接口完成用户列表和用户生命周期的主要操作:查询、分页、关键字搜索、院区筛选、查看详情、新增、编辑和停用。角色列表也已经接入,用于展示角色卡片。
最新接口文档没有提供用户与角色的关联数据,因此用户表中的角色只能显示“未返回角色”;角色接口也没有返回用户人数,角色卡片不会再根据当前用户列表臆造人数。
页面上暂时保留但无法真正执行的功能是:
- 批量导入用户;
- 重置密码;
- 为用户分配或移除角色;
- 角色人数统计。
另外,`/api/v1/permissions` 管理的是 API 权限定义(资源、路径和动作),不是用户或角色的权限分配关系。模板文档权限使用 `/api/v1/templates/{templateId}/permissions`,两者也不能混用。
## 2. 当前已接入接口
| 页面功能 | 接口 | 状态 | 说明 |
| -------- | --------------------------- | ------ | -------------------------------------------------------- |
| 用户列表 | `GET /api/v1/users` | 已接入 | 支持 `page`、`size`、`keyword`、`campusId`;前端已接分页 |
| 用户详情 | `GET /api/v1/users/{id}` | 已接入 | 用于打开编辑弹窗 |
| 新增用户 | `POST /api/v1/users` | 已接入 | 创建时提交账号、密码、基础资料、院区、科室和数据范围 |
| 编辑用户 | `PUT /api/v1/users/{id}` | 已接入 | 不修改用户名和密码 |
| 停用用户 | `DELETE /api/v1/users/{id}` | 已接入 | 后端是软停用,前端有二次确认 |
| 角色列表 | `GET /api/v1/roles` | 已接入 | 支持 `page`、`size`、`keyword`;最新响应没有 `userCount` |
| 院区字典 | `GET /api/v1/campuses` | 已接入 | 用于院区显示和用户表单 |
| 科室字典 | `GET /api/v1/departments` | 已接入 | 用于科室显示和用户表单,可按院区筛选 |
### 2.1 已遵守的接口约束
- 所有请求使用统一响应包装,并通过 `X-Token` 携带登录令牌;
- 用户列表的 `page` 从 1 开始,`size` 范围为 1–200;
- 创建用户时密码只出现在请求中,不能出现在任何响应或日志中;
- 编辑接口不接收用户名和密码;
- 停用接口不执行物理删除,只将状态改为 `DISABLED`;
- 用户接口返回的手机号和邮箱可能是脱敏值。前端编辑时,如果用户没有重新填写,不会把脱敏值回传覆盖原联系方式;
- 用户角色、角色人数和最终权限判断必须由后端提供和校验,前端不自行推导。
## 3. 建议补充的后端接口
### 3.1 用户角色关联(最高优先级)
用户列表和详情最好直接在 `UserResponse` 中增加角色摘要,避免列表为每个用户额外请求一次接口:
```json
{
"roles": [
{
"id": "角色 UUID",
"code": "DOCTOR",
"name": "医生"
}
]
}
```
同时提供角色关系的读取和覆盖更新接口,供用户编辑弹窗使用:
```http
GET /api/v1/users/{userId}/roles
PUT /api/v1/users/{userId}/roles
Content-Type: application/json
```
请求体建议为:
```json
{
"roleIds": ["角色 UUID 1", "角色 UUID 2"]
}
```
`PUT` 使用“完整替换”语义,便于前端重复提交保持幂等。响应建议返回用户和最新角色摘要:
```json
{
"code": 0,
"message": "OK",
"data": {
"userId": "用户 UUID",
"roles": [
{
"id": "角色 UUID",
"code": "DOCTOR",
"name": "医生"
}
],
"updatedAt": "2026-09-01T08:00:00Z"
}
}
```
后端应校验角色是否存在、是否停用、当前操作人是否有分配权限,并记录角色变更审计日志。建议错误码包括 `400`、`401`、`403`、`404` 和 `409`。
### 3.2 重置密码
建议提供:
```http
POST /api/v1/users/{userId}/password/reset
Content-Type: application/json
```
请求体:
```json
{
"newPassword": "管理员输入的新密码",
"forceChangeOnNextLogin": true
}
```
响应使用 `ApiResponseVoid`,不返回密码:
```json
{
"code": 0,
"message": "密码已重置",
"data": {}
}
```
密码必须在服务端进行强度校验和哈希存储;密码不能写入日志、审计详情或响应。若产品要求服务端生成临时密码,应通过受控的一次性展示或院内安全渠道交付,不建议作为普通接口字段长期返回。建议错误码包括 `400`、`401`、`403`、`404` 和 `429`。
### 3.3 批量导入用户
批量导入不建议直接把文件上传后立即写库,建议拆成“预览校验 + 确认导入”:
```http
POST /api/v1/users/import/preview
Content-Type: multipart/form-data
```
表单字段:
| 字段 | 类型 | 说明 |
| ---------- | ---- | ---------------------------------------- |
| `file` | file | CSV 或 XLSX 文件,建议限制文件大小和行数 |
| `campusId` | UUID | 没有院区列时使用的默认院区,可选 |
预览响应至少应包含:
```json
{
"code": 0,
"data": {
"importId": "导入批次 UUID",
"fileName": "users.xlsx",
"totalRows": 100,
"validRows": 96,
"invalidRows": 4,
"rows": [
{
"rowNo": 12,
"status": "INVALID",
"errors": ["用户名已存在"],
"username": "zhangsan",
"displayName": "张三"
}
]
}
}
```
确认导入:
```http
POST /api/v1/users/import/commit
Content-Type: application/json
```
```json
{
"importId": "导入批次 UUID"
}
```
如果导入量较大,确认接口返回任务号并异步执行:
```http
GET /api/v1/users/import/jobs/{jobId}
```
导入文件建议支持 `username`、`displayName`、`employeeNo`、`phone`、`email`、`campusId`、`departmentId`、`roleCodes` 和 `dataScope` 列。密码应遵循统一的临时密码或首次登录设置策略,不建议在普通导入文件中保存明文密码。导入必须逐行返回校验错误,不能因为一行错误而静默跳过整批数据。
### 3.4 角色人数统计
当前 `GET /api/v1/roles` 的响应没有 `userCount`。如果原型需要保留角色卡片人数,建议新增专用汇总接口:
```http
GET /api/v1/roles/summary?campusId={campusId}
```
响应建议为:
```json
{
"code": 0,
"data": [
{
"roleId": "角色 UUID",
"code": "DOCTOR",
"name": "医生",
"description": "可查看并发起签署任务",
"status": "ENABLED",
"userCount": 18
}
]
}
```
需要和后端确认人数口径:建议只统计当前操作人数据权限范围内、状态为 `ENABLED` 的用户,并按当前页面选择的院区过滤;如果产品要统计全院,应明确忽略页面院区筛选。统计接口也必须执行当前用户的权限范围校验。
### 3.5 API 权限分配(仅在产品需要时补充)
现有 `/api/v1/permissions` 只是 API 权限目录的增删改查。若需要让管理员把 API 权限分配给角色,还需要关系接口:
```http
GET /api/v1/roles/{roleId}/permissions
PUT /api/v1/roles/{roleId}/permissions
```
请求体可以使用完整替换语义:
```json
{
"permissionIds": ["API 权限 UUID 1", "API 权限 UUID 2"]
}
```
这组接口与模板文档权限接口不同。模板的角色、科室和用户授权继续使用:
```http
GET /api/v1/templates/{templateId}/permissions
POST /api/v1/templates/{templateId}/permissions
DELETE /api/v1/templates/{templateId}/permissions/{permissionId}
```
## 4. 接口错误与审计要求
所有新增接口建议继续使用统一响应格式,并至少覆盖:
| HTTP 状态 | 场景 |
| --------- | ---------------------------------- |
| `400` | 参数、格式、文件内容或业务校验失败 |
| `401` | 未登录或令牌失效 |
| `403` | 当前用户没有对应管理权限 |
| `404` | 用户、角色、导入批次或权限不存在 |
| `409` | 用户名重复、角色关系并发冲突等 |
| `429` | 密码重置或批量任务触发频率限制 |
| `500` | 服务端异常 |
用户创建、编辑、停用、密码重置、角色变更和批量导入都应产生审计记录,至少包含操作人、目标用户、操作类型、结果、时间和链路追踪 ID;不得记录密码、完整手机号、身份证号或完整病历信息。
## 5. 推荐实施顺序
1. 先补用户角色摘要和角色绑定接口,解除用户表“未返回角色”的限制;
2. 补密码重置接口,前端再把现有提示改为重置密码弹窗;
3. 补批量导入预览、确认和任务查询;
4. 根据产品是否保留角色卡片人数,补角色统计接口;
5. 如果要管理 API 权限,再补角色与 API 权限的关联接口,不能复用 `/api/v1/permissions` CRUD 代替。