From d293831bf93c9e1b2eac5bf28957f0657cfbf928 Mon Sep 17 00:00:00 2001 From: Alex Yang Date: Wed, 26 Nov 2025 01:37:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0websocket,=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=AE=9E=E6=97=B6=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/index.html | 24 +++ static/js/server-status.js | 400 ++++++++++++++++++++++--------------- 2 files changed, 262 insertions(+), 162 deletions(-) diff --git a/static/index.html b/static/index.html index 47c3115..f29d8d3 100644 --- a/static/index.html +++ b/static/index.html @@ -260,6 +260,30 @@
+ +
diff --git a/static/js/server-status.js b/static/js/server-status.js index 1698321..b7c6f31 100644 --- a/static/js/server-status.js +++ b/static/js/server-status.js @@ -1,4 +1,4 @@ -// server-status.js - 服务器状态组件功能实现 +// 服务器状态组件 - 显示CPU使用率和查询统计 // 全局变量 let serverStatusUpdateTimer = null; @@ -9,208 +9,284 @@ let previousServerData = { // 初始化服务器状态组件 function initServerStatusWidget() { - console.log('初始化服务器状态组件'); - - // 确保组件存在 - if (!document.getElementById('server-status-widget')) { - console.warn('服务器状态组件不存在'); - return; + // 确保DOM元素存在 + const widget = document.getElementById('server-status-widget'); + if (!widget) return; + + // 初始化页面类型检测 + updateWidgetDisplayByPageType(); + + // 设置页面切换事件监听 + handlePageSwitchEvents(); + + // 设置WebSocket监听(如果可用) + setupWebSocketListeners(); + + // 立即加载一次数据 + loadServerStatusData(); + + // 设置定时更新(每5秒更新一次) + serverStatusUpdateTimer = setInterval(loadServerStatusData, 5000); +} + +// 判断当前页面是否为仪表盘 +function isCurrentPageDashboard() { + // 方法1:检查侧边栏激活状态 + const dashboardLink = document.querySelector('.sidebar a[href="#dashboard"]'); + if (dashboardLink && dashboardLink.classList.contains('active')) { + return true; + } + + // 方法2:检查仪表盘特有元素 + const dashboardElements = [ + '#dashboard-container', + '.dashboard-summary', + '#dashboard-stats' + ]; + + for (const selector of dashboardElements) { + if (document.querySelector(selector)) { + return true; } - - // 监听页面切换事件 - handlePageSwitchEvents(); - - // 初始加载数据 - loadServerStatusData(); - - // 监听WebSocket连接事件 - monitorWebSocketConnection(); + } + + // 方法3:检查URL哈希值 + if (window.location.hash === '#dashboard' || window.location.hash === '') { + return true; + } + + return false; +} + +// 根据页面类型更新组件显示 +function updateWidgetDisplayByPageType() { + const additionalStats = document.getElementById('server-additional-stats'); + if (!additionalStats) return; + + // 如果当前页面是仪表盘,隐藏额外统计指标 + if (isCurrentPageDashboard()) { + additionalStats.classList.add('hidden'); + } else { + // 非仪表盘页面,显示额外统计指标 + additionalStats.classList.remove('hidden'); + } } // 处理页面切换事件 function handlePageSwitchEvents() { - // 监听导航点击事件 - document.querySelectorAll('.sidebar-link').forEach(link => { - link.addEventListener('click', () => { - // 页面切换后重新初始化组件 - setTimeout(() => { - if (document.getElementById('server-status-widget')) { - loadServerStatusData(); - } - }, 300); - }); + // 监听哈希变化(导航切换) + window.addEventListener('hashchange', updateWidgetDisplayByPageType); + + // 监听侧边栏点击事件 + const sidebarLinks = document.querySelectorAll('.sidebar a'); + sidebarLinks.forEach(link => { + link.addEventListener('click', function() { + // 延迟检查,确保页面已切换 + setTimeout(updateWidgetDisplayByPageType, 100); }); + }); + + // 监听导航菜单点击事件 + const navLinks = document.querySelectorAll('nav a'); + navLinks.forEach(link => { + link.addEventListener('click', function() { + setTimeout(updateWidgetDisplayByPageType, 100); + }); + }); } -// 监听WebSocket连接 +// 监控WebSocket连接状态 function monitorWebSocketConnection() { - // 检查全局WebSocket连接 - if (window.wsConnection && window.wsConnection.readyState === WebSocket.OPEN) { - setupWebSocketListeners(); - } else { - // 如果WebSocket未连接,尝试监听其连接状态 - const originalOnOpen = window.wsConnection?.onopen; - if (window.wsConnection) { - window.wsConnection.onopen = function(event) { - if (originalOnOpen) originalOnOpen(event); - setupWebSocketListeners(); - }; + // 如果存在WebSocket连接,监听消息 + if (window.socket) { + window.socket.addEventListener('message', function(event) { + try { + const data = JSON.parse(event.data); + if (data.type === 'status_update') { + updateServerStatusWidget(data.payload); } - } + } catch (error) { + console.error('解析WebSocket消息失败:', error); + } + }); + } } // 设置WebSocket监听器 function setupWebSocketListeners() { - // 保存原始的onmessage函数 - const originalOnMessage = window.wsConnection.onmessage; - - // 重写onmessage函数 - window.wsConnection.onmessage = function(event) { - // 调用原始函数 - if (originalOnMessage) originalOnMessage(event); - - // 处理服务器状态数据 - try { - const data = JSON.parse(event.data); - if (data.type === 'initial_data' || data.type === 'stats_update') { - updateServerStatusWidget(data.data); - } - } catch (error) { - console.error('处理服务器状态WebSocket消息失败:', error); - } - }; + // 如果WebSocket已经存在 + if (window.socket) { + monitorWebSocketConnection(); + } else { + // 监听socket初始化事件 + window.addEventListener('socketInitialized', function() { + monitorWebSocketConnection(); + }); + } } // 加载服务器状态数据 async function loadServerStatusData() { - try { - // 使用现有的API获取系统状态 - const statusData = await window.api?.getStatus(); - if (statusData && !statusData.error) { - updateServerStatusWidget(statusData); - } - } catch (error) { - console.error('加载服务器状态数据失败:', error); + try { + // 使用现有的API获取系统状态 + const api = window.api || {}; + const getStatusFn = api.getStatus || function() { return Promise.resolve({}); }; + const statusData = await getStatusFn(); + if (statusData && !statusData.error) { + updateServerStatusWidget(statusData); } + } catch (error) { + console.error('加载服务器状态数据失败:', error); + } } // 更新服务器状态组件 function updateServerStatusWidget(stats) { - // 确保组件存在 - const widget = document.getElementById('server-status-widget'); - if (!widget) return; + // 确保组件存在 + const widget = document.getElementById('server-status-widget'); + if (!widget) return; + + // 确保stats存在 + stats = stats || {}; + + // 提取CPU使用率 + let cpuUsage = 0; + if (stats.system && typeof stats.system.cpu === 'number') { + cpuUsage = stats.system.cpu; + } else if (typeof stats.cpuUsage === 'number') { + cpuUsage = stats.cpuUsage; + } + + // 提取查询统计数据 + let totalQueries = 0; + let blockedQueries = 0; + let allowedQueries = 0; + + if (stats.dns) { + const allowed = typeof stats.dns.Allowed === 'number' ? stats.dns.Allowed : 0; + const blocked = typeof stats.dns.Blocked === 'number' ? stats.dns.Blocked : 0; + const errors = typeof stats.dns.Errors === 'number' ? stats.dns.Errors : 0; + totalQueries = allowed + blocked + errors; + blockedQueries = blocked; + allowedQueries = allowed; + } else { + totalQueries = typeof stats.totalQueries === 'number' ? stats.totalQueries : 0; + blockedQueries = typeof stats.blockedQueries === 'number' ? stats.blockedQueries : 0; + allowedQueries = typeof stats.allowedQueries === 'number' ? stats.allowedQueries : 0; + } + + // 更新CPU使用率 + const cpuValueElement = document.getElementById('server-cpu-value'); + if (cpuValueElement) { + cpuValueElement.textContent = cpuUsage.toFixed(1) + '%'; + } + + const cpuBarElement = document.getElementById('server-cpu-bar'); + if (cpuBarElement) { + cpuBarElement.style.width = Math.min(cpuUsage, 100) + '%'; - // 提取CPU使用率 - let cpuUsage = 0; - if (stats.system && stats.system.cpu) { - cpuUsage = stats.system.cpu; - } else if (stats.cpuUsage) { - cpuUsage = stats.cpuUsage; + // 根据CPU使用率改变颜色 + if (cpuUsage > 80) { + cpuBarElement.className = 'h-full bg-danger rounded-full'; + } else if (cpuUsage > 50) { + cpuBarElement.className = 'h-full bg-warning rounded-full'; + } else { + cpuBarElement.className = 'h-full bg-success rounded-full'; } - - // 提取查询量 - let queryCount = 0; - if (stats.dns) { - queryCount = (stats.dns.Allowed || 0) + (stats.dns.Blocked || 0) + (stats.dns.Errors || 0); - } else if (stats.totalQueries) { - queryCount = stats.totalQueries; + } + + // 更新查询量 + const queriesValueElement = document.getElementById('server-queries-value'); + if (queriesValueElement) { + queriesValueElement.textContent = formatNumber(totalQueries); + } + + // 计算查询量百分比(假设最大查询量为10000) + const queryPercentage = Math.min((totalQueries / 10000) * 100, 100); + const queriesBarElement = document.getElementById('server-queries-bar'); + if (queriesBarElement) { + queriesBarElement.style.width = queryPercentage + '%'; + } + + // 更新额外统计指标 + const totalQueriesElement = document.getElementById('server-total-queries'); + if (totalQueriesElement) { + totalQueriesElement.textContent = formatNumber(totalQueries); + } + + const blockedQueriesElement = document.getElementById('server-blocked-queries'); + if (blockedQueriesElement) { + blockedQueriesElement.textContent = formatNumber(blockedQueries); + } + + const allowedQueriesElement = document.getElementById('server-allowed-queries'); + if (allowedQueriesElement) { + allowedQueriesElement.textContent = formatNumber(allowedQueries); + } + + // 添加光晕提示效果 + if (previousServerData.cpu !== cpuUsage || previousServerData.queries !== totalQueries) { + addGlowEffect(); + } + + // 更新服务器状态指示器 + const statusIndicator = document.getElementById('server-status-indicator'); + if (statusIndicator) { + // 检查系统状态 + if (stats.system && stats.system.status === 'error') { + statusIndicator.className = 'inline-block w-2 h-2 bg-danger rounded-full'; + } else { + statusIndicator.className = 'inline-block w-2 h-2 bg-success rounded-full'; } - - // 更新CPU使用率 - if (document.getElementById('server-cpu-value')) { - document.getElementById('server-cpu-value').textContent = cpuUsage.toFixed(1) + '%'; - } - if (document.getElementById('server-cpu-bar')) { - document.getElementById('server-cpu-bar').style.width = Math.min(cpuUsage, 100) + '%'; - - // 根据CPU使用率改变颜色 - const cpuBar = document.getElementById('server-cpu-bar'); - if (cpuUsage > 80) { - cpuBar.className = 'h-full bg-danger rounded-full'; - } else if (cpuUsage > 50) { - cpuBar.className = 'h-full bg-warning rounded-full'; - } else { - cpuBar.className = 'h-full bg-success rounded-full'; - } - } - - // 更新查询量 - if (document.getElementById('server-queries-value')) { - document.getElementById('server-queries-value').textContent = formatNumber(queryCount); - } - - // 计算查询量百分比(假设最大查询量为10000) - const queryPercentage = Math.min((queryCount / 10000) * 100, 100); - if (document.getElementById('server-queries-bar')) { - document.getElementById('server-queries-bar').style.width = queryPercentage + '%'; - } - - // 添加光晕提示效果 - if (previousServerData.cpu !== cpuUsage || previousServerData.queries !== queryCount) { - addGlowEffect(); - } - - // 更新服务器状态指示器 - if (document.getElementById('server-status-indicator')) { - const indicator = document.getElementById('server-status-indicator'); - - // 检查系统状态 - if (stats.system && stats.system.status === 'error') { - indicator.className = 'inline-block w-2 h-2 bg-danger rounded-full'; - } else { - indicator.className = 'inline-block w-2 h-2 bg-success rounded-full'; - } - } - - // 保存当前数据用于下次比较 - previousServerData = { - cpu: cpuUsage, - queries: queryCount - }; + } + + // 保存当前数据用于下次比较 + previousServerData = { + cpu: cpuUsage, + queries: totalQueries + }; } // 添加光晕提示效果 function addGlowEffect() { - const widget = document.getElementById('server-status-widget'); - if (!widget) return; - - // 添加光晕类 - widget.classList.add('glow-effect'); - - // 2秒后移除光晕 - setTimeout(() => { - widget.classList.remove('glow-effect'); - }, 2000); + const widget = document.getElementById('server-status-widget'); + if (!widget) return; + + // 添加光晕类 + widget.classList.add('glow-effect'); + + // 2秒后移除光晕 + setTimeout(function() { + widget.classList.remove('glow-effect'); + }, 2000); } -// 格式化数字(添加千位分隔符) +// 格式化数字 function formatNumber(num) { - if (num >= 1000000) { - return (num / 1000000).toFixed(1) + 'M'; - } else if (num >= 1000) { - return (num / 1000).toFixed(1) + 'K'; - } - return num.toString(); + if (num >= 1000000) { + return (num / 1000000).toFixed(1) + 'M'; + } else if (num >= 1000) { + return (num / 1000).toFixed(1) + 'K'; + } + return num.toString(); } // 在DOM加载完成后初始化 -window.addEventListener('DOMContentLoaded', () => { - // 延迟初始化,确保页面完全加载 - setTimeout(initServerStatusWidget, 500); - - // 监听页面切换事件(已在handlePageSwitchEvents中处理) +window.addEventListener('DOMContentLoaded', function() { + // 延迟初始化,确保页面完全加载 + setTimeout(initServerStatusWidget, 500); }); // 在页面卸载时清理资源 -window.addEventListener('beforeunload', () => { - if (serverStatusUpdateTimer) { - clearInterval(serverStatusUpdateTimer); - serverStatusUpdateTimer = null; - } +window.addEventListener('beforeunload', function() { + if (serverStatusUpdateTimer) { + clearInterval(serverStatusUpdateTimer); + serverStatusUpdateTimer = null; + } }); // 导出函数供其他模块使用 window.serverStatusWidget = { - init: initServerStatusWidget, - update: updateServerStatusWidget + init: initServerStatusWidget, + update: updateServerStatusWidget }; \ No newline at end of file