yiwaima / ERP图片放大显示

// ==UserScript==
// @name         ERP图片放大显示
// @namespace    https://openuserjs.org/users/yiwaima
// @version      3.4
// @description  监控ERP系统中特定POST请求并放大显示图片,支持拖动、按网址位置记忆、尺寸调整、自适应字体和智能滑动显示
// @author       yiwaima
// @match        https://*.erp321.com/*
// @exclude      https://*.erp321.com/app/item/itemsku/itemskudialog.aspx*
// @grant        none
// @license      MIT
// @homepageURL  https://openuserjs.org/scripts/yiwaima/ERP图片放大显示
// @supportURL   https://github.com/yiwaima/erp-image-zoom-display/issues
// @updateURL    https://openuserjs.org/meta/yiwaima/ERP图片放大显示.meta.js
// @downloadURL  https://openuserjs.org/install/yiwaima/ERP图片放大显示.user.js
// ==/UserScript==

(function() {
    'use strict';

    // 创建图片显示框 - 支持拖动、位置记忆和尺寸调整
    function createImageDisplay() {
        const display = document.createElement('div');
        display.id = 'erp-image-display';

        // 从localStorage加载保存的位置和尺寸
        const savedPosition = loadDisplayPosition();
        const topPosition = savedPosition?.top || '35px';
        const rightPosition = savedPosition?.right || '10px';
        const width = savedPosition?.width || '400px';
        const height = savedPosition?.height || '400px';
        const isMinimized = savedPosition?.isMinimized || false;

        // 保存原始尺寸和当前尺寸
        let originalWidth = savedPosition?.width || '400px';
        let originalHeight = savedPosition?.height || '400px';
        let currentIsMinimized = isMinimized;
        // 保存缩小前的尺寸,用于恢复
        let sizeBeforeMinimize = { 
            width: savedPosition?.sizeBeforeMinimize?.width || width, 
            height: savedPosition?.sizeBeforeMinimize?.height || height 
        };

        display.style.cssText = `
            position: fixed;
            top: ${topPosition};
            right: ${rightPosition};
            width: ${isMinimized ? '100px' : width};
            height: ${isMinimized ? '100px' : height};
            background: white;
            border: 2px solid #ddd;
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            z-index: 9999;
            overflow: hidden;
            padding: 0;
            cursor: move;
            user-select: none;
            transition: width 0.3s ease, height 0.3s ease, opacity 0.3s ease;
        `;

        // 添加提示信息容器
        const alertContainer = document.createElement('div');
        alertContainer.id = 'erp-image-alerts';
        alertContainer.style.cssText = `
            position: absolute;
            top: 10px;
            left: 10px;
            right: 10px;
            text-align: center;
            z-index: 1;
            pointer-events: none;
            opacity: ${isMinimized ? '0' : '1'};
            transition: opacity 0.3s ease;
        `;

        // 创建第一个提示信息标签(调整透明度为30%)
        const alert1 = document.createElement('div');
        alert1.id = 'erp-alert-1';
        alert1.style.cssText = `
            background-color: rgba(255, 255, 255, 0.3);
            color: red;
            font-weight: bold;
            padding: 5px 10px;
            border-radius: 4px;
            margin-bottom: 5px;
            display: none;
            font-size: 14px;
            transition: all 0.3s ease;
        `;

        // 创建第二个提示信息标签(调整透明度为30%)
        const alert2 = document.createElement('div');
        alert2.id = 'erp-alert-2';
        alert2.style.cssText = `
            background-color: rgba(255, 255, 255, 0.3);
            color: gray;
            font-weight: bold;
            padding: 5px 10px;
            border-radius: 4px;
            display: none;
            font-size: 14px;
            transition: all 0.3s ease;
        `;

        alertContainer.appendChild(alert1);
        alertContainer.appendChild(alert2);
        display.appendChild(alertContainer);

        // 创建图片滚动容器
        const imgContainer = document.createElement('div');
        imgContainer.id = 'erp-image-scroll-container';
        imgContainer.style.cssText = `
            width: 100%;
            height: 100%;
            overflow: auto;
            display: flex;
            justify-content: center;
            align-items: flex-start;
            pointer-events: auto;
            /* 隐藏默认滚动条 */
            scrollbar-width: none;
            -ms-overflow-style: none;
        `;
        
        // 添加自定义滚动条CSS,隐藏默认滚动条
        const style = document.createElement('style');
        style.textContent = `
            /* 隐藏WebKit浏览器滚动条 */
            #erp-image-scroll-container::-webkit-scrollbar {
                display: none;
            }
            
            /* 隐藏Firefox滚动条 */
            #erp-image-scroll-container {
                scrollbar-width: none;
            }
            
            /* 隐藏IE滚动条 */
            #erp-image-scroll-container {
                -ms-overflow-style: none;
            }
            
            /* 确保主容器也没有滚动条 */
            #erp-image-display {
                overflow: hidden;
            }
        `;
        document.head.appendChild(style);

        // 创建图片元素
        const img = document.createElement('img');
        img.id = 'erp-displayed-image';
        img.style.cssText = `
            max-width: 100%;
            height: auto;
            display: block;
            margin: 0 auto;
            object-fit: contain;
        `;
        img.alt = 'ERP产品图片';

        imgContainer.appendChild(img);
        display.appendChild(imgContainer);

        // 添加功能按钮容器
        const buttonContainer = document.createElement('div');
        buttonContainer.id = 'erp-image-buttons';
        buttonContainer.style.cssText = `
            position: absolute;
            bottom: 10px;
            right: 10px;
            display: flex;
            gap: 5px;
            opacity: 0.8;
            transition: opacity 0.3s ease;
            z-index: 2; /* 确保按钮在图片上方 */
            pointer-events: auto; /* 确保按钮可以点击 */
        `;

        // SVG图标定义 - 调整尺寸,放大图标缩小后显示更大
        const zoomInSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 512 512"><path fill="currentColor" d="M414 354q-18-18-41-11l-32-32q43-53 43-119q0-80-56-136T192 0T56 56T0 192t56 136t136 56q70 0 119-43l32 32q-6 24 11 41l85 85q13 13 30 13q18 0 30-13q13-13 13-30t-13-30zm-222-13q-62 0-105.5-43.5T43 192T86.5 86.5T192 43t105.5 43.5T341 192t-43.5 105.5T192 341m64-170h-43v-43q0-21-21-21t-21 21v43h-43q-21 0-21 21t21 21h43v43q0 21 21 21t21-21v-43h43q21 0 21-21t-21-21"></path></svg>`;
        const zoomOutSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 1025 1025"><path fill="currentColor" d="M1005.856 822q19 19 19 46t-19 46l-91 92q-19 19-45.5 19t-45.5-19l-114-114l-133 133q-27 0-45.5-19t-18.5-45V576q0-26 18.5-45t45.5-19h384q26 0 45 19t19 45l-133 133zm-557-310h-383q-27 0-45.5-18.5T1.856 448l132-132l-114-113q-19-19-19-46t19-46l91-92q19-19 46-19t46 19l114 114l132-132q27 0 45.5 18.5t18.5 45.5v383q0 27-19 45.5t-45 18.5"></path></svg>`;
        const plusSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 64 64"><path fill="currentColor" d="M38 26V2H26v24H2v12h24v24h12V38h24V26z"></path></svg>`;
        const minusSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 64 64"><path fill="currentColor" d="M2 26h60v12H2z"></path></svg>`;

        // 添加放大缩小切换按钮
        const zoomToggleButton = document.createElement('button');
        zoomToggleButton.id = 'erp-zoom-toggle';
        zoomToggleButton.innerHTML = isMinimized ? zoomInSvg : zoomOutSvg;
        zoomToggleButton.style.cssText = `
            width: 30px;
            height: 30px;
            border: none;
            border-radius: 50%;
            background-color: rgba(0, 0, 0, 0.5);
            color: white;
            font-size: 14px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.3s ease;
        `;

        // 添加尺寸加按钮
        const sizePlusButton = document.createElement('button');
        sizePlusButton.id = 'erp-size-plus';
        sizePlusButton.innerHTML = plusSvg;
        sizePlusButton.style.cssText = `
            width: 30px;
            height: 30px;
            border: none;
            border-radius: 50%;
            background-color: rgba(0, 0, 0, 0.5);
            color: white;
            font-size: 16px;
            font-weight: bold;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.3s ease;
        `;

        // 添加尺寸减按钮
        const sizeMinusButton = document.createElement('button');
        sizeMinusButton.id = 'erp-size-minus';
        sizeMinusButton.innerHTML = minusSvg;
        sizeMinusButton.style.cssText = `
            width: 30px;
            height: 30px;
            border: none;
            border-radius: 50%;
            background-color: rgba(0, 0, 0, 0.5);
            color: white;
            font-size: 16px;
            font-weight: bold;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.3s ease;
        `;

        // 根据是否最小化调整按钮显示
        if (isMinimized) {
            // 最小化时只显示放大缩小按钮,且占图片1/4大小
            buttonContainer.appendChild(zoomToggleButton);
            buttonContainer.style.bottom = '25%';
            buttonContainer.style.right = '25%';
            buttonContainer.style.opacity = '0.5';
            zoomToggleButton.style.width = '50px';
            zoomToggleButton.style.height = '50px';
            alertContainer.style.display = 'none';
            sizePlusButton.style.display = 'none';
            sizeMinusButton.style.display = 'none';
        } else {
            buttonContainer.appendChild(zoomToggleButton);
            buttonContainer.appendChild(sizePlusButton);
            buttonContainer.appendChild(sizeMinusButton);
        }

        // 添加按钮到显示框
        display.appendChild(buttonContainer);
        document.body.appendChild(display);

        // 放大缩小切换功能
        zoomToggleButton.addEventListener('click', function(e) {
            e.stopPropagation(); // 防止触发拖动
            
            currentIsMinimized = !currentIsMinimized;
            
            if (currentIsMinimized) {
                // 缩小前保存当前尺寸
                sizeBeforeMinimize = { width: display.style.width, height: display.style.height };
                
                // 缩小到100x100
                display.style.width = '100px';
                display.style.height = '100px';
                zoomToggleButton.innerHTML = zoomInSvg;
                alertContainer.style.display = 'none';
                sizePlusButton.style.display = 'none';
                sizeMinusButton.style.display = 'none';
                buttonContainer.style.bottom = '25%';
                buttonContainer.style.right = '25%';
                buttonContainer.style.opacity = '0.5';
                zoomToggleButton.style.width = '50px';
                zoomToggleButton.style.height = '50px';
                
                // 缩小状态下设置图片为完整显示
                img.style.objectFit = 'contain';
                img.style.minWidth = 'auto';
                img.style.minHeight = 'auto';
                img.style.maxWidth = '100%';
                img.style.height = 'auto';
                
                // 缩小状态下图片容器不滚动
                imgContainer.style.overflow = 'hidden';
            } else {
                // 恢复到缩小前的尺寸
                display.style.width = sizeBeforeMinimize.width;
                display.style.height = sizeBeforeMinimize.height;
                zoomToggleButton.innerHTML = zoomOutSvg;
                alertContainer.style.display = 'block';
                alertContainer.style.opacity = '1';
                
                // 将加减按钮添加到DOM并显示
                buttonContainer.appendChild(sizePlusButton);
                buttonContainer.appendChild(sizeMinusButton);
                sizePlusButton.style.display = 'flex';
                sizeMinusButton.style.display = 'flex';
                
                buttonContainer.style.bottom = '10px';
                buttonContainer.style.right = '10px';
                buttonContainer.style.opacity = '0.8';
                zoomToggleButton.style.width = '30px';
                zoomToggleButton.style.height = '30px';
                
                // 更新原始尺寸(用于切换放大缩小)
                originalWidth = sizeBeforeMinimize.width;
                originalHeight = sizeBeforeMinimize.height;
                
                // 非缩小状态下图片容器可滚动
                imgContainer.style.overflow = 'auto';
                
                // 延迟执行,确保DOM更新完成
                setTimeout(() => {
                    // 如果图片已加载,根据宽高比调整显示方式
                    if (img.complete) {
                        // 获取图片原始宽高
                        const imageWidth = img.naturalWidth;
                        const imageHeight = img.naturalHeight;
                        
                        if (imageHeight > imageWidth) {
                            // 高度大于宽度:上下滑动,宽度填充容器,高度自适应
                            img.style.cssText = `
                                display: block;
                                margin: 0 auto;
                                max-width: 100%;
                                max-height: none;
                                width: 100%;
                                height: auto;
                                object-fit: contain;
                            `;
                            
                            // 计算垂直滚动位置
                            const containerHeight = imgContainer.clientHeight;
                            const renderedImageHeight = img.clientHeight;
                            
                            // 如果图片高度大于容器高度,垂直滚动到中间位置
                            if (renderedImageHeight > containerHeight) {
                                const scrollTop = (renderedImageHeight - containerHeight) / 2;
                                imgContainer.scrollTo({ top: scrollTop, behavior: 'smooth' });
                            }
                        } else {
                            // 宽度大于高度:裁剪成正方形,居中显示,裁剪两边留中间
                            img.style.cssText = `
                                display: block;
                                margin: 0 auto;
                                max-width: 100%;
                                max-height: 100%;
                                width: auto;
                                height: 100%;
                                object-fit: cover;
                                object-position: center;
                            `;
                        }
                    }
                }, 200);
            }
            
            // 保存当前状态
            saveDisplayPosition(display.style.top, display.style.right, display.style.width, display.style.height, currentIsMinimized, sizeBeforeMinimize);
        });
        
        // 添加鼠标滚轮滚动功能
        imgContainer.addEventListener('wheel', function(e) {
            // 只有在非缩小状态下才允许滚动
            if (!currentIsMinimized) {
                e.stopPropagation(); // 防止影响页面滚动
            }
        });
        
        // 图片加载完成后根据宽高比调整显示方式
        img.addEventListener('load', function() {
            // 只有在非缩小状态下才执行调整
            if (!currentIsMinimized) {
                // 获取图片原始宽高
                const imageWidth = img.naturalWidth;
                const imageHeight = img.naturalHeight;
                
                if (imageHeight > imageWidth) {
                    // 高度大于宽度:上下滑动,宽度填充容器,高度自适应
                    img.style.cssText = `
                        display: block;
                        margin: 0 auto;
                        max-width: 100%;
                        max-height: none;
                        width: 100%;
                        height: auto;
                        object-fit: contain;
                    `;
                    
                    // 计算垂直滚动位置
                    const containerHeight = imgContainer.clientHeight;
                    const renderedImageHeight = img.clientHeight;
                    
                    // 如果图片高度大于容器高度,垂直滚动到中间位置
                    if (renderedImageHeight > containerHeight) {
                        const scrollTop = (renderedImageHeight - containerHeight) / 2;
                        imgContainer.scrollTo({ top: scrollTop, behavior: 'smooth' });
                    }
                } else {
                    // 宽度大于高度:裁剪成正方形,居中显示,裁剪两边留中间
                    img.style.cssText = `
                        display: block;
                        margin: 0 auto;
                        max-width: 100%;
                        max-height: 100%;
                        width: auto;
                        height: 100%;
                        object-fit: cover;
                        object-position: center;
                    `;
                }
            }
        });

        // 尺寸加功能
        sizePlusButton.addEventListener('click', function(e) {
            e.stopPropagation(); // 防止触发拖动
            
            const currentWidth = parseInt(display.style.width);
            const currentHeight = parseInt(display.style.height);
            const newWidth = currentWidth + 50;
            const newHeight = currentHeight + 50;
            
            display.style.width = newWidth + 'px';
            display.style.height = newHeight + 'px';
            
            // 更新原始尺寸(用于切换放大缩小)
            originalWidth = display.style.width;
            originalHeight = display.style.height;
            
            // 更新提示字体尺寸
            updateAlertFontSize(display);
            
            // 保存当前状态
            saveDisplayPosition(display.style.top, display.style.right, display.style.width, display.style.height, currentIsMinimized, sizeBeforeMinimize);
        });

        // 尺寸减功能
        sizeMinusButton.addEventListener('click', function(e) {
            e.stopPropagation(); // 防止触发拖动
            
            const currentWidth = parseInt(display.style.width);
            const currentHeight = parseInt(display.style.height);
            
            // 限制最小尺寸为100px
            if (currentWidth > 150 && currentHeight > 150) {
                const newWidth = currentWidth - 50;
                const newHeight = currentHeight - 50;
                
                display.style.width = newWidth + 'px';
                display.style.height = newHeight + 'px';
                
                // 更新原始尺寸(用于切换放大缩小)
                originalWidth = display.style.width;
                originalHeight = display.style.height;
                
                // 更新提示字体尺寸
                updateAlertFontSize(display);
                
                // 保存当前状态
                saveDisplayPosition(display.style.top, display.style.right, display.style.width, display.style.height, currentIsMinimized, sizeBeforeMinimize);
            }
        });

        // 更新提示字体尺寸函数
        function updateAlertFontSize(displayElement) {
            const currentWidth = parseInt(displayElement.style.width);
            const alert1Element = document.getElementById('erp-alert-1');
            const alert2Element = document.getElementById('erp-alert-2');
            
            // 基于400px基准尺寸计算字体大小,使用更平缓的缩放比例
            const baseSize = 14;
            const minSize = 12; // 最小字体12px
            const maxSize = 24; // 最大字体24px
            
            // 使用平方根让缩小更平缓
            const scaleFactor = Math.sqrt(currentWidth / 400);
            const newFontSize = baseSize * scaleFactor;
            
            // 限制字体大小范围
            const clampedFontSize = Math.max(minSize, Math.min(maxSize, newFontSize));
            
            if (alert1Element) {
                alert1Element.style.fontSize = clampedFontSize + 'px';
            }
            if (alert2Element) {
                alert2Element.style.fontSize = clampedFontSize + 'px';
            }
        }

        // 初始化提示字体尺寸
        setTimeout(() => {
            updateAlertFontSize(display);
        }, 100);

        // 添加拖动功能
        let isDragging = false;
        let startX, startY, startTop, startRight;
        let originalTransition;

        display.addEventListener('mousedown', function(e) {
            // 如果点击的是按钮,不触发拖动
            if (e.target.closest('#erp-image-buttons')) {
                return;
            }
            
            isDragging = true;
            startX = e.clientX;
            startY = e.clientY;
            startTop = parseInt(display.style.top);
            startRight = parseInt(display.style.right);
            display.style.zIndex = 10000; // 拖动时提高层级
            
            // 保存原始过渡效果并移除,避免拖动时的过渡动画
            originalTransition = display.style.transition;
            display.style.transition = 'none';
        });

        document.addEventListener('mousemove', function(e) {
            if (!isDragging) return;

            const deltaX = e.clientX - startX;
            const deltaY = e.clientY - startY;
            
            // 计算新位置,确保不超出顶部页面范围
            const newTop = Math.max(0, startTop + deltaY); // 限制顶部位置
            const newRight = Math.max(0, startRight - deltaX); // 限制右侧位置,确保不超出屏幕
            
            // 实时更新位置,不使用过渡动画
            display.style.top = newTop + 'px';
            display.style.right = newRight + 'px';
        });

        document.addEventListener('mouseup', function() {
            if (isDragging) {
                isDragging = false;
                display.style.zIndex = 9999; // 拖动结束后恢复层级
                
                // 恢复原始过渡效果
                display.style.transition = originalTransition;
                
                // 再次确保最终位置不超出顶部
                const finalTop = Math.max(0, parseInt(display.style.top));
                display.style.top = finalTop + 'px';
                
                // 保存当前位置和尺寸到localStorage
                saveDisplayPosition(display.style.top, display.style.right, display.style.width, display.style.height, currentIsMinimized, sizeBeforeMinimize);
            }
        });

        // 鼠标悬停时显示按钮
        display.addEventListener('mouseenter', function() {
            if (!currentIsMinimized) {
                buttonContainer.style.opacity = '1';
            }
        });

        display.addEventListener('mouseleave', function() {
            if (!currentIsMinimized) {
                buttonContainer.style.opacity = '0.8';
            }
        });

        return display;
    }

    // 获取当前页面的基础URL(用于位置和尺寸存储的键)
function getBaseUrl() {
    const url = new URL(window.location.href);
    return `${url.protocol}//${url.host}${url.pathname}`;
}

// 保存显示框位置和尺寸到localStorage,按网址存储
function saveDisplayPosition(top, right, width, height, isMinimized, sizeBeforeMinimize = null) {
    try {
        const baseUrl = getBaseUrl();
        const positions = JSON.parse(localStorage.getItem('erpImageDisplayPositions') || '{}');
        
        positions[baseUrl] = {
            top: top,
            right: right,
            width: width,
            height: height,
            isMinimized: isMinimized,
            sizeBeforeMinimize: sizeBeforeMinimize
        };
        
        localStorage.setItem('erpImageDisplayPositions', JSON.stringify(positions));
        console.log('💾 已保存图片显示框位置和尺寸:', { top, right, width, height, isMinimized, sizeBeforeMinimize, url: baseUrl });
    } catch (error) {
        console.error('❌ 保存位置和尺寸失败:', error);
    }
}

// 从localStorage加载显示框位置和尺寸,按网址加载
function loadDisplayPosition() {
    try {
        const baseUrl = getBaseUrl();
        const positions = JSON.parse(localStorage.getItem('erpImageDisplayPositions') || '{}');
        
        if (positions[baseUrl]) {
            const position = positions[baseUrl];
            console.log('📥 已加载保存的图片显示框位置和尺寸:', position, '来自网址:', baseUrl);
            return position;
        }
    } catch (error) {
        console.error('❌ 加载位置和尺寸失败:', error);
    }
    return null;
}

    // 通用的URL查找函数 - 查找第一个URL,不限定图片格式
    function findFirstImageUrl(obj) {
        // URL正则表达式 - 查找任何HTTP/HTTPS链接
        const urlRegex = /https?:\/\/[^\s"']+(?:\?[^"']*)?/i;

        // 递归查找函数
        function search(obj) {
            // 如果是字符串,检查是否是URL
            if (typeof obj === 'string') {
                const match = obj.match(urlRegex);
                if (match) {
                    return match[0];
                }
            }
            // 如果是数组,遍历每个元素
            else if (Array.isArray(obj)) {
                for (let i = 0; i < obj.length; i++) {
                    const result = search(obj[i]);
                    if (result) {
                        return result;
                    }
                }
            }
            // 如果是对象,遍历每个属性
            else if (obj && typeof obj === 'object') {
                for (const key in obj) {
                    if (obj.hasOwnProperty(key)) {
                        const result = search(obj[key]);
                        if (result) {
                            return result;
                        }
                    }
                }
            }
            // 未找到URL
            return null;
        }

        return search(obj);
    }

    // 提取产品信息(name、taxAfterPrice和sku_id)的函数
    function extractProductInfo(obj) {
        // 存储找到的信息
        const info = {
            name: null,
            taxAfterPrice: null,
            sku_id: null
        };

        // 递归查找函数
        function search(obj) {
            // 如果是对象,遍历每个属性
            if (obj && typeof obj === 'object') {
                // 检查是否有name字段
                if (obj.hasOwnProperty('name') && typeof obj.name === 'string' && !info.name) {
                    info.name = obj.name;
                }

                // 检查是否有taxAfterPrice字段
                if (obj.hasOwnProperty('taxAfterPrice') && (typeof obj.taxAfterPrice === 'number' || typeof obj.taxAfterPrice === 'string') && !info.taxAfterPrice) {
                    info.taxAfterPrice = parseFloat(obj.taxAfterPrice);
                }

                // 检查是否有sku_id或类似字段(货品编码)
                if ((obj.hasOwnProperty('sku_id') || obj.hasOwnProperty('id') || obj.hasOwnProperty('SkuId') || obj.hasOwnProperty('SKU_ID')) && !info.sku_id) {
                    info.sku_id = obj.sku_id || obj.id || obj.SkuId || obj.SKU_ID;
                }

                // 如果所有字段都找到了,直接返回
                if (info.name && info.taxAfterPrice !== null && info.sku_id) {
                    return true;
                }

                // 如果是数组,遍历每个元素
                if (Array.isArray(obj)) {
                    for (let i = 0; i < obj.length; i++) {
                        if (search(obj[i])) {
                            return true;
                        }
                    }
                } else {
                    // 遍历对象的每个属性
                    for (const key in obj) {
                        if (obj.hasOwnProperty(key)) {
                            if (search(obj[key])) {
                                return true;
                            }
                        }
                    }
                }
            }
            return false;
        }

        search(obj);
        return info;
    }
    
    // 从cookie中提取指定名称的值
    function getCookie(name) {
        const match = document.cookie.match(new RegExp(`(^| )${name}=([^;]+)`));
        return match ? match[2] : null;
    }
    
    // 生成UUID函数,用于生成webbox-request-id
    function generateUUID() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            const r = Math.random() * 16 | 0;
            const v = c === 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    }
    
    // 检查价格变动并显示提示
    async function checkPriceChange(sku_id) {
        // 从cookie中提取u_id和u_co_id
        const u_id = getCookie('u_id');
        const u_co_id = getCookie('u_co_id');
        
        console.log('🔍 开始检查价格变动');
        console.log('📦 产品编码:', sku_id);
        
        if (!u_id || !u_co_id) {
            console.log('❌ 无法从cookie中获取u_id或u_co_id');
            return;
        }
        
        try {
            // 构建请求URL和表单数据
            const url = `https://apiweb.erp321.com/webapi/ItemApi/Log/GetPageListV2?owner_co_id=${u_co_id}&authorize_co_id=${u_co_id}`;
            const formData = {
                "ip": "",
                "uid": u_id,
                "coid": u_co_id,
                "page": {
                    "currentPage": 1,
                    "pageSize": 20,
                    "starSize": 1,
                    "hasPageInfo": true
                },
                "data": {
                    "type": 1,
                    "id": sku_id,
                    "creators": [],
                    "beginDate": "",
                    "endDate": "",
                    "onlyDel": false,
                    "name": "修改普通商品资料"
                },
                "isOtherStore": false
            };
            
            console.log('📤 发送价格变动检查请求');
            
            // 从当前页面获取路径信息
            const currentPath = window.location.pathname;
            
            // 构建headers对象,只保留必需字段
            const headers = {
                'accept': 'application/json',
                'content-type': 'application/json; charset=utf-8',
                'gwfp': getCookie('gwfp') || '',
                'u_sso_token': getCookie('u_sso_token') || '',
                'webbox-request-id': generateUUID(),
                'webbox-route-path': currentPath,
                'Cookie': document.cookie
            };
            
            // 发送POST请求,添加credentials: 'include'解决跨域cookie问题
            const response = await fetch(url, {
                method: 'POST',
                headers: headers,
                body: JSON.stringify(formData),
                credentials: 'include',
                mode: 'cors'
            });
            
            const responseData = await response.json();
            
            // 检查响应是否包含data数组
            if (responseData.data && Array.isArray(responseData.data)) {
                // 遍历data数组
                for (const item of responseData.data) {
                    // 检查remark是否含有关键词"成本价"
                    if (item.remark && item.remark.includes('成本价')) {
                        // 提取成本价变动信息
                        const costPriceMatch = item.remark.match(/成本价:([\d.]+)->([\d.]+)/);
                        if (costPriceMatch && costPriceMatch.length === 3) {
                            const oldPrice = costPriceMatch[1];
                            const newPrice = costPriceMatch[2];
                            
                            // 格式化修改日期为yyyy-MM-dd格式
                            let formattedDate = '未知日期';
                            if (item.created) {
                                try {
                                    const date = new Date(item.created);
                                    if (!isNaN(date.getTime())) {
                                        const year = date.getFullYear();
                                        const month = String(date.getMonth() + 1).padStart(2, '0');
                                        const day = String(date.getDate()).padStart(2, '0');
                                        formattedDate = `${year}-${month}-${day}`;
                                    }
                                } catch (e) {
                                    console.error('❌ 日期格式解析错误:', e.message);
                                }
                            }
                            
                            console.log('💰 发现价格变动:', `${oldPrice}->${newPrice} (修改日期: ${formattedDate})`);
                            
                            // 显示红字提示
                            const alert3 = document.createElement('div');
                            alert3.id = 'erp-alert-3';
                            alert3.style.cssText = `
                                background-color: rgba(255, 0, 0, 0.1);
                                color: red;
                                font-weight: bold;
                                padding: 5px 10px;
                                border-radius: 4px;
                                margin-bottom: 5px;
                                display: block;
                                font-size: 14px;
                                transition: all 0.3s ease;
                            `;
                            alert3.textContent = `价格有变动: ${oldPrice}->${newPrice} (修改日期: ${formattedDate})`;
                            
                            // 添加到提示容器
                            const alertContainer = document.getElementById('erp-image-alerts');
                            if (alertContainer) {
                                // 移除已存在的价格变动提示
                                const existingAlert3 = document.getElementById('erp-alert-3');
                                if (existingAlert3) {
                                    existingAlert3.remove();
                                }
                                alertContainer.appendChild(alert3);
                                console.log('✅ 价格变动提示已显示');
                            }
                            return;
                        }
                    }
                }
                
                console.log('📭 未发现价格变动');
            } else {
                console.log('❌ 响应不包含有效的数据');
            }
        } catch (error) {
            console.error('❌ 检查价格变动失败:', error.message);
        }
    }

    // 更新显示的图片和提示信息
    function updateDisplayedImage(picUrl, productInfo = {}) {
        let imgElement = document.getElementById('erp-displayed-image');
        if (!imgElement) {
            createImageDisplay();
            imgElement = document.getElementById('erp-displayed-image');
        }

        imgElement.src = picUrl;
        console.log('📷 已更新图片显示:', picUrl);

        // 获取提示信息元素
        const alert1 = document.getElementById('erp-alert-1');
        const alert2 = document.getElementById('erp-alert-2');
        const existingAlert3 = document.getElementById('erp-alert-3');

        // 重置提示信息
        if (alert1) alert1.style.display = 'none';
        if (alert2) alert2.style.display = 'none';
        if (existingAlert3) existingAlert3.remove();

        // 根据产品信息显示提示
        if (alert1 && productInfo.name) {
            if (productInfo.name.toLowerCase().includes('18k')) {
                alert1.textContent = '金镶嵌,注意包装';
                alert1.style.display = 'block';
            }
        }

        if (alert2 && productInfo.taxAfterPrice !== null) {
            if (productInfo.taxAfterPrice >= 600) {
                alert2.textContent = '货品贵重,注意包装';
                alert2.style.color = 'gray';
                alert2.style.display = 'block';
            }
        }
        
        // 检查价格变动
        if (productInfo.sku_id) {
            checkPriceChange(productInfo.sku_id);
        }
    }

    // 解析请求数据(支持字符串、FormData等)
    function parseRequestData(data) {
        if (!data) return '';

        if (typeof data === 'string') {
            return data;
        } else if (data instanceof FormData) {
            // 解析FormData
            let result = '';
            for (let [key, value] of data.entries()) {
                if (result) result += '&';
                result += `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
            }
            return result;
        } else {
            // 尝试将其他类型转换为字符串
            try {
                return JSON.stringify(data);
            } catch (e) {
                return String(data);
            }
        }
    }

    // 检查请求是否包含__CALLBACKPARAM且Method为CheckQty或LoadDataToJSON
    function isRelevantRequest(url, data) {
        // 检查URL参数
        const urlStr = typeof url === 'string' ? url : url instanceof URL ? url.href : '';
        const urlContainsTarget = urlStr.includes('__CALLBACKPARAM') &&
            ((urlStr.includes('"Method":"CheckQty"') || urlStr.includes("'Method':'CheckQty'")) ||
             (urlStr.includes('"Method":"LoadDataToJSON"') || urlStr.includes("'Method':'LoadDataToJSON'")));

        if (urlContainsTarget) {
            return true;
        }

        // 解析请求体数据
        const dataStr = parseRequestData(data);

        // 检查请求体
        if (!dataStr.includes('__CALLBACKPARAM')) return false;

        // 提取__CALLBACKPARAM的值
        const callbackParamMatch = dataStr.match(/__CALLBACKPARAM=([^&]+)/);
        if (!callbackParamMatch) return false;

        // 解码URL参数
        const callbackParam = decodeURIComponent(callbackParamMatch[1]);

        // 检查是否包含Method:CheckQty或Method:LoadDataToJSON
        const isMatch = callbackParam.includes('"Method":"CheckQty"') ||
               callbackParam.includes("'Method':'CheckQty'") ||
               callbackParam.includes('"Method":"LoadDataToJSON"') ||
               callbackParam.includes("'Method':'LoadDataToJSON'");

        return isMatch;
    }

    // 保存原始的XMLHttpRequest发送方法
    const originalXHRSend = XMLHttpRequest.prototype.send;

    // 重写XMLHttpRequest的send方法以监控请求
    XMLHttpRequest.prototype.send = function(data) {
        // 保存当前实例
        const xhr = this;

        // 检查请求是否是相关请求(CheckQty或LoadDataToJSON)
        const isRelevant = isRelevantRequest(xhr.responseURL, data);

        // 只处理相关请求
        if (isRelevant) {
            // 监听响应
            xhr.addEventListener('readystatechange', function() {
                if (xhr.readyState === 4) {
                    // 处理响应内容,移除可能的前缀
                    let responseText = xhr.responseText;
                    // 移除可能的"0|"前缀
                    if (responseText.startsWith('0|')) {
                        responseText = responseText.substring(2);
                    }

                    try {
                        // 尝试解析响应内容
                        const response = JSON.parse(responseText);
                        // console.log('✅ XMLHttpRequest成功解析响应:', JSON.stringify(response));

                        // 检查响应是否包含ReturnValue
                        if (response.ReturnValue && typeof response.ReturnValue === 'string') {
                            // 解析ReturnValue字符串(可能是嵌套JSON数组)
                            const returnValueObj = JSON.parse(response.ReturnValue);
                            // console.log('✅ XMLHttpRequest成功解析ReturnValue:', JSON.stringify(returnValueObj));

                            // 使用通用函数查找图片链接
                            const picUrl = findFirstImageUrl(returnValueObj);
                            if (picUrl) {
                                // 提取产品信息
                                const productInfo = extractProductInfo(returnValueObj);
                                updateDisplayedImage(picUrl, productInfo);
                            } else {
                                console.log('❌ XMLHttpRequest未找到图片URL');
                            }
                        }
                    } catch (error) {
                        console.error('❌ XMLHttpRequest响应解析错误:', error);
                        console.error('📄 XMLHttpRequest原始响应文本:', responseText);
                    }
                }
            });
        }

        // 调用原始的send方法
        originalXHRSend.call(xhr, data);
    };

    // 同样监控fetch请求
    const originalFetch = window.fetch;
    window.fetch = async function(url, options) {
        // 解析URL
        const requestUrl = typeof url === 'string' ? url : url.href;

        // 检查请求是否是相关请求(CheckQty或LoadDataToJSON)
        const isRelevant = isRelevantRequest(requestUrl, options?.body);

        // 发送原始请求
        const response = await originalFetch.call(this, url, options);

        // 只处理相关请求的响应
        if (isRelevant) {
            // 处理响应
            try {
                // 克隆响应以避免影响原始请求
                const clonedResponse = response.clone();

                // 获取文本响应
                const textResponse = await clonedResponse.text();

                // 处理响应内容,移除可能的前缀
                let responseText = textResponse;
                // 移除可能的"0|"前缀
                if (responseText.startsWith('0|')) {
                    responseText = responseText.substring(2);
                }

                // 尝试解析为JSON
                try {
                    const responseJson = JSON.parse(responseText);
                    // console.log('✅ fetch成功解析响应:', JSON.stringify(responseJson));

                    // 检查响应是否包含ReturnValue
                    if (responseJson.ReturnValue && typeof responseJson.ReturnValue === 'string') {
                        // 解析ReturnValue字符串(可能是嵌套JSON数组)
                        const returnValueObj = JSON.parse(responseJson.ReturnValue);
                        // console.log('✅ fetch成功解析ReturnValue:', JSON.stringify(returnValueObj));

                        // 使用通用函数查找图片链接
                        const picUrl = findFirstImageUrl(returnValueObj);
                        if (picUrl) {
                            // 提取产品信息
                            const productInfo = extractProductInfo(returnValueObj);
                            updateDisplayedImage(picUrl, productInfo);
                        } else {
                            console.log('❌ fetch未找到图片URL');
                        }
                    }
                } catch (jsonError) {
                    console.error('❌ fetch JSON解析错误:', jsonError);
                    console.error('📄 fetch原始响应文本:', responseText);
                }
            } catch (error) {
                console.error('❌ fetch响应处理错误:', error);
            }
        }

        // 返回原始响应
        return response;
    };

    console.log('ERP 图片显示显示 v3.1 已启动,正在监控包含__CALLBACKPARAM且Method为CheckQty或LoadDataToJSON的请求...');
    console.log('将在页面右上角显示产品图片,支持拖动和按网址位置记忆。');
})();