feat(platform): expose multi-source vehicle evidence
This commit is contained in:
@@ -15,6 +15,7 @@ import { formatZhNumber } from '../domain/formatters';
|
||||
import { parseVehicleProfileSyncCSV, vehicleProfileSyncCSVHeader } from '../domain/profileSync';
|
||||
import { FleetMap } from '../map/FleetMap';
|
||||
import { InlineError, PageLoading } from '../shared/AsyncState';
|
||||
import { VehicleSourceEvidencePanel } from '../shared/VehicleSourceEvidencePanel';
|
||||
|
||||
function fmt(value?: string) { return value?.trim() || '—'; }
|
||||
function metric(value: number | undefined, fallback = '—') { return typeof value === 'number' && Number.isFinite(value) ? formatZhNumber(value, 1) : fallback; }
|
||||
@@ -173,6 +174,7 @@ function TelemetryPanel({ data, pending, error }: { data?: LatestTelemetryRespon
|
||||
|
||||
function VehicleRecord({ detail, liveRealtime, telemetry, telemetryPending, telemetryError, onUpdated }: { detail: VehicleDetail; liveRealtime?: VehicleRealtimeRow; telemetry?: LatestTelemetryResponse; telemetryPending: boolean; telemetryError?: string; onUpdated: () => void }) {
|
||||
const { session } = usePlatformSession();
|
||||
const [sourceEvidenceOpen, setSourceEvidenceOpen] = useState(false);
|
||||
const realtime = liveRealtime ?? detail.realtimeSummary;
|
||||
const identity = detail.identity;
|
||||
const mapVehicles = realtime ? [realtime] : [];
|
||||
@@ -185,11 +187,12 @@ function VehicleRecord({ detail, liveRealtime, telemetry, telemetryPending, tele
|
||||
</section>
|
||||
|
||||
<div className="v2-record-grid">
|
||||
<section className="v2-single-map-card"><FleetMap vehicles={mapVehicles} selectedVin={detail.vin} onSelect={() => undefined} /><footer><span><IconMapPin />{realtime ? `实时坐标 ${realtime.longitude.toFixed(6)}, ${realtime.latitude.toFixed(6)}` : '暂无有效实时坐标'}{identity?.locationText ? ` · 档案区域 ${identity.locationText}` : ''}</span><time>更新时间:{fmt(realtime?.lastSeen)}</time></footer></section>
|
||||
<section className="v2-single-map-card"><FleetMap vehicles={mapVehicles} selectedVin={detail.vin} onSelect={() => undefined} /><footer><button type="button" className="v2-map-source-link" title="展开全部位置来源" onClick={() => setSourceEvidenceOpen(true)}><IconMapPin />{realtime ? `实时坐标 ${realtime.longitude.toFixed(6)}, ${realtime.latitude.toFixed(6)}` : '暂无有效实时坐标'}{identity?.locationText ? ` · 档案区域 ${identity.locationText}` : ''}</button><time>更新时间:{fmt(realtime?.lastSeen)}</time></footer></section>
|
||||
<Archive detail={detail} editable={canAdminister(session)} onUpdated={onUpdated} />
|
||||
<section className="v2-record-card v2-live-card"><header><strong>实时指标</strong><span><IconClock />{timeOnly(realtime?.lastSeen)}</span></header><div className="v2-live-grid">
|
||||
<div><small>速度</small><strong>{metric(realtime?.speedKmh)}<em>km/h</em></strong></div><div><small>SOC</small><strong>{metric(realtime?.socPercent)}<em>%</em></strong></div><div><small>总里程</small><strong>{metric(realtime?.totalMileageKm)}<em>km</em></strong></div><div><small>当日里程</small><strong>{metric(lastMileage?.dailyMileageKm)}<em>km</em></strong></div><div><small>在线来源</small><strong>{realtime?.onlineSourceCount ?? 0}<em>个</em></strong></div><div><small>数据源总数</small><strong>{detail.sourceStatus.length}<em>个</em></strong></div>
|
||||
<div><small>速度</small><strong>{metric(realtime?.speedKmh)}<em>km/h</em></strong></div><div><small>SOC</small><strong>{metric(realtime?.socPercent)}<em>%</em></strong></div><div><small>总里程</small><button type="button" className="v2-live-source-link" title="展开全部里程来源" onClick={() => setSourceEvidenceOpen(true)}>{metric(realtime?.totalMileageKm)}<em>km</em></button></div><div><small>当日里程</small><button type="button" className="v2-live-source-link" title="展开全部里程来源" onClick={() => setSourceEvidenceOpen(true)}>{metric(lastMileage?.dailyMileageKm)}<em>km</em></button></div><div><small>在线来源</small><strong>{realtime?.onlineSourceCount ?? 0}<em>个</em></strong></div><div><small>数据源总数</small><strong>{detail.sourceStatus.length}<em>个</em></strong></div>
|
||||
</div></section>
|
||||
<VehicleSourceEvidencePanel vin={detail.vin} open={sourceEvidenceOpen} onOpenChange={setSourceEvidenceOpen} />
|
||||
<TelemetryPanel data={telemetry} pending={telemetryPending} error={telemetryError} />
|
||||
<Events detail={detail} />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user