const DEFAULT_API_BASE = "http://127.0.0.1:4777"; const statusText = document.querySelector("#statusText"); const versionText = document.querySelector("#versionText"); const updatePanel = document.querySelector("#updatePanel"); const updateText = document.querySelector("#updateText"); const updateGuideBtn = document.querySelector("#updateGuideBtn"); const resultBox = document.querySelector("#resultBox"); const settingsPanel = document.querySelector("#settingsPanel"); const capturePageBtn = document.querySelector("#capturePageBtn"); const captureMainBtn = document.querySelector("#captureMainBtn"); const testSaveBtn = document.querySelector("#testSaveBtn"); const openDashboardBtn = document.querySelector("#openDashboardBtn"); const apiBaseInput = document.querySelector("#apiBaseInput"); const pluginTokenInput = document.querySelector("#pluginTokenInput"); const saveSettingsBtn = document.querySelector("#saveSettingsBtn"); let settings = { apiBase: DEFAULT_API_BASE, pluginToken: "", }; let latestExtensionInfo = null; async function init() { versionText.textContent = `插件版本 ${currentVersion()}`; settings = await loadSettings(); apiBaseInput.value = settings.apiBase; pluginTokenInput.value = settings.pluginToken; await checkHealth(); } async function loadSettings() { const stored = await chromeStorageGet(["apiBase", "pluginToken"]); return { apiBase: normalizeApiBase(stored.apiBase || DEFAULT_API_BASE), pluginToken: stored.pluginToken || "", }; } async function saveSettings() { settings = { apiBase: normalizeApiBase(apiBaseInput.value || DEFAULT_API_BASE), pluginToken: pluginTokenInput.value.trim(), }; await chromeStorageSet(settings); settings = await loadSettings(); apiBaseInput.value = settings.apiBase; pluginTokenInput.value = settings.pluginToken; resultBox.innerHTML = "
连接配置已保存,下次打开会自动带出。
"; await checkHealth(); settingsPanel.open = false; } async function checkHealth() { try { const response = await fetch(`${settings.apiBase}/api/health`); if (!response.ok) throw new Error("服务未响应"); const payload = await response.json(); latestExtensionInfo = payload.extension || null; statusText.textContent = payload.authRequired && !settings.pluginToken ? "系统已连接,待填写插件 Token" : "系统已连接"; renderUpdatePrompt(payload.extension); setButtonsDisabled(payload.authRequired && !settings.pluginToken); openDashboardBtn.disabled = false; } catch { statusText.textContent = "系统未连接"; latestExtensionInfo = null; renderUpdatePrompt(null); setButtonsDisabled(true); openDashboardBtn.disabled = false; } } function renderUpdatePrompt(extensionInfo) { if (!extensionInfo?.recommendedVersion || !isVersionGreater(extensionInfo.recommendedVersion, currentVersion())) { updatePanel.hidden = true; settingsPanel.classList.remove("has-update"); return; } updatePanel.hidden = false; settingsPanel.classList.add("has-update"); updateText.textContent = `当前 ${currentVersion()},系统推荐 ${extensionInfo.recommendedVersion}。${extensionInfo.updateNote || "建议更新插件后再采集。"}`; } function setButtonsDisabled(disabled) { capturePageBtn.disabled = disabled; captureMainBtn.disabled = disabled; testSaveBtn.disabled = disabled; openDashboardBtn.disabled = disabled; } async function getActiveTab() { const activeTabs = await chrome.tabs.query({ active: true, lastFocusedWindow: true }); let tab = activeTabs.find(isInjectableTab); if (!tab) { const allTabs = await chrome.tabs.query({}); tab = allTabs.reverse().find(isInjectableTab); } if (!tab?.id) throw new Error("没有找到可采集的普通网页标签页,请先打开淘宝、小红书或 1688 页面"); return tab; } async function runExtractor(mode) { const tab = await getActiveTab(); try { const response = await chrome.tabs.sendMessage(tab.id, { type: "EXTRACT_PRODUCTS", mode }); return response?.items || []; } catch (firstError) { try { await chrome.scripting.executeScript({ target: { tabId: tab.id }, files: ["content.js"], }); const response = await chrome.tabs.sendMessage(tab.id, { type: "EXTRACT_PRODUCTS", mode }); return response?.items || []; } catch (secondError) { throw new Error(`页面采集脚本无法运行:${secondError.message || firstError.message}`); } } } async function capture(mode) { resultBox.innerHTML = "正在采集当前页面...
"; setButtonsDisabled(true); try { const items = await runExtractor(mode); if (!items.length) { resultBox.innerHTML = "没有识别到可采集的商品/笔记。可以滚动页面后再试,或打开详情页采集主商品。
"; return; } const payload = await postCaptures(items); resultBox.innerHTML = renderSavedResult(payload.items || [], payload.credits); } catch (error) { resultBox.innerHTML = `采集失败:${escapeHtml(error.message)}
排查:确认系统地址和插件 Token;当前页不是浏览器内部页;淘宝/小红书/1688 页面可刷新后重试。
`; } finally { setButtonsDisabled(false); } } async function postCaptures(items) { const headers = { "Content-Type": "application/json" }; if (settings.pluginToken) headers.Authorization = `Bearer ${settings.pluginToken}`; const response = await fetch(`${settings.apiBase}/api/captures`, { method: "POST", headers, body: JSON.stringify({ items }), }); const payload = await response.json(); if (!response.ok) throw new Error(payload.error || "保存失败"); return payload; } async function testSave() { resultBox.innerHTML = "正在测试写入系统...
"; setButtonsDisabled(true); try { const payload = await postCaptures([ { platform: "1688", title: "插件测试款 藏式编绳手链 民族风", url: `https://detail.1688.com/offer/plugin-test-${Date.now()}.html`, image: "", priceText: "¥6.80", supplier: "插件诊断测试", metrics: { visibleText: "现货 混批 支持拿样 1000+人付款 求链接" }, notes: "来自浏览器插件测试保存按钮", }, ]); resultBox.innerHTML = `测试保存成功。采集链路正常。
已写入:${escapeHtml(payload.items?.[0]?.title || "测试款")}
${payload.credits ? `已扣 ${escapeHtml(payload.credits.deducted)} 积分,剩余 ${escapeHtml(payload.credits.remaining)}。
` : ""} `; } catch (error) { resultBox.innerHTML = `测试保存失败:${escapeHtml(error.message)}
请确认系统地址可访问,SaaS 模式需要填写插件 Token。
`; } finally { setButtonsDisabled(false); } } function renderSavedResult(items, credits) { return `已保存 ${items.length} 条候选。
${credits ? `已扣 ${escapeHtml(credits.deducted)} 积分,剩余 ${escapeHtml(credits.remaining)}。
` : ""}${escapeHtml(guide)}
安装包:${escapeHtml(latestExtensionInfo?.fileName || "product-sourcing-capture-extension.zip")}