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 @@
+
+
+
@@ -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