feat(account): 实现平台账号管理功能

- 新增平台账号列表查询接口(自动筛选超级管理员和平台用户)
- 新增密码修改和状态切换专用接口
- 增强角色分配功能,支持空数组清空所有角色
- 新增超级管理员保护机制,禁止分配角色
- 新增完整的集成测试和OpenSpec规范文档
This commit is contained in:
2026-01-14 17:00:30 +08:00
parent 5556b1028c
commit b1195c16df
15 changed files with 1713 additions and 51 deletions

View File

@@ -0,0 +1,63 @@
# role-permission Spec Delta
## MODIFIED Requirements
### Requirement: 角色类型与用户类型匹配
系统 SHALL 在分配角色时校验角色类型与用户类型的匹配关系:平台用户只能分配平台角色,代理/企业账号只能分配客户角色,超级管理员不允许分配角色。分配角色时支持传递空数组以清空账号的所有角色。
#### Scenario: 平台用户分配平台角色
- **WHEN** 为平台用户user_type=2分配平台角色role_type=1
- **THEN** 系统允许分配
#### Scenario: 平台用户分配客户角色
- **WHEN** 为平台用户user_type=2分配客户角色role_type=2
- **THEN** 系统拒绝分配并返回错误"角色类型与账号类型不匹配"
#### Scenario: 代理账号分配客户角色
- **WHEN** 为代理账号user_type=3分配客户角色role_type=2
- **THEN** 系统允许分配
#### Scenario: 代理账号分配平台角色
- **WHEN** 为代理账号user_type=3分配平台角色role_type=1
- **THEN** 系统拒绝分配并返回错误"角色类型与账号类型不匹配"
#### Scenario: 企业账号分配客户角色
- **WHEN** 为企业账号user_type=4分配客户角色role_type=2
- **THEN** 系统允许分配
#### Scenario: 超级管理员禁止分配角色
- **WHEN** 尝试为超级管理员user_type=1分配任何角色
- **THEN** 系统拒绝分配并返回错误 CodeInvalidParam "超级管理员不允许分配角色"
#### Scenario: 清空账号所有角色
- **WHEN** 调用分配角色接口时传递空数组 `role_ids: []`
- **THEN** 系统删除该账号的所有现有角色关联,返回成功
#### Scenario: 传递空数组给超级管理员
- **WHEN** 为超级管理员user_type=1调用分配角色接口且传递空数组
- **THEN** 系统拒绝操作并返回错误"超级管理员不允许分配角色"
---
## ADDED Requirements
### Requirement: 角色分配灵活性
系统 SHALL 支持灵活的角色分配操作允许传递空数组清空所有角色允许传递部分角色ID进行增量分配不强制要求账号必须拥有角色。
#### Scenario: 创建无角色的平台用户
- **WHEN** 创建平台用户账号后未分配任何角色
- **THEN** 系统允许该状态,账号可正常登录但无权限访问受保护资源
#### Scenario: 清空代理账号的唯一角色
- **WHEN** 代理账号user_type=3拥有一个角色调用分配角色接口传递空数组
- **THEN** 系统清空该代理账号的角色,账号变为无角色状态
#### Scenario: 增量分配角色
- **WHEN** 账号已有角色A调用分配角色接口传递 `role_ids: [B, C]`
- **THEN** 系统跳过已存在的关联只新增角色B和C如果尚未分配
#### Scenario: 角色分配验证规则调整
- **WHEN** 前端调用角色分配接口
- **THEN** `role_ids` 字段验证规则为 `omitempty`(可选),允许传递 null、空数组或角色ID列表

View File

@@ -0,0 +1,125 @@
# user-organization Spec Delta
## ADDED Requirements
### Requirement: 平台账号列表查询
系统 SHALL 提供专门的平台账号列表查询接口自动筛选平台用户user_type=2和超级管理员user_type=1支持按用户名、手机号、状态筛选并返回分页结果。
#### Scenario: 查询平台账号列表
- **WHEN** 调用平台账号列表接口 `GET /api/admin/platform-accounts`
- **THEN** 系统自动筛选 `user_type IN (1, 2)` 的账号并返回列表
#### Scenario: 按用户名筛选
- **WHEN** 调用平台账号列表接口并传递 `username=admin`
- **THEN** 系统返回用户名包含 "admin" 的平台账号(模糊查询)
#### Scenario: 按手机号筛选
- **WHEN** 调用平台账号列表接口并传递 `phone=138`
- **THEN** 系统返回手机号包含 "138" 的平台账号(模糊查询)
#### Scenario: 按状态筛选
- **WHEN** 调用平台账号列表接口并传递 `status=1`
- **THEN** 系统返回状态为启用status=1的平台账号
#### Scenario: 分页查询
- **WHEN** 调用平台账号列表接口并传递 `page=2&page_size=10`
- **THEN** 系统返回第2页数据每页10条记录同时返回总记录数
#### Scenario: 超级管理员包含在列表中
- **WHEN** 调用平台账号列表接口
- **THEN** 返回结果包含所有超级管理员账号user_type=1
#### Scenario: 列表返回字段
- **WHEN** 平台账号列表接口返回数据
- **THEN** 每条记录包含id, username, phone, user_type, status, created_at, updated_at
---
### Requirement: 平台账号密码修改
系统 SHALL 提供专门的密码修改接口,允许管理员重置平台账号密码,无需验证旧密码。新密码必须经过 bcrypt 哈希后存储,并自动设置 updater 字段。
#### Scenario: 修改平台账号密码
- **WHEN** 调用密码修改接口 `PUT /api/admin/platform-accounts/:id/password` 并传递 `new_password`
- **THEN** 系统验证账号存在,哈希新密码,更新数据库,设置 updater 字段
#### Scenario: 密码格式验证
- **WHEN** 调用密码修改接口传递的密码长度小于 8 位或大于 32 位
- **THEN** 系统拒绝修改并返回错误 CodeInvalidParam "密码长度必须在 8-32 位之间"
#### Scenario: 账号不存在
- **WHEN** 调用密码修改接口传递的账号ID不存在
- **THEN** 系统返回错误 CodeAccountNotFound "账号不存在"
#### Scenario: 密码哈希
- **WHEN** 密码修改成功
- **THEN** 系统使用 bcrypt.GenerateFromPassword 哈希密码,并将哈希值存储到 password 字段
#### Scenario: 修改超级管理员密码
- **WHEN** 调用密码修改接口修改超级管理员user_type=1的密码
- **THEN** 系统允许修改(超级管理员密码可以被重置)
---
### Requirement: 平台账号状态切换
系统 SHALL 提供专门的状态切换接口,允许启用或禁用平台账号。状态值必须为 0禁用或 1启用操作自动设置 updater 字段。
#### Scenario: 启用平台账号
- **WHEN** 调用状态切换接口 `PUT /api/admin/platform-accounts/:id/status` 并传递 `status=1`
- **THEN** 系统将账号状态设置为启用status=1设置 updater 字段
#### Scenario: 禁用平台账号
- **WHEN** 调用状态切换接口并传递 `status=0`
- **THEN** 系统将账号状态设置为禁用status=0设置 updater 字段
#### Scenario: 无效状态值
- **WHEN** 调用状态切换接口传递的 status 不是 0 或 1
- **THEN** 系统拒绝修改并返回错误 CodeInvalidParam "状态值必须为 0 或 1"
#### Scenario: 账号不存在
- **WHEN** 调用状态切换接口传递的账号ID不存在
- **THEN** 系统返回错误 CodeAccountNotFound "账号不存在"
#### Scenario: 禁用超级管理员
- **WHEN** 调用状态切换接口禁用超级管理员user_type=1
- **THEN** 系统允许禁用(超级管理员可以被禁用)
#### Scenario: 已禁用账号无法登录
- **WHEN** 账号状态为禁用status=0时尝试登录
- **THEN** 认证系统拒绝登录并返回错误 CodeAccountDisabled "账号已被禁用"
---
### Requirement: 平台账号 CRUD 复用
系统 SHALL 为平台账号管理接口复用现有的账号 CRUD 功能,包括新增、查询详情、编辑、删除和角色管理,确保代码复用和功能一致性。
#### Scenario: 新增平台账号
- **WHEN** 调用 `POST /api/admin/platform-accounts` 创建账号
- **THEN** 系统复用现有 AccountHandler.Create 方法,限制 user_type 必须为 1 或 2
#### Scenario: 查询平台账号详情
- **WHEN** 调用 `GET /api/admin/platform-accounts/:id` 查询账号
- **THEN** 系统复用现有 AccountHandler.Get 方法,返回账号完整信息
#### Scenario: 编辑平台账号
- **WHEN** 调用 `PUT /api/admin/platform-accounts/:id` 更新账号
- **THEN** 系统复用现有 AccountHandler.Update 方法,支持部分字段更新
#### Scenario: 删除平台账号
- **WHEN** 调用 `DELETE /api/admin/platform-accounts/:id` 删除账号
- **THEN** 系统复用现有 AccountHandler.Delete 方法,执行软删除
#### Scenario: 分配角色
- **WHEN** 调用 `POST /api/admin/platform-accounts/:id/roles` 分配角色
- **THEN** 系统复用现有 AccountHandler.AssignRoles 方法,支持空数组和超级管理员保护
#### Scenario: 查询账号角色
- **WHEN** 调用 `GET /api/admin/platform-accounts/:id/roles` 查询角色
- **THEN** 系统复用现有 AccountHandler.GetRoles 方法,返回角色列表
#### Scenario: 移除单个角色
- **WHEN** 调用 `DELETE /api/admin/platform-accounts/:id/roles/:role_id` 移除角色
- **THEN** 系统复用现有 AccountHandler.RemoveRole 方法,删除角色关联