/** * Pinduoduo Cookie Sync Extension Popup Script * 拼多多 Cookie 自动保活弹窗界面交互与实时日志引擎 */ document.addEventListener('DOMContentLoaded', async () => { const statusBadge = document.getElementById('statusBadge') const mmsStatus = document.getElementById('mmsStatus') const shopDisplay = document.getElementById('shopDisplay') const lastSyncDisplay = document.getElementById('lastSyncDisplay') const orderCountRow = document.getElementById('orderCountRow') const orderCountDisplay = document.getElementById('orderCountDisplay') const statusMsg = document.getElementById('statusMsg') const btnSyncNow = document.getElementById('btnSyncNow') const btnSaveConfig = document.getElementById('btnSaveConfig') const btnToggleImport = document.getElementById('btnToggleImport') const btnApplyImport = document.getElementById('btnApplyImport') const importArea = document.getElementById('importArea') const importJsonInput = document.getElementById('importJsonInput') const inputServerUrl = document.getElementById('inputServerUrl') const inputShopId = document.getElementById('inputShopId') const inputSyncToken = document.getElementById('inputSyncToken') const inputManualCookie = document.getElementById('inputManualCookie') const logBox = document.getElementById('logBox') const logCountBadge = document.getElementById('logCountBadge') const btnCopyLogs = document.getElementById('btnCopyLogs') const btnClearLogs = document.getElementById('btnClearLogs') let cachedLogs = [] function formatTime(timestamp) { if (!timestamp) return '未同步' const d = new Date(timestamp) if (isNaN(d.getTime())) return '未同步' const m = String(d.getMonth() + 1).padStart(2, '0') const day = String(d.getDate()).padStart(2, '0') const h = String(d.getHours()).padStart(2, '0') const min = String(d.getMinutes()).padStart(2, '0') const s = String(d.getSeconds()).padStart(2, '0') return `${m}-${day} ${h}:${min}:${s}` } function showMsg(text, type = 'success') { statusMsg.style.display = 'block' if (type === 'error') { statusMsg.className = 'msg-box msg-error' } else if (type === 'warn') { statusMsg.className = 'msg-box msg-warn' } else { statusMsg.className = 'msg-box msg-success' } statusMsg.textContent = text } // 加载并渲染运行日志 function refreshLogs() { chrome.runtime.sendMessage({ action: 'get_logs' }, (res) => { const logs = Array.isArray(res?.logs) ? res.logs : [] cachedLogs = logs logCountBadge.textContent = `(${logs.length}条)` if (logs.length === 0) { logBox.innerHTML = '
暂无运行日志
' return } let html = '' for (const item of logs) { let tagClass = 'log-tag-info' let tagText = '[INFO]' if (item.level === 'success') { tagClass = 'log-tag-success' tagText = '[OK]' } else if (item.level === 'warn') { tagClass = 'log-tag-warn' tagText = '[WARN]' } else if (item.level === 'error') { tagClass = 'log-tag-error' tagText = '[ERR]' } const detailsHtml = item.details ? `
↳ ${escapeHtml(item.details)}
` : '' html += `
${item.time || ''} ${tagText} [${escapeHtml(item.action || '系统')}] ${escapeHtml(item.message || '')} ${detailsHtml}
` } logBox.innerHTML = html }) } function escapeHtml(str) { if (!str) return '' return String(str) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') } function refreshStatusView(statusData) { const storage = statusData?.storage || {} const hasCookie = Boolean(statusData?.hasCookie) const hasPassId = Boolean(statusData?.hasPassId) const cookieCount = statusData?.cookieCount || 0 // 1. MMS 登录状态 if (hasPassId) { mmsStatus.textContent = `已就绪 (包含 PASS_ID,共 ${cookieCount} 项)` mmsStatus.style.color = '#15803d' } else if (hasCookie) { mmsStatus.textContent = `未含 PASS_ID (共 ${cookieCount} 项)` mmsStatus.style.color = '#d97706' } else { mmsStatus.textContent = '未检测到拼多多登录 Cookie' mmsStatus.style.color = '#b91c1c' } // 2. 店铺标识 if (storage.shopName) { shopDisplay.textContent = `${storage.shopName} (${storage.shopId || ''})` } else if (storage.shopId) { shopDisplay.textContent = storage.shopId } else { shopDisplay.textContent = '未配置' } // 3. 上次同步 if (storage.lastSyncAt) { lastSyncDisplay.textContent = formatTime(storage.lastSyncAt) } else { lastSyncDisplay.textContent = '从未同步' } // 4. 订单数 if (storage.totalOrders !== undefined) { orderCountRow.style.display = 'flex' orderCountDisplay.textContent = `${storage.totalOrders} 笔` } else { orderCountRow.style.display = 'none' } // 5. 顶部角标与状态消息 if (!storage.serverUrl || !storage.shopId || !storage.syncToken) { statusBadge.className = 'badge badge-gray' statusBadge.textContent = '待配对' } else if (!hasPassId && !storage.manualCookie) { statusBadge.className = 'badge badge-warn' statusBadge.textContent = '未登录MMS' showMsg('未检测到拼多多后台核心会话 (PASS_ID)。请在当前浏览器登录 mms.pinduoduo.com 并刷新后台页面', 'warn') } else if (storage.lastStatus === 'ok') { statusBadge.className = 'badge badge-ok' statusBadge.textContent = '运行正常' if (storage.lastMessage) { showMsg(storage.lastMessage, 'success') } } else if (storage.lastStatus === 'error') { statusBadge.className = 'badge badge-err' statusBadge.textContent = '同步异常' if (storage.lastMessage) { showMsg(storage.lastMessage, 'error') } } else { statusBadge.className = 'badge badge-gray' statusBadge.textContent = '待同步' } // 填充输入框 inputServerUrl.value = storage.serverUrl || '' inputShopId.value = storage.shopId || '' inputSyncToken.value = storage.syncToken || '' inputManualCookie.value = storage.manualCookie || '' } // 初始化加载状态与日志 chrome.runtime.sendMessage({ action: 'get_status' }, (res) => { refreshStatusView(res) }) refreshLogs() // 切换一键导入框 btnToggleImport.addEventListener('click', (e) => { e.preventDefault() if (importArea.style.display === 'none') { importArea.style.display = 'block' importJsonInput.focus() } else { importArea.style.display = 'none' } }) // 执行一键导入解析 btnApplyImport.addEventListener('click', () => { const raw = importJsonInput.value.trim() if (!raw) return try { const parsed = JSON.parse(raw) if (parsed.serverUrl) inputServerUrl.value = parsed.serverUrl if (parsed.shopId) inputShopId.value = parsed.shopId if (parsed.syncToken) inputSyncToken.value = parsed.syncToken if (parsed.cookie) inputManualCookie.value = parsed.cookie importArea.style.display = 'none' showMsg('配置解析成功,请点击下方【保存配置并重连】生效', 'success') } catch { showMsg('JSON 格式不正确,请确保完整复制管理系统后台弹窗中的配置', 'error') } }) // 保存配置 btnSaveConfig.addEventListener('click', async () => { const serverUrl = inputServerUrl.value.trim() const shopId = inputShopId.value.trim() const syncToken = inputSyncToken.value.trim() const manualCookie = inputManualCookie.value.trim() if (!serverUrl || !shopId || !syncToken) { showMsg('请完整填写服务器地址、店铺标识和配对密钥', 'error') return } await chrome.storage.local.set({ serverUrl, shopId, syncToken, manualCookie, }) showMsg('配置已保存!正在发起加密上传与网关校验...', 'success') triggerSync() }) // 手动触发同步 function triggerSync() { btnSyncNow.disabled = true btnSyncNow.textContent = '正在加密上传...' chrome.runtime.sendMessage({ action: 'trigger_sync' }, (res) => { btnSyncNow.disabled = false btnSyncNow.textContent = '立即上传同步 Cookie' if (res && res.success) { showMsg(res.message || '同步成功!', 'success') } else { showMsg(res?.message || '同步失败,请检查网络或配置', 'error') } // 刷新界面与日志 chrome.runtime.sendMessage({ action: 'get_status' }, (s) => { refreshStatusView(s) }) refreshLogs() }) } btnSyncNow.addEventListener('click', triggerSync) // 复制日志功能 btnCopyLogs.addEventListener('click', async () => { if (!cachedLogs || cachedLogs.length === 0) { alert('当前没有日志可复制') return } const textLines = cachedLogs.map((item) => { const detailStr = item.details ? ` | 详情: ${item.details}` : '' return `[${item.time}] [${item.level.toUpperCase()}] [${item.action}] ${item.message}${detailStr}` }) const fullText = `=== 拼多多保活插件运行日志 (共 ${cachedLogs.length} 条) ===\n` + textLines.join('\n') try { await navigator.clipboard.writeText(fullText) const origText = btnCopyLogs.textContent btnCopyLogs.textContent = '已复制!' setTimeout(() => { btnCopyLogs.textContent = origText }, 1500) } catch (err) { console.error('复制日志到剪贴板失败:', err) alert('复制失败,请手动选择复制') } }) // 清空日志功能 btnClearLogs.addEventListener('click', () => { if (confirm('确定要清空扩展的历史运行日志吗?')) { chrome.runtime.sendMessage({ action: 'clear_logs' }, () => { refreshLogs() }) } }) })