Greasy Fork is available in English.
5倍价格
当前为
// ==UserScript==
// @name 店小蜜价格助手
// @namespace http://tampermonkey.net/
// @version 1.8.0
// @description 5倍价格
// @author Rayu
// @match https://www.dianxiaomi.com/web/shopeeSite/edit*
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// --- 配置项 ---
const HIGHLIGHT_COLOR = 'yellow';
const MULTIPLE_THRESHOLD = 5;
const INCLUDE_EQUAL = true;
const DEBOUNCE_DELAY = 300;
let debounceTimer;
let skuElementsMap = new Map();
function cleanName(name) {
return name ? name.replace(/\s+/g, ' ').trim() : '';
}
/**
* 获取两个主题的信息
* @returns {Object} { theme1: {name, checkboxes}, theme2: {name, checkboxes} }
*/
function getThemesInfo() {
const themeBoxes = document.querySelectorAll('#skuAttrInfo .theme-box');
const themes = [];
themeBoxes.forEach(box => {
const headerTextEl = box.querySelector('.theme-box-header .theme-value-text');
const themeName = headerTextEl ? cleanName(headerTextEl.title || headerTextEl.textContent) : '';
const checkboxes = Array.from(box.querySelectorAll('.checkbox-group input[type="checkbox"]:checked'));
if (themeName && checkboxes.length > 0) {
themes.push({ name: themeName, checkboxes: checkboxes });
}
});
return themes.length >= 2 ? { theme1: themes[0], theme2: themes[1] } : null;
}
/**
* 获取 SKU 数据
*/
function getSkuData() {
const skuData = [];
skuElementsMap.clear();
const headerRow = document.querySelector('#skuDataInfo thead tr');
let theme1ColIndex = -1;
let theme2ColIndex = -1;
let priceColIndex = -1;
if (headerRow) {
const headers = headerRow.querySelectorAll('th');
let themeColCount = 0;
headers.forEach((th, index) => {
const text = cleanName(th.textContent);
if (text.includes('价格')) {
priceColIndex = index;
} else if (themeColCount === 0 && (text.includes('顏色') || text.includes('重量') || text.includes('尺寸') || text.includes('款式') || text.includes('规格'))) {
theme1ColIndex = index;
themeColCount++;
} else if (themeColCount === 1 && (text.includes('顏色') || text.includes('重量') || text.includes('尺寸') || text.includes('款式') || text.includes('规格'))) {
theme2ColIndex = index;
themeColCount++;
}
});
}
if (theme1ColIndex === -1 || theme2ColIndex === -1 || priceColIndex === -1) {
console.error('[Shopee Price Highlighter & Filter] Could not find theme or price columns.');
return [];
}
const dataRows = document.querySelectorAll('#skuDataInfo tbody tr');
dataRows.forEach((row) => {
const cells = row.querySelectorAll('td');
if (cells.length === 0) return;
const theme1Cell = cells[theme1ColIndex];
const theme2Cell = cells[theme2ColIndex];
const priceCell = cells[priceColIndex];
const theme1Value = cleanName(theme1Cell ? theme1Cell.textContent : '');
const theme2Value = cleanName(theme2Cell ? theme2Cell.textContent : '');
const priceInput = priceCell ? priceCell.querySelector('input.g-form-component') : null;
if (!theme1Value || !theme2Value || !priceInput) return;
const price = parseFloat(priceInput.value);
if (!isNaN(price) && price > 0) {
const combinedName = `${theme1Value} ${theme2Value}`;
const data = {
combinedName: combinedName,
theme1Value: theme1Value,
theme2Value: theme2Value,
price: price,
priceInput: priceInput
};
skuData.push(data);
skuElementsMap.set(combinedName, data);
}
});
console.log(`[Shopee Price Highlighter & Filter] Found ${skuData.length} valid SKUs.`);
return skuData;
}
/**
* 高亮价格
*/
function highlightPrices() {
console.log('[Shopee Price Highlighter & Filter] Executing price highlight...');
const skuData = getSkuData();
if (skuData.length === 0) return;
const validPrices = skuData.map(s => s.price).filter(price => !isNaN(price) && price > 0);
if (validPrices.length === 0) {
skuData.forEach(sku => { sku.priceInput.style.backgroundColor = ''; });
return;
}
const minPrice = Math.min(...validPrices);
const thresholdPrice = minPrice * MULTIPLE_THRESHOLD;
console.log(`[Shopee Price Highlighter & Filter] Min Price: ${minPrice}, Threshold: ${thresholdPrice} (${MULTIPLE_THRESHOLD}x)`);
skuData.forEach(sku => {
sku.priceInput.style.backgroundColor = '';
if (!isNaN(sku.price)) {
if (INCLUDE_EQUAL) {
if (sku.price >= thresholdPrice) {
sku.priceInput.style.backgroundColor = HIGHLIGHT_COLOR;
}
} else {
if (sku.price > thresholdPrice) {
sku.priceInput.style.backgroundColor = HIGHLIGHT_COLOR;
}
}
}
});
}
function setCheckboxState(checkboxInput, checked) {
if (!checkboxInput || checkboxInput.checked === checked) return;
checkboxInput.checked = checked;
const event = new Event('change', { bubbles: true });
checkboxInput.dispatchEvent(event);
console.log(`[Shopee Price Highlighter & Filter] Checkbox for "${cleanName(checkboxInput.value)}" set to ${checked}`);
}
/**
* 移除最低价选项
*/
function removeLowestPriceSku() {
const themesInfo = getThemesInfo();
if (!themesInfo) {
alert('无法识别变种主题结构');
return;
}
// 判断哪个主题选项更多
const { theme1, theme2 } = themesInfo;
let targetTheme, otherTheme;
if (theme1.checkboxes.length >= theme2.checkboxes.length) {
targetTheme = theme1;
otherTheme = theme2;
} else {
targetTheme = theme2;
otherTheme = theme1;
}
if (targetTheme.checkboxes.length <= 1) {
alert(`${targetTheme.name}至少需要保留一个选项`);
return;
}
// 计算每个目标选项的最低价格(代表价格)
const optionPrices = new Map();
targetTheme.checkboxes.forEach(checkbox => {
const optionName = cleanName(checkbox.value);
let minPriceForOption = Infinity;
otherTheme.checkboxes.forEach(otherCheckbox => {
const otherOptionName = cleanName(otherCheckbox.value);
// 根据主题顺序组合
let combinedName;
if (targetTheme === theme1) {
combinedName = `${optionName} ${otherOptionName}`;
} else {
combinedName = `${otherOptionName} ${optionName}`;
}
const skuData = skuElementsMap.get(combinedName);
if (skuData && skuData.price < minPriceForOption) {
minPriceForOption = skuData.price;
}
});
if (minPriceForOption !== Infinity) {
optionPrices.set(checkbox, minPriceForOption);
}
});
// 找到最低价的选项
let lowestCheckbox = null;
let lowestPrice = Infinity;
optionPrices.forEach((price, checkbox) => {
if (price < lowestPrice) {
lowestPrice = price;
lowestCheckbox = checkbox;
}
});
if (lowestCheckbox) {
const optionName = cleanName(lowestCheckbox.value);
setCheckboxState(lowestCheckbox, false);
console.log(`[Shopee Price Highlighter & Filter] Removed lowest price option in ${targetTheme.name}: ${optionName} (代表价格: ${lowestPrice})`);
setTimeout(highlightPrices, DEBOUNCE_DELAY);
}
}
/**
* 移除最高价选项
*/
function removeHighestPriceSku() {
const themesInfo = getThemesInfo();
if (!themesInfo) {
alert('无法识别变种主题结构');
return;
}
const { theme1, theme2 } = themesInfo;
let targetTheme, otherTheme;
if (theme1.checkboxes.length >= theme2.checkboxes.length) {
targetTheme = theme1;
otherTheme = theme2;
} else {
targetTheme = theme2;
otherTheme = theme1;
}
if (targetTheme.checkboxes.length <= 1) {
alert(`${targetTheme.name}至少需要保留一个选项`);
return;
}
const optionPrices = new Map();
targetTheme.checkboxes.forEach(checkbox => {
const optionName = cleanName(checkbox.value);
let minPriceForOption = Infinity;
otherTheme.checkboxes.forEach(otherCheckbox => {
const otherOptionName = cleanName(otherCheckbox.value);
let combinedName;
if (targetTheme === theme1) {
combinedName = `${optionName} ${otherOptionName}`;
} else {
combinedName = `${otherOptionName} ${optionName}`;
}
const skuData = skuElementsMap.get(combinedName);
if (skuData && skuData.price < minPriceForOption) {
minPriceForOption = skuData.price;
}
});
if (minPriceForOption !== Infinity) {
optionPrices.set(checkbox, minPriceForOption);
}
});
let highestCheckbox = null;
let highestPrice = -Infinity;
optionPrices.forEach((price, checkbox) => {
if (price > highestPrice) {
highestPrice = price;
highestCheckbox = checkbox;
}
});
if (highestCheckbox) {
const optionName = cleanName(highestCheckbox.value);
setCheckboxState(highestCheckbox, false);
console.log(`[Shopee Price Highlighter & Filter] Removed highest price option in ${targetTheme.name}: ${optionName} (代表价格: ${highestPrice})`);
setTimeout(highlightPrices, DEBOUNCE_DELAY);
}
}
// --- MutationObserver ---
const observerCallback = function(mutationsList, observer) {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
highlightPrices();
}, DEBOUNCE_DELAY);
};
let observerRetryCount = 0;
const maxObserverRetries = 10;
const observerRetryInterval = 500;
function initializeObserver() {
const targetNode = document.getElementById('skuDataInfo');
if (targetNode) {
const config = {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['value']
};
const observer = new MutationObserver(observerCallback);
observer.observe(targetNode, config);
const skuAttrInfoNode = document.getElementById('skuAttrInfo');
if (skuAttrInfoNode) {
const attrConfig = {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['checked']
};
const attrObserver = new MutationObserver(observerCallback);
attrObserver.observe(skuAttrInfoNode, attrConfig);
console.log('[Shopee Price Highlighter & Filter] MutationObserver started for both sections.');
}
console.log('[Shopee Price Highlighter & Filter] MutationObserver initialized.');
highlightPrices();
} else if (observerRetryCount < maxObserverRetries) {
observerRetryCount++;
console.warn(`[Shopee Price Highlighter & Filter] Retrying observer init (${observerRetryCount}/${maxObserverRetries})...`);
setTimeout(initializeObserver, observerRetryInterval);
} else {
console.error('[Shopee Price Highlighter & Filter] Failed to initialize observer.');
}
}
/**
* 添加功能按钮
*/
let addButtonsRetryCount = 0;
const maxAddButtonsRetries = 10;
const addButtonsRetryInterval = 500;
function addFilterButtons() {
if (document.getElementById('skuFilterButtons')) {
console.log('[Shopee Price Highlighter & Filter] Filter buttons already exist.');
return;
}
const targetElementForButtons = document.querySelector("#skuDataInfo > div.form-card-content > div > div > div.mb-20.flex-justify-between");
if (targetElementForButtons) {
const buttonContainer = document.createElement('div');
buttonContainer.id = 'skuFilterButtons';
buttonContainer.style.cssText = 'display: flex; gap: 10px; align-items: center;';
const createButton = (text, onClickHandler) => {
const button = document.createElement('button');
button.className = 'ant-btn ant-btn-default css-1oz1bg8';
button.textContent = text;
button.style.backgroundColor = '#e6f7ff';
button.style.borderColor = '#91d5ff';
button.style.color = '#1890ff';
button.style.minWidth = 'unset';
button.style.padding = '4px 12px';
button.style.height = '32px';
button.addEventListener('click', onClickHandler);
return button;
};
buttonContainer.appendChild(createButton('移除最低价', removeLowestPriceSku));
buttonContainer.appendChild(createButton('移除最高价', removeHighestPriceSku));
targetElementForButtons.appendChild(buttonContainer);
console.log('[Shopee Price Highlighter & Filter] Filter buttons added successfully.');
addButtonsRetryCount = 0;
} else if (addButtonsRetryCount < maxAddButtonsRetries) {
addButtonsRetryCount++;
console.warn(`[Shopee Price Highlighter & Filter] Retrying button addition (${addButtonsRetryCount}/${maxAddButtonsRetries})...`);
setTimeout(addFilterButtons, addButtonsRetryInterval);
} else {
console.error('[Shopee Price Highlighter & Filter] Failed to add filter buttons.');
}
}
// --- 启动脚本 ---
function init() {
initializeObserver();
addFilterButtons();
setTimeout(addFilterButtons, 1500);
setTimeout(highlightPrices, 1500);
setTimeout(addFilterButtons, 4000);
setTimeout(highlightPrices, 4000);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();