/** * Pinduoduo Merchant Page Active Keepalive & Anti-Inactivity Content Script * 拼多多商家后台页面主动保活、防休眠心跳与超时弹窗秒级拦截注入脚本 */ ;(function () { 'use strict' const TAG = '[PDD-KEEPALIVE]' const HEARTBEAT_INTERVAL_MS = 2 * 60 * 1000 // 每 2 分钟执行一次主动心跳与会话续期 const AUTO_RELOAD_INTERVAL_MS = 25 * 60 * 1000 // 每 25 分钟自动平滑刷新一次页面以保证全状态新鲜 let lastUserActivityTime = Date.now() let isReloading = false console.log(`${TAG} 拼多多页面主动保活与防休眠助手已加载:`, window.location.href) // 辅助:向 background 记录运行日志 function reportLog(level, action, message, details = null) { try { chrome.runtime.sendMessage({ action: 'content_log', level, module: '页面保活', actionName: action, message, details, }) } catch { // 忽略通信异常 } } // 1. 监听真实用户操作,记录活跃时间戳 const userEvents = ['mousemove', 'mousedown', 'keydown', 'scroll', 'touchstart'] userEvents.forEach((evt) => { window.addEventListener( evt, () => { lastUserActivityTime = Date.now() }, { passive: true }, ) }) // 2. 模拟轻量用户活动(重置拼多多前端页面的空闲计时器) function dispatchFakeUserActivity() { try { const evt = new MouseEvent('mousemove', { view: window, bubbles: true, cancelable: true, clientX: Math.floor(Math.random() * 200) + 100, clientY: Math.floor(Math.random() * 200) + 100, }) document.dispatchEvent(evt) window.dispatchEvent(new Event('focus')) } catch (e) { console.warn(`${TAG} 模拟微动作异常:`, e) } } // 3. 发送轻量级静默 API 心跳(主动向拼多多服务端续期 PASS_ID 与会话 TTL) async function sendSilentSessionHeartbeat() { try { dispatchFakeUserActivity() // 选择拼多多商家后台最轻量的只读接口进行探测与续期 const endpoints = [ '/mangkhut/mms/recentOrderList?page=1&pageSize=1', '/home/', '/orders/list', ] const targetEndpoint = endpoints[Math.floor(Math.random() * endpoints.length)] const resp = await fetch(targetEndpoint, { method: 'GET', credentials: 'include', headers: { 'X-Requested-With': 'XMLHttpRequest', Accept: 'application/json, text/plain, */*', }, }) if (resp.ok) { console.log(`${TAG} 服务端会话静默续期成功 (${targetEndpoint})`) } else if (resp.status === 401 || resp.status === 403) { reportLog('warn', '会话预警', `页面心跳返回 HTTP ${resp.status},可能需要重新登录`) } } catch (err) { console.warn(`${TAG} 发送静默续期心跳异常:`, err) } } // 4. 实时拦截超时提示遮罩弹窗(秒级自动点击刷新/恢复) function scanAndBustInactivityModal() { if (isReloading) return // 拼多多超时弹窗典型文案特征 const triggerKeywords = [ '当前页面停留时间过长', '为了避免数据延迟', '建议刷新一次页面', '停留时间过长', ] // 查找所有可能的弹窗/Modal 容器 const modalContainers = document.querySelectorAll( '.ant-modal, .pdd-modal, [class*="modal"], [class*="dialog"], [role="dialog"]', ) for (const container of modalContainers) { const text = container.textContent || '' const hasKeyword = triggerKeywords.some((kw) => text.includes(kw)) if (!hasKeyword) continue console.warn(`${TAG} 🚨 捕获到拼多多超时休眠弹窗!立即执行秒级自动恢复...`) reportLog('warn', '弹窗拦截', '捕获到「页面停留时间过长」弹窗,立即自动点击刷新续期会话') // 寻找弹窗内的「刷新」或确定按钮 const buttons = container.querySelectorAll('button, a, [role="button"]') let clicked = false for (const btn of buttons) { const btnText = (btn.textContent || '').trim() if (btnText.includes('刷新') || btnText.includes('确定') || btnText.includes('知道了')) { btn.click() clicked = true console.log(`${TAG} ✅ 已自动触发弹窗内【${btnText}】按钮`) break } } if (!clicked) { // 若未找到合适按钮,直接调用页面无感平滑重载 isReloading = true console.log(`${TAG} 未找到确定按钮,执行 location.reload()`) setTimeout(() => { window.location.reload() }, 500) } return } // 全局文本扫描(兜底非标准 modal 结构) const allDivs = document.querySelectorAll('div') for (const div of allDivs) { if (div.children.length === 0 && div.textContent) { if (div.textContent.includes('当前页面停留时间过长')) { const parent = div.closest('div[style*="z-index"]') || div.parentElement const btn = parent ? parent.querySelector('button') : null if (btn) { console.warn(`${TAG} 兜底捕获超时弹窗,触发点击`) btn.click() } else { isReloading = true window.location.reload() } break } } } } // 5. DOM 变化观察器(毫秒级感知弹窗挂载) const observer = new MutationObserver(() => { scanAndBustInactivityModal() }) if (document.body) { observer.observe(document.body, { childList: true, subtree: true, }) } else { document.addEventListener('DOMContentLoaded', () => { observer.observe(document.body, { childList: true, subtree: true, }) }) } // 6. 定时执行静默会话心跳 setInterval(() => { sendSilentSessionHeartbeat() scanAndBustInactivityModal() }, HEARTBEAT_INTERVAL_MS) // 7. 定时平滑刷新兜底(每 25 分钟:若用户 10 分钟未操作,自动安全刷新当前页面刷新凭证) setInterval(() => { const idleTime = Date.now() - lastUserActivityTime // 如果页面处于静置状态(超过 5 分钟未打字或点击),执行一次平滑刷新保持全局新鲜 if (idleTime > 5 * 60 * 1000 && !isReloading) { console.log(`${TAG} 页面静置已超周期,执行安全平滑重载以更新全量会话凭证`) reportLog('info', '周期刷新', '后台页面静置超 25 分钟,自动平滑重载以保持 Token 绝对新鲜') isReloading = true window.location.reload() } }, AUTO_RELOAD_INTERVAL_MS) // 8. 响应来自 Background 的保活 Ping chrome.runtime.onMessage.addListener((req, _sender, sendResponse) => { if (req.action === 'ping_keepalive') { sendSilentSessionHeartbeat() scanAndBustInactivityModal() sendResponse({ status: 'alive', timestamp: Date.now() }) } }) // 初始化首次扫描与心跳 setTimeout(() => { sendSilentSessionHeartbeat() scanAndBustInactivityModal() reportLog('info', '页面接入', '拼多多商家后台已成功注入主动保活与防退出引擎') }, 3000) })()