All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m47s
3.3 KiB
3.3 KiB
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 函数签名:
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 指针实现)