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

@@ -90,30 +90,52 @@ function validateFile(file) {
**文件名**: `iccid_import_template.xlsx`
**格式**:
| ICCID | MSISDN |
|-------|--------|
| 89860012345678901234 | 13800000001 |
| 89860012345678901235 | 13800000002 |
| ICCID | MSISDN | virtual_no |
|-------|--------|------------|
| 89860012345678901234 | 13800000001 | VNO-00001 |
| 89860012345678901235 | 13800000002 | VNO-00002 |
**字段说明**:
| 列名 | 是否必填 | 说明 |
|------|---------|------|
| ICCID | **是** | 卡唯一标识电信19位/其他20位 |
| MSISDN | **是** | 接入号 |
| virtual_no | **是** | 虚拟号,全局唯一;留空将导致该行导入失败 |
**要点**:
- 必须包含表头行(ICCID, MSISDN)
- ICCID和MSISDN列必须设置为**文本格式**(重要!)
- 必须包含表头行(ICCID, MSISDN, virtual_no)
- 所有列必须设置为**文本格式**(重要!)
- Excel中设置文本格式: 选中列 → 右键 → 设置单元格格式 → 文本
- `virtual_no` 为必填列,**缺少该列将导致整批导入失败**
### 设备导入模板
**文件名**: `device_import_template.xlsx`
**格式**:
| device_no | device_name | device_model | device_type | max_sim_slots | manufacturer | iccid_1 | iccid_2 | iccid_3 | iccid_4 |
|-----------|-------------|--------------|-------------|---------------|--------------|---------|---------|---------|---------|
| DEV-001 | GPS追踪器A | GT06N | GPS Tracker | 4 | Concox | 89860012345678901234 | 89860012345678901235 | | |
| DEV-002 | GPS追踪器B | GT06N | GPS Tracker | 4 | Concox | 89860012345678901236 | | | |
| virtual_no | device_name | device_model | device_type | max_sim_slots | manufacturer | imei | iccid_1 | iccid_2 | iccid_3 | iccid_4 |
|------------|-------------|--------------|-------------|---------------|--------------|------|---------|---------|---------|---------|
| DEV-001 | GPS追踪器A | GT06N | GPS Tracker | 4 | Concox | 123456789012345 | 89860012345678901234 | 89860012345678901235 | | |
| DEV-002 | GPS追踪器B | GT06N | GPS Tracker | 4 | Concox | 123456789012346 | 89860012345678901236 | | | |
**字段说明**:
| 列名 | 是否必填 | 说明 |
|------|---------|------|
| virtual_no | **是** | 设备虚拟号,全局唯一;**留空不再跳过,将记录为失败行** |
| device_name | 否 | 设备名称 |
| device_model | 否 | 设备型号 |
| device_type | 否 | 设备类型 |
| max_sim_slots | 否 | 最大SIM卡槽数默认4 |
| manufacturer | 否 | 制造商 |
| imei | 否 | 设备IMEI |
| iccid_1 ~ iccid_4 | 否 | 绑定的IoT卡ICCID填写时对应ICCID必须已存在于系统中 |
**要点**:
- 所有列都必须设置为**文本格式**
- device_no为必填项
- iccid_1 ~ iccid_4为可选项,填写时对应的ICCID必须已存在于系统中
- `virtual_no` 为必填项,留空将记录为失败行(而非静默跳过)
- iccid_1 ~ iccid_4为可选项填写时对应的ICCID必须已存在于系统中
## 模板下载功能实现