diff --git a/README.md b/README.md index 6ce18c6..849c700 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![License](https://img.shields.io/badge/license-MIT-4EB1BA.svg?style=flat-square)](https://github.com/cppla/ServerStatus) [![Version](https://img.shields.io/badge/Version-Build%201.1.6-red)](https://github.com/cppla/ServerStatus) -![Latest Host Version](https://dl.cpp.la/Archive/serverstatus_1_1_6.png) +![Latest Host Version](https://dl.cpp.la/Archive/serverstatus_1_1_6_1.png) `Watchdog触发式告警,interval只是为了防止频繁收到报警信息造成的骚扰,并不是探测间隔。值得注意的是,Exprtk库默认使用窄字符类型,中文等Unicode字符无法解析计算,等待修复。 ` diff --git a/web/css/app.css b/web/css/app.css index 3e78f06..0480d0b 100644 --- a/web/css/app.css +++ b/web/css/app.css @@ -90,17 +90,13 @@ table.data tbody tr:hover{background:rgba(255,255,255,.04)} .badge.ok{background:rgba(16,185,129,.15);color:var(--ok);border-color:rgba(16,185,129,.3)} .badge.warn{background:rgba(245,158,11,.15);color:var(--warn);border-color:rgba(245,158,11,.4)} .badge.err{background:rgba(239,68,68,.15);color:var(--danger);border-color:rgba(239,68,68,.4)} -.meter{--val:0;--clr:var(--accent);position:relative;height:18px;border-radius:14px;background:linear-gradient(145deg,var(--bg),var(--bg-alt));border:1px solid var(--border);overflow:hidden;min-width:64px} -.meter span{position:absolute;inset:0;background:linear-gradient(90deg,var(--clr),var(--clr) 60%,var(--accent-glow));background-size:160% 100%;width:calc(var(--val)*1%);transition:width .8s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:500;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.35)} -.meter.danger{--clr:var(--danger)} -.meter.warn{--clr:var(--warn)} .footer{margin:2rem 0 2.5rem;display:flex;align-items:center;justify-content:center;gap:.5rem;font-size:12px;color:var(--text-dim)} .footer a{color:var(--text-dim)} .footer a:hover{color:var(--accent)} .muted{color:var(--text-dim)} .status-off{color:var(--danger);font-weight:600} .status-on{color:var(--ok);font-weight:600} -@media (max-width:1100px){.nav{flex-wrap:wrap}.table-wrap{border-radius:8px}.meter{min-width:54px}} +@media (max-width:1100px){.nav{flex-wrap:wrap}.table-wrap{border-radius:8px}} @keyframes fade{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}} /* modal styles */ @@ -238,17 +234,7 @@ body.light .gauge-half .needle{background:linear-gradient(var(--text),var(--text table.data tbody tr.high-load{background:rgba(239,68,68,.10);} table.data tbody tr.high-load:hover{background:rgba(239,68,68,.18);} -/* 详情进度条 */ -.row-bars{display:flex;gap:.6rem;align-items:stretch} -.bar-wrap{flex:1;display:flex;flex-direction:column;gap:.25rem;min-width:0} -.bar-label{display:flex;justify-content:space-between;font-size:11px;opacity:.85;font-family:ui-monospace,monospace;letter-spacing:.5px} -.bar{position:relative;height:14px;border-radius:8px;background:linear-gradient(145deg,var(--bg),var(--bg-alt));border:1px solid var(--border);overflow:hidden} -.bar span{position:absolute;inset:0;--p:0;background:linear-gradient(90deg,var(--accent),var(--accent-glow));width:calc(var(--p)*100%);transition:width .9s cubic-bezier(.4,0,.2,1),background .4s} -.bar[data-warn] span{background:linear-gradient(90deg,var(--warn),#fbbf24)} -.bar[data-bad] span{background:linear-gradient(90deg,var(--danger),#f87171)} -.bar.io span{background:linear-gradient(90deg,#0284c7,#38bdf8)} -.bar.io[data-warn] span{background:linear-gradient(90deg,var(--warn),#fbbf24)} -.bar.io[data-bad] span{background:linear-gradient(90deg,var(--danger),#f87171)} +/* 旧进度条相关样式已清理 */ .cards .card-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;} .cards .card-title{font-weight:600;font-size:.95rem;} .cards .tag{font-size:.65rem;padding:.15rem .4rem;border-radius:4px;background:var(--border);letter-spacing:.5px;} diff --git a/web/js/app.js b/web/js/app.js index 3ae406b..852e916 100644 --- a/web/js/app.js +++ b/web/js/app.js @@ -8,9 +8,7 @@ const els = { sslBody: ()=>document.getElementById('sslBody') }; -function bytes(v){ if(v===0) return '0B'; if(!v) return '-'; const k=1000; const u=['B','KB','MB','GB','TB','PB']; const i=Math.floor(Math.log(v)/Math.log(k)); return (v/Math.pow(k,i)).toFixed(i?1:0)+u[i]; } -// 通用进位:从 KB/MB 起始单位自动进位到 KB/MB/GB/TB,与 bytes() 风格一致 (1000 进位) -function humanAuto(v,startIdx=0){ if(v==null||isNaN(v)) return '-'; const units=['KB','MB','GB','TB','PB']; let val=v; let i=startIdx; while(val>=1000 && istartIdx? val.toFixed(1): val.toFixed(0))+units[i]; } +// (清理) 已移除 bytes / humanAuto 等未使用的通用进位函数 // 最小单位 MB: function humanMinMBFromKB(kb){ if(kb==null||isNaN(kb)) return '-'; // 输入单位: KB let mb = kb/1000; const units=['MB','GB','TB','PB']; let i=0; while(mb>=1000 && i=1000 && i=100? kb.toFixed(0): kb.toFixed(1); return out+units[i]; } -function pct(v){ return (v||0).toFixed(0)+'%'; } -function clsBy(v){ return v>=90?'danger':v>=80?'warn':'ok'; } +// (清理) pct / clsBy 已不再使用 function humanAgo(ts){ if(!ts) return '-'; const s=Math.floor((Date.now()/1000 - ts)); const m=Math.floor(s/60); return m>0? m+' 分钟前':'几秒前'; } function num(v){ return (typeof v==='number' && !isNaN(v)) ? v : '-'; } @@ -88,9 +85,8 @@ function renderServers(){ const online = s.online4||s.online6; const proto = online ? (s.online4 && s.online6? '双栈': s.online4? 'IPv4':'IPv6') : '离线'; const statusPill = online ? `${proto}` : `${proto}`; - const cpuCls = clsBy(s.cpu); - const memPct = s.memory_total? (s.memory_used/s.memory_total*100):0; const memCls = clsBy(memPct); - const hddPct = s.hdd_total? (s.hdd_used/s.hdd_total*100):0; const hddCls = clsBy(hddPct); + const memPct = s.memory_total? (s.memory_used/s.memory_total*100):0; + const hddPct = s.hdd_total? (s.hdd_used/s.hdd_total*100):0; const monthInBytes = (s.network_in - s.last_network_in) || 0; // 原始: B const monthOutBytes = (s.network_out - s.last_network_out) || 0; const monthIn = humanMinMBFromB(monthInBytes); // 最小单位 MB @@ -133,7 +129,7 @@ function renderServers(){ }); }); - // 仪表盘无需 drawSparks + // 仪表盘无需历史 spark 小图 } // 生成仪表盘 (圆形 conic-gradient) function gaugeHTML(type,val){ @@ -159,8 +155,8 @@ function renderServersCards(){ const online = s.online4||s.online6; const proto = online ? (s.online4 && s.online6? '双栈': s.online4? 'IPv4':'IPv6') : '离线'; const pill = `${proto}`; - const memPct = s.memory_total? (s.memory_used/s.memory_total*100):0; - const hddPct = s.hdd_total? (s.hdd_used/s.hdd_total*100):0; + const memPct = s.memory_total? (s.memory_used/s.memory_total*100):0; + const hddPct = s.hdd_total? (s.hdd_used/s.hdd_total*100):0; // 月流量(移动端)并应用 500GB 阈值配色逻辑 const monthInBytes = (s.network_in - s.last_network_in) || 0; // B const monthOutBytes = (s.network_out - s.last_network_out) || 0; @@ -444,32 +440,7 @@ window.addEventListener('resize', ()=>{ renderSSLCards(); }); -// 绘制小型折线 (sparklines) -function drawSparks(){ - const els = document.querySelectorAll('.spark'); - els.forEach(div=>{ - // 若已有canvas跳过重建 - let canvas = div.querySelector('canvas'); - if(!canvas){ canvas = document.createElement('canvas'); div.appendChild(canvas); } - const key = div.getAttribute('data-key'); - const metric = div.getAttribute('data-metric'); - const hist = (S.metricHist[key] && S.metricHist[key][metric])? S.metricHist[key][metric]:[]; - const W = 80, H = 26; canvas.width=W; canvas.height=H; const ctx=canvas.getContext('2d'); - ctx.clearRect(0,0,W,H); - div.classList.add('spark-ready'); - if(hist.length<2){ ctx.fillStyle='var(--text-dim)'; ctx.font='10px system-ui'; ctx.fillText('-', W/2-3, H/2+3); return; } - // 硬盘与 CPU/内存保持一致的折线显示(去掉低波动迷你条特殊样式) - const max = Math.max(...hist); const min = Math.min(...hist); const range = Math.max(1,max-min); - const step = W/(hist.length-1); - // 线颜色 - let color = '#3b82f6'; if(metric==='mem') color='#10b981'; else if(metric==='hdd') color='#f59e0b'; - ctx.strokeStyle=color; ctx.lineWidth=1.3; ctx.beginPath(); - hist.forEach((v,i)=>{ const x=i*step; const y=H - ( (v-min)/range )* (H-4) -2; if(i===0) ctx.moveTo(x,y); else ctx.lineTo(x,y); }); - ctx.stroke(); - // 当前值点 - const last = hist[hist.length-1]; const lx = W-1; const ly = H - ((last-min)/range)*(H-4)-2; ctx.fillStyle=color; ctx.beginPath(); ctx.arc(lx,ly,2,0,Math.PI*2); ctx.fill(); - }); -} +// (清理) drawSparks 已移除 // 负载折线图 (load1 历史) function drawLoadChart(key){