7.4 KiB
7.4 KiB
id, title, phase, deps, status, created
| id | title | phase | deps | status | created | |
|---|---|---|---|---|---|---|
| T-628 | 采集当前记录阶段与单条耗时指示器 | 2 |
|
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生成、③更新蝦皮及⑥商品套图的计时显示。