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:
|
||||
- Device-level package purchases with shared data pool
|
||||
- Batch device allocation to agents
|
||||
- Remote device operations (reboot, password change, reset)
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: 设备实体定义
|
||||
|
||||
系统 SHALL 定义设备(Device)实体,用于管理用户的物联网设备(如 GPS 追踪器、智能传感器等),支持设备与 IoT 卡的绑定关系、设备批量分配和设备操作。
|
||||
@@ -27,7 +25,7 @@ This capability supports:
|
||||
|
||||
**基本属性**:
|
||||
- `id`: 设备 ID(主键,BIGINT)
|
||||
- `device_no`: 设备编号(唯一,VARCHAR(50))
|
||||
- `device_no`: 设备编号(唯一,VARCHAR(100))
|
||||
- `device_name`: 设备名称(VARCHAR(255))
|
||||
- `device_model`: 设备型号(VARCHAR(100))
|
||||
- `device_type`: 设备类型(VARCHAR(50),如 "GPS Tracker"、"Camera"、"Sensor")
|
||||
@@ -35,35 +33,36 @@ This capability supports:
|
||||
- `manufacturer`: 设备制造商(VARCHAR(255),可选)
|
||||
- `batch_no`: 批次号(VARCHAR(100),用于批量导入追溯)
|
||||
|
||||
**所有权和状态**:
|
||||
- `owner_type`: 所有者类型(VARCHAR(20),"platform"-平台库存(等待分配) | "agent"-代理商 | "user"-用户)
|
||||
- `owner_id`: 所有者 ID(BIGINT,platform 时为 0,agent/user 时为对应的 ID)
|
||||
- `status`: 设备状态(INT,1-未激活 2-已激活 3-已停用)
|
||||
**店铺归属和状态**:
|
||||
- `shop_id`: 店铺 ID(BIGINT,可空,NULL 表示平台库存,有值表示店铺所有)
|
||||
- `status`: 设备状态(INT,1-在库 2-已分销 3-已激活 4-已停用)
|
||||
- `activated_at`: 激活时间(TIMESTAMP,可空)
|
||||
|
||||
**设备操作配置**(预留字段,用于后续设备操作功能):
|
||||
- `device_username`: 设备登录账号(VARCHAR(100),可选)
|
||||
- `device_password_encrypted`: 设备登录密码(加密存储,TEXT,可选)
|
||||
- `device_password_encrypted`: 设备登录密码(加密存储,VARCHAR(255),可选)
|
||||
- `device_api_endpoint`: 设备 API 接口地址(VARCHAR(500),可选)
|
||||
|
||||
**系统字段**:
|
||||
- `created_at`: 创建时间(TIMESTAMP,自动填充)
|
||||
- `updated_at`: 更新时间(TIMESTAMP,自动填充)
|
||||
- `creator`: 创建人 ID(BIGINT)
|
||||
- `updater`: 更新人 ID(BIGINT)
|
||||
|
||||
#### Scenario: 用户添加设备
|
||||
|
||||
- **WHEN** 用户添加自己的设备(设备编号为 "GPS-001",设备名称为 "物流车辆追踪器")
|
||||
- **THEN** 系统创建设备记录,`owner_type` 为 "user",`owner_id` 为用户 ID,状态为 1(未激活)
|
||||
- **THEN** 系统创建设备记录,根据用户归属设置 `shop_id`,状态为 1(在库)
|
||||
|
||||
#### Scenario: 平台导入设备到库存
|
||||
|
||||
- **WHEN** 平台批量导入设备数据(准备发货给代理)
|
||||
- **THEN** 系统创建设备记录,`owner_type` 为 "platform",`owner_id` 为 0,状态为 1(未激活)
|
||||
- **THEN** 系统创建设备记录,`shop_id` 为 NULL(平台库存),状态为 1(在库)
|
||||
|
||||
#### Scenario: 运营人员批量分配设备给代理
|
||||
#### Scenario: 运营人员批量分配设备给代理店铺
|
||||
|
||||
- **WHEN** 运营人员将平台库存设备(ID 为 1001)分配给代理商(用户 ID 为 123)
|
||||
- **THEN** 系统将设备的 `owner_type` 变更为 "agent",`owner_id` 设置为 123,同时自动分配该设备绑定的所有 IoT 卡给代理
|
||||
- **WHEN** 运营人员将平台库存设备(ID 为 1001)分配给代理店铺(ID 为 10)
|
||||
- **THEN** 系统将设备的 `shop_id` 设置为 10,同时自动将该设备绑定的所有 IoT 卡的 `shop_id` 也设置为 10
|
||||
|
||||
---
|
||||
|
||||
@@ -102,7 +101,7 @@ This capability supports:
|
||||
- 一个 IoT 卡同一时间只能绑定一个设备
|
||||
- 绑定时记录插槽位置(slot_position: 1, 2, 3, 4)
|
||||
- 绑定时记录绑定时间和绑定状态(1-已绑定 2-已解绑)
|
||||
- 设备绑定 IoT 卡后,IoT 卡的 `owner_type` 变更为 "device",`owner_id` 变更为设备 ID
|
||||
- 绑定/解绑操作不改变 IoT 卡的 shop_id(所有权由分销操作管理,而非绑定操作)
|
||||
|
||||
**中间表 device_sim_bindings**:
|
||||
- `id`: 绑定记录 ID(主键,BIGINT)
|
||||
@@ -118,27 +117,12 @@ This capability supports:
|
||||
#### Scenario: 绑定 IoT 卡到设备
|
||||
|
||||
- **WHEN** 用户将 IoT 卡(ID 为 101)绑定到设备(ID 为 1001)的插槽 1
|
||||
- **THEN** 系统创建绑定记录,`device_id` 为 1001,`iot_card_id` 为 101,`slot_position` 为 1,`bind_status` 为 1(已绑定),`bind_time` 为当前时间,IoT 卡的 `owner_type` 变更为 "device",`owner_id` 变更为 1001
|
||||
|
||||
#### Scenario: 绑定超过最大插槽数量
|
||||
|
||||
- **WHEN** 用户尝试将第 5 张 IoT 卡绑定到最大插槽数为 4 的设备
|
||||
- **THEN** 系统拒绝绑定,返回错误信息"设备插槽已满,最多支持 4 张 IoT 卡"
|
||||
|
||||
#### Scenario: 绑定已被占用的 IoT 卡
|
||||
|
||||
- **WHEN** 用户尝试绑定已被其他设备绑定的 IoT 卡
|
||||
- **THEN** 系统拒绝绑定,返回错误信息"该 IoT 卡已被其他设备绑定"
|
||||
- **THEN** 系统创建绑定记录,`device_id` 为 1001,`iot_card_id` 为 101,`slot_position` 为 1,`bind_status` 为 1(已绑定),`bind_time` 为当前时间
|
||||
|
||||
#### Scenario: 解绑 IoT 卡
|
||||
|
||||
- **WHEN** 用户解绑设备的 IoT 卡(绑定记录 ID 为 10)
|
||||
- **THEN** 系统将绑定记录的 `bind_status` 从 1(已绑定) 变更为 2(已解绑),`unbind_time` 记录解绑时间,IoT 卡的 `owner_type` 和 `owner_id` 重置
|
||||
|
||||
#### Scenario: 查询设备当前绑定的 IoT 卡
|
||||
|
||||
- **WHEN** 用户查询设备(ID 为 1001)当前绑定的 IoT 卡
|
||||
- **THEN** 系统返回 `device_id` 为 1001 且 `bind_status` 为 1(已绑定) 的所有绑定记录,包含 IoT 卡信息(ICCID、运营商、激活状态等)和插槽位置
|
||||
- **THEN** 系统将绑定记录的 `bind_status` 从 1(已绑定) 变更为 2(已解绑),`unbind_time` 记录解绑时间,IoT 卡的 `shop_id` 保持不变
|
||||
|
||||
---
|
||||
|
||||
@@ -179,23 +163,23 @@ This capability supports:
|
||||
|
||||
### Requirement: 设备批量分配
|
||||
|
||||
系统 SHALL 支持运营人员批量分配设备给代理,设备分配时自动分配该设备绑定的所有 IoT 卡。
|
||||
系统 SHALL 支持运营人员批量分配设备给代理店铺,设备分配时自动分配该设备绑定的所有 IoT 卡。
|
||||
|
||||
**分配规则**:
|
||||
- 只能分配 `owner_type` 为 "platform" 的设备(平台库存)
|
||||
- 分配时,设备的 `owner_type` 变更为 "agent",`owner_id` 设置为代理用户 ID
|
||||
- 分配时,设备绑定的所有 IoT 卡的 `owner_type` 也变更为 "agent",`owner_id` 设置为代理用户 ID
|
||||
- 只能分配 `shop_id` 为 NULL 的设备(平台库存)
|
||||
- 分配时,设备的 `shop_id` 设置为目标店铺 ID
|
||||
- 分配时,设备绑定的所有 IoT 卡的 `shop_id` 也设置为目标店铺 ID
|
||||
- 分配操作记录到操作日志
|
||||
|
||||
#### Scenario: 运营人员批量分配设备
|
||||
|
||||
- **WHEN** 运营人员将 10 台设备(平台库存)分配给代理商(用户 ID 为 123)
|
||||
- **THEN** 系统将这 10 台设备的 `owner_type` 变更为 "agent",`owner_id` 设置为 123,同时将这些设备绑定的所有 IoT 卡也分配给代理 123
|
||||
- **WHEN** 运营人员将 10 台设备(平台库存)分配给代理店铺(ID 为 10)
|
||||
- **THEN** 系统将这 10 台设备的 `shop_id` 设置为 10,同时将这些设备绑定的所有 IoT 卡的 `shop_id` 也设置为 10
|
||||
|
||||
#### Scenario: 分配已分配的设备
|
||||
|
||||
- **WHEN** 运营人员尝试分配 `owner_type` 为 "agent" 的设备
|
||||
- **THEN** 系统拒绝分配,返回错误信息"该设备已分配给代理,不能重复分配"
|
||||
- **WHEN** 运营人员尝试分配 `shop_id` 不为 NULL 的设备
|
||||
- **THEN** 系统拒绝分配,返回错误信息"该设备已分配给店铺,不能重复分配"
|
||||
|
||||
---
|
||||
|
||||
@@ -259,14 +243,13 @@ This capability supports:
|
||||
|
||||
### Requirement: 设备查询和筛选
|
||||
|
||||
系统 SHALL 支持多维度查询和筛选设备,包括状态、所有者、批次号、设备类型等。
|
||||
系统 SHALL 支持多维度查询和筛选设备,包括状态、店铺归属、批次号、设备类型等。
|
||||
|
||||
**查询条件**:
|
||||
- 设备编号(精确匹配或模糊匹配)
|
||||
- 设备名称(模糊匹配)
|
||||
- 设备状态(单选或多选)
|
||||
- 所有者类型(platform | agent | user)
|
||||
- 所有者 ID(仅当所有者类型为 agent/user 时有效)
|
||||
- 店铺 ID(shop_id): 可选,NULL 表示平台库存
|
||||
- 批次号(精确匹配)
|
||||
- 设备类型(单选或多选)
|
||||
- 设备制造商(模糊匹配)
|
||||
@@ -277,25 +260,19 @@ This capability supports:
|
||||
- 默认每页 20 条,最大每页 100 条
|
||||
- 返回总记录数和总页数
|
||||
|
||||
**数据权限**:
|
||||
- 基于 shop_id 自动应用数据权限过滤
|
||||
- 代理只能看到自己店铺及下级店铺的设备
|
||||
|
||||
#### Scenario: 查询平台库存设备
|
||||
|
||||
- **WHEN** 运营人员查询平台库存设备
|
||||
- **THEN** 系统返回 `owner_type` 为 "platform" 的设备列表
|
||||
- **THEN** 系统返回 `shop_id` 为 NULL 的设备列表
|
||||
|
||||
#### Scenario: 代理查询自己的设备
|
||||
#### Scenario: 代理查询自己店铺的设备
|
||||
|
||||
- **WHEN** 代理商(用户 ID 为 123)查询自己的设备
|
||||
- **THEN** 系统返回 `owner_type` 为 "agent" 且 `owner_id` 为 123 的设备列表
|
||||
|
||||
#### Scenario: 用户查询自己的设备
|
||||
|
||||
- **WHEN** 用户(用户 ID 为 2001)查询自己的设备
|
||||
- **THEN** 系统返回 `owner_type` 为 "user" 且 `owner_id` 为 2001 的设备列表,包含设备绑定的所有 IoT 卡信息
|
||||
|
||||
#### Scenario: 运营人员通过设备查看绑定的所有 IoT 卡
|
||||
|
||||
- **WHEN** 运营人员需要处理投诉,查询设备(ID 为 1001)绑定的所有 IoT 卡
|
||||
- **THEN** 系统返回设备信息和绑定的所有 IoT 卡详细信息(ICCID、运营商、激活状态、流量使用等),方便统一查看和管理
|
||||
- **WHEN** 代理店铺(ID 为 10)查询自己的设备
|
||||
- **THEN** 系统返回 `shop_id` 为 10(及其下级店铺)的设备列表
|
||||
|
||||
---
|
||||
|
||||
@@ -304,14 +281,13 @@ This capability supports:
|
||||
系统 SHALL 对设备数据进行校验,确保数据完整性和一致性。
|
||||
|
||||
**校验规则**:
|
||||
- 设备编号(device_no):必填,长度 1-50 字符,唯一
|
||||
- 设备名称(device_name):必填,长度 1-255 字符
|
||||
- 设备型号(device_model):必填,长度 1-100 字符
|
||||
- 设备类型(device_type):必填,长度 1-50 字符
|
||||
- 设备编号(device_no):必填,长度 1-100 字符,唯一
|
||||
- 设备名称(device_name):可选,长度 1-255 字符
|
||||
- 设备型号(device_model):可选,长度 1-100 字符
|
||||
- 设备类型(device_type):可选,长度 1-50 字符
|
||||
- 最大插槽数(max_sim_slots):必填,1-4 之间的整数
|
||||
- 所有者类型(owner_type):必填,枚举值 "platform" | "agent" | "user"
|
||||
- 所有者 ID(owner_id):必填,≥ 0,当 owner_type 为 "platform" 时必须为 0
|
||||
- 设备状态(status):必填,枚举值 1(未激活) | 2(已激活) | 3(已停用)
|
||||
- 店铺 ID(shop_id):可选,NULL 表示平台库存,有值必须是有效的店铺 ID
|
||||
- 设备状态(status):必填,枚举值 1(在库) | 2(已分销) | 3(已激活) | 4(已停用)
|
||||
|
||||
#### Scenario: 创建设备时插槽数超出范围
|
||||
|
||||
@@ -322,3 +298,4 @@ This capability supports:
|
||||
|
||||
- **WHEN** 用户创建设备,设备编号为已存在的 "DEV-001"
|
||||
- **THEN** 系统拒绝创建,返回错误信息"设备编号已存在"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user