增加websocket,数据实时显示

This commit is contained in:
Alex Yang
2025-11-26 01:37:47 +08:00
parent 3d9990ddea
commit d293831bf9
2 changed files with 262 additions and 162 deletions

View File

@@ -260,6 +260,30 @@
<div id="server-queries-bar" class="h-full bg-primary rounded-full" style="width: 0%"></div> <div id="server-queries-bar" class="h-full bg-primary rounded-full" style="width: 0%"></div>
</div> </div>
</div> </div>
<!-- 额外指标区域 - 初始隐藏,只在非首页显示 -->
<div id="server-additional-stats" class="hidden flex items-center">
<div class="w-1 h-8 bg-gray-200 rounded-full mx-1"></div>
<div class="flex flex-col">
<div class="flex items-center">
<span class="text-xs font-medium text-gray-500">总量</span>
<span id="server-total-queries" class="ml-2 text-sm font-semibold">0</span>
</div>
</div>
<div class="w-1 h-8 bg-gray-200 rounded-full mx-1"></div>
<div class="flex flex-col">
<div class="flex items-center">
<span class="text-xs font-medium text-gray-500">屏蔽</span>
<span id="server-blocked-queries" class="ml-2 text-sm font-semibold">0</span>
</div>
</div>
<div class="w-1 h-8 bg-gray-200 rounded-full mx-1"></div>
<div class="flex flex-col">
<div class="flex items-center">
<span class="text-xs font-medium text-gray-500">正常</span>
<span id="server-allowed-queries" class="ml-2 text-sm font-semibold">0</span>
</div>
</div>
</div>
<div class="absolute top-1 right-1"> <div class="absolute top-1 right-1">
<span id="server-status-indicator" class="inline-block w-2 h-2 bg-success rounded-full"></span> <span id="server-status-indicator" class="inline-block w-2 h-2 bg-success rounded-full"></span>
</div> </div>

View File

@@ -1,4 +1,4 @@
// server-status.js - 服务器状态组件功能实现 // 服务器状态组件 - 显示CPU使用率和查询统计
// 全局变量 // 全局变量
let serverStatusUpdateTimer = null; let serverStatusUpdateTimer = null;
@@ -9,83 +9,129 @@ let previousServerData = {
// 初始化服务器状态组件 // 初始化服务器状态组件
function initServerStatusWidget() { function initServerStatusWidget() {
console.log('初始化服务器状态组件'); // 确保DOM元素存在
const widget = document.getElementById('server-status-widget');
if (!widget) return;
// 确保组件存在 // 初始化页面类型检测
if (!document.getElementById('server-status-widget')) { updateWidgetDisplayByPageType();
console.warn('服务器状态组件不存在');
return;
}
// 监听页面切换事件 // 设置页面切换事件监听
handlePageSwitchEvents(); handlePageSwitchEvents();
// 初始加载数据 // 设置WebSocket监听如果可用
setupWebSocketListeners();
// 立即加载一次数据
loadServerStatusData(); loadServerStatusData();
// 监听WebSocket连接事件 // 设置定时更新每5秒更新一次
monitorWebSocketConnection(); 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;
}
}
// 方法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() { function handlePageSwitchEvents() {
// 监听导航点击事件 // 监听哈希变化(导航切换)
document.querySelectorAll('.sidebar-link').forEach(link => { window.addEventListener('hashchange', updateWidgetDisplayByPageType);
link.addEventListener('click', () => {
// 页面切换后重新初始化组 // 监听侧边栏点击事
setTimeout(() => { const sidebarLinks = document.querySelectorAll('.sidebar a');
if (document.getElementById('server-status-widget')) { sidebarLinks.forEach(link => {
loadServerStatusData(); link.addEventListener('click', function() {
} // 延迟检查,确保页面已切换
}, 300); setTimeout(updateWidgetDisplayByPageType, 100);
});
});
// 监听导航菜单点击事件
const navLinks = document.querySelectorAll('nav a');
navLinks.forEach(link => {
link.addEventListener('click', function() {
setTimeout(updateWidgetDisplayByPageType, 100);
}); });
}); });
} }
// 监WebSocket连接 // 监WebSocket连接状态
function monitorWebSocketConnection() { function monitorWebSocketConnection() {
// 检查全局WebSocket连接 // 如果存在WebSocket连接,监听消息
if (window.wsConnection && window.wsConnection.readyState === WebSocket.OPEN) { if (window.socket) {
setupWebSocketListeners(); window.socket.addEventListener('message', function(event) {
} else { try {
// 如果WebSocket未连接尝试监听其连接状态 const data = JSON.parse(event.data);
const originalOnOpen = window.wsConnection?.onopen; if (data.type === 'status_update') {
if (window.wsConnection) { updateServerStatusWidget(data.payload);
window.wsConnection.onopen = function(event) {
if (originalOnOpen) originalOnOpen(event);
setupWebSocketListeners();
};
} }
} catch (error) {
console.error('解析WebSocket消息失败:', error);
}
});
} }
} }
// 设置WebSocket监听器 // 设置WebSocket监听器
function setupWebSocketListeners() { function setupWebSocketListeners() {
// 保存原始的onmessage函数 // 如果WebSocket已经存在
const originalOnMessage = window.wsConnection.onmessage; if (window.socket) {
monitorWebSocketConnection();
// 重写onmessage函数 } else {
window.wsConnection.onmessage = function(event) { // 监听socket初始化事件
// 调用原始函数 window.addEventListener('socketInitialized', function() {
if (originalOnMessage) originalOnMessage(event); monitorWebSocketConnection();
});
// 处理服务器状态数据
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() { async function loadServerStatusData() {
try { try {
// 使用现有的API获取系统状态 // 使用现有的API获取系统状态
const statusData = await window.api?.getStatus(); const api = window.api || {};
const getStatusFn = api.getStatus || function() { return Promise.resolve({}); };
const statusData = await getStatusFn();
if (statusData && !statusData.error) { if (statusData && !statusData.error) {
updateServerStatusWidget(statusData); updateServerStatusWidget(statusData);
} }
@@ -100,72 +146,104 @@ function updateServerStatusWidget(stats) {
const widget = document.getElementById('server-status-widget'); const widget = document.getElementById('server-status-widget');
if (!widget) return; if (!widget) return;
// 确保stats存在
stats = stats || {};
// 提取CPU使用率 // 提取CPU使用率
let cpuUsage = 0; let cpuUsage = 0;
if (stats.system && stats.system.cpu) { if (stats.system && typeof stats.system.cpu === 'number') {
cpuUsage = stats.system.cpu; cpuUsage = stats.system.cpu;
} else if (stats.cpuUsage) { } else if (typeof stats.cpuUsage === 'number') {
cpuUsage = stats.cpuUsage; cpuUsage = stats.cpuUsage;
} }
// 提取查询 // 提取查询统计数据
let queryCount = 0; let totalQueries = 0;
let blockedQueries = 0;
let allowedQueries = 0;
if (stats.dns) { if (stats.dns) {
queryCount = (stats.dns.Allowed || 0) + (stats.dns.Blocked || 0) + (stats.dns.Errors || 0); const allowed = typeof stats.dns.Allowed === 'number' ? stats.dns.Allowed : 0;
} else if (stats.totalQueries) { const blocked = typeof stats.dns.Blocked === 'number' ? stats.dns.Blocked : 0;
queryCount = stats.totalQueries; 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使用率 // 更新CPU使用率
if (document.getElementById('server-cpu-value')) { const cpuValueElement = document.getElementById('server-cpu-value');
document.getElementById('server-cpu-value').textContent = cpuUsage.toFixed(1) + '%'; if (cpuValueElement) {
cpuValueElement.textContent = cpuUsage.toFixed(1) + '%';
} }
if (document.getElementById('server-cpu-bar')) {
document.getElementById('server-cpu-bar').style.width = Math.min(cpuUsage, 100) + '%'; const cpuBarElement = document.getElementById('server-cpu-bar');
if (cpuBarElement) {
cpuBarElement.style.width = Math.min(cpuUsage, 100) + '%';
// 根据CPU使用率改变颜色 // 根据CPU使用率改变颜色
const cpuBar = document.getElementById('server-cpu-bar');
if (cpuUsage > 80) { if (cpuUsage > 80) {
cpuBar.className = 'h-full bg-danger rounded-full'; cpuBarElement.className = 'h-full bg-danger rounded-full';
} else if (cpuUsage > 50) { } else if (cpuUsage > 50) {
cpuBar.className = 'h-full bg-warning rounded-full'; cpuBarElement.className = 'h-full bg-warning rounded-full';
} else { } else {
cpuBar.className = 'h-full bg-success rounded-full'; cpuBarElement.className = 'h-full bg-success rounded-full';
} }
} }
// 更新查询量 // 更新查询量
if (document.getElementById('server-queries-value')) { const queriesValueElement = document.getElementById('server-queries-value');
document.getElementById('server-queries-value').textContent = formatNumber(queryCount); if (queriesValueElement) {
queriesValueElement.textContent = formatNumber(totalQueries);
} }
// 计算查询量百分比假设最大查询量为10000 // 计算查询量百分比假设最大查询量为10000
const queryPercentage = Math.min((queryCount / 10000) * 100, 100); const queryPercentage = Math.min((totalQueries / 10000) * 100, 100);
if (document.getElementById('server-queries-bar')) { const queriesBarElement = document.getElementById('server-queries-bar');
document.getElementById('server-queries-bar').style.width = queryPercentage + '%'; 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 !== queryCount) { if (previousServerData.cpu !== cpuUsage || previousServerData.queries !== totalQueries) {
addGlowEffect(); addGlowEffect();
} }
// 更新服务器状态指示器 // 更新服务器状态指示器
if (document.getElementById('server-status-indicator')) { const statusIndicator = document.getElementById('server-status-indicator');
const indicator = document.getElementById('server-status-indicator'); if (statusIndicator) {
// 检查系统状态 // 检查系统状态
if (stats.system && stats.system.status === 'error') { if (stats.system && stats.system.status === 'error') {
indicator.className = 'inline-block w-2 h-2 bg-danger rounded-full'; statusIndicator.className = 'inline-block w-2 h-2 bg-danger rounded-full';
} else { } else {
indicator.className = 'inline-block w-2 h-2 bg-success rounded-full'; statusIndicator.className = 'inline-block w-2 h-2 bg-success rounded-full';
} }
} }
// 保存当前数据用于下次比较 // 保存当前数据用于下次比较
previousServerData = { previousServerData = {
cpu: cpuUsage, cpu: cpuUsage,
queries: queryCount queries: totalQueries
}; };
} }
@@ -178,12 +256,12 @@ function addGlowEffect() {
widget.classList.add('glow-effect'); widget.classList.add('glow-effect');
// 2秒后移除光晕 // 2秒后移除光晕
setTimeout(() => { setTimeout(function() {
widget.classList.remove('glow-effect'); widget.classList.remove('glow-effect');
}, 2000); }, 2000);
} }
// 格式化数字(添加千位分隔符) // 格式化数字
function formatNumber(num) { function formatNumber(num) {
if (num >= 1000000) { if (num >= 1000000) {
return (num / 1000000).toFixed(1) + 'M'; return (num / 1000000).toFixed(1) + 'M';
@@ -194,15 +272,13 @@ function formatNumber(num) {
} }
// 在DOM加载完成后初始化 // 在DOM加载完成后初始化
window.addEventListener('DOMContentLoaded', () => { window.addEventListener('DOMContentLoaded', function() {
// 延迟初始化,确保页面完全加载 // 延迟初始化,确保页面完全加载
setTimeout(initServerStatusWidget, 500); setTimeout(initServerStatusWidget, 500);
// 监听页面切换事件已在handlePageSwitchEvents中处理
}); });
// 在页面卸载时清理资源 // 在页面卸载时清理资源
window.addEventListener('beforeunload', () => { window.addEventListener('beforeunload', function() {
if (serverStatusUpdateTimer) { if (serverStatusUpdateTimer) {
clearInterval(serverStatusUpdateTimer); clearInterval(serverStatusUpdateTimer);
serverStatusUpdateTimer = null; serverStatusUpdateTimer = null;