Files
order_site/apps/extensions/pdd-cookie-sync/popup.js
T

303 lines
10 KiB
JavaScript

/**
* 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 = '<div class="log-empty">暂无运行日志</div>'
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
? `<div style="color: #94a3b8; font-size: 10px; margin-left: 12px;">↳ ${escapeHtml(item.details)}</div>`
: ''
html += `
<div class="log-item">
<span class="log-time">${item.time || ''}</span>
<span class="${tagClass}">${tagText}</span>
<span class="log-action">[${escapeHtml(item.action || '系统')}]</span>
<span>${escapeHtml(item.message || '')}</span>
${detailsHtml}
</div>
`
}
logBox.innerHTML = html
})
}
function escapeHtml(str) {
if (!str) return ''
return String(str)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
}
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()
})
}
})
})