|
|
@@ -2080,6 +2080,10 @@
|
|
|
.qr-thr-lab { color:#666; font-size:12px; }
|
|
|
.qr-thr { width:46px; padding:3px 5px; border:1px solid #ddd; border-radius:6px; font-size:12px; }
|
|
|
#qr-score:disabled { opacity:.6; cursor:wait; }
|
|
|
+ .ui-confirm-bg { position:fixed; inset:0; background:rgba(0,0,0,.38); z-index:200; display:flex; align-items:center; justify-content:center; }
|
|
|
+ .ui-confirm { background:#fff; border-radius:14px; box-shadow:0 14px 50px rgba(0,0,0,.28); width:400px; max-width:92vw; padding:22px 24px; }
|
|
|
+ .ui-confirm-msg { font-size:14px; color:#1a1a1a; line-height:1.6; white-space:pre-line; margin-bottom:18px; }
|
|
|
+ .ui-confirm-acts { display:flex; justify-content:flex-end; gap:10px; }
|
|
|
.qr-dims { padding:8px 20px 10px; max-height:32vh; overflow:auto; border-bottom:1px solid #f0f0f0; }
|
|
|
.qr-row { display:flex; align-items:flex-start; gap:10px; padding:4px 0; }
|
|
|
.qr-row + .qr-row { border-top:1px solid #f6f6f6; }
|
|
|
@@ -2933,11 +2937,11 @@
|
|
|
ea.textContent = `解构全部已采纳(${adoptedN})`;
|
|
|
}
|
|
|
$("#btn-batch").onclick = () => state.selected.size && startExtract([...state.selected]);
|
|
|
- $("#btn-extract-adopted").onclick = () => {
|
|
|
+ $("#btn-extract-adopted").onclick = async () => {
|
|
|
const cids = (state.posts || []).filter((p) => p.adopted).map((p) => p.case_id);
|
|
|
if (!cids.length) return toast("当前 query 下没有已采纳的帖子", "warn");
|
|
|
const dir = state.mode === "process" ? "工序" : "工具";
|
|
|
- if (!confirm(`对该 query 下全部 ${cids.length} 个已采纳帖做${dir}解构?\n已解构过的会自动跳过/复用,不重复花钱。`)) return;
|
|
|
+ if (!(await uiConfirm(`对该 query 下全部 ${cids.length} 个已采纳帖做${dir}解构?\n已解构过的会自动跳过/复用,不重复花钱。`))) return;
|
|
|
startExtract(cids); // 复用:认领锁 + 解构去重 + showTask 轮询
|
|
|
};
|
|
|
|
|
|
@@ -3668,6 +3672,35 @@
|
|
|
/* ════ 任务面板(✕ 只隐藏;「操作日志」按钮可随时唤回)════ */
|
|
|
let pollTimer = null,
|
|
|
hasTask = false;
|
|
|
+ // 自建确认弹框(替代浏览器原生 confirm):返回 Promise<bool>。Enter=确定 / Esc=取消 / 点遮罩=取消
|
|
|
+ function uiConfirm(message, opt = {}) {
|
|
|
+ const { okText = "确定", cancelText = "取消" } = opt;
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ const bg = document.createElement("div");
|
|
|
+ bg.className = "ui-confirm-bg";
|
|
|
+ bg.innerHTML =
|
|
|
+ '<div class="ui-confirm"><div class="ui-confirm-msg"></div>'
|
|
|
+ + '<div class="ui-confirm-acts">'
|
|
|
+ + '<button class="btn" data-act="cancel"></button>'
|
|
|
+ + '<button class="btn seal" data-act="ok"></button></div></div>';
|
|
|
+ bg.querySelector(".ui-confirm-msg").textContent = message;
|
|
|
+ bg.querySelector('[data-act="cancel"]').textContent = cancelText;
|
|
|
+ bg.querySelector('[data-act="ok"]').textContent = okText;
|
|
|
+ document.body.appendChild(bg);
|
|
|
+ const done = (v) => { bg.remove(); document.removeEventListener("keydown", onKey, true); resolve(v); };
|
|
|
+ bg.addEventListener("click", (e) => {
|
|
|
+ if (e.target === bg) return done(false);
|
|
|
+ const a = e.target.closest("[data-act]");
|
|
|
+ if (a) done(a.dataset.act === "ok");
|
|
|
+ });
|
|
|
+ const onKey = (e) => {
|
|
|
+ if (e.key === "Escape") { e.preventDefault(); done(false); }
|
|
|
+ else if (e.key === "Enter") { e.preventDefault(); done(true); }
|
|
|
+ };
|
|
|
+ document.addEventListener("keydown", onKey, true);
|
|
|
+ bg.querySelector('[data-act="ok"]').focus();
|
|
|
+ });
|
|
|
+ }
|
|
|
function showTask(title, taskId, onDone, onSettled) {
|
|
|
hasTask = true;
|
|
|
$("#task-panel").hidden = false;
|
|
|
@@ -3987,7 +4020,7 @@
|
|
|
$("#qr-search-all").onclick = async () => {
|
|
|
const keeps = Object.entries(qrState.scores || {}).filter(([, v]) => qrKeep(v));
|
|
|
if (!keeps.length) return;
|
|
|
- if (!confirm(`将对 ${keeps.length} 个达标 query 各起一次搜索(小红书+公众号 各20),确认?`)) return;
|
|
|
+ if (!(await uiConfirm(`将对 ${keeps.length} 个达标 query 各起一次搜索(小红书+公众号 各20),确认?`))) return;
|
|
|
qrClosePop();
|
|
|
const items = [];
|
|
|
for (const [, v] of keeps) {
|