const $ = (sel) => document.querySelector(sel); // Promise-based sendMessage with timeout (MV3 reliable) function sendMsg(msg, timeoutMs = 10000) { return new Promise((resolve) => { let settled = false; const timer = setTimeout(() => { if (!settled) { settled = true; resolve({ error: "消息超时,请检查插件是否正常加载" }); } }, timeoutMs); chrome.runtime.sendMessage(msg, (res) => { if (settled) return; settled = true; clearTimeout(timer); if (chrome.runtime.lastError) { resolve({ error: chrome.runtime.lastError.message }); } else { resolve(res || { error: "无响应" }); } }); }); } function setUI(state) { const dot = $("#statusDot"); const text = $("#statusText"); const btn = $("#btnToggle"); if (state === "loading") { dot.className = "dot dot-gray"; text.textContent = "连接中..."; btn.textContent = "启动"; btn.className = "btn btn-primary"; btn.disabled = true; } else if (state === "error") { dot.className = "dot dot-red"; text.textContent = "服务未连接"; btn.textContent = "启动"; btn.className = "btn btn-primary"; btn.disabled = true; $("#statToday").textContent = "-"; $("#statPending").textContent = "-"; $("#statFails").textContent = "-"; $("#todayCount").textContent = "- / -"; $("#connTest").innerHTML = '无法连接到后台脚本,请右键插件→重新加载'; } else if (state === "running") { dot.className = "dot dot-green"; text.textContent = "运行中"; btn.textContent = "停止"; btn.className = "btn btn-danger"; btn.disabled = false; } else if (state === "stopped") { dot.className = "dot dot-gray"; text.textContent = "已停止"; btn.textContent = "启动"; btn.className = "btn btn-primary"; btn.disabled = false; } } async function loadStatus() { setUI("loading"); const status = await sendMsg({ type: "GET_STATUS" }); if (!status || status.error) { setUI("error"); return; } setUI(status.polling ? "running" : "stopped"); if (status.statusError) { $("#connTest").innerHTML = `${status.statusError}`; } else { $("#connTest").innerHTML = ""; } $("#statToday").textContent = status.todayCount; $("#statFails").textContent = status.consecutiveFailures; const config = await sendMsg({ type: "GET_CONFIG" }); if (config && !config.error) { $("#shopId").value = config.shopId || ""; $("#serverUrl").value = config.serverUrl || "http://localhost:3000"; const limit = config.dailyLimit || 20; const pending = status.pendingCount || 0; $("#statPending").textContent = pending; $("#todayCount").textContent = `${status.todayCount} / ${limit}`; } } $("#btnToggle").addEventListener("click", async () => { const btn = $("#btnToggle"); btn.disabled = true; btn.textContent = "处理中..."; // Save config first await saveConfig(); // Check current status and toggle const status = await sendMsg({ type: "GET_STATUS" }); const isRunning = status && status.polling; if (isRunning) { await sendMsg({ type: "STOP_POLLING" }); } else { const res = await sendMsg({ type: "START_POLLING" }); if (res && res.error) { console.error("启动失败:", res.error); } } // Reload status to update UI await loadStatus(); }); $("#btnTest").addEventListener("click", async () => { const testEl = $("#connTest"); testEl.innerHTML = "测试中..."; await saveConfig(); const res = await sendMsg({ type: "TEST_CONNECTION" }, 5000); if (res && res.ok) { testEl.innerHTML = '✓ 连接成功'; } else { testEl.innerHTML = `✗ ${res?.error || "连接失败,请确认本地服务已启动"}`; } }); function saveConfig() { return new Promise((resolve) => { chrome.storage.local.get(["config"], (data) => { const existing = data.config || {}; const config = { ...existing, serverUrl: $("#serverUrl").value.trim() || "http://localhost:3000", shopId: $("#shopId").value.trim(), }; chrome.storage.local.set({ config }, resolve); }); }); } let refreshTimer = null; function scheduleSaveAndRefresh() { clearTimeout(refreshTimer); refreshTimer = setTimeout(async () => { await saveConfig(); await loadStatus(); }, 400); } // 输入店铺名时要立即保存并刷新数量;change 只有失焦后才触发,容易看起来没有同步。 ["shopId", "serverUrl"].forEach((id) => { const input = $(`#${id}`); input.addEventListener("input", scheduleSaveAndRefresh); input.addEventListener("change", async () => { clearTimeout(refreshTimer); await saveConfig(); await loadStatus(); }); }); loadStatus();