// ==UserScript== // @name 京东图书定价查询助手 // @namespace http://tampermonkey.net/ // @version 2.9 // @description 完美兼容详情页无刷新切换商品,自动清理旧标签并重新抓取。 // @author M // @match *://t.jd.com/* // @match *://item.jd.com/* // @grant GM_xmlhttpRequest // @connect item.m.jd.com // ==/UserScript== (function() { 'use strict'; const CONFIG = { FOLLOW: { card: '.item-inner', price: '.p-price' }, ITEM: { anchor: '.product-price-panel' } }; const skuQueue = []; let activeRequests = 0; const CONCURRENCY = 3; let lastItemSku = null; // 🌟 新增:用于记录当前详情页的 SKU function getPageType() { const host = window.location.host; if (host.includes('item.jd.com')) return 'ITEM'; return 'FOLLOW'; } const currentPage = getPageType(); console.log(`🚀 定价全能王 V2.9 启动!当前识别页面类型: ${currentPage}`); function fetchPrice(task) { const {sku, targetContainer} = task; activeRequests++; console.log(`⏳ [抓取中] 正在查询 SKU: ${sku}`); GM_xmlhttpRequest({ method: "GET", url: `https://item.m.jd.com/product/${sku}.html`, timeout: 8000, onload: function(response) { if (response.finalUrl && response.finalUrl.includes('risk_handler')) { console.error(`🚨🚨🚨 触发京东风控!SKU: ${sku} 的请求被拦截到了验证码页面!`); activeRequests--; processQueue(); return; } try { const html = response.responseText; let marketPrice = null; let currentPrice = null; let mMatch = html.match(/"linePrice"\s*:\s*\{[^}]*?"price"\s*:\s*["'](\d+\.\d{1,2})["']/i); if (mMatch) marketPrice = parseFloat(mMatch[1]); let pMatch = html.match(/"jdPrice"\s*:\s*["'](\d+\.\d{1,2})["']/i); if (pMatch) currentPrice = parseFloat(pMatch[1]); if (marketPrice && currentPrice) { const discount = ((currentPrice / marketPrice) * 10).toFixed(2); injectDisplay(targetContainer, marketPrice, discount, sku); } else if (marketPrice) { injectDisplay(targetContainer, marketPrice, null, sku); } else { console.log(`⚠️ SKU:${sku} 没有匹配到定价数据。`); } } catch (e) { console.error(`❌ SKU:${sku} 解析报错`, e); } setTimeout(() => { activeRequests--; processQueue(); }, Math.floor(Math.random() * 2000) + 1500); }, onerror: function() { console.error(`🚨 网络请求彻底失败 (SKU: ${sku})`); activeRequests--; processQueue(); } }); } // 🎨 === 核心 UI 装修区 === 🎨 function injectDisplay(container, mPrice, discount, sku) { if (document.querySelector(`.gemini-tag-${sku}`)) return; const isDetailPage = (currentPage === 'ITEM'); const wrap = document.createElement('span'); wrap.className = `gemini-price-tag gemini-tag-${sku}`; if (isDetailPage) { wrap.style.cssText = "display:inline-block; vertical-align:bottom; margin-left:10px; margin-right:10px; margin-bottom:2px;"; } else { wrap.style.cssText = "display:inline-block;"; } const mSpan = document.createElement('span'); mSpan.style.cssText = `color:#999; font-size:13px; margin-left:8px;`; mSpan.innerText = `定价:¥${mPrice}`; wrap.appendChild(mSpan); if (discount) { const dSpan = document.createElement('span'); dSpan.style.cssText = `color:#f30; margin-left:6px; font-size:13px; font-weight:bold; background:#fff1f1; padding:1px 5px; border-radius:3px; border:1px solid #ff000030;`; dSpan.innerText = `${discount}折`; wrap.appendChild(dSpan); } if (isDetailPage) { const priceGrayElem = document.querySelector('.product-price-gray-line-through'); if (priceGrayElem && priceGrayElem.parentNode) { priceGrayElem.parentNode.insertBefore(wrap, priceGrayElem.nextSibling); console.log(`✅ SKU:${sku} 展示成功!(插在售价后面)`); } else { const commentElem = document.querySelector('.product-price-panel--options-comment'); if (commentElem && commentElem.parentNode) { commentElem.parentNode.insertBefore(wrap, commentElem); console.log(`✅ SKU:${sku} 展示成功!(插在评论前面)`); } else { container.appendChild(wrap); console.log(`✅ SKU:${sku} 展示成功!(兜底插在面板末尾)`); } } } else { container.appendChild(wrap); console.log(`✅ SKU:${sku} 关注页展示成功!`); } } function processQueue() { if (activeRequests >= CONCURRENCY || skuQueue.length === 0) return; while (activeRequests < CONCURRENCY && skuQueue.length > 0) { fetchPrice(skuQueue.shift()); } } function scan() { if (currentPage === 'ITEM') { const anchor = document.querySelector(CONFIG.ITEM.anchor); if (anchor) { const skuMatch = window.location.pathname.match(/\/(\d+)\.html/); if (skuMatch) { const currentUrlSku = skuMatch[1]; // 🌟 核心侦测逻辑:发现页面被无刷新切换了! if (lastItemSku && lastItemSku !== currentUrlSku) { console.log(`🔄 侦测到无刷新切换商品: ${lastItemSku} -> ${currentUrlSku},准备重置...`); // 1. 撕掉旧的标签 const oldTags = document.querySelectorAll('.gemini-price-tag'); oldTags.forEach(tag => tag.remove()); // 2. 砸碎旧的查询锁 anchor.removeAttribute('data-price-fetching'); } // 更新当前记录的 SKU lastItemSku = currentUrlSku; if (!document.querySelector(`.gemini-tag-${currentUrlSku}`) && !anchor.getAttribute('data-price-fetching')) { anchor.setAttribute('data-price-fetching', 'true'); fetchPrice({sku: currentUrlSku, targetContainer: anchor}); } } } } else { const conf = CONFIG.FOLLOW; const cards = document.querySelectorAll(conf.card); cards.forEach(card => { if (card.getAttribute('data-price-queued')) return; const link = card.querySelector('a[href*="jd.com"]'); const priceArea = card.querySelector(conf.price); if (link && priceArea) { const match = link.href.match(/\/(\d{6,15})/); if (match) { card.setAttribute('data-price-queued', 'true'); skuQueue.push({sku: match[1], targetContainer: priceArea}); } } }); processQueue(); } } // 每 2 秒扫描一次地址栏和页面的变化 setInterval(scan, 2000); })();