// ==UserScript== // @name 游戏盈亏监控 // @namespace https://greasyfork.org/users/your-id // @version 2.4.0 // @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 // @downloadURL none // ==/UserScript== (function() { 'use strict'; // 配置参数 const config = { checkInterval: 2000, profitThreshold: null, lossThreshold: null, monitoring: false, currentIndex: 0, columnIndex: 7, currentPage: 1, totalPages: 1, totalItems: 0, itemsPerPage: 10, batchSize: 5, maxParallel: 3, activeRequests: 0, processedItems: 0, monitoringDuration: 40, lastCheckTime: 0, startTime: 0, panelCollapsed: false, profitAlerts: 0, lossAlerts: 0 }; // 兼容性存储对象 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 = `

游戏盈亏监控

状态: 未启动
进度: 0/0
页数: 1/1
速度: 0 条/分钟
预计剩余时间: 计算中...
盈利超标: 0 亏损超标: 0
`; 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; for (const menu of visibleMenus) { // 通过位置判断是否关联 const dropdownRect = dropdown.getBoundingClientRect(); 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; updatePaginationInfo(); } if (callback) callback(success); }); } // 增强版选择订单状态 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() { updatePaginationInfo(); config.currentPage = 1; config.currentIndex = 0; // 新的初始化流程 const initSequence = [ () => setPageSize(200, (success) => { console.log(success ? '成功设置分页大小' : '设置分页大小失败'); initSequence.shift()(); }), () => setTimeRange(() => { console.log('时间范围设置完成'); initSequence.shift()(); }), () => selectOrderStatus('已支付', (success) => { console.log(success ? '成功设置订单状态' : '设置订单状态失败'); initSequence.shift()(); }), () => { console.log('开始执行查询'); setTimeout(() => clickQueryButton(), 1000); } ]; initSequence.shift()(); } // 更新分页信息 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 || 200; config.totalPages = 1; } else { const totalText = pagination.querySelector('.el-pagination__total')?.textContent || ''; config.totalItems = parseInt(totalText.match(/\d+/)?.[0] || 0); const sizeText = pagination.querySelector('.el-select .el-input__inner')?.value || '200'; config.itemsPerPage = parseInt(sizeText) || 200; config.totalPages = Math.ceil(config.totalItems / config.itemsPerPage); } document.getElementById('totalItems').textContent = config.totalItems; document.getElementById('totalPages').textContent = config.totalPages; updateProgressDisplay(); } // 点击查询按钮 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 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 processBatch() { if (!config.monitoring || config.activeRequests >= config.maxParallel) 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('所有数据检查完成'); setTimeout(() => { if (config.monitoring) startMonitoring(); }, config.checkInterval); } return; } const batchSize = Math.min(config.batchSize, userRows.length - config.currentIndex, config.maxParallel - config.activeRequests); if (batchSize <= 0) return; 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++; processUser(currentRow, userNameElement, () => { config.activeRequests--; config.processedItems++; updateProgressDisplay(); setTimeout(processBatch, 100); }); } else { config.currentIndex++; config.processedItems++; updateProgressDisplay(); } } config.currentIndex += batchSize; setTimeout(processBatch, 100); } // 处理单个用户 function processUser(row, userNameElement, callback) { const userName = userNameElement.textContent.trim(); // 滚动并点击用户名称 userNameElement.scrollIntoView({ behavior: 'smooth', block: 'center' }); setTimeout(() => { safeClick(userNameElement, () => { setTimeout(() => { checkUserProfit(row, userName, callback); }, 1500); }); }, 800); } // 检查用户盈亏 function checkUserProfit(row, userName, callback) { const profitCell = document.querySelector(`.el-dialog__body .el-table__row td:nth-child(${config.columnIndex + 1}) .cell`); if (!profitCell) { console.log('未找到盈亏数据'); closeDialog(); if (callback) callback(); return; } const text = profitCell.textContent.trim(); const isProfit = text.includes('+'); const value = parseFloat(text.replace(/[^\d.-]/g, '')); if (!isNaN(value)) { if (isProfit && config.profitThreshold && value >= config.profitThreshold) { notify(`用户 ${userName} 盈利超标: +${value}`, 'profit'); incrementAlertCount('profit'); } else if (!isProfit && config.lossThreshold && Math.abs(value) >= config.lossThreshold) { notify(`用户 ${userName} 亏损超标: ${value}`, 'loss'); incrementAlertCount('loss'); } } closeDialog(); if (callback) callback(); } // 增加警报计数 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); }); } } // 关闭对话框 function closeDialog() { const closeBtn = document.querySelector('.el-dialog__headerbtn'); if (closeBtn) safeClick(closeBtn, () => {}); } // 通知提醒 function notify(message, type) { alert(message); if (typeof GM_notification !== 'undefined') { GM_notification({ title: type === 'profit' ? '盈利报警' : '亏损报警', text: message, timeout: 5000 }); } console.warn(message); } // 更新进度显示 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 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); } })();