diff --git a/docs/tasks/T-659.md b/docs/tasks/T-659.md new file mode 100644 index 0000000..49abb68 --- /dev/null +++ b/docs/tasks/T-659.md @@ -0,0 +1,83 @@ +--- +id: T-659 +title: 更新蝦皮批次内容预检改为剔除跳过不中止整批 +status: TODO +phase: 7 +deps: [] +created: 2026-07-17 +--- + +# T-659 更新蝦皮批次内容预检改为剔除跳过不中止整批 + +## 问题 / 背景 + +③「更新蝦皮」选定批次点「开始更新」时,若批次内有个别记录的新标题或新封面生成失败(内容为空),当前会弹窗「更新内容未生成」并中止**整批**更新——1~2 条失败记录拦下其余全部合格记录。 + +代码链路(`app/gui/tabs/apply.py`): + +1. `_start_update()`(:243)按当前筛选收集候选任务:`_is_update_candidate_task()`(:390)只看 `stage == "generated"` 且 `status ∈ {success, pending, failed}`,**生成失败的记录也在候选内**; +2. `_update_content_error()`(:584)按更新模式检查候选:模式含标题要求 `new_title` 非空、含封面要求 `new_cover_path` 非空,**任何一条缺失**即返回完整错误文案; +3. :256-260 预检非空 → `QMessageBox.warning("更新内容未生成", ...)` → `return`,一条都不执行。 + +该预检的原始意图是拦「更新模式选错」的整体性错误(如批次只生成了标题、用户却选了标题+封面),但没有区分「全部缺失(模式错)」与「个别缺失(个别生成失败)」。执行层 `ApplyWorker` 本身支持逐条跳过(汇总格式含「略过{skipped}」,:697),预检比执行器更严格,属于门槛过度。 + +## 需求定稿 + +预检从「一票中止」改为「剔除 + 知情确认」: + +1. 缺少本轮所需内容(按更新模式判定新标题/新封面)的记录,从本轮任务中**剔除**,不进 `ApplyWorker`; +2. 确认弹窗(保留,符合 ③ 开始更新前弹窗确认的红线)中新增跳过说明:缺标题/缺封面的条数与示例商品ID,让用户知情后再确认; +3. 仅当**剔除后无任务可执行**(整批缺失,大概率模式选错)时,保留现有「更新内容未生成」警告中止,并沿用回②生成或调整更新内容的引导文案; +4. 被剔除记录的库内状态、stage、Excel 回写均不变——它们不算本轮失败也不算略过,修复(②补生成)后下轮自然重新入选。 + +## 实现方案 + +- `_update_content_error()` 重构为返回结构化结果(如「可执行任务列表 + 缺标题列表 + 缺封面列表」),或新增并列函数;不再以「有缺失」为中止条件。 +- `_start_update()`: + - 剔除后可执行任务 > 0:把跳过统计并入 `_confirmation_message()`(新增行如「跳过 N 条缺少新标题(示例商品ID:…)」),確認后仅以可执行任务创建 `ApplyWorker`; + - 剔除后为 0:维持现「更新内容未生成」`QMessageBox.warning` 中止,文案不变; +- 「检查本轮更新」(dry_run)与正式更新走同一套剔除逻辑,两者展示一致的跳过说明。 +- 状态栏摘要同步:本轮开始时记录「本轮 N 条,跳过 M 条(缺标题 x / 缺封面 y)」。 +- 不修改 `ApplyWorker`、CDP 流程、批次/店铺筛选、Excel 回写和 `_is_update_candidate_task()` 的候选口径(failed 状态保留在候选中是为了重试上轮更新失败的记录,与本问题无关)。 + +## 验收标准 + +- [ ] 批次内 1~2 条缺新标题/新封面时,点「开始更新」不再中止:确认弹窗列出跳过条数与示例商品ID,确认后其余记录正常执行。 +- [ ] 跳过的记录不进入本轮执行,也不被计为本轮失败或略过;其库内状态与 Excel 不受本轮影响。 +- [ ] 整批全部缺失所需内容时,仍弹「更新内容未生成」警告并中止,引导文案与现版一致。 +- [ ] 「检查本轮更新」(dry_run)与正式更新的剔除与提示行为一致。 +- [ ] 更新模式为「只更新标题」时只按新标题剔除;「只更新封面」只按新封面剔除;「标题和封面」按两者分别统计并都剔除。 +- [ ] 确认弹窗仍在执行前出现(③ 红线不变);取消则不执行任何任务。 +- [ ] 被跳过记录在②补生成后,下轮筛选自动重新入选并可正常更新。 +- [ ] CDP 执行、批次筛选、店铺筛选、停止/重置更新、Excel 回写行为不变。 + +## 测试要求 + +- `tests/test_gui.py`(既有「更新内容未生成」用例所在文件)覆盖:部分缺标题、部分缺封面、两者混合、全部缺失中止、剔除后确认文案内容、dry_run 一致性、三种更新模式的剔除口径。 +- 断言跳过记录未进入 worker 任务列表、状态与 stage 未被改动。 +- 回归:无缺失时确认文案与现版一致(不出现跳过行)。 + +## 文档同步 + +- 实现时更新 `docs/04-architecture.md` 中 ③ 更新前置校验的描述(如有);不修改冻结的 `docs/06-tasks.md`。 + +## 验证 + +```bash +py -3.10 -m unittest tests.test_gui +py -3.10 -m unittest discover -s tests +py -3.10 -m ruff check app tests main.py +py -3.10 -m compileall app main.py +git diff --check +``` + +## 非目标 + +- 不修改 ②AI生成的失败重试机制,不在③内触发补生成。 +- 不修改 `ApplyWorker` 执行语义、并发、批次大小与账号就绪检查。 +- 不改动「账号未就绪」中止逻辑(那是另一类整体性前置条件)。 +- 不引入按记录勾选/排除的手动选择 UI。 + +## 执行记录 + +- 待实现。