feat(platform): harden telemetry pipeline and unify Semi UI workspaces

This commit is contained in:
lingniu
2026-07-18 00:26:36 +08:00
parent 65b4e4f055
commit 159c80b0ae
136 changed files with 21616 additions and 1785 deletions

View File

@@ -1,4 +1,5 @@
import { useQuery } from '@tanstack/react-query';
import { Button, Card, Empty, Input, Spin, Tag } from '@douyinfe/semi-ui';
import { useMemo, useState } from 'react';
import { api } from '../../api/client';
import type { VehicleLocationSourceEvidence, VehicleMileageSourceEvidence } from '../../api/types';
@@ -28,16 +29,16 @@ function evidenceTone(source: Pick<VehicleLocationSourceEvidence, 'recommended'
function sourceBadges(source: Pick<VehicleLocationSourceEvidence, 'recommended' | 'selectedWithinProtocol' | 'enabled' | 'online' | 'qualityStatus'>) {
return <>
{source.recommended ? <b className="is-recommended"></b> : null}
{!source.recommended && source.selectedWithinProtocol ? <b></b> : null}
{!source.enabled ? <b className="is-disabled"></b> : null}
{source.enabled && !source.online ? <b className="is-offline">线</b> : null}
{source.qualityStatus !== 'OK' ? <b className="is-warning">{source.qualityStatus}</b> : null}
{source.recommended ? <Tag className="is-recommended" color="blue" type="light" size="small"></Tag> : null}
{!source.recommended && source.selectedWithinProtocol ? <Tag color="cyan" type="light" size="small"></Tag> : null}
{!source.enabled ? <Tag className="is-disabled" color="grey" type="light" size="small"></Tag> : null}
{source.enabled && !source.online ? <Tag className="is-offline" color="grey" type="light" size="small">线</Tag> : null}
{source.qualityStatus !== 'OK' ? <Tag className="is-warning" color="orange" type="light" size="small">{source.qualityStatus}</Tag> : null}
</>;
}
function LocationSourceCard({ source }: { source: VehicleLocationSourceEvidence }) {
return <article className={`v2-source-evidence-card is-${evidenceTone(source)}`}>
return <Card className={`v2-source-evidence-card is-${evidenceTone(source)}`} bodyStyle={{ padding: 0 }}>
<header><div><strong>{source.sourceLabel || source.protocol}</strong><span>{source.protocol}{source.terminalLabel ? ` · ${source.terminalLabel}` : ''}</span></div><aside>{sourceBadges(source)}</aside></header>
<dl>
<div><dt></dt><dd>{coordinate(source)}</dd></div>
@@ -48,12 +49,12 @@ function LocationSourceCard({ source }: { source: VehicleLocationSourceEvidence
<div><dt></dt><dd>{source.receivedAt || '—'}</dd></div>
</dl>
{source.qualityReason ? <p>{source.qualityReason}</p> : null}
</article>;
</Card>;
}
function MileageSourceCard({ source }: { source: VehicleMileageSourceEvidence }) {
const comparable = { ...source, online: true };
return <article className={`v2-source-evidence-card is-${evidenceTone(comparable)}`}>
return <Card className={`v2-source-evidence-card is-${evidenceTone(comparable)}`} bodyStyle={{ padding: 0 }}>
<header><div><strong>{source.sourceLabel || source.protocol}</strong><span>{source.protocol}{source.terminalLabel ? ` · ${source.terminalLabel}` : ''}</span></div><aside>{sourceBadges(comparable)}</aside></header>
<dl>
<div><dt></dt><dd>{source.dailyMileageKm == null ? '—' : `${number(source.dailyMileageKm)} km`}</dd></div>
@@ -64,7 +65,7 @@ function MileageSourceCard({ source }: { source: VehicleMileageSourceEvidence })
<div><dt></dt><dd>{source.latestEventTime || '—'}</dd></div>
</dl>
{source.qualityReason ? <p>{source.qualityReason}</p> : null}
</article>;
</Card>;
}
export function VehicleSourceEvidencePanel({
@@ -100,18 +101,18 @@ export function VehicleSourceEvidencePanel({
return `已读取 ${query.data.locationSources.length} 个位置来源、${query.data.mileageSources.length} 个里程来源`;
}, [query.data, sourceCount]);
return <section className={`v2-source-evidence${compact ? ' is-compact' : ''}${expanded ? ' is-open' : ''}`}>
return <Card className={`v2-source-evidence${compact ? ' is-compact' : ''}${expanded ? ' is-open' : ''}`} bodyStyle={{ padding: 0 }}>
<header className="v2-source-evidence-trigger">
<div><strong></strong><span>{description}</span></div>
<button type="button" aria-expanded={expanded} onClick={() => setExpanded(!expanded)}>{expanded ? '收起来源' : '查看全部来源'}</button>
<Button theme="light" aria-expanded={expanded} onClick={() => setExpanded(!expanded)}>{expanded ? '收起来源' : '查看全部来源'}</Button>
</header>
{expanded ? <div className="v2-source-evidence-body">
<div className="v2-source-evidence-toolbar">
<label><span></span><input type="date" value={date} max={today()} onChange={(event) => setDate(event.target.value)} /></label>
<label><span></span><Input aria-label="里程日期" type="date" value={date} max={today()} onChange={setDate} /></label>
<small></small>
</div>
{query.isPending ? <div className="v2-source-evidence-state"><i /></div> : null}
{query.isError ? <div className="v2-source-evidence-state is-error"><span>{query.error instanceof Error ? query.error.message : '来源证据读取失败'}</span><button type="button" onClick={() => void query.refetch()}></button></div> : null}
{query.isPending ? <div className="v2-source-evidence-state" role="status"><Spin size="small" /></div> : null}
{query.isError ? <div className="v2-source-evidence-state is-error"><span>{query.error instanceof Error ? query.error.message : '来源证据读取失败'}</span><Button theme="borderless" type="danger" size="small" onClick={() => void query.refetch()}></Button></div> : null}
{query.data ? <>
<div className="v2-source-evidence-summary">
<div><small></small><strong>{query.data.recommendedLocationLabel || query.data.recommendedLocationProtocol || '—'}</strong></div>
@@ -121,8 +122,8 @@ export function VehicleSourceEvidencePanel({
</div>
{query.data.locationSources.length ? <section className="v2-source-evidence-group"><header><strong></strong><span>{query.data.locationConflict ? `后台检测到位置冲突${query.data.conflictDistanceM == null ? '' : ` · ${number(query.data.conflictDistanceM)} m`}` : '推荐来源与备用来源并列展示'}</span></header><div>{query.data.locationSources.map((source, index) => <LocationSourceCard key={`${source.protocol}-${source.sourceLabel}-${source.terminalLabel}-${index}`} source={source} />)}</div></section> : null}
{query.data.mileageSources.length ? <section className="v2-source-evidence-group"><header><strong>{query.data.mileageDate} </strong><span> {number(query.data.comparison.dailyMileageDeltaKm)} km</span></header><div>{query.data.mileageSources.map((source, index) => <MileageSourceCard key={`${source.protocol}-${source.sourceLabel}-${source.terminalLabel}-${index}`} source={source} />)}</div></section> : null}
{!query.data.locationSources.length && !query.data.mileageSources.length ? <div className="v2-source-evidence-state"></div> : null}
{!query.data.locationSources.length && !query.data.mileageSources.length ? <Empty className="v2-source-evidence-empty" title="暂无来源证据" description="该车辆当前没有可展示的位置或里程来源。" /> : null}
</> : null}
</div> : null}
</section>;
</Card>;
}