## MODIFIED Requirements ### Requirement: 导入任务实体定义 系统 SHALL 定义 IoT 卡导入任务(IotCardImportTask)实体,用于跟踪 IoT 卡批量导入的进度和结果。 **实体字段**: **任务信息**: - `id`: 任务 ID(主键,BIGINT) - `task_no`: 任务编号(VARCHAR(50),唯一,格式: IMP-YYYYMMDD-XXXXXX) - `status`: 任务状态(INT,1-待处理 2-处理中 3-已完成 4-失败) **导入参数**: - `carrier_id`: 运营商 ID(BIGINT,必填) - `carrier_type`: 运营商类型(VARCHAR(10),CMCC/CUCC/CTCC/CBN) - `batch_no`: 批次号(VARCHAR(100),可选) - `file_name`: 原始文件名(VARCHAR(255),可选) **待导入数据**: - `card_list`: 待导入卡列表(JSONB,结构: [{iccid, msisdn}],替代原 iccid_list) **进度统计**: - `total_count`: 总数(INT,CSV 文件总行数) - `success_count`: 成功数(INT,成功导入的卡数量) - `skip_count`: 跳过数(INT,因重复等原因跳过的数量) - `fail_count`: 失败数(INT,因格式错误等原因失败的数量) **结果详情**: - `skipped_items`: 跳过记录详情(JSONB,结构: [{line, iccid, msisdn, reason}]) - `failed_items`: 失败记录详情(JSONB,结构: [{line, iccid, msisdn, reason}]) **时间和错误**: - `started_at`: 开始处理时间(TIMESTAMP,可空) - `completed_at`: 完成时间(TIMESTAMP,可空) - `error_message`: 任务级错误信息(TEXT,可空,如文件解析失败等) **系统字段**: - `shop_id`: 店铺 ID(BIGINT,可空,记录发起导入的店铺) - `created_at`: 创建时间(TIMESTAMP,自动填充) - `updated_at`: 更新时间(TIMESTAMP,自动填充) - `creator`: 创建人 ID(BIGINT) - `updater`: 更新人 ID(BIGINT) #### Scenario: 创建导入任务 - **GIVEN** 管理员上传包含 ICCID 和 MSISDN 两列的 CSV 文件 - **WHEN** 系统解析 CSV 并创建导入任务 - **THEN** 系统创建导入任务记录,`card_list` 包含 [{iccid, msisdn}] 结构,`status` 为 1(待处理) --- ### Requirement: IotCard 写入时同步填充 ICCID 双列 `processBatch()` 在初始化 `model.IotCard` 时,SHALL 调用 `utils.SplitICCID` 赋值 `ICCID19` 和 `ICCID20` 两个字段。 - `ICCID19 string` = `iccid19`(`SplitICCID` 返回值第一个,所有合法卡必填) - `ICCID20 *string` = `iccid20`(`SplitICCID` 返回值第二个,**指针类型**;19 位卡返回 `nil`,GORM 写入 SQL NULL;禁止赋空字符串 `""`) - 若 `SplitICCID` 返回 `iccid19 == ""`(异常长度 ICCID),不写入数据库,标记为 fail(此情况在 `ValidateICCID` 长度校验后理论上不应出现,作防御性保留) `SplitICCID` 函数签名: ```go func SplitICCID(iccid string) (iccid19 string, iccid20 *string) // 19 位:返回 (iccid, nil) // 20 位:返回 (iccid[:19], &iccid) // 其他:返回 ("", nil) ``` #### Scenario: 导入 19 位卡时填充双列 - **WHEN** 批量导入时某张卡的 ICCID 长度为 19 位 - **THEN** 写入数据库时 `iccid_19` = ICCID 原值,`iccid_20` 为 **SQL NULL**(通过 `*string` 赋值 `nil` 实现) #### Scenario: 导入 20 位卡时填充双列 - **WHEN** 批量导入时某张卡的 ICCID 长度为 20 位 - **THEN** 写入数据库时 `iccid_19` = ICCID 前 19 位,`iccid_20` = ICCID 原值(通过 `*string` 赋非 nil 指针实现)