Files
cmshoppe/docs/tasks/T-628.md
T

7.4 KiB
Raw Blame History

id, title, phase, deps, status, created
id title phase deps status created
T-628 采集当前记录阶段与单条耗时指示器 2
T-620
TODO 2026-07-14

问题 / 背景

①「导入采集」处理商品详情页时,打开页面、等待加载和下载封面都可能持续较长时间。当前页面只有静态的「批次进度」汇总、底部状态栏和运行日志,用户在一条记录长时间未结束时难以判断采集是否仍在执行。

已核实的现状:

  • collectBatchProgressOverview 是根据 SQLite 任务快照生成的汇总 label,refresh_tasks() 时会整体重写文本,本身没有运行计时语义。
  • CollectWorker.progress 主要在一条记录结束后发出,不能反映当前记录正在执行哪个步骤。
  • row_updated(status=running) 在单条记录登录状态检查之后才发出;若以它作为计时起点,会漏掉前置检查和本条登录检查耗时。
  • editor.collect() 已有 open_product / wait_ready / read_title / read_cover / download_cover 等步骤回调,可作为结构化阶段来源。

顾客希望在「批次进度」同行右侧增加动态计时,并在每条记录开始时重置,让用户能看到当前采集任务仍处于运行状态。

计时数字持续变化只能证明 GUI 计时器仍在运行,不能证明 CDP 一定在继续推进。因此本任务把需求优化为「当前阶段 + 当前记录耗时」指示器:阶段显示最后一次已知进展,秒数显示该记录已经等待多久,不向用户承诺任务一定健康。

方案

1. 批次进度同行增加独立运行指示器

  • 在现有「批次进度」右侧增加独立 label,不把计时字符串拼入 batch_progress_label,避免 refresh_tasks() 重写批次汇总时覆盖计时内容。
  • 两个 label 放入同一水平布局:批次汇总占可伸缩区域,运行指示器靠右并按最长合理文案预留稳定宽度,秒数变化不得造成布局抖动。
  • 运行中推荐文案:正在采集 3/20 · 等待商品页加载 · 本条 00:18。
  • 窗口空间不足时,允许批次汇总自然换行;运行状态、序号和时间必须保持可见,完整商品 ID / 账号可放在中文 tooltip 中,不在紧凑 label 内强行堆叠。
  • 不使用纯装饰性转圈或闪烁动画;每秒变化的计时和明确的「正在采集」文字即为运行反馈。

2. 使用结构化 Worker 活动信号

  • 为 CollectWorker 增加专用结构化活动信号,例如 activity: Signal(dict);不得通过解析用户日志文本推断当前任务或步骤。
  • 活动 payload 至少支持:
    • preflight_started:开始检查账号和 Chrome;
    • task_started:一条 eligible 记录开始处理;
    • task_step:当前记录进入新步骤;
    • task_finished:当前记录成功、失败或略过。
  • payload 使用稳定字段,如 state / index / total / task_id / item_id / alias / step / result,不得把账号密码、Cookie、token 或未脱敏异常放入信号。
  • task_started 应在进入每条记录处理循环后尽早发出,覆盖本条账号匹配、登录检查和后续采集耗时;不得等到 db.mark_running() 后才开始计时。
  • editor.collect() 的步骤回调继续用于日志,同时把步骤作为结构化 task_step 发给 GUI。阶段映射集中维护并全部显示中文,至少覆盖:检查账号、打开商品页、等待商品页加载、读取标题、读取封面、下载封面、保存采集结果。
  • 结构化活动信号只增加可观察性,不改变原有 progress / row_updated / log / failed / finished / cancelled 的业务语义。
  • 本轮正常完成、停止和前置阻断继续以现有 finished / cancelled 信号及 summary 中的 blocked 字段为唯一终态来源,不在 activity 中复制一套终态协议。

3. 计时口径与生命周期

  • GUI 使用父对象为 CollectTab 的 QTimer,每 1000ms 刷新一次;真实耗时通过 time.monotonic() 计算,不通过简单 seconds += 1 累加。
  • 点击「采集旧标题/旧封面」并成功创建 Worker 后,记录批次开始时间,显示 正在检查账号 · 00:00。
  • 收到 task_started 时重置当前记录起点并开始显示 本条 00:00;收到 task_step 只更新阶段文字,不重置本条计时。
  • 下一条记录开始时重新从 00:00 计时;成功、失败或略过可短暂冻结本条耗时,随后由下一条 task_started 覆盖。
  • 用户点击「停止」后,指示器立即改为 正在停止 · 本条 00:18,在当前不可中断步骤退出前继续显示等待时间;收到 cancelled 后再冻结为终态,不能提前伪装成已经停止。
  • 正常完成、前置检查阻断、用户停止、Worker 异常及线程释放路径都必须停止 QTimer、清理当前任务引用并冻结最终文字,不能在采集结束后继续走秒。
  • 本轮终态文案应区分:
    • 正常完成:采集完成 · 总用时 08:32;
    • 用户停止:采集已停止 · 总用时 03:10;
    • 前置阻断:采集未开始 · 检查未通过;
    • 异常结束:采集已结束 · 请查看运行日志。
  • 计时只用于本次 GUI 显示,不写入 SQLite 或 Excel;现有逐条诊断日志中的 elapsed_ms 保持不变。

4. 状态语义与视觉边界

  • 运行中使用现有信息色/进行中色,并保留「正在采集」文字,不能只靠颜色表达状态。
  • 完成、停止、阻断和异常沿用项目既有状态语义色;不增加“卡死”自动判定。页面加载和图片下载可能合法地持续较久,仅凭固定秒数变色会产生误报。
  • 用户看到持续增加的本条耗时,应理解为“该记录尚未结束”;阶段长时间不变化时可据此决定查看日志或停止,但 UI 不显示“运行正常”等未经验证的结论。

验收要点

  • 有批次任务但未运行时,批次汇总显示正常,右侧运行指示器不误报正在采集。
  • 点击采集后,在首条记录开始前显示中文前置检查状态和持续计时;GUI 保持可响应。
  • 第一条记录开始时显示 1/N 并从 00:00 计时;步骤变化时阶段文字变化、本条计时不重置。
  • 第二条记录开始时显示 2/N,本条时间重新从 00:00 开始。
  • 成功、失败和略过记录都能进入正确的下一条计时;不会因为某条失败而停止整轮指示器。
  • 正常完成、前置阻断、用户停止、Worker 异常和线程收尾后计时全部停止,等待数秒后界面秒数不再变化。
  • 批次进度汇总刷新不会覆盖运行指示器;运行指示器更新也不会改变批次阶段统计。
  • 运行状态 label 宽度稳定,在最小支持窗口及 Windows 100% / 125% / 150% 显示缩放下无重叠和明显布局跳动。
  • 单测使用可控 time.monotonic() 或注入时间验证,不通过真实 sleep() 拉长测试。
  • 自动验证:py -3.10 -m unittest discover -s tests、python -m ruff check app tests main.py、py -3.10 -m compileall app main.py、git diff --check 全绿。

边界(不改什么)

  • 不修改 CDP 选择器、商品页打开/关闭策略、Chrome 前后台切换、登录判定或采集重试策略。
  • 不修改任务 stage/status、SQLite schema、Excel schema、回写流程或批次统计口径。
  • 不把计时器放进 Worker 线程,不让 GUI 每秒查询 SQLite,也不把每秒 tick 写入运行日志。
  • 不改变②AI生成、③更新蝦皮及⑥商品套图的计时显示。