From 3d9990ddea348691cec68b5da14e860f59fb4569 Mon Sep 17 00:00:00 2001 From: Alex Yang Date: Wed, 26 Nov 2025 01:17:25 +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 | 55 ++++++++++ static/js/server-status.js | 216 +++++++++++++++++++++++++++++++++++++ 2 files changed, 271 insertions(+) create mode 100644 static/js/server-status.js diff --git a/static/index.html b/static/index.html index 1f1acac..47c3115 100644 --- a/static/index.html +++ b/static/index.html @@ -58,6 +58,34 @@ animation: glow-pulse 2s ease-in-out; } + /* 服务器状态组件光晕效果 */ + .glow-effect { + animation: pulse 2s ease-in-out; + } + + @keyframes pulse { + 0% { + box-shadow: 0 0 0 0 rgba(41, 128, 185, 0.4); + } + 70% { + box-shadow: 0 0 0 10px rgba(41, 128, 185, 0); + } + 100% { + box-shadow: 0 0 0 0 rgba(41, 128, 185, 0); + } + } + + /* 服务器状态组件样式优化 */ + .server-status-widget { + min-width: 170px; + transition: all 0.3s ease; + } + + .server-status-widget:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + } + /* 蓝色光晕效果 */ .number-glow-blue { animation: glow-blue 2s ease-in-out; @@ -211,6 +239,32 @@
+ +
+
+
+ CPU + 0% +
+
+
+
+
+
+
+
+ 查询 + 0 +
+
+
+
+
+
+ +
+
+ @@ -564,6 +618,7 @@ + diff --git a/static/js/server-status.js b/static/js/server-status.js new file mode 100644 index 0000000..1698321 --- /dev/null +++ b/static/js/server-status.js @@ -0,0 +1,216 @@ +// server-status.js - 服务器状态组件功能实现 + +// 全局变量 +let serverStatusUpdateTimer = null; +let previousServerData = { + cpu: 0, + queries: 0 +}; + +// 初始化服务器状态组件 +function initServerStatusWidget() { + console.log('初始化服务器状态组件'); + + // 确保组件存在 + if (!document.getElementById('server-status-widget')) { + console.warn('服务器状态组件不存在'); + return; + } + + // 监听页面切换事件 + handlePageSwitchEvents(); + + // 初始加载数据 + loadServerStatusData(); + + // 监听WebSocket连接事件 + monitorWebSocketConnection(); +} + +// 处理页面切换事件 +function handlePageSwitchEvents() { + // 监听导航点击事件 + document.querySelectorAll('.sidebar-link').forEach(link => { + link.addEventListener('click', () => { + // 页面切换后重新初始化组件 + setTimeout(() => { + if (document.getElementById('server-status-widget')) { + loadServerStatusData(); + } + }, 300); + }); + }); +} + +// 监听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监听器 +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); + } + }; +} + +// 加载服务器状态数据 +async function loadServerStatusData() { + try { + // 使用现有的API获取系统状态 + const statusData = await window.api?.getStatus(); + if (statusData && !statusData.error) { + updateServerStatusWidget(statusData); + } + } catch (error) { + console.error('加载服务器状态数据失败:', error); + } +} + +// 更新服务器状态组件 +function updateServerStatusWidget(stats) { + // 确保组件存在 + const widget = document.getElementById('server-status-widget'); + if (!widget) return; + + // 提取CPU使用率 + let cpuUsage = 0; + if (stats.system && stats.system.cpu) { + cpuUsage = stats.system.cpu; + } else if (stats.cpuUsage) { + cpuUsage = stats.cpuUsage; + } + + // 提取查询量 + 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; + } + + // 更新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 + }; +} + +// 添加光晕提示效果 +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); +} + +// 格式化数字(添加千位分隔符) +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(); +} + +// 在DOM加载完成后初始化 +window.addEventListener('DOMContentLoaded', () => { + // 延迟初始化,确保页面完全加载 + setTimeout(initServerStatusWidget, 500); + + // 监听页面切换事件(已在handlePageSwitchEvents中处理) +}); + +// 在页面卸载时清理资源 +window.addEventListener('beforeunload', () => { + if (serverStatusUpdateTimer) { + clearInterval(serverStatusUpdateTimer); + serverStatusUpdateTimer = null; + } +}); + +// 导出函数供其他模块使用 +window.serverStatusWidget = { + init: initServerStatusWidget, + update: updateServerStatusWidget +}; \ No newline at end of file