## 1. CSV 解析改造

- [x] 1.1 修改 `pkg/utils/csv.go` 的 `CSVParseResult` 结构体，添加 `Cards []CardInfo` 替代 `ICCIDs []string`
- [x] 1.2 修改 `ParseICCIDFromCSV` 函数为 `ParseCardCSV`，支持解析 ICCID + MSISDN 两列
- [x] 1.3 添加列数校验，单列 CSV 直接返回错误
- [x] 1.4 添加 ICCID/MSISDN 非空校验，空值记录为解析错误
- [x] 1.5 更新表头识别逻辑，支持 msisdn/接入号/手机号 关键字
- [x] 1.6 更新 `pkg/utils/csv_test.go` 测试用例

## 2. 导入任务模型改造

- [x] 2.1 创建数据库迁移：将 `iccid_list` 字段重命名为 `card_list`，类型保持 JSONB
- [x] 2.2 修改 `internal/model/iot_card_import_task.go`，定义 `CardListJSON` 类型为 `[]CardInfo{ICCID, MSISDN}`
- [x] 2.3 更新 `ImportResultItem` 结构体添加 `MSISDN` 字段

## 3. 导入服务改造

- [x] 3.1 修改 `internal/service/iot_card_import/service.go`，调用新的 `ParseCardCSV` 函数
- [x] 3.2 将解析结果的 `Cards` 存入任务的 `card_list` 字段

## 4. 导入任务处理改造

- [x] 4.1 修改 `internal/task/iot_card_import.go` 的 `getICCIDsFromTask` 改为 `getCardsFromTask`
- [x] 4.2 修改 `processBatch` 函数，创建卡记录时同时填充 `ICCID` 和 `MSISDN`
- [x] 4.3 更新失败/跳过记录的结构，包含 MSISDN 信息
- [x] 4.4 更新 `internal/task/iot_card_import_test.go` 测试用例

## 5. API 文档更新

- [x] 5.1 更新路由注册中 CSV 文件字段的描述，说明必须包含 ICCID 和 MSISDN 两列
- [x] 5.2 重新生成 OpenAPI 文档
