feat: 资产标识符标准化、资产历史订单查询及导入虚拟号强制验证
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m21s

主要变更:
- 新增 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>
This commit is contained in:
2026-04-07 17:39:36 +08:00
parent 7e489a19fb
commit 80c6f6c756
69 changed files with 3039 additions and 851 deletions

View File

@@ -0,0 +1,22 @@
## MODIFIED Requirements
### Requirement: 设备批量导入
系统 SHALL 支持通过 Excel 文件批量导入设备。**[BREAKING]** `virtual_no` 为空的行行为变更:原行为为"静默跳过skip",改为"记录为失败行fail并报告原因"。
**失败原因文本(新增)**
- VirtualNo 为空:`"设备虚拟号(virtual_no)不能为空"`
#### Scenario: 正常导入VirtualNo 有值)
- **WHEN** Excel 中某行 virtual_no="DEV-001",其他字段合法
- **THEN** 导入成功,设备记录写入数据库
#### Scenario: VirtualNo 为空的行记录为失败(原为跳过)
- **WHEN** Excel 中某行 virtual_no 列为空或未填写
- **THEN** 该行计入失败(`fail_count++`),失败原因为"设备虚拟号(virtual_no)不能为空"
- **THEN** 该行不再计入 `skip_count`
- **THEN** 其他合法行继续导入,不因此行中断
#### Scenario: 导入任务结果报告包含 VirtualNo 失败原因
- **WHEN** 导入任务处理完毕,含有 VirtualNo 为空的行
- **THEN** 失败明细列表中,该行的 `reason` 字段为"设备虚拟号(virtual_no)不能为空"`line` 字段为对应行号

View File

@@ -0,0 +1,40 @@
## MODIFIED Requirements
### Requirement: IoT 卡批量导入
系统 SHALL 支持通过 Excel 文件批量导入 IoT 卡。**[BREAKING]** `virtual_no` 列由可选改为必填Excel 中 `virtual_no` 列为空的行,系统 MUST 将其记录为失败行并报告原因,不得静默跳过或将其写入数据库。
**必填列(更新后)**
- `iccid`必填ICCID电信 19 位/其他 20 位,格式校验
- `virtual_no`**必填,由可选改为必填**虚拟号全局唯一1-50 字符
- `msisdn`(可选):手机号/接入号
**失败原因文本(中文)**
- ICCID 为空:`"ICCID 不能为空"`
- ICCID 格式错误:`"ICCID 格式错误应为19-20位数字"`
- VirtualNo 为空:`"虚拟号(virtual_no)不能为空"`(新增)
- VirtualNo 已被占用:`"虚拟号已被占用: <值>"`(已有)
- ICCID 已存在:`"ICCID 已存在: <值>"`(已有)
#### Scenario: 正常导入ICCID 和 VirtualNo 均有值)
- **WHEN** Excel 中某行 ICCID="898600XXXXX"virtual_no="CARD-001"
- **THEN** 导入成功卡记录写入数据库VirtualNo 和 ICCID 同步注册到 `tb_asset_identifier`
#### Scenario: VirtualNo 为空的行被拒绝
- **WHEN** Excel 中某行 ICCID="898600YYYYY"virtual_no 列为空或未填写
- **THEN** 该行计入失败,失败原因为"虚拟号(virtual_no)不能为空"
- **THEN** 其他合法行继续导入,不因此行中断
#### Scenario: VirtualNo 重复被拒绝
- **WHEN** Excel 中某行的 virtual_no 与已有卡/设备的 VirtualNo 重复(跨表)
- **THEN** 该行计入失败,原因为"虚拟号已被占用: <值>"
#### Scenario: Excel 文件中无 VirtualNo 列
- **WHEN** Excel 表头中不包含 `virtual_no`/`虚拟号`/`设备号` 等可识别列名
- **THEN** 所有数据行均因 VirtualNo 为空而失败,导入结果中 `fail_count = 总行数``success_count = 0`
- **THEN** 返回错误提示:"Excel 文件缺少 virtual_no 列,请使用最新模板"
#### Scenario: 导入任务完成后的结果报告
- **WHEN** 导入任务处理完毕
- **THEN** 结果包含:`success_count``fail_count``skip_count`、失败明细列表(含行号、原因)
- **THEN** VirtualNo 为空的失败行在明细中明确体现行号和原因