feat: 资产标识符标准化、资产历史订单查询及导入虚拟号强制验证
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m21s
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:
@@ -201,8 +201,8 @@ TBD - created by archiving change iot-card-standalone-management. Update Purpose
|
||||
- **表头识别关键字**:
|
||||
- ICCID 列: iccid/ICCID/卡号/号码
|
||||
- MSISDN 列: msisdn/MSISDN/接入号/手机号/电话/号码
|
||||
- virtual_no 列(新增,可选): virtual_no/VirtualNo/虚拟号/设备号
|
||||
- **列数要求**: 至少 2 列(ICCID 和 MSISDN),virtual_no 为可选第三列
|
||||
- virtual_no 列(**必填**): virtual_no/VirtualNo/虚拟号/设备号
|
||||
- **列数要求**: 至少 3 列(ICCID、MSISDN、virtual_no),virtual_no 为必填列
|
||||
- **列格式**: 应设置为文本格式(避免长数字被转为科学记数法)
|
||||
|
||||
**解析规则**:
|
||||
@@ -211,12 +211,13 @@ TBD - created by archiving change iot-card-standalone-management. Update Purpose
|
||||
- 跳过空行
|
||||
- ICCID 为空的行记录为失败
|
||||
- MSISDN 为空的行记录为失败
|
||||
- virtual_no 为空的行:跳过该列(不填入,保留原值)
|
||||
- virtual_no 为空的行:**[BREAKING]** 记录为失败行,失败原因为"虚拟号(virtual_no)不能为空"(原行为为跳过该列)
|
||||
- Excel 中不包含 virtual_no 列时:所有数据行均因 VirtualNo 为空而失败,返回错误提示"Excel 文件缺少 virtual_no 列,请使用最新模板"
|
||||
|
||||
**virtual_no 导入规则(只补空白)**:
|
||||
- 该行 virtual_no 不为空 + 数据库当前值为 NULL:填入新值
|
||||
- 该行 virtual_no 不为空 + 数据库当前值已有值:跳过(不覆盖)
|
||||
- **批次级唯一性检查**:在执行导入前,先检查整批中所有非空 virtual_no 是否与数据库现存值重复;有任意冲突则**整批失败**,响应中返回冲突的 virtual_no 及行号列表
|
||||
**virtual_no 导入规则**:
|
||||
- virtual_no 为必填列,为空则该行记录为失败
|
||||
- virtual_no 全局唯一(跨卡和设备),重复则失败,原因为"虚拟号已被占用: <值>"
|
||||
- **批次级唯一性检查**:在执行导入前,先检查整批中所有 virtual_no 是否与数据库现存值重复;有任意冲突则**整批失败**,响应中返回冲突的 virtual_no 及行号列表
|
||||
|
||||
**示例 Excel 内容**:
|
||||
```
|
||||
@@ -226,20 +227,27 @@ TBD - created by archiving change iot-card-standalone-management. Update Purpose
|
||||
| 89860012345678901235 | 13800000002 | |
|
||||
```
|
||||
|
||||
#### Scenario: 解析标准双列 Excel 文件(无 virtual_no 列)
|
||||
#### Scenario: 正常导入(ICCID 和 VirtualNo 均有值)
|
||||
|
||||
- **WHEN** Excel 文件只含 ICCID 和 MSISDN 两列,无虚拟号列
|
||||
- **THEN** 解析结果包含 2 条有效记录,virtual_no 字段为空,不影响导入逻辑
|
||||
- **WHEN** Excel 中某行 ICCID="898600XXXXX",virtual_no="CARD-001",msisdn="13800000001"
|
||||
- **THEN** 导入成功,卡记录写入数据库,VirtualNo 和 ICCID 同步注册到 `tb_asset_identifier`
|
||||
|
||||
#### Scenario: 解析含 virtual_no 列的三列 Excel
|
||||
#### Scenario: VirtualNo 为空的行被拒绝
|
||||
|
||||
- **WHEN** Excel 文件含 ICCID、MSISDN、虚拟号三列,某行 virtual_no = "CARD-001",对应卡当前 virtual_no 为 NULL
|
||||
- **THEN** 解析后该卡的 virtual_no 填入 "CARD-001"
|
||||
- **WHEN** Excel 中某行 ICCID="898600YYYYY",virtual_no 列为空或未填写
|
||||
- **THEN** 该行计入失败,失败原因为"虚拟号(virtual_no)不能为空"
|
||||
- **THEN** 其他合法行继续导入,不因此行中断
|
||||
|
||||
#### Scenario: virtual_no 已有值时不覆盖
|
||||
#### Scenario: VirtualNo 重复被拒绝
|
||||
|
||||
- **WHEN** Excel 中某行 virtual_no = "CARD-NEW",但该卡数据库中已有 virtual_no = "CARD-OLD"
|
||||
- **THEN** 该卡的 virtual_no 保持 "CARD-OLD" 不变,该行跳过(不报错,不计入失败)
|
||||
- **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: 批次中有 virtual_no 与现存数据重复
|
||||
|
||||
@@ -252,6 +260,12 @@ TBD - created by archiving change iot-card-standalone-management. Update Purpose
|
||||
- **WHEN** 系统解析该 Excel 文件
|
||||
- **THEN** 系统正确识别三列,按规则处理 virtual_no
|
||||
|
||||
#### Scenario: 导入任务完成后的结果报告
|
||||
|
||||
- **WHEN** 导入任务处理完毕
|
||||
- **THEN** 结果包含:`success_count`、`fail_count`、`skip_count`、失败明细列表(含行号、原因)
|
||||
- **THEN** VirtualNo 为空的失败行在明细中明确体现行号和原因
|
||||
|
||||
#### Scenario: 拒绝非Excel格式文件
|
||||
|
||||
- **GIVEN** 上传文件扩展名为 .csv
|
||||
|
||||
Reference in New Issue
Block a user