Greasy Fork

Greasy Fork is available in English.

店小蜜5倍价格筛选

5倍价格筛选

当前为 2025-11-12 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         店小蜜5倍价格筛选
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  5倍价格筛选
// @author       Rayu
// @match        https://www.dianxiaomi.com/web/shopeeSite/*
// @exclude      https://www.dianxiaomi.com/web/shopeeSite/edit*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // 等待页面加载完成
    function waitForElement(selector, callback, maxWait = 10000) {
        const startTime = Date.now();
        const interval = setInterval(() => {
            const element = document.querySelector(selector);
            if (element) {
                clearInterval(interval);
                callback();
            } else if (Date.now() - startTime > maxWait) {
                clearInterval(interval);
                console.log('等待元素超时');
            }
        }, 500);
    }

    // ================== 数据持久化缓存模块 ==================
    const CACHE_KEY = 'dianxiaomi_product_cache';
    const CACHE_EXPIRE_DAYS = 7; // 缓存过期天数

    // 缓存管理器
    const CacheManager = {
        // 保存数据到localStorage
        save(data) {
            try {
                const cacheData = {
                    data: data,
                    timestamp: Date.now(),
                    version: '1.0.0'
                };
                localStorage.setItem(CACHE_KEY, JSON.stringify(cacheData));
                console.log('💾 数据已保存到localStorage,当前数量:', data.length);
            } catch (e) {
                console.error('❌ 保存缓存失败:', e);
            }
        },

        // 从localStorage加载数据
        load() {
            try {
                const cached = localStorage.getItem(CACHE_KEY);
                if (!cached) {
                    console.log('📂 未找到缓存数据,初始化为空数组');
                    return [];
                }

                const cacheData = JSON.parse(cached);
                const age = Date.now() - cacheData.timestamp;
                const ageDays = Math.floor(age / (1000 * 60 * 60 * 24));

                console.log(`📂 加载缓存数据: ${cacheData.data.length} 条记录`);
                console.log(`⏰ 缓存时间: ${ageDays} 天前`);

                return cacheData.data || [];
            } catch (e) {
                console.error('❌ 加载缓存失败:', e);
                return [];
            }
        },

        // 清除所有缓存
        clear() {
            try {
                localStorage.removeItem(CACHE_KEY);
                console.log('🗑️ 已清除localStorage中的所有缓存');
            } catch (e) {
                console.error('❌ 清除缓存失败:', e);
            }
        },

        // 清理过期缓存(超过7天)
        cleanExpired() {
            try {
                const cached = localStorage.getItem(CACHE_KEY);
                if (!cached) return;

                const cacheData = JSON.parse(cached);
                const age = Date.now() - cacheData.timestamp;
                const ageDays = age / (1000 * 60 * 60 * 24);

                if (ageDays > CACHE_EXPIRE_DAYS) {
                    this.clear();
                    console.log(`🧹 自动清理 ${Math.floor(ageDays)} 天前的过期缓存`);
                    return true;
                }
                return false;
            } catch (e) {
                console.error('❌ 清理过期缓存失败:', e);
                return false;
            }
        },

        // 获取缓存信息
        getInfo() {
            try {
                const cached = localStorage.getItem(CACHE_KEY);
                if (!cached) {
                    return { exists: false, count: 0, ageDays: 0 };
                }

                const cacheData = JSON.parse(cached);
                const age = Date.now() - cacheData.timestamp;
                const ageDays = Math.floor(age / (1000 * 60 * 60 * 24));

                return {
                    exists: true,
                    count: cacheData.data?.length || 0,
                    ageDays: ageDays,
                    timestamp: cacheData.timestamp
                };
            } catch (e) {
                console.error('❌ 获取缓存信息失败:', e);
                return { exists: false, count: 0, ageDays: 0 };
            }
        }
    };

    // 页面加载时自动清理过期缓存
    CacheManager.cleanExpired();

    // 从localStorage加载已缓存的数据
    let capturedApiData = CacheManager.load();

    // 将capturedApiData和缓存管理器暴露到全局作用域
    window.capturedApiData = capturedApiData;
    window.CacheManager = CacheManager;

    console.log('🚀 API拦截器已启动');
    console.log('💡 提示: 可以在控制台使用 window.capturedApiData 或 capturedApiData 访问捕获的数据');

    // 公共函数:添加悬停效果
    function addHoverEffect(element, hoverColor, normalColor) {
        element.addEventListener('mouseenter', function() {
            this.style.backgroundColor = hoverColor;
        });
        element.addEventListener('mouseleave', function() {
            this.style.backgroundColor = normalColor;
        });
    }

    // 拦截XMLHttpRequest
    const originalXHROpen = XMLHttpRequest.prototype.open;
    const originalXHRSend = XMLHttpRequest.prototype.send;

    XMLHttpRequest.prototype.open = function(method, url) {
        this._url = url;
        this._method = method;
        return originalXHROpen.apply(this, arguments);
    };

    XMLHttpRequest.prototype.send = function(body) {
        const xhr = this;
        const requestBody = body;

        this.addEventListener('load', function() {
            try {
                if (this._url && this.responseText) {
                    // 检查是否是目标API
                    const isTargetApi = this._url.includes('shopeeProduct') ||
                                       this._url.includes('getProductById');


                    if (isTargetApi) {
                        console.log('🎯 捕获到目标API (XHR):', this._url);
                    }


                    // 尝试解析JSON响应
                    const data = JSON.parse(this.responseText);
                    console.log('🔍 XHR请求:', this._url);
                    console.log('📦 响应数据:', data);


                    capturedApiData.push({
                        url: this._url,
                        method: 'XHR',
                        data: data,
                        timestamp: new Date().toISOString()
                    });

                    // 自动保存到localStorage
                    CacheManager.save(capturedApiData);

                    if (isTargetApi) {
                        console.log('✅ 已保存到 capturedApiData,当前总数:', capturedApiData.length);
                    }


                }
            } catch (e) {
                // 忽略非JSON响应
                if (this._url && (this._url.includes('shopeeProduct') || this._url.includes('getProductById'))) {
                    console.error('❌ 解析目标API响应失败:', this._url, e);
                }
            }
        });

        this.addEventListener('error', function() {
            console.error('❌ XHR请求失败:', this._url);
        });

        return originalXHRSend.apply(this, arguments);
    };

    // 拦截fetch
    const originalFetch = window.fetch;
    window.fetch = function() {
        const url = arguments[0];
        const isTargetApi = typeof url === 'string' &&
                           (url.includes('shopeeProduct') || url.includes('getProductById'));


        if (isTargetApi) {
            console.log('🎯 准备发起目标API请求 (Fetch):', url);
        }


        return originalFetch.apply(this, arguments).then(response => {
            // 克隆响应以便读取
            const clonedResponse = response.clone();

            clonedResponse.json().then(data => {
                console.log('🔍 Fetch请求:', url);
                console.log('📦 响应数据:', data);


                capturedApiData.push({
                    url: url,
                    method: 'Fetch',
                    data: data,
                    timestamp: new Date().toISOString()
                });

                // 自动保存到localStorage
                CacheManager.save(capturedApiData);

                if (isTargetApi) {
                    console.log('✅ 已保存到 capturedApiData,当前总数:', capturedApiData.length);
                }
            }).catch((e) => {
                // 忽略非JSON响应
                if (isTargetApi) {
                    console.error('❌ 解析目标API响应失败:', url, e);
                }
            });

            return response;
        }).catch(error => {
            console.error('❌ Fetch请求失败:', url, error);
            throw error;
        });
    };

    // 从API数据中提取商品信息(新格式)
    function extractProductInfo() {
        const products = [];
        console.log('开始从API数据中提取商品信息...');
        console.log(`已捕获 ${capturedApiData.length} 个API请求`);

        // 遍历所有捕获的API数据
        capturedApiData.forEach((apiCall, index) => {
            console.log(`\n处理API请求 ${index + 1}:`, apiCall.url);

            // 判断API类型
            const isGetProductById = apiCall.url.includes('getProductById');
            console.log(`🔖 API类型: ${isGetProductById ? 'getProductById (规格列表)' : 'pageList (商品列表)'}`);

            // 如果是getProductById API,直接提取variations数组
            if (isGetProductById && apiCall.data && apiCall.data.data && Array.isArray(apiCall.data.data)) {
                console.log(`📦 发现 getProductById 数据,包含 ${apiCall.data.data.length} 个规格`);

                // 从第一个variation中获取商品基本信息
                const firstVariation = apiCall.data.data[0];
                if (firstVariation) {
                    const product = {
                        name: firstVariation.dxmProductName || '(从规格数据获取)',
                        id: firstVariation.dxmProductId || firstVariation.id, // 保留原始ID用于数据合并
                        idStr: firstVariation.idStr || firstVariation.id, // 用于UI显示
                        dxmProductId: firstVariation.dxmProductId || firstVariation.id,
                        specifications: []
                    };

                    // 提取所有规格
                    apiCall.data.data.forEach((variation, vIndex) => {
                        // 组合 option1 和 option2
                        const optionText = [variation.option1, variation.option2].filter(Boolean).join(' - ');
                        console.log(`  [${vIndex + 1}] ${optionText}: ¥${variation.price} (idStr: ${variation.idStr || '无'})`);
                        if ((variation.option1 !== undefined || variation.option2 !== undefined) && variation.price !== undefined) {
                            product.specifications.push({
                                option: optionText,
                                price: variation.price,
                                idStr: variation.idStr || variation.id
                            });
                        }
                    });

                    if (product.specifications.length > 0) {
                        console.log(`✅ 从 getProductById 提取商品: ${product.name} (DXM ID: ${product.dxmProductId})`);
                        console.log(`   └─ 规格数量: ${product.specifications.length}`);
                        products.push(product);
                    }
                }

                // getProductById API处理完毕,跳过递归查找
                return;
            }

            // 对于pageList API,使用递归查找
            // 递归查找数据中的商品信息
            function findProducts(obj, path = '') {
                if (!obj || typeof obj !== 'object') return;

                // 检查当前对象是否包含商品信息(必须有name和id)
                if (obj.name && obj.id) {
                    console.log(`\n🔍 发现潜在商品对象: ${obj.name} (ID: ${obj.id})`);
                    console.log(`  ├─ 路径: ${path}`);
                    console.log(`  ├─ idStr: ${obj.idStr || '无'}`);
                    console.log(`  ├─ dxmProductId: ${obj.dxmProductId || '无'}`);
                    console.log(`  ├─ variations 类型: ${Array.isArray(obj.variations) ? '数组' : typeof obj.variations}`);
                    console.log(`  └─ variations 长度: ${Array.isArray(obj.variations) ? obj.variations.length : 'N/A'}`);

                    const product = {
                        name: obj.name,
                        id: obj.id, // 保留原始ID用于数据合并
                        idStr: obj.idStr || obj.id, // 用于UI显示
                        dxmProductId: obj.idStr || obj.dxmProductId || obj.id, // 优先使用idStr
                        specifications: []
                    };

                    // 提取variations数组
                    if (Array.isArray(obj.variations)) {
                        console.log(`  📦 开始处理 ${obj.variations.length} 个 variations...`);
                        obj.variations.forEach((variation, vIndex) => {
                            // 组合 option1 和 option2
                            const optionText = [variation.option1, variation.option2].filter(Boolean).join(' - ');
                            console.log(`    [${vIndex + 1}] option1=${variation.option1}, option2=${variation.option2 || '无'}, price=${variation.price}, dxmProductId=${variation.dxmProductId || '无'}`);
                            if ((variation.option1 !== undefined || variation.option2 !== undefined) && variation.price !== undefined) {
                                product.specifications.push({
                                    option: optionText,
                                    price: variation.price
                                });
                            }
                        });
                        console.log(`  ✅ 成功提取 ${product.specifications.length} 个规格`);
                    } else {
                        console.log(`  ⚠️ variations 不是数组或不存在`);
                        // 输出整个对象的键,帮助调试
                        console.log(`  📋 对象的所有键:`, Object.keys(obj).join(', '));
                    }

                    // dxmProductId已在创建product时设置(优先级:idStr > dxmProductId > id)
                    console.log(`  ✓ 使用的 dxmProductId: ${product.dxmProductId}`);

                    // 只有当有规格数据时才添加商品
                    if (product.specifications.length > 0) {
                        console.log(`✓ 找到商品: ${product.name} (ID: ${product.id}, DXM ID: ${product.dxmProductId || '无'})`);
                        console.log(`  └─ 规格数量: ${product.specifications.length}`);
                        console.log(`  └─ 路径: ${path}`);
                        products.push(product);
                        console.log(`  ⚙️ 调试模式: 继续递归查找所有嵌套对象`);
                    } else {
                        console.log(`  ❌ 该商品没有有效的规格数据,跳过`);
                    }
                }

                // 递归遍历对象和数组
                if (Array.isArray(obj)) {
                    obj.forEach((item, idx) => findProducts(item, `${path}[${idx}]`));
                } else {
                    // 遍历对象的所有属性
                    for (let key in obj) {
                        if (obj.hasOwnProperty(key)) {
                            findProducts(obj[key], path ? `${path}.${key}` : key);
                        }
                    }
                }
            }

            findProducts(apiCall.data);
        });

        console.log(`\n共找到 ${products.length} 个商品(去重前)`);

        // 去重:合并相同ID的商品数据
        const productMap = new Map();
        products.forEach(product => {
            const key = product.id; // 使用原始ID作为唯一标识符

            if (productMap.has(key)) {
                // 如果已存在该商品,合并规格数据
                const existing = productMap.get(key);
                console.log(`🔄 发现重复商品: ${product.name} (ID: ${key})`);
                console.log(`   合并前规格数量: ${existing.specifications.length}`);
                console.log(`   待合并规格数量: ${product.specifications.length}`);

                // 合并规格数组(去重相同option的规格)
                const specMap = new Map();
                existing.specifications.forEach(spec => {
                    specMap.set(spec.option, spec);
                });
                product.specifications.forEach(spec => {
                    if (!specMap.has(spec.option)) {
                        specMap.set(spec.option, spec);
                    }
                });

                existing.specifications = Array.from(specMap.values());
                console.log(`   合并后规格数量: ${existing.specifications.length}`);
            } else {
                // 首次出现该商品,直接添加
                productMap.set(key, product);
            }
        });

        const mergedProducts = Array.from(productMap.values());
        console.log(`\n✅ 去重后共 ${mergedProducts.length} 个商品`);

        return mergedProducts;
    }

    // 显示商品数据
    function displayProductData(products) {
        console.log('\n=== 商品信息数据 ===');
        console.log(`共找到 ${products.length} 个商品`);

        console.log('\n详细列表:');
        products.forEach((product, index) => {
            console.log(`${index + 1}. 商品: ${product.name}`);
            console.log(`   ID: ${product.id}`);
            console.log(`   DXM ID: ${product.dxmProductId}`);
            console.log(`   规格数量: ${product.specifications.length} 个`);

            product.specifications.forEach((spec, sIndex) => {
                console.log(`   [${sIndex + 1}] ${spec.option}: ${spec.price}`);
            });
            console.log('---');
        });

        return products;
    }

    // ⭐ [新增] 自动滚动并勾选高价差商品的函数
    async function selectHighPriceProducts() {
        console.log('🔘 一键勾选按钮被点击');
        const btn = document.getElementById('dianxiaomi-select-high-price-btn');
        if (!btn) {
            console.error('❌ 未找到一键勾选按钮元素');
            return;
        }

        // 检查是否存在商品数据
        if (!window.dianxiaomiProductData || window.dianxiaomiProductData.length === 0) {
            console.warn('⚠️ 商品数据不存在');
            alert('请先点击"手动获取"按钮加载商品数据!');
            return;
        }

        console.log(`📊 当前商品数据数量: ${window.dianxiaomiProductData.length}`);
        btn.disabled = true;
        btn.textContent = '🔄 正在勾选...';

        // 筛选出所有高价差商品
        const highPriceProducts = window.dianxiaomiProductData.filter(product => {
            if (!product.specifications || product.specifications.length <= 1) return false;
            const prices = product.specifications.map(s => parseFloat(s.price)).filter(p => p > 0);
            if (prices.length <= 1) return false;
            const minPrice = Math.min(...prices);
            const maxPrice = Math.max(...prices);
            return (maxPrice / minPrice) > 5;
        });

        if (highPriceProducts.length === 0) {
            alert('未在当前列表中找到高价差商品。');
            btn.disabled = false;
            btn.textContent = `✔️ 一键勾选 (0)`;
            return;
        }

        console.log(`准备勾选 ${highPriceProducts.length} 个高价差商品...`);

        // 寻找页面上的表格容器
        const tableWrapper = document.querySelector('.vxe-table--body-wrapper');
        if (!tableWrapper) {
            alert('错误:无法在页面上找到商品表格,无法执行勾选操作。');
            btn.disabled = false;
            btn.textContent = `✔️ 一键勾选 (${highPriceProducts.length})`;
            return;
        }

        // 滚动回页面顶部
        window.scrollTo({ top: 0, behavior: 'auto' });
        await new Promise(resolve => setTimeout(resolve, 300));
        console.log('🔝 已滚动回页面顶部,开始一次性滚动查找所有商品...');

        // 创建商品名称集合用于快速查找
        const productNames = new Set(highPriceProducts.map(p => p.name));
        const foundRows = new Map(); // 存储找到的商品行:商品名称 -> 行元素

        // 滚动参数配置
        const scrollSpeed = 200; // 每次滚动像素数
        const scrollInterval = 5; // 每次滚动间隔(毫秒)
        const maxScrolls = 500; // 最大滚动次数

        let scrollCount = 0;
        btn.textContent = `🔄 滚动查找中...`;

        // 一次性从头到尾滚动页面,收集所有目标商品行
        while (scrollCount < maxScrolls && foundRows.size < highPriceProducts.length) {
            // 获取当前页面中所有的商品行
            const allRows = document.querySelectorAll('.vxe-table--body-wrapper table tbody tr');

            // 在当前可视区域查找包含目标商品名称的行
            for (const row of allRows) {
                const rect = row.getBoundingClientRect();
                const windowHeight = window.innerHeight;

                // 判断行是否在浏览器窗口可视区域内
                const isVisible = rect.top >= 0 && rect.top <= windowHeight && rect.bottom >= 0 && rect.bottom <= windowHeight;

                if (isVisible) {
                    const rowText = row.textContent;
                    // 检查是否包含任何目标商品名称
                    for (const productName of productNames) {
                        if (rowText.includes(productName) && !foundRows.has(productName)) {
                            foundRows.set(productName, row);
                            console.log(`✅ 找到目标商品(第 ${scrollCount + 1} 次滚动): ${productName}`);
                            btn.textContent = `🔄 已找到 ${foundRows.size}/${highPriceProducts.length}`;
                            break;
                        }
                    }
                }
            }

            // 如果已找到所有商品,停止滚动
            if (foundRows.size >= highPriceProducts.length) {
                console.log('✅ 已找到所有目标商品,停止滚动');
                break;
            }

            // 使用 window.scrollBy 进行真实页面滚动
            window.scrollBy({
                top: scrollSpeed,
                behavior: 'auto'
            });

            await new Promise(resolve => setTimeout(resolve, scrollInterval));
            scrollCount++;

            // 检查是否已滚动到页面底部
            const scrollHeight = document.documentElement.scrollHeight;
            const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
            const clientHeight = window.innerHeight;

            if (scrollTop + clientHeight >= scrollHeight - 10) {
                console.log('⚠️ 已滚动到页面底部');
                break;
            }
        }

        console.log(`\n📋 滚动完成,共找到 ${foundRows.size}/${highPriceProducts.length} 个商品,开始勾选...`);

        // 统一勾选所有找到的商品
        let successCount = 0;
        let notFoundCount = highPriceProducts.length - foundRows.size;

        for (let i = 0; i < highPriceProducts.length; i++) {
            const product = highPriceProducts[i];
            const targetRow = foundRows.get(product.name);

            btn.textContent = `🔄 勾选中(${i + 1}/${highPriceProducts.length})`;

            if (targetRow) {
                try {
                    // 查找并点击复选框
                    const checkbox = targetRow.querySelector('.ant-checkbox-input');
                    if (checkbox) {
                        checkbox.click();
                        successCount++;
                        console.log(`✅ 已勾选 (${successCount}/${foundRows.size}): ${product.name}`);
                        await new Promise(resolve => setTimeout(resolve, 50));
                    } else {
                        console.warn(`❌ 在行内未找到复选框: ${product.name}`);
                        notFoundCount++;
                        successCount--;
                    }
                } catch (e) {
                    console.error(`❌ 勾选商品时发生错误: ${product.name}`, e);
                    notFoundCount++;
                }
            } else {
                console.warn(`⚠️ 未找到商品: ${product.name}`);
            }
        }

        alert(`勾选完成!\n\n成功勾选: ${successCount} 个\n未找到或失败: ${notFoundCount} 个`);
        console.log(`勾选操作完成。成功: ${successCount}, 失败/未找到: ${notFoundCount}`);

        btn.disabled = false;
        btn.textContent = `✅ 已完成`;
        setTimeout(() => {
            btn.textContent = `✔️ 一键勾选 (${highPriceProducts.length})`;
        }, 5000);
    }

    // 创建浮动窗口UI
    function createFloatingPanel() {
        // 创建容器
        const panel = document.createElement('div');
        panel.id = 'dianxiaomi-price-panel';
        panel.style.cssText = `
            position: fixed;
            top: 10px;
            right: 10px;
            width: 400px;
            max-height: 600px;
            background: white;
            border: 2px solid #1890ff;
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            z-index: 999999;
            font-family: Arial, sans-serif;
            overflow: hidden;
            display: flex;
            flex-direction: column;
        `;

        // 创建标题栏
        const header = document.createElement('div');
        header.style.cssText = `
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 12px 15px;
            font-weight: bold;
            font-size: 16px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            cursor: move;
        `;
        header.innerHTML = `
            <span>📊 商品价格数据</span>
            <button id="dianxiaomi-close-btn" style="
                background: rgba(255,255,255,0.2);
                border: none;
                color: white;
                cursor: pointer;
                padding: 4px 8px;
                border-radius: 4px;
                font-size: 18px;
                line-height: 1;
            ">×</button>
        `;

        // 创建工具栏
        const toolbar = document.createElement('div');
        toolbar.style.cssText = `
            padding: 10px 15px;
            background: #f5f5f5;
            border-bottom: 1px solid #e0e0e0;
            display: flex;
            gap: 10px;
            align-items: center;
        `;
        toolbar.innerHTML = `
            <button id="dianxiaomi-refresh-btn" style="
                background: #1890ff;
                color: white;
                border: none;
                padding: 8px 16px;
                border-radius: 4px;
                cursor: pointer;
                font-size: 14px;
                font-weight: 500;
                transition: background 0.3s;
            ">🔄 手动获取</button>
            <button id="dianxiaomi-clear-btn" style="
                background: #ff4d4f;
                color: white;
                border: none;
                padding: 8px 16px;
                border-radius: 4px;
                cursor: pointer;
                font-size: 14px;
                font-weight: 500;
                transition: background 0.3s;
            ">🗑️ 清除缓存</button>
            <button id="dianxiaomi-select-high-price-btn" style="
                background: #52c41a;
                color: white;
                border: none;
                padding: 8px 16px;
                border-radius: 4px;
                cursor: pointer;
                font-size: 14px;
                font-weight: 500;
                transition: background 0.3s;
                display: none; /* 默认隐藏 */
            ">✔️ 一键勾选</button>
            <span id="dianxiaomi-status" style="
                flex-grow: 1;
                text-align: right;
                color: #666;
                font-size: 14px;
            ">准备就绪</span>
        `;

        // 创建内容区域
        const content = document.createElement('div');
        content.id = 'dianxiaomi-content';
        content.style.cssText = `
            flex: 1;
            overflow-y: auto;
            padding: 15px;
            max-height: 500px;
        `;
        content.innerHTML = '<div style="color: #999; text-align: center; padding: 40px 20px;">点击"手动获取"按钮开始获取数据</div>';

        // 组装面板
        panel.appendChild(header);
        panel.appendChild(toolbar);
        panel.appendChild(content);
        document.body.appendChild(panel);

        // 添加拖拽功能
        let isDragging = false;
        let currentX;
        let currentY;
        let initialX;
        let initialY;

        header.addEventListener('mousedown', (e) => {
            if (e.target.id === 'dianxiaomi-close-btn') return;
            isDragging = true;
            initialX = e.clientX - panel.offsetLeft;
            initialY = e.clientY - panel.offsetTop;
        });

        document.addEventListener('mousemove', (e) => {
            if (isDragging) {
                e.preventDefault();
                currentX = e.clientX - initialX;
                currentY = e.clientY - initialY;
                panel.style.left = currentX + 'px';
                panel.style.top = currentY + 'px';
                panel.style.right = 'auto';
            }
        });

        document.addEventListener('mouseup', () => {
            isDragging = false;
        });

        // 关闭按钮事件
        document.getElementById('dianxiaomi-close-btn').addEventListener('click', () => {
            panel.style.display = 'none';
        });

        // 刷新按钮事件
        document.getElementById('dianxiaomi-refresh-btn').addEventListener('click', () => {
            updatePanelData(true); // 自动展开
        });

        // 清除缓存按钮事件
        document.getElementById('dianxiaomi-clear-btn').addEventListener('click', () => {
            // 清空内存中的数组
            capturedApiData.length = 0;

            // 清除localStorage中的缓存
            CacheManager.clear();

            console.log('🗑️ 已清除所有缓存数据(内存 + localStorage)');
            console.log('💡 当前 capturedApiData.length =', window.capturedApiData.length);

            const contentEl = document.getElementById('dianxiaomi-content');
            const statusEl = document.getElementById('dianxiaomi-status');

            contentEl.innerHTML = '<div style="color: #52c41a; text-align: center; padding: 40px 20px;">✓ 缓存已清除<br/><small style="color: #999;">内存和localStorage数据已全部清空</small><br/><small style="color: #999;">点击"手动获取"重新加载数据</small></div>';
            statusEl.textContent = '缓存已清除';
            statusEl.style.color = '#52c41a';

            // 隐藏勾选按钮
            document.getElementById('dianxiaomi-select-high-price-btn').style.display = 'none';
        });

        // ⭐ [新增] 一键勾选按钮事件
        const selectHighPriceBtn = document.getElementById('dianxiaomi-select-high-price-btn');
        if (selectHighPriceBtn) {
            selectHighPriceBtn.addEventListener('click', selectHighPriceProducts);
            console.log('✅ 一键勾选按钮事件已绑定');
        } else {
            console.error('❌ 一键勾选按钮元素不存在,无法绑定事件');
        }

        // 鼠标悬停效果
        addHoverEffect(document.getElementById('dianxiaomi-refresh-btn'), '#40a9ff', '#1890ff');
        addHoverEffect(document.getElementById('dianxiaomi-clear-btn'), '#ff7875', '#ff4d4f');
        addHoverEffect(document.getElementById('dianxiaomi-select-high-price-btn'), '#73d13d', '#52c41a');

        return panel;
    }

    // 自动收起所有商品
    async function collapseAllProducts() {
        console.log('🔽 开始收起所有商品...');

        // 定义所有可能的选择器(与展开相同)
        const selectors = [
            'td.col_10 span.link',
            'td[class*="col_10"] span.link',
            '.vxe-body--column.col_10 span.link',
            'span.link'
        ];

        // 循环尝试所有选择器,找到第一个有结果的
        let collapseButtons = [];
        for (const selector of selectors) {
            collapseButtons = document.querySelectorAll(selector);
            if (collapseButtons.length > 0) break;
        }

        console.log(`✓ 找到 ${collapseButtons.length} 个潜在收起按钮`);

        if (collapseButtons.length === 0) {
            console.log('⚠️ 未找到收起按钮');
            return 0;
        }

        let collapsedCount = 0;

        // 批量点击所有收起按钮(使用真实的鼠标事件模拟)
        const clickPromises = [];
        for (let i = 0; i < collapseButtons.length; i++) {
            const button = collapseButtons[i];

            // 检查按钮是否可见且可点击
            if (button && button.offsetParent !== null) {
                try {
                    // 模拟真实的鼠标事件序列
                    const eventConfig = {
                        view: window,
                        bubbles: true,
                        cancelable: true,
                        button: 0
                    };
                    ['mousedown', 'mouseup', 'click'].forEach(eventType => {
                        button.dispatchEvent(new MouseEvent(eventType, eventConfig));
                    });

                    collapsedCount++;

                    if (i < 3) {
                        console.log(`✓ 已触发第 ${i + 1} 个收起按钮`);
                    }

                    // 每10个按钮后稍微延迟一下,给浏览器处理时间
                    if (collapsedCount % 10 === 0) {
                        clickPromises.push(new Promise(resolve => setTimeout(resolve, 100)));
                    }
                } catch (e) {
                    console.error(`❌ 收起第 ${i + 1} 个商品失败:`, e);
                }
            }
        }

        console.log(`✓ 已触发 ${collapsedCount} 个收起按钮(模拟点击事件)`);

        // 等待所有点击延迟完成
        await Promise.all(clickPromises);

        // 等待收起动画完成
        await new Promise(resolve => setTimeout(resolve, 500));

        console.log(`✅ 成功收起 ${collapsedCount} 个商品`);

        return collapsedCount;
    }

    // 自动展开所有商品
    async function expandAllProducts() {
        console.log('🔍 开始查找展开按钮...');

        // 定义所有可能的选择器
        const selectors = [
            'td.col_10 span.link',
            'td[class*="col_10"] span.link',
            '.vxe-body--column.col_10 span.link',
            'span.link'
        ];

        // 循环尝试所有选择器,找到第一个有结果的
        let expandButtons = [];
        for (const selector of selectors) {
            expandButtons = document.querySelectorAll(selector);
            if (expandButtons.length > 0) break;
        }

        console.log(`✓ 找到 ${expandButtons.length} 个潜在展开按钮`);

        if (expandButtons.length === 0) {
            console.log('⚠️ 未找到展开按钮');
            return 0;
        }

        // 输出第一个按钮的详细信息用于调试
        if (expandButtons.length > 0) {
            const firstButton = expandButtons[0];
            console.log('📋 第一个按钮详情:');
            console.log('  - 标签:', firstButton.tagName);
            console.log('  - 类名:', firstButton.className);
            console.log('  - 内容:', firstButton.textContent?.trim() || '无文本');
            console.log('  - 父元素:', firstButton.parentElement?.tagName);
            console.log('  - HTML:', firstButton.outerHTML.substring(0, 200));
        }

        // 记录展开前的API数据数量
        const beforeApiCount = capturedApiData.length;
        console.log(`📊 展开前已捕获 ${beforeApiCount} 个API请求`);

        let expandedCount = 0;

        // 批量点击所有展开按钮(使用真实的鼠标事件模拟)
        const clickPromises = [];
        for (let i = 0; i < expandButtons.length; i++) {
            const button = expandButtons[i];

            // 检查按钮是否可见且可点击
            if (button && button.offsetParent !== null) {
                try {
                    // 模拟真实的鼠标事件序列
                    const eventConfig = {
                        view: window,
                        bubbles: true,
                        cancelable: true,
                        button: 0
                    };
                    ['mousedown', 'mouseup', 'click'].forEach(eventType => {
                        button.dispatchEvent(new MouseEvent(eventType, eventConfig));
                    });

                    expandedCount++;

                    if (i < 3) {
                        console.log(`✓ 已触发第 ${i + 1} 个展开按钮`);
                    }

                    // 每10个按钮后稍微延迟一下,给浏览器处理时间
                    if (expandedCount % 10 === 0) {
                        clickPromises.push(new Promise(resolve => setTimeout(resolve, 200)));
                    }
                } catch (e) {
                    console.error(`❌ 展开第 ${i + 1} 个商品失败:`, e);
                }
            }
        }

        console.log(`✓ 已触发 ${expandedCount} 个展开按钮(模拟点击事件)`);

        // 等待所有点击延迟完成
        await Promise.all(clickPromises);

        // 等待API请求完成(优化为更短的等待时间)
        const waitTime = Math.max(1000, expandedCount * 80); // 最少1秒,每个商品80ms
        console.log(`⏳ 等待 ${waitTime}ms 让API请求完成...`);

        // 分段检查API请求数量(减少检查次数,更快响应)
        for (let i = 0; i < 2; i++) {
            await new Promise(resolve => setTimeout(resolve, waitTime / 2));
            const currentApiCount = capturedApiData.length;
            const newCount = currentApiCount - beforeApiCount;
            if (newCount > 0) {
                console.log(`  ✓ 已捕获 ${newCount} 个新API请求...`);
            }
        }

        // 检查是否捕获到新的API数据
        const afterApiCount = capturedApiData.length;
        const newApiCount = afterApiCount - beforeApiCount;
        console.log(`📊 展开后共捕获 ${afterApiCount} 个API请求(新增 ${newApiCount} 个)`);

        if (newApiCount === 0) {
            console.log('⚠️ 警告:展开后未捕获到新的API请求!');
        } else {
            console.log(`✓ 成功捕获到 ${newApiCount} 个新的API请求`);
        }

        return expandedCount;
    }

    // ⭐ [新增] 展开并获取数据后自动收起
    async function expandAndCollapse() {
        console.log('🔄 开始展开获取数据流程...');

        // 先展开所有商品
        const expandedCount = await expandAllProducts();

        if (expandedCount > 0) {
            console.log(`✅ 已展开 ${expandedCount} 个商品,等待数据获取完成...`);

            // 等待一段时间确保数据获取完成
            await new Promise(resolve => setTimeout(resolve, 1000));

            // 收起所有商品
            const collapsedCount = await collapseAllProducts();
            console.log(`✅ 已收起 ${collapsedCount} 个商品,恢复到未展开状态`);

            return { expandedCount, collapsedCount };
        } else {
            console.log('⚠️ 未能展开商品,跳过收起操作');
            return { expandedCount: 0, collapsedCount: 0 };
        }
    }

    // 更新面板数据
    async function updatePanelData(autoExpand = true) {
        const statusEl = document.getElementById('dianxiaomi-status');
        const contentEl = document.getElementById('dianxiaomi-content');

        // 如果启用自动展开
        if (autoExpand) {
            statusEl.textContent = '正在处理...';
            statusEl.style.color = '#ff9800';

            // 使用新的展开并收起功能
            const result = await expandAndCollapse();

            if (result.expandedCount === 0) {
                statusEl.textContent = '未找到可展开的商品';
                statusEl.style.color = '#ff4d4f';
                return;
            }
        }

        statusEl.textContent = '正在获取数据...';
        statusEl.style.color = '#1890ff';

        setTimeout(() => {
            const productData = extractProductInfo();
            displayProductData(productData);
            window.dianxiaomiProductData = productData;

            // 更新UI显示
            if (productData.length === 0) {
                contentEl.innerHTML = '<div style="color: #ff4d4f; text-align: center; padding: 40px 20px;">⚠️ 未找到商品数据<br/><small style="color: #999;">请确保页面已加载完成</small></div>';
                statusEl.textContent = '未找到数据';
                statusEl.style.color = '#ff4d4f';
            } else {
                const totalSpecs = productData.reduce((sum, p) => sum + p.specifications.length, 0);
                // 统计高价差商品数量
                let highPriceRatioCount = 0;

                let html = `
                    <div style="margin-bottom: 10px; padding: 10px; background: #e6f7ff; border-radius: 4px; border-left: 3px solid #1890ff;">
                        <strong style="color: #1890ff;">✓ 成功获取 ${productData.length} 个商品,共 ${totalSpecs} 个规格</strong>
                    </div>
                    <div style="font-size: 12px; color: #666; margin-bottom: 10px; display: flex; align-items: center; gap: 12px;">
                        <span>最新更新: ${new Date().toLocaleTimeString()}</span>
                    </div>
                `;

                productData.forEach((item, index) => {
                    // 计算最低价和最高价
                    let minPrice = Infinity;
                    let maxPrice = -Infinity;
                    item.specifications.forEach(spec => {
                        const price = parseFloat(spec.price);
                        if (!isNaN(price) && price > 0) { // 确保价格大于0
                            minPrice = Math.min(minPrice, price);
                            maxPrice = Math.max(maxPrice, price);
                        }
                    });

                    // 判断价格差是否超过5倍
                    const priceRatio = (minPrice !== Infinity && minPrice > 0) ? (maxPrice / minPrice) : 1;
                    const hasHighPriceRatio = priceRatio > 5;
                    if (hasHighPriceRatio) highPriceRatioCount++;
                    const warningStyle = hasHighPriceRatio ? 'border: 2px solid #ff4d4f; background: #fff1f0;' : '';
                    const warningBadge = hasHighPriceRatio ? `<span style="background: #ff4d4f; color: white; padding: 2px 8px; border-radius: 12px; font-size: 11px; margin-left: 8px;">⚠️ 价差${priceRatio.toFixed(1)}倍</span>` : '';

                    html += `
                        <div style="
                            margin-bottom: 10px;
                            padding: 12px;
                            background: #fafafa;
                            border-radius: 6px;
                            border: 1px solid #e0e0e0;
                            ${warningStyle}
                            transition: all 0.3s;
                            position: relative;
                        " onmouseover="this.style.borderColor='#1890ff';" onmouseout="this.style.borderColor='${hasHighPriceRatio ? '#ff4d4f' : '#e0e0e0'}';">
                            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px;">
                                <div style="display: flex; align-items: center; flex: 1; min-width: 0;">
                                    <div style="font-weight: 600; color: #333; font-size: 14px; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
                                        ${index + 1}. ${item.name || '未知商品'}
                                        ${warningBadge}
                                    </div>
                                </div>
                                <div style="display: flex; gap: 8px; margin-left: 8px;">
                                    <button onclick="window.editProduct(${index})" style="
                                        background: #1890ff;
                                        color: white;
                                        border: none;
                                        padding: 4px 12px;
                                        border-radius: 4px;
                                        cursor: pointer;
                                        font-size: 12px;
                                        transition: all 0.2s;
                                    " onmouseover="this.style.background='#40a9ff'" onmouseout="this.style.background='#1890ff'">✏️ 编辑</button>
                                </div>
                            </div>
                            <div style="color: #666; font-size: 12px; margin-bottom: 8px;">
                                📦 共 ${item.specifications.length} 个规格 | ID: ${item.idStr}
                            </div>
                        </div>
                    `;
                });

                // 获取缓存信息
                const cacheInfo = CacheManager.getInfo();

                // 添加统计信息
                html += `
                    <div style="
                        margin-top: 15px;
                        padding: 12px;
                        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                        border-radius: 6px;
                        color: white;
                    ">
                        <div style="font-weight: bold; margin-bottom: 8px;">📈 统计信息</div>
                        <div style="font-size: 13px; line-height: 1.8;">
                            商品数量: ${productData.length} 件<br/>
                            高价差商品: ${highPriceRatioCount} 件<br/>
                            规格数量: ${totalSpecs} 个<br/>
                            API记录: ${capturedApiData.length} 条<br/>
                            ${cacheInfo.exists ? `💾 缓存: ${cacheInfo.ageDays}天前 (${cacheInfo.count}条)` : '💾 缓存: 无'}
                        </div>
                    </div>
                `;



                 contentEl.innerHTML = html;
                statusEl.textContent = `已加载 ${productData.length} 个商品`;
                statusEl.style.color = '#52c41a';

                // ⭐ [修改] 控制一键勾选按钮的显示
                const selectBtn = document.getElementById('dianxiaomi-select-high-price-btn');
                console.log(`🔍 检查一键勾选按钮: 找到=${!!selectBtn}, 高价差商品数=${highPriceRatioCount}`);
                if (selectBtn) {
                    if (highPriceRatioCount > 0) {
                        selectBtn.style.display = 'block';
                        selectBtn.textContent = `✔️ 一键勾选 (${highPriceRatioCount})`;
                        console.log(`✅ 一键勾选按钮已显示,数量: ${highPriceRatioCount}`);
                    } else {
                        selectBtn.style.display = 'none';
                        console.log('ℹ️ 一键勾选按钮已隐藏(无高价差商品)');
                    }
                } else {
                    console.error('❌ 未找到一键勾选按钮元素!');
                }

            }
        }, 500);
    }

    // 编辑商品函数 - 打开店小秘编辑页面
    window.editProduct = function(index) {
        const product = window.dianxiaomiProductData[index];
        if (!product) {
            alert('商品数据不存在');
            return;
        }

        // 使用 idStr 构建编辑链接
        const editUrl = `https://www.dianxiaomi.com/web/shopeeSite/edit?id=${product.idStr}`;
        console.log('🔗 打开编辑页面:', editUrl);

        // 在新标签页打开编辑链接
        window.open(editUrl, '_blank');
    };



    // 主函数
    function main() {
        console.log('店小蜜价格助手已启动');

        // 创建浮动面板
        setTimeout(() => {
            createFloatingPanel();
            console.log('✓ UI面板已创建');

            // 不再自动执行数据获取,只保留手动获取功能
        }, 1000);
    }

    // 页面加载完成后执行
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', main);
    } else {
        main();
    }

})();