feat(platform-web): show source consistency

This commit is contained in:
lingniu
2026-07-04 03:57:26 +08:00
parent 2e50f43ff4
commit 353b71ebbb
2 changed files with 132 additions and 0 deletions

View File

@@ -26,6 +26,26 @@ const coverageStatusText: Record<string, string> = {
no_data: '暂无来源'
};
function isFiniteNumber(value: unknown): value is number {
return typeof value === 'number' && Number.isFinite(value);
}
function formatCompactNumber(value?: number, suffix = '') {
if (!isFiniteNumber(value)) return '-';
return `${value.toLocaleString(undefined, { maximumFractionDigits: 1 })}${suffix}`;
}
function parseTimeMs(value?: string) {
if (!value) return undefined;
const ms = Date.parse(value);
return Number.isFinite(ms) ? ms : undefined;
}
function formatSeconds(value?: number) {
if (!isFiniteNumber(value)) return '-';
return `${Math.round(value)}`;
}
export function VehicleDetail({
vin,
protocol,
@@ -96,6 +116,20 @@ export function VehicleDetail({
const online = resolution?.online || summary?.online || identity?.online || false;
const lastSeen = resolution?.lastSeen || summary?.lastSeen || latest?.lastSeen || '-';
const serviceStatus = detail?.serviceStatus;
const realtimeRows = detail?.realtime ?? [];
const realtimeSources = new Set(realtimeRows.map((row) => row.protocol).filter(Boolean));
const sourceCount = Math.max(detail?.sourceStatus?.length ?? 0, realtimeSources.size, summary?.sourceCount ?? 0, protocols.length);
const onlineSourceCount = detail?.sourceStatus?.length
? detail.sourceStatus.filter((source) => source.online).length
: summary?.onlineSourceCount ?? 0;
const locatedSourceCount = realtimeRows.filter((row) => isFiniteNumber(row.longitude) && isFiniteNumber(row.latitude)).length;
const mileageValues = realtimeRows.map((row) => row.totalMileageKm).filter(isFiniteNumber);
const mileageDelta = mileageValues.length > 1 ? Math.max(...mileageValues) - Math.min(...mileageValues) : undefined;
const timeValues = [
...realtimeRows.map((row) => parseTimeMs(row.lastSeen)),
...(detail?.sourceStatus ?? []).map((source) => parseTimeMs(source.lastSeen))
].filter(isFiniteNumber);
const sourceTimeDeltaSeconds = timeValues.length > 1 ? (Math.max(...timeValues) - Math.min(...timeValues)) / 1000 : undefined;
const activeProtocol = query.protocol?.trim() ?? '';
const scopeText = activeProtocol ? `单一来源:${activeProtocol}` : '全部来源聚合';
const formKey = `${query.keyword}-${query.protocol ?? ''}`;
@@ -284,6 +318,20 @@ export function VehicleDetail({
)}
</Card>
<Card bordered title="跨来源一致性" style={{ marginTop: 16 }}>
<Descriptions
row
data={[
{ key: '来源覆盖', value: sourceCount > 0 ? `${sourceCount} 个来源` : '-' },
{ key: '在线来源', value: sourceCount > 0 ? `${onlineSourceCount}/${sourceCount} 在线` : '-' },
{ key: '位置覆盖', value: locatedSourceCount > 0 ? `${locatedSourceCount} 个来源有位置` : '暂无位置' },
{ key: '里程差异', value: formatCompactNumber(mileageDelta, ' km') },
{ key: '来源时间差', value: formatSeconds(sourceTimeDeltaSeconds) },
{ key: '车辆服务视角', value: activeProtocol ? `当前只看 ${activeProtocol}` : '三类来源合并为同一车辆服务' }
]}
/>
</Card>
<Card bordered title="来源诊断明细" style={{ marginTop: 16 }}>
<Table
loading={loading}