feat: 逐步加回col-extra/col-disk/DualLineChart (全部通过Node检查)

This commit is contained in:
qinglong
2026-06-14 12:30:31 +08:00
parent 71c9508330
commit cd02cf3de7
+62 -1
View File
@@ -56,7 +56,7 @@
.node-notes { font-size:.75rem; color:var(--text-dim); font-style:italic; margin-bottom:8px }
/* 横版布局 — 左设备信息 | 右数据+图表同行 */
#sentinel-grid.layout-row { display:flex;flex-direction:column;gap:12px }
#sentinel-grid.layout-row .node-card { display:grid;grid-template-columns:160px 1fr 0.8fr 1fr;gap:12px 16px;align-items:start }
#sentinel-grid.layout-row .node-card { display:grid;grid-template-columns:160px 1fr 0.8fr 1fr 0.8fr 1fr;gap:12px 16px;align-items:start }
#sentinel-grid.layout-row .col-left { min-width:0 }
#sentinel-grid.layout-row .col-right-stack { display:flex;flex-direction:column;gap:12px;min-width:0 }
#sentinel-grid.layout-row .col-extra { display:flex;flex-direction:column;gap:6px;padding:0 8px }
@@ -70,6 +70,30 @@
#sentinel-grid.layout-row .part-name { font-weight:500;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap }
#sentinel-grid.layout-row .part-mount { color:var(--text-dim);font-size:.65rem }
#sentinel-grid.layout-row .part-bar { height:3px;border-radius:1px;background:var(--md-sys-color-surface-container-lowest);margin:2px 0 }
#sentinel-grid.layout-row .part-bar-fill { height:100%;border-radius:1px;background:var(--primary) }
#sentinel-grid.layout-row .part-detail { display:flex;justify-content:space-between;font-size:.6rem;color:var(--text-dim) }
#sentinel-grid.layout-row .part-pct { text-align:right }
#sentinel-grid.layout-row .col-extra { display:flex;flex-direction:column;gap:6px;padding:0 8px }
#sentinel-grid.layout-row .extra-row { font-size:.8rem;padding:3px 0;border-bottom:1px solid var(--md-sys-color-surface-container-lowest) }
#sentinel-grid.layout-row .extra-row .elabel { font-size:.65rem;color:var(--text-dim);text-transform:uppercase;margin-right:4px }
#sentinel-grid.layout-row .extra-row .eval { font-weight:500 }
#sentinel-grid.layout-row .col-disk { overflow-y:auto;max-height:200px;padding:0 4px }
#sentinel-grid.layout-row .disk-list { display:flex;flex-direction:column;gap:4px }
#sentinel-grid.layout-row .part-row { display:flex;flex-direction:column;gap:2px;padding:3px 0;border-bottom:1px solid var(--md-sys-color-surface-container-lowest) }
#sentinel-grid.layout-row .part-info { display:flex;justify-content:space-between;font-size:.7rem }
#sentinel-grid.layout-row .part-name { font-weight:500;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap }
#sentinel-grid.layout-row .part-mount { color:var(--text-dim);font-size:.65rem }
#sentinel-grid.layout-row .part-bar { height:3px;border-radius:1px;background:var(--md-sys-color-surface-container-lowest);margin:2px 0 }
#sentinel-grid.layout-row .part-bar-fill { height:100%;border-radius:1px;background:var(--primary) }
#sentinel-grid.layout-row .part-detail { display:flex;justify-content:space-between;font-size:.6rem;color:var(--text-dim) }
#sentinel-grid.layout-row .part-pct { text-align:right }
#sentinel-grid.layout-row .col-disk { overflow-y:auto;max-height:200px;padding:0 4px }
#sentinel-grid.layout-row .disk-list { display:flex;flex-direction:column;gap:4px }
#sentinel-grid.layout-row .part-row { display:flex;flex-direction:column;gap:2px;padding:3px 0;border-bottom:1px solid var(--md-sys-color-surface-container-lowest) }
#sentinel-grid.layout-row .part-info { display:flex;justify-content:space-between;font-size:.7rem }
#sentinel-grid.layout-row .part-name { font-weight:500;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap }
#sentinel-grid.layout-row .part-mount { color:var(--text-dim);font-size:.65rem }
#sentinel-grid.layout-row .part-bar { height:3px;border-radius:1px;background:var(--md-sys-color-surface-container-lowest);margin:2px 0 }
#sentinel-grid.layout-row .part-bar-fill { height:100%;border-radius:1px;background:var(--primary);transition:width .6s }
#sentinel-grid.layout-row .part-detail { display:flex;justify-content:space-between;font-size:.6rem;color:var(--text-dim) }
#sentinel-grid.layout-row .part-size { text-align:left }
@@ -208,6 +232,7 @@
'<div class="mtr" id="mtr-'+id+'-net"><div class="mtr-data"><span class="rlabel">NET</span> <span class="rval net-down" style="font-size:.85rem">0</span> <span class="rval net-up" style="font-size:.85rem">0</span></div><canvas id="'+id+'-net" width="200" height="48"></canvas></div>'+
'<div class="col-info" style="text-align:right;font-size:.7rem;color:var(--text-dim);margin-top:4px"></div>'+
'</div>'+
'<div class="col-disk"><div class="disk-list"></div></div>'+
'<div class="col-extra">'+
'<div class="extra-row"><span class="elabel">负载</span> <span class="eval load-val">—</span></div>'+
'<div class="extra-row"><span class="elabel">SWAP</span> <span class="eval swap-val">—</span></div>'+
@@ -319,6 +344,40 @@
if (trafEl && sysData.network) trafEl.textContent = '↓'+(sysData.network.rx_mb||0).toFixed(0)+'M ↑'+(sysData.network.tx_mb||0).toFixed(0)+'M';
if (procEl && sysData.process) procEl.textContent = (sysData.process.memory_mb||0).toFixed(0)+'MB';
// 更新额外指标
var loadEl = card.querySelector('.load-val');
var swapEl = card.querySelector('.swap-val');
var tempEl = card.querySelector('.temp-val');
var trafEl = card.querySelector('.traf-val');
var procEl = card.querySelector('.proc-val');
var sysData = n.system || {};
if (loadEl && sysData.cpu) loadEl.textContent = (sysData.cpu.load_avg||[0,0,0]).map(function(v){return v.toFixed(1);}).join(' / ');
if (swapEl && sysData.swap) { var st = sysData.swap.total_gb||0; swapEl.textContent = st > 0 ? (sysData.swap.percent||0).toFixed(1)+'% ('+(sysData.swap.used_gb||0).toFixed(1)+'G)' : '—'; }
if (tempEl && sysData.temperature) tempEl.textContent = (sysData.temperature.current||0) > 0 ? (sysData.temperature.current).toFixed(1)+'°C' : '—';
if (trafEl && sysData.network) trafEl.textContent = '↓'+(sysData.network.rx_mb||0).toFixed(0)+'M ↑'+(sysData.network.tx_mb||0).toFixed(0)+'M';
if (procEl && sysData.process) procEl.textContent = (sysData.process.memory_mb||0).toFixed(0)+'MB';
// 磁盘分区
var diskList = card.querySelector('.disk-list');
if (diskList && sysData.partitions) {
var parts = sysData.partitions || [];
if (!diskList.querySelector('.part-row') || diskList.children.length !== parts.length) {
diskList.innerHTML = parts.map(function(p){
return '<div class="part-row"><div class="part-info"><span class="part-name">'+esc(p.device||'?')+'</span> <span class="part-mount">'+esc(p.mount||'')+'</span></div><div class="part-bar"><div class="part-bar-fill" style="width:'+(p.percent||0)+'%"></div></div><div class="part-detail"><span class="part-size">'+fmtSizeGB(p)+'</span><span class="part-pct">'+(p.percent||0).toFixed(0)+'%</span></div></div>';
}).join('');
} else {
var rows = diskList.querySelectorAll('.part-row');
parts.forEach(function(p, i){
if (rows[i]) {
var fill = rows[i].querySelector('.part-bar-fill');
var pct = rows[i].querySelector('.part-pct');
if (fill) fill.style.width = (p.percent||0)+'%';
if (pct) pct.textContent = (p.percent||0).toFixed(0)+'%';
}
});
}
}
var infoR = card.querySelector('.col-info');
if (infoR) infoR.textContent = (n.last_seen ? new Date(n.last_seen*1000).toLocaleTimeString() : '—');
} else {
@@ -366,6 +425,8 @@
function bar(v) { return v < 60 ? 'bar-green' : (v < 85 ? 'bar-yellow' : 'bar-red'); }
function fmtSizeGB(p) { var u=p.used_gb||0, t=p.total_gb||0; return fmtSize(u*1073741824)+' / '+fmtSize(t*1073741824); }
function fmtSize(bytes) { if(bytes===undefined||bytes===null)return'—'; bytes=Math.abs(bytes); if(bytes>=1e12)return(bytes/1e12).toFixed(1)+' TB'; if(bytes>=1e9)return(bytes/1e9).toFixed(1)+' GB'; if(bytes>=1e6)return(bytes/1e6).toFixed(1)+' MB'; if(bytes>=1e3)return(bytes/1e3).toFixed(1)+' KB'; return bytes.toFixed(0)+' B'; }
function fmtSize(bytes) { if(bytes===undefined||bytes===null)return'—'; bytes=Math.abs(bytes); if(bytes>=1e12)return(bytes/1e12).toFixed(1)+' TB'; if(bytes>=1e9)return(bytes/1e9).toFixed(1)+' GB'; if(bytes>=1e6)return(bytes/1e6).toFixed(1)+' MB'; if(bytes>=1e3)return(bytes/1e3).toFixed(1)+' KB'; return bytes.toFixed(0)+' B'; }
function fmtSizeGB(p) { var u=p.used_gb||0, t=p.total_gb||0; return fmtSize(u*1073741824)+' / '+fmtSize(t*1073741824); }
function fmtSpeed(bps) { return bps<1024?bps.toFixed(0)+'B/s':(bps<1048576?(bps/1024).toFixed(0)+'K/s':(bps/1048576).toFixed(1)+'M/s'); }
function esc(s) { return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;'); }