## Context 批量订购包含文件上传、异步任务处理、任务恢复和逐行失败查看四个阶段。任务创建需要绑定一个代理商和一种支付方式,线下支付还需要上传整批凭证;任务处理过程中可能出现部分成功和钱包余额不足,前端必须展示后端结果而不能把整批操作当成原子事务。 ## Goals / Non-Goals - Goals: 提供批量订单 Excel 上传、支付方式选择、任务进度展示、任务恢复和逐行失败明细。 - Goals: 使用 `request_id` 防止重复提交,并按任务 ID 查询服务端真实状态。 - Goals: 复用公共异步任务的五态语义和终态规则。 - Non-Goals: 不在前端解析 Excel 业务行、不执行订单创建、不计算订单金额、不回滚已成功订单。 - Non-Goals: 不改造现有单笔订单创建和单笔支付凭证上传流程。 - Non-Goals: 不新增后端模板下载接口。 ## Decisions - Decision: 批量订购页面使用独立任务视图,订单列表只提供入口,不把逐行结果嵌入订单列表表格。 - Rationale: 批量任务有独立生命周期和大量逐行结果,独立页面更适合恢复、轮询和分页查看。 - Decision: `payment_method` 在创建表单中为单选值,并在请求中对整批固定;线下支付时才允许提交 `voucher_file`。 - Rationale: 产品明确一个批次不能混合支付方式,前端应避免生成含混请求。 - Decision: 使用前端静态 Excel 模板资源。 - Rationale: 产品明确模板下载不依赖后端动态生成,减少接口依赖。 - Decision: 使用 `request_id` 作为客户端幂等键,并在创建前生成一次、提交重试时复用同一值。 - Rationale: 防止网络重试或重复点击创建多个相同批次。 - Decision: 部分成功、钱包余额不足和逐行业务失败均由后端任务结果表达;前端只展示计数和失败明细,不自行推断或回滚。 - Rationale: 钱包扣款和订单事务边界属于后端职责,前端不能可靠重建。 ## Data Model - Create request: `shop_id`、`payment_method`、`file`、可选 `voucher_file`、`request_id`。 - Task identity: `task_id`、`task_no`。 - Task status: `1=待处理`、`2=处理中`、`3=已完成`、`4=已失败`、`5=已取消`;部分成功仍属于已完成终态。 - Task summary: status, total count, success count, failed count, amount summary, timestamps and safe error summary when returned. - Item result: row number, asset identifier, package code, row status and safe error reason. - Item query: task ID, page, size and optional row status filter. ## Risks / Trade-offs - Risk: 后端金额字段名称或单位未在产品文档中明确。 - Mitigation: API 类型和页面以接口实际返回字段为准,统一标注金额单位;实施前补齐字段契约,前端不自行计算汇总。 - Risk: 文件或凭证上传成功但任务创建请求失败,可能留下孤立对象。 - Mitigation: 创建失败时保留用户选择和错误提示;对象清理策略由后端存储生命周期或接口约定处理。 - Risk: 任务详情恢复时任务已过期、删除或用户失去权限。 - Mitigation: 按页面权限和接口错误处理展示对应状态,不重复创建原任务。 ## Migration Plan 1. 确认批量订购任务摘要、金额和逐行结果字段契约。 2. 新增 API、类型、权限和静态模板资源。 3. 实现批量订购入口、文件上传、线下凭证上传和幂等提交。 4. 实现任务详情、公共状态展示、轮询和 `task_id` 恢复。 5. 实现逐行结果分页、状态筛选和失败明细展示。 6. 验证钱包余额不足、部分成功、重复提交、刷新恢复和权限组合。 ## Open Questions - 批量订购任务摘要中的金额字段名称、金额单位和金额分类需要以后端接口文档确认。 - 失败明细中的资产字段是统一 `asset_identifier`,还是按资产类型返回 `iccid` / `virtual_no`,需要以后端确认。 - `voucher_file` 是单文件、文件数组还是已上传对象存储 key,需要与 multipart 接口契约确认。 - 批量订购入口的最终路由、菜单名称和权限编码需要产品/后端确认。