Files
xh-medical-sign-web/clinical-web/docs/users-permissions-api.md
T
yelan fc22d22f85 feat(config): 按业务模块拆分 Mock 开关
用 VITE_MOCK_* 系列环境变量替换全局 VITE_USE_MOCK,各模块独立控制演示数据
启用,并新增 src/utils/mock-flags.ts 统一解析缺省值。文档库关闭演示库时
如实提示接口待接入,避免静默沿用本地数据或覆盖已保存内容。
2026-09-15 09:47:31 +08:00

8.8 KiB
Raw Blame History

用户与权限接口核验与接入说明

核验基准:本机后端 http://127.0.0.1:18080/v3/api-docs(接口前缀为 /api)。浏览器请求仍统一使用 /api,认证请求头为 X-Token。

1. 核验结论

后端当前已经提供用户、角色、API 权限关系和模板权限所需的主要接口。前端原实现的主要问题不是代理地址,而是把已经存在的接口误判为缺失,导致角色显示、密码重置、批量导入和角色权限分配没有真正接通。

本轮已完成以下接入:

  • 用户列表和详情正确映射后端 LOCKED 状态、角色摘要、院区/科室名称、版本号和首次改密标记;
  • 新增用户提交 roleIds,编辑用户使用聚合管理接口完整替换资料和角色,并提交 expectedVersion;
  • 角色卡片改用 GET /api/v1/roles/summary 获取服务端人数统计;
  • 重置密码使用 POST /api/v1/users/{userId}/password/reset,前端校验 12 位密码并支持下次登录改密;
  • 批量导入使用预览、确认提交和任务查询三段流程,不展示或记录密码、手机号和邮箱;
  • 用户与角色的 API 权限分配使用 GET/PUT /api/v1/roles/{roleId}/permissions,不再把权限目录 CRUD 当成关系接口;
  • 模板文档权限页支持 USER 授权对象,可对单个用户增加或删除模板权限;
  • 登录后的受保护路由会刷新 /api/v1/auth/me,用户页菜单和路由至少按 system:user:query 做体验层门控,最终权限仍由后端校验。

2. 后端契约与前端映射

页面能力 后端接口 前端状态 关键约束
用户列表 GET /api/v1/users 已接入 page 从 1 开始,size 传后端分页参数;支持 keyword、campusId
用户详情 GET /api/v1/users/{id} 已接入 角色从 roles 摘要映射为角色名称和 ID
新增用户 POST /api/v1/users 已接入 username、password、displayName、campusId 必填;密码至少 8 位;可传 roleIds
编辑用户资料 PUT /api/v1/users/{id} API 已封装 不接收用户名和密码;支持 clearPhone、clearEmail、expectedVersion
编辑用户与角色 PUT /api/v1/users/{id}/management 已接入 一次提交资料、数据范围和完整 roleIds;使用版本号避免覆盖并发修改
读取用户角色 GET /api/v1/users/{userId}/roles API 已封装 返回角色摘要、关系版本和更新时间
覆盖用户角色 PUT /api/v1/users/{userId}/roles API 已封装 roleIds 是完整替换集合,可选 expectedVersion
停用用户 DELETE /api/v1/users/{id} 已接入 后端语义为软停用,前端保留二次确认
重置密码 POST /api/v1/users/{userId}/password/reset 已接入 newPassword 至少 12 位;响应不返回密码
导入预览 POST /api/v1/users/import/preview 已接入 multipart/form-data,字段为 file,可选默认 campusId
确认导入 POST /api/v1/users/import/commit 已接入 仅提交预览返回的 importId;预览存在错误时前端禁止提交
导入任务 GET /api/v1/users/import/jobs/{jobId} 已接入 展示服务端任务状态,不把文件内容写入日志
角色分页 GET /api/v1/roles 已接入 RoleResponse 不含 userCount,只用于角色选项和基础信息
角色人数 GET /api/v1/roles/summary 已接入 人数由服务端统计,支持可选 campusId
API 权限目录 GET/POST/PUT/DELETE /api/v1/permissions API 已封装 这是权限定义目录,不是角色关系
角色 API 权限 GET/PUT /api/v1/roles/{roleId}/permissions 已接入 permissionIds 完整替换,可选 expectedVersion
当前用户 GET /api/v1/auth/me 已接入 刷新 permissions、角色、数据范围和 passwordChangeRequired
模板权限 GET/POST/DELETE /api/v1/templates/{templateId}/permissions 已接入 subjectType 支持 ROLE、DEPARTMENT、USER;继承记录不可直接删除

3. 重要 DTO 规则

3.1 用户状态和并发版本

后端用户状态为 ENABLED、DISABLED、LOCKED。此前前端把除 DISABLED 外的所有值都当成启用,已修复为三态映射;锁定用户不能建立会话,不能仅按“停用”展示。

用户编辑响应带有 version。聚合编辑会将该版本作为 expectedVersion 提交,服务端返回并发冲突时前端不会自行覆盖新数据。

3.2 脱敏联系方式

详情可能返回脱敏手机号或邮箱。前端未修改脱敏字段时不回传该字段;用户明确清空时才提交 clearPhone: true 或 clearEmail: true。完整手机号、邮箱和密码不写入日志或审计展示。

3.3 批量导入

预览响应只包含行号、校验状态、错误、用户名和姓名,不包含手机号、邮箱或密码。前端只有在 invalidRows === 0 时才启用确认按钮,提交后展示 jobId 和服务端状态。

4. 仍需后端确认或前端后续补齐的事项

  1. OpenAPI 给出了权限资源和动作枚举,但没有给出完整的权限编码初始化清单。前端目前使用已存在于权限目录 Mock/约定中的 system:user:query 做用户页菜单与路由门控;system:user:create、system:user:update、system:user:disable、角色及权限关系的最终编码需要以后端权限中心实际数据为准。
  2. 当前页面已经能分配角色 API 权限,但 API 权限目录本身的新增、编辑、停用尚未做独立管理页面;对应 API 封装已存在。
  3. 后端提供了 POST /api/v1/auth/password/change,当前只完成请求类型和 API 封装,尚未在本轮新增强制改密弹窗。passwordChangeRequired 已保留在登录和当前用户模型中,产品若要求登录后强制改密,应补充全局改密流程。
  4. 导入任务契约当前状态为 PREVIEWED、COMMITTED、EXPIRED、FAILED;如果未来改为真正异步处理,应在后端扩展状态和前端轮询策略,不能由前端猜测完成状态。
  5. 所有管理接口仍必须由后端执行 401/403、数据范围、角色/权限状态和审计校验。前端隐藏菜单或按钮只改善体验,不能作为安全边界。

5. 联调验收

真实接口模式:

VITE_MOCK_USERS=false npm run dev

至少验证以下场景:

  • 登录后 Network 中所有业务请求带 X-Token,并能看到一次 /api/v1/auth/me;
  • 用户详情显示后端角色名称,编辑角色后刷新列表仍保持;
  • LOCKED 用户显示为锁定而不是启用;
  • 未修改脱敏联系方式时编辑不会覆盖原值,清空时发送清除标记;
  • 重置密码不出现在任何响应、列表或前端日志;
  • 导入存在错误时不能提交,零错误预览才允许提交并显示任务号;
  • 角色 API 权限保存后重新读取,确认 permissionIds 是完整替换结果;
  • 模板权限可选择单个用户,直接权限可删除,继承权限保持不可删除;
  • 无用户查询权限的账号不能通过菜单或直接 URL进入用户页,后端 403 仍是最终判断。

6. 验证命令

本轮修改后应在 clinical-web 目录执行:

npm run lint
npm run format:check
npx vue-tsc --noEmit
npm run build -- --outDir /tmp/clinical-web-build-<date>