修改web服务器指标卡片

This commit is contained in:
Alex Yang
2025-12-03 09:04:48 +08:00
parent c8cdd09455
commit dd01058b32
2 changed files with 172 additions and 104 deletions

View File

@@ -203,6 +203,7 @@
<div> <div>
<p class="text-sm text-gray-500 font-medium mb-1">CPU 使用率</p> <p class="text-sm text-gray-500 font-medium mb-1">CPU 使用率</p>
<h3 id="cpuValue" class="text-3xl font-bold text-gray-900 metric-value">0.0%</h3> <h3 id="cpuValue" class="text-3xl font-bold text-gray-900 metric-value">0.0%</h3>
<p id="cpuDetails" class="text-xs text-gray-500 mt-1">0.00 GHz | 负载: 0.00</p>
</div> </div>
<div class="bg-blue-100 p-3 rounded-full"> <div class="bg-blue-100 p-3 rounded-full">
<i class="fa fa-microchip text-blue-600 text-xl"></i> <i class="fa fa-microchip text-blue-600 text-xl"></i>
@@ -216,6 +217,7 @@
<div> <div>
<p class="text-sm text-gray-500 font-medium mb-1">内存使用率</p> <p class="text-sm text-gray-500 font-medium mb-1">内存使用率</p>
<h3 id="memoryValue" class="text-3xl font-bold text-gray-900 metric-value">0.0%</h3> <h3 id="memoryValue" class="text-3xl font-bold text-gray-900 metric-value">0.0%</h3>
<p id="memoryDetails" class="text-xs text-gray-500 mt-1">0 MB / 0 MB</p>
</div> </div>
<div class="bg-green-100 p-3 rounded-full"> <div class="bg-green-100 p-3 rounded-full">
<i class="fa fa-memory text-green-600 text-xl"></i> <i class="fa fa-memory text-green-600 text-xl"></i>
@@ -229,6 +231,7 @@
<div> <div>
<p class="text-sm text-gray-500 font-medium mb-1">磁盘使用率</p> <p class="text-sm text-gray-500 font-medium mb-1">磁盘使用率</p>
<h3 id="diskValue" class="text-3xl font-bold text-gray-900 metric-value">0.0%</h3> <h3 id="diskValue" class="text-3xl font-bold text-gray-900 metric-value">0.0%</h3>
<p id="diskDetails" class="text-xs text-gray-500 mt-1">0 MB / 0 MB</p>
</div> </div>
<div class="bg-yellow-100 p-3 rounded-full"> <div class="bg-yellow-100 p-3 rounded-full">
<i class="fa fa-hdd text-yellow-600 text-xl"></i> <i class="fa fa-hdd text-yellow-600 text-xl"></i>
@@ -241,7 +244,8 @@
<div class="flex justify-between items-start"> <div class="flex justify-between items-start">
<div> <div>
<p class="text-sm text-gray-500 font-medium mb-1">网络流量</p> <p class="text-sm text-gray-500 font-medium mb-1">网络流量</p>
<h3 id="networkValue" class="text-3xl font-bold text-gray-900 metric-value">0.0 MB/s</h3> <h3 id="networkValue" class="text-3xl font-bold text-gray-900 metric-value">0.0</h3>
<p id="networkDetails" class="text-xs text-gray-500 mt-1">接收: 0 MB/s | 发送: 0 MB/s<br>总量: 接收 0 MB | 发送 0 MB</p>
</div> </div>
<div class="bg-purple-100 p-3 rounded-full"> <div class="bg-purple-100 p-3 rounded-full">
<i class="fa fa-exchange-alt text-purple-600 text-xl"></i> <i class="fa fa-exchange-alt text-purple-600 text-xl"></i>

View File

@@ -6,7 +6,8 @@ let state = {
currentTimeRange: '1h', // 与UI默认值保持一致 currentTimeRange: '1h', // 与UI默认值保持一致
customStartTime: '', customStartTime: '',
customEndTime: '', customEndTime: '',
currentInterval: '10m' // 固定10分钟区间 currentInterval: '10m', // 固定10分钟区间
historyMetrics: {} // 存储历史指标数据
} }
// WebSocket连接 // WebSocket连接
@@ -1200,133 +1201,196 @@ function handleMetricsUpdate(message) {
// 更新状态卡片 // 更新状态卡片
function updateStatusCards(metrics) { function updateStatusCards(metrics) {
// 更新历史指标数据
updateHistoryMetrics(metrics);
// 使用历史数据或当前数据
const displayMetrics = {
cpu: metrics.cpu || state.historyMetrics.cpu,
memory: metrics.memory || state.historyMetrics.memory,
disk: metrics.disk || state.historyMetrics.disk,
network: metrics.network || state.historyMetrics.network
};
// 更新CPU状态卡片 // 更新CPU状态卡片
if (metrics.cpu) { if (displayMetrics.cpu) {
if (Array.isArray(metrics.cpu) && metrics.cpu.length > 0) { let cpuUsage = 0;
const latestCPU = metrics.cpu[metrics.cpu.length - 1].value; let cpuGhz = 0;
const cpuElement = document.getElementById('cpuValue'); let cpuLoad = 0;
if (cpuElement) {
cpuElement.textContent = `${latestCPU.toFixed(1)}%`; // 解析CPU数据
} if (Array.isArray(displayMetrics.cpu) && displayMetrics.cpu.length > 0) {
} else if (typeof metrics.cpu === 'number') { cpuUsage = displayMetrics.cpu[displayMetrics.cpu.length - 1].value;
const cpuElement = document.getElementById('cpuValue'); } else if (typeof displayMetrics.cpu === 'number') {
if (cpuElement) { cpuUsage = displayMetrics.cpu;
cpuElement.textContent = `${metrics.cpu.toFixed(1)}%`; } else if (typeof displayMetrics.cpu === 'object' && displayMetrics.cpu.usage) {
} cpuUsage = displayMetrics.cpu.usage;
cpuGhz = displayMetrics.cpu.frequency || 0;
cpuLoad = displayMetrics.cpu.load || 0;
}
// 更新显示
const cpuElement = document.getElementById('cpuValue');
const cpuDetailsElement = document.getElementById('cpuDetails');
if (cpuElement) {
cpuElement.textContent = `${cpuUsage.toFixed(1)}%`;
// 设置红色显示如果达到顶峰
cpuElement.className = cpuUsage > 90 ? 'text-red-500' : '';
}
if (cpuDetailsElement) {
cpuDetailsElement.textContent = `${cpuGhz.toFixed(2)} GHz | 负载: ${cpuLoad.toFixed(2)}`;
} }
} }
// 更新内存状态卡片 // 更新内存状态卡片
if (metrics.memory) { if (displayMetrics.memory) {
if (Array.isArray(metrics.memory) && metrics.memory.length > 0) { let memoryUsage = 0;
const latestMemory = metrics.memory[metrics.memory.length - 1].value; let memoryUsed = 0;
const memoryElement = document.getElementById('memoryValue'); let memoryTotal = 0;
if (memoryElement) {
memoryElement.textContent = `${latestMemory.toFixed(1)}%`; // 解析内存数据
} if (Array.isArray(displayMetrics.memory) && displayMetrics.memory.length > 0) {
} else if (typeof metrics.memory === 'number') { memoryUsage = displayMetrics.memory[displayMetrics.memory.length - 1].value;
const memoryElement = document.getElementById('memoryValue'); } else if (typeof displayMetrics.memory === 'number') {
if (memoryElement) { memoryUsage = displayMetrics.memory;
memoryElement.textContent = `${metrics.memory.toFixed(1)}%`; } else if (typeof displayMetrics.memory === 'object') {
} memoryUsage = displayMetrics.memory.usage || 0;
memoryUsed = displayMetrics.memory.used || 0;
memoryTotal = displayMetrics.memory.total || 0;
}
// 更新显示
const memoryElement = document.getElementById('memoryValue');
const memoryDetailsElement = document.getElementById('memoryDetails');
if (memoryElement) {
memoryElement.textContent = `${memoryUsage.toFixed(1)}%`;
// 设置红色显示如果达到顶峰
memoryElement.className = memoryUsage > 90 ? 'text-red-500' : '';
}
if (memoryDetailsElement) {
memoryDetailsElement.textContent = `${formatBytes(memoryUsed)} / ${formatBytes(memoryTotal)}`;
} }
} }
// 更新磁盘状态卡片 // 更新磁盘状态卡片
if (metrics.disk) { if (displayMetrics.disk) {
const diskElement = document.getElementById('diskValue'); let totalUsed = 0;
if (diskElement) { let totalSize = 0;
if (typeof metrics.disk === 'object' && metrics.disk !== null && !Array.isArray(metrics.disk)) { let usagePercent = 0;
// 计算所有挂载点的平均使用率
let totalUsage = 0;
let mountpointCount = 0;
for (const mountpoint in metrics.disk) { // 过滤掉不需要的挂载点
const data = metrics.disk[mountpoint]; const excludedMountpoints = ['/usr', '/boot', '/boot/efi'];
if (data && Array.isArray(data) && data.length > 0) {
const latestValue = data[data.length - 1].value; // 解析磁盘数据
totalUsage += latestValue; if (typeof displayMetrics.disk === 'object' && displayMetrics.disk !== null && !Array.isArray(displayMetrics.disk)) {
mountpointCount++; // 按挂载点分组的数据
} else if (typeof data === 'number') { for (const mountpoint in displayMetrics.disk) {
totalUsage += data; // 跳过排除的挂载点
mountpointCount++; if (excludedMountpoints.includes(mountpoint)) {
} continue;
} }
if (mountpointCount > 0) { const data = displayMetrics.disk[mountpoint];
const averageUsage = totalUsage / mountpointCount; if (data && typeof data === 'object' && data.used !== undefined && data.total !== undefined) {
diskElement.textContent = `${averageUsage.toFixed(1)}%`; totalUsed += data.used;
totalSize += data.total;
} }
} else if (Array.isArray(metrics.disk) && metrics.disk.length > 0) {
const latestDisk = metrics.disk[metrics.disk.length - 1].value;
diskElement.textContent = `${latestDisk.toFixed(1)}%`;
} else if (typeof metrics.disk === 'number') {
diskElement.textContent = `${metrics.disk.toFixed(1)}%`;
} }
} else if (typeof displayMetrics.disk === 'object' && displayMetrics.disk.used !== undefined && displayMetrics.disk.total !== undefined) {
// 单磁盘数据
totalUsed = displayMetrics.disk.used;
totalSize = displayMetrics.disk.total;
}
// 计算使用率
if (totalSize > 0) {
usagePercent = (totalUsed / totalSize) * 100;
}
// 更新显示
const diskElement = document.getElementById('diskValue');
const diskDetailsElement = document.getElementById('diskDetails');
if (diskElement) {
diskElement.textContent = `${usagePercent.toFixed(1)}%`;
// 设置红色显示如果达到顶峰
diskElement.className = usagePercent > 90 ? 'text-red-500' : '';
}
if (diskDetailsElement) {
diskDetailsElement.textContent = `${formatBytes(totalUsed)} / ${formatBytes(totalSize)}`;
} }
} }
// 更新网络状态卡片 // 更新网络状态卡片
if (metrics.network) { if (displayMetrics.network) {
const networkValueElement = document.getElementById('networkValue'); let sentRate = 0;
const networkSentElement = document.getElementById('networkSent'); let receivedRate = 0;
const networkReceivedElement = document.getElementById('networkReceived'); let sentTotal = 0;
let receivedTotal = 0;
// 处理不同格式的网络数据 // 解析网络数据
if (metrics.network.sent && metrics.network.received) { if (displayMetrics.network.sent && displayMetrics.network.received) {
// 处理数组格式的数据 // 处理数组格式的数据
if (Array.isArray(metrics.network.sent) && metrics.network.sent.length > 0 && if (Array.isArray(displayMetrics.network.sent) && displayMetrics.network.sent.length > 0 &&
Array.isArray(metrics.network.received) && metrics.network.received.length > 0) { Array.isArray(displayMetrics.network.received) && displayMetrics.network.received.length > 0) {
const latestSent = metrics.network.sent[metrics.network.sent.length - 1].value; sentRate = displayMetrics.network.sent[displayMetrics.network.sent.length - 1].value;
const latestReceived = metrics.network.received[metrics.network.received.length - 1].value; receivedRate = displayMetrics.network.received[displayMetrics.network.received.length - 1].value;
// 计算总量(假设数组中的值是累积的)
if (networkValueElement) { sentTotal = displayMetrics.network.sent.reduce((sum, item) => sum + item.value, 0);
// 显示较大的值 receivedTotal = displayMetrics.network.received.reduce((sum, item) => sum + item.value, 0);
const maxValue = Math.max(latestSent, latestReceived);
networkValueElement.textContent = formatBytes(maxValue, 2, true); // 显示速率
}
if (networkSentElement) {
networkSentElement.textContent = formatBytes(latestSent, 2, true);
}
if (networkReceivedElement) {
networkReceivedElement.textContent = formatBytes(latestReceived, 2, true);
}
} }
// 处理数值格式的数据 // 处理数值格式的数据
else if (typeof metrics.network.sent === 'number' && typeof metrics.network.received === 'number') { else if (typeof displayMetrics.network.sent === 'number' && typeof displayMetrics.network.received === 'number') {
if (networkValueElement) { sentRate = displayMetrics.network.sent;
const maxValue = Math.max(metrics.network.sent, metrics.network.received); receivedRate = displayMetrics.network.received;
networkValueElement.textContent = formatBytes(maxValue, 2, true); sentTotal = displayMetrics.network.sent_total || sentRate;
} receivedTotal = displayMetrics.network.received_total || receivedRate;
if (networkSentElement) {
networkSentElement.textContent = formatBytes(metrics.network.sent, 2, true);
}
if (networkReceivedElement) {
networkReceivedElement.textContent = formatBytes(metrics.network.received, 2, true);
}
} }
} else if (typeof metrics.network === 'object' && } else if (typeof displayMetrics.network === 'object' &&
metrics.network.bytes_sent !== undefined && displayMetrics.network.bytes_sent !== undefined &&
metrics.network.bytes_received !== undefined) { displayMetrics.network.bytes_received !== undefined) {
// WebSocket消息格式 // WebSocket消息格式
if (networkValueElement) { sentRate = displayMetrics.network.bytes_sent;
const maxValue = Math.max(metrics.network.bytes_sent, metrics.network.bytes_received); receivedRate = displayMetrics.network.bytes_received;
networkValueElement.textContent = formatBytes(maxValue, 2, true); sentTotal = displayMetrics.network.bytes_sent_total || sentRate;
} receivedTotal = displayMetrics.network.bytes_received_total || receivedRate;
if (networkSentElement) {
networkSentElement.textContent = formatBytes(metrics.network.bytes_sent, 2, true);
}
if (networkReceivedElement) {
networkReceivedElement.textContent = formatBytes(metrics.network.bytes_received, 2, true);
}
} }
// 计算比率
let ratioText = '0.0';
if (sentRate > 0) {
ratioText = (receivedRate / sentRate).toFixed(1);
}
// 更新显示
const networkValueElement = document.getElementById('networkValue');
const networkDetailsElement = document.getElementById('networkDetails');
if (networkValueElement) {
networkValueElement.innerHTML = `${ratioText} <span style="color: green;">↓</span> / <span style="color: red;">↑</span>`;
}
if (networkDetailsElement) {
networkDetailsElement.innerHTML =
`接收: <span style="color: green;">${formatBytes(receivedRate, 2, true)}</span> | ` +
`发送: <span style="color: red;">${formatBytes(sentRate, 2, true)}</span><br>` +
`总量: 接收 ${formatBytes(receivedTotal)} | 发送 ${formatBytes(sentTotal)}`;
}
}
}
// 更新历史指标数据
function updateHistoryMetrics(metrics) {
// 只更新有有效数据的指标
if (metrics.cpu) {
state.historyMetrics.cpu = metrics.cpu;
}
if (metrics.memory) {
state.historyMetrics.memory = metrics.memory;
}
if (metrics.disk) {
state.historyMetrics.disk = metrics.disk;
}
if (metrics.network) {
state.historyMetrics.network = metrics.network;
} }
} }