refactor: 横版左设备/中指标/右图表 — 三列配对布局
This commit is contained in:
@@ -54,16 +54,18 @@
|
|||||||
.node-sys { font-size:.75rem; color:var(--text-dim); margin-bottom:4px }
|
.node-sys { font-size:.75rem; color:var(--text-dim); margin-bottom:4px }
|
||||||
.node-url { font-size:.75rem; color:var(--text-dim); margin-bottom:8px; word-break:break-all }
|
.node-url { font-size:.75rem; color:var(--text-dim); margin-bottom:8px; word-break:break-all }
|
||||||
.node-notes { font-size:.75rem; color:var(--text-dim); font-style:italic; margin-bottom:8px }
|
.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 { display:flex;flex-direction:column;gap:12px }
|
||||||
#sentinel-grid.layout-row .node-card { display:grid;grid-template-columns:220px 1fr 180px;gap:12px 16px;align-items:start }
|
#sentinel-grid.layout-row .node-card { display:grid;grid-template-columns:200px 1fr 200px;gap:8px 16px;align-items:start }
|
||||||
#sentinel-grid.layout-row .col-left { min-width:0 }
|
#sentinel-grid.layout-row .col-left { min-width:0 }
|
||||||
#sentinel-grid.layout-row .col-mid { min-width:0 }
|
#sentinel-grid.layout-row .col-mid { display:flex;flex-direction:column;gap:8px }
|
||||||
#sentinel-grid.layout-row .col-right { display:flex;flex-direction:column;gap:8px }
|
#sentinel-grid.layout-row .col-mid .rlabel { font-size:.7rem;color:var(--text-dim);text-transform:uppercase;display:inline-block;width:40px }
|
||||||
#sentinel-grid.layout-row .col-chart { display:flex;flex-direction:column;gap:4px }
|
#sentinel-grid.layout-row .col-mid .rval { font-weight:600 }
|
||||||
#sentinel-grid.layout-row .col-chart canvas { border-radius:4px;background:var(--md-sys-color-surface-container-lowest) }
|
#sentinel-grid.layout-row .row-cpu, #sentinel-grid.layout-row .row-mem, #sentinel-grid.layout-row .row-net { padding:4px 0;border-bottom:1px solid var(--md-sys-color-surface-container-lowest) }
|
||||||
#sentinel-grid.layout-row .col-info { text-align:right }
|
#sentinel-grid.layout-row .col-right { display:flex;flex-direction:column;gap:4px }
|
||||||
#sentinel-grid.layout-row .node-time { grid-column:1/-1;margin-top:8px }
|
#sentinel-grid.layout-row .col-right canvas { border-radius:3px;background:var(--md-sys-color-surface-container-lowest) }
|
||||||
|
#sentinel-grid.layout-row .col-info { text-align:right;font-size:.75rem;color:var(--text-dim);margin-top:4px }
|
||||||
|
#sentinel-grid.layout-row .node-time { grid-column:1;margin-top:4px }
|
||||||
#sentinel-grid.layout-row .metric-bar { display:none }
|
#sentinel-grid.layout-row .metric-bar { display:none }
|
||||||
.metric-row { display:flex; gap:12px; margin-bottom:8px }
|
.metric-row { display:flex; gap:12px; margin-bottom:8px }
|
||||||
.metric { flex:1 }
|
.metric { flex:1 }
|
||||||
@@ -186,17 +188,19 @@
|
|||||||
(sysInfo.trim() ? '<div class="node-sys">'+esc(sysInfo)+'</div>' : '')+
|
(sysInfo.trim() ? '<div class="node-sys">'+esc(sysInfo)+'</div>' : '')+
|
||||||
'<div class="node-url">'+esc(n.url||'')+'</div>'+
|
'<div class="node-url">'+esc(n.url||'')+'</div>'+
|
||||||
(n.notes ? '<div class="node-notes">📝 '+esc(n.notes)+'</div>' : '')+
|
(n.notes ? '<div class="node-notes">📝 '+esc(n.notes)+'</div>' : '')+
|
||||||
|
'<div class="node-time"></div>'+
|
||||||
|
'</div>'+
|
||||||
|
'<div class="col-mid">'+
|
||||||
|
'<div class="row-cpu"><span class="rlabel">CPU</span> <span class="rval cpu-val">0%</span></div>'+
|
||||||
|
'<div class="row-mem"><span class="rlabel">MEM</span> <span class="rval mem-val">0%</span> <span class="mem-row-detail" style="font-size:.65rem;color:var(--text-dim)"></span></div>'+
|
||||||
|
'<div class="row-net"><span class="rlabel">NET</span> <span class="rval net-down" style="font-size:.85rem"></span> <span class="rval net-up" style="font-size:.85rem"></span></div>'+
|
||||||
'</div>'+
|
'</div>'+
|
||||||
'<div class="col-mid"><div class="metrics-body"></div></div>'+
|
|
||||||
'<div class="col-right">'+
|
'<div class="col-right">'+
|
||||||
'<div class="col-chart">'+
|
'<canvas id="'+id+'-cpu" width="180" height="36"></canvas>'+
|
||||||
'<canvas id="'+id+'-cpu" width="160" height="50"></canvas>'+
|
'<canvas id="'+id+'-mem" width="180" height="36"></canvas>'+
|
||||||
'<canvas id="'+id+'-mem" width="160" height="50"></canvas>'+
|
'<canvas id="'+id+'-net" width="180" height="36"></canvas>'+
|
||||||
'<canvas id="'+id+'-net" width="160" height="50"></canvas>'+
|
|
||||||
'</div>'+
|
|
||||||
'<div class="col-info"></div>'+
|
'<div class="col-info"></div>'+
|
||||||
'</div>'+
|
'</div>';
|
||||||
'<div class="node-time"></div>';
|
|
||||||
} else {
|
} else {
|
||||||
card.innerHTML =
|
card.innerHTML =
|
||||||
'<div class="node-name">'+(n.online?'🟢':'🔴')+' '+esc(n.name)+'</div>'+
|
'<div class="node-name">'+(n.online?'🟢':'🔴')+' '+esc(n.name)+'</div>'+
|
||||||
@@ -242,39 +246,27 @@
|
|||||||
body.setAttribute('data-mem', (sys.memory||{}).percent||0);
|
body.setAttribute('data-mem', (sys.memory||{}).percent||0);
|
||||||
|
|
||||||
if (isRow) {
|
if (isRow) {
|
||||||
// 初始化/更新中间栏的数值
|
// 更新中间列数值
|
||||||
var isNewRow = !body.querySelector('.cpu-val');
|
var cpuEl = card.querySelector('.cpu-val');
|
||||||
if (isNewRow) {
|
var memEl = card.querySelector('.mem-val');
|
||||||
body.innerHTML =
|
var netDn = card.querySelector('.net-down');
|
||||||
'<div class="metric-row">'+
|
var netUp = card.querySelector('.net-up');
|
||||||
'<div class="metric"><div class="metric-label">CPU</div><div class="metric-value cpu-val" style="font-size:1.3rem">0%</div></div>'+
|
var mrd = card.querySelector('.mem-row-detail');
|
||||||
'<div class="metric"><div class="metric-label">MEM</div><div class="metric-value mem-val" style="font-size:1.3rem">0%</div></div>'+
|
if (cpuEl) cpuEl.textContent = cpuVal.toFixed(1) + '%';
|
||||||
'<div class="metric"><div class="mem-row-detail" style="font-size:.7rem;color:var(--text-dim)"></div></div>'+
|
if (memEl) memEl.textContent = memVal.toFixed(1) + '%';
|
||||||
'</div>'+
|
if (netDn) netDn.textContent = '↓' + fmtSpeed(net.rx_bytes_sec||0);
|
||||||
'<div class="metric-row">'+
|
if (netUp) netUp.textContent = '↑' + fmtSpeed(net.tx_bytes_sec||0);
|
||||||
'<div class="metric"><div class="metric-label">NET ↓</div><div class="metric-value net-down" style="font-size:1rem"></div></div>'+
|
|
||||||
'<div class="metric"><div class="metric-label">NET ↑</div><div class="metric-value net-up" style="font-size:1rem"></div></div>'+
|
|
||||||
'</div>';
|
|
||||||
}
|
|
||||||
body.querySelector('.net-down').textContent = fmtSpeed(net.rx_bytes_sec||0);
|
|
||||||
body.querySelector('.net-up').textContent = fmtSpeed(net.tx_bytes_sec||0);
|
|
||||||
var mrd = body.querySelector('.mem-row-detail');
|
|
||||||
if (mrd) mrd.textContent = (mem.used_gb||0).toFixed(1)+'/'+(mem.total_gb||0).toFixed(1)+' GB';
|
if (mrd) mrd.textContent = (mem.used_gb||0).toFixed(1)+'/'+(mem.total_gb||0).toFixed(1)+' GB';
|
||||||
animateValue(body.querySelector('.cpu-val'), oldCpu, cpuVal, 1, '%');
|
|
||||||
animateValue(body.querySelector('.mem-val'), oldMem, memVal, 1, '%');
|
|
||||||
// 图表更新
|
// 图表更新
|
||||||
var charts = _chartInstances[id];
|
var charts = _chartInstances[id];
|
||||||
if (charts && charts[0]) {
|
if (charts && charts[0]) {
|
||||||
try { charts[0].update(cpuVal); charts[1].update(memVal); charts[2].update(net.rx_bytes_sec||0); } catch(e) {}
|
try { charts[0].update(cpuVal); charts[1].update(memVal); charts[2].update(net.rx_bytes_sec||0); } catch(e) {}
|
||||||
}
|
}
|
||||||
|
// 右侧信息
|
||||||
var infoR = card.querySelector('.col-info');
|
var infoR = card.querySelector('.col-info');
|
||||||
if (infoR) infoR.innerHTML =
|
if (infoR) infoR.textContent = (n.last_seen ? new Date(n.last_seen*1000).toLocaleTimeString() : '—');
|
||||||
'<div style="font-size:1.1rem;font-weight:600">CPU '+(cpuVal).toFixed(1)+'%</div>'+
|
var timeEl = card.querySelector('.node-time');
|
||||||
'<div style="font-size:1.1rem;font-weight:600;margin-top:4px">MEM '+(memVal).toFixed(1)+'%</div>'+
|
if (timeEl) timeEl.innerHTML = '<div style="font-size:.7rem;color:var(--text-dim);margin-top:8px">'+(n.last_seen ? new Date(n.last_seen*1000).toLocaleTimeString() : '—')+'</div>';
|
||||||
'<div style="font-size:.7rem;color:var(--text-dim);margin-top:4px">'+(mem.used_gb||0).toFixed(1)+'/'+(mem.total_gb||0).toFixed(1)+' GB</div>'+
|
|
||||||
'<div style="font-size:.75rem;color:var(--text-dim);margin-top:8px">↓ '+fmtSpeed(net.rx_bytes_sec||0)+'</div>'+
|
|
||||||
'<div style="font-size:.75rem;color:var(--text-dim)">↑ '+fmtSpeed(net.tx_bytes_sec||0)+'</div>';
|
|
||||||
card.querySelector('.node-time').innerHTML = '<div style="font-size:.7rem;color:var(--text-dim);margin-top:8px">'+(n.last_seen ? new Date(n.last_seen*1000).toLocaleTimeString() : '—')+'</div>';
|
|
||||||
} else {
|
} else {
|
||||||
// 网格模式 — oldCpu/oldMem 已在上面读取(在setAttribute之前)
|
// 网格模式 — oldCpu/oldMem 已在上面读取(在setAttribute之前)
|
||||||
var hasMetricBar = body.querySelector('.metric-bar');
|
var hasMetricBar = body.querySelector('.metric-bar');
|
||||||
|
|||||||
Reference in New Issue
Block a user