添加更详细的信息查询

This commit is contained in:
CN-JS-HuiBai
2026-04-04 22:05:53 +08:00
parent d0bd05409d
commit ba712f1907
5 changed files with 244 additions and 3 deletions

View File

@@ -1254,6 +1254,43 @@ input:checked+.slider:before {
align-items: center;
}
/* ---- Server Detail Grid ---- */
.detail-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
margin-top: 10px;
}
.detail-item {
background: var(--bg-card);
border: 1px solid var(--border-color);
padding: 16px;
border-radius: var(--radius-md);
display: flex;
flex-direction: column;
gap: 8px;
}
.detail-label {
font-size: 0.75rem;
font-weight: 600;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.detail-value {
font-family: var(--font-mono);
font-size: 1.1rem;
font-weight: 700;
color: var(--accent-indigo);
}
:root.light-theme .detail-value {
color: var(--accent-blue);
}
/* ---- Animations ---- */
@keyframes fadeInUp {
from {

View File

@@ -364,6 +364,64 @@
</div>
</div>
</div>
<!-- Server Detail Modal -->
<div class="modal-overlay" id="serverDetailModal">
<div class="modal" style="max-width: 600px;">
<div class="modal-header">
<h2 id="serverDetailTitle">服务器详情</h2>
<button class="modal-close" id="serverDetailClose">&times;</button>
</div>
<div class="modal-body" id="serverDetailBody">
<div id="detailLoading" style="text-align: center; padding: 20px; display: none;">
<div class="dot dot-pulse" style="display: inline-block; width: 12px; height: 12px; background: var(--accent-indigo);"></div>
<span style="margin-left: 10px; color: var(--text-secondary);">正在从数据库读取详情...</span>
</div>
<div class="detail-grid" id="detailGrid">
<div class="detail-item">
<span class="detail-label">CPU 忙碌率 (Busy)</span>
<span class="detail-value" id="detailCpuBusy">0%</span>
</div>
<div class="detail-item">
<span class="detail-label">系统负载 (Load)</span>
<span class="detail-value" id="detailSysLoad">0%</span>
</div>
<div class="detail-item">
<span class="detail-label">内存使用率 (RAM)</span>
<span class="detail-value" id="detailMemUsedPct">0%</span>
</div>
<div class="detail-item">
<span class="detail-label">SWAP 使用率</span>
<span class="detail-value" id="detailSwapUsedPct">0%</span>
</div>
<div class="detail-item">
<span class="detail-label">根分区使用率 (/)</span>
<span class="detail-value" id="detailRootFsUsedPct">0%</span>
</div>
<div class="detail-item">
<span class="detail-label">CPU 核心总数</span>
<span class="detail-value" id="detailCpuCores">0 核心</span>
</div>
<div class="detail-item">
<span class="detail-label">物理内存总量</span>
<span class="detail-value" id="detailMemTotal">0 GB</span>
</div>
<div class="detail-item">
<span class="detail-label">运行时间 (Uptime)</span>
<span class="detail-value" id="detailUptime">0天 0小时</span>
</div>
<div class="detail-item">
<span class="detail-label">网络接收速率 (RX)</span>
<span class="detail-value" id="detailNetRx">0 Mbps</span>
</div>
<div class="detail-item">
<span class="detail-label">网络发送速率 (TX)</span>
<span class="detail-value" id="detailNetTx">0 Mbps</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Login Modal -->

View File

@@ -60,7 +60,23 @@
loginForm: document.getElementById('loginForm'),
loginError: document.getElementById('loginError'),
footerTime: document.getElementById('footerTime'),
legendP95: document.getElementById('legendP95')
legendP95: document.getElementById('legendP95'),
// Server Details Modal
serverDetailModal: document.getElementById('serverDetailModal'),
serverDetailClose: document.getElementById('serverDetailClose'),
serverDetailTitle: document.getElementById('serverDetailTitle'),
detailGrid: document.getElementById('detailGrid'),
detailLoading: document.getElementById('detailLoading'),
detailCpuBusy: document.getElementById('detailCpuBusy'),
detailSysLoad: document.getElementById('detailSysLoad'),
detailMemUsedPct: document.getElementById('detailMemUsedPct'),
detailSwapUsedPct: document.getElementById('detailSwapUsedPct'),
detailRootFsUsedPct: document.getElementById('detailRootFsUsedPct'),
detailCpuCores: document.getElementById('detailCpuCores'),
detailMemTotal: document.getElementById('detailMemTotal'),
detailUptime: document.getElementById('detailUptime'),
detailNetRx: document.getElementById('detailNetRx'),
detailNetTx: document.getElementById('detailNetTx')
};
// ---- State ----
@@ -113,6 +129,26 @@
if (e.key === 'Escape') {
closeSettings();
closeLoginModal();
closeServerDetail();
}
});
// Server detail modal listeners
dom.serverDetailClose.addEventListener('click', closeServerDetail);
dom.serverDetailModal.addEventListener('click', (e) => {
if (e.target === dom.serverDetailModal) closeServerDetail();
});
// Server table row click delegator
dom.serverTableBody.addEventListener('click', (e) => {
const row = e.target.closest('tr');
if (row && !row.classList.contains('empty-row')) {
const instance = row.getAttribute('data-instance');
const job = row.getAttribute('data-job');
const source = row.getAttribute('data-source');
if (instance && job && source) {
openServerDetail(instance, job, source);
}
}
});
@@ -354,7 +390,7 @@
const diskPct = server.diskTotal > 0 ? (server.diskUsed / server.diskTotal * 100) : 0;
return `
<tr>
<tr data-instance="${escapeHtml(server.instance)}" data-job="${escapeHtml(server.job)}" data-source="${escapeHtml(server.source)}" style="cursor: pointer;">
<td>
<span class="status-dot ${server.up ? 'status-dot-online' : 'status-dot-offline'}"></span>
</td>
@@ -393,6 +429,54 @@
}).join('');
}
// ---- Server Detail ----
async function openServerDetail(instance, job, source) {
dom.serverDetailTitle.textContent = `${job} - 服务器详情`;
dom.serverDetailModal.classList.add('active');
// Show loading
dom.detailGrid.style.opacity = '0.3';
dom.detailLoading.style.display = 'block';
try {
const url = `/api/metrics/server-details?instance=${encodeURIComponent(instance)}&job=${encodeURIComponent(job)}&source=${encodeURIComponent(source)}`;
const response = await fetch(url);
if (!response.ok) throw new Error('Fetch failed');
const data = await response.json();
renderServerDetail(data);
} catch (err) {
console.error('Error fetching server details:', err);
} finally {
dom.detailGrid.style.opacity = '1';
dom.detailLoading.style.display = 'none';
}
}
function closeServerDetail() {
dom.serverDetailModal.classList.remove('active');
}
function renderServerDetail(data) {
dom.detailCpuBusy.textContent = formatPercent(data.cpuBusy);
dom.detailSysLoad.textContent = data.sysLoad.toFixed(1) + '%';
dom.detailMemUsedPct.textContent = formatPercent(data.memUsedPct);
dom.detailSwapUsedPct.textContent = formatPercent(data.swapUsedPct);
dom.detailRootFsUsedPct.textContent = formatPercent(data.rootFsUsedPct);
dom.detailCpuCores.textContent = data.cpuCores + ' 核心';
dom.detailMemTotal.textContent = formatBytes(data.memTotal);
// Uptime formatting
const uptimeSec = data.uptime;
const days = Math.floor(uptimeSec / 86400);
const hours = Math.floor((uptimeSec % 86400) / 3600);
const mins = Math.floor((uptimeSec % 3600) / 60);
dom.detailUptime.textContent = `${days}${hours}小时 ${mins}`;
dom.detailNetRx.textContent = formatBandwidth(data.netRx);
dom.detailNetTx.textContent = formatBandwidth(data.netTx);
}
// ---- Network History ----
async function fetchNetworkHistory() {
try {