diff --git a/web/css/app.css b/web/css/app.css
index 92011e3..395fa08 100644
--- a/web/css/app.css
+++ b/web/css/app.css
@@ -101,6 +101,8 @@ table.data tbody tr:hover{background:rgba(255,255,255,.04)}
/* modal styles */
.modal-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.55);display:flex;align-items:flex-start;justify-content:center;padding:5vh 1rem;z-index:50;backdrop-filter:blur(4px)}
.modal-box{position:relative;width:100%;max-width:560px;background:var(--bg-alt);border:1px solid var(--border);border-radius:16px;box-shadow:0 8px 30px -6px rgba(0,0,0,.6);padding:1.25rem 1.35rem;display:flex;flex-direction:column;gap:.9rem;animation:fade .25s ease}
+.modal-box.high-load{border-color:rgba(239,68,68,.6);background:linear-gradient(180deg, rgba(239,68,68,.16), rgba(239,68,68,.08)), var(--bg-alt);box-shadow:0 0 0 1px rgba(239,68,68,.38),0 10px 28px -10px rgba(239,68,68,.28)}
+body:not(.light) .modal-box.high-load{background:linear-gradient(180deg, rgba(239,68,68,.24), rgba(239,68,68,.12)), var(--bg-alt)}
.modal-title{margin:0;font-size:16px;font-weight:600;letter-spacing:.5px}
.modal-close{position:absolute;top:10px;right:12px;background:transparent;border:0;color:var(--text-dim);font-size:20px;line-height:1;cursor:pointer;padding:4px;border-radius:8px;transition:var(--trans)}
.modal-close:hover{color:var(--text);background:var(--bg)}
@@ -229,10 +231,14 @@ body.light .gauge-half .needle{background:linear-gradient(var(--text),var(--text
}
.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,.6);background:linear-gradient(180deg, rgba(239,68,68,.22), rgba(239,68,68,.12));box-shadow:0 0 0 1px rgba(239,68,68,.48),0 6px 18px -6px rgba(239,68,68,.28);}
+.cards .card.high-load{border-color:rgba(239,68,68,.6);background:linear-gradient(180deg, rgba(239,68,68,.22), rgba(239,68,68,.12)), var(--bg-alt);box-shadow:0 0 0 1px rgba(239,68,68,.48),0 6px 18px -6px rgba(239,68,68,.28);}
table.data tbody tr.high-load{background:rgba(239,68,68,.18) !important;}
table.data tbody tr.high-load:hover{background:rgba(239,68,68,.26) !important;}
+/* SSL 域名告警底色:与高负载相同 */
+#sslTable td.alert-domain{background:rgba(239,68,68,.18) !important;}
+#sslTable tr:hover td.alert-domain{background:rgba(239,68,68,.26) !important;}
+
/* OS 着色(更明显):
1) 为各 OS 类定义 --os-color 变量
2) 行左侧使用 inset box-shadow 画 4px 彩条
@@ -277,10 +283,10 @@ table.data tbody tr[class*="os-"]:hover{background:linear-gradient(180deg, color
.cards .kvlist div{display:flex;flex-direction:column;}
.cards .kvlist span.key{opacity:.6;}
.cards .buckets{margin-top:.25rem;}
-.cards .expand-btn{position:absolute;top:.5rem;right:.5rem;background:transparent;border:0;color:var(--text-dim);cursor:pointer;font-size:.9rem;padding:.2rem;}
-.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 .kvlist .alert-domain{background:rgba(239,68,68,.18);border:1px solid rgba(239,68,68,.35);border-radius:8px;padding:.4rem .5rem;}
+.cards .kvlist .alert-domain .key{opacity:.85}
+/* 移除移动端卡片展开箭头与展开区域(已按需简化交互) */
/* 旧移动端 latency spark 样式移除 */
/* 简易信号格,用于服务连通性延迟展示 */
diff --git a/web/js/app.js b/web/js/app.js
index 2ff5393..779eeab 100644
--- a/web/js/app.js
+++ b/web/js/app.js
@@ -219,15 +219,14 @@ function renderServersCards(){
const buckets = `
${bucket(p1)}${bucket(p2)}${bucket(p3)}
`;
// 唯一 key 已附加为 s._key(如需使用)
const highLoad = online && ( (s.cpu||0)>=90 || (memPct)>=90 || (hddPct)>=90 );
- html += `\n
\n \n
\n
负载${s.load_1==-1?'–':s.load_1?.toFixed(2)}
\n
在线${s.uptime||'-'}
\n
月流量${monthIn}${monthOut}
\n
网络${netNow}
\n
总流量${netTotal}
\n
CPU${s.cpu||0}%
\n
内存${memPct.toFixed(0)}%
\n
硬盘${hddPct.toFixed(0)}%
\n
\n ${buckets}\n
\n
${online?'点击卡片可查看详情':'离线,不可查看详情'}
\n
\n
`;
+ html += `\n \n
\n
负载${s.load_1==-1?'–':s.load_1?.toFixed(2)}
\n
在线${s.uptime||'-'}
\n
月流量${monthIn}${monthOut}
\n
网络${netNow}
\n
总流量${netTotal}
\n
CPU${s.cpu||0}%
\n
内存${memPct.toFixed(0)}%
\n
硬盘${hddPct.toFixed(0)}%
\n
\n ${buckets}\n
`;
});
wrap.innerHTML = html || '无数据
';
wrap.querySelectorAll('.card').forEach(card=>{
const idx = parseInt(card.getAttribute('data-idx'));
- card.addEventListener('click', e=>{
- if(e.target.classList.contains('expand-btn')){ card.classList.toggle('expanded'); e.stopPropagation(); return;}
+ card.addEventListener('click', ()=>{
if(card.getAttribute('data-online')!=='1') return; // 离线不弹
- openDetail(idx);
+ openDetail(idx);
});
});
}
@@ -315,9 +314,11 @@ function renderSSL(){
const cls = c.expire_days<=0? 'err': c.expire_days<=7? 'warn':'ok';
const status = c.expire_days<=0? '已过期': c.expire_days<=7? '将到期':'正常';
const dt = c.expire_ts? new Date(c.expire_ts*1000).toISOString().replace('T',' ').replace(/\.\d+Z/,''):'-';
+ // 当证书进入警告/错误状态时,高亮域名列底色(与高负载相同的底色)
+ const domainCellCls = (cls !== 'ok') ? 'alert-domain' : '';
html += `
| ${c.name||'-'} |
- ${(c.domain||'').replace(/^https?:\/\//,'')} |
+ ${(c.domain||'').replace(/^https?:\/\//,'')} |
${c.port||443} |
${c.expire_days??'-'} |
${dt} |
@@ -336,10 +337,11 @@ function renderSSLCards(){
const cls = c.expire_days<=0? 'err': c.expire_days<=7? 'warn':'ok';
const status = c.expire_days<=0? '已过期': c.expire_days<=7? '将到期':'正常';
const dt = c.expire_ts? new Date(c.expire_ts*1000).toISOString().replace('T',' ').replace(/\.\d+Z/,''):'-';
+ const domainRowCls = (cls !== 'ok') ? 'alert-domain' : '';
html += `
-
域名${(c.domain||'').replace(/^https?:\/\//,'')}
+
域名${(c.domain||'').replace(/^https?:\/\//,'')}
端口${c.port||443}
剩余(天)${c.expire_days??'-'}
到期${dt.split(' ')[0]||dt}
@@ -396,6 +398,7 @@ function openDetail(i){
const s = S.servers[i]; if(!s) return;
const box = document.getElementById('detailContent');
const modal = document.getElementById('detailModal');
+ const modalBox = modal.querySelector('.modal-box');
const osText = osLabel(s.os);
const titleEl = document.getElementById('detailTitle');
titleEl.textContent = s.name + ' 详情';
@@ -476,6 +479,9 @@ function openDetail(i){
${latencyBlock}
`;
modal.style.display='flex';
+ // 根据高负载阈值(>=90% 任一项)给弹窗加高亮底色
+ const highLoad = (s.cpu||0) >= 90 || memPct >= 90 || hddPct >= 90;
+ if(modalBox){ modalBox.classList.toggle('high-load', highLoad); }
document.addEventListener('keydown', escCloseOnce);
if(!offline){
drawLatencyChart(key);
@@ -488,7 +494,14 @@ function openDetail(i){
}
}
function escCloseOnce(e){ if(e.key==='Escape'){ closeDetail(); } }
-function closeDetail(){ const m=document.getElementById('detailModal'); m.style.display='none'; document.removeEventListener('keydown', escCloseOnce); stopDetailAutoUpdate(); }
+function closeDetail(){
+ const m=document.getElementById('detailModal');
+ m.style.display='none';
+ const b = m.querySelector('.modal-box');
+ if(b) b.classList.remove('high-load');
+ document.removeEventListener('keydown', escCloseOnce);
+ stopDetailAutoUpdate();
+}
document.getElementById('detailClose').addEventListener('click', closeDetail);
document.getElementById('detailModal').addEventListener('click', e=>{ if(e.target.id==='detailModal') closeDetail(); });