Files
huang 80c6f6c756
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m21s
feat: 资产标识符标准化、资产历史订单查询及导入虚拟号强制验证
主要变更:
- 新增 AssetIdentifier 模型及 Store,统一管理资产标识符(ICCID/IMEI/SN 等)
- 新增迁移:asset_identifier 表、order 表新增 asset_identifier 字段、iot_card.virtual_no NOT NULL 约束
- 资产 Handler/Service/Route 全面重构,支持标识符路由查询与解析
- 新增资产历史订单查询接口,支持跨设备/卡/钱包维度的订单聚合
- 设备与物联卡导入任务强制校验虚拟号,缺失时直接拒绝
- Excel 工具函数优化,前端导入指引文档同步更新
- 归档三个 OpenSpec 提案:asset-identifier-standardization、asset-historical-orders、import-mandatory-virtual-no
- 更新 OpenAPI 文档及相关 DTO

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-07 17:39:36 +08:00

5.0 KiB
Raw Permalink Blame History

Capability: 资产操作路由标识符标准化

Purpose

定义 B 端资产操作类接口统一使用资产标识符ICCID 或 VirtualNo作为路径参数的规范废弃原有基于数据库主键 ID 的路由,并规定标识符解析的性能要求。

Requirements

Requirement: B 端资产操作接口统一使用标识符路径参数

B 端所有资产操作类接口 SHALL 使用资产标识符ICCID 或 VirtualNo作为路径参数废弃原有基于数据库主键 ID 的路由。系统内部通过注册表将标识符解析为资产实体Handler 层无需关心 ID。

标识符规则

  • IoT 卡:接受 ICCID 或 VirtualNo均为全局唯一
  • 设备:接受 VirtualNo全局唯一
  • 不接受 IMEI/SN/MSISDN非唯一仅 Resolve 的 fallback 路径支持)

废弃的旧路由 → 新路由映射

旧路由(废弃) 新路由
GET /api/admin/assets/:asset_type/:id/realtime-status GET /api/admin/assets/:identifier/realtime-status
POST /api/admin/assets/:asset_type/:id/refresh POST /api/admin/assets/:identifier/refresh
GET /api/admin/assets/:asset_type/:id/packages GET /api/admin/assets/:identifier/packages
GET /api/admin/assets/:asset_type/:id/current-package GET /api/admin/assets/:identifier/current-package
GET /api/admin/assets/:asset_type/:id/wallet GET /api/admin/assets/:identifier/wallet
GET /api/admin/assets/:asset_type/:id/wallet/transactions GET /api/admin/assets/:identifier/wallet/transactions
PATCH /api/admin/assets/:asset_type/:id/polling-status PATCH /api/admin/assets/:identifier/polling-status
POST /api/admin/assets/device/:device_id/stop POST /api/admin/assets/:identifier/stop
POST /api/admin/assets/device/:device_id/start POST /api/admin/assets/:identifier/start
POST /api/admin/assets/card/:iccid/stop POST /api/admin/assets/:identifier/stop(合并)
POST /api/admin/assets/card/:iccid/start POST /api/admin/assets/:identifier/start(合并)
DELETE /api/admin/devices/:id DELETE /api/admin/devices/:virtual_no
GET /api/admin/devices/:id/cards GET /api/admin/devices/:virtual_no/cards
POST /api/admin/devices/:id/cards POST /api/admin/devices/:virtual_no/cards
DELETE /api/admin/devices/:id/cards/:cardId DELETE /api/admin/devices/:virtual_no/cards/:iccid
PATCH /api/admin/devices/:id/deactivate PATCH /api/admin/assets/:identifier/deactivate
PATCH /api/admin/iot-cards/:id/deactivate PATCH /api/admin/assets/:identifier/deactivate(合并)

Scenario: 通过 ICCID 操作 IoT 卡

  • WHEN 管理员请求 GET /api/admin/assets/898600XXXXXXXX/packages
  • THEN 系统解析 ICCID找到对应 IoT 卡,返回该卡的套餐列表

Scenario: 通过 VirtualNo 操作设备

  • WHEN 管理员请求 POST /api/admin/assets/DEV-001/stop
  • THEN 系统解析 VirtualNo找到对应设备执行批量停机停该设备下所有已实名卡

Scenario: 通过 VirtualNo 操作绑定了设备的 IoT 卡(停机)

  • WHEN 管理员请求 POST /api/admin/assets/CARD-001/stopCARD-001 是 IoT 卡的 VirtualNo
  • THEN 系统解析 VirtualNo找到 IoT 卡,执行单卡停机

Scenario: stop/start 接口对卡和设备行为差异

  • WHEN identifier 解析为 IoT 卡时调用 stop
  • THEN 执行单卡停机
  • WHEN identifier 解析为设备时调用 stop
  • THEN 执行设备停机(批量停机该设备下所有已实名卡)

Scenario: 标识符不存在

  • WHEN 管理员请求的 :identifier 在注册表和 fallback 查询中均未找到对应资产
  • THEN 返回 HTTP 404错误消息"资产不存在"

Scenario: 无权限操作该资产

  • WHEN 代理用户请求的 identifier 对应的资产不属于该代理的数据权限范围
  • THEN 返回 HTTP 403错误消息"无权限操作该资源或资源不存在"

Scenario: 设备绑卡管理使用设备 VirtualNo

  • WHEN 管理员请求 GET /api/admin/devices/DEV-001/cards
  • THEN 系统通过 VirtualNo 找到设备,返回该设备绑定的卡列表

Scenario: 设备解绑卡使用 ICCID

  • WHEN 管理员请求 DELETE /api/admin/devices/DEV-001/cards/898600XXXXXXXX
  • THEN 系统通过 VirtualNo 找到设备,通过 ICCID 找到卡,执行解绑

Requirement: 新路由下标识符的解析性能

资产操作接口中标识符解析 SHALL 优先走注册表(单次精确查询),保证解析延迟不超过 10ms在正常数据库负载下

Scenario: 注册表命中路径

  • WHEN 请求携带的 identifier 存在于 tb_asset_identifier
  • THEN 系统单次查询注册表得到 asset_type 和 asset_id无需扫描 tb_device 或 tb_iot_card

Scenario: 注册表未命中fallback

  • WHEN 请求携带的 identifier 不在注册表(如 IMEI 或旧数据)
  • THEN 系统 fallback 到原有多字段 OR 查询,同样能定位资产(性能稍低,为次要路径)