设备导入卡槽不对的问题

This commit is contained in:
2026-04-30 11:56:09 +08:00
parent 9238eeb56e
commit 8a3c45c577
10 changed files with 478 additions and 32 deletions

View File

@@ -0,0 +1,178 @@
# device-import 规格增量
## MODIFIED Requirements
### Requirement: 设备批量导入
系统 SHALL 提供设备批量导入功能,通过 Excel 文件导入设备并自动绑定卡,按固定列位置读取,表头行内容不影响解析结果,仅平台用户可操作。
**API 端点**: `POST /api/admin/devices/import`
**请求参数**:
- `batch_no`: 批次号(必填)
- `file_key`: 对象存储文件路径(必填,通过 /storage/upload-url 获取)
**Excel 格式**:
- **文件格式**: 仅支持 `.xlsx` (Excel 2007+)
- **Sheet**: 读取第一个sheet或优先读取名为"导入数据"的sheet
- **表头行**: 第1行固定为表头永远跳过内容不限中文、英文均可
- **列位置(固定,不可变)**:
```
第1列索引0: 虚拟号(必填,全局唯一)
第2列索引1: 设备名称(可选)
第3列索引2: 设备型号(可选)
第4列索引3: 设备类型(可选)
第5列索引4: IMEI可选
第6列索引5: 制造商(可选)
第7列索引6: 最大SIM槽数可选默认4范围1-4
第8列索引7: 卡1 ICCID可选对应槽位1
第9列索引8: 卡2 ICCID可选对应槽位2
第10列索引9: 卡3 ICCID可选对应槽位3
第11列索引10: 卡4 ICCID可选对应槽位4
```
- **列格式**: 所有列应设置为文本格式(避免数字被转为科学记数法)
**失败原因文本**:
- VirtualNo 为空:`"设备虚拟号(virtual_no)不能为空"`
- MaxSimSlots 越界:`"最大SIM槽数必须在1-4之间"`
- ICCID 填写槽位超出最大槽位:`"卡槽填写超出最大SIM槽数"`
**导入规则**:
- 按列索引取值,不识别列名,第一行永远跳过
- 若整行目标列皆为空,视为空行跳过,不计入 total不计入失败
- MaxSimSlots 为空或 0 回填默认值 4非空且不在 [1,4] 记录为失败
- `卡1~卡4` 的列位本身就是槽位定义,导入时必须保留原始列位信息,不得按非空 ICCID 顺序重排
- 前置槽位允许为空;如果仅填写 `卡2`、`卡3`,则表示设备只在槽位 2、3 上绑定卡
- 任一已填写 ICCID 的槽位编号若大于 `max_sim_slots`,则该行导入失败
- 导入的设备 shop_id = NULL平台库存
- 导入的设备 status = 1在库
- 设备号重复则该行跳过
- ICCID 必须已存在于系统中(先导入卡,再导入设备)
- ICCID 不存在则该行失败
- ICCID 已绑定其他设备则该行失败
- 导入通过异步任务处理,立即返回任务 ID
**权限**: 仅平台用户
**响应**:
- `task_id`: 导入任务 ID
- `task_no`: 任务编号
- `message`: 提示信息
#### Scenario: 提交设备导入任务
- **WHEN** 平台管理员上传 Excel 文件并提交导入请求
- **THEN** 系统创建导入任务,返回任务 ID开始异步处理
#### Scenario: 中文表头正常导入
- **GIVEN** Excel 文件第1行表头为 `虚拟号 | 设备名称 | 设备型号 | 设备类型 | IMEI | 制造商 | 最大SIM槽数 | 卡1 | 卡2 | 卡3 | 卡4`
- **WHEN** 系统解析该 Excel 文件
- **THEN** 系统跳过第1行从第2行开始按列位置解析数据
#### Scenario: 仅填写卡2和卡3时保留原始槽位
- **GIVEN** 某行 `最大SIM槽数 = 3`
- **AND** `卡1` 为空,`卡2 = ICCID_A``卡3 = ICCID_B`
- **WHEN** 系统解析该行
- **THEN** 系统将 `ICCID_A` 识别为槽位2的卡
- **AND** 系统将 `ICCID_B` 识别为槽位3的卡
- **AND** 系统不得将其重排为槽位1和槽位2
#### Scenario: 填写槽位超出最大SIM槽数
- **GIVEN** 某行 `最大SIM槽数 = 2`
- **AND** `卡3 = ICCID_C`
- **WHEN** 系统解析该行
- **THEN** 该行导入失败
- **AND** 失败原因为"卡槽填写超出最大SIM槽数"
#### Scenario: 代理尝试导入设备
- **WHEN** 代理用户尝试导入设备
- **THEN** 系统返回 403 错误,提示"无权限执行此操作"
#### Scenario: 文件格式错误
- **WHEN** 平台管理员上传非 Excel 格式(.xlsx)的文件
- **THEN** 系统创建任务但处理失败,任务状态为"失败",错误信息为"不支持的文件格式 .csv请上传Excel文件(.xlsx)"
#### Scenario: Excel结构错误
- **WHEN** 平台管理员上传的Excel文件无工作表或无数据行
- **THEN** 系统创建任务但处理失败,记录相应错误信息
#### Scenario: VirtualNo 为空的行记录为失败
- **WHEN** Excel 中某行第1列虚拟号为空
- **THEN** 该行计入失败(`fail_count++`),失败原因为"设备虚拟号(virtual_no)不能为空"
- **AND** 其他合法行继续导入,不因此行中断
### Requirement: 设备导入任务执行
系统 SHALL 异步执行设备导入任务,逐行处理 Excel 数据。
**处理规则**:
- 打开Excel文件选择第一个sheet或优先"导入数据"sheet
- 跳过第1行表头行从第2行开始按固定列位置解析数据
- 若整行目标列皆为空,视为空行跳过,不计入 total
- 逐行解析数据,并保留每个 ICCID 对应的原始槽位编号
- 对每行数据执行以下校验:
1. 设备号是否已存在(已存在则跳过)
2. ICCID 是否存在于系统中(不存在则失败)
3. ICCID 是否已绑定其他设备(已绑定则失败)
4. 已填写 ICCID 的槽位是否超出该设备 `max_sim_slots`(超出则失败)
- 校验通过后:
1. 创建设备记录
2. 按 ICCID 的原始槽位创建 `slot_position` 一致的设备-卡绑定记录
- 记录处理结果(成功/跳过/失败)
**任务状态**:
- 1: 待处理
- 2: 处理中
- 3: 已完成
- 4: 失败
#### Scenario: 导入成功
- **WHEN** Excel 中所有设备号不重复且 ICCID 有效
- **THEN** 系统创建所有设备和绑定记录,任务状态为"已完成"
#### Scenario: 前置空槽导入成功
- **GIVEN** 某行 `卡1` 为空,`卡2 = ICCID_A``卡3 = ICCID_B`
- **WHEN** 该行校验通过并执行导入
- **THEN** 系统创建两条绑定记录
- **AND** `ICCID_A` 的 `slot_position = 2`
- **AND** `ICCID_B` 的 `slot_position = 3`
#### Scenario: 部分导入成功
- **WHEN** Excel 中部分设备号已存在或部分 ICCID 无效
- **THEN** 系统只导入有效的行,记录跳过和失败的详情,任务状态为"已完成"
#### Scenario: ICCID 不存在
- **WHEN** Excel 中某行的 ICCID 在系统中不存在
- **THEN** 该行导入失败,记录失败原因"ICCID 不存在"
#### Scenario: ICCID 已绑定其他设备
- **WHEN** Excel 中某行的 ICCID 已绑定到其他设备
- **THEN** 该行导入失败,记录失败原因"ICCID 已绑定其他设备"
#### Scenario: 设备号重复
- **WHEN** Excel 中某行的设备号在系统中已存在
- **THEN** 该行被跳过,记录跳过原因"设备号已存在"
#### Scenario: 填写槽位超出最大SIM槽数时任务记录失败
- **WHEN** Excel 中某行声明 `最大SIM槽数 = 2`,但填写了 `卡3` 或 `卡4`
- **THEN** 该行计入失败(`fail_count++`
- **AND** 失败明细中的 `reason` 字段为"卡槽填写超出最大SIM槽数"
#### Scenario: 导入任务结果报告包含 VirtualNo 失败原因
- **WHEN** 导入任务处理完毕,含有 VirtualNo 为空的行
- **THEN** 失败明细列表中,该行的 `reason` 字段为"设备虚拟号(virtual_no)不能为空"`line` 字段为对应行号