This commit is contained in:
Break
2026-06-02 16:56:18 +08:00
parent a6cd550b94
commit 36e68e6672
6 changed files with 269 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
## Context
现有代理开放接口(`internal/service/agent_open_api/service.go`)已实现卡维度的流量查询、状态查询、实名查询和钱包购买。设备维度的 Gateway 操作(切网、重启、恢复出厂)已在 `internal/service/device/gateway_service.go` 中实现,设备级套餐流量查询通过 `PackageUsageStore.ListByCarrier(ctx, "device", deviceID, ...)` 支持。
本次变更在现有 `agent_open_api` service 中扩展设备维度能力,复用已有的 device service 和 package usage store不引入新的数据模型或迁移。
## Goals / Non-Goals
**Goals:**
- 新增 4 个代理开放接口:设备流量查询、切网、重启、恢复出厂
- 复用现有 device service 的 Gateway 调用逻辑,不重复实现
- 权限校验与卡接口保持一致(`shop_id IN SubordinateShopIDs`
- 设备标识符支持虚拟号和 IMEI
**Non-Goals:**
- 不新增数据库表或迁移
- 不修改现有卡接口
- 不支持 SN 作为设备标识符(开放接口只暴露虚拟号/IMEI
- 不支持批量设备操作
## Decisions
### 决策一agent_open_api service 注入 device.Service 依赖
**选择**:在 `agent_open_api.Service` 结构体中新增 `deviceService *device.Service` 字段,通过构造函数注入。
**理由**device service 已封装了 Gateway 调用、审计日志和设备查询逻辑,直接复用避免重复实现。相比新建独立函数,注入 service 更符合项目分层规范。
**替代方案**:在 agent_open_api service 中直接注入 deviceStore 和 gatewayClient自行实现权限校验和 Gateway 调用。缺点是重复了 device service 中已有的审计日志和错误处理逻辑。
### 决策二:设备权限校验方式
**选择**:查询设备后,手动检查 `device.ShopID != nil && SubordinateShopIDs 包含 *device.ShopID`
**理由**`ApplyShopFilter` 作用于 GORM query而 device service 的 `GetByIdentifier` 内部已有自己的查询逻辑。为避免侵入 device service在 agent_open_api service 层做显式权限校验,与卡接口的 `resolveOpenAPICard` 模式一致。
**实现**:新增 `resolveOpenAPIDevice(ctx, deviceNo)` 私有方法,复用 `device.Service.GetDeviceByIdentifier`,然后校验 shop_id。
### 决策三:设备流量查询复用 PackageUsageStore
**选择**:直接在 `agent_open_api.Service` 中调用已注入的 `packageUsageStore.ListByCarrier(ctx, "device", device.ID, &status)`
**理由**`packageUsageStore` 已在 agent_open_api service 中注入(用于卡流量查询),`ListByCarrier` 支持 `"device"` 类型,无需额外改动 store 层。
### 决策四:切网接口调用 device.Service.GatewaySwitchCard
**选择**agent_open_api service 调用 `deviceService.GatewaySwitchCard(ctx, identifier, &dto.SwitchCardRequest{ICCID: req.ICCID})`
**理由**`GatewaySwitchCard` 已包含审计日志记录,开放接口复用可保证操作可追溯。
**注意**`GatewaySwitchCard` 内部通过 `getGatewayDevice` 再次查询设备,存在两次查询。考虑到操作频率低,接受此开销,不做优化。
## Risks / Trade-offs
- **[风险] device service 审计日志中的操作者信息**`GatewaySwitchCard` 等方法通过 `middleware.GetUserIDFromContext` 获取操作者 ID。开放接口认证中间件已将代理账号 ID 写入 `ContextKeyUserID`,审计日志可正确记录操作者。→ 无需额外处理。
- **[风险] 设备标识符两次查询**`resolveOpenAPIDevice` 查一次,`GatewaySwitchCard` 内部再查一次。→ 接受,操作类接口频率低,影响可忽略。
- **[Trade-off] 不支持 SN**admin 接口支持虚拟号/IMEI/SN开放接口只支持虚拟号/IMEI。→ 简化外部接口SN 是内部管理标识,不适合对外暴露。
## Migration Plan
无数据库变更,无需迁移。直接部署新版本即可。
## Open Questions
(无)