From 4e7a8c2ba3f041b848dd6c7f59b50249728cc33c Mon Sep 17 00:00:00 2001 From: justme Date: Thu, 22 Oct 2026 10:57:53 +0800 Subject: [PATCH] web: draw isolated points as a connected series and mark unrecorded time in the adaptive audit [CI] --- web/display/src/AdaptiveAudit.tsx | 7 +++++-- web/display/src/display.css | 6 ++++++ web/shared/charts/TimeChart.tsx | 15 ++++++++++++--- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/web/display/src/AdaptiveAudit.tsx b/web/display/src/AdaptiveAudit.tsx index 4913dc3..d464092 100644 --- a/web/display/src/AdaptiveAudit.tsx +++ b/web/display/src/AdaptiveAudit.tsx @@ -17,12 +17,12 @@ const STATES = [ { key: 'quiet', label: '平稳', level: 'ok' }, { key: 'watch', label: '观察', level: 'warn' }, { key: 'active', label: '活跃', level: 'bad' }, - { key: 'dead', label: '不通', level: 'none' }, + { key: 'dead', label: '不通', level: 'dead' }, ] as const type StateKey = (typeof STATES)[number]['key'] const KIND_NAMES: Record = { quic_ping: 'QUIC 往返', tcp_ping: 'TCP 往返', tcp_connect: 'TCP 建连', http_request: 'HTTP 请求' } -const STATE_LABEL: Record = { quiet: '平稳', watch: '观察', active: '活跃', dead: '不通' } +const STATE_LABEL: Record = { start: '启动', quiet: '平稳', watch: '观察', active: '活跃', dead: '不通' } const secondsOf = (b: AdaptiveBucketDto, state: StateKey) => b[`${state}_seconds` as const] @@ -141,6 +141,9 @@ export function AdaptiveAudit({ lineId }: { lineId: string }) { {s.label} ))} + + 无记录 + {data.kinds.map((k) => ( diff --git a/web/display/src/display.css b/web/display/src/display.css index db409f2..b50acb3 100644 --- a/web/display/src/display.css +++ b/web/display/src/display.css @@ -2752,3 +2752,9 @@ input { color: var(--app-ink-muted); font-size: 13px; } + +/* 自适应审计里「不通」:比「没有记录」(灰、半透明)深 */ +.bar.dead { + background: var(--app-ink-muted); + opacity: 1; +} diff --git a/web/shared/charts/TimeChart.tsx b/web/shared/charts/TimeChart.tsx index 7c84c9e..4ca2422 100644 --- a/web/shared/charts/TimeChart.tsx +++ b/web/shared/charts/TimeChart.tsx @@ -40,10 +40,19 @@ export function fmtOffset(ms: number): string { return h > 0 ? `${h}:${two(m)}${sec ? ':' + two(sec) : ''}` : `${m}:${two(sec)}` } -/** 有值的格子不到三分之一(而且至少有一个)算稀疏。 */ +/** + * 稀疏:有值的点里,前后都是空的(孤立的)占三成以上。每 10 秒才一次的建连放在 5 秒的格子里就是隔一格有一格没有, + * 每个点都是孤立的,连不成线,图上什么都看不见;这种序列画出点,并把点连起来。 + */ function isSparse(values: (number | null)[]): boolean { - const filled = values.filter((v) => v !== null).length - return filled > 0 && filled < values.length / 3 + let filled = 0 + let isolated = 0 + for (let i = 0; i < values.length; i++) { + if (values[i] === null) continue + filled++ + if ((i === 0 || values[i - 1] === null) && (i === values.length - 1 || values[i + 1] === null)) isolated++ + } + return filled > 0 && isolated / filled >= 0.3 } /**