# asset-queries Specification ## Purpose 提供基于已知资产 ID 的轻量查询接口,包括实时状态查询、手动刷新、套餐历史列表和当前主套餐详情。供前端在 resolve 之后进行快速轮询和详情展示。 ## Requirements ### Requirement: 轻量实时状态查询 系统 SHALL 提供基于持久化数据的轻量状态查询接口,供前端在已知资产 ID 后进行快速轮询。 **API 端点**: `GET /api/admin/assets/:asset_type/:id/realtime-status` **约束**: - `:asset_type` 取值为 `device` 或 `card` - 此接口**不调用网关**,仅读取 DB/Redis 中持久化的最新数据 - 不包含套餐流量计算(与 resolve 的区别) - "实时性"依赖轮询系统定期刷新(实名状态约 5 分钟,流量约 10 分钟) **card 类型响应字段**: - `network_status`: 网络状态(0-停机 1-开机) - `real_name_status`: 实名状态(0-未实名 1-已实名) - `current_month_usage_mb`: 本月已用流量(持久化缓存值) - `last_sync_at`: 最后与 Gateway 同步时间 **device 类型响应字段**: - `device_protect_status`: 保护期状态(`"none"` / `"stop"` / `"start"`) - `cards`: 所有绑定卡的状态列表(同 DeviceCardInfo 结构) #### Scenario: 查询单卡实时状态 - **WHEN** 管理员调用 `GET /api/admin/assets/card/123/realtime-status` - **THEN** 系统返回该卡的 network_status、real_name_status、current_month_usage_mb、last_sync_at #### Scenario: 查询设备实时状态 - **WHEN** 管理员调用 `GET /api/admin/assets/device/456/realtime-status` - **THEN** 系统返回设备的保护期状态及所有绑定卡的当前状态列表 #### Scenario: asset_type 参数非法 - **WHEN** 管理员调用 `GET /api/admin/assets/unknown-type/123/realtime-status` - **THEN** 系统返回 HTTP 400 参数错误 --- ### Requirement: 手动刷新接口 系统 SHALL 提供手动触发网关同步的接口,用于客服主动刷新资产最新状态。 **API 端点**: `POST /api/admin/assets/:asset_type/:id/refresh` **行为规则**: - card 类型:直接调用 `RefreshCardDataFromGateway(iccid)` 同步网络状态、实名状态、本月流量、最后同步时间 - device 类型:对该设备所有绑定卡遍历调用 `RefreshCardDataFromGateway` **设备类型频率限制**: - 使用 Redis Key `RedisDeviceRefreshCooldownKey(deviceID)` 限频 - 同一设备 30 秒冷却期内不允许重复触发 - 冷却期内调用返回 HTTP 429 **响应**: - 刷新完成后返回刷新后的最新状态(与 realtime-status 响应结构相同) #### Scenario: 刷新单卡状态 - **WHEN** 客服调用 `POST /api/admin/assets/card/123/refresh` - **THEN** 系统调用 RefreshCardDataFromGateway,更新 DB 中的卡状态字段,返回刷新后的最新状态 #### Scenario: 刷新设备状态(首次) - **WHEN** 管理员调用 `POST /api/admin/assets/device/456/refresh`,该设备有 3 张绑定卡 - **THEN** 系统依次刷新 3 张卡,设置 30 秒冷却期,返回最新状态 #### Scenario: 设备刷新冷却期内重复触发 - **WHEN** 管理员在 30 秒冷却期内第二次调用 `POST /api/admin/assets/device/456/refresh` - **THEN** 系统返回 HTTP 429,提示"刷新过于频繁,请稍后再试" --- ### Requirement: 套餐历史列表查询 系统 SHALL 提供资产的全量套餐记录查询接口,包含历史和当前生效套餐。 **API 端点**: `GET /api/admin/assets/:asset_type/:id/packages` **排序**: 按 `created_at` 倒序(最新套餐在前) **分页**: 不分页,全量返回 **范围**: 包含所有状态(含 status=4 已失效的历史套餐) **按 asset_type 区分查询**: - card:查询 `PackageUsage.iot_card_id = :id` - device:查询 `PackageUsage.device_id = :id` **每条记录响应字段**: - `package_usage_id`: 套餐使用记录 ID - `package_name`: 套餐名称 - `package_type`: 套餐类型(formal/addon) - `master_usage_id`: 主套餐 ID(加油包时有值,主套餐时为 null) - `real_data_mb`: 真总流量(MB) - `virtual_data_mb`: 虚总流量/停机阈值(MB) - `package_used_mb`: 展示已使用流量(经虚流量换算) - `package_remain_mb`: 展示剩余流量 - `activated_at`: 生效时间 - `expires_at`: 过期时间 - `status`: 套餐状态(0-待生效 1-生效中 2-已用完 3-已过期 4-已失效) #### Scenario: 查询卡的套餐历史 - **WHEN** 管理员调用 `GET /api/admin/assets/card/123/packages`,该卡有 3 条套餐记录(含 1 条已失效) - **THEN** 系统返回全部 3 条记录,按创建时间倒序排列 #### Scenario: 查询设备的套餐历史 - **WHEN** 管理员调用 `GET /api/admin/assets/device/456/packages` - **THEN** 系统返回该设备 device_id 下的所有套餐记录 #### Scenario: 资产无套餐记录 - **WHEN** 管理员查询一张从未购买过套餐的卡 - **THEN** 系统返回空数组,不报错 --- ### Requirement: 当前主套餐详情查询 系统 SHALL 提供查询资产当前生效主套餐的接口,用于展示套餐详细信息。 **API 端点**: `GET /api/admin/assets/:asset_type/:id/current-package` **查询条件**: `status = 1(生效中)AND master_usage_id IS NULL` **多套餐同时生效时**:只返回主套餐(master_usage_id IS NULL),不返回加油包 **响应字段**: - 完整套餐信息(同套餐历史列表中的单条记录字段) - 当无生效主套餐时,返回 HTTP 404 #### Scenario: 返回当前主套餐 - **WHEN** 管理员调用 `GET /api/admin/assets/card/123/current-package`,该卡有 1 个生效主套餐和 1 个加油包 - **THEN** 系统只返回主套餐信息,不包含加油包 #### Scenario: 无当前生效主套餐 - **WHEN** 管理员查询没有生效中主套餐的资产 - **THEN** 系统返回 HTTP 404 --- ### Requirement: RefreshCardDataFromGateway 完整同步 系统 SHALL 提供从 Gateway 完整同步卡数据的方法,替代原 `SyncCardStatusFromGateway`(仅为示例实现)。 **方法签名**: `RefreshCardDataFromGateway(ctx context.Context, iccid string) error` **同步字段**: - `network_status`: 网络状态(从网关卡状态映射) - `real_name_status`: 实名状态(从网关实名接口获取) - `current_month_usage_mb`: 本月已用流量(从网关流量接口获取) - `last_sync_time`: 更新为当前时间 **错误处理**: 网关调用失败时记录 Error 日志并返回错误,不更新 DB #### Scenario: 完整同步卡数据 - **WHEN** 调用 `RefreshCardDataFromGateway(ctx, "89860123456789012345")` - **THEN** 系统调用网关接口,将 network_status、real_name_status、current_month_usage_mb、last_sync_time 写回 DB