2026-07-08 11:00:29 +08:00
|
|
|
|
---
|
|
|
|
|
|
id: T-552
|
|
|
|
|
|
title: 任务失败原因带上失败步骤(①②③ 阶段/状态列可见)
|
|
|
|
|
|
phase: 7
|
|
|
|
|
|
deps: [T-207, T-523]
|
2026-07-08 11:08:01 +08:00
|
|
|
|
status: DONE
|
2026-07-08 11:00:29 +08:00
|
|
|
|
created: 2026-07-08
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 问题 / 背景
|
|
|
|
|
|
|
|
|
|
|
|
①导入采集(及②③)列表里任务失败时,阶段/状态列只显示「失败」,操作员**看不出卡在哪一步**(打开商品页 / 页面就绪 / 读标题 / 读封面 / 下载封面 / 写库 / 回写Excel)。
|
|
|
|
|
|
|
|
|
|
|
|
- 失败**步骤信息其实已被采集**:T-207 把 `step=preflight/open_product/wait_ready/read_title/read_cover/download_cover/db_write/excel_write_back` 记进了 `run_log_events`。
|
|
|
|
|
|
- 但 `db.mark_failed(task_id, phase, error)` 里 `phase` 只是粗粒度(collect/generate/apply),`error` 只是原始消息;`tasks.last_error` 不含步骤。
|
|
|
|
|
|
- ① 阶段列的 tooltip 已经在显示 `last_error`,但只有消息、没有步骤 → 要知道哪步得去翻「采集运行日志」逐条对,摩擦大。
|
|
|
|
|
|
|
|
|
|
|
|
这是"数据有、但没暴露在失败发生处"的可见性问题,不是要重新采集数据。
|
|
|
|
|
|
|
|
|
|
|
|
## 方案(P0:prepend 步骤到 last_error,最小改动)
|
|
|
|
|
|
|
|
|
|
|
|
让失败的 `last_error` 带上**中文步骤**,例如「读封面失败:图片超过大小上限」「打开商品页失败:CDP 端口无响应」。
|
|
|
|
|
|
|
|
|
|
|
|
- **worker**(`app/gui/workers.py` 的 `CollectWorker`,及②③对应 worker):失败时 worker 已知当前 step(T-207 在逐任务追踪),把该 step 传给失败写库。
|
|
|
|
|
|
- **db**(`app/db.py` `mark_failed`):把中文步骤 **prepend 到 `last_error`**(不改 schema),存成 `「<步骤中文>失败:<原因>」`;step 已是中文/已知失败步骤时避免重复前缀。
|
|
|
|
|
|
- **step→中文映射**(放一处共用,如 worker 或 db helper):`preflight→预检 / open_product→打开商品页 / wait_ready→页面就绪 / read_title→读标题 / read_cover→读封面 / download_cover→下载封面 / db_write→写库 / excel_write_back→回写Excel`;未知 step 用原值兜底。
|
|
|
|
|
|
- **展示**:①②③ 的阶段/状态列 tooltip 已显示 `last_error`(含步骤后即自动可见);阶段列文案可选显示「失败·<步骤>」(能从 last_error 派生就派生,不额外加列)。
|
|
|
|
|
|
- 三个模块共用同一套 step→中文 + prepend 逻辑,一次覆盖①②③"失败看不出哪步"。
|
|
|
|
|
|
|
|
|
|
|
|
> 备注:更结构化的做法是新增 `tasks.last_error_step` 字段(便于阶段列内联显示/上色),但需 schema 迁移;本任务按 P0 走 prepend,`last_error_step` 作为后续可选增强,双击看完整步骤链(run_log_events 按 task_id 过滤)也作为后续 P1。
|
|
|
|
|
|
|
|
|
|
|
|
## 验收要点
|
|
|
|
|
|
|
|
|
|
|
|
- 采集/生成/更新任一步失败后,`tasks.last_error` 以「<中文步骤>失败:<原因>」开头。
|
|
|
|
|
|
- ①②③ 失败行悬停 tooltip 能看到"是哪一步失败 + 原因",无需翻运行日志。
|
|
|
|
|
|
- step→中文映射覆盖上述所有步骤,未知 step 不崩、用原值。
|
|
|
|
|
|
- 已带步骤前缀的 error 不重复加前缀。
|
|
|
|
|
|
- 单测:`tests/test_db.py` 断言 `mark_failed` 带 step 时 `last_error` 前缀正确、无 step 时保持原样;`tests/test_gui.py` 断言失败行 tooltip 含步骤文案(至少①覆盖,②③视改动补充)。
|
|
|
|
|
|
|
|
|
|
|
|
## 边界(不改什么)
|
|
|
|
|
|
|
|
|
|
|
|
只改 `mark_failed` 的 step 前缀 + worker 传 step + 模型 tooltip/阶段文案 + 单测;不改采集/生成/更新执行流程、`run_log_events` 结构(T-207 保留)、CDP/Shopee 交互、Excel、DB schema(P0 不加字段)。
|
|
|
|
|
|
|
|
|
|
|
|
## 执行记录
|
|
|
|
|
|
|
2026-07-08 11:08:01 +08:00
|
|
|
|
- 2026-07-08:完成 T-552。
|
|
|
|
|
|
- 代码:`app/db.py` 新增 `FAILURE_STEP_LABELS`、`failure_step_label()`、`format_failure_error()`;`mark_failed()` 与 `set_applied()` 增加可选 `step` 参数,带 step 时把 `last_error` 统一保存为「<中文步骤>失败:<原因>」,无 step 时保持旧行为,已带步骤前缀时不重复添加。
|
|
|
|
|
|
- 代码:①`CollectWorker` 采集失败时把当前 step 传给 `mark_failed`,并立即向 GUI 发出带步骤前缀的 `last_error`;②`app/ai.py` 的生成失败写库传入当前 title/cover step;③`ApplyWorker` 更新失败和异常失败传入当前 step 给 `set_applied`,默认归因为 `apply_task`,真实编辑器步骤仍由 `on_step` 覆盖。
|
|
|
|
|
|
- 展示:①②③ 表格模型原本 tooltip 已读取 `last_error`,因此失败行悬停可直接看到失败步骤与原因;未新增列、不改 DB schema、不改 run_log_events。
|
|
|
|
|
|
- 测试:`tests/test_db.py` 覆盖 `mark_failed` 带 step 前缀、未知 step 兜底、重复前缀不叠加、无 step 保持原样,以及 `set_applied` 更新失败 step 前缀;`tests/test_gui.py` 覆盖①②③失败行 tooltip 显示步骤与原因,并更新③ worker 失败原因断言。
|
|
|
|
|
|
- 验证:`py -3.10 -m unittest discover -s tests -p "test_db.py"` 通过(9 tests);`py -3.10 -m unittest discover -s tests -p "test_gui.py"` 通过(104 tests);`py -3.10 -m unittest discover -s tests -p "test_ai.py"` 通过(40 tests);`python -m ruff check app tests main.py` 通过;`python -m ruff check scripts\gen_task_board.py tests\test_task_board.py` 通过;`py -3.10 -m compileall app main.py` 通过;`py -3.10 -m py_compile scripts/gen_task_board.py` 通过;`git diff --check` 通过;`py -3.10 -m unittest discover -s tests` 通过(257 tests)。
|