// ==UserScript== // @name 结案报告监工 // @namespace yuntu-evaluation-task-watcher // @version 0.2.0 // @description 监听云图坑位,按配置的报告ID列表依次启动已有报告 // @match https://yuntu.oceanengine.com/yuntu_brand/ecom/evaluation/task_list* // @require https://cdn.jsdelivr.net/npm/sweetalert2@11 // @grant none // @run-at document-idle // ==/UserScript== (function () { "use strict"; const STORAGE_KEY = "yuntu_evaluation_task_watcher_state_v1"; const LAUNCHER_POSITION_KEY = "yuntu_evaluation_task_watcher_launcher_position_v1"; const DEFAULT_PAGE_STATE = { enabled: false, importMode: "id", manualTaskIds: [], importKeyword: "", watchTaskIds: [], submittedTaskIds: [], selectedBrandKey: "", webhookUrl: "", }; const DEFAULT_CONFIG = { industryVersion: "10005", pollIntervalMs: 30000, taskListRefreshIntervalMs: 60000, submitCooldownMs: 4000, }; const runtime = { aadvid: "", pageState: { ...DEFAULT_PAGE_STATE }, brandContext: null, busy: false, timerId: null, launcherEl: null, dragState: null, suppressClickOnce: false, lastQuotaStatus: "未检查", lastTaskListStatus: "未同步", lastTaskListSyncAt: 0, lastAction: "未执行", latestSourceTasks: [], logs: [], }; const toast = Swal.mixin({ toast: true, position: "top-end", showConfirmButton: false, timer: 2500, timerProgressBar: true, }); function readStore() { try { const raw = localStorage.getItem(STORAGE_KEY); return raw ? JSON.parse(raw) : {}; } catch (error) { console.error("[结案报告监工] 读取本地存储失败", error); return {}; } } function writeStore(store) { localStorage.setItem(STORAGE_KEY, JSON.stringify(store)); } function loadLauncherPosition() { try { const raw = localStorage.getItem(LAUNCHER_POSITION_KEY); if (!raw) { return null; } const data = JSON.parse(raw); if (typeof data?.x !== "number" || typeof data?.y !== "number") { return null; } return data; } catch (error) { console.error("[结案报告监工] 读取悬浮按钮位置失败", error); return null; } } function saveLauncherPosition(position) { localStorage.setItem(LAUNCHER_POSITION_KEY, JSON.stringify(position)); } function loadPageState(aadvid) { const store = readStore(); const saved = store[aadvid] || {}; return { ...DEFAULT_PAGE_STATE, ...saved, importMode: ["id", "keyword", "mine"].includes(saved.importMode) ? saved.importMode : "id", manualTaskIds: dedupeTaskIds(saved.manualTaskIds || saved.watchTaskIds || []), importKeyword: String(saved.importKeyword || ""), watchTaskIds: dedupeTaskIds(saved.watchTaskIds || []), submittedTaskIds: dedupeTaskIds(saved.submittedTaskIds || []), selectedBrandKey: String(saved.selectedBrandKey || ""), webhookUrl: String(saved.webhookUrl || ""), }; } function savePageState() { const store = readStore(); store[runtime.aadvid] = { enabled: runtime.pageState.enabled, importMode: runtime.pageState.importMode, manualTaskIds: runtime.pageState.manualTaskIds, importKeyword: runtime.pageState.importKeyword, watchTaskIds: runtime.pageState.watchTaskIds, submittedTaskIds: runtime.pageState.submittedTaskIds, selectedBrandKey: runtime.pageState.selectedBrandKey, webhookUrl: runtime.pageState.webhookUrl, }; writeStore(store); } function dedupeTaskIds(values) { const unique = new Set(); for (const value of values) { const taskId = String(value || "").trim(); if (taskId) { unique.add(taskId); } } return Array.from(unique); } function parseTaskIds(text) { return dedupeTaskIds(String(text || "").split(/[\s,\n,]+/)); } function clampLauncherPosition(x, y) { if (!runtime.launcherEl) { return { x, y }; } const rect = runtime.launcherEl.getBoundingClientRect(); const maxX = Math.max(8, window.innerWidth - rect.width - 8); const maxY = Math.max(8, window.innerHeight - rect.height - 8); return { x: Math.min(Math.max(8, x), maxX), y: Math.min(Math.max(8, y), maxY), }; } function applyLauncherPosition(position) { if (!runtime.launcherEl) { return; } const next = clampLauncherPosition(position.x, position.y); runtime.launcherEl.style.left = `${next.x}px`; runtime.launcherEl.style.top = `${next.y}px`; runtime.launcherEl.style.right = "auto"; runtime.launcherEl.style.bottom = "auto"; } function getPendingTaskIds() { const submitted = new Set(runtime.pageState.submittedTaskIds); return runtime.pageState.watchTaskIds.filter((taskId) => !submitted.has(taskId)); } function getAadvidFromUrl() { return new URL(window.location.href).searchParams.get("aadvid") || ""; } function pushLog(message) { const entry = `${new Date().toLocaleTimeString()} ${message}`; runtime.logs.unshift(entry); runtime.logs = runtime.logs.slice(0, 12); console.log("[结案报告监工]", message); } function showToast(icon, title, text) { pushLog(text || title); renderLauncher(); return toast.fire({ icon, title, text, }); } function getModeLabel(mode = runtime.pageState.importMode) { if (mode === "keyword") { return "关键词导入"; } if (mode === "mine") { return "我创建的"; } return "ID导入"; } function formatSyncTime(timestamp) { if (!timestamp) { return "未同步"; } return new Date(timestamp).toLocaleTimeString(); } function buildHeaders(pathId, contentType) { const headers = { Accept: "application/json, text/plain, */*", "x-request-start": String(Date.now()), }; if (pathId) { headers["x-path-id"] = pathId; } if (contentType) { headers["Content-Type"] = contentType; } if (runtime.brandContext?.industryVersion) { headers["x-industry-version"] = runtime.brandContext.industryVersion; } return headers; } async function requestJson(url, options = {}) { const response = await fetch(url, { method: options.method || "GET", credentials: "include", headers: buildHeaders(options.pathId, options.contentType), body: options.body ? JSON.stringify(options.body) : undefined, referrer: options.referrer || window.location.href, referrerPolicy: "strict-origin-when-cross-origin", }); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return response.json(); } async function sendWebhookNotification(taskId) { const webhookUrl = String(runtime.pageState.webhookUrl || "").trim(); if (!webhookUrl) { return; } const pendingCount = getPendingTaskIds().length; const message = `结案报告监工通知:品牌 ${runtime.brandContext.brandName}(${runtime.brandContext.mainBrandId}) ` + `已启动报告 ${taskId},剩余待提交 ${pendingCount} 个。`; const response = await fetch(webhookUrl, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ msg_type: "text", content: { text: message, }, }), }); if (!response.ok) { throw new Error(`Webhook HTTP ${response.status}`); } } function formatBrandOption(meta) { return `${meta.brand_name} (${meta.brand_id}) / ${meta.industry_name} (${meta.industry_id})`; } function normalizeBrandMetadata(list) { const candidates = []; const seen = new Set(); for (const item of Array.isArray(list) ? list : []) { const industryId = String(item?.industry_id || ""); if (industryId.length !== 2) { continue; } const brandId = String(item?.brand_id || ""); const brandName = String(item?.brand_name || ""); const industryName = String(item?.industry_name || ""); const key = `${brandId}|${industryId}`; if (!brandId || seen.has(key)) { continue; } seen.add(key); candidates.push({ key, brandId, brandName, industryId, industryName, }); } return candidates; } async function fetchUserInfoContext() { const url = `https://yuntu.oceanengine.com/yuntu_ng/api/v1/get_user_info?aadvid=${encodeURIComponent(runtime.aadvid)}`; const data = await requestJson(url, { method: "GET", referrer: window.location.href, }); const brandMetadata = normalizeBrandMetadata(data?.data?.brandMetadata); if (brandMetadata.length === 0) { throw new Error("未从 get_user_info 中解析到品牌和行业信息"); } let selected = brandMetadata.find((item) => item.key === runtime.pageState.selectedBrandKey) || null; if (!selected && brandMetadata.length > 1) { const inputOptions = {}; for (const item of brandMetadata) { inputOptions[item.key] = formatBrandOption(item); } const result = await Swal.fire({ title: "选择品牌", input: "select", inputOptions, inputPlaceholder: "请选择当前要监听的品牌", confirmButtonText: "确认", allowOutsideClick: false, allowEscapeKey: false, inputValidator: (value) => { if (!value) { return "需要先选择品牌"; } return undefined; }, text: `aadvid=${runtime.aadvid}`, }); if (!result.isConfirmed) { throw new Error("未选择品牌,脚本未启动"); } selected = brandMetadata.find((item) => item.key === result.value) || null; } if (!selected) { selected = brandMetadata[0]; } runtime.pageState.selectedBrandKey = selected.key; savePageState(); return { aadvid: runtime.aadvid, mainBrandId: selected.brandId, brandName: selected.brandName, level1IndustryId: selected.industryId, industryName: selected.industryName, industryVersion: DEFAULT_CONFIG.industryVersion, currentUserId: String(data?.data?.userInfo?.user?.id || ""), }; } async function checkQuota() { const url = `https://yuntu.oceanengine.com/yuntu_common/api/v1/evaluation/create/check_task_creation_rate_limit` + `?aadvid=${encodeURIComponent(runtime.brandContext.aadvid)}`; const payload = { main_brand_id: runtime.brandContext.mainBrandId, level_1_industry_id: runtime.brandContext.level1IndustryId, }; const referrer = `https://yuntu.oceanengine.com/yuntu_brand/ecom/evaluation/task_create` + `?business_type=0&industry_version_type=${encodeURIComponent(runtime.brandContext.industryVersion)}` + `&version=0&aadvid=${encodeURIComponent(runtime.brandContext.aadvid)}`; const data = await requestJson(url, { method: "POST", pathId: "evaluation_task_create", contentType: "application/json", body: payload, referrer, }); return { isAbleToCreate: String(data?.data?.is_able_to_create || "") === "1", message: data?.data?.msg || data?.msg || "无响应信息", }; } async function startExistingTask(taskId) { const url = `https://yuntu.oceanengine.com/yuntu_common/api/v1/ecomTaskList/start_calaulate_evaluation_task` + `?aadvid=${encodeURIComponent(runtime.brandContext.aadvid)}`; const payload = { main_brand_id: runtime.brandContext.mainBrandId, level_1_industry_id: runtime.brandContext.level1IndustryId, task_id: String(taskId), }; const referrer = `https://yuntu.oceanengine.com/yuntu_brand/ecom/evaluation/task_list` + `?aadvid=${encodeURIComponent(runtime.brandContext.aadvid)}`; const data = await requestJson(url, { method: "POST", pathId: "evaluation_task_list", contentType: "application/json", body: payload, referrer, }); return { success: data?.status === 0 && data?.data?.is_success === true, message: data?.msg || "无响应信息", }; } async function fetchEvaluationTaskList(searchWord = "") { const url = `https://yuntu.oceanengine.com/yuntu_common/api/v1/ecomTaskList/get_evaluation_task_list` + `?aadvid=${encodeURIComponent(runtime.brandContext.aadvid)}`; const payload = { main_brand_id: runtime.brandContext.mainBrandId, level_1_industry_id: runtime.brandContext.level1IndustryId, page_num: "1", page_size: "100", order_type: 1, }; if (searchWord) { payload.search_word = searchWord; } const referrer = `https://yuntu.oceanengine.com/yuntu_brand/ecom/evaluation/task_list` + `?aadvid=${encodeURIComponent(runtime.brandContext.aadvid)}`; const data = await requestJson(url, { method: "POST", pathId: "evaluation_task_list", contentType: "application/json", body: payload, referrer, }); const taskList = Array.isArray(data?.data?.task_list) ? data.data.task_list : []; return taskList.map((item) => ({ taskId: String(item?.task_id || "").trim(), taskName: String(item?.task_name || "").trim(), taskStatus: Number(item?.task_status), userId: String(item?.user_id || "").trim(), createTime: String(item?.create_time || "").trim(), })).filter((item) => item.taskId); } async function syncTaskSource(force = false) { const now = Date.now(); if (!force && now - runtime.lastTaskListSyncAt < DEFAULT_CONFIG.taskListRefreshIntervalMs) { return; } const mode = runtime.pageState.importMode; let sourceTasks = []; if (mode === "id") { const manualIds = dedupeTaskIds(runtime.pageState.manualTaskIds || []); if (manualIds.length === 0) { runtime.latestSourceTasks = []; runtime.pageState.watchTaskIds = []; runtime.lastTaskListStatus = "ID列表为空"; runtime.lastTaskListSyncAt = now; savePageState(); renderLauncher(); return; } const selectedIdSet = new Set(manualIds); const taskList = await fetchEvaluationTaskList(); sourceTasks = taskList.filter((item) => item.taskStatus === 0 && selectedIdSet.has(item.taskId)); } else if (mode === "keyword") { const keyword = String(runtime.pageState.importKeyword || "").trim(); if (!keyword) { runtime.latestSourceTasks = []; runtime.pageState.watchTaskIds = []; runtime.lastTaskListStatus = "关键词为空"; runtime.lastTaskListSyncAt = now; savePageState(); renderLauncher(); return; } const taskList = await fetchEvaluationTaskList(keyword); sourceTasks = taskList.filter((item) => item.taskStatus === 0); } else { const currentUserId = String(runtime.brandContext.currentUserId || ""); const taskList = await fetchEvaluationTaskList(); sourceTasks = taskList.filter((item) => item.taskStatus === 0 && item.userId === currentUserId); } runtime.latestSourceTasks = sourceTasks; runtime.pageState.watchTaskIds = dedupeTaskIds(sourceTasks.map((item) => item.taskId)); runtime.lastTaskListStatus = `${getModeLabel(mode)}匹配 ${sourceTasks.length} 个待提交`; runtime.lastTaskListSyncAt = now; savePageState(); renderLauncher(); } function persistControlDialogValues(root = document) { const modeInput = root.querySelector("#ysw-import-mode"); const taskIdsInput = root.querySelector("#ysw-task-ids"); const keywordInput = root.querySelector("#ysw-keyword"); const webhookInput = root.querySelector("#ysw-webhook-url"); runtime.pageState.importMode = String(modeInput ? modeInput.value : "id"); runtime.pageState.manualTaskIds = parseTaskIds(taskIdsInput ? taskIdsInput.value : ""); runtime.pageState.importKeyword = String(keywordInput ? keywordInput.value : "").trim(); runtime.pageState.webhookUrl = String(webhookInput ? webhookInput.value : "").trim(); savePageState(); renderLauncher(); } function stopPolling(showNotice = true) { if (runtime.timerId !== null) { window.clearInterval(runtime.timerId); runtime.timerId = null; } runtime.pageState.enabled = false; savePageState(); renderLauncher(); if (showNotice) { showToast("info", "监听已停止", `aadvid=${runtime.aadvid}`); } } function startPolling() { stopPolling(false); runtime.pageState.enabled = true; savePageState(); runtime.timerId = window.setInterval(runCycle, DEFAULT_CONFIG.pollIntervalMs); renderLauncher(); showToast("success", "开始监听", `${runtime.brandContext.brandName} / aadvid=${runtime.aadvid}`); runCycle(); } async function runCycle() { if (!runtime.pageState.enabled || runtime.busy) { return; } runtime.busy = true; renderLauncher(); try { await syncTaskSource(); } catch (error) { runtime.lastAction = "同步报告列表失败"; runtime.lastTaskListStatus = `同步失败: ${error.message}`; await showToast("error", "同步报告列表失败", error.message); runtime.busy = false; renderLauncher(); return; } const pendingTaskIds = getPendingTaskIds(); if (pendingTaskIds.length === 0) { runtime.lastAction = "当前无待提交报告,继续等待"; renderLauncher(); runtime.busy = false; renderLauncher(); return; } try { const quota = await checkQuota(); runtime.lastQuotaStatus = quota.isAbleToCreate ? "有坑位" : quota.message; if (!quota.isAbleToCreate) { runtime.lastAction = "本轮未提交"; pushLog(`暂无坑位: ${quota.message}`); return; } const nextTaskId = pendingTaskIds[0]; runtime.lastAction = `准备启动报告 ${nextTaskId}`; const startResult = await startExistingTask(nextTaskId); if (!startResult.success) { runtime.lastAction = `启动失败 ${nextTaskId}`; await showToast("error", "启动失败", `报告 ${nextTaskId} 启动失败: ${startResult.message}`); return; } runtime.pageState.submittedTaskIds = dedupeTaskIds([ ...runtime.pageState.submittedTaskIds, nextTaskId, ]); savePageState(); renderLauncher(); runtime.lastAction = `已启动报告 ${nextTaskId}`; try { await sendWebhookNotification(nextTaskId); } catch (error) { pushLog(`Webhook 发送失败: ${error.message}`); } runtime.lastTaskListSyncAt = 0; await showToast("success", "启动成功", `报告 ${nextTaskId} 已提交计算`); window.setTimeout(runCycle, DEFAULT_CONFIG.submitCooldownMs); } catch (error) { runtime.lastAction = "执行异常"; await showToast("error", "执行异常", error.message); } finally { runtime.busy = false; renderLauncher(); } } function buildControlHtml() { const pendingCount = getPendingTaskIds().length; const submittedCount = runtime.pageState.submittedTaskIds.length; const logs = runtime.logs.length > 0 ? runtime.logs.slice(0, 8).join("
") : "暂无日志"; const currentPendingList = runtime.latestSourceTasks.length > 0 ? runtime.latestSourceTasks .slice(0, 20) .map((item) => `
${escapeHtml(item.taskName || `报告 ${item.taskId}`)} (${escapeHtml(item.taskId)})
`) .join("") : "
暂无匹配的待提交报告
"; return [ `
`, `
aadvid:${runtime.aadvid}
`, `
品牌:${runtime.brandContext.brandName} (${runtime.brandContext.mainBrandId})
`, `
行业:${runtime.brandContext.industryName} (${runtime.brandContext.level1IndustryId})
`, `
当前用户ID:${runtime.brandContext.currentUserId || "未识别"}
`, `
导入方式:${getModeLabel()}
`, `
运行状态:${runtime.pageState.enabled ? "监听中" : "已停止"}
`, `
坑位状态:${runtime.lastQuotaStatus}
`, `
报告同步:${runtime.lastTaskListStatus}
`, `
上次同步:${formatSyncTime(runtime.lastTaskListSyncAt)}
`, `
最近动作:${runtime.lastAction}
`, `
待提交 / 已提交:${pendingCount} / ${submittedCount}
`, `
Webhook:${runtime.pageState.webhookUrl ? "已配置" : "未配置"}
`, `
当前待提交报告:
${currentPendingList}${runtime.latestSourceTasks.length > 20 ? `
其余 ${runtime.latestSourceTasks.length - 20} 个未展开
` : ""}
`, `
最近日志:
${logs}
`, `
点击右下角悬浮按钮可再次打开配置
`, `
`, ].join(""); } async function openControlDialog() { const stateLabel = runtime.pageState.enabled ? "保存并继续监听" : "保存并开始监听"; const denyLabel = runtime.pageState.enabled ? "停止监听" : "仅保存"; const result = await Swal.fire({ title: "结案报告监工", html: `${buildControlHtml()}` + `
` + `` + `` + `
` + `
` + `` + `` + `
` + `
` + `` + `` + `
` + `
` + `` + `` + `
`, showCancelButton: true, showDenyButton: true, showCloseButton: true, focusConfirm: false, confirmButtonText: stateLabel, denyButtonText: denyLabel, cancelButtonText: "取消", footer: '', didOpen: (popup) => { const modeSelect = popup.querySelector("#ysw-import-mode"); const idWrapper = popup.querySelector("#ysw-id-wrapper"); const keywordWrapper = popup.querySelector("#ysw-keyword-wrapper"); const clearButton = popup.querySelector("#ysw-clear-submitted"); if (modeSelect && idWrapper && keywordWrapper) { const toggleModeFields = () => { const mode = modeSelect.value; idWrapper.style.display = mode === "id" ? "block" : "none"; keywordWrapper.style.display = mode === "keyword" ? "block" : "none"; }; toggleModeFields(); modeSelect.addEventListener("change", toggleModeFields); } if (!clearButton) { return; } clearButton.addEventListener("click", async () => { const confirmResult = await Swal.fire({ title: "确认清空已提交记录?", text: "清空之后,脚本会重新启动列表里已经成功提交过的报告。", icon: "warning", showCancelButton: true, confirmButtonText: "确认清空", cancelButtonText: "取消", }); if (!confirmResult.isConfirmed) { return; } runtime.pageState.submittedTaskIds = []; savePageState(); renderLauncher(); await showToast("success", "已清空", "已提交记录已经清空"); Swal.close(); openControlDialog(); }); }, preConfirm: () => { persistControlDialogValues(document); if (runtime.pageState.importMode === "id" && runtime.pageState.manualTaskIds.length === 0) { Swal.showValidationMessage("ID导入模式下请至少填写一个报告ID"); return false; } if (runtime.pageState.importMode === "keyword" && !runtime.pageState.importKeyword) { Swal.showValidationMessage("关键词导入模式下请输入关键词"); return false; } return true; }, preDeny: () => { persistControlDialogValues(document); return true; }, }); if (result.isConfirmed) { try { await syncTaskSource(true); } catch (error) { await showToast("error", "同步报告列表失败", error.message); openControlDialog(); return; } startPolling(); return; } if (result.isDenied) { if (runtime.pageState.enabled) { stopPolling(); } else { try { await syncTaskSource(true); } catch (error) { pushLog(`保存后同步失败: ${error.message}`); } await showToast("success", "已保存", `当前模式:${getModeLabel(runtime.pageState.importMode)}`); } } } function ensureLauncher() { if (runtime.launcherEl) { return; } const style = document.createElement("style"); style.textContent = ` #ysw-launcher { position: fixed; right: 16px; bottom: 20px; z-index: 999999; width: 196px; padding: 10px 12px; border: 0; border-radius: 14px; background: linear-gradient(135deg, #1677ff, #0f56c3); color: #fff; box-shadow: 0 10px 30px rgba(22, 119, 255, 0.28); cursor: pointer; user-select: none; text-align: left; font: 12px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; } #ysw-launcher:hover { filter: brightness(1.05); } #ysw-launcher .ysw-launcher-title { display: block; font-size: 14px; font-weight: 700; } #ysw-launcher .ysw-launcher-status, #ysw-launcher .ysw-launcher-count { display: block; opacity: 0.92; } `; const button = document.createElement("button"); button.id = "ysw-launcher"; button.type = "button"; button.innerHTML = ` 结案报告监工 `; button.addEventListener("click", () => { if (runtime.suppressClickOnce) { runtime.suppressClickOnce = false; return; } openControlDialog(); }); button.addEventListener("mousedown", (event) => { if (event.button !== 0) { return; } const rect = button.getBoundingClientRect(); runtime.dragState = { startX: event.clientX, startY: event.clientY, offsetX: event.clientX - rect.left, offsetY: event.clientY - rect.top, moved: false, }; }); document.head.appendChild(style); document.body.appendChild(button); runtime.launcherEl = button; const savedPosition = loadLauncherPosition(); if (savedPosition) { applyLauncherPosition(savedPosition); } else { const rect = button.getBoundingClientRect(); applyLauncherPosition({ x: window.innerWidth - rect.width - 16, y: window.innerHeight - rect.height - 20, }); } window.addEventListener("mousemove", (event) => { if (!runtime.dragState || !runtime.launcherEl) { return; } const nextX = event.clientX - runtime.dragState.offsetX; const nextY = event.clientY - runtime.dragState.offsetY; const movedDistance = Math.abs(event.clientX - runtime.dragState.startX) + Math.abs(event.clientY - runtime.dragState.startY); if (movedDistance > 4) { runtime.dragState.moved = true; } applyLauncherPosition({ x: nextX, y: nextY }); }); window.addEventListener("mouseup", () => { if (!runtime.dragState || !runtime.launcherEl) { return; } if (runtime.dragState.moved) { const rect = runtime.launcherEl.getBoundingClientRect(); saveLauncherPosition({ x: rect.left, y: rect.top }); runtime.suppressClickOnce = true; } runtime.dragState = null; }); window.addEventListener("resize", () => { if (!runtime.launcherEl) { return; } const rect = runtime.launcherEl.getBoundingClientRect(); applyLauncherPosition({ x: rect.left, y: rect.top }); }); renderLauncher(); } function renderLauncher() { if (!runtime.launcherEl) { return; } const statusEl = runtime.launcherEl.querySelector(".ysw-launcher-status"); const countEl = runtime.launcherEl.querySelector(".ysw-launcher-count"); const pendingCount = getPendingTaskIds().length; const statusText = runtime.pageState.enabled ? runtime.busy ? "状态:执行中" : "状态:监听中" : "状态:已停止"; statusEl.textContent = statusText; countEl.textContent = `待提交:${pendingCount} 已提交:${runtime.pageState.submittedTaskIds.length}`; } function escapeHtml(value) { return String(value || "") .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); } async function init() { runtime.aadvid = getAadvidFromUrl(); if (!runtime.aadvid) { await Swal.fire({ icon: "error", title: "缺少 aadvid", text: "当前 URL 中没有解析到 aadvid,脚本无法运行。", }); return; } runtime.pageState = loadPageState(runtime.aadvid); ensureLauncher(); try { runtime.brandContext = await fetchUserInfoContext(); } catch (error) { await Swal.fire({ icon: "error", title: "初始化失败", text: error.message, }); return; } const hasConfig = (runtime.pageState.importMode === "id" && runtime.pageState.manualTaskIds.length > 0) || (runtime.pageState.importMode === "keyword" && !!runtime.pageState.importKeyword) || runtime.pageState.importMode === "mine"; if (hasConfig) { try { await syncTaskSource(true); } catch (error) { pushLog(`初始化同步失败: ${error.message}`); } } if (!hasConfig) { await Swal.fire({ icon: "info", title: "首次配置", text: `已识别到 ${runtime.brandContext.brandName},请先选择导入方式并完成配置。`, }); openControlDialog(); return; } if (runtime.pageState.enabled) { startPolling(); return; } await showToast( "info", "脚本已加载", `${runtime.brandContext.brandName} 已识别,点击右下角“结案报告监工”打开配置` ); } init(); })();