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

3.3 KiB
Raw Blame History

MODIFIED Requirements

Requirement: 统一资产解析入口

系统 SHALL 提供统一的资产查找接口,通过任意标识符定位卡或设备,并返回该资产的中等聚合信息。

API 端点: GET /api/admin/assets/resolve/:identifier

查找顺序(更新后):

  1. 主路径:查 tb_asset_identifier WHERE identifier = ? → 命中则得到 asset_type + asset_id直接查对应表取完整记录
  2. Fallback 路径(注册表未命中时):
    • 先查 tb_device(匹配 virtual_no = ? OR imei = ? OR sn = ?
    • 未命中则查 tb_iot_card(匹配 virtual_no = ? OR iccid = ? OR msisdn = ?
  3. 两条路径均未命中 → 返回 HTTP 404

数据权限规则:

  • 代理用户:只能查看 shop_id 在自己及下级店铺范围内的资产
  • 平台用户SuperAdmin/Platform可查看所有资产
  • 企业账号:暂不支持此接口,调用时返回 HTTP 403

响应结构AssetResolveResponse:

通用字段device 和 card 均有)

  • asset_type: 资产类型("device""card"
  • asset_id: 资产主键 ID
  • identifier: 本次查询所用的标识符(原样回传)
  • virtual_no: 虚拟号(设备/卡均使用此字段)
  • status: 资产状态(整型)
  • asset_status: 业务状态1-在库 2-已销售 3-已换货 4-已停用)
  • generation: 资产世代编号
  • batch_no: 批次号
  • shop_id: 所属店铺 ID平台库存时为空
  • shop_name: 所属店铺名称
  • series_id: 套餐系列 ID未绑定时为空
  • series_name: 套餐系列名称
  • first_commission_paid: 一次性佣金是否已发放
  • accumulated_recharge: 累计充值金额(分)
  • activated_at: 激活时间(未激活时为空)
  • created_at: 创建时间
  • updated_at: 更新时间

状态与套餐字段device 和 card 均有)

  • real_name_status: 实名状态(整型)
  • current_package: 当前套餐名称(无套餐时返回空字符串)
  • package_total_mbpackage_used_mbpackage_remain_mb: 套餐流量信息
  • device_protect_status: 保护期状态

绑定关系字段

  • iccid: 仅 card 类型时有值
  • bound_device_idbound_device_nobound_device_name: 仅 card 类型且绑定设备时有值
  • bound_card_countcards: 仅 device 类型时有值

Scenario: 通过注册表主路径精确解析

  • WHEN 管理员输入 identifier 为已存在于 tb_asset_identifier 的 VirtualNo 或 ICCID
  • THEN 系统单次查询注册表命中,直接查对应表返回完整资产信息,响应时间 < 50ms

Scenario: Fallback 路径解析 IMEI

  • WHEN 管理员输入 identifier 为设备 IMEI不在注册表中
  • THEN 注册表未命中,系统 fallback 查 tb_device 的 imei 字段,找到后返回资产信息
  • THEN 响应中 identifier 字段原样回传该 IMEI 值

Scenario: Fallback 路径解析 MSISDN

  • WHEN 管理员输入 identifier 为 IoT 卡的手机号MSISDN
  • THEN 注册表未命中fallback 查 tb_iot_card 的 msisdn 字段
  • THEN 若存在多张卡的 MSISDN 相同返回第一条匹配记录MSISDN 非唯一,存在歧义,记录 warn 日志)

Scenario: 标识符完全不存在

  • WHEN 管理员输入的 identifier 在注册表和 fallback 均未找到
  • THEN 返回 HTTP 404错误消息"资产不存在"