// ==UserScript==
// @name 游戏盈亏监控
// @namespace https://greasyfork.org/users/your-id
// @version 2.5.9
// @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: 0,
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,
alertQueue: [],
isShowingAlert: false,
activeDialogs: {},
dialogCounter: 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;
}
try {
element.click();
return true;
} catch (e) {
console.log('直接click方法失败,尝试其他方法');
}
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);
}
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);
}
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);
}
function processUser(row, userNameElement, callback) {
const userName = userNameElement.textContent.trim();
const dialogId = 'dialog_' + (++config.dialogCounter);
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);
}
}
});
}
function openUserDialog(userNameElement, dialogId) {
closeAllDialogs(() => {
const randomParam = `?t=${Date.now()}`;
userNameElement.href = userNameElement.href.split('?')[0] + randomParam;
safeClick(userNameElement, () => {
waitForDialogContent(dialogId, userNameElement.textContent.trim());
});
});
}
function waitForDialogContent(dialogId, expectedUserName) {
const maxWait = 3000;
const start = Date.now();
const check = setInterval(() => {
const dialog = document.querySelector('.el-dialog__wrapper:not([style*="display: none"])');
if (!dialog) return;
const dialogUser = dialog.querySelector('.user-name')?.textContent.trim();
const contentLoaded = dialog.textContent.includes('余额')
|| dialog.textContent.includes('Balance');
if (dialogUser === expectedUserName && contentLoaded) {
clearInterval(check);
checkUserProfit(dialog, expectedUserName, dialogId, () => {
config.activeDialogs[dialogId].callback();
});
}
if (Date.now() - start > maxWait) {
clearInterval(check);
console.error(`[${expectedUserName}] 对话框内容加载超时`);
closeDialog(dialogId);
config.activeDialogs[dialogId].callback();
}
}, 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
);
if (batchSize <= 0) {
setTimeout(processBatch, 100);
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 checkUserProfit(dialog, userName, dialogId, callback) {
const observer = new MutationObserver((mutations) => {
const balanceTables = Array.from(dialog.querySelectorAll('.el-table')).filter(table => {
const headers = Array.from(table.querySelectorAll('th'));
return headers.some(th => {
const text = th.textContent.trim().toLowerCase();
return text.includes('余额') || text.includes('balance');
});
});
if (balanceTables.length > 0) {
observer.disconnect();
processActualBalance(balanceTables[0], userName, dialogId, callback);
}
});
observer.observe(dialog, {
childList: true,
subtree: true,
attributes: true
});
setTimeout(() => {
observer.disconnect();
console.error(`[${userName}] 表格加载超时`);
closeDialog(dialogId);
callback();
}, 3000);
}
function processActualBalance(table, userName, dialogId, callback) {
const userRow = Array.from(table.querySelectorAll('tr')).find(tr => {
return tr.textContent.includes(userName.split('_')[1]);
});
if (!userRow) {
console.error(`[${userName}] 未找到用户对应行`);
closeDialog(dialogId);
callback();
return;
}
const headers = Array.from(table.querySelectorAll('th'));
const balanceIndex = headers.findIndex(th => {
const text = th.textContent.trim().toLowerCase();
return text.includes('余额') || text.includes('balance');
});
if (balanceIndex === -1) {
console.error(`[${userName}] 未找到余额列`);
closeDialog(dialogId);
callback();
return;
}
const balanceCell = userRow.querySelector(`td:nth-child(${balanceIndex + 1}) .cell`);
if (!balanceCell) {
console.error(`[${userName}] 未找到余额单元格`);
closeDialog(dialogId);
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);
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);
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(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) {
console.warn(`[ALERT] ${message}`);
fallbackAlert(message);
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);
}
}
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;
}
}
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);
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);
}
})();