网络流量
-
0.0 MB/s
+
0.0
+
接收: 0 MB/s | 发送: 0 MB/s
总量: 接收 0 MB | 发送 0 MB
diff --git a/backend/static/js/app.js b/backend/static/js/app.js
index 43a2286..18b4091 100644
--- a/backend/static/js/app.js
+++ b/backend/static/js/app.js
@@ -6,7 +6,8 @@ let state = {
currentTimeRange: '1h', // 与UI默认值保持一致
customStartTime: '',
customEndTime: '',
- currentInterval: '10m' // 固定10分钟区间
+ currentInterval: '10m', // 固定10分钟区间
+ historyMetrics: {} // 存储历史指标数据
}
// WebSocket连接
@@ -1200,133 +1201,196 @@ function handleMetricsUpdate(message) {
// 更新状态卡片
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状态卡片
- if (metrics.cpu) {
- if (Array.isArray(metrics.cpu) && metrics.cpu.length > 0) {
- const latestCPU = metrics.cpu[metrics.cpu.length - 1].value;
- const cpuElement = document.getElementById('cpuValue');
- if (cpuElement) {
- cpuElement.textContent = `${latestCPU.toFixed(1)}%`;
- }
- } else if (typeof metrics.cpu === 'number') {
- const cpuElement = document.getElementById('cpuValue');
- if (cpuElement) {
- cpuElement.textContent = `${metrics.cpu.toFixed(1)}%`;
- }
+ if (displayMetrics.cpu) {
+ let cpuUsage = 0;
+ let cpuGhz = 0;
+ let cpuLoad = 0;
+
+ // 解析CPU数据
+ if (Array.isArray(displayMetrics.cpu) && displayMetrics.cpu.length > 0) {
+ cpuUsage = displayMetrics.cpu[displayMetrics.cpu.length - 1].value;
+ } else if (typeof displayMetrics.cpu === 'number') {
+ cpuUsage = displayMetrics.cpu;
+ } 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 (Array.isArray(metrics.memory) && metrics.memory.length > 0) {
- const latestMemory = metrics.memory[metrics.memory.length - 1].value;
- const memoryElement = document.getElementById('memoryValue');
- if (memoryElement) {
- memoryElement.textContent = `${latestMemory.toFixed(1)}%`;
- }
- } else if (typeof metrics.memory === 'number') {
- const memoryElement = document.getElementById('memoryValue');
- if (memoryElement) {
- memoryElement.textContent = `${metrics.memory.toFixed(1)}%`;
- }
+ if (displayMetrics.memory) {
+ let memoryUsage = 0;
+ let memoryUsed = 0;
+ let memoryTotal = 0;
+
+ // 解析内存数据
+ if (Array.isArray(displayMetrics.memory) && displayMetrics.memory.length > 0) {
+ memoryUsage = displayMetrics.memory[displayMetrics.memory.length - 1].value;
+ } else if (typeof displayMetrics.memory === 'number') {
+ memoryUsage = displayMetrics.memory;
+ } 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) {
- const diskElement = document.getElementById('diskValue');
- if (diskElement) {
- if (typeof metrics.disk === 'object' && metrics.disk !== null && !Array.isArray(metrics.disk)) {
- // 计算所有挂载点的平均使用率
- let totalUsage = 0;
- let mountpointCount = 0;
-
- for (const mountpoint in metrics.disk) {
- const data = metrics.disk[mountpoint];
- if (data && Array.isArray(data) && data.length > 0) {
- const latestValue = data[data.length - 1].value;
- totalUsage += latestValue;
- mountpointCount++;
- } else if (typeof data === 'number') {
- totalUsage += data;
- mountpointCount++;
- }
+ if (displayMetrics.disk) {
+ let totalUsed = 0;
+ let totalSize = 0;
+ let usagePercent = 0;
+
+ // 过滤掉不需要的挂载点
+ const excludedMountpoints = ['/usr', '/boot', '/boot/efi'];
+
+ // 解析磁盘数据
+ if (typeof displayMetrics.disk === 'object' && displayMetrics.disk !== null && !Array.isArray(displayMetrics.disk)) {
+ // 按挂载点分组的数据
+ for (const mountpoint in displayMetrics.disk) {
+ // 跳过排除的挂载点
+ if (excludedMountpoints.includes(mountpoint)) {
+ continue;
}
- if (mountpointCount > 0) {
- const averageUsage = totalUsage / mountpointCount;
- diskElement.textContent = `${averageUsage.toFixed(1)}%`;
+ const data = displayMetrics.disk[mountpoint];
+ if (data && typeof data === 'object' && data.used !== undefined && data.total !== undefined) {
+ 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) {
- const networkValueElement = document.getElementById('networkValue');
- const networkSentElement = document.getElementById('networkSent');
- const networkReceivedElement = document.getElementById('networkReceived');
+ if (displayMetrics.network) {
+ let sentRate = 0;
+ let receivedRate = 0;
+ 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 &&
- Array.isArray(metrics.network.received) && metrics.network.received.length > 0) {
+ if (Array.isArray(displayMetrics.network.sent) && displayMetrics.network.sent.length > 0 &&
+ Array.isArray(displayMetrics.network.received) && displayMetrics.network.received.length > 0) {
- const latestSent = metrics.network.sent[metrics.network.sent.length - 1].value;
- const latestReceived = metrics.network.received[metrics.network.received.length - 1].value;
-
- if (networkValueElement) {
- // 显示较大的值
- 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);
- }
+ sentRate = displayMetrics.network.sent[displayMetrics.network.sent.length - 1].value;
+ receivedRate = displayMetrics.network.received[displayMetrics.network.received.length - 1].value;
+ // 计算总量(假设数组中的值是累积的)
+ sentTotal = displayMetrics.network.sent.reduce((sum, item) => sum + item.value, 0);
+ receivedTotal = displayMetrics.network.received.reduce((sum, item) => sum + item.value, 0);
}
// 处理数值格式的数据
- else if (typeof metrics.network.sent === 'number' && typeof metrics.network.received === 'number') {
- if (networkValueElement) {
- const maxValue = Math.max(metrics.network.sent, metrics.network.received);
- networkValueElement.textContent = formatBytes(maxValue, 2, true);
- }
-
- if (networkSentElement) {
- networkSentElement.textContent = formatBytes(metrics.network.sent, 2, true);
- }
-
- if (networkReceivedElement) {
- networkReceivedElement.textContent = formatBytes(metrics.network.received, 2, true);
- }
+ else if (typeof displayMetrics.network.sent === 'number' && typeof displayMetrics.network.received === 'number') {
+ sentRate = displayMetrics.network.sent;
+ receivedRate = displayMetrics.network.received;
+ sentTotal = displayMetrics.network.sent_total || sentRate;
+ receivedTotal = displayMetrics.network.received_total || receivedRate;
}
- } else if (typeof metrics.network === 'object' &&
- metrics.network.bytes_sent !== undefined &&
- metrics.network.bytes_received !== undefined) {
+ } else if (typeof displayMetrics.network === 'object' &&
+ displayMetrics.network.bytes_sent !== undefined &&
+ displayMetrics.network.bytes_received !== undefined) {
// WebSocket消息格式
- if (networkValueElement) {
- const maxValue = Math.max(metrics.network.bytes_sent, metrics.network.bytes_received);
- networkValueElement.textContent = formatBytes(maxValue, 2, true);
- }
-
- if (networkSentElement) {
- networkSentElement.textContent = formatBytes(metrics.network.bytes_sent, 2, true);
- }
-
- if (networkReceivedElement) {
- networkReceivedElement.textContent = formatBytes(metrics.network.bytes_received, 2, true);
- }
+ sentRate = displayMetrics.network.bytes_sent;
+ receivedRate = displayMetrics.network.bytes_received;
+ sentTotal = displayMetrics.network.bytes_sent_total || sentRate;
+ receivedTotal = displayMetrics.network.bytes_received_total || receivedRate;
}
+
+ // 计算比率
+ 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} ↓ / ↑`;
+ }
+ if (networkDetailsElement) {
+ networkDetailsElement.innerHTML =
+ `接收: ${formatBytes(receivedRate, 2, true)} | ` +
+ `发送: ${formatBytes(sentRate, 2, true)}
` +
+ `总量: 接收 ${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;
}
}