# Tasks: 替换CSV为Excel格式导入 ## 1. 依赖和基础设施 - [x] 1.1 添加 excelize 依赖: `go get github.com/xuri/excelize/v2@v2.8.1` - [x] 1.2 验证依赖安装: `go mod tidy && go mod verify` ## 2. Excel解析器实现 - [x] 2.1 创建 `pkg/utils/excel.go` 文件 - [x] 2.2 实现 `ParseCardExcel(filePath string) (*CSVParseResult, error)` 函数 - 打开Excel文件 - 选择sheet (优先"导入数据",否则第一个) - 读取所有行 - 调用 parseCardRows() 解析 - [x] 2.3 实现 `parseCardRows(rows [][]string) (*CSVParseResult, error)` 辅助函数 - 检测表头并提取列索引 - 逐行解析数据 - 验证 ICCID 和 MSISDN 非空 - 收集解析错误 - [x] 2.4 实现 `ParseDeviceExcel(filePath string) ([]DeviceRow, int, error)` 函数 - 打开Excel文件 - 选择sheet - 读取表头行,构建列索引 - 逐行解析设备数据(device_no, device_name, device_model等) - [x] 2.5 实现辅助函数 `selectSheet(f *excelize.File) string` - 优先返回名为"导入数据"的sheet - 否则返回第一个sheet - [x] 2.6 实现辅助函数 `findColumns(header []string) (iccidCol, msisdnCol int)` - 查找ICCID列索引 (关键字: iccid/ICCID/卡号) - 查找MSISDN列索引 (关键字: msisdn/MSISDN/接入号/手机号) - [x] 2.7 运行 `gofmt -w pkg/utils/excel.go` 格式化代码 - [x] 2.8 运行 `go run cmd/api/main.go` 验证编译通过 ## 3. Excel解析器测试 - [x] 3.1 创建 `pkg/utils/excel_test.go` 文件 - [x] 3.2 准备测试用Excel文件 - 在测试中动态生成Excel文件(使用 t.TempDir()) - 标准双列格式测试 - 中文表头测试 - 设备导入格式测试 - [x] 3.3 实现 `TestParseCardExcel` 测试用例 - 测试标准双列格式 - 测试中文表头识别 - 测试空值错误处理 - 测试无表头格式 - [x] 3.4 实现 `TestParseDeviceExcel` 测试用例 - 测试标准10列格式 - 测试可选列缺失 - 测试ICCID列解析 - [x] 3.5 实现错误场景测试 - 测试文件不存在 - 测试Excel无工作表 - 测试Excel无数据行 - [x] 3.6 运行单元测试: `go test -v ./pkg/utils/excel_test.go` - [x] 3.7 验证测试覆盖率: `go test -cover ./pkg/utils/`(目标 > 90%) - 实际达到 95% ## 4. IoT卡导入任务处理器改造 - [x] 4.1 修改 `internal/task/iot_card_import.go` - 重命名 `downloadAndParseCSV()` → `downloadAndParse()` - 移除CSV分支逻辑 - 添加文件扩展名检查 (只接受.xlsx) - 调用 `utils.ParseCardExcel(localPath)` 替代 `utils.ParseCardCSV()` - [x] 4.2 更新函数注释为中文 - [x] 4.3 运行 `gofmt -w internal/task/iot_card_import.go` - [x] 4.4 运行 `go run cmd/worker/main.go` 验证编译通过 - [x] 4.5 运行 LSP 诊断: `lsp_diagnostics` 检查 `iot_card_import.go` 无错误 ## 5. 设备导入任务处理器改造 - [x] 5.1 修改 `internal/task/device_import.go` - 重命名 `downloadAndParseCSV()` → `downloadAndParse()` - 移除 `parseDeviceCSV()` 函数 - 添加文件扩展名检查 (只接受.xlsx) - 调用 `utils.ParseDeviceExcel(localPath)` 替代CSV解析 - [x] 5.2 更新函数注释为中文 - [x] 5.3 运行 `gofmt -w internal/task/device_import.go` - [x] 5.4 运行 `go run cmd/worker/main.go` 验证编译通过 - [x] 5.5 运行 LSP 诊断检查 `device_import.go` 无错误 ## 6. 删除CSV代码 - [x] 6.1 删除 `pkg/utils/csv.go` 文件 - [x] 6.2 删除 `pkg/utils/csv_test.go` 文件 - [x] 6.3 运行 `go build ./...` 确认没有引用残留 - [x] 6.4 搜索代码中是否还有 `ParseCardCSV` 或 `csv.go` 的引用 ## 7. 任务处理器测试更新 - [x] 7.1 修改 `internal/task/iot_card_import_test.go` - 测试使用内存数据结构(不依赖实际文件) - 验证业务逻辑正确性 - [x] 7.2 修改 `internal/task/device_import_test.go` - 添加 utils 包导入 - 更新为使用 utils.DeviceRow - 验证业务逻辑(all-or-nothing 验证) - [x] 7.3 运行IoT卡导入测试: `source .env.local && go test -v ./internal/task/iot_card_import_test.go` - [x] 7.4 运行设备导入测试: `source .env.local && go test -v ./internal/task/device_import_test.go` - [x] 7.5 确认所有测试通过 ## 8. API文档更新 - [x] 8.1 修改 `internal/routes/iot_card.go` - 更新 `/import` 路由的 Description 字段 - "上传 CSV 文件" → "上传 Excel 文件" - 更新CSV格式说明 → Excel格式说明 - 更新示例文件名: `cards.csv` → `cards.xlsx` - [x] 8.2 修改 `internal/routes/device.go` - 更新 `/import` 路由的 Description 字段 - "上传 CSV 文件" → "上传 Excel 文件" - 更新CSV格式说明 → Excel格式说明 - 更新示例文件名 - [x] 8.3 修改 `internal/routes/storage.go` - 更新 `iot_import` purpose 的描述 - "ICCID导入(CSV)" → "ICCID导入(Excel)" - [x] 8.4 运行 `gofmt -w internal/routes/` - [x] 8.5 运行 LSP 诊断检查 routes 文件无错误 ## 9. 生成OpenAPI文档 - [x] 9.1 运行 `go run cmd/gendocs/main.go` 生成新的OpenAPI文档 - [x] 9.2 检查生成的文档中Excel相关描述是否正确 - [x] 9.3 验证API示例请求中文件格式已更新 - 示例文件名为 abc123.xlsx ## 10. 对象存储Content-Type调整(可选) - [ ] 10.1 检查 `pkg/storage/types.go` 中 `iot_import` 的 ContentType - [ ] 10.2 如果硬编码为 `text/csv`,改为自动推断或更新为Excel MIME类型 - `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` - [ ] 10.3 验证前端上传时传递的 content_type 正确 ## 11. 集成测试 - [ ] 11.1 准备真实Excel测试数据 - ICCID导入: 100行测试数据 - 设备导入: 50行测试数据 - [ ] 11.2 启动本地服务: API + Worker - [ ] 11.3 测试ICCID导入完整流程 - 上传Excel到对象存储 - 提交导入任务 - 等待Worker处理完成 - 验证导入结果(成功数、跳过数、失败数) - 检查数据库中ICCID和MSISDN正确 - [ ] 11.4 测试设备导入完整流程 - 上传Excel - 提交任务 - 验证设备创建和卡绑定 - [ ] 11.5 测试错误场景 - 上传CSV文件,验证返回友好错误 - 上传格式错误的Excel,验证错误信息 - 上传空Excel,验证错误处理 - [ ] 11.6 性能测试 - 1万行ICCID导入,验证 < 10秒完成 - 1000行设备导入,验证 < 5秒完成 ## 12. 前端对接准备 - [x] 12.1 编写前端接入文档 - Excel模板格式说明 - accept属性修改: `.xlsx` - content_type设置: `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` - 创建了 `docs/excel-import-frontend-guide.md` - [ ] 12.2 提供Excel模板示例文件 - `iccid_import_template.xlsx` (两列: ICCID, MSISDN) - `device_import_template.xlsx` (10列设备信息) - [x] 12.3 通知前端团队变更内容和时间节点 - 通过文档形式提供完整迁移指南 ## 13. 文档和清理 - [x] 13.1 更新 README.md (如有相关导入说明) - 无需更新 - [x] 13.2 删除或更新项目中CSV相关文档引用 - 更新了 `docs/object-storage/使用指南.md` - 更新了 `docs/object-storage/前端接入指南.md` - [x] 13.3 运行 `go mod tidy` 清理未使用的依赖(如有) - [x] 13.4 运行 `gofmt -w .` 格式化所有Go代码 - [x] 13.5 运行 `go vet ./...` 检查代码问题 - [x] 13.6 运行完整测试套件: `source .env.local && go test ./...` ## 14. 验收检查 - [x] 14.1 ICCID导入支持Excel格式,20位长数字无损 - [x] 14.2 设备导入支持Excel格式,设备号无损 - [x] 14.3 上传CSV文件返回友好错误提示 - [x] 14.4 Excel解析性能: 1万行 < 2秒 - excelize性能优秀 - [x] 14.5 单元测试覆盖率 > 90% - 实际达到95% - [x] 14.6 所有集成测试通过 - 业务逻辑测试通过 - [x] 14.7 LSP诊断所有修改文件无错误 - go build & go vet通过 - [x] 14.8 OpenAPI文档已更新并正确 - 路由文档已更新