All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 4m39s
9.5 KiB
9.5 KiB
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行固定为表头,永远跳过,内容不限(中文、英文均可)
- 列位置(固定,不可变):
第1列(索引0): 虚拟号(必填,全局唯一) 第2列(索引1): 设备名称(可选) 第3列(索引2): 设备型号(可选) 第4列(索引3): 设备类型(可选) 第5列(索引4): IMEI(可选) 第6列(索引5): 制造商(可选) 第7列(索引6): 最大SIM槽数(可选,默认4,范围1-4) 第8列(索引7): 卡1 ICCID(可选) 第9列(索引8): 卡2 ICCID(可选) 第10列(索引9): 卡3 ICCID(可选) 第11列(索引10): 卡4 ICCID(可选) - 列格式: 所有列应设置为文本格式(避免数字被转为科学记数法)
失败原因文本:
- VirtualNo 为空:
"设备虚拟号(virtual_no)不能为空" - MaxSimSlots 越界:
"最大SIM槽数必须在1-4之间"
导入规则:
- 按列索引取值,不识别列名,第一行永远跳过
- 若整行目标列皆为空,视为空行跳过,不计入 total,不计入失败
- MaxSimSlots 为空或 0 回填默认值 4;非空且不在 [1,4] 记录为失败
- 导入的设备 shop_id = NULL(平台库存)
- 导入的设备 status = 1(在库)
- 设备号重复则该行跳过
- ICCID 必须已存在于系统中(先导入卡,再导入设备)
- ICCID 不存在则该行失败
- ICCID 已绑定其他设备则该行失败
- 导入通过异步任务处理,立即返回任务 ID
权限: 仅平台用户
响应:
task_id: 导入任务 IDtask_no: 任务编号message: 提示信息
Scenario: 提交设备导入任务
- WHEN 平台管理员上传 Excel 文件并提交导入请求
- THEN 系统创建导入任务,返回任务 ID,开始异步处理
Scenario: 中文表头正常导入
- GIVEN Excel 文件第1行表头为
虚拟号 | 设备名称 | 设备型号 | 设备类型 | IMEI | 制造商 | 最大SIM槽数 | 卡1 | 卡2 | 卡3 | 卡4 - WHEN 系统解析该 Excel 文件
- THEN 系统跳过第1行,从第2行开始按列位置解析数据
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)不能为空" - THEN 其他合法行继续导入,不因此行中断
Requirement: 设备导入任务执行
系统 SHALL 异步执行设备导入任务,逐行处理 Excel 数据。
处理规则:
- 打开Excel文件,选择第一个sheet(或优先"导入数据"sheet)
- 跳过第1行(表头行),从第2行开始按固定列位置解析数据
- 若整行目标列皆为空,视为空行跳过,不计入 total
- 逐行解析数据
- 对每行数据执行以下校验:
- 设备号是否已存在(已存在则跳过)
- ICCID 是否存在于系统中(不存在则失败)
- ICCID 是否已绑定其他设备(已绑定则失败)
- 校验通过后:
- 创建设备记录
- 创建设备-卡绑定记录
- 记录处理结果(成功/跳过/失败)
任务状态:
- 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 该行被跳过,记录跳过原因"设备号已存在"
Scenario: VirtualNo 为空的行记录为失败
- WHEN Excel 中某行第1列(虚拟号)为空
- THEN 该行计入失败(
fail_count++),失败原因为"设备虚拟号(virtual_no)不能为空" - THEN 其他合法行继续导入,不因此行中断
Scenario: 导入任务结果报告包含 VirtualNo 失败原因
- WHEN 导入任务处理完毕,含有 VirtualNo 为空的行
- THEN 失败明细列表中,该行的
reason字段为"设备虚拟号(virtual_no)不能为空",line字段为对应行号
Requirement: 设备导入任务列表查询
系统 SHALL 提供设备导入任务列表查询功能,仅平台用户可操作。
API 端点: GET /api/admin/devices/import/tasks
查询条件:
status(可选): 任务状态 1-4batch_no(可选): 批次号,模糊匹配start_time(可选): 创建时间起始end_time(可选): 创建时间结束
分页:
- 默认每页 20 条,最大每页 100 条
响应字段:
id: 任务 IDtask_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 错误,提示"导入任务不存在"
Requirement: 设备导入批次支持实名策略配置
系统 SHALL 在设备导入请求(ImportDeviceRequest)中支持 realname_policy 参数,以批次为单位指定导入设备的实名策略,默认为 none。
请求字段新增:
realname_policy:实名认证策略(枚举:none/before_order/after_order,可选,默认none)
任务字段新增:
DeviceImportTask新增realname_policy字段(VARCHAR(20) NOT NULL DEFAULT 'none')
导入行为:
- 该批次导入的所有设备统一使用
realname_policy的值写入Device.realname_policy,不支持同一批次混用 - 导入任务记录该字段用于审计
Scenario: 不传 realname_policy 时默认为 none
- WHEN 设备导入请求未包含
realname_policy字段 - THEN 导入的所有设备
realname_policy为none
Scenario: 指定 before_order 导入设备
- WHEN 设备导入请求中
realname_policy=before_order - THEN 该批次导入的所有设备
realname_policy均为before_order
Scenario: 传入无效 realname_policy 被拒绝
- WHEN 设备导入请求中
realname_policy=unknown - THEN 系统返回参数校验错误,提示实名策略值无效
Scenario: 设备导入任务响应返回 realname_policy
- WHEN 管理员查询设备导入任务列表或详情
- THEN 响应中包含
realname_policy字段