feat(account): 实现平台账号管理功能
- 新增平台账号列表查询接口(自动筛选超级管理员和平台用户) - 新增密码修改和状态切换专用接口 - 增强角色分配功能,支持空数组清空所有角色 - 新增超级管理员保护机制,禁止分配角色 - 新增完整的集成测试和OpenSpec规范文档
This commit is contained in:
@@ -0,0 +1,388 @@
|
||||
# 平台账号管理功能实现
|
||||
|
||||
## 📋 变更概述
|
||||
|
||||
**Change ID**: `add-platform-account-management`
|
||||
|
||||
**目标**:实现专门的平台账号(平台用户 + 超级管理员)管理接口,提供语义清晰的专用操作,并增强角色分配灵活性。
|
||||
|
||||
**验证状态**: ✅ PASSED (`openspec validate add-platform-account-management --strict`)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 功能需求(用户需求)
|
||||
|
||||
根据原始需求,需要实现以下接口:
|
||||
|
||||
1. ✅ **分页查询列表**
|
||||
- 查询条件:账号名称
|
||||
- 返回值:名称、手机号、创建时间、状态(启用/停用)
|
||||
- **包含超级管理员**
|
||||
|
||||
2. ✅ **新增平台账号**
|
||||
- 表单参数:名称、手机号(登录账号)、登录密码、状态(启用/禁用)、选择角色(多选)
|
||||
|
||||
3. ✅ **编辑平台账号**
|
||||
- 参考新增接口
|
||||
|
||||
4. ✅ **修改密码**
|
||||
- 表单参数:新密码(无需旧密码)
|
||||
|
||||
5. ✅ **启用/禁用接口**
|
||||
- 独立的状态切换接口
|
||||
|
||||
6. ✅ **超级管理员出现在列表中**
|
||||
- 列表自动包含 `user_type IN (1, 2)` 的账号
|
||||
|
||||
---
|
||||
|
||||
## 🔧 技术实现方案
|
||||
|
||||
### 1. 新增接口列表
|
||||
|
||||
#### 核心管理接口
|
||||
| 方法 | 路径 | 说明 | 实现方式 |
|
||||
|------|------|------|---------|
|
||||
| `GET` | `/api/admin/platform-accounts` | 平台账号列表(含超管) | **新增** `ListPlatformAccounts` |
|
||||
| `POST` | `/api/admin/platform-accounts` | 新增平台账号 | **复用** `Create` |
|
||||
| `GET` | `/api/admin/platform-accounts/:id` | 获取详情 | **复用** `Get` |
|
||||
| `PUT` | `/api/admin/platform-accounts/:id` | 编辑平台账号 | **复用** `Update` |
|
||||
| `DELETE` | `/api/admin/platform-accounts/:id` | 删除平台账号 | **复用** `Delete` |
|
||||
|
||||
#### 专用操作接口
|
||||
| 方法 | 路径 | 说明 | 实现方式 |
|
||||
|------|------|------|---------|
|
||||
| `PUT` | `/api/admin/platform-accounts/:id/password` | 修改密码 | **新增** `UpdatePassword` |
|
||||
| `PUT` | `/api/admin/platform-accounts/:id/status` | 启用/禁用 | **新增** `UpdateStatus` |
|
||||
|
||||
#### 角色管理接口
|
||||
| 方法 | 路径 | 说明 | 实现方式 |
|
||||
|------|------|------|---------|
|
||||
| `POST` | `/api/admin/platform-accounts/:id/roles` | 分配角色 | **增强** `AssignRoles` |
|
||||
| `GET` | `/api/admin/platform-accounts/:id/roles` | 获取角色列表 | **复用** `GetRoles` |
|
||||
| `DELETE` | `/api/admin/platform-accounts/:id/roles/:role_id` | 移除单个角色 | **复用** `RemoveRole` |
|
||||
|
||||
### 2. 新增 DTO
|
||||
|
||||
```go
|
||||
// UpdatePasswordRequest 修改密码请求
|
||||
type UpdatePasswordRequest struct {
|
||||
NewPassword string `json:"new_password" validate:"required,min=8,max=32"`
|
||||
}
|
||||
|
||||
// UpdateStatusRequest 状态切换请求
|
||||
type UpdateStatusRequest struct {
|
||||
Status int `json:"status" validate:"required,min=0,max=1"`
|
||||
}
|
||||
|
||||
// PlatformAccountListRequest 平台账号列表请求
|
||||
type PlatformAccountListRequest struct {
|
||||
Page int `json:"page" query:"page" validate:"omitempty,min=1"`
|
||||
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100"`
|
||||
Username string `json:"username" query:"username" validate:"omitempty,max=50"`
|
||||
Phone string `json:"phone" query:"phone" validate:"omitempty,max=20"`
|
||||
Status *int `json:"status" query:"status" validate:"omitempty,min=0,max=1"`
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 新增 Service 方法
|
||||
|
||||
```go
|
||||
// UpdatePassword 修改密码
|
||||
func (s *Service) UpdatePassword(ctx context.Context, accountID uint, newPassword string) error
|
||||
|
||||
// UpdateStatus 状态切换
|
||||
func (s *Service) UpdateStatus(ctx context.Context, accountID uint, status int) error
|
||||
|
||||
// ListPlatformAccounts 平台账号列表查询(自动筛选 user_type IN (1,2))
|
||||
func (s *Service) ListPlatformAccounts(ctx context.Context, req *model.PlatformAccountListRequest) ([]*model.Account, int64, error)
|
||||
```
|
||||
|
||||
### 4. 角色分配增强
|
||||
|
||||
**修改前**:
|
||||
```go
|
||||
type AssignRolesRequest struct {
|
||||
RoleIDs []uint `json:"role_ids" validate:"required,min=1"` // 必填,至少1个
|
||||
}
|
||||
```
|
||||
|
||||
**修改后**:
|
||||
```go
|
||||
type AssignRolesRequest struct {
|
||||
RoleIDs []uint `json:"role_ids" validate:"omitempty"` // 可选,允许空数组
|
||||
}
|
||||
```
|
||||
|
||||
**业务逻辑调整**:
|
||||
- ✅ 允许传递空数组 `[]` 清空所有角色
|
||||
- ✅ 超级管理员(`user_type=1`)禁止分配角色,返回错误
|
||||
- ✅ 平台用户(`user_type=2`)可分配无限个平台角色
|
||||
|
||||
---
|
||||
|
||||
## 📝 API 使用示例
|
||||
|
||||
### 1. 查询平台账号列表
|
||||
|
||||
**请求**:
|
||||
```http
|
||||
GET /api/admin/platform-accounts?page=1&page_size=20&username=admin&status=1
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"phone": "13800000000",
|
||||
"user_type": 1,
|
||||
"status": 1,
|
||||
"created_at": "2025-01-14T10:00:00Z",
|
||||
"updated_at": "2025-01-14T10:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"username": "platform_user",
|
||||
"phone": "13900000000",
|
||||
"user_type": 2,
|
||||
"status": 1,
|
||||
"created_at": "2025-01-14T11:00:00Z",
|
||||
"updated_at": "2025-01-14T11:00:00Z"
|
||||
}
|
||||
],
|
||||
"total": 2,
|
||||
"page": 1,
|
||||
"size": 20
|
||||
},
|
||||
"timestamp": "2025-01-14T10:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 新增平台账号
|
||||
|
||||
**请求**:
|
||||
```http
|
||||
POST /api/admin/platform-accounts
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"username": "new_platform_user",
|
||||
"phone": "13700000000",
|
||||
"password": "SecurePass@123",
|
||||
"user_type": 2
|
||||
}
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"id": 3,
|
||||
"username": "new_platform_user",
|
||||
"phone": "13700000000",
|
||||
"user_type": 2,
|
||||
"status": 1,
|
||||
"created_at": "2025-01-14T12:00:00Z"
|
||||
},
|
||||
"timestamp": "2025-01-14T12:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 修改密码
|
||||
|
||||
**请求**:
|
||||
```http
|
||||
PUT /api/admin/platform-accounts/3/password
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"new_password": "NewSecurePass@456"
|
||||
}
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "success",
|
||||
"data": null,
|
||||
"timestamp": "2025-01-14T12:05:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 启用/禁用账号
|
||||
|
||||
**请求**:
|
||||
```http
|
||||
PUT /api/admin/platform-accounts/3/status
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"status": 0
|
||||
}
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "success",
|
||||
"data": null,
|
||||
"timestamp": "2025-01-14T12:10:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 分配角色(支持空数组)
|
||||
|
||||
**清空所有角色**:
|
||||
```http
|
||||
POST /api/admin/platform-accounts/3/roles
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"role_ids": []
|
||||
}
|
||||
```
|
||||
|
||||
**分配多个角色**:
|
||||
```http
|
||||
POST /api/admin/platform-accounts/3/roles
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"role_ids": [1, 2, 3]
|
||||
}
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": 10,
|
||||
"account_id": 3,
|
||||
"role_id": 1,
|
||||
"status": 1
|
||||
}
|
||||
],
|
||||
"timestamp": "2025-01-14T12:15:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 超级管理员保护
|
||||
|
||||
**尝试为超级管理员分配角色**(会被拒绝):
|
||||
```http
|
||||
POST /api/admin/platform-accounts/1/roles
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"role_ids": [1]
|
||||
}
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"code": 1001,
|
||||
"msg": "超级管理员不允许分配角色",
|
||||
"data": null,
|
||||
"timestamp": "2025-01-14T12:20:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 业务规则
|
||||
|
||||
### 用户类型筛选
|
||||
- ✅ **平台账号列表**:自动筛选 `user_type IN (1, 2)`
|
||||
- ✅ **包含超级管理员**:`user_type=1` 的账号出现在列表中
|
||||
|
||||
### 角色分配规则
|
||||
| 用户类型 | 允许分配角色数量 | 角色类型限制 | 是否允许清空角色 |
|
||||
|---------|----------------|-------------|----------------|
|
||||
| 超级管理员(1) | ❌ 不允许分配 | - | ❌ |
|
||||
| 平台用户(2) | ✅ 无限制 | 只能分配平台角色(`role_type=1`) | ✅ |
|
||||
| 代理账号(3) | ✅ 最多 1 个 | 只能分配客户角色(`role_type=2`) | ✅ |
|
||||
| 企业账号(4) | ✅ 最多 1 个 | 只能分配客户角色(`role_type=2`) | ✅ |
|
||||
|
||||
### 密码规则
|
||||
- ✅ 长度:8-32 位
|
||||
- ✅ 存储:bcrypt 哈希
|
||||
- ✅ 修改:无需验证旧密码(管理员重置场景)
|
||||
|
||||
### 状态规则
|
||||
- ✅ 启用:`status=1`
|
||||
- ✅ 禁用:`status=0`
|
||||
- ✅ 禁用账号无法登录(认证层拦截)
|
||||
|
||||
---
|
||||
|
||||
## 📂 文件清单
|
||||
|
||||
### 提案文件
|
||||
- `openspec/changes/add-platform-account-management/proposal.md` - 变更提案
|
||||
- `openspec/changes/add-platform-account-management/tasks.md` - 实现任务清单
|
||||
- `openspec/changes/add-platform-account-management/README.md` - 本文档
|
||||
|
||||
### Spec Deltas
|
||||
- `openspec/changes/add-platform-account-management/specs/role-permission/spec.md` - 角色分配逻辑调整
|
||||
- `openspec/changes/add-platform-account-management/specs/user-organization/spec.md` - 平台账号管理增强
|
||||
|
||||
---
|
||||
|
||||
## ✅ 验证结果
|
||||
|
||||
```bash
|
||||
$ openspec validate add-platform-account-management --strict
|
||||
Change 'add-platform-account-management' is valid
|
||||
```
|
||||
|
||||
**验证通过**:所有 delta specs 格式正确,需求完整,场景覆盖充分。
|
||||
|
||||
---
|
||||
|
||||
## 🚀 下一步
|
||||
|
||||
### 1. 审查提案
|
||||
请审查以下文件:
|
||||
- `openspec/changes/add-platform-account-management/proposal.md` - 确认业务需求和影响范围
|
||||
- `openspec/changes/add-platform-account-management/tasks.md` - 确认实现任务清单
|
||||
- `openspec/changes/add-platform-account-management/specs/*/spec.md` - 确认需求定义
|
||||
|
||||
### 2. 批准后开始实现
|
||||
批准后,我将按照 `tasks.md` 的顺序逐步实现:
|
||||
1. Model 层(DTO 定义)
|
||||
2. Service 层(业务逻辑)
|
||||
3. Handler 层(HTTP 处理)
|
||||
4. 路由注册
|
||||
5. 单元测试
|
||||
6. 集成测试
|
||||
7. 文档更新
|
||||
|
||||
### 3. 实现完成后归档
|
||||
实现完成并测试通过后,使用以下命令归档:
|
||||
```bash
|
||||
openspec archive add-platform-account-management
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 问题反馈
|
||||
|
||||
如有任何问题或需要调整,请告知:
|
||||
- 业务需求是否准确?
|
||||
- 接口设计是否合理?
|
||||
- 角色分配逻辑是否符合预期?
|
||||
- 是否需要额外功能?
|
||||
@@ -0,0 +1,128 @@
|
||||
# Change: 实现平台账号管理接口
|
||||
|
||||
## Why
|
||||
|
||||
当前系统已有通用的账号管理功能,但缺少针对**平台账号(平台用户 + 超级管理员)**的专用管理接口。业务需要:
|
||||
|
||||
1. **专门的平台账号列表**:筛选出 `user_type IN (1, 2)` 的账号,包含超级管理员
|
||||
2. **语义明确的专用接口**:密码修改、启用/禁用需要独立端点,而非通过通用 Update 接口
|
||||
3. **角色分配灵活性**:允许清空角色、支持可选角色分配
|
||||
4. **超级管理员保护**:超级管理员在列表中只读显示,禁止编辑角色
|
||||
|
||||
**现状**:
|
||||
- ✅ 已有账号 CRUD 功能(`/internal/handler/admin/account.go`)
|
||||
- ✅ 已有角色分配功能(`AssignRoles`, `GetRoles`, `RemoveRole`)
|
||||
- ❌ 缺少专门的密码修改接口(当前混在 Update 接口中)
|
||||
- ❌ 缺少专门的启用/禁用接口(当前混在 Update 接口中)
|
||||
- ❌ 角色分配要求至少 1 个角色(不允许清空)
|
||||
- ❌ 没有超级管理员编辑保护
|
||||
|
||||
## What Changes
|
||||
|
||||
### 1. 新增专用接口
|
||||
|
||||
#### Handler 层新增方法
|
||||
- `UpdatePassword(c *fiber.Ctx)` - 修改密码专用接口
|
||||
- `UpdateStatus(c *fiber.Ctx)` - 启用/禁用专用接口
|
||||
- `ListPlatformAccounts(c *fiber.Ctx)` - 平台账号列表查询(user_type IN (1,2))
|
||||
|
||||
#### Service 层新增方法
|
||||
- `UpdatePassword(ctx, accountID, newPassword)` - 密码修改业务逻辑
|
||||
- `UpdateStatus(ctx, accountID, status)` - 状态切换业务逻辑
|
||||
- `ListPlatformAccounts(ctx, req)` - 平台账号列表查询(自动筛选 user_type)
|
||||
|
||||
#### 新增 DTO
|
||||
- `UpdatePasswordRequest` - 密码修改请求(只包含 `new_password`)
|
||||
- `UpdateStatusRequest` - 状态修改请求(只包含 `status`)
|
||||
- `PlatformAccountListRequest` - 平台账号列表请求(移除 user_type 筛选)
|
||||
|
||||
### 2. 优化现有角色分配逻辑
|
||||
|
||||
#### Service 层修改
|
||||
- `AssignRoles` 方法增强:
|
||||
- 允许 `roleIDs` 为空数组(清空所有角色)
|
||||
- 超级管理员(`user_type=1`)禁止分配角色,返回错误
|
||||
- 平台用户(`user_type=2`)可分配无限个平台角色(`role_type=1`)
|
||||
|
||||
#### DTO 修改
|
||||
- `AssignRolesRequest.RoleIDs` 改为可选(`validate:"omitempty"`)
|
||||
|
||||
### 3. 新增路由
|
||||
|
||||
```go
|
||||
// 平台账号专用路由
|
||||
GET /api/admin/platform-accounts // 平台账号列表(含超级管理员)
|
||||
POST /api/admin/platform-accounts // 新增平台账号
|
||||
GET /api/admin/platform-accounts/:id // 获取详情
|
||||
PUT /api/admin/platform-accounts/:id // 编辑平台账号
|
||||
DELETE /api/admin/platform-accounts/:id // 删除平台账号
|
||||
|
||||
// 专用操作接口
|
||||
PUT /api/admin/platform-accounts/:id/password // 修改密码
|
||||
PUT /api/admin/platform-accounts/:id/status // 启用/禁用
|
||||
|
||||
// 角色管理
|
||||
POST /api/admin/platform-accounts/:id/roles // 分配角色(支持空数组)
|
||||
GET /api/admin/platform-accounts/:id/roles // 获取角色列表
|
||||
DELETE /api/admin/platform-accounts/:id/roles/:role_id // 移除单个角色
|
||||
```
|
||||
|
||||
### 4. 响应格式调整
|
||||
|
||||
**列表返回字段**(符合需求):
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"phone": "13800000000",
|
||||
"created_at": "2025-01-14T10:30:00Z",
|
||||
"status": 1,
|
||||
"user_type": 1
|
||||
}
|
||||
],
|
||||
"total": 10,
|
||||
"page": 1,
|
||||
"size": 20
|
||||
}
|
||||
```
|
||||
|
||||
## Impact
|
||||
|
||||
### 受影响的 Specs
|
||||
- `role-permission` - 角色分配逻辑调整(允许空数组)
|
||||
- `user-organization` - 平台账号管理增强
|
||||
|
||||
### 受影响的代码模块
|
||||
- `internal/handler/admin/account.go` - 新增 3 个 Handler 方法
|
||||
- `internal/service/account/service.go` - 新增 2 个 Service 方法,修改 AssignRoles
|
||||
- `internal/model/account_dto.go` - 新增 2 个 DTO,修改 AssignRolesRequest
|
||||
- `internal/routes/account.go` - 新增路由注册
|
||||
|
||||
### Breaking Changes
|
||||
无。新增功能向后兼容,现有接口保持不变。
|
||||
|
||||
### 数据库变更
|
||||
无。复用现有 `tb_account` 表结构。
|
||||
|
||||
### 迁移计划
|
||||
无需迁移。新接口与现有接口共存,前端可按需切换。
|
||||
|
||||
## Risks
|
||||
|
||||
1. **角色分配空数组行为**:允许清空所有角色可能导致账号无权限
|
||||
- **缓解措施**:前端二次确认,文档明确说明
|
||||
|
||||
2. **超级管理员保护**:禁止编辑超级管理员角色可能影响已有流程
|
||||
- **缓解措施**:仅对 `user_type=1` 生效,平台用户不受影响
|
||||
|
||||
3. **路由命名冲突**:新增 `/platform-accounts` 路由可能与未来规划冲突
|
||||
- **缓解措施**:遵循 RESTful 规范,路径清晰语义化
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. ✅ **已确认**:超级管理员是否需要出现在平台账号列表? → **是**
|
||||
2. ✅ **已确认**:修改密码是否需要旧密码验证? → **否**(管理员重置场景)
|
||||
3. ✅ **已确认**:角色分配是否必填? → **可选**(允许无角色账号)
|
||||
4. ✅ **已确认**:是否允许清空所有角色? → **是**(灵活分配)
|
||||
@@ -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列表
|
||||
@@ -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 方法,删除角色关联
|
||||
@@ -0,0 +1,134 @@
|
||||
# 实现任务清单
|
||||
|
||||
## 1. 准备工作
|
||||
- [x] 1.1 阅读现有账号管理代码(Handler/Service/Store)
|
||||
- [x] 1.2 确认现有 DTO 定义和验证规则
|
||||
- [x] 1.3 确认现有路由注册模式
|
||||
|
||||
## 2. Model 层(DTO 定义)
|
||||
- [x] 2.1 在 `internal/model/account_dto.go` 中新增 `UpdatePasswordRequest`
|
||||
- 字段:`new_password` (必填,8-32位)
|
||||
- [x] 2.2 在 `internal/model/account_dto.go` 中新增 `UpdateStatusRequest`
|
||||
- 字段:`status` (必填,0 或 1)
|
||||
- [x] 2.3 在 `internal/model/account_dto.go` 中新增 `PlatformAccountListRequest`
|
||||
- 复用 `AccountListRequest`,移除 `user_type` 字段
|
||||
- [x] 2.4 修改 `AssignRolesRequest`
|
||||
- 将 `role_ids` 验证规则从 `required,min=1` 改为 `omitempty`
|
||||
- 允许空数组
|
||||
|
||||
## 3. Service 层(业务逻辑)
|
||||
- [x] 3.1 在 `internal/service/account/service.go` 中新增 `UpdatePassword` 方法
|
||||
- 验证账号存在
|
||||
- 验证密码格式
|
||||
- bcrypt 哈希新密码
|
||||
- 更新数据库
|
||||
- 设置 Updater 字段
|
||||
- [x] 3.2 在 `internal/service/account/service.go` 中新增 `UpdateStatus` 方法
|
||||
- 验证账号存在
|
||||
- 验证状态值(0 或 1)
|
||||
- 更新数据库
|
||||
- 设置 Updater 字段
|
||||
- [x] 3.3 在 `internal/service/account/service.go` 中新增 `ListPlatformAccounts` 方法
|
||||
- 自动筛选 `user_type IN (1, 2)`
|
||||
- 支持 username, phone, status 筛选
|
||||
- 支持分页
|
||||
- 返回账号列表 + 总数
|
||||
- [x] 3.4 修改 `AssignRoles` 方法
|
||||
- 支持 `roleIDs` 为空数组(清空所有角色)
|
||||
- 超级管理员(`user_type=1`)禁止分配角色,返回错误
|
||||
- 空数组时删除所有现有角色
|
||||
- 非空数组时保持现有逻辑
|
||||
|
||||
## 4. Handler 层(HTTP 处理)
|
||||
- [x] 4.1 在 `internal/handler/admin/account.go` 中新增 `UpdatePassword` 方法
|
||||
- 解析路径参数 `id`
|
||||
- 解析请求 body (`UpdatePasswordRequest`)
|
||||
- 调用 `service.UpdatePassword`
|
||||
- 返回 `response.Success(c, nil)`
|
||||
- [x] 4.2 在 `internal/handler/admin/account.go` 中新增 `UpdateStatus` 方法
|
||||
- 解析路径参数 `id`
|
||||
- 解析请求 body (`UpdateStatusRequest`)
|
||||
- 调用 `service.UpdateStatus`
|
||||
- 返回 `response.Success(c, nil)`
|
||||
- [x] 4.3 在 `internal/handler/admin/account.go` 中新增 `ListPlatformAccounts` 方法
|
||||
- 解析查询参数 (`PlatformAccountListRequest`)
|
||||
- 调用 `service.ListPlatformAccounts`
|
||||
- 返回 `response.SuccessWithPagination(c, accounts, total, req.Page, req.PageSize)`
|
||||
|
||||
## 5. 路由注册
|
||||
- [x] 5.1 在 `internal/routes/account.go` 中新增 `registerPlatformAccountRoutes` 函数
|
||||
- 注册 `GET /api/admin/platform-accounts` → `h.ListPlatformAccounts`
|
||||
- 注册 `POST /api/admin/platform-accounts` → `h.Create`(复用现有)
|
||||
- 注册 `GET /api/admin/platform-accounts/:id` → `h.Get`(复用现有)
|
||||
- 注册 `PUT /api/admin/platform-accounts/:id` → `h.Update`(复用现有)
|
||||
- 注册 `DELETE /api/admin/platform-accounts/:id` → `h.Delete`(复用现有)
|
||||
- 注册 `PUT /api/admin/platform-accounts/:id/password` → `h.UpdatePassword`
|
||||
- 注册 `PUT /api/admin/platform-accounts/:id/status` → `h.UpdateStatus`
|
||||
- 注册 `POST /api/admin/platform-accounts/:id/roles` → `h.AssignRoles`(复用现有)
|
||||
- 注册 `GET /api/admin/platform-accounts/:id/roles` → `h.GetRoles`(复用现有)
|
||||
- 注册 `DELETE /api/admin/platform-accounts/:id/roles/:role_id` → `h.RemoveRole`(复用现有)
|
||||
- [x] 5.2 在 `internal/routes/router.go` 中调用 `registerPlatformAccountRoutes`
|
||||
|
||||
## 6. 错误码定义
|
||||
- [x] 6.1 检查 `pkg/errors/codes.go` 中是否有所需错误码
|
||||
- `CodeAccountNotFound` (已有)
|
||||
- `CodeInvalidPassword` (已有)
|
||||
- `CodeInvalidParam` (已有)
|
||||
- `CodeUnauthorized` (已有)
|
||||
- [x] 6.2 如需新增,添加错误码和消息
|
||||
|
||||
## 7. 常量定义
|
||||
- [x] 7.1 检查 `pkg/constants/constants.go` 中状态常量
|
||||
- `StatusDisabled = 0` (已有)
|
||||
- `StatusEnabled = 1` (已有)
|
||||
- `UserTypeSuperAdmin = 1` (已有)
|
||||
- `UserTypePlatform = 2` (已有)
|
||||
|
||||
## 8. 单元测试
|
||||
- [x] 8.1 为 `UpdatePassword` 方法编写单元测试
|
||||
- 测试成功场景
|
||||
- 测试账号不存在场景
|
||||
- 测试密码格式错误场景
|
||||
- [x] 8.2 为 `UpdateStatus` 方法编写单元测试
|
||||
- 测试启用/禁用场景
|
||||
- 测试账号不存在场景
|
||||
- 测试无效状态值场景
|
||||
- [x] 8.3 为 `ListPlatformAccounts` 方法编写单元测试
|
||||
- 测试自动筛选 user_type IN (1,2)
|
||||
- 测试分页功能
|
||||
- 测试筛选条件(username, phone, status)
|
||||
- [x] 8.4 为修改后的 `AssignRoles` 方法编写测试
|
||||
- 测试空数组清空角色场景
|
||||
- 测试超级管理员禁止分配角色场景
|
||||
- 测试平台用户分配角色场景
|
||||
|
||||
## 9. 集成测试
|
||||
- [x] 9.1 编写 API 集成测试(`tests/integration/platform_account_test.go`)
|
||||
- 测试平台账号列表查询
|
||||
- 测试新增平台账号
|
||||
- 测试修改密码接口
|
||||
- 测试启用/禁用接口
|
||||
- 测试角色分配(含空数组场景)
|
||||
- [x] 9.2 测试超级管理员保护逻辑
|
||||
- 超级管理员出现在列表中
|
||||
- 超级管理员禁止分配角色
|
||||
|
||||
## 10. 文档更新
|
||||
- [x] 10.1 更新 OpenAPI 文档(如果使用 `openapi-generation`)
|
||||
- [x] 10.2 在 `docs/` 目录创建功能总结文档
|
||||
- 接口列表
|
||||
- 请求/响应示例
|
||||
- 错误码说明
|
||||
- 注意事项(超级管理员保护、角色清空等)
|
||||
|
||||
## 11. 验证与清理
|
||||
- [x] 11.1 运行所有单元测试:`go test ./internal/service/account/...`
|
||||
- [x] 11.2 运行集成测试:`go test ./tests/integration/...`
|
||||
- [x] 11.3 使用 `openspec validate add-platform-account-management --strict` 验证提案
|
||||
- [x] 11.4 代码格式化:`gofmt -w .`
|
||||
- [x] 11.5 静态检查:`go vet ./...`
|
||||
|
||||
## 12. 部署准备
|
||||
- [x] 12.1 确认无数据库迁移需求
|
||||
- [x] 12.2 确认向后兼容(现有接口不受影响)
|
||||
- [x] 12.3 准备发布说明(新增接口列表、使用示例)
|
||||
Reference in New Issue
Block a user