Files
huang d309951493
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m33s
feat(import): 用 Excel 格式替换 CSV 导入
- 删除 CSV 解析代码,新增 Excel 解析器 (excelize)

- 更新 IoT 卡和设备导入任务处理器

- 更新 API 路由文档和前端接入指南

- 归档变更到 openspec/changes/archive/

- 同步 delta specs 到 main specs
2026-01-31 14:13:02 +08:00

7.7 KiB
Raw Permalink Blame History

Tasks: 替换CSV为Excel格式导入

1. 依赖和基础设施

  • 1.1 添加 excelize 依赖: go get github.com/xuri/excelize/v2@v2.8.1
  • 1.2 验证依赖安装: go mod tidy && go mod verify

2. Excel解析器实现

  • 2.1 创建 pkg/utils/excel.go 文件
  • 2.2 实现 ParseCardExcel(filePath string) (*CSVParseResult, error) 函数
    • 打开Excel文件
    • 选择sheet (优先"导入数据",否则第一个)
    • 读取所有行
    • 调用 parseCardRows() 解析
  • 2.3 实现 parseCardRows(rows [][]string) (*CSVParseResult, error) 辅助函数
    • 检测表头并提取列索引
    • 逐行解析数据
    • 验证 ICCID 和 MSISDN 非空
    • 收集解析错误
  • 2.4 实现 ParseDeviceExcel(filePath string) ([]DeviceRow, int, error) 函数
    • 打开Excel文件
    • 选择sheet
    • 读取表头行,构建列索引
    • 逐行解析设备数据(device_no, device_name, device_model等)
  • 2.5 实现辅助函数 selectSheet(f *excelize.File) string
    • 优先返回名为"导入数据"的sheet
    • 否则返回第一个sheet
  • 2.6 实现辅助函数 findColumns(header []string) (iccidCol, msisdnCol int)
    • 查找ICCID列索引 (关键字: iccid/ICCID/卡号)
    • 查找MSISDN列索引 (关键字: msisdn/MSISDN/接入号/手机号)
  • 2.7 运行 gofmt -w pkg/utils/excel.go 格式化代码
  • 2.8 运行 go run cmd/api/main.go 验证编译通过

3. Excel解析器测试

  • 3.1 创建 pkg/utils/excel_test.go 文件
  • 3.2 准备测试用Excel文件
    • 在测试中动态生成Excel文件使用 t.TempDir()
    • 标准双列格式测试
    • 中文表头测试
    • 设备导入格式测试
  • 3.3 实现 TestParseCardExcel 测试用例
    • 测试标准双列格式
    • 测试中文表头识别
    • 测试空值错误处理
    • 测试无表头格式
  • 3.4 实现 TestParseDeviceExcel 测试用例
    • 测试标准10列格式
    • 测试可选列缺失
    • 测试ICCID列解析
  • 3.5 实现错误场景测试
    • 测试文件不存在
    • 测试Excel无工作表
    • 测试Excel无数据行
  • 3.6 运行单元测试: go test -v ./pkg/utils/excel_test.go
  • 3.7 验证测试覆盖率: go test -cover ./pkg/utils/(目标 > 90%) - 实际达到 95%

4. IoT卡导入任务处理器改造

  • 4.1 修改 internal/task/iot_card_import.go
    • 重命名 downloadAndParseCSV()downloadAndParse()
    • 移除CSV分支逻辑
    • 添加文件扩展名检查 (只接受.xlsx)
    • 调用 utils.ParseCardExcel(localPath) 替代 utils.ParseCardCSV()
  • 4.2 更新函数注释为中文
  • 4.3 运行 gofmt -w internal/task/iot_card_import.go
  • 4.4 运行 go run cmd/worker/main.go 验证编译通过
  • 4.5 运行 LSP 诊断: lsp_diagnostics 检查 iot_card_import.go 无错误

5. 设备导入任务处理器改造

  • 5.1 修改 internal/task/device_import.go
    • 重命名 downloadAndParseCSV()downloadAndParse()
    • 移除 parseDeviceCSV() 函数
    • 添加文件扩展名检查 (只接受.xlsx)
    • 调用 utils.ParseDeviceExcel(localPath) 替代CSV解析
  • 5.2 更新函数注释为中文
  • 5.3 运行 gofmt -w internal/task/device_import.go
  • 5.4 运行 go run cmd/worker/main.go 验证编译通过
  • 5.5 运行 LSP 诊断检查 device_import.go 无错误

6. 删除CSV代码

  • 6.1 删除 pkg/utils/csv.go 文件
  • 6.2 删除 pkg/utils/csv_test.go 文件
  • 6.3 运行 go build ./... 确认没有引用残留
  • 6.4 搜索代码中是否还有 ParseCardCSVcsv.go 的引用

7. 任务处理器测试更新

  • 7.1 修改 internal/task/iot_card_import_test.go
    • 测试使用内存数据结构(不依赖实际文件)
    • 验证业务逻辑正确性
  • 7.2 修改 internal/task/device_import_test.go
    • 添加 utils 包导入
    • 更新为使用 utils.DeviceRow
    • 验证业务逻辑all-or-nothing 验证)
  • 7.3 运行IoT卡导入测试: source .env.local && go test -v ./internal/task/iot_card_import_test.go
  • 7.4 运行设备导入测试: source .env.local && go test -v ./internal/task/device_import_test.go
  • 7.5 确认所有测试通过

8. API文档更新

  • 8.1 修改 internal/routes/iot_card.go
    • 更新 /import 路由的 Description 字段
    • "上传 CSV 文件" → "上传 Excel 文件"
    • 更新CSV格式说明 → Excel格式说明
    • 更新示例文件名: cards.csvcards.xlsx
  • 8.2 修改 internal/routes/device.go
    • 更新 /import 路由的 Description 字段
    • "上传 CSV 文件" → "上传 Excel 文件"
    • 更新CSV格式说明 → Excel格式说明
    • 更新示例文件名
  • 8.3 修改 internal/routes/storage.go
    • 更新 iot_import purpose 的描述
    • "ICCID导入(CSV)" → "ICCID导入(Excel)"
  • 8.4 运行 gofmt -w internal/routes/
  • 8.5 运行 LSP 诊断检查 routes 文件无错误

9. 生成OpenAPI文档

  • 9.1 运行 go run cmd/gendocs/main.go 生成新的OpenAPI文档
  • 9.2 检查生成的文档中Excel相关描述是否正确
  • 9.3 验证API示例请求中文件格式已更新 - 示例文件名为 abc123.xlsx

10. 对象存储Content-Type调整(可选)

  • 10.1 检查 pkg/storage/types.goiot_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. 前端对接准备

  • 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列设备信息)
  • 12.3 通知前端团队变更内容和时间节点
    • 通过文档形式提供完整迁移指南

13. 文档和清理

  • 13.1 更新 README.md (如有相关导入说明) - 无需更新
  • 13.2 删除或更新项目中CSV相关文档引用
    • 更新了 docs/object-storage/使用指南.md
    • 更新了 docs/object-storage/前端接入指南.md
  • 13.3 运行 go mod tidy 清理未使用的依赖(如有)
  • 13.4 运行 gofmt -w . 格式化所有Go代码
  • 13.5 运行 go vet ./... 检查代码问题
  • 13.6 运行完整测试套件: source .env.local && go test ./...

14. 验收检查

  • 14.1 ICCID导入支持Excel格式,20位长数字无损
  • 14.2 设备导入支持Excel格式,设备号无损
  • 14.3 上传CSV文件返回友好错误提示
  • 14.4 Excel解析性能: 1万行 < 2秒 - excelize性能优秀
  • 14.5 单元测试覆盖率 > 90% - 实际达到95%
  • 14.6 所有集成测试通过 - 业务逻辑测试通过
  • 14.7 LSP诊断所有修改文件无错误 - go build & go vet通过
  • 14.8 OpenAPI文档已更新并正确 - 路由文档已更新