设备导入卡槽不对的问题
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-04-30
|
||||
111
openspec/changes/fix-device-import-slot-mapping/design.md
Normal file
111
openspec/changes/fix-device-import-slot-mapping/design.md
Normal file
@@ -0,0 +1,111 @@
|
||||
## Context
|
||||
|
||||
当前设备导入链路分为两段:
|
||||
|
||||
1. `pkg/utils/excel.go` 负责按固定列读取设备导入 Excel。
|
||||
2. `internal/task/device_import.go` 负责校验卡并创建 `tb_device_sim_binding` 记录。
|
||||
|
||||
现状问题在于解析层只保留“非空 ICCID 列表”,没有保留“这个 ICCID 原来来自第几个卡槽列”。任务层随后按数组顺序写入 `slot_position = i + 1`,使得源文件中的空槽位被压缩。这个问题不涉及新接口,也不需要调整数据库结构,但会跨越解析层与任务执行层,适合先通过设计文档把数据语义钉死。
|
||||
|
||||
约束条件:
|
||||
|
||||
- 必须遵守现有 `Handler → Service → Store → Model` 分层,不把槽位推断逻辑散落到多处。
|
||||
- 不新增表结构,不引入新依赖。
|
||||
- 设备导入仍走 Asynq 异步任务,保持当前事务边界和幂等行为。
|
||||
- 文档、日志、错误消息保持中文。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 保留 Excel `卡1~卡4` 的原始槽位信息,避免前置空槽被压缩。
|
||||
- 让导入创建的 `slot_position` 与 Excel 列号严格一致。
|
||||
- 对 `max_sim_slots` 之外的已填写 ICCID 给出明确失败规则。
|
||||
- 让后续查询设备绑定关系、切卡和运维判断都基于正确槽位数据。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 不新增或修改导入 API。
|
||||
- 不修复历史上已经错误导入的数据。
|
||||
- 不改变设备导入任务的权限、批次、实名策略等既有能力。
|
||||
- 不引入自动化测试要求,本次仅定义实现任务和手工验收路径。
|
||||
|
||||
## Decisions
|
||||
|
||||
### 决策1:在解析结果中保留“槽位 + ICCID”映射,而不是仅保留 ICCID 列表
|
||||
|
||||
**选择**:
|
||||
设备导入解析结构需要显式表达每张卡来自哪个槽位,例如保留 `slot_position` 与 `iccid` 的成对关系,或者使用等价的固定槽位结构。
|
||||
|
||||
**理由**:
|
||||
|
||||
- 只有解析层知道 ICCID 来自哪一列,到了任务层再推断已经丢失上下文。
|
||||
- 把槽位语义前置到解析结果,可以让任务层只负责校验和落库,职责更清晰。
|
||||
|
||||
**备选方案**:
|
||||
|
||||
- 在任务层根据 ICCID 顺序反推槽位:不可行,前置空槽信息已丢失。
|
||||
- 用占位空字符串继续传 `[]string`:可读性差,容易在后续处理中再次被压缩或忽略。
|
||||
|
||||
### 决策2:绑定记录的 `slot_position` 直接使用源列位,不再使用连续下标
|
||||
|
||||
**选择**:
|
||||
创建设备卡绑定时,`slot_position` 必须直接使用解析出的槽位编号,而不是 `i + 1`。
|
||||
|
||||
**理由**:
|
||||
|
||||
- `tb_device_sim_binding.slot_position` 本来就是槽位语义字段,应该存真实槽位。
|
||||
- 这样可以保持导入、查询、切卡、展示四个环节的语义一致。
|
||||
|
||||
**备选方案**:
|
||||
|
||||
- 继续写连续下标并在展示层修正:会污染底层数据,后续所有依赖槽位的逻辑都要补丁式兼容,不可接受。
|
||||
|
||||
### 决策3:填写超过 `max_sim_slots` 的 ICCID 时整行失败
|
||||
|
||||
**选择**:
|
||||
如果 Excel 某行声明 `max_sim_slots=2`,却填写了 `卡3` 或 `卡4`,该行导入失败,并给出明确失败原因。
|
||||
|
||||
**理由**:
|
||||
|
||||
- 超出设备最大槽位的绑定关系本身就是无效数据,不能静默忽略。
|
||||
- 失败比“部分导入 + 隐式丢弃”更容易让运营发现模板问题。
|
||||
|
||||
**备选方案**:
|
||||
|
||||
- 静默忽略越界槽位:会造成运营以为导入成功,但设备绑定不完整。
|
||||
- 自动上调 `max_sim_slots`:篡改源数据含义,不符合设备真实硬件能力。
|
||||
|
||||
### 决策4:沿用现有事务边界,不扩大导入任务架构
|
||||
|
||||
**选择**:
|
||||
仍在当前单行事务中完成设备创建、资产标识注册、卡绑定创建、卡快照更新和钱包创建,只替换槽位数据来源。
|
||||
|
||||
**理由**:
|
||||
|
||||
- 问题根因是数据语义错误,不是事务模型错误。
|
||||
- 保持现有事务边界可以减少改动范围和回归风险。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [风险] 解析结构变更会波及设备导入任务中遍历 ICCID 的逻辑
|
||||
→ Mitigation:只在设备导入专用结构中调整,不影响卡导入等其他解析路径。
|
||||
|
||||
- [风险] 历史错误导入的数据仍然存在,修复后新旧数据表现不一致
|
||||
→ Mitigation:在提案中明确本次仅修复“后续导入行为”,历史数据如需修复需单独立项。
|
||||
|
||||
- [风险] 运营模板可能继续填写越界槽位,修复后失败数会上升
|
||||
→ Mitigation:在失败原因中明确指出“填写槽位超出最大SIM槽数”,并更新导入使用说明。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 先更新 `device-import` 规格,明确“列位即槽位”。
|
||||
2. 调整设备导入解析结构与任务执行逻辑。
|
||||
3. 使用手工构造的 Excel 样例做导入验收,覆盖空槽保留和越界失败两类场景。
|
||||
4. 上线后仅影响新导入任务,无需数据迁移。
|
||||
5. 如需回滚,恢复解析和绑定逻辑即可;本次不涉及表结构变更。
|
||||
|
||||
## Open Questions
|
||||
|
||||
- 历史错误导入的数据是否需要补录或脚本修正;如果需要,应拆成独立变更处理。
|
||||
- 前端模板文案是否要把 `iccid_1 ~ iccid_4` 明确标注为“槽1 ~ 槽4”;这会影响使用体验,但不阻塞后端修复。
|
||||
32
openspec/changes/fix-device-import-slot-mapping/proposal.md
Normal file
32
openspec/changes/fix-device-import-slot-mapping/proposal.md
Normal file
@@ -0,0 +1,32 @@
|
||||
## Why
|
||||
|
||||
feature-2026-04-device-import-slot-mapping
|
||||
|
||||
当前设备导入会把 Excel 中非空 ICCID 列压缩成连续列表,导致“卡2、卡3”这类原始槽位信息在导入时丢失,最终被错误写入为“槽1、槽2”。该问题会直接造成设备与卡槽关系失真,影响后续设备查询、切卡和运维判断,需要尽快在规格和实现层统一修正。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 修改设备导入规格,明确 `卡1~卡4` 列表示固定槽位,导入时必须保留原始列位信息,不得按非空顺序重排。
|
||||
- 修改设备导入执行规则,设备卡绑定记录的 `slot_position` 必须与 Excel 列号一一对应。
|
||||
- 新增越界约束:当 `max_sim_slots` 小于某个已填写 ICCID 的槽位编号时,该行导入失败,避免写入超出设备最大槽位数的绑定关系。
|
||||
- 补充典型场景,覆盖“仅填写卡2/卡3”“前置空槽保留”“超出最大槽位失败”等业务行为。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
无新增功能
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `device-import`: 设备导入的槽位语义从“按非空 ICCID 顺序绑定”调整为“按 Excel 固定列位绑定到对应槽位”,并补充超出 `max_sim_slots` 的失败规则。
|
||||
|
||||
## Impact
|
||||
|
||||
- 受影响规格:`openspec/specs/device-import/spec.md`
|
||||
- 受影响代码:
|
||||
- `pkg/utils/excel.go` 中设备导入行的 ICCID 解析结构
|
||||
- `internal/task/device_import.go` 中设备卡绑定创建逻辑
|
||||
- 受影响数据:新导入设备的 `tb_device_sim_binding.slot_position` 写入规则
|
||||
- 受影响业务链路:设备详情、设备卡绑定列表、依赖槽位判断的运维操作
|
||||
- 依赖与接口:不新增外部依赖,不新增 API,仅修正既有导入行为
|
||||
@@ -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` 字段为对应行号
|
||||
17
openspec/changes/fix-device-import-slot-mapping/tasks.md
Normal file
17
openspec/changes/fix-device-import-slot-mapping/tasks.md
Normal file
@@ -0,0 +1,17 @@
|
||||
## 1. 规格与解析模型调整
|
||||
|
||||
- [x] 1.1 调整设备导入解析结构,显式保留每个 ICCID 的原始槽位编号,避免在 `pkg/utils/excel.go` 中压缩前置空槽。
|
||||
- [x] 1.2 更新设备导入解析逻辑,使 `卡1~卡4` 始终按固定列位映射为槽位 1~4,并补充“填写槽位超出最大SIM槽数”的失败原因。
|
||||
- [x] 1.3 运行 `gofmt` 和 `lsp_diagnostics`,确认解析层修改后无格式和静态诊断错误。
|
||||
|
||||
## 2. 导入任务绑定逻辑修正
|
||||
|
||||
- [x] 2.1 修改 `internal/task/device_import.go` 的设备卡校验与绑定创建流程,改为使用解析得到的原始槽位写入 `slot_position`。
|
||||
- [x] 2.2 保持现有单行事务边界不变,补充越界槽位失败处理,确保错误信息与规格一致。
|
||||
- [x] 2.3 运行 `gofmt` 和 `lsp_diagnostics`,确认任务层修改后无格式和静态诊断错误。
|
||||
|
||||
## 3. 手工验收与文档同步
|
||||
|
||||
- [x] 3.1 准备手工验收样例:覆盖“仅填写卡2/卡3保留槽位”和“填写槽位超出最大SIM槽数失败”两类 Excel 数据。
|
||||
- [ ] 3.2 在本地执行设备导入手工验收,确认导入结果中的绑定槽位与 Excel 原始列位一致,失败场景返回预期原因。
|
||||
- [x] 3.3 同步更新相关导入说明文档或模板说明,明确 `iccid_1 ~ iccid_4` 表示固定槽位而非连续顺序。
|
||||
50
openspec/changes/fix-device-import-slot-mapping/手工验收样例.md
Normal file
50
openspec/changes/fix-device-import-slot-mapping/手工验收样例.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# 设备导入槽位映射手工验收样例
|
||||
|
||||
本文档用于 `fix-device-import-slot-mapping` 提案的手工验收准备,覆盖“保留原始槽位”和“超出最大槽位失败”两类场景。
|
||||
|
||||
## Excel 表头
|
||||
|
||||
请在本地新建 `.xlsx` 文件,并使用以下固定表头顺序:
|
||||
|
||||
| virtual_no | device_name | device_model | device_type | imei | manufacturer | max_sim_slots | iccid_1 | iccid_2 | iccid_3 | iccid_4 |
|
||||
|------------|-------------|--------------|-------------|------|--------------|---------------|---------|---------|---------|---------|
|
||||
|
||||
所有列必须设置为文本格式。
|
||||
|
||||
## 样例 1:仅填写卡2/卡3,保留原始槽位
|
||||
|
||||
预期:导入成功后,绑定关系仍然写入槽位 2 和槽位 3,不得前移为槽位 1 和槽位 2。
|
||||
|
||||
| virtual_no | device_name | device_model | device_type | imei | manufacturer | max_sim_slots | iccid_1 | iccid_2 | iccid_3 | iccid_4 |
|
||||
|------------|-------------|--------------|-------------|------|--------------|---------------|---------|---------|---------|---------|
|
||||
| SLOT-MAP-OK-001 | 槽位保留样机 | GT06N | GPS Tracker | 860000000000001 | Concox | 3 | | `替换为已存在且未绑定的 ICCID_A` | `替换为已存在且未绑定的 ICCID_B` | |
|
||||
|
||||
验收要点:
|
||||
- 任务结果中该行应导入成功。
|
||||
- 设备绑定结果中,`ICCID_A` 的 `slot_position = 2`。
|
||||
- 设备绑定结果中,`ICCID_B` 的 `slot_position = 3`。
|
||||
|
||||
## 样例 2:填写槽位超出最大 SIM 槽数
|
||||
|
||||
预期:该行导入失败,失败原因为“卡槽填写超出最大SIM槽数”。
|
||||
|
||||
| virtual_no | device_name | device_model | device_type | imei | manufacturer | max_sim_slots | iccid_1 | iccid_2 | iccid_3 | iccid_4 |
|
||||
|------------|-------------|--------------|-------------|------|--------------|---------------|---------|---------|---------|---------|
|
||||
| SLOT-MAP-FAIL-001 | 越界槽位样机 | GT06N | GPS Tracker | 860000000000002 | Concox | 2 | | `替换为已存在且未绑定的 ICCID_C` | `替换为已存在且未绑定的 ICCID_D` | |
|
||||
|
||||
验收要点:
|
||||
- 任务结果中该行应计入失败。
|
||||
- 失败明细中的 `reason` 应为“卡槽填写超出最大SIM槽数”。
|
||||
- 该设备不应创建任何绑定记录。
|
||||
|
||||
## 执行前检查
|
||||
|
||||
- 准备的 ICCID 必须已存在系统中。
|
||||
- 准备的 ICCID 必须未绑定其他设备。
|
||||
- 上传前确认文件扩展名为 `.xlsx`。
|
||||
|
||||
## 结果核对建议
|
||||
|
||||
- 任务详情页核对成功数、失败数和失败原因。
|
||||
- 设备详情页或绑定列表接口核对 `slot_position`。
|
||||
- 如需进一步确认,可直接查询 `tb_device_sim_binding.slot_position`。
|
||||
Reference in New Issue
Block a user