# 71 实现采购任务演练执行与结果回传 - 类型:需求 - 父级大工单:#1 - 所属 MVP / 版本:#2 Client 可运行任务闭环(MVP) - 状态:已完成,待用户验收 - 日期:2026-08-09 - Gitea 工单:http://ilaer.eicp.net:8418/chengma/cmautobuy/issues/71 ## 背景与目标 Client 已认识采购任务数据,但没有独立采购执行器。直接开放领取会让任务卡在 已领取状态,也可能把尚未验证的页面操作带入真实订单流程。本任务先建立只处理 本地任务的 `dry_run` 演练服务,在最终提交订单前停止并可靠回传结果。 ## 最终方案 - 新增独立 `PurchaseTaskService`,不复用采集执行器,也不领取 Admin 任务。 - 新增可注入的 `PddPurchaseAdapter` 窄接口。接口没有提交订单或付款方法。 - 动态规格使用完整 `options` 对象精确选择和比较,不写死颜色、尺码维度。 - 进入打开商品、选择规格、设置数量和确认页等关键动作前先持久化步骤;动作前后 重新读取商品、规格、数量和人民币分价格。 - 多候选、无匹配、价格超限、验证码、登录失效、未知页面、风控页和支付页均停止。 - 演练结果明确记录 `mode=dry_run`、确认规格、数量、价格、未提交订单和未付款。 - 结果或失败与执行记录、Outbox 在 SQLite 事务内一起保存。提交失败只补交 Outbox, 不重新执行手机流程。 - HTTP Gateway 保持只声明 `collect`,采购领取留给依赖工单 #72。 ## 改了哪些文件 - `client/src/pdd_purchase_adapter.py`:采购演练适配层接口和最新页面状态对象。 - `client/src/purchase_task_service.py`:本地采购演练、校验、失败分类和结果提交。 - `client/src/task_repository.py`:采购运行、步骤、结果、失败及 Outbox 原子持久化。 - `client/src/task_models.py`:执行记录说明同时适用于采集和采购。 - `client/test/test_purchase_task_service.py`:正常演练和安全停止场景测试。 - `docs/client/02-architecture.md`:记录采购服务和无下单入口的适配边界。 - `docs/client/03-data-model.md`:采购结果改用动态 `options` 对象。 ## 验收结果 | 验收标准 | 结果 | |---|---| | 本地采购任务创建独立执行记录并进入演练 | 通过 | | 动态 options 精确选择,不写死颜色尺码 | 通过 | | 关键动作前后使用最新页面状态复核 | 通过 | | 价格超过人民币分上限时停止 | 通过 | | 多候选、无匹配、验证码、登录和未知页面安全停止 | 通过 | | 到达最终提交前停止,不提交订单或付款 | 通过 | | 结果先写 SQLite 与 Outbox,提交失败不重跑手机流程 | 通过 | | HTTP Client 仍只声明 collect | 通过 | ## 测试 - 执行的命令: - `C:/Python310/python.exe -m unittest discover -s test -p "test_purchase*.py" -v` - `C:/Python310/python.exe -m unittest discover -s test -p "test_*.py" -q` - `C:/Python310/python.exe -m py_compile src/task_models.py src/task_repository.py src/pdd_purchase_adapter.py src/purchase_task_service.py` - 设置 `QT_QPA_PLATFORM=offscreen` 后创建并关闭 `MainWindow` - 结果:采购专项 6 项通过;Client 全量 193 项通过;语法检查通过;离屏冒烟输出 `MAIN_WINDOW_OK`。 - **未验证到的部分**:未连接真实 Android 设备;本工单使用可注入 Mock Adapter 验证应用层和安全边界,没有点击真实提交订单或付款。 ## 相关提交 - `311d55f` 实现采购任务安全演练