feat: 实现物联网卡独立管理和批量导入功能
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 4m42s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 4m42s
新增物联网卡独立管理模块,支持单卡查询、批量导入和状态管理。主要变更包括: 功能特性: - 新增物联网卡 CRUD 接口(查询、分页列表、删除) - 支持 CSV/Excel 批量导入物联网卡 - 实现异步导入任务处理和进度跟踪 - 新增 ICCID 号码格式校验器(支持 Luhn 算法) - 新增 CSV 文件解析工具(支持编码检测和错误处理) 数据库变更: - 移除 iot_card 和 device 表的 owner_id/owner_type 字段 - 新增 iot_card_import_task 导入任务表 - 为导入任务添加运营商类型字段 测试覆盖: - 新增 IoT 卡 Store 层单元测试 - 新增 IoT 卡导入任务单元测试 - 新增 IoT 卡集成测试(包含导入流程测试) - 新增 CSV 工具和 ICCID 校验器测试 文档更新: - 更新 OpenAPI 文档(新增 7 个 IoT 卡接口) - 归档 OpenSpec 变更提案 - 更新 API 文档规范和生成器指南 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,9 +10,7 @@ This capability supports:
|
||||
- Integration with Gateway project for real-time status synchronization
|
||||
- Batch import and multi-dimensional querying
|
||||
- Support for normal cards (require real-name verification) and industry cards (no real-name required)
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: IoT 卡实体定义
|
||||
|
||||
系统 SHALL 定义 IoT 卡(IotCard)实体,包含 IoT 卡(物联网卡/流量卡/SIM卡)的商品属性、状态属性、所有权信息和 Gateway 集成字段。
|
||||
@@ -161,35 +159,60 @@ This capability supports:
|
||||
|
||||
### Requirement: IoT 卡批量导入
|
||||
|
||||
系统 SHALL 支持批量导入 IoT 卡数据,用于初始化库存或补充库存。
|
||||
系统 SHALL 支持通过 CSV 文件批量导入 IoT 卡 ICCID,支持大批量数据(几万条),异步处理并跟踪导入进度。
|
||||
|
||||
**导入字段**:
|
||||
- ICCID(必填)
|
||||
- 卡类型(必填,如 "4G"、"5G"、"NB-IoT")
|
||||
- 卡业务类型(可选,枚举值 "normal" | "industry",默认 "normal")
|
||||
- 运营商 ID(必填,从 carriers 表中选择)
|
||||
- IMSI(可选)
|
||||
- 手机号码(可选)
|
||||
- 供应商(可选)
|
||||
- 成本价(必填)
|
||||
- 批次号(必填)
|
||||
**导入方式**:
|
||||
- 上传 CSV 文件,每行一个 ICCID
|
||||
- 在界面选择运营商、批次号等公共参数
|
||||
- 不支持一次导入多种运营商的卡
|
||||
|
||||
**导入规则**:
|
||||
- ICCID 必须唯一,重复 ICCID 将被拒绝
|
||||
- 导入的 IoT 卡默认状态为 1(在库),所有者为平台(`owner_type` 为 "platform",`owner_id` 为 0)
|
||||
- 导入成功后记录操作日志
|
||||
**导入参数**:
|
||||
- CSV 文件(必填): 仅包含 ICCID 列
|
||||
- 运营商 ID(必填): 在界面选择
|
||||
- 批次号(可选): 在界面填写
|
||||
|
||||
#### Scenario: 批量导入 IoT 卡成功
|
||||
**校验规则**:
|
||||
- ICCID 格式校验: 字母数字混合,长度根据运营商(电信19位,其他20位)
|
||||
- ICCID 唯一性校验: 重复 ICCID 跳过,不中断导入
|
||||
|
||||
- **WHEN** 平台上传包含 100 条 IoT 卡数据的 CSV 文件
|
||||
- **THEN** 系统创建 100 条 IoT 卡记录,状态为 1(在库),所有者为平台,返回导入成功消息
|
||||
**处理规则**:
|
||||
- 异步处理: 创建导入任务后立即返回任务 ID
|
||||
- 分批处理: 每批 1000 条
|
||||
- 重复处理: 跳过已存在的 ICCID,记录跳过原因
|
||||
- 格式错误: 记录失败原因,继续处理其他行
|
||||
|
||||
#### Scenario: 批量导入包含重复 ICCID
|
||||
**导入结果**:
|
||||
- 总数(total_count)
|
||||
- 成功数(success_count)
|
||||
- 跳过数(skip_count): 因重复等原因跳过
|
||||
- 失败数(fail_count): 因格式错误等原因失败
|
||||
- 跳过详情: 包含行号、ICCID、原因
|
||||
- 失败详情: 包含行号、ICCID、原因
|
||||
|
||||
- **WHEN** 平台上传的 CSV 文件中包含已存在的 ICCID
|
||||
- **THEN** 系统拒绝重复 ICCID 的 IoT 卡,返回错误信息并列出重复 ICCID,其他有效 IoT 卡正常导入
|
||||
#### Scenario: 发起 IoT 卡批量导入
|
||||
|
||||
---
|
||||
- **WHEN** 管理员上传包含 10000 个 ICCID 的 CSV 文件,选择运营商为电信,批次号为 "BATCH-2025-001"
|
||||
- **THEN** 系统创建导入任务,返回任务 ID,后台异步处理导入
|
||||
|
||||
#### Scenario: 导入时跳过重复 ICCID
|
||||
|
||||
- **WHEN** CSV 文件中的 ICCID "8986001234567890123" 已存在于系统中
|
||||
- **THEN** 系统跳过该 ICCID,记录跳过原因为"ICCID 已存在",继续处理其他 ICCID
|
||||
|
||||
#### Scenario: 导入时记录格式错误
|
||||
|
||||
- **WHEN** CSV 文件第 100 行的 ICCID "12345" 长度不符合电信卡要求(19位)
|
||||
- **THEN** 系统记录失败,原因为"电信 ICCID 必须为 19 位",行号为 100,继续处理其他 ICCID
|
||||
|
||||
#### Scenario: 查询导入任务进度
|
||||
|
||||
- **WHEN** 管理员查询导入任务(ID 为 1)的进度
|
||||
- **THEN** 系统返回任务状态、总数、成功数、跳过数、失败数、开始时间、完成时间
|
||||
|
||||
#### Scenario: 查询导入任务失败详情
|
||||
|
||||
- **WHEN** 管理员查询导入任务(ID 为 1)的失败详情
|
||||
- **THEN** 系统返回失败记录列表,每条包含行号、ICCID、失败原因
|
||||
|
||||
### Requirement: IoT 卡查询和筛选
|
||||
|
||||
@@ -302,3 +325,51 @@ This capability supports:
|
||||
|
||||
- **WHEN** 平台创建 IoT 卡,成本价为 50.00,分销价为 40.00
|
||||
- **THEN** 系统拒绝创建,返回错误信息"分销价不能低于成本价"
|
||||
|
||||
### Requirement: 单卡列表查询
|
||||
|
||||
系统 SHALL 提供单卡列表查询功能,用于管理未绑定设备的 IoT 卡资产。
|
||||
|
||||
**单卡定义**: 单卡是指未绑定到任何设备的 IoT 卡,即在 `device_sim_bindings` 表中不存在 `bind_status = 1`(已绑定) 的记录。
|
||||
|
||||
**查询条件**:
|
||||
- 套餐 ID(package_id): 可选,筛选已购买指定套餐的卡
|
||||
- 是否分销(is_distributed): 可选,true-已分销 false-未分销
|
||||
- 卡号状态(status): 可选,1-在库 2-已分销 3-已激活 4-已停用
|
||||
- 运营商(carrier_id): 可选,运营商 ID
|
||||
- 分销商 ID(shop_id): 可选,店铺 ID
|
||||
- 网卡号段(iccid_range): 可选,格式 "起始ICCID-结束ICCID"
|
||||
- ICCID: 可选,模糊匹配
|
||||
- 卡接入号(msisdn): 可选,模糊匹配
|
||||
- 是否换卡(is_replaced): 可选,true-有换卡记录 false-无换卡记录
|
||||
|
||||
**分页**:
|
||||
- 默认每页 20 条,最大每页 100 条
|
||||
- 返回总记录数和总页数
|
||||
|
||||
**数据权限**:
|
||||
- 基于 shop_id 自动应用数据权限过滤
|
||||
- 代理只能看到自己店铺及下级店铺的卡
|
||||
|
||||
#### Scenario: 查询未绑定设备的单卡列表
|
||||
|
||||
- **WHEN** 管理员查询单卡列表
|
||||
- **THEN** 系统返回所有未绑定设备的 IoT 卡(在 device_sim_bindings 中无 bind_status=1 记录的卡)
|
||||
|
||||
#### Scenario: 按运营商筛选单卡
|
||||
|
||||
- **WHEN** 管理员查询运营商 ID 为 1(电信)的单卡
|
||||
- **THEN** 系统返回 carrier_id = 1 且未绑定设备的 IoT 卡列表
|
||||
|
||||
#### Scenario: 按网卡号段筛选单卡
|
||||
|
||||
- **WHEN** 管理员查询 ICCID 号段为 "8986001000000000000-8986001999999999999" 的单卡
|
||||
- **THEN** 系统返回 ICCID 在该号段范围内且未绑定设备的 IoT 卡列表
|
||||
|
||||
#### Scenario: 按是否换卡筛选单卡
|
||||
|
||||
- **WHEN** 管理员查询有换卡记录的单卡(is_replaced=true)
|
||||
- **THEN** 系统返回在 card_replacement_records 表中有记录的 IoT 卡列表
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user