feat: unify vehicle live metric rail

This commit is contained in:
lingniu
2026-07-19 10:10:28 +08:00
parent a6f6ce260f
commit add47b7efc
4 changed files with 241 additions and 25 deletions

View File

@@ -23,6 +23,7 @@ import { ProtocolTag } from '../shared/ProtocolTag';
import { SegmentedTabs } from '../shared/SegmentedTabs';
import { VehicleSourceEvidencePanel } from '../shared/VehicleSourceEvidencePanel';
import { WorkspaceCommandBar } from '../shared/WorkspaceCommandBar';
import { WorkspaceMetricRail, type WorkspaceQueueMetricRailItem } from '../shared/WorkspaceMetricRail';
import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader';
import { WorkspaceSideSheet, type WorkspaceSideSheetBadgeColor } from '../shared/WorkspaceSideSheet';
import { monitorReturnFromParams, withMonitorReturn } from '../routing/monitorContext';
@@ -466,6 +467,46 @@ function VehicleRecord({ detail, liveRealtime, telemetry, telemetryPending, tele
...(hasMenu(session, 'statistics') ? [{ key: 'statistics', label: '里程查询', icon: <IconClock />, to: withMonitorReturn(`/statistics?vins=${encodeURIComponent(detail.vin)}`, monitorReturn), type: 'tertiary' as const }] : []),
...(hasMenu(session, 'alerts') ? [{ key: 'alerts', label: '告警事件', icon: <IconAlarm />, to: `/alerts?vin=${encodeURIComponent(detail.vin)}`, type: 'tertiary' as const }] : [])
];
const liveMetrics: WorkspaceQueueMetricRailItem[] = [
{
label: '速度',
value: <>{availableMetric(realtime?.speedKmh, realtime?.speedAvailable)}<em className="v2-vehicle-live-unit">km/h</em></>,
note: '实时车速',
tone: 'primary',
emphasis: 'primary'
},
{
label: 'SOC',
value: <>{availableMetric(realtime?.socPercent, realtime?.socAvailable)}<em className="v2-vehicle-live-unit">%</em></>,
note: '剩余电量',
tone: 'success',
emphasis: 'secondary'
},
{
label: '总里程',
value: <>{availableMetric(realtime?.totalMileageKm, realtime?.mileageAvailable)}<em className="v2-vehicle-live-unit">km</em></>,
note: <span className="v2-vehicle-live-action-note"><IconChevronRight /></span>,
emphasis: 'secondary',
ariaLabel: '查看总里程全部来源',
onClick: () => setSourceEvidenceOpen(true)
},
{
label: '当日里程',
value: <>{availableMetric(realtime?.todayMileageKm, realtime?.todayMileageAvailable)}<em className="v2-vehicle-live-unit">km</em></>,
note: <span className="v2-vehicle-live-action-note"><IconChevronRight /></span>,
tone: 'primary',
emphasis: 'primary',
ariaLabel: '查看当日里程全部来源',
onClick: () => setSourceEvidenceOpen(true)
},
{
label: '来源状态',
value: <>{realtime?.onlineSourceCount ?? 0}<em className="v2-vehicle-live-unit">/ {detail.sourceStatus.length}</em></>,
note: '在线来源 / 全部',
tone: (realtime?.onlineSourceCount ?? 0) > 0 ? 'success' : 'neutral',
emphasis: 'secondary'
}
];
useLayoutEffect(() => {
const root = recordRootRef.current;
if (!root) return;
@@ -529,14 +570,17 @@ function VehicleRecord({ detail, liveRealtime, telemetry, telemetryPending, tele
description="关键运行指标与推荐数据来源"
meta={<span className="v2-live-report-meta"><i className={realtime?.online ? 'is-online' : ''} />{realtime?.online ? '实时在线' : '当前离线'} · <IconClock /><PlatformTime value={realtime?.lastSeen || identity?.lastSeen} /></span>}
/>
<div className="v2-live-grid" role="list" aria-label="车辆实时指标">
<div className="v2-live-metric is-speed" role="listitem"><small></small><strong>{availableMetric(realtime?.speedKmh, realtime?.speedAvailable)}<em>km/h</em></strong><span></span></div>
<div className="v2-live-metric is-soc" role="listitem"><small>SOC</small><strong>{availableMetric(realtime?.socPercent, realtime?.socAvailable)}<em>%</em></strong><span></span></div>
<div className="v2-live-metric is-mileage" role="listitem"><small></small><Button theme="borderless" type="tertiary" className="v2-live-source-link" title="展开全部里程来源" aria-label="查看总里程全部来源" onClick={() => setSourceEvidenceOpen(true)}><span>{availableMetric(realtime?.totalMileageKm, realtime?.mileageAvailable)}<em>km</em></span><IconChevronRight /></Button><span></span></div>
<div className="v2-live-metric is-today-mileage" role="listitem"><small></small><Button theme="borderless" type="tertiary" className="v2-live-source-link" title="展开全部里程来源" aria-label="查看当日里程全部来源" onClick={() => setSourceEvidenceOpen(true)}><span>{availableMetric(realtime?.todayMileageKm, realtime?.todayMileageAvailable)}<em>km</em></span><IconChevronRight /></Button><span></span></div>
<div className="v2-live-metric is-source" role="listitem"><small></small><ProtocolTag protocol={realtime?.primaryProtocol} className="v2-live-primary-protocol" /><span title={realtime?.locationSource}>{protocolSourceLabel(realtime?.locationSource) || '当前最优来源'}</span></div>
<div className="v2-live-metric is-source-status" role="listitem"><small></small><strong>{realtime?.onlineSourceCount ?? 0}<em> / {detail.sourceStatus.length}</em></strong><span>线 / </span></div>
</div>
<WorkspaceMetricRail
variant="queue"
className="v2-vehicle-live-metric-rail"
ariaLabel="车辆实时指标"
items={liveMetrics}
context={<span className="v2-vehicle-live-source-context">
<small></small>
<strong><ProtocolTag protocol={realtime?.primaryProtocol} className="v2-live-primary-protocol" compact /></strong>
<em title={realtime?.locationSource}>{protocolSourceLabel(realtime?.locationSource) || '当前最优来源'}</em>
</span>}
/>
<CurrentVehicleAddress vehicle={realtime} fallback={identity?.locationText} />
</section>
</Card>