All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m33s
- 删除 CSV 解析代码,新增 Excel 解析器 (excelize) - 更新 IoT 卡和设备导入任务处理器 - 更新 API 路由文档和前端接入指南 - 归档变更到 openspec/changes/archive/ - 同步 delta specs 到 main specs
211 lines
6.9 KiB
Markdown
211 lines
6.9 KiB
Markdown
# device-import Specification
|
||
|
||
## Purpose
|
||
TBD - created by archiving change add-device-management. Update Purpose after archive.
|
||
## 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行,列名如下(顺序可任意):
|
||
```
|
||
device_no, device_name, device_model, device_type,
|
||
max_sim_slots, manufacturer, iccid_1, iccid_2, iccid_3, iccid_4
|
||
```
|
||
- **数据行**: 从第2行开始
|
||
- **列格式**: 所有列应设置为文本格式(避免数字被转为科学记数法)
|
||
|
||
**示例Excel内容**:
|
||
```
|
||
| 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 | 8986001234567890001 | 8986001234567890002 | | |
|
||
| DEV-002 | GPS追踪器B | GT06N | GPS Tracker | 4 | Concox | 8986001234567890003 | | | |
|
||
```
|
||
|
||
**字段说明**:
|
||
- `device_no`: 设备号(必填,唯一)
|
||
- `device_name`: 设备名称(可选)
|
||
- `device_model`: 设备型号(可选)
|
||
- `device_type`: 设备类型(可选)
|
||
- `max_sim_slots`: 最大插槽数(可选,默认 4,范围 1-4)
|
||
- `manufacturer`: 制造商(可选)
|
||
- `iccid_1` ~ `iccid_4`: 对应插槽 1-4 的 ICCID(可选,空值表示该插槽无卡)
|
||
|
||
**导入规则**:
|
||
- 导入的设备 shop_id = NULL(平台库存)
|
||
- 导入的设备 status = 1(在库)
|
||
- 设备号重复则该行跳过
|
||
- ICCID 必须已存在于系统中(先导入卡,再导入设备)
|
||
- ICCID 不存在则该行失败
|
||
- ICCID 已绑定其他设备则该行失败
|
||
- 导入通过异步任务处理,立即返回任务 ID
|
||
|
||
**权限**: 仅平台用户
|
||
|
||
**响应**:
|
||
- `task_id`: 导入任务 ID
|
||
- `task_no`: 任务编号
|
||
- `message`: 提示信息
|
||
|
||
#### Scenario: 提交设备导入任务
|
||
|
||
- **WHEN** 平台管理员上传 Excel 文件并提交导入请求
|
||
- **THEN** 系统创建导入任务,返回任务 ID,开始异步处理
|
||
|
||
#### Scenario: 代理尝试导入设备
|
||
|
||
- **WHEN** 代理用户尝试导入设备
|
||
- **THEN** 系统返回 403 错误,提示"无权限执行此操作"
|
||
|
||
#### Scenario: 文件格式错误
|
||
|
||
- **WHEN** 平台管理员上传非 Excel 格式(.xlsx)的文件
|
||
- **THEN** 系统创建任务但处理失败,任务状态为"失败",错误信息为"不支持的文件格式 .csv,请上传Excel文件(.xlsx)"
|
||
|
||
#### Scenario: Excel结构错误
|
||
|
||
- **WHEN** 平台管理员上传的Excel文件无工作表或无数据行
|
||
- **THEN** 系统创建任务但处理失败,任务状态为"失败",记录相应错误信息
|
||
|
||
---
|
||
|
||
### Requirement: 设备导入任务执行
|
||
|
||
系统 SHALL 异步执行设备导入任务,逐行处理 Excel 数据。
|
||
|
||
**处理规则**:
|
||
- 打开Excel文件,选择第一个sheet(或优先"导入数据"sheet)
|
||
- 读取表头行,识别列索引
|
||
- 逐行解析数据
|
||
- 对每行数据执行以下校验:
|
||
1. 设备号是否已存在(已存在则跳过)
|
||
2. ICCID 是否存在于系统中(不存在则失败)
|
||
3. ICCID 是否已绑定其他设备(已绑定则失败)
|
||
- 校验通过后:
|
||
1. 创建设备记录
|
||
2. 创建设备-卡绑定记录
|
||
- 记录处理结果(成功/跳过/失败)
|
||
|
||
**任务状态**:
|
||
- 1: 待处理
|
||
- 2: 处理中
|
||
- 3: 已完成
|
||
- 4: 失败
|
||
|
||
#### Scenario: 导入成功
|
||
|
||
- **WHEN** Excel 中所有设备号不重复且 ICCID 有效
|
||
- **THEN** 系统创建所有设备和绑定记录,任务状态为"已完成"
|
||
|
||
#### Scenario: 部分导入成功
|
||
|
||
- **WHEN** Excel 中部分设备号已存在或部分 ICCID 无效
|
||
- **THEN** 系统只导入有效的行,记录跳过和失败的详情,任务状态为"已完成"
|
||
|
||
#### Scenario: ICCID 不存在
|
||
|
||
- **WHEN** Excel 中某行的 ICCID 在系统中不存在
|
||
- **THEN** 该行导入失败,记录失败原因"ICCID 不存在"
|
||
|
||
#### Scenario: ICCID 已绑定其他设备
|
||
|
||
- **WHEN** Excel 中某行的 ICCID 已绑定到其他设备
|
||
- **THEN** 该行导入失败,记录失败原因"ICCID 已绑定其他设备"
|
||
|
||
#### Scenario: 设备号重复
|
||
|
||
- **WHEN** Excel 中某行的设备号在系统中已存在
|
||
- **THEN** 该行被跳过,记录跳过原因"设备号已存在"
|
||
|
||
---
|
||
|
||
### Requirement: 设备导入任务列表查询
|
||
|
||
系统 SHALL 提供设备导入任务列表查询功能,仅平台用户可操作。
|
||
|
||
**API 端点**: `GET /api/admin/devices/import/tasks`
|
||
|
||
**查询条件**:
|
||
- `status`(可选): 任务状态 1-4
|
||
- `batch_no`(可选): 批次号,模糊匹配
|
||
- `start_time`(可选): 创建时间起始
|
||
- `end_time`(可选): 创建时间结束
|
||
|
||
**分页**:
|
||
- 默认每页 20 条,最大每页 100 条
|
||
|
||
**响应字段**:
|
||
- `id`: 任务 ID
|
||
- `task_no`: 任务编号
|
||
- `status`: 任务状态
|
||
- `status_text`: 任务状态文本
|
||
- `batch_no`: 批次号
|
||
- `file_name`: 文件名
|
||
- `total_count`: 总数
|
||
- `success_count`: 成功数
|
||
- `skip_count`: 跳过数
|
||
- `fail_count`: 失败数
|
||
- `started_at`: 开始时间
|
||
- `completed_at`: 完成时间
|
||
- `error_message`: 错误信息
|
||
- `created_at`: 创建时间
|
||
|
||
**权限**: 仅平台用户
|
||
|
||
#### Scenario: 查询导入任务列表
|
||
|
||
- **WHEN** 平台管理员查询导入任务列表
|
||
- **THEN** 系统返回所有导入任务,按创建时间倒序排列
|
||
|
||
#### Scenario: 按状态筛选任务
|
||
|
||
- **WHEN** 平台管理员查询状态为 3(已完成)的任务
|
||
- **THEN** 系统只返回已完成的任务
|
||
|
||
#### Scenario: 代理尝试查询导入任务
|
||
|
||
- **WHEN** 代理用户尝试查询导入任务
|
||
- **THEN** 系统返回 403 错误,提示"无权限执行此操作"
|
||
|
||
---
|
||
|
||
### Requirement: 设备导入任务详情查询
|
||
|
||
系统 SHALL 提供设备导入任务详情查询功能,包含跳过和失败记录的详细信息。
|
||
|
||
**API 端点**: `GET /api/admin/devices/import/tasks/:id`
|
||
|
||
**响应字段**:
|
||
- 包含任务列表的所有字段
|
||
- `skipped_items`: 跳过记录详情列表
|
||
- `line`: 行号
|
||
- `device_no`: 设备号
|
||
- `reason`: 跳过原因
|
||
- `failed_items`: 失败记录详情列表
|
||
- `line`: 行号
|
||
- `device_no`: 设备号
|
||
- `reason`: 失败原因
|
||
|
||
**权限**: 仅平台用户
|
||
|
||
#### Scenario: 查询导入任务详情
|
||
|
||
- **WHEN** 平台管理员查询导入任务详情(ID=1)
|
||
- **THEN** 系统返回任务的完整信息,包括跳过和失败记录详情
|
||
|
||
#### Scenario: 查询不存在的任务
|
||
|
||
- **WHEN** 平台管理员查询不存在的任务(ID=999)
|
||
- **THEN** 系统返回 404 错误,提示"导入任务不存在"
|
||
|