|
@@ -1787,7 +1787,7 @@
|
|
|
bottom: 22px;
|
|
bottom: 22px;
|
|
|
width: 440px;
|
|
width: 440px;
|
|
|
max-height: 55vh;
|
|
max-height: 55vh;
|
|
|
- z-index: 60;
|
|
|
|
|
|
|
+ z-index: 130; /* 高于弹层(modal-bg 70/dialog 120),搜索进度日志始终可见 */
|
|
|
display: flex;
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
flex-direction: column;
|
|
|
border: 1px solid var(--line-dark);
|
|
border: 1px solid var(--line-dark);
|
|
@@ -3935,16 +3935,45 @@
|
|
|
if (!e.target.closest("#qr-pop") && !e.target.closest("td.qr-c.keep")) qrClosePop();
|
|
if (!e.target.closest("#qr-pop") && !e.target.closest("td.qr-c.keep")) qrClosePop();
|
|
|
});
|
|
});
|
|
|
// 搜全部达标:逐格起任务(朴素循环,失败不阻断)
|
|
// 搜全部达标:逐格起任务(朴素循环,失败不阻断)
|
|
|
|
|
+ // 批量进度面板:任务面板里列出每个搜索的实时状态(轮询各 task_id)
|
|
|
|
|
+ function showQrBatch(items) {
|
|
|
|
|
+ hasTask = true;
|
|
|
|
|
+ $("#task-panel").hidden = false;
|
|
|
|
|
+ $("#task-title").textContent = `搜全部达标 · ${items.length} 个`;
|
|
|
|
|
+ $("#task-dot").className = "dot";
|
|
|
|
|
+ clearTimeout(pollTimer);
|
|
|
|
|
+ const st = {};
|
|
|
|
|
+ const poll = async () => {
|
|
|
|
|
+ await Promise.all(items.map(async (it) => {
|
|
|
|
|
+ if (st[it.task_id] && st[it.task_id] !== "running") return;
|
|
|
|
|
+ try { const t = await api("/api/task_status?task_id=" + encodeURIComponent(it.task_id)); st[it.task_id] = t.status; }
|
|
|
|
|
+ catch (e) { st[it.task_id] = st[it.task_id] || "running"; }
|
|
|
|
|
+ }));
|
|
|
|
|
+ const done = items.filter((it) => st[it.task_id] && st[it.task_id] !== "running").length;
|
|
|
|
|
+ $("#task-title").textContent = `搜全部达标 · ${done}/${items.length} 完成`;
|
|
|
|
|
+ $("#task-log").textContent = items.map((it) => {
|
|
|
|
|
+ const s = st[it.task_id] || "running";
|
|
|
|
|
+ return `${s === "done" ? "✅" : s === "failed" ? "❌" : "⏳"} ${it.query_id} ${it.query}`;
|
|
|
|
|
+ }).join("\n");
|
|
|
|
|
+ if (done < items.length) pollTimer = setTimeout(poll, 2000);
|
|
|
|
|
+ else $("#task-dot").className = "dot done";
|
|
|
|
|
+ };
|
|
|
|
|
+ poll();
|
|
|
|
|
+ }
|
|
|
$("#qr-search-all").onclick = async () => {
|
|
$("#qr-search-all").onclick = async () => {
|
|
|
const keeps = Object.entries(qrState.scores || {}).filter(([, v]) => qrKeep(v));
|
|
const keeps = Object.entries(qrState.scores || {}).filter(([, v]) => qrKeep(v));
|
|
|
if (!keeps.length) return;
|
|
if (!keeps.length) return;
|
|
|
if (!confirm(`将对 ${keeps.length} 个达标 query 各起一次搜索(小红书+公众号 各20),确认?`)) return;
|
|
if (!confirm(`将对 ${keeps.length} 个达标 query 各起一次搜索(小红书+公众号 各20),确认?`)) return;
|
|
|
- let ok = 0;
|
|
|
|
|
|
|
+ qrClosePop();
|
|
|
|
|
+ const items = [];
|
|
|
for (const [, v] of keeps) {
|
|
for (const [, v] of keeps) {
|
|
|
- try { await qrRunSearch(v.rewrite || v.query); ok++; }
|
|
|
|
|
|
|
+ const q = v.rewrite || v.query;
|
|
|
|
|
+ try { const r = await qrRunSearch(q); if (r.task_id) items.push({ query: q, query_id: r.query_id, task_id: r.task_id }); }
|
|
|
catch (e) { /* 单格失败不阻断 */ }
|
|
catch (e) { /* 单格失败不阻断 */ }
|
|
|
}
|
|
}
|
|
|
- toast(`已发起 ${ok}/${keeps.length} 个搜索任务`, "info");
|
|
|
|
|
|
|
+ if (!items.length) return toast("全部发起失败", "error");
|
|
|
|
|
+ toast(`已发起 ${items.length}/${keeps.length} 个搜索`, "info");
|
|
|
|
|
+ showQrBatch(items);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
/* ════ 新建搜索 ════ */
|
|
/* ════ 新建搜索 ════ */
|