Greasy Fork

Greasy Fork is available in English.

游戏盈亏监控

高效监控游戏平台用户盈亏数据,支持自动选择状态和分页,优化大数据处理

// ==UserScript==
// @name         游戏盈亏监控
// @namespace    http://greasyfork.icu/users/your-id
// @version      2.6.6
// @description  高效监控游戏平台用户盈亏数据,支持自动选择状态和分页,优化大数据处理
// @author       Cisco
// @match        https://7777m.topcms.org/*
// @match        https://*.topcms.org/*
// @icon         https://7777m.topcms.org/favicon.ico
// @license      MIT
// @grant        GM_notification
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @run-at       document-end
// ==/UserScript==
 
(function() {
    'use strict';
 
    // 配置参数
    const config = {
        checkInterval: 2000,
        profitThreshold: null,
        lossThreshold: null,
        monitoring: false,
        currentIndex: 0,
        columnIndex: 0,
        currentPage: 1,
        totalPages: 1,
        totalItems: 0,
        itemsPerPage: 10,
        batchSize: 5,
        maxParallel: 2,
        activeRequests: 0,
        processedItems: 0,
        monitoringDuration: 40,
        lastCheckTime: 0,
        startTime: 0,
        panelCollapsed: false,
        profitAlerts: 0,
        lossAlerts: 0,
        dialogQueue: [],      // 告警消息队列
        isDialogProcessing: false, // 是否正在显示告警
        activeDialogs: {}, // 跟踪每个请求的对话框
        dialogCounter: 0   // 对话框唯一ID计数器
    };
 
    // 存储对象
    const storage = {
        get: function(key, defaultValue) {
            try {
                if (typeof GM_getValue !== 'undefined') {
                    return GM_getValue(key, defaultValue);
                }
                const value = localStorage.getItem(`monitor_${key}`);
                return value !== null ? JSON.parse(value) : defaultValue;
            } catch (e) {
                console.error('Storage get error:', e);
                return defaultValue;
            }
        },
        set: function(key, value) {
            try {
                if (typeof GM_setValue !== 'undefined') {
                    GM_setValue(key, value);
                } else {
                    localStorage.setItem(`monitor_${key}`, JSON.stringify(value));
                }
            } catch (e) {
                console.error('Storage set error:', e);
            }
        }
    };
 
    // 添加样式
    function addStyles() {
        const css = `
        .monitor-panel {
            position: fixed;
            top: 20px;
            right: 20px;
            z-index: 9999;
            background: white;
            padding: 15px;
            border: 1px solid #ddd;
            border-radius: 5px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            font-family: Arial, sans-serif;
            width: 320px;
            max-height: 90vh;
            overflow-y: auto;
            transition: all 0.3s ease;
        }
        .monitor-panel.collapsed {
            width: 40px;
            height: 40px;
            overflow: hidden;
            padding: 5px;
        }
        .toggle-panel {
            position: absolute;
            top: 5px;
            right: 5px;
            width: 30px;
            height: 30px;
            border: none;
            background: #f0f0f0;
            border-radius: 50%;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 16px;
            z-index: 10000;
        }
        .toggle-panel:hover {
            background: #e0e0e0;
        }
        .collapsed .panel-content {
            display: none;
        }
        .monitor-header {
            margin: 0 0 15px 0;
            color: #333;
            font-size: 16px;
            font-weight: bold;
            border-bottom: 1px solid #eee;
            padding-bottom: 10px;
        }
        .monitor-input-group {
            margin-bottom: 12px;
        }
        .monitor-label {
            display: block;
            margin-bottom: 5px;
            color: #666;
            font-size: 13px;
        }
        .monitor-input {
            width: 100%;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            box-sizing: border-box;
        }
        .monitor-button {
            width: 100%;
            padding: 10px;
            background: #409EFF;
            color: white;
            border: none;
            border-radius: 4px;
            font-weight: bold;
            cursor: pointer;
            transition: background 0.3s;
        }
        .monitor-button.stop {
            background: #F56C6C;
        }
        .monitor-stats {
            margin-top: 15px;
            font-size: 12px;
            color: #666;
            border-top: 1px solid #eee;
            padding-top: 10px;
        }
        .monitor-stat-row {
            display: flex;
            justify-content: space-between;
            margin-bottom: 5px;
        }
        .monitor-progress-container {
            margin: 10px 0;
            height: 10px;
            background: #f0f0f0;
            border-radius: 5px;
            overflow: hidden;
        }
        .monitor-progress-bar {
            height: 100%;
            background: linear-gradient(to right, #67C23A, #409EFF);
            transition: width 0.3s;
        }
        .monitor-speed {
            font-size: 11px;
            color: #999;
            text-align: right;
        }
        .monitor-alert-count {
            display: flex;
            justify-content: space-between;
            margin-top: 5px;
        }
        .monitor-alert-badge {
            display: inline-block;
            padding: 2px 6px;
            border-radius: 10px;
            font-size: 11px;
            font-weight: bold;
        }
        .profit-badge {
            background: #f0f9eb;
            color: #67C23A;
        }
        .loss-badge {
            background: #fef0f0;
            color: #F56C6C;
        }
        `;
        const style = document.createElement('style');
        style.type = 'text/css';
        style.appendChild(document.createTextNode(css));
        document.head.appendChild(style);
    }
 
    // 创建控制面板
    function createControlPanel() {
        addStyles();
        
        const panel = document.createElement('div');
        panel.className = 'monitor-panel';
        panel.id = 'monitorPanel';
        
        // 添加收起/展开按钮
        const toggleBtn = document.createElement('button');
        toggleBtn.className = 'toggle-panel';
        toggleBtn.innerHTML = '×';
        toggleBtn.title = '收起/展开控制面板';
        toggleBtn.addEventListener('click', togglePanel);
        
        // 面板内容
        const panelContent = document.createElement('div');
        panelContent.className = 'panel-content';
        panelContent.innerHTML = `
            <h3 class="monitor-header">游戏盈亏监控</h3>
            <div class="monitor-input-group">
                <label class="monitor-label">盈利阈值(+)</label>
                <input type="number" id="profitThresholdInput" placeholder="输入正数" class="monitor-input">
            </div>
            <div class="monitor-input-group">
                <label class="monitor-label">亏损阈值(-)</label>
                <input type="number" id="lossThresholdInput" placeholder="输入正数" class="monitor-input">
            </div>
            <div class="monitor-input-group">
                <label class="monitor-label">监控时长(分钟)</label>
                <input type="number" id="minutesInput" value="40" min="1" class="monitor-input">
            </div>
            <div class="monitor-input-group">
                <label class="monitor-label">并行数量</label>
                <input type="number" id="parallelInput" value="3" min="1" max="10" class="monitor-input" disabled>
            </div>
            <button id="toggleMonitor" class="monitor-button">开始监控</button>
            
            <div class="monitor-stats">
                <div class="monitor-stat-row">
                    <span>状态:</span>
                    <span id="statusText">未启动</span>
                </div>
                <div class="monitor-stat-row">
                    <span>进度:</span>
                    <span id="currentPosition">0</span>/<span id="totalItems">0</span> 条
                </div>
                <div class="monitor-stat-row">
                    <span>页数:</span>
                    <span id="displayPage">1</span>/<span id="totalPages">1</span>
                </div>
                <div class="monitor-stat-row">
                    <span>速度:</span>
                    <span id="speedText">0 条/分钟</span>
                </div>
                
                <div class="monitor-progress-container">
                    <div id="progressBar" class="monitor-progress-bar" style="width: 0%"></div>
                </div>
                <div class="monitor-speed" id="timeRemaining">预计剩余时间: 计算中...</div>
                
                <div class="monitor-alert-count">
                    <span class="monitor-alert-badge profit-badge">盈利超标: <span id="profitAlerts">0</span></span>
                    <span class="monitor-alert-badge loss-badge">亏损超标: <span id="lossAlerts">0</span></span>
                </div>
            </div>
        `;
 
        panel.appendChild(toggleBtn);
        panel.appendChild(panelContent);
        document.body.appendChild(panel);
        
        // 恢复面板状态和设置
        config.panelCollapsed = storage.get('panelCollapsed', false);
        if (config.panelCollapsed) {
            panel.classList.add('collapsed');
            toggleBtn.innerHTML = '≡';
        }
        
        const savedProfit = storage.get('profitThreshold', null);
        const savedLoss = storage.get('lossThreshold', null);
        const savedMinutes = storage.get('monitoringDuration', 40);
        const savedParallel = storage.get('parallelCount', 3);
        config.profitAlerts = storage.get('profitAlerts', 0);
        config.lossAlerts = storage.get('lossAlerts', 0);
        
        if (savedProfit) document.getElementById('profitThresholdInput').value = savedProfit;
        if (savedLoss) document.getElementById('lossThresholdInput').value = savedLoss;
        document.getElementById('minutesInput').value = savedMinutes;
        document.getElementById('parallelInput').value = savedParallel;
        document.getElementById('profitAlerts').textContent = config.profitAlerts;
        document.getElementById('lossAlerts').textContent = config.lossAlerts;
        
        document.getElementById('toggleMonitor').addEventListener('click', toggleMonitoring);
    }
 
    // 收起/展开面板
    function togglePanel() {
        const panel = document.getElementById('monitorPanel');
        config.panelCollapsed = !panel.classList.contains('collapsed');
        
        if (config.panelCollapsed) {
            panel.classList.add('collapsed');
            this.innerHTML = '≡';
        } else {
            panel.classList.remove('collapsed');
            this.innerHTML = '×';
        }
        
        storage.set('panelCollapsed', config.panelCollapsed);
    }
 
    // 切换监控状态
    function toggleMonitoring() {
        const profitVal = parseFloat(document.getElementById('profitThresholdInput').value);
        const lossVal = parseFloat(document.getElementById('lossThresholdInput').value);
        const minutes = parseInt(document.getElementById('minutesInput').value) || 40;
        const parallel = parseInt(document.getElementById('parallelInput').value) || 3;
 
        if (isNaN(profitVal) && isNaN(lossVal)) {
            alert('请至少设置一个阈值');
            return;
        }
 
        storage.set('profitThreshold', isNaN(profitVal) ? null : profitVal);
        storage.set('lossThreshold', isNaN(lossVal) ? null : Math.abs(lossVal));
        storage.set('monitoringDuration', minutes);
        storage.set('parallelCount', parallel);
 
        config.profitThreshold = isNaN(profitVal) ? null : profitVal;
        config.lossThreshold = isNaN(lossVal) ? null : Math.abs(lossVal);
        config.monitoringDuration = minutes;
        config.maxParallel = Math.min(Math.max(parallel, 1), 10);
        config.monitoring = !config.monitoring;
 
        const btn = document.getElementById('toggleMonitor');
        const status = document.getElementById('statusText');
 
        if (config.monitoring) {
            btn.textContent = '停止监控';
            btn.classList.add('stop');
            let statusMsg = '监控中 (';
            if (config.profitThreshold) statusMsg += `盈>${config.profitThreshold}`;
            if (config.lossThreshold) statusMsg += `${config.profitThreshold ? ' ' : ''}亏>${config.lossThreshold}`;
            status.textContent = statusMsg + ')';
            
            config.startTime = Date.now();
            config.processedItems = 0;
            config.lastCheckTime = Date.now();
            
            startMonitoring();
        } else {
            btn.textContent = '开始监控';
            btn.classList.remove('stop');
            status.textContent = '已停止';
        }
    }
 
    // 主监控流程
    function startMonitoring() {
        if (!config.monitoring) return;
 
        const firstPageBtn = document.querySelector('.el-pager .number:first-child');
        if (firstPageBtn && !firstPageBtn.classList.contains('active')) {
            safeClick(firstPageBtn, () => {
                setTimeout(() => initMonitoring(), 2000);
            });
        } else {
            initMonitoring();
        }
    }
 
    // 安全点击函数(带回调)
    function safeClick(element, callback) {
        if (simulateClick(element)) {
            setTimeout(() => {
                if (callback) callback();
            }, 500);
        } else if (callback) {
            callback();
        }
    }
 
    // 可靠的模拟点击函数
    function simulateClick(element) {
        if (!element) {
            console.log('模拟点击失败:元素不存在');
            return false;
        }
 
        // 方法1: 直接调用click方法
        try {
            element.click();
            return true;
        } catch (e) {
            console.log('直接click方法失败,尝试其他方法');
        }
 
        // 方法2: 创建并派发鼠标事件
        try {
            const mouseDown = new MouseEvent('mousedown', {
                bubbles: true,
                cancelable: true,
                view: window
            });
            element.dispatchEvent(mouseDown);
 
            const mouseUp = new MouseEvent('mouseup', {
                bubbles: true,
                cancelable: true,
                view: window
            });
            element.dispatchEvent(mouseUp);
 
            const clickEvent = new MouseEvent('click', {
                bubbles: true,
                cancelable: true,
                view: window
            });
            element.dispatchEvent(clickEvent);
            return true;
        } catch (e) {
            console.log('标准MouseEvent创建失败:', e);
        }
 
        // 方法3: 最简事件
        try {
            const event = document.createEvent('Event');
            event.initEvent('click', true, true);
            element.dispatchEvent(event);
            return true;
        } catch (e) {
            console.log('最简事件创建失败:', e);
        }
 
        console.log('所有点击模拟方法均失败');
        return false;
    }
 
    // 选择下拉选项
    function selectDropdownOption(selector, optionText, callback) {
        const dropdown = document.querySelector(selector);
        if (!dropdown) {
            console.log('未找到下拉框:', selector);
            if (callback) callback(false);
            return;
        }
 
        // 先检查当前是否已经是目标值
        const currentValue = dropdown.querySelector('.el-input__inner')?.value;
        if (currentValue === optionText) {
            if (callback) callback(true);
            return;
        }
 
        // 点击打开下拉框
        safeClick(dropdown, () => {
            setTimeout(() => {
                // 查找页面中所有可见的下拉菜单
                const allMenus = Array.from(document.querySelectorAll('.el-select-dropdown'));
                const visibleMenus = allMenus.filter(menu => {
                    return !menu.style.display || menu.style.display !== 'none';
                });
 
                // 查找与当前下拉框关联的菜单
                let targetMenu = null;
                const dropdownRect = dropdown.getBoundingClientRect();
 
                for (const menu of visibleMenus) {
                    const menuRect = menu.getBoundingClientRect();
                    // 检查菜单是否出现在下拉框附近
                    if (Math.abs(menuRect.left - dropdownRect.left) < 50 && 
                        (Math.abs(menuRect.top - dropdownRect.bottom) < 20 || 
                        Math.abs(menuRect.bottom - dropdownRect.top) < 20)) {
                        targetMenu = menu;
                        break;
                    }
                }
 
                if (!targetMenu) {
                    console.log('未找到关联的下拉菜单');
                    if (callback) callback(false);
                    return;
                }
 
                // 查找匹配的选项
                const options = targetMenu.querySelectorAll('.el-select-dropdown__item');
                let optionFound = false;
                
                for (const option of options) {
                    if (option.textContent.trim() === optionText) {
                        // 确保选项可见
                        option.scrollIntoView({ behavior: 'instant', block: 'nearest' });
                        
                        // 点击选项
                        setTimeout(() => {
                            if (simulateClick(option)) {
                                optionFound = true;
                                // 等待下拉框关闭
                                setTimeout(() => {
                                    if (callback) callback(true);
                                }, 800);
                            } else {
                                if (callback) callback(false);
                            }
                        }, 200);
                        break;
                    }
                }
                
                if (!optionFound) {
                    console.log('未找到选项:', optionText);
                    if (callback) callback(false);
                }
            }, 500);
        });
    }
 
    // 设置每页显示条数
    function setPageSize(size, callback) {
    selectDropdownOption('.el-pagination__sizes .el-select', `${size}条/页`, (success) => {
        if (success) {
            config.itemsPerPage = size;
            // 设置成功后强制重新加载数据
            setTimeout(() => {
                updatePaginationInfo();
                if (callback) callback(true);
            }, 1500); // 等待数据重新加载
        } else {
            if (callback) callback(false);
        }
    });
}
 
    // 选择订单状态
    function selectOrderStatus(status, callback) {
        selectDropdownOption('.el-select.filter-item', status, callback);
    }
 
    // 设置时间范围
    function setTimeRange(callback) {
        const now = new Date();
        const startTime = new Date(now.getTime() - config.monitoringDuration * 60000);
        const endTime = new Date(now);
        endTime.setHours(23, 59, 59, 0);
 
        const formatTime = (date) => {
            const pad = num => num.toString().padStart(2, '0');
            return `${date.getFullYear()}-${pad(date.getMonth()+1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
        };
 
        const timeInputs = document.querySelectorAll('.el-range-input');
        if (timeInputs.length >= 2) {
            timeInputs[0].value = formatTime(startTime);
            timeInputs[1].value = formatTime(endTime);
            timeInputs.forEach(input => {
                input.dispatchEvent(new Event('input', { bubbles: true }));
                input.dispatchEvent(new Event('change', { bubbles: true }));
            });
            
            setTimeout(() => {
                if (callback) callback();
            }, 500);
        } else if (callback) {
            callback();
        }
    }
 
    // 初始化监控
    function initMonitoring() {
        // 先重置分页信息
        config.currentPage = 1;
        config.currentIndex = 0;
        
        // 新的初始化流程
        const initSteps = [
            (next) => selectOrderStatus('已支付', (success) => {
                console.log(success ? '状态设置成功' : '状态设置失败');
                next();
            }),
            (next) => setTimeRange(() => {
                console.log('时间设置完成');
                next();
            }),
            (next) => setPageSize(200, (success) => {
                console.log(success ? '分页设置成功' : '分页设置失败');
                next();
            }),
            () => {
                console.log('开始查询');
                // 查询前再次更新分页信息
                updatePaginationInfo();
                setTimeout(() => clickQueryButton(), 1000);
            }
        ];
    
        // 执行步骤
        function executeStep() {
            if (initSteps.length > 0) {
                const step = initSteps.shift();
                step(executeStep);
            }
        }
    
        executeStep();
    }
 
    // 更新分页信息
    function updatePaginationInfo() {
        const pagination = document.querySelector('.el-pagination');
        if (!pagination) {
            const rows = document.querySelectorAll('.el-table__row:not(.el-table__row--level)');
            config.totalItems = rows.length;
            config.itemsPerPage = rows.length || config.itemsPerPage;
            config.totalPages = 1;
        } else {
            // 从分页信息中获取总条数(适应不同格式)
            const totalText = pagination.querySelector('.el-pagination__total')?.textContent || '';
            const totalMatch = totalText.match(/(\d+)(?=\s*条)/) || [null, 0];
            config.totalItems = parseInt(totalMatch[1]) || 0;
            
            // 确保使用当前设置的分页大小
            config.itemsPerPage = config.itemsPerPage || 200;
            config.totalPages = Math.ceil(config.totalItems / config.itemsPerPage);
        }
        
        // 更新UI显示
        document.getElementById('totalItems').textContent = config.totalItems;
        document.getElementById('totalPages').textContent = config.totalPages;
        updateProgressDisplay();
        
        console.log('更新分页信息 - 总条数:', config.totalItems, '每页:', config.itemsPerPage, '总页数:', config.totalPages);
    }
 
    // 点击查询按钮
    function clickQueryButton() {
        const queryBtn = [...document.querySelectorAll('.filter-container button.el-button')]
            .find(btn => !btn.classList.contains('is-disabled') && btn.textContent.includes('查询'));
 
        if (queryBtn) {
            safeClick(queryBtn, () => {
                setTimeout(() => checkUsers(), 3000);
            });
        } else {
            console.log('未找到查询按钮');
            setTimeout(() => {
                if (config.monitoring) clickQueryButton();
            }, 1000);
        }
    }
 
    // 更新进度显示
    function updateProgressDisplay() {
        const currentPos = (config.currentPage - 1) * config.itemsPerPage + config.currentIndex + 1;
        document.getElementById('currentPosition').textContent = currentPos;
        document.getElementById('displayPage').textContent = config.currentPage;
        
        const progressPercent = (currentPos / config.totalItems * 100).toFixed(1);
        document.getElementById('progressBar').style.width = `${progressPercent}%`;
        
        const now = Date.now();
        const elapsedMinutes = (now - config.startTime) / 60000;
        const speed = elapsedMinutes > 0 ? Math.round(config.processedItems / elapsedMinutes) : 0;
        document.getElementById('speedText').textContent = `${speed} 条/分钟`;
        
        if (speed > 0) {
            const remainingItems = config.totalItems - currentPos;
            const remainingMinutes = Math.ceil(remainingItems / speed);
            document.getElementById('timeRemaining').textContent = `预计剩余时间: ${remainingMinutes} 分钟`;
        }
    }
 
    // 检查用户列表
    function checkUsers() {
        const userRows = document.querySelectorAll('.el-table__row:not(.el-table__row--level)');
        if (userRows.length === 0) {
            console.log('未找到用户数据');
            setTimeout(() => {
                if (config.monitoring) startMonitoring();
            }, config.checkInterval);
            return;
        }
 
        config.currentIndex = 0;
        processBatch();
    }
 
    // 新增:重置新一轮监控的函数
    function resetForNewRound() {
        // 保存原始设置
        const originalProfitThreshold = config.profitThreshold;
        const originalLossThreshold = config.lossThreshold;
        const originalMonitoringDuration = config.monitoringDuration;
        const originalParallel = config.maxParallel;
        
        // 重置状态
        config.startTime = Date.now();
        config.processedItems = 0;
        config.lastCheckTime = Date.now();
        config.currentPage = 1;
        config.currentIndex = 0;
        
        // 重新获取分页信息
        updatePaginationInfo();
        
        // 恢复设置
        config.profitThreshold = originalProfitThreshold;
        config.lossThreshold = originalLossThreshold;
        config.monitoringDuration = originalMonitoringDuration;
        config.maxParallel = originalParallel;
        
        console.log('新一轮监控准备完成,总条数:', config.totalItems);
    }
    // 修改processUser函数,确保每次只处理一个对话框
    function processUser(row, userNameElement, callback) {
        const userName = userNameElement.textContent.trim();
        const dialogId = 'dialog_' + (++config.dialogCounter);
        
        // 保存当前对话框ID到配置中
        config.activeDialogs[dialogId] = {
            userName: userName,
            callback: callback
        };
    
        // 先关闭所有可能打开的对话框
        closeAllDialogs(() => {
            // 滚动并点击用户名称
            userNameElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
            setTimeout(() => {
                openUserDialog(userNameElement, dialogId);
            }, 500);
        });
    }
    
    // 新增关闭所有对话框的函数
    function closeAllDialogs(callback) {
        const dialogs = document.querySelectorAll('.el-dialog__wrapper:not([style*="display: none"])');
        if (dialogs.length === 0) {
            if (callback) callback();
            return;
        }
        
        let closedCount = 0;
        dialogs.forEach(dialog => {
            const closeBtn = dialog.querySelector('.el-dialog__headerbtn');
            if (closeBtn) {
                safeClick(closeBtn, () => {
                    closedCount++;
                    if (closedCount === dialogs.length && callback) {
                        setTimeout(callback, 300);
                    }
                });
            } else {
                closedCount++;
                if (closedCount === dialogs.length && callback) {
                    setTimeout(callback, 300);
                }
            }
        });
    }
    
    // 修改openUserDialog函数
    function openUserDialog(userNameElement, dialogId) {
        safeClick(userNameElement, () => {
            // 增加对话框打开确认
            const checkDialog = setInterval(() => {
                const dialog = document.querySelector('.el-dialog__wrapper:not([style*="display: none"])');
                if (dialog) {
                    clearInterval(checkDialog);
                    // 确保对话框内容已加载
                    setTimeout(() => {
                        checkUserProfit(dialog, config.activeDialogs[dialogId].userName, dialogId, config.activeDialogs[dialogId].callback);
                    }, 800);
                }
            }, 200);
        });
    }
    // 处理批次数据
    function processBatch() {
        if (!config.monitoring || config.activeRequests >= config.maxParallel) {
            setTimeout(processBatch, 100);
            return;
        }
 
        const userRows = document.querySelectorAll('.el-table__row:not(.el-table__row--level)');
        if (config.currentIndex >= userRows.length) {
            if (config.currentPage < config.totalPages) {
            goToNextPage();
            } else {
            console.log('所有数据检查完成');
            resetForNewRound();
            setTimeout(() => {
                if (config.monitoring) startMonitoring();
            }, config.checkInterval);
            }
            return;
        }
 
        // 计算可处理数量
        const batchSize = Math.min(
            config.batchSize,
            userRows.length - config.currentIndex,
            config.maxParallel - config.activeRequests
        );
 
        for (let i = 0; i < batchSize; i++) {
            const currentRow = userRows[config.currentIndex + i];
            const userNameElement = currentRow.querySelector('.el-tooltip[style*="color: rgb(24, 144, 255)"]');
            if (userNameElement) {
            config.activeRequests++;
 
            // 将任务放入队列中,由弹窗队列串行处理
            config.dialogQueue.push(() => {
                processUser(currentRow, userNameElement, () => {
                config.activeRequests--;
                config.processedItems++;
                updateProgressDisplay();
                setTimeout(processBatch, 50); // 每处理完一个继续调度
                });
            });
            } else {
            config.processedItems++;
            updateProgressDisplay();
            }
        }
 
        config.currentIndex += batchSize;
        processDialogQueue(); // 开始弹窗串行处理
    }
 
    function processDialogQueue() {
        // 如果已经有弹窗正在处理,退出
        if (config.isDialogProcessing) return;
 
        const nextTask = config.dialogQueue.shift(); // 取出下一个弹窗任务
        if (!nextTask) return;
 
        config.isDialogProcessing = true;
 
        // 执行任务(内部调用 processUser → openUserDialog → checkUserProfit)
        nextTask();
    }
 
    // 处理单个用户
    function checkUserProfit(dialog, userName, dialogId, callback) {
        // 增加重试机制
        let retryCount = 0;
        const maxRetries = 3;
        
        function attemptCheck() {
            const tables = dialog.querySelectorAll('.el-dialog__body .el-table');
            if (tables.length < 2) {
                if (retryCount < maxRetries) {
                    retryCount++;
                    console.log(`[${userName}] 未找到表格,重试 ${retryCount}/${maxRetries}`);
                    setTimeout(attemptCheck, 1000);
                    return;
                }
                console.error(`[${userName}] 未找到包含余额的表格`);
                closeDialog(dialogId);
                if (callback) callback();
                return;
            }
    
            // 获取第二个表格(余额表格)
            const balanceTable = tables[1];
            
            // 改进的查找余额列逻辑
            const headerCells = balanceTable.querySelectorAll('.el-table__header .cell');
            let balanceColumnIndex = -1;
            
            // 更灵活的查找余额列
            for (let i = 0; i < headerCells.length; i++) {
                const headerText = headerCells[i].textContent.trim().toLowerCase();
                if (headerText.includes('余额') || headerText.includes('balance')) {
                    balanceColumnIndex = i;
                    break;
                }
            }
            
            if (balanceColumnIndex === -1) {
                console.error(`[${userName}] 未找到余额列`);
                closeDialog(dialogId);
                if (callback) callback();
                return;
            }
            
            // 更健壮的单元格查找
            const balanceCell = balanceTable.querySelector(
                `.el-table__body tr:first-child td:nth-child(${balanceColumnIndex + 1}) .cell`
            );
    
            if (!balanceCell) {
                if (retryCount < maxRetries) {
                    retryCount++;
                    console.log(`[${userName}] 未找到余额单元格,重试 ${retryCount}/${maxRetries}`);
                    setTimeout(attemptCheck, 1000);
                    return;
                }
                console.error(`[${userName}] 未找到余额单元格`);
                closeDialog(dialogId);
                if (callback) callback();
                return;
            }
    
            // 提取数值
            const rawText = balanceCell.textContent.trim();
            const numericText = rawText.replace(/,/g, '');
            const value = parseFloat(numericText.replace(/[^\d.-]/g, ''));
            
            console.log(`[${userName}] 余额解析: "${rawText}" → ${value}`);
    
            if (isNaN(value)) {
                console.error(`[${userName}] 余额解析失败:`, rawText);
                closeDialog(dialogId);
                if (callback) callback();
                return;
            }
    
            // 阈值检查
            if (config.profitThreshold !== null && value >= config.profitThreshold) {
                const exceed = (value - config.profitThreshold).toFixed(2);
                showAlert(`用户 ${userName} 余额超标: ${value} (超过${exceed})`, 'profit');
                incrementAlertCount('profit');
            } 
            else if (config.lossThreshold !== null && value <= config.lossThreshold) {
                const below = (config.lossThreshold - value).toFixed(2);
                showAlert(`用户 ${userName} 余额不足: ${value} (低于${below})`, 'loss');
                incrementAlertCount('loss');
            }
    
            // 弹窗处理完后,关闭并释放队列控制
            closeDialog(dialogId, () => {
                config.isDialogProcessing = false;
                processDialogQueue(); // 处理下一个弹窗
                if (callback) callback();
            });
 
        }
        
        attemptCheck();
    }
    
    // 增加警报计数
    function incrementAlertCount(type) {
        const elementId = type === 'profit' ? 'profitAlerts' : 'lossAlerts';
        const currentCount = parseInt(document.getElementById(elementId).textContent) || 0;
        const newCount = currentCount + 1;
        document.getElementById(elementId).textContent = newCount;
        
        if (type === 'profit') {
            config.profitAlerts = newCount;
            storage.set('profitAlerts', newCount);
        } else {
            config.lossAlerts = newCount;
            storage.set('lossAlerts', newCount);
        }
    }
 
    // 翻到下一页
    function goToNextPage() {
        const nextBtn = document.querySelector('.el-pagination .btn-next:not([disabled])');
        if (nextBtn) {
            safeClick(nextBtn, () => {
                setTimeout(() => {
                    config.currentPage++;
                    config.currentIndex = 0;
                    updatePaginationInfo();
                    setTimeout(() => checkUsers(), 2000);
                }, 1500);
            });
        }
    }
 
    
    // 改进的 closeDialog 函数
    function closeDialog(dialogId, callback) {
        delete config.activeDialogs[dialogId];
        const dialog = document.querySelector('.el-dialog__wrapper:not([style*="display: none"])');
        if (dialog) {
            const closeBtn = dialog.querySelector('.el-dialog__headerbtn');
            if (closeBtn) {
                safeClick(closeBtn, () => {
                    // 等待对话框完全关闭
                    setTimeout(() => {
                        if (callback) callback();
                    }, 500);
                });
            } else if (callback) {
                callback();
            }
        } else if (callback) {
            callback();
        }
    }
    
    // 改进的通知函数
    function showAlert(message, type) {
        // 1. 控制台日志
        console.warn(`[ALERT] ${message}`);
        
        alert(message);
        // 2. 使用GM_notification或浏览器通知
        if (typeof GM_notification !== 'undefined') {
            try {
                GM_notification({
                    title: type === 'profit' ? '盈利报警' : '亏损报警',
                    text: message,
                    timeout: 5000,
                    onclick: function() {
                        window.focus();
                    }
                });
                return;
            } catch (e) {
                console.error('GM_notification失败:', e);
            }
        }
        
        // 3. 使用Web Notification
        if (window.Notification && Notification.permission === 'granted') {
            new Notification(type === 'profit' ? '盈利报警' : '亏损报警', {
                body: message,
                icon: 'https://7777m.topcms.org/favicon.ico'
            });
            return;
        } else if (window.Notification && Notification.permission !== 'denied') {
            Notification.requestPermission().then(function(permission) {
                if (permission === 'granted') {
                    new Notification(type === 'profit' ? '盈利报警' : '亏损报警', {
                        body: message,
                        icon: 'https://7777m.topcms.org/favicon.ico'
                    });
                } else {
                    fallbackAlert(message);
                }
            });
            return;
        }
        
        // 4. 最终弹窗方案
        fallbackAlert(message);
 
    }
    
    function fallbackAlert(message) {
        // 创建自定义弹窗
        const alertDiv = document.createElement('div');
        alertDiv.style.position = 'fixed';
        alertDiv.style.top = '20px';
        alertDiv.style.right = '20px';
        alertDiv.style.padding = '15px';
        alertDiv.style.background = '#f8f8f8';
        alertDiv.style.border = '1px solid #ddd';
        alertDiv.style.borderRadius = '5px';
        alertDiv.style.boxShadow = '0 2px 10px rgba(0,0,0,0.1)';
        alertDiv.style.zIndex = '99999';
        alertDiv.textContent = message;
        
        document.body.appendChild(alertDiv);
        
        // 5秒后自动消失
        setTimeout(() => {
            alertDiv.remove();
        }, 5000);
    }
    
    // 初始化
    function init() {
        const checkTable = setInterval(() => {
            if (document.querySelector('.el-table')) {
                clearInterval(checkTable);
                createControlPanel();
                console.log('脚本初始化完成');
            }
        }, 500);
    }
 
    if (document.readyState === 'complete') {
        init();
    } else {
        window.addEventListener('load', init);
    }
})();