From 49decdfed1dee2de009e34a0787b371b8796d63f Mon Sep 17 00:00:00 2001 From: cppla Date: Fri, 15 Aug 2025 13:59:12 +0800 Subject: [PATCH] gpt commit --- web/css/app.css | 81 ++++++++++++++++++++++++++++++------------------- web/js/app.js | 30 ++++++------------ 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/web/css/app.css b/web/css/app.css index f112e82..54922c5 100644 --- a/web/css/app.css +++ b/web/css/app.css @@ -26,30 +26,30 @@ table.data tbody td{padding:.55rem .75rem;border-bottom:1px solid var(--border); /* 防止数值变化导致列抖动:为月流量(7)/当前网络(8)/总流量(9)设置固定宽度并使用等宽数字 */ table.data th,table.data td{font-variant-numeric:tabular-nums} /* 月流量(2) 左对齐;当前网络(8)/总流量(9) 居中 */ -table.data thead th:nth-child(2),table.data tbody td:nth-child(2){ +#serversTable thead th:nth-child(2),#serversTable tbody td:nth-child(2){ /* 月流量列:向左贴近协议(减小左 padding),同时加大右 padding 拉开与节点距离 */ width:128px;min-width:128px;max-width:128px;font-variant-numeric:tabular-nums;letter-spacing:.3px;text-align:center;padding:0 1.05rem 0 .15rem; } /* 节点列加宽,避免被月流量胶囊视觉挤压 */ -table.data thead th:nth-child(3),table.data tbody td:nth-child(3){ +#serversTable thead th:nth-child(3),#serversTable tbody td:nth-child(3){ width:160px;min-width:160px;max-width:160px; } /* 协议列继续收紧右侧 padding 与固定宽度 */ -table.data thead th:nth-child(1),table.data tbody td:nth-child(1){ +#serversTable thead th:nth-child(1),#serversTable tbody td:nth-child(1){ padding-right:.14rem;width:78px;min-width:78px;max-width:78px; /* 扩大协议列并恢复适度间距 */ } /* 让双色胶囊更靠近协议列 */ -table.data tbody td:nth-child(2) .caps-traffic.duo{margin-left:-6px;} /* 向协议方向微移,视觉更靠近;右侧 padding 增大避免靠近节点 */ -table.data thead th:nth-child(8),table.data tbody td:nth-child(8), -table.data thead th:nth-child(9),table.data tbody td:nth-child(9){ +#serversTable tbody td:nth-child(2) .caps-traffic.duo{margin-left:-6px;} /* 向协议方向微移,视觉更靠近;右侧 padding 增大避免靠近节点 */ +#serversTable thead th:nth-child(8),#serversTable tbody td:nth-child(8), +#serversTable thead th:nth-child(9),#serversTable tbody td:nth-child(9){ width:132px;min-width:132px;max-width:132px;font-variant-numeric:tabular-nums;letter-spacing:.3px;text-align:center; /* 进一步拉开与 CPU/内存/硬盘 组的视觉距离 */ padding-right:1.95rem; } /* CPU / 内存 / 硬盘 列:居中 + 固定宽度 与仪表盘一致 */ -table.data thead th:nth-child(10),table.data tbody td:nth-child(10), -table.data thead th:nth-child(11),table.data tbody td:nth-child(11), -table.data thead th:nth-child(12),table.data tbody td:nth-child(12){ +#serversTable thead th:nth-child(10),#serversTable tbody td:nth-child(10), +#serversTable thead th:nth-child(11),#serversTable tbody td:nth-child(11), +#serversTable thead th:nth-child(12),#serversTable tbody td:nth-child(12){ width:70px;min-width:70px;max-width:70px;text-align:center;padding-left:1.1rem;padding-right:0; /* 继续右移并贴近右侧列 */ } /* 月流量胶囊 */ @@ -118,10 +118,7 @@ table.data tbody tr:hover{background:rgba(255,255,255,.04)} /* 详情弹窗三列信息行 */ -/* spark lines */ -.spark{width:82px;height:28px;display:flex;align-items:center;justify-content:center} -.spark canvas{width:100%;height:100%;display:block} -/* 仪表盘样式 (替换 spark) */ +/* 旧 spark 样式已移除,现使用半圆仪表盘 */ /* 全圆旧样式(保留以便回退) */ .gauge{--p:0;--col:var(--accent);width:74px;height:74px;position:relative;display:grid;place-items:center;font-size:11px;font-family:ui-monospace,monospace;font-weight:600;color:var(--text);} .gauge:before{content:"";position:absolute;inset:0;border-radius:50%;background:conic-gradient(var(--col) calc(var(--p)*1turn),rgba(255,255,255,0.06) 0);mask:radial-gradient(circle at 50% 50%,transparent 58%,#000 59%);-webkit-mask:radial-gradient(circle at 50% 50%,transparent 58%,#000 59%);border:1px solid var(--border);box-shadow:0 2px 6px -2px rgba(0,0,0,.4),0 0 0 1px rgba(255,255,255,.05);} @@ -163,40 +160,38 @@ body.light .gauge-half .needle{background:linear-gradient(var(--text),var(--text .bucket:hover label{color:var(--text)} /* 居中联通电信移动列 */ -table.data thead th:last-child, table.data tbody td:last-child { text-align:center; } +#serversTable thead th:last-child, #serversTable tbody td:last-child { text-align:center; } /* 放大第13列宽度以容纳更宽水桶 */ -table.data thead th:nth-child(13),table.data tbody td:nth-child(13){ +#serversTable thead th:nth-child(13),#serversTable tbody td:nth-child(13){ width:150px;min-width:150px;max-width:150px;padding-left:0;padding-right:.55rem; /* 去除左 padding 进一步贴近 */ } /* 调整“总流量”表头(第9列)padding 使标题文字居中,不受正文额外右 padding 影响 */ -table.data thead th:nth-child(9){padding-left:.75rem;padding-right:.75rem;} +#serversTable thead th:nth-child(9){padding-left:.75rem;padding-right:.75rem;} .buckets{justify-content:center} /* 响应式隐藏非关键列,保持可读性 */ @media (max-width:1100px){ - table.data{min-width:100%;} - table.data thead th:nth-child(3), - table.data tbody td:nth-child(3), /* 节点 */ - table.data thead th:nth-child(4), - table.data tbody td:nth-child(4), /* 虚拟化 */ - table.data thead th:nth-child(8), - table.data tbody td:nth-child(8) /* 当前网络 */ {display:none} + #serversTable{min-width:100%;} + #serversTable thead th:nth-child(3), + #serversTable tbody td:nth-child(3), /* 节点 */ + #serversTable thead th:nth-child(4), + #serversTable tbody td:nth-child(4), /* 虚拟化 */ + #serversTable thead th:nth-child(8), + #serversTable tbody td:nth-child(8) /* 当前网络 */ {display:none} } @media (max-width:820px){ - table.data thead th:nth-child(5), - table.data tbody td:nth-child(5), /* 在线 */ - table.data thead th:nth-child(6), - table.data tbody td:nth-child(6) /* 负载 */ {display:none} - .spark{width:60px} + #serversTable thead th:nth-child(5), + #serversTable tbody td:nth-child(5), /* 在线 */ + #serversTable thead th:nth-child(6), + #serversTable tbody td:nth-child(6) /* 负载 */ {display:none} .buckets{gap:6px;min-width:100px} } @media (max-width:640px){ - table.data thead th:nth-child(4), - table.data tbody td:nth-child(4) /* 位置 */ {display:none} + #serversTable thead th:nth-child(4), + #serversTable tbody td:nth-child(4) /* 位置 */ {display:none} .topbar{flex-wrap:wrap;padding:.6rem .8rem} .actions{width:100%;justify-content:flex-end;margin-top:.4rem} .wrapper{padding:0 .7rem} - .spark{width:52px} #panel-servers .table-wrap{display:none;} #serversCards{display:grid!important;grid-template-columns:1fr;gap:.75rem;margin-top:.5rem;} /* 服务与证书移动端卡片 */ @@ -205,6 +200,28 @@ table.data thead th:nth-child(9){padding-left:.75rem;padding-right:.75rem;} .modal-box{max-width:100%;border-radius:14px;padding:1rem .95rem;} .modal-content{max-height:65vh;overflow:auto;} } + +/* SSL 表(证书)列宽与换行修正,避免复用服务器列宽导致名称与域名重叠 */ +#sslTable th,#sslTable td{white-space:nowrap;padding:.55rem .75rem;} +#sslTable th:nth-child(1),#sslTable td:nth-child(1){width:140px;min-width:120px;} +/* 域名允许换行以防过长挤压 */ +#sslTable th:nth-child(2),#sslTable td:nth-child(2){white-space:normal;max-width:320px;overflow-wrap:anywhere;} + +/* === 覆盖:要求三个表 (servers / monitors / ssl) 全部改为自动宽度 === */ +/* 1. 取消全局 table.data 的 min-width 对这三个表的影响 */ +#serversTable,#monitorsTable,#sslTable{min-width:0;} +/* 2. 统一去除之前为 serversTable 设定的列固定宽度,允许浏览器自动分配 */ +#serversTable thead th,#serversTable tbody td, +#monitorsTable thead th,#monitorsTable tbody td, +#sslTable thead th,#sslTable tbody td{ + width:auto!important;min-width:0!important;max-width:none!important; + padding:.55rem .7rem; +} +/* 3. 允许证书域名不受 max-width 限制(如仍需换行可保留 overflow-wrap) */ +#sslTable th:nth-child(2),#sslTable td:nth-child(2){max-width:none;white-space:normal;overflow-wrap:anywhere;} +/* 4. 取消“联通|电信|移动”列固定宽度 */ +#serversTable thead th:nth-child(13),#serversTable tbody td:nth-child(13){width:auto!important;min-width:0!important;} +/* 5. 如需稍微限制仪表盘相关列最小可读宽度,可设定一个较小下限 (可选) -- 暂不设置,完全交由自动布局 */ .cards .card{border:1px solid var(--border);border-radius:12px;padding:.75rem .85rem;background:linear-gradient(145deg,var(--bg),var(--bg-alt));display:flex;flex-direction:column;gap:.45rem;position:relative;} .cards .card.offline{opacity:.6;} .cards .card.high-load{border-color:rgba(239,68,68,.55);box-shadow:0 0 0 1px rgba(239,68,68,.4),0 4px 16px -4px rgba(239,68,68,.3);} @@ -236,7 +253,7 @@ table.data tbody tr.high-load:hover{background:rgba(239,68,68,.18);} .cards .expand-btn:focus, .cards .expand-btn:hover{color:var(--text);} .cards .expand-area{margin-top:.4rem;display:none;animation:fadeIn .25s ease;} .cards .card.expanded .expand-area{display:block;} -.cards canvas.lat-spark{width:100%;height:80px;border:1px solid var(--border);border-radius:10px;margin-top:.25rem;background:linear-gradient(145deg,var(--bg),var(--bg-alt));} +/* 旧移动端 latency spark 样式移除 */ /* 新 Logo 样式 */ .brand{display:flex;align-items:center;gap:.55rem;font-weight:600;letter-spacing:.5px;font-size:16px;position:relative} diff --git a/web/js/app.js b/web/js/app.js index 6ab575a..3c38c15 100644 --- a/web/js/app.js +++ b/web/js/app.js @@ -326,12 +326,7 @@ function openDetail(i){ `; } - function barHTML(label,valPct,text,role,io){ - const lvl = valPct>=90?'bad':(valPct>=80?'warn':''); - const ioCls = io? ' io':''; - return `
${label}${text}
`; - } - function ioBar(label,bytesVal,role){ const peak=150*1000*1000; const pct=Math.min(100,(bytesVal/peak)*100); const lvl = bytesVal>100*1000*1000?'bad': bytesVal>50*1000*1000?'warn':''; return barHTML(label,pct, (bytes(bytesVal)+'/s'), role, true).replace('
(x.name||x.location||'node')===key); } function updateDetailMetrics(key){ const s = findServerByKey(key); if(!s) return; if(!(s.online4||s.online6)) return; // 离线不更新 - const memPct = s.memory_total? (s.memory_used/s.memory_total*100):0; - const swapPct = s.swap_total? (s.swap_used/s.swap_total*100):0; - const hddPct = s.hdd_total? (s.hdd_used/s.hdd_total*100):0; - const ioRead = (typeof s.io_read==='number')? s.io_read:0; - const ioWrite = (typeof s.io_write==='number')? s.io_write:0; - const procLine = `${num(s.tcp_count)} / ${num(s.udp_count)} / ${num(s.process_count)} / ${num(s.thread_count)}`; - const procEl = document.getElementById('detail-proc'); if(procEl) procEl.textContent = procLine; - function upd(role,pct,text){ const wrap=document.querySelector(`#detailContent .bar-wrap[data-role="${role}"]`); if(!wrap) return; const valSpan=wrap.querySelector('.bar-label span:last-child'); if(valSpan) valSpan.textContent=text; const bar=wrap.querySelector('.bar span'); if(bar) bar.style.setProperty('--p',(pct/100).toFixed(3)); const box=wrap.querySelector('.bar'); if(box){ box.removeAttribute('data-warn'); box.removeAttribute('data-bad'); if(pct>=90) box.setAttribute('data-bad',''); else if(pct>=80) box.setAttribute('data-warn',''); } } - if(document.querySelector('.bar-wrap[data-role="swap"]')) upd('swap', swapPct, s.swap_total? swapPct.toFixed(1)+'%':'-'); - function updIO(role,val){ const wrap=document.querySelector(`#detailContent .bar-wrap[data-role="${role}"]`); if(!wrap) return; const peak=150*1000*1000; const pct=Math.min(100,(val/peak)*100); const bar=wrap.querySelector('.bar span'); if(bar) bar.style.setProperty('--p',(pct/100).toFixed(3)); const lbl=wrap.querySelector('.bar-label span:last-child'); if(lbl) lbl.textContent= bytes(val)+'/s'; const box=wrap.querySelector('.bar'); if(box){ box.removeAttribute('data-warn'); box.removeAttribute('data-bad'); if(val>100*1000*1000) box.setAttribute('data-bad',''); else if(val>50*1000*1000) box.setAttribute('data-warn',''); } } - updIO('io-read', ioRead); - updIO('io-write', ioWrite); + const procLine = `${num(s.tcp_count)} / ${num(s.udp_count)} / ${num(s.process_count)} / ${num(s.thread_count)}`; + const procEl = document.getElementById('detail-proc'); if(procEl) procEl.textContent = procLine; + const cuEl=document.getElementById('lat-cu'); if(cuEl) cuEl.textContent = num(s.time_10010)+'ms'; + const ctEl=document.getElementById('lat-ct'); if(ctEl) ctEl.textContent = num(s.time_189)+'ms'; + const cmEl=document.getElementById('lat-cm'); if(cmEl) cmEl.textContent = num(s.time_10086)+'ms'; // 延迟动态刷新 (若存在) - const cuEl=document.getElementById('lat-cu'); if(cuEl) cuEl.textContent = num(s.time_10010)+'ms'; - const ctEl=document.getElementById('lat-ct'); if(ctEl) ctEl.textContent = num(s.time_189)+'ms'; - const cmEl=document.getElementById('lat-cm'); if(cmEl) cmEl.textContent = num(s.time_10086)+'ms'; + const cuE1=document.getElementById('lat-cu'); if(cuE1) cuE1.textContent = num(s.time_10010)+'ms'; + const ctE1=document.getElementById('lat-ct'); if(ctE1) ctE1.textContent = num(s.time_189)+'ms'; + const cmE1=document.getElementById('lat-cm'); if(cmE1) cmE1.textContent = num(s.time_10086)+'ms'; } function startDetailAutoUpdate(){ stopDetailAutoUpdate(); S._detailTimer = setInterval(()=>{ if(S._openDetailKey) updateDetailMetrics(S._openDetailKey); }, 1000); } function stopDetailAutoUpdate(){ if(S._detailTimer){ clearInterval(S._detailTimer); S._detailTimer=null; } }