多项优化

This commit is contained in:
Alex Yang
2025-12-03 12:11:20 +08:00
parent bd70dc1748
commit 454a205051
3 changed files with 155 additions and 20 deletions

View File

@@ -3,7 +3,7 @@
"id": "yunc", "id": "yunc",
"name": "cloud", "name": "cloud",
"device_id": "yunc", "device_id": "yunc",
"token": "bedb47554f06ebabc075b52d8320428f", "token": "f1dee2c8ffbdd4974af84b92a254892b",
"interval": "10s", "interval": "10s",
"debug": true, "debug": true,
"api_port": 8081 "api_port": 8081

View File

@@ -38,6 +38,21 @@
font-feature-settings: "tnum"; font-feature-settings: "tnum";
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
} }
/* 自动刷新开关样式 */
.toggle-checkbox:checked {
right: 0;
border-color: #3b82f6;
}
.toggle-checkbox:checked + .toggle-label {
background-color: #3b82f6;
}
.toggle-checkbox {
right: 5px;
top: 2px;
}
</style> </style>
</head> </head>
<body class="bg-gray-50 text-gray-900"> <body class="bg-gray-50 text-gray-900">
@@ -257,33 +272,53 @@
<!-- 图表选项卡导航 --> <!-- 图表选项卡导航 -->
<div class="mb-6"> <div class="mb-6">
<div class="bg-white rounded-xl shadow-md border border-gray-100"> <div class="bg-white rounded-xl shadow-md border border-gray-100">
<div class="flex flex-wrap items-center justify-between px-6 py-4" id="chartTabs"> <div class="flex flex-wrap items-start justify-between px-6 py-4" id="chartTabs">
<!-- 选项卡导航 --> <!-- 选项卡导航 -->
<div class="flex flex-wrap"> <div class="flex flex-wrap items-center gap-2">
<!-- CPU 选项卡 --> <!-- CPU 选项卡 -->
<button class="chart-tab active px-4 py-2 text-sm font-medium text-blue-600 border-b-2 border-blue-600 hover:bg-gray-50 transition-colors mr-2" data-tab="cpu"> <button class="chart-tab active px-4 py-2 text-sm font-medium text-blue-600 border-b-2 border-blue-600 hover:bg-gray-50 transition-colors" data-tab="cpu">
CPU CPU
</button> </button>
<!-- 内存 选项卡 --> <!-- 内存 选项卡 -->
<button class="chart-tab px-4 py-2 text-sm font-medium text-gray-600 border-b-2 border-transparent hover:bg-gray-50 transition-colors mr-2" data-tab="memory"> <button class="chart-tab px-4 py-2 text-sm font-medium text-gray-600 border-b-2 border-transparent hover:bg-gray-50 transition-colors" data-tab="memory">
内存 内存
</button> </button>
<!-- 磁盘 选项卡 --> <!-- 磁盘 选项卡 -->
<button class="chart-tab px-4 py-2 text-sm font-medium text-gray-600 border-b-2 border-transparent hover:bg-gray-50 transition-colors mr-2" data-tab="disk"> <button class="chart-tab px-4 py-2 text-sm font-medium text-gray-600 border-b-2 border-transparent hover:bg-gray-50 transition-colors" data-tab="disk">
磁盘 磁盘
</button> </button>
<!-- 网络 选项卡 --> <!-- 网络 选项卡 -->
<button class="chart-tab px-4 py-2 text-sm font-medium text-gray-600 border-b-2 border-transparent hover:bg-gray-50 transition-colors mr-2" data-tab="network"> <button class="chart-tab px-4 py-2 text-sm font-medium text-gray-600 border-b-2 border-transparent hover:bg-gray-50 transition-colors" data-tab="network">
网络 网络
</button> </button>
<!-- 网速 选项卡 --> <!-- 网速 选项卡 -->
<button class="chart-tab px-4 py-2 text-sm font-medium text-gray-600 border-b-2 border-transparent hover:bg-gray-50 transition-colors mr-2" data-tab="speed"> <button class="chart-tab px-4 py-2 text-sm font-medium text-gray-600 border-b-2 border-transparent hover:bg-gray-50 transition-colors" data-tab="speed">
网速 网速
</button> </button>
<!-- 网卡选择和刷新按钮 -->
<div id="interfaceSelectorContainer" class="flex items-center gap-1 ml-4 hidden">
<label for="networkInterface" class="text-sm font-medium text-gray-700">网卡:</label>
<select id="networkInterface" class="px-3 py-1 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm">
<option value="all">所有网卡</option>
</select>
<button id="refreshInterfacesBtn" class="bg-gray-100 hover:bg-gray-200 text-gray-700 px-3 py-1 rounded-lg transition-colors text-sm">
<i class="fa fa-refresh"></i>
</button>
</div>
<!-- 自动刷新开关 -->
<div class="flex items-center gap-2 ml-4">
<label for="autoRefreshToggle" class="text-sm font-medium text-gray-700">自动刷新:</label>
<div class="relative inline-block w-10 mr-2 align-middle select-none">
<input type="checkbox" id="autoRefreshToggle" class="toggle-checkbox absolute block w-5 h-5 rounded-full bg-white border-4 appearance-none cursor-pointer" checked="false">
<label for="autoRefreshToggle" class="toggle-label block overflow-hidden h-5 rounded-full bg-gray-300 cursor-pointer"></label>
</div>
</div>
</div> </div>
<!-- 自定义时间选择 --> <!-- 自定义时间选择 -->
<div class="flex items-center gap-2"> <div class="flex items-center gap-2 mt-2 md:mt-0 w-full md:w-auto">
<input type="datetime-local" id="customStartTime" class="px-3 py-1 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm"> <input type="datetime-local" id="customStartTime" class="px-3 py-1 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm">
<span class="text-gray-500 text-sm"></span> <span class="text-gray-500 text-sm"></span>
<input type="datetime-local" id="customEndTime" class="px-3 py-1 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm"> <input type="datetime-local" id="customEndTime" class="px-3 py-1 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm">
@@ -375,8 +410,11 @@
<thead> <thead>
<tr class="bg-gray-50"> <tr class="bg-gray-50">
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">设备名称</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">设备名称</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">设备ID</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">IP地址</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">IP地址</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">token</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">状态</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">状态</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">创建时间</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">操作</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">操作</th>
</tr> </tr>
</thead> </thead>

View File

@@ -7,7 +7,8 @@ let state = {
customStartTime: '', customStartTime: '',
customEndTime: '', customEndTime: '',
currentInterval: '10m', // 固定10分钟区间 currentInterval: '10m', // 固定10分钟区间
historyMetrics: {} // 存储历史指标数据 historyMetrics: {}, // 存储历史指标数据
autoRefreshEnabled: false // 自动刷新开关状态,默认关闭
} }
// WebSocket连接 // WebSocket连接
@@ -31,6 +32,9 @@ function initApp() {
// 设置定时刷新 // 设置定时刷新
setInterval(loadMetrics, 30000); setInterval(loadMetrics, 30000);
setInterval(loadServerCount, 30000); setInterval(loadServerCount, 30000);
// 初始化网卡列表
loadNetworkInterfaces();
} }
// 初始化自定义时间范围 // 初始化自定义时间范围
@@ -1173,7 +1177,8 @@ async function loadServerInfo(deviceId) {
if (!response.ok) { if (!response.ok) {
throw new Error('Failed to fetch server info'); throw new Error('Failed to fetch server info');
} }
const deviceData = await response.json(); const data = await response.json();
const deviceData = data.device;
// 更新服务器信息显示 // 更新服务器信息显示
const serverInfoDisplay = document.getElementById('serverInfoDisplay'); const serverInfoDisplay = document.getElementById('serverInfoDisplay');
@@ -1193,11 +1198,14 @@ async function loadServerInfo(deviceId) {
// 处理指标更新 // 处理指标更新
function handleMetricsUpdate(message) { function handleMetricsUpdate(message) {
const { device_id, metrics } = message; const { device_id, metrics } = message;
// 直接更新不再检查device_id // 直接更新统计卡片,始终实时更新
updateStatusCards(metrics); updateStatusCards(metrics);
// 根据自动刷新开关状态决定是否刷新图表
if (state.autoRefreshEnabled) {
// 立即刷新数据以确保图表也更新 // 立即刷新数据以确保图表也更新
setTimeout(() => loadMetrics(), 500); setTimeout(() => loadMetrics(), 500);
} }
}
// 更新状态卡片 // 更新状态卡片
function updateStatusCards(metrics) { function updateStatusCards(metrics) {
@@ -2080,6 +2088,83 @@ function bindEvents() {
if (zoomOutBtn && zoomInBtn && currentTimeRangeDisplay) { if (zoomOutBtn && zoomInBtn && currentTimeRangeDisplay) {
// 时间范围选项列表,用于缩放 // 时间范围选项列表,用于缩放
const timeRanges = ['30m', '1h', '2h', '6h', '12h', '24h']; const timeRanges = ['30m', '1h', '2h', '6h', '12h', '24h'];
}
// 网卡选择和刷新按钮事件
const networkInterfaceSelect = document.getElementById('networkInterface');
const refreshInterfacesBtn = document.getElementById('refreshInterfacesBtn');
if (networkInterfaceSelect) {
networkInterfaceSelect.addEventListener('change', (e) => {
state.currentInterface = e.target.value;
loadMetrics(); // 切换网卡后重新加载数据
});
}
if (refreshInterfacesBtn) {
refreshInterfacesBtn.addEventListener('click', loadNetworkInterfaces);
}
// 自动刷新开关事件
const autoRefreshToggle = document.getElementById('autoRefreshToggle');
if (autoRefreshToggle) {
autoRefreshToggle.addEventListener('change', (e) => {
state.autoRefreshEnabled = e.target.checked;
// 如果开启了自动刷新,立即刷新一次数据
if (state.autoRefreshEnabled) {
loadMetrics();
}
});
}
}
// 加载网卡列表
async function loadNetworkInterfaces() {
try {
// 获取设备ID
const hash = window.location.hash;
let deviceId = '';
if (hash.startsWith('#serverMonitor/')) {
deviceId = hash.split('/')[1];
}
// 从网络指标API获取网卡列表
const response = await fetch(`${API_BASE_URL}/metrics/network?device_id=${deviceId}`);
const data = await response.json();
// 从返回的数据中提取网卡列表
const interfaces = Object.keys(data.data || {});
// 更新下拉选择框
const selectElement = document.getElementById('networkInterface');
if (selectElement) {
// 清空现有选项
selectElement.innerHTML = '<option value="all">所有网卡</option>';
// 添加新选项
interfaces.forEach(iface => {
if (iface !== 'all') {
const option = document.createElement('option');
option.value = iface;
option.textContent = iface;
selectElement.appendChild(option);
}
});
// 如果当前选中的网卡不存在,重置为'all'
if (!interfaces.includes(state.currentInterface) && state.currentInterface !== 'all') {
state.currentInterface = 'all';
}
// 设置当前选中的值
selectElement.value = state.currentInterface;
}
} catch (error) {
console.error('加载网卡列表失败:', error);
// 显示友好的错误提示
showToast('加载网卡列表失败,请稍后重试', 'error');
}
}
// 更新当前时间范围显示 // 更新当前时间范围显示
const updateTimeRangeDisplay = () => { const updateTimeRangeDisplay = () => {
@@ -2155,7 +2240,7 @@ function bindEvents() {
// 重新加载数据 // 重新加载数据
loadMetrics(); loadMetrics();
}); });
}
// 重置缩放按钮事件处理 // 重置缩放按钮事件处理
if (resetZoomBtn) { if (resetZoomBtn) {
@@ -2168,7 +2253,7 @@ function bindEvents() {
}); });
}); });
} }
}
// 工具函数 // 工具函数
function showContent(contentId) { function showContent(contentId) {
@@ -2231,6 +2316,18 @@ function initChartTabs() {
} }
}); });
}); });
// 初始状态:根据当前选中的选项卡显示/隐藏网卡选择下拉框
const activeTab = document.querySelector('.chart-tab.active');
const interfaceContainer = document.getElementById('interfaceSelectorContainer');
if (activeTab && interfaceContainer) {
const tabId = activeTab.dataset.tab;
if (tabId === 'network' || tabId === 'speed') {
interfaceContainer.classList.remove('hidden');
} else {
interfaceContainer.classList.add('hidden');
}
}
} }
// 页面加载完成后初始化 // 页面加载完成后初始化