()
| 214 | } |
| 215 | |
| 216 | function renderOverview(){ |
| 217 | const total = S.servers.length; |
| 218 | const online = S.servers.filter(s => metrics(s).online).length; |
| 219 | const alerts = alertStats(); |
| 220 | const sslWarn = S.ssl.filter(c => c.mismatch || c.expire_days <= 7).length; |
| 221 | const monthDown = S.servers.reduce((sum, s) => sum + metrics(s).monthIn, 0); |
| 222 | const monthUp = S.servers.reduce((sum, s) => sum + metrics(s).monthOut, 0); |
| 223 | $('overviewCards').innerHTML = [ |
| 224 | card('在线主机', `${online}/${total}`, '当前在线节点', online === total ? 'ok' : 'warn'), |
| 225 | card('证书风险', sslWarn, sslWarn ? '过期或域名不匹配' : '证书正常', sslWarn ? 'warn' : 'ok'), |
| 226 | card('本月上行', humanMinMBFromB(monthUp), '上传累计', ''), |
| 227 | card('本月下行', humanMinMBFromB(monthDown), '下载累计', ''), |
| 228 | card('活跃告警', alerts.total, `离线 ${alerts.offline} / 异常 ${alerts.abnormal} / 被墙 ${alerts.blocked}`, alerts.total ? (alerts.offline || alerts.blocked ? 'err' : 'warn') : 'ok') |
| 229 | ].join(''); |
| 230 | } |
| 231 | function card(label, value, hint, cls){ return `<div class="overview-card ${cls}"><span class="label">${esc(label)}</span><span class="value">${esc(value)}</span><span class="hint">${esc(hint)}</span></div>`; } |
| 232 | |
| 233 | function alertStats(){ |
no test coverage detected