ISSUE-0075:状态列「待采集」与 HTTP 列「✓已采」视觉矛盾¶
现象¶
用户截图(v0.10.112)官网列表去重视图,多行显示:
| 状态 | HTTP | 网址 |
|---|---|---|
| 待采集 | ✓ 已采 (tooltip: pool-hit emails=0 phones=27) | https://bbahc.org/Aleknagik |
| 待采集 | ✓ 已采 | https://www.genevawoodsbird... |
| 待采集 | ✓ 已采 | https://www.unitedpt.com/ |
用户问"为什么后边是已采,前边还是待采?" — 视觉矛盾。
根因:两列看不同维度¶
| 列 | 数据源 | 维度 |
|---|---|---|
| 状态 | row.scrape_status 字段 |
当前 row(MapTaskData 单行) |
| HTTP | websiteLogMap.get(row.website) |
URL 维度(任意 row 的 page-log) |
场景:连锁店共享同 URL(westernunion / bbahc 等):
- 第 1 个商家 row 命中该 URL → engine 处理 → 写 emails + scrape_status=2 + page-log mstage:success
- 第 2 个商家 row 也指向该 URL,仍在 queue 没轮到 → scrape_status=0
- 官网去重视图按 URL group 取第一行作为代表,碰巧拿到了 status=0 那行
- UI 显示:状态列看 row 自己 = 待采集;HTTP 列看 URL 历史 = ✓已采
代码里的「查重复用」(scraper-executor.ts:152-178)能避免重复抓,但只在 engine pick 到该 row 时才执行 —— 排队中的行 UI 仍是 status=0。
修复(v0.10.114)¶
A:engine 启动时批量复用(治本)¶
新函数 batchDedupeByUrl() 在 engine-manager.ts:
- 拉所有
status=2行 → 建url → source row索引(emails非空优先) - 拉所有
status=0行 → 按 source row 分组 - 对每组
updateByQuery(id IN [...], { emails, socials, scrape_status:2, sync:0 })
调用时机:
- 每个 SW session 跑一次(dedupeRanThisSession 模块标记)
- 用户「立即触发」时 markDedupeNeedsRerun() 重置标记,下次 manageQueue 再跑
收益: - 视觉矛盾消除(同 URL 多行一起变 status=2) - 节省 worker — 不再重复跑相同 URL(你的 335 商家、238 URL 意味着 ~100 行直接秒标)
B:官网去重视图代表行优先 status=2(兜底)¶
data-view.tsx 官网 useMemo:
const score = (r) => (emails?.length>0 ? 2 : 0) + (scrape_status===2 ? 1 : 0);
const byUrl = new Map();
for (const r of rows) {
const k = r.website.toLowerCase();
if (!byUrl.has(k) || score(r) > score(byUrl.get(k))) byUrl.set(k, r);
}
即便 A 还没跑完,UI 也会优先展示已采过的 row 作代表,状态列直接显示「已完成」。
设计教训¶
- UI 列必须维度一致 — row 字段 + URL 维度信息混在一行,必然出现矛盾
- engine pick 节奏不等于数据可见节奏 — 处理完毕的成果应该立即扩散到同维度的其他行
- 类似坑:分组时取"第一个"作代表是隐性 bug — 应该按"代表性 score"选
验证¶
- 装 v0.10.114 后第一次开 engine:
- sysLog 会出现
pipeline batch-dedupe-applied { urls: N, rows: M } - 官网去重视图所有同 URL 行立即变 "已完成"
- 点「立即触发」:再跑一次,覆盖刚新建任务的同 URL 行