# USPS 自动集包开发检查清单 ## 开发前准备 - [ ] 已阅读 USPS自动集包需求文档.md - [ ] 已阅读 spec.md 接口规范 - [ ] 已阅读 tasks.md 任务分解 - [ ] 已确认数据库表结构(label_replace_requests, bag_tag_waybills) - [ ] 已确认 USPS 运单号识别规则 --- ## 阶段一:模型定义 ### 任务 1.1:创建任务状态模型 **文件**:`src/MDL/Models/AutoPackTaskStatus.cs` - [ ] 创建 `AutoPackTaskStatus` 类 - [ ] TaskId (string) - [ ] TagNumber (string) - [ ] Status (string) - [ ] TotalCount (int) - [ ] ProcessedCount (int) - [ ] SuccessCount (int) - [ ] FailedCount (int) - [ ] CurrentWaybill (string) - [ ] StartTime (DateTime) - [ ] EndTime (DateTime?) - [ ] FailedItems (List) - [ ] CancellationTokenSource (CancellationTokenSource) - [ ] 创建 `AutoPackFailedItem` 类 - [ ] WaybillNumber (string) - [ ] ErrorCode (int) - [ ] ErrorMessage (string) - [ ] 添加必要的 using 语句 - [ ] 编译通过 ### 任务 1.2:创建请求/响应 DTO **文件**:`src/MDL/Models/AutoPackRequest.cs` - [ ] 创建 `StartAutoPackRequest` 类 - [ ] TagNumber (string) - [ ] Creator (string, 默认 "system") - [ ] 创建 `StartAutoPackResponse` 类 - [ ] TaskId (string) - [ ] TagNumber (string) - [ ] Status (string) - [ ] TotalCount (int) - [ ] Message (string) - [ ] 创建 `AutoPackProgressResponse` 类 - [ ] TaskId (string) - [ ] TagNumber (string) - [ ] Status (string) - [ ] TotalCount (int) - [ ] ProcessedCount (int) - [ ] SuccessCount (int) - [ ] FailedCount (int) - [ ] CurrentWaybill (string) - [ ] Progress (int) - [ ] Message (string) - [ ] StartTime (DateTime) - [ ] EstimatedEndTime (DateTime?) - [ ] FailedItems (List) - [ ] 创建 `AutoPackResultResponse` 类 - [ ] TaskId (string) - [ ] TagNumber (string) - [ ] Status (string) - [ ] TotalCount (int) - [ ] SuccessCount (int) - [ ] FailedCount (int) - [ ] StartTime (DateTime) - [ ] EndTime (DateTime?) - [ ] Duration (int) - [ ] FailedItems (List) - [ ] 编译通过 --- ## 阶段二:数据访问层 ### 任务 2.1:扩展 Repository 接口 **文件**:`src/DAL/Interfaces/IBagTagRepository.cs` - [ ] 添加 `GetEligibleUspsWaybillsAsync(DateTime cutoffTime)` 方法声明 - [ ] 添加 `GetEligibleUspsWaybillCountAsync(DateTime cutoffTime)` 方法声明 - [ ] 添加 XML 注释 - [ ] 编译通过 ### 任务 2.2:实现 Repository 方法 **文件**:`src/DAL/Repositories/BagTagRepository.cs` - [ ] 实现 `GetEligibleUspsWaybillsAsync` 方法 - [ ] 使用 SqlSugar 执行 SQL 查询 - [ ] 查询条件:ReplaceStatus = 'Y' - [ ] 查询条件:CreatedAt >= cutoffTime - [ ] 查询条件:FinalMileTrackingNumber IS NOT NULL AND != '' - [ ] 查询条件:未关联到 bag_tag_waybills(LEFT JOIN + IS NULL) - [ ] 查询条件:USPS 格式(REGEXP '^(92|93|94|95)') - [ ] 查询条件:USPS 格式(REGEXP '^420[0-9]{5}(92|93|94|95)') - [ ] 查询条件:USPS 格式(REGEXP '^420[0-9]{9}(92|93|94|95)') - [ ] ORDER BY CreatedAt ASC - [ ] 返回 List - [ ] 实现 `GetEligibleUspsWaybillCountAsync` 方法 - [ ] 使用 COUNT(*) 查询 - [ ] 相同的 WHERE 条件 - [ ] 返回 int - [ ] 添加异常处理 - [ ] 编译通过 --- ## 阶段三:业务逻辑层 ### 任务 3.1:扩展 Service 接口 **文件**:`src/BLL/Interfaces/IBagTagService.cs` - [ ] 添加 `StartAutoPackAsync(string tagNumber, string creator)` 方法声明 - [ ] 添加 `GetAutoPackProgressAsync(string taskId)` 方法声明 - [ ] 添加 `CancelAutoPackAsync(string taskId)` 方法声明 - [ ] 添加 `GetAutoPackResultAsync(string taskId)` 方法声明 - [ ] 添加 XML 注释 - [ ] 编译通过 ### 任务 3.2:实现任务启动逻辑 **文件**:`src/BLL/Services/BagTagService.cs` - [ ] 注入 ICacheService(如未注入) - [ ] 实现 `StartAutoPackAsync` 方法 - [ ] 验证袋牌存在(GetByTagNumberAsync) - [ ] 验证袋牌状态为 "Opened" - [ ] 计算 cutoffTime(DateTime.UtcNow.AddHours(-84)) - [ ] 调用 GetEligibleUspsWaybillsAsync 获取包裹列表 - [ ] 检查包裹数量 > 0 - [ ] 生成唯一 TaskId(格式:task_{timestamp}_{guid}) - [ ] 创建 AutoPackTaskStatus 对象 - [ ] 存入缓存(key: "autopack:{taskId}", 过期时间 60 分钟) - [ ] 启动后台任务(Task.Run) - [ ] 返回 StartAutoPackResponse - [ ] 添加异常处理 - [ ] 编译通过 ### 任务 3.3:实现自动集包执行逻辑 **文件**:`src/BLL/Services/BagTagService.cs` - [ ] 创建 `ExecuteAutoPackAsync` 私有方法 - [ ] 参数:taskId, tagNumber, waybills, creator - [ ] 创建 Random 对象 - [ ] 遍历 waybills - [ ] 从缓存获取任务状态 - [ ] 检查 CancellationTokenSource.IsCancellationRequested - [ ] 更新 CurrentWaybill - [ ] 调用 AssociateWaybillAsync 进行关联 - [ ] 更新 SuccessCount 或 FailedCount - [ ] 记录失败信息到 FailedItems - [ ] 更新 ProcessedCount - [ ] 保存任务状态到缓存 - [ ] 随机延迟 2-4 秒(最后一个不延迟) - [ ] 任务完成处理 - [ ] 设置 Status(completed/cancelled) - [ ] 设置 EndTime - [ ] 清空 CurrentWaybill - [ ] 保存最终状态到缓存 - [ ] 实现 `GetAutoPackProgressAsync` 方法 - [ ] 从缓存获取任务状态 - [ ] 计算 Progress 百分比 - [ ] 计算 EstimatedEndTime - [ ] 映射到 AutoPackProgressResponse - [ ] 返回响应 - [ ] 实现 `CancelAutoPackAsync` 方法 - [ ] 从缓存获取任务状态 - [ ] 检查任务是否存在且状态为 processing - [ ] 调用 CancellationTokenSource.Cancel() - [ ] 更新状态为 cancelled - [ ] 保存到缓存 - [ ] 返回 bool - [ ] 实现 `GetAutoPackResultAsync` 方法 - [ ] 从缓存获取任务状态 - [ ] 映射到 AutoPackResultResponse - [ ] 计算 Duration - [ ] 返回响应 - [ ] 添加异常处理 - [ ] 编译通过 --- ## 阶段四:接口层 ### 任务 4.1:实现控制器方法 **文件**:`src/CONTROLLER/Controllers/BagTagController.cs` - [ ] 添加 `StartAutoPack` 方法 - [ ] HTTP POST 路由:"auto-pack/start" - [ ] 参数:[FromBody] StartAutoPackRequest - [ ] 调用 _bagTagService.StartAutoPackAsync - [ ] 返回统一响应格式 { code, message, data } - [ ] 异常处理 - [ ] 添加 `GetAutoPackProgress` 方法 - [ ] HTTP GET 路由:"auto-pack/progress/{taskId}" - [ ] 参数:string taskId - [ ] 调用 _bagTagService.GetAutoPackProgressAsync - [ ] 处理任务不存在的情况 - [ ] 返回统一响应格式 - [ ] 异常处理 - [ ] 添加 `CancelAutoPack` 方法 - [ ] HTTP POST 路由:"auto-pack/cancel/{taskId}" - [ ] 参数:string taskId - [ ] 调用 _bagTagService.CancelAutoPackAsync - [ ] 处理取消失败的情况 - [ ] 返回统一响应格式 - [ ] 异常处理 - [ ] 添加 `GetAutoPackResult` 方法 - [ ] HTTP GET 路由:"auto-pack/result/{taskId}" - [ ] 参数:string taskId - [ ] 调用 _bagTagService.GetAutoPackResultAsync - [ ] 处理任务不存在的情况 - [ ] 返回统一响应格式 - [ ] 异常处理 - [ ] 编译通过 ### 任务 4.2:注册依赖注入 **文件**:`src/CONTROLLER/Program.cs` - [ ] 检查 ICacheService 是否已注册 - [ ] 检查 IBagTagService 是否已注册 - [ ] 确认无需额外注册 --- ## 阶段五:测试与优化 ### 任务 5.1:编写单元测试 - [ ] 测试启动任务 - 袋牌不存在 - [ ] 测试启动任务 - 袋牌未打开 - [ ] 测试启动任务 - 无符合条件的包裹 - [ ] 测试启动任务 - 成功启动 - [ ] 测试查询进度 - 任务不存在 - [ ] 测试查询进度 - 正常查询 - [ ] 测试取消任务 - 任务不存在 - [ ] 测试取消任务 - 任务已完成 - [ ] 测试取消任务 - 正常取消 - [ ] 测试自动集包执行 - 全部成功 - [ ] 测试自动集包执行 - 部分失败 - [ ] 测试自动集包执行 - 取消操作 - [ ] 所有测试通过 ### 任务 5.2:性能优化与联调 - [ ] SQL 查询性能优化 - [ ] 检查 label_replace_requests 表索引(CreatedAt, ReplaceStatus, FinalMileTrackingNumber) - [ ] 检查 bag_tag_waybills 表索引(FinalMileTrackingNumber) - [ ] 缓存配置优化 - [ ] 确认缓存过期时间合理(60分钟) - [ ] 并发控制 - [ ] 确认同时只能有一个自动集包任务在运行(可选) - [ ] 异常处理完善 - [ ] 数据库连接异常 - [ ] 缓存访问异常 - [ ] 关联操作异常 - [ ] WinForm 联调 - [ ] 前端能正常调用启动接口 - [ ] 前端能正常轮询进度 - [ ] 进度条实时更新 - [ ] 取消功能正常 - [ ] 大数据量测试(100+ 包裹) --- ## 代码审查清单 ### 代码规范 - [ ] 命名规范符合项目标准 - [ ] 方法添加 XML 注释 - [ ] 复杂逻辑添加行内注释 - [ ] 无死代码 - [ ] 无 Console.WriteLine(使用 ILogger) ### 异常处理 - [ ] 所有异步方法有 try-catch - [ ] 异常信息不暴露敏感信息 - [ ] 异常正确记录日志 ### 性能 - [ ] 数据库查询使用参数化 SQL - [ ] 避免 N+1 查询问题 - [ ] 缓存使用合理 ### 安全 - [ ] 输入参数验证 - [ ] 防止 SQL 注入 - [ ] 权限检查(如需要) --- ## 部署检查清单 - [ ] 代码编译通过 - [ ] 单元测试全部通过 - [ ] 数据库迁移脚本(如需要) - [ ] 配置文件更新(如需要) - [ ] API 文档更新 - [ ] 部署到测试环境 - [ ] 测试环境验证通过 - [ ] 部署到生产环境 - [ ] 生产环境验证通过 --- ## 文档检查清单 - [ ] spec.md 已更新(如有变更) - [ ] tasks.md 已更新(如有变更) - [ ] 接口文档已更新 - [ ] 前端联调文档已提供 --- ## 验收标准 ### 功能验收 - [ ] 创建 USPS 袋牌后能自动触发集包(或手动触发接口) - [ ] 正确筛选符合条件的 USPS 包裹(84小时内、未集包、已换单) - [ ] 逐个关联包裹,间隔 2-4 秒 - [ ] 实时反馈进度(总数、已处理数、成功数、失败数) - [ ] 支持取消操作 - [ ] 记录操作日志 ### 性能验收 - [ ] 100 个包裹处理时间 < 10 分钟 - [ ] 前端轮询响应时间 < 100ms - [ ] 内存占用稳定,无内存泄漏 ### 兼容性验收 - [ ] WinForm 前端正常调用 - [ ] 接口响应格式符合规范 - [ ] 错误码定义清晰