feat: 实现企业卡授权和授权记录管理功能
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m9s

主要功能:
- 添加企业卡授权/回收接口 (POST /enterprises/:id/allocate-cards, recall-cards)
- 添加授权记录管理接口 (GET/PUT /authorizations)
- 实现代理用户数据权限过滤(只能查看自己店铺下企业的授权记录)
- 添加 GORM callback 支持授权记录表的数据权限过滤

技术改进:
- 原生 SQL 查询手动添加数据权限过滤(ListWithJoin, GetByIDWithJoin)
- 移除卡授权预检接口(allocate-cards/preview),保留内部方法
- 完善单元测试和集成测试覆盖
This commit is contained in:
2026-01-26 15:07:03 +08:00
parent 45aa7deb87
commit fdcff33058
42 changed files with 4782 additions and 298 deletions

View File

@@ -0,0 +1,112 @@
# authorization-record Specification
## Purpose
TBD - created by archiving change add-authorization-record-management. Update Purpose after archive.
## Requirements
### Requirement: 授权记录列表查询
系统 SHALL 提供授权记录列表接口,支持分页和多条件筛选。
#### Scenario: 平台用户查询所有授权记录
- **WHEN** 平台用户请求 `GET /api/admin/authorizations`
- **THEN** 系统返回所有授权记录(包含有效和已回收)
- **AND** 每条记录包含企业名称、卡信息ICCID/MSISDN、授权人名称
#### Scenario: 代理用户查询授权记录
- **WHEN** 代理用户请求 `GET /api/admin/authorizations`
- **THEN** 系统只返回该代理店铺下企业的授权记录
- **AND** 不包含下级店铺的授权记录
#### Scenario: 按企业筛选
- **WHEN** 请求包含 `enterprise_id` 参数
- **THEN** 系统只返回该企业的授权记录
#### Scenario: 按ICCID模糊查询
- **WHEN** 请求包含 `iccid` 参数
- **THEN** 系统返回 ICCID 包含该值的授权记录
#### Scenario: 按授权人类型筛选
- **WHEN** 请求包含 `authorizer_type` 参数2=平台3=代理)
- **THEN** 系统只返回该类型授权人创建的记录
#### Scenario: 按状态筛选
- **WHEN** 请求包含 `status` 参数
- **AND** `status=1` 表示有效,`status=0` 表示已回收
- **THEN** 系统只返回对应状态的授权记录
#### Scenario: 按授权时间范围筛选
- **WHEN** 请求包含 `start_time` 和/或 `end_time` 参数
- **THEN** 系统只返回授权时间在该范围内的记录
#### Scenario: 分页查询
- **WHEN** 请求包含 `page``page_size` 参数
- **THEN** 系统返回对应页的数据
- **AND** 响应包含 `total` 总记录数
### Requirement: 授权记录详情查询
系统 SHALL 提供授权记录详情接口,返回单条记录的完整信息。
#### Scenario: 查询存在的授权记录
- **WHEN** 请求 `GET /api/admin/authorizations/:id`
- **AND** 记录存在且用户有权限查看
- **THEN** 系统返回该授权记录的完整信息
- **AND** 包含关联的企业名称、卡信息、授权人名称、回收人名称
#### Scenario: 查询不存在的授权记录
- **WHEN** 请求 `GET /api/admin/authorizations/:id`
- **AND** 记录不存在
- **THEN** 系统返回 404 错误
#### Scenario: 查询无权限的授权记录
- **WHEN** 代理用户请求 `GET /api/admin/authorizations/:id`
- **AND** 该记录不属于代理的店铺
- **THEN** 系统返回 404 错误(不暴露记录存在)
### Requirement: 修改授权备注
系统 SHALL 提供修改授权备注的接口。
#### Scenario: 平台用户修改任意备注
- **WHEN** 平台用户请求 `PUT /api/admin/authorizations/:id/remark`
- **AND** 提供新的备注内容
- **THEN** 系统更新该授权记录的备注
- **AND** 返回更新后的记录
#### Scenario: 代理用户修改备注
- **WHEN** 代理用户请求 `PUT /api/admin/authorizations/:id/remark`
- **AND** 该记录属于代理的店铺
- **THEN** 系统更新该授权记录的备注
#### Scenario: 代理用户修改无权限的备注
- **WHEN** 代理用户请求 `PUT /api/admin/authorizations/:id/remark`
- **AND** 该记录不属于代理的店铺
- **THEN** 系统返回 404 错误
#### Scenario: 备注长度限制
- **WHEN** 请求的备注内容超过 500 字符
- **THEN** 系统返回 400 错误,提示备注过长
### Requirement: 授权记录响应格式
系统 SHALL 使用统一的响应格式返回授权记录。
#### Scenario: 列表响应格式
- **WHEN** 返回授权记录列表
- **THEN** 每条记录包含以下字段:
- `id`: 记录ID
- `enterprise_id`: 企业ID
- `enterprise_name`: 企业名称
- `card_id`: 卡ID
- `iccid`: ICCID
- `msisdn`: 手机号
- `authorized_by`: 授权人ID
- `authorizer_name`: 授权人名称
- `authorizer_type`: 授权人类型
- `authorized_at`: 授权时间
- `revoked_by`: 回收人ID可空
- `revoker_name`: 回收人名称(可空)
- `revoked_at`: 回收时间(可空)
- `status`: 状态1=有效0=已回收)
- `remark`: 备注

View File

@@ -22,6 +22,18 @@ TBD - created by archiving change refactor-framework-cleanup. Update Purpose aft
- **WHEN** 表不包含 owner_id 字段
- **THEN** 不添加数据权限过滤条件
#### Scenario: 授权记录表特殊处理
- **WHEN** 查询 `tb_enterprise_card_authorization`
- **AND** 当前用户是代理用户
- **THEN** 自动添加 WHERE enterprise_id IN (SELECT id FROM tb_enterprise WHERE owner_shop_id = 当前店铺ID) 条件
- **AND** 不包含下级店铺的数据
#### Scenario: 平台用户查询授权记录
- **WHEN** 查询 `tb_enterprise_card_authorization`
- **AND** 当前用户是平台用户或超级管理员
- **THEN** 不添加数据权限过滤条件
- **AND** 可查询所有授权记录
### Requirement: Skip Data Permission
系统 SHALL 支持通过 Context 绕过数据权限过滤。