From 3d395aaa8d6197895fad457891936fc0ca8c5ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B2=D0=BE=D0=B2=20=D0=90=D1=80=D1=82?= =?UTF-8?q?=D0=B5=D0=BC?= Date: Sun, 5 Jul 2026 21:43:32 +0300 Subject: [PATCH] =?UTF-8?q?BUR-61=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=8C=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D1=8F=D1=82=D1=8C=20=D0=B8=20=D0=BE=D1=82=D0=BE=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=B6=D0=B0=D1=82=D1=8C=20current.value=20=3D=20null=20?= =?UTF-8?q?=D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/current/types.ts | 2 +- src/features/edge-detail/components/ArchiveView.tsx | 4 ++-- src/features/electrical-schematics/ElectricalNode.tsx | 4 ++-- src/utils/format.ts | 6 +++--- src/utils/metricStatus.ts | 5 +++-- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/entities/current/types.ts b/src/entities/current/types.ts index bfa31cf..bf97b7c 100644 --- a/src/entities/current/types.ts +++ b/src/entities/current/types.ts @@ -1,7 +1,7 @@ export type CurrentItem = { edge: string; tag: string; - value: number; + value: number | null; createdAt: string; updatedAt: string; time: string; diff --git a/src/features/edge-detail/components/ArchiveView.tsx b/src/features/edge-detail/components/ArchiveView.tsx index 9c5909d..ce4dbfd 100644 --- a/src/features/edge-detail/components/ArchiveView.tsx +++ b/src/features/edge-detail/components/ArchiveView.tsx @@ -5,7 +5,7 @@ import { CalendarDays, CalendarClock, Check, ChevronDown, Clock3, DatabaseZap, S import type { CurrentItem } from '../../../entities/current/types'; import { HistoryChart } from '../../../features/history-chart/HistoryChart'; import { RANGE_PRESETS, createRange, type DateRangeState } from '../../../features/history/dateRange'; -import { toIsoFromInput } from '../../../utils/format'; +import { formatNumber, toIsoFromInput } from '../../../utils/format'; import type { HistoryGranularity } from '../../../utils/historyGranularity'; type ArchiveViewProps = { @@ -191,7 +191,7 @@ export function ArchiveView({ {label !== item.tag ? {item.tag} : null} - {item.value.toLocaleString('ru-RU', { maximumFractionDigits: item.precision ?? 3 })} + {formatNumber(item.value)} {selected ? : null} diff --git a/src/features/electrical-schematics/ElectricalNode.tsx b/src/features/electrical-schematics/ElectricalNode.tsx index 3b51f56..bf9dfb7 100644 --- a/src/features/electrical-schematics/ElectricalNode.tsx +++ b/src/features/electrical-schematics/ElectricalNode.tsx @@ -29,8 +29,8 @@ export function ElectricalNode({ liveValues, node, ownerEdgeId }: ElectricalNode ? getLiveValue(liveValues, node.edgeId || ownerEdgeId, node.tagId) : getLiveValue(liveValues, bindingEdgeId, bindings?.stateTagId); const alarmValue = node.kind === 'decoration' ? getLiveValue(liveValues, bindingEdgeId, bindings?.alarmTagId) : undefined; - const alarmActive = Boolean(alarmValue && Number(alarmValue.value) !== 0); - const stateActive = Boolean(mainValue && Number(mainValue.value) !== 0); + const alarmActive = Boolean(alarmValue && alarmValue.value !== null && alarmValue.value !== 0); + const stateActive = Boolean(mainValue && mainValue.value !== null && mainValue.value !== 0); const title = getNodeTitle(node, mainValue); const style: CSSProperties = { left: node.position.x, diff --git a/src/utils/format.ts b/src/utils/format.ts index 2f27483..e5e81f2 100644 --- a/src/utils/format.ts +++ b/src/utils/format.ts @@ -1,7 +1,7 @@ /** Форматирует числовое значение показателя для карточек и мини-плиток. */ -export function formatNumber(value: number): string { - if (!Number.isFinite(value)) { - return '-'; +export function formatNumber(value: number | null): string { + if (value === null || !Number.isFinite(value)) { + return '—'; } return new Intl.NumberFormat('ru-RU', { diff --git a/src/utils/metricStatus.ts b/src/utils/metricStatus.ts index 10be0bd..6c246d4 100644 --- a/src/utils/metricStatus.ts +++ b/src/utils/metricStatus.ts @@ -16,8 +16,9 @@ function isConfiguredLimit(value: number | null): value is number { export function getMetricStatus(item: CurrentItem, now = Date.now()): MetricStatusInfo { const measuredAt = new Date(item.time).getTime(); const ageSeconds = Number.isFinite(measuredAt) ? Math.max(0, Math.round((now - measuredAt) / 1000)) : Number.POSITIVE_INFINITY; - const belowMin = isConfiguredLimit(item.min) && item.value < item.min; - const aboveMax = isConfiguredLimit(item.max) && item.value > item.max; + const value = item.value; + const belowMin = isConfiguredLimit(value) && isConfiguredLimit(item.min) && value < item.min; + const aboveMax = isConfiguredLimit(value) && isConfiguredLimit(item.max) && value > item.max; if (belowMin || aboveMax) { return { status: 'critical', label: 'за пределами уставки', ageSeconds };