Просмотр исходного кода

feat(mode_workflow): 搜索进度可见——任务面板提到弹层之上 + 搜全部达标 实时列出各任务状态

刘文武 6 дней назад
Родитель
Сommit
a14c07351a
1 измененных файлов с 33 добавлено и 4 удалено
  1. 33 4
      examples/mode_workflow/index.html

+ 33 - 4
examples/mode_workflow/index.html

@@ -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);
       };
       };
 
 
       /* ════ 新建搜索 ════ */
       /* ════ 新建搜索 ════ */