feat(web): live-данные — polling, онлайн-индикаторы, относительное время, actionable-очередь ошибок apply, часовая агрегация статистики

This commit is contained in:
Denozordec
2026-09-25 01:17:33 +07:00
parent 98e4dcdefb
commit 0b426fa7ae
11 changed files with 272 additions and 69 deletions
+19
View File
@@ -34,6 +34,8 @@ const timeFmt = new Intl.DateTimeFormat('ru-RU', {
second: '2-digit',
})
const relativeFmt = new Intl.RelativeTimeFormat('ru-RU', { numeric: 'auto' })
/** Compact packet counter: 1,2K / 3,4M */
export function formatPackets(n: number | undefined | null): string {
if (n === undefined || n === null) return '—'
@@ -72,3 +74,20 @@ export function formatStampDateTime(iso: string | null | undefined): string {
export function formatTime(d: Date): string {
return timeFmt.format(d)
}
/** «2 минуты назад» / «5 часов назад»; старше 7 дней — полная дата. */
export function formatRelativeTime(iso: string | null | undefined): string {
if (!iso) return '—'
const t = Date.parse(iso)
if (Number.isNaN(t)) return '—'
const diffMs = t - Date.now()
const absMin = Math.round(Math.abs(diffMs) / 60_000)
if (absMin < 1) return 'только что'
const sign = diffMs < 0 ? -1 : 1
if (absMin < 60) return relativeFmt.format(sign * absMin, 'minute')
const absHours = Math.round(absMin / 60)
if (absHours < 24) return relativeFmt.format(sign * absHours, 'hour')
const absDays = Math.round(absHours / 24)
if (absDays < 7) return relativeFmt.format(sign * absDays, 'day')
return formatDateTime(iso)
}