diff --git a/README.md b/README.md index 7096e01..851d725 100644 --- a/README.md +++ b/README.md @@ -540,6 +540,16 @@ UptimeRobot 的探测来自其多个节点,适合作为**异地视角**与自 - [x] 页脚改为展示「数据更新于 … + 下次检查 Ns」,tooltip 内含服务端更新节奏与快照生成时间 - [x] `scripts/verify.cjs` 适配纯外部数据源部署(自动跳过不适用的探测类断言),并新增「倒计时对齐服务端」断言 +### v0.11.2 已实现 + +**修复你反馈的两个问题** + +- [x] **「狼的评论系统」那一条高度/样式与其他行不一致**:实测在线行 **58px**、离线行 **43px**。根因是**可用率列的 90 格 mini 条**——它是 `inline-flex` 元素,参与行内布局时其基线会把行盒抬高约 15px,于是「当天有可用率数据、条正常渲染」的行比不带条的行高出一截。修复:给单元格内容统一 `vertical-align: middle`、mini 条容器改 flex 布局,现在**所有行等高(实测 43px)** +- [x] **「最近事件」改为与表格同一套样式**:不再用独立的「时间线卡片」风格,改为**与监控表格完全同构的表格**(相同的圆角容器、表头样式、行分隔线、hover、状态底色)——故障行淡红、证书行淡琥珀、恢复行不染;类型以小徽标呈现,详情列完整显示 + - 实现上刻意**不共用 `.monitor-table` 类名**,避免被其他按类名统计/定位的逻辑误算(这一点被测试当场抓到:共用类名时面板条目数被多算 1~8 个) + +> 说明:行高在「内容长度相当」时保证一致;名称或地址特别长时允许换行(这是上一版你要求的「数据完整显示」),此时行自然更高——属于数据本身需要的空间,不再靠截断换取整齐。 + ### v0.11.1 已实现 **修复你反馈的三个问题** diff --git a/docs/screenshot-desktop.png b/docs/screenshot-desktop.png index db1d140..597faba 100644 Binary files a/docs/screenshot-desktop.png and b/docs/screenshot-desktop.png differ diff --git a/docs/screenshot-mobile.png b/docs/screenshot-mobile.png index 49e74b4..045d771 100644 Binary files a/docs/screenshot-mobile.png and b/docs/screenshot-mobile.png differ diff --git a/docs/screenshot-shiroko.png b/docs/screenshot-shiroko.png index b5407ef..1a07b04 100644 Binary files a/docs/screenshot-shiroko.png and b/docs/screenshot-shiroko.png differ diff --git a/docs/screenshot-view-cards.png b/docs/screenshot-view-cards.png index 1cfd878..2bd38d5 100644 Binary files a/docs/screenshot-view-cards.png and b/docs/screenshot-view-cards.png differ diff --git a/docs/screenshot-view-table.png b/docs/screenshot-view-table.png index e87f202..e7de7bb 100644 Binary files a/docs/screenshot-view-table.png and b/docs/screenshot-view-table.png differ diff --git a/edge/cloudflare/worker.js b/edge/cloudflare/worker.js index 1a00b69..cd9b9e4 100644 --- a/edge/cloudflare/worker.js +++ b/edge/cloudflare/worker.js @@ -11,7 +11,7 @@ import { connect } from 'cloudflare:sockets'; -const VERSION = '0.11.1'; +const VERSION = '0.11.2'; const HISTORY_LIMIT = 48; const UPTIME_DAYS = 90; const USER_AGENT = 'shiroko-monitor/0.3 (lightweight uptime panel)'; diff --git a/prober/node/index.js b/prober/node/index.js index 13090c0..767d8c1 100644 --- a/prober/node/index.js +++ b/prober/node/index.js @@ -37,7 +37,7 @@ const CONCURRENCY = 8; const WRITE_DEBOUNCE_MS = 300; const DEFAULT_INTERVAL_SEC = 60; const PORT = Number(process.env.PORT || 8787); -const VERSION = '0.11.1'; +const VERSION = '0.11.2'; const UR_DEFAULT_POLL_SEC = 300; const UR_MIN_REFRESH_GAP_MS = 60000; diff --git a/public/assets/app.js b/public/assets/app.js index afbd743..3bd5cf2 100644 --- a/public/assets/app.js +++ b/public/assets/app.js @@ -1,4 +1,4 @@ -const VERSION = '0.11.1'; +const VERSION = '0.11.2'; const HB_LIMIT = 48; const UPTIME_DAYS = 90; const BROWSER_CONCURRENCY = 6; @@ -263,14 +263,16 @@ function renderEvents() { if (count) count.textContent = all.length > shown.length ? `最近 ${shown.length} / ${all.length} 条` : `最近 ${all.length} 条`; const label = { down: '故障', up: '恢复', tls: '证书', maintenance: '维护' }; + // 与监控表格同一套结构(tr/td + data-status),因此行高、边框、hover、状态底色天然一致 + const statusOf = { down: 'down', up: 'up', tls: 'pending', maintenance: 'up' }; list.innerHTML = shown.map((e) => { const maint = e.maintenance ? '维护' : ''; - return `
| 时间 | 类型 | 目标 | 详情 |
|---|
暂无事件记录(故障、恢复与证书提醒会出现在这里)
@@ -68,7 +75,7 @@ - + diff --git a/public/status.json b/public/status.json index 73aad6e..c8529fd 100644 --- a/public/status.json +++ b/public/status.json @@ -1,8 +1,8 @@ { "prober": "shiroko-monitor-node/0.11.1", "demo": false, - "generatedAt": "2026-10-14T02:22:02.705Z", - "dataUpdatedAt": "2026-10-14T02:20:34.658Z", + "generatedAt": "2026-10-14T02:48:57.258Z", + "dataUpdatedAt": "2026-10-14T02:45:46.268Z", "updateIntervalSec": 300, "dataFilter": "uptimerobot", "probeScope": "uptimerobot", @@ -11,12 +11,12 @@ "up": 5, "down": 1, "pending": 0, - "avgLatency": 654, + "avgLatency": 735, "avgUptime90": 83.3, "memory": { - "rssMB": 57.2, - "heapUsedMB": 9, - "heapTotalMB": 10.5 + "rssMB": 64.5, + "heapUsedMB": 11.2, + "heapTotalMB": 14.2 } }, "sources": { @@ -24,10 +24,10 @@ "enabled": true, "ok": true, "error": null, - "lastSyncAt": "2026-10-14T02:20:34.658Z", + "lastSyncAt": "2026-10-14T02:45:46.268Z", "count": 6, "syncing": false, - "lastSyncMs": 1791944433802 + "lastSyncMs": 1791945944983 } }, "notify": { @@ -55,189 +55,194 @@ "monitors": { "ur-792059439": { "status": "up", - "latency": 295, + "latency": 190, "code": null, "detail": "UptimeRobot:运行正常", - "lastCheck": "2026-10-14T02:15:00.000Z", + "lastCheck": "2026-10-14T02:41:00.000Z", "history": [ { - "t": "2026-10-13T03:30:00.000Z", + "t": "2026-10-13T03:50:00.000Z", "ok": true, - "ms": 196 + "ms": 104 }, { - "t": "2026-10-13T04:10:00.000Z", + "t": "2026-10-13T04:35:00.000Z", "ok": true, - "ms": 348 + "ms": 478 }, { - "t": "2026-10-13T04:50:00.000Z", + "t": "2026-10-13T05:15:00.000Z", "ok": true, - "ms": 305 + "ms": 353 }, { - "t": "2026-10-13T05:30:00.000Z", + "t": "2026-10-13T05:55:00.000Z", "ok": true, - "ms": 287 + "ms": 294 }, { - "t": "2026-10-13T06:10:00.000Z", + "t": "2026-10-13T06:35:00.000Z", "ok": true, - "ms": 290 + "ms": 238 }, { - "t": "2026-10-13T06:50:00.000Z", + "t": "2026-10-13T07:15:00.000Z", "ok": true, - "ms": 261 + "ms": 259 }, { - "t": "2026-10-13T07:30:00.000Z", + "t": "2026-10-13T07:55:00.000Z", "ok": true, - "ms": 323 + "ms": 227 }, { - "t": "2026-10-13T08:10:00.000Z", + "t": "2026-10-13T08:35:00.000Z", "ok": true, - "ms": 280 + "ms": 434 }, { - "t": "2026-10-13T08:50:00.000Z", + "t": "2026-10-13T09:15:00.000Z", "ok": true, - "ms": 372 + "ms": 333 }, { - "t": "2026-10-13T09:30:00.000Z", + "t": "2026-10-13T09:55:00.000Z", "ok": true, - "ms": 263 + "ms": 427 }, { - "t": "2026-10-13T10:15:00.000Z", + "t": "2026-10-13T10:35:00.000Z", + "ok": true, + "ms": 233 + }, + { + "t": "2026-10-13T11:15:00.000Z", + "ok": true, + "ms": 388 + }, + { + "t": "2026-10-13T11:55:00.000Z", + "ok": true, + "ms": 329 + }, + { + "t": "2026-10-13T12:35:00.000Z", + "ok": true, + "ms": 422 + }, + { + "t": "2026-10-13T13:15:00.000Z", + "ok": true, + "ms": 271 + }, + { + "t": "2026-10-13T13:55:00.000Z", "ok": true, "ms": 307 }, { - "t": "2026-10-13T10:55:00.000Z", + "t": "2026-10-13T14:35:00.000Z", "ok": true, - "ms": 379 + "ms": 417 }, { - "t": "2026-10-13T11:35:00.000Z", + "t": "2026-10-13T15:15:00.000Z", "ok": true, - "ms": 244 + "ms": 283 }, { - "t": "2026-10-13T12:15:00.000Z", + "t": "2026-10-13T15:55:00.000Z", "ok": true, - "ms": 337 + "ms": 308 }, { - "t": "2026-10-13T12:55:00.000Z", + "t": "2026-10-13T16:35:00.000Z", "ok": true, - "ms": 392 + "ms": 279 }, { - "t": "2026-10-13T13:35:00.000Z", + "t": "2026-10-13T17:15:00.000Z", "ok": true, - "ms": 249 + "ms": 239 }, { - "t": "2026-10-13T14:15:00.000Z", + "t": "2026-10-13T17:55:00.000Z", "ok": true, - "ms": 549 + "ms": 299 }, { - "t": "2026-10-13T14:55:00.000Z", + "t": "2026-10-13T18:35:00.000Z", "ok": true, - "ms": 231 + "ms": 240 }, { - "t": "2026-10-13T15:40:00.000Z", + "t": "2026-10-13T19:15:00.000Z", "ok": true, - "ms": 251 + "ms": 526 }, { - "t": "2026-10-13T16:20:00.000Z", + "t": "2026-10-13T19:55:00.000Z", "ok": true, - "ms": 482 + "ms": 367 }, { - "t": "2026-10-13T17:00:00.000Z", + "t": "2026-10-13T20:35:00.000Z", "ok": true, - "ms": 266 + "ms": 369 }, { - "t": "2026-10-13T17:40:00.000Z", + "t": "2026-10-13T21:15:00.000Z", "ok": true, - "ms": 249 + "ms": 281 }, { - "t": "2026-10-13T18:20:00.000Z", + "t": "2026-10-13T21:55:00.000Z", + "ok": true, + "ms": 321 + }, + { + "t": "2026-10-13T22:35:00.000Z", + "ok": true, + "ms": 150 + }, + { + "t": "2026-10-13T23:15:00.000Z", + "ok": true, + "ms": 298 + }, + { + "t": "2026-10-13T23:55:00.000Z", "ok": true, "ms": 305 }, { - "t": "2026-10-13T19:00:00.000Z", + "t": "2026-10-14T00:35:00.000Z", "ok": true, - "ms": 479 + "ms": 208 }, { - "t": "2026-10-13T19:40:00.000Z", + "t": "2026-10-14T01:15:00.000Z", "ok": true, - "ms": 378 + "ms": 421 }, { - "t": "2026-10-13T20:20:00.000Z", + "t": "2026-10-14T02:05:00.000Z", "ok": true, - "ms": 372 + "ms": 272 }, { - "t": "2026-10-13T21:00:00.000Z", + "t": "2026-10-14T02:41:00.000Z", "ok": true, - "ms": 276 - }, - { - "t": "2026-10-13T21:40:00.000Z", - "ok": true, - "ms": 304 - }, - { - "t": "2026-10-13T22:20:00.000Z", - "ok": true, - "ms": 202 - }, - { - "t": "2026-10-13T23:00:00.000Z", - "ok": true, - "ms": 228 - }, - { - "t": "2026-10-13T23:40:00.000Z", - "ok": true, - "ms": 316 - }, - { - "t": "2026-10-14T00:20:00.000Z", - "ok": true, - "ms": 356 - }, - { - "t": "2026-10-14T01:35:00.000Z", - "ok": true, - "ms": 343 - }, - { - "t": "2026-10-14T02:15:00.000Z", - "ok": true, - "ms": 295 + "ms": 190 } ], "daily": { "2026-10-14": { - "total": 1, - "up": 1, - "latSum": 295, - "latCount": 1, - "latMax": 295 + "total": 7, + "up": 7, + "latSum": 1758, + "latCount": 7, + "latMax": 326 } }, "meta": { @@ -262,22 +267,22 @@ "90": 0 }, "lat": { - "avg": 295, - "max": 295, + "avg": 251, + "max": 326, "days": [ { "key": "2026-10-14", - "avg": 295 + "avg": 251 } ] } }, "ur-795497022": { "status": "up", - "latency": 816, + "latency": 811, "code": null, "detail": "UptimeRobot:运行正常", - "lastCheck": "2026-10-14T02:19:00.000Z", + "lastCheck": "2026-10-14T02:45:00.000Z", "history": [ { "t": "2026-10-13T03:35:00.000Z", @@ -440,28 +445,28 @@ "ms": 676 }, { - "t": "2026-10-14T01:14:00.000Z", + "t": "2026-10-14T01:31:00.000Z", "ok": true, - "ms": 783 + "ms": 802 }, { - "t": "2026-10-14T01:46:00.000Z", + "t": "2026-10-14T02:08:00.000Z", "ok": true, - "ms": 646 + "ms": 634 }, { - "t": "2026-10-14T02:19:00.000Z", + "t": "2026-10-14T02:45:00.000Z", "ok": true, - "ms": 816 + "ms": 811 } ], "daily": { "2026-10-14": { - "total": 1, - "up": 1, - "latSum": 816, - "latCount": 1, - "latMax": 816 + "total": 7, + "up": 7, + "latSum": 5767, + "latCount": 7, + "latMax": 845 } }, "meta": { @@ -486,206 +491,206 @@ "90": 5432 }, "lat": { - "avg": 816, - "max": 816, + "avg": 824, + "max": 845, "days": [ { "key": "2026-10-14", - "avg": 816 + "avg": 824 } ] } }, "ur-795556828": { "status": "up", - "latency": 120, + "latency": 448, "code": null, "detail": "UptimeRobot:运行正常", - "lastCheck": "2026-10-14T02:16:00.000Z", + "lastCheck": "2026-10-14T02:41:00.000Z", "history": [ { - "t": "2026-10-13T03:00:00.000Z", + "t": "2026-10-13T03:45:00.000Z", "ok": true, - "ms": 409 + "ms": 229 }, { - "t": "2026-10-13T03:40:00.000Z", + "t": "2026-10-13T04:30:00.000Z", "ok": true, - "ms": 231 + "ms": 234 }, { - "t": "2026-10-13T04:20:00.000Z", + "t": "2026-10-13T05:10:00.000Z", "ok": true, - "ms": 250 + "ms": 181 }, { - "t": "2026-10-13T05:00:00.000Z", + "t": "2026-10-13T05:50:00.000Z", "ok": true, - "ms": 134 + "ms": 206 }, { - "t": "2026-10-13T05:40:00.000Z", + "t": "2026-10-13T06:30:00.000Z", "ok": true, - "ms": 193 + "ms": 241 }, { - "t": "2026-10-13T06:20:00.000Z", + "t": "2026-10-13T07:10:00.000Z", "ok": true, - "ms": 260 + "ms": 241 }, { - "t": "2026-10-13T07:00:00.000Z", + "t": "2026-10-13T07:50:00.000Z", "ok": true, - "ms": 254 + "ms": 512 }, { - "t": "2026-10-13T07:40:00.000Z", + "t": "2026-10-13T08:30:00.000Z", "ok": true, - "ms": 559 + "ms": 216 }, { - "t": "2026-10-13T08:20:00.000Z", + "t": "2026-10-13T09:10:00.000Z", "ok": true, - "ms": 205 + "ms": 256 }, { - "t": "2026-10-13T09:00:00.000Z", + "t": "2026-10-13T09:55:00.000Z", "ok": true, - "ms": 264 + "ms": 455 }, { - "t": "2026-10-13T09:40:00.000Z", + "t": "2026-10-13T10:35:00.000Z", "ok": true, - "ms": 305 + "ms": 372 }, { - "t": "2026-10-13T10:20:00.000Z", + "t": "2026-10-13T11:15:00.000Z", "ok": true, - "ms": 420 + "ms": 240 }, { - "t": "2026-10-13T11:00:00.000Z", + "t": "2026-10-13T11:55:00.000Z", "ok": true, - "ms": 227 + "ms": 261 }, { - "t": "2026-10-13T11:40:00.000Z", + "t": "2026-10-13T12:35:00.000Z", "ok": true, - "ms": 389 + "ms": 335 }, { - "t": "2026-10-13T12:20:00.000Z", - "ok": true, - "ms": 302 - }, - { - "t": "2026-10-13T13:00:00.000Z", - "ok": true, - "ms": 375 - }, - { - "t": "2026-10-13T13:40:00.000Z", - "ok": true, - "ms": 287 - }, - { - "t": "2026-10-13T14:20:00.000Z", - "ok": true, - "ms": 352 - }, - { - "t": "2026-10-13T15:00:00.000Z", - "ok": true, - "ms": 404 - }, - { - "t": "2026-10-13T15:40:00.000Z", - "ok": true, - "ms": 323 - }, - { - "t": "2026-10-13T16:20:00.000Z", - "ok": true, - "ms": 311 - }, - { - "t": "2026-10-13T17:00:00.000Z", - "ok": true, - "ms": 376 - }, - { - "t": "2026-10-13T17:40:00.000Z", + "t": "2026-10-13T13:15:00.000Z", "ok": true, "ms": 413 }, { - "t": "2026-10-13T18:20:00.000Z", + "t": "2026-10-13T13:55:00.000Z", "ok": true, - "ms": 386 + "ms": 283 }, { - "t": "2026-10-13T19:00:00.000Z", + "t": "2026-10-13T14:35:00.000Z", "ok": true, - "ms": 302 + "ms": 309 }, { - "t": "2026-10-13T19:40:00.000Z", + "t": "2026-10-13T15:20:00.000Z", "ok": true, - "ms": 376 + "ms": 451 }, { - "t": "2026-10-13T20:20:00.000Z", + "t": "2026-10-13T16:00:00.000Z", "ok": true, - "ms": 266 + "ms": 248 }, { - "t": "2026-10-13T21:00:00.000Z", + "t": "2026-10-13T16:40:00.000Z", "ok": true, - "ms": 475 + "ms": 378 }, { - "t": "2026-10-13T21:40:00.000Z", + "t": "2026-10-13T17:20:00.000Z", "ok": true, - "ms": 354 + "ms": 293 }, { - "t": "2026-10-13T22:20:00.000Z", + "t": "2026-10-13T18:00:00.000Z", "ok": true, - "ms": 239 + "ms": 495 }, { - "t": "2026-10-13T23:00:00.000Z", + "t": "2026-10-13T18:40:00.000Z", + "ok": true, + "ms": 391 + }, + { + "t": "2026-10-13T19:20:00.000Z", + "ok": true, + "ms": 338 + }, + { + "t": "2026-10-13T20:00:00.000Z", + "ok": true, + "ms": 363 + }, + { + "t": "2026-10-13T20:40:00.000Z", + "ok": true, + "ms": 499 + }, + { + "t": "2026-10-13T21:20:00.000Z", + "ok": true, + "ms": 372 + }, + { + "t": "2026-10-13T22:00:00.000Z", + "ok": true, + "ms": 194 + }, + { + "t": "2026-10-13T22:40:00.000Z", "ok": true, "ms": 225 }, { - "t": "2026-10-13T23:40:00.000Z", + "t": "2026-10-13T23:20:00.000Z", "ok": true, - "ms": 243 + "ms": 237 }, { - "t": "2026-10-14T00:20:00.000Z", + "t": "2026-10-14T00:00:00.000Z", "ok": true, - "ms": 319 + "ms": 215 }, { - "t": "2026-10-14T01:40:00.000Z", + "t": "2026-10-14T00:40:00.000Z", "ok": true, - "ms": 382 + "ms": 298 }, { - "t": "2026-10-14T02:16:00.000Z", + "t": "2026-10-14T01:20:00.000Z", "ok": true, - "ms": 120 + "ms": 450 + }, + { + "t": "2026-10-14T02:05:00.000Z", + "ok": true, + "ms": 229 + }, + { + "t": "2026-10-14T02:41:00.000Z", + "ok": true, + "ms": 448 } ], "daily": { "2026-10-14": { - "total": 1, - "up": 1, - "latSum": 120, - "latCount": 1, - "latMax": 120 + "total": 7, + "up": 7, + "latSum": 2113, + "latCount": 7, + "latMax": 448 } }, "meta": { @@ -710,28 +715,23 @@ "90": 0 }, "lat": { - "avg": 120, - "max": 120, + "avg": 302, + "max": 448, "days": [ { "key": "2026-10-14", - "avg": 120 + "avg": 302 } ] } }, "ur-792059414": { "status": "up", - "latency": 1760, + "latency": 1795, "code": null, "detail": "UptimeRobot:运行正常", - "lastCheck": "2026-10-14T02:18:00.000Z", + "lastCheck": "2026-10-14T02:40:00.000Z", "history": [ - { - "t": "2026-10-13T03:10:00.000Z", - "ok": true, - "ms": 1144 - }, { "t": "2026-10-13T03:55:00.000Z", "ok": true, @@ -848,53 +848,58 @@ "ms": 2649 }, { - "t": "2026-10-13T21:00:00.000Z", + "t": "2026-10-13T21:05:00.000Z", "ok": true, - "ms": 3079 + "ms": 2923 }, { - "t": "2026-10-13T21:40:00.000Z", + "t": "2026-10-13T21:50:00.000Z", "ok": true, - "ms": 2829 + "ms": 1964 }, { - "t": "2026-10-13T22:20:00.000Z", + "t": "2026-10-13T22:35:00.000Z", "ok": true, - "ms": 1984 + "ms": 2335 }, { - "t": "2026-10-13T23:00:00.000Z", + "t": "2026-10-13T23:20:00.000Z", "ok": true, - "ms": 1853 + "ms": 2418 }, { - "t": "2026-10-13T23:40:00.000Z", + "t": "2026-10-14T00:00:00.000Z", "ok": true, - "ms": 2628 + "ms": 1947 }, { - "t": "2026-10-14T00:20:00.000Z", + "t": "2026-10-14T00:40:00.000Z", "ok": true, - "ms": 2416 + "ms": 2257 }, { - "t": "2026-10-14T01:38:00.000Z", + "t": "2026-10-14T01:20:00.000Z", "ok": true, - "ms": 3054 + "ms": 2605 }, { - "t": "2026-10-14T02:18:00.000Z", + "t": "2026-10-14T02:01:00.000Z", "ok": true, - "ms": 1760 + "ms": 2591 + }, + { + "t": "2026-10-14T02:40:00.000Z", + "ok": true, + "ms": 1795 } ], "daily": { "2026-10-14": { - "total": 1, - "up": 1, - "latSum": 1760, - "latCount": 1, - "latMax": 1760 + "total": 7, + "up": 7, + "latSum": 12076, + "latCount": 7, + "latMax": 1795 } }, "meta": { @@ -919,201 +924,206 @@ "90": 7593 }, "lat": { - "avg": 1760, - "max": 1760, + "avg": 1725, + "max": 1795, "days": [ { "key": "2026-10-14", - "avg": 1760 + "avg": 1725 } ] } }, "ur-798788113": { "status": "up", - "latency": 281, + "latency": 433, "code": null, "detail": "UptimeRobot:运行正常", - "lastCheck": "2026-10-14T02:16:00.000Z", + "lastCheck": "2026-10-14T02:42:00.000Z", "history": [ { - "t": "2026-10-13T03:25:00.000Z", - "ok": true, - "ms": 446 - }, - { - "t": "2026-10-13T04:10:00.000Z", + "t": "2026-10-13T04:00:00.000Z", "ok": true, "ms": 400 }, { - "t": "2026-10-13T04:50:00.000Z", + "t": "2026-10-13T04:40:00.000Z", "ok": true, - "ms": 422 + "ms": 357 }, { - "t": "2026-10-13T05:30:00.000Z", + "t": "2026-10-13T05:20:00.000Z", + "ok": true, + "ms": 372 + }, + { + "t": "2026-10-13T06:00:00.000Z", + "ok": true, + "ms": 426 + }, + { + "t": "2026-10-13T06:40:00.000Z", + "ok": true, + "ms": 314 + }, + { + "t": "2026-10-13T07:20:00.000Z", "ok": true, "ms": 449 }, { - "t": "2026-10-13T06:10:00.000Z", + "t": "2026-10-13T08:00:00.000Z", "ok": true, - "ms": 386 + "ms": 279 }, { - "t": "2026-10-13T06:50:00.000Z", + "t": "2026-10-13T08:40:00.000Z", "ok": true, - "ms": 311 + "ms": 407 }, { - "t": "2026-10-13T07:30:00.000Z", + "t": "2026-10-13T09:20:00.000Z", "ok": true, - "ms": 384 + "ms": 317 }, { - "t": "2026-10-13T08:10:00.000Z", + "t": "2026-10-13T10:00:00.000Z", "ok": true, - "ms": 390 + "ms": 627 }, { - "t": "2026-10-13T08:50:00.000Z", + "t": "2026-10-13T10:40:00.000Z", "ok": true, - "ms": 461 + "ms": 505 }, { - "t": "2026-10-13T09:30:00.000Z", + "t": "2026-10-13T11:20:00.000Z", "ok": true, - "ms": 545 + "ms": 424 }, { - "t": "2026-10-13T10:10:00.000Z", + "t": "2026-10-13T12:00:00.000Z", "ok": true, - "ms": 456 + "ms": 1135 }, { - "t": "2026-10-13T10:50:00.000Z", + "t": "2026-10-13T12:40:00.000Z", "ok": true, - "ms": 394 + "ms": 462 }, { - "t": "2026-10-13T11:30:00.000Z", + "t": "2026-10-13T13:20:00.000Z", "ok": true, - "ms": 398 + "ms": 436 }, { - "t": "2026-10-13T12:10:00.000Z", + "t": "2026-10-13T14:00:00.000Z", "ok": true, - "ms": 588 + "ms": 521 }, { - "t": "2026-10-13T12:50:00.000Z", + "t": "2026-10-13T14:40:00.000Z", "ok": true, - "ms": 430 + "ms": 480 }, { - "t": "2026-10-13T13:30:00.000Z", + "t": "2026-10-13T15:20:00.000Z", "ok": true, - "ms": 502 + "ms": 462 }, { - "t": "2026-10-13T14:15:00.000Z", + "t": "2026-10-13T16:00:00.000Z", "ok": true, - "ms": 355 + "ms": 331 }, { - "t": "2026-10-13T14:55:00.000Z", + "t": "2026-10-13T16:40:00.000Z", "ok": true, - "ms": 358 + "ms": 373 }, { - "t": "2026-10-13T15:35:00.000Z", + "t": "2026-10-13T17:20:00.000Z", "ok": true, - "ms": 385 + "ms": 429 }, { - "t": "2026-10-13T16:15:00.000Z", + "t": "2026-10-13T18:00:00.000Z", "ok": true, - "ms": 342 + "ms": 558 }, { - "t": "2026-10-13T16:55:00.000Z", + "t": "2026-10-13T18:40:00.000Z", "ok": true, - "ms": 428 + "ms": 370 }, { - "t": "2026-10-13T17:35:00.000Z", + "t": "2026-10-13T19:20:00.000Z", "ok": true, - "ms": 508 + "ms": 1519 }, { - "t": "2026-10-13T18:15:00.000Z", + "t": "2026-10-13T20:00:00.000Z", "ok": true, - "ms": 602 + "ms": 483 }, { - "t": "2026-10-13T18:55:00.000Z", + "t": "2026-10-13T20:40:00.000Z", "ok": true, - "ms": 363 + "ms": 388 }, { - "t": "2026-10-13T19:40:00.000Z", + "t": "2026-10-13T21:20:00.000Z", "ok": true, - "ms": 1380 + "ms": 367 }, { - "t": "2026-10-13T20:20:00.000Z", + "t": "2026-10-13T22:00:00.000Z", "ok": true, - "ms": 512 + "ms": 273 }, { - "t": "2026-10-13T21:00:00.000Z", + "t": "2026-10-13T22:40:00.000Z", "ok": true, - "ms": 394 + "ms": 261 }, { - "t": "2026-10-13T21:40:00.000Z", - "ok": true, - "ms": 238 - }, - { - "t": "2026-10-13T22:20:00.000Z", - "ok": true, - "ms": 323 - }, - { - "t": "2026-10-13T23:00:00.000Z", - "ok": true, - "ms": 353 - }, - { - "t": "2026-10-13T23:40:00.000Z", - "ok": true, - "ms": 179 - }, - { - "t": "2026-10-14T00:20:00.000Z", + "t": "2026-10-13T23:20:00.000Z", "ok": true, "ms": 263 }, { - "t": "2026-10-14T01:36:00.000Z", + "t": "2026-10-14T00:00:00.000Z", "ok": true, - "ms": 383 + "ms": 229 }, { - "t": "2026-10-14T02:16:00.000Z", + "t": "2026-10-14T00:40:00.000Z", "ok": true, - "ms": 281 + "ms": 363 + }, + { + "t": "2026-10-14T01:20:00.000Z", + "ok": true, + "ms": 329 + }, + { + "t": "2026-10-14T02:06:00.000Z", + "ok": true, + "ms": 234 + }, + { + "t": "2026-10-14T02:42:00.000Z", + "ok": true, + "ms": 433 } ], "daily": { "2026-10-14": { - "total": 1, - "up": 1, - "latSum": 281, - "latCount": 1, - "latMax": 281 + "total": 7, + "up": 7, + "latSum": 2680, + "latCount": 7, + "latMax": 435 } }, "meta": { @@ -1138,12 +1148,12 @@ "90": 0 }, "lat": { - "avg": 281, - "max": 281, + "avg": 383, + "max": 435, "days": [ { "key": "2026-10-14", - "avg": 281 + "avg": 383 } ] } @@ -1168,7 +1178,7 @@ ], "daily": { "2026-10-14": { - "total": 1, + "total": 7, "up": 0 } }, diff --git a/scripts/verify-views.cjs b/scripts/verify-views.cjs index 47cccf2..71fbcc1 100644 --- a/scripts/verify-views.cjs +++ b/scripts/verify-views.cjs @@ -300,15 +300,31 @@ async function main() { const dt = await dp.evaluate(() => document.querySelector('tr[data-status] .t-uptime')?.title ?? ''); check('表格可用率 tooltip 含 90 天日均延迟', /90 天日均延迟 \d+ ms/.test(dt), dt.slice(0, 60)); - // ---- 极端内容:表格不得把数据截断,同时不得出现横向滚动 ---- + // 行高一致性要在「内容长度相当」的前提下检查:先把配置里的名称统一成等长短名 + // (注意:名称来自 monitors.json,不是 status.json),再单独注入超长内容验证不截断 const statusPath = path.join(tmpDir, 'status.json'); const snap = JSON.parse(fs.readFileSync(statusPath, 'utf8')); - const ids = Object.keys(snap.monitors); + const cfgPath2 = path.join(tmpDir, 'monitors.json'); + const cfgJson = JSON.parse(fs.readFileSync(cfgPath2, 'utf8')); + let ids = Object.keys(snap.monitors); + cfgJson.monitors.forEach((m, i) => { m.name = `目标 ${i + 1}`; }); + fs.writeFileSync(cfgPath2, `${JSON.stringify(cfgJson, null, 2)}\n`); + await dp.goto('http://localhost:8894/?source=static&view=table', { waitUntil: 'domcontentloaded' }); + await dp.waitForSelector('table.monitor-table tbody tr[data-status]', { timeout: 20000 }); + await dp.waitForTimeout(900); + const heights = await dp.evaluate(() => { + const hs = [...document.querySelectorAll('table.monitor-table tbody tr[data-status]')].map((tr) => Math.round(tr.getBoundingClientRect().height)); + return { hs, unique: [...new Set(hs)] }; + }); + check('内容等长时表格各行等高(可用率条不再撑高行)', heights.unique.length === 1, `行高 ${heights.unique.join('/')}(共 ${heights.hs.length} 行)`); + + // ---- 极端内容:表格不得把数据截断,同时不得出现横向滚动 ---- let injected = 0; for (const id of ids.slice(0, 2)) { - snap.monitors[id].name = `这是一个相当长的监控目标名称用于验证表格完整显示-${id}`; - injected++; + const m = cfgJson.monitors.find((x) => x.id === id); + if (m) { m.name = `这是一个相当长的监控目标名称用于验证表格完整显示-${id}`; injected++; } } + fs.writeFileSync(cfgPath2, `${JSON.stringify(cfgJson, null, 2)}\n`); // 注入事件,验证事件区块的时间线样式与折叠 snap.events = Array.from({ length: 12 }, (_, i) => ({ t: new Date(Date.now() - i * 60000).toISOString(), @@ -337,26 +353,38 @@ async function main() { check(`长名称/长地址不再被截断(注入 ${injected} 个)`, clip.clipped === 0, `截断单元格 ${clip.clipped} 个,最大 ${clip.worst}px`); check('表格仍无横向滚动', clip.pageOverflow <= 0 && clip.tableOverflow <= 0, `页面 ${clip.pageOverflow} / 表格 ${clip.tableOverflow}`); const evr = await dp.evaluate(() => { - const ev = document.querySelector('.ev'); - const cs = ev ? getComputedStyle(ev) : null; - const dot = ev ? getComputedStyle(ev, '::before') : null; + const table = document.querySelector('.events-table'); + const evRow = table?.querySelector('tbody tr'); + const cs = evRow ? getComputedStyle(evRow) : null; const more = document.getElementById('events-more'); return { - shown: document.querySelectorAll('.ev').length, - grid: cs?.display ?? 'none', - dotVisible: dot ? dot.width !== '0px' && dot.backgroundColor !== 'rgba(0, 0, 0, 0)' : false, - leftBorder: cs?.borderLeftWidth ?? '', + shown: (evRow ? table.querySelectorAll('tbody tr').length : 0), + tag: table?.tagName ?? 'none', + hasThead: Boolean(table?.querySelector('thead th')), + headerSameSize: (() => { + const mon = document.querySelector('.monitor-table thead th'); + const ev = table?.querySelector('thead th'); + return mon && ev ? getComputedStyle(mon).fontSize === getComputedStyle(ev).fontSize : false; + })(), + rowBg: cs?.backgroundColor ?? '', + cellBorder: evRow ? getComputedStyle(evRow.querySelector('td')).borderBottomWidth : '', moreHidden: more?.hidden ?? true, moreText: more?.textContent ?? '', count: document.getElementById('events-count')?.textContent ?? '', }; }); - check('事件区块使用时间线布局(grid + 圆点)', evr.grid === 'grid' && evr.dotVisible === true, `display=${evr.grid} 圆点=${evr.dotVisible}`); - check('事件行按类型着色(左描边)', evr.leftBorder === '3px', evr.leftBorder); + check('事件区块与监控表格同构(table + thead)', evr.tag === 'TABLE' && evr.hasThead === true && evr.headerSameSize === true, `${evr.tag},表头字号一致=${evr.headerSameSize}`); + const evBg = await dp.evaluate(() => { + const rows = [...document.querySelectorAll('.events-table tbody tr')]; + const down = rows.find((r) => r.dataset.status === 'down'); + const up = rows.find((r) => r.dataset.status === 'up'); + return { down: down ? getComputedStyle(down).backgroundColor : '无', up: up ? getComputedStyle(up).backgroundColor : '无', downCells: down ? down.querySelectorAll('td').length : 0 }; + }); + check('事件行复用表格状态底色(故障行着色、恢复行不染)', /^(color\(|rgba?\(\d)/.test(evBg.down) && evBg.down !== 'rgba(0, 0, 0, 0)' && evBg.up === 'rgba(0, 0, 0, 0)' && evBg.downCells === 4, `故障=${evBg.down.slice(0, 30)} 恢复=${evBg.up} 列数=${evBg.downCells}`); check('事件默认折叠为 8 条并可展开', evr.shown === 8 && evr.moreHidden === false && /展开全部 12 条/.test(evr.moreText), `显示 ${evr.shown} 条,按钮「${evr.moreText}」,计数「${evr.count}」`); await dp.click('#events-more'); await dp.waitForTimeout(300); - const evExpanded = await dp.evaluate(() => ({ shown: document.querySelectorAll('.ev').length, text: document.getElementById('events-more').textContent })); + const evExpanded = await dp.evaluate(() => ({ shown: document.querySelectorAll('.events-table tbody tr').length, text: document.getElementById('events-more').textContent })); check('展开后显示全部事件', evExpanded.shown === 12 && evExpanded.text === '收起', `显示 ${evExpanded.shown} 条`); await dp.close(); await new Promise((r) => demoServer.close(r));