// ==UserScript==
// @name 游戏盈亏监控
// @namespace https://greasyfork.org/users/your-id
// @version 2.0.1
// @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
// @run-at document-end
// @downloadURL none
// ==/UserScript==
(function() {
'use strict';
// 配置参数
const config = {
checkInterval: 2000, // 检查间隔(毫秒)
profitThreshold: null, // 盈利阈值
lossThreshold: null, // 亏损阈值
monitoring: false,
currentIndex: 0,
columnIndex: 7, // 盈亏数据列下标(从0开始)
currentPage: 1,
totalPages: 1,
totalItems: 0,
itemsPerPage: 10,
retryCount: 0,
maxRetries: 3
};
// 创建控制面板
function createControlPanel() {
const panel = document.createElement('div');
panel.style.cssText = `
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: 280px;
`;
panel.innerHTML = `
游戏盈亏监控
状态: 未启动
进度: 0/0 条
页数: 1/1
`;
document.body.appendChild(panel);
document.getElementById('toggleMonitor').addEventListener('click', toggleMonitoring);
}
// 切换监控状态
function toggleMonitoring() {
const profitVal = parseFloat(document.getElementById('profitThresholdInput').value);
const lossVal = parseFloat(document.getElementById('lossThresholdInput').value);
if (isNaN(profitVal) && isNaN(lossVal)) {
alert('请至少设置一个阈值');
return;
}
config.profitThreshold = isNaN(profitVal) ? null : profitVal;
config.lossThreshold = isNaN(lossVal) ? null : Math.abs(lossVal);
config.monitoring = !config.monitoring;
const btn = document.getElementById('toggleMonitor');
const status = document.getElementById('statusText');
if (config.monitoring) {
btn.textContent = '停止监控';
btn.style.background = '#F56C6C';
let statusMsg = '监控中 (';
if (config.profitThreshold) statusMsg += `盈>${config.profitThreshold}`;
if (config.lossThreshold) statusMsg += `${config.profitThreshold ? ' ' : ''}亏>${config.lossThreshold}`;
status.textContent = statusMsg + ')';
startMonitoring();
} else {
btn.textContent = '开始监控';
btn.style.background = '#409EFF';
status.textContent = '已停止';
}
}
// 主监控流程
function startMonitoring() {
if (!config.monitoring) return;
// 重置到第一页
const firstPageBtn = document.querySelector('.el-pager .number:first-child');
if (firstPageBtn && !firstPageBtn.classList.contains('active')) {
simulateClick(firstPageBtn);
setTimeout(() => initMonitoring(), 2000);
} else {
initMonitoring();
}
}
function initMonitoring() {
updatePaginationInfo();
config.currentPage = 1;
config.currentIndex = 0;
setTimeRange();
setTimeout(() => clickQueryButton(), 1000);
}
// 更新分页信息
function updatePaginationInfo() {
const pagination = document.querySelector('.el-pagination');
if (!pagination) {
config.totalPages = 1;
config.totalItems = document.querySelectorAll('.el-table__row:not(.el-table__row--level)').length;
return;
}
// 获取总条数
const totalText = pagination.querySelector('.el-pagination__total')?.textContent || '';
config.totalItems = parseInt(totalText.match(/\d+/)?.[0] || 0);
// 获取每页条数
const sizeText = pagination.querySelector('.el-select-dropdown__item.selected span')?.textContent || '10';
config.itemsPerPage = parseInt(sizeText.match(/\d+/)?.[0] || 10);
// 计算总页数
config.totalPages = Math.ceil(config.totalItems / config.itemsPerPage);
// 更新UI显示
document.getElementById('totalItems').textContent = config.totalItems;
document.getElementById('totalPages').textContent = config.totalPages;
updateProgressDisplay();
}
// 更新进度显示
function updateProgressDisplay() {
const currentPos = (config.currentPage - 1) * config.itemsPerPage + config.currentIndex + 1;
document.getElementById('currentPosition').textContent = currentPos;
document.getElementById('displayPage').textContent = config.currentPage;
}
// 设置时间范围(关键修改点)
function setTimeRange() {
const minutes = parseInt(document.getElementById('minutesInput').value) || 40;
const now = new Date();
const startTime = new Date(now.getTime() - minutes * 60000);
// 固定结束时间为当天23:59:59
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 })));
}
}
// 点击查询按钮
function clickQueryButton() {
const queryBtn = [...document.querySelectorAll('.filter-container button.el-button')]
.find(btn => !btn.classList.contains('is-disabled') && btn.textContent.includes('查询'));
if (queryBtn) {
simulateClick(queryBtn);
setTimeout(() => checkUsers(), 3000);
} else {
console.log('未找到查询按钮');
if (config.retryCount++ < config.maxRetries) {
setTimeout(clickQueryButton, 1000);
} else {
alert('无法找到查询按钮');
toggleMonitoring();
}
}
}
// 检查用户列表
function checkUsers() {
const userRows = document.querySelectorAll('.el-table__row:not(.el-table__row--level)');
if (userRows.length === 0) {
console.log('未找到用户数据');
setTimeout(startMonitoring, config.checkInterval);
return;
}
config.currentIndex = 0;
checkNextUser();
}
// 检查下一个用户
function checkNextUser() {
if (!config.monitoring) 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(startMonitoring, config.checkInterval);
}
return;
}
const currentRow = userRows[config.currentIndex];
const userNameElement = currentRow.querySelector('.el-tooltip[style*="color: rgb(24, 144, 255)"]');
if (userNameElement) {
scrollAndClick(userNameElement, () => {
setTimeout(() => checkUserProfit(currentRow, userNameElement.textContent.trim()), 1500);
});
} else {
config.currentIndex++;
setTimeout(checkNextUser, 500);
}
}
// 检查用户盈亏
function checkUserProfit(row, userName) {
const profitCell = document.querySelector(`.el-dialog__body .el-table__row td:nth-child(${config.columnIndex + 1}) .cell`);
if (!profitCell) {
console.log('未找到盈亏数据');
closeDialog();
proceedToNext();
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');
} else if (!isProfit && config.lossThreshold && Math.abs(value) >= config.lossThreshold) {
notify(`用户 ${userName} 亏损超标: ${value}`, 'loss');
}
}
closeDialog();
proceedToNext();
}
// 处理下一个检查
function proceedToNext() {
config.currentIndex++;
updateProgressDisplay();
setTimeout(checkNextUser, 800);
}
// 翻到下一页
function goToNextPage() {
const nextBtn = document.querySelector('.el-pagination .btn-next:not([disabled])');
if (nextBtn) {
simulateClick(nextBtn);
setTimeout(() => {
config.currentPage++;
config.currentIndex = 0;
updatePaginationInfo();
checkUsers();
}, 2500);
}
}
// 关闭对话框
function closeDialog() {
const closeBtn = document.querySelector('.el-dialog__headerbtn');
if (closeBtn) simulateClick(closeBtn);
}
// 通知提醒
function notify(message, type) {
alert(message);
if (typeof GM_notification !== 'undefined') {
GM_notification({
title: type === 'profit' ? '盈利报警' : '亏损报警',
text: message,
timeout: 5000
});
}
console.warn(message);
}
// 模拟点击(兼容Element UI)
function simulateClick(element) {
['mousedown', 'mouseup', 'click'].forEach(event => {
element.dispatchEvent(new MouseEvent(event, { bubbles: true }));
});
}
// 滚动并点击元素
function scrollAndClick(element, callback) {
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
setTimeout(() => {
simulateClick(element);
if (callback) callback();
}, 800);
}
// 初始化
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);
}
})();