import { IconRefresh, IconSearch } from '@douyinfe/semi-icons'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { FormEvent, useDeferredValue, useEffect, useState } from 'react'; import { api } from '../../api/client'; import type { VehicleCoverageRow, VehicleLocationSourceEvidence, VehicleSourceDiagnostic } from '../../api/types'; import { InlineError } from '../shared/AsyncState'; import { LIVE_QUERY_POLICY, QUERY_MEMORY } from '../queryPolicy'; import ReconciliationCenter from './ReconciliationCenter'; function statusLabel(status: string) { return { ok: '正常', warning: '关注', error: '异常' }[status] ?? status; } function fmt(value?: string) { if (!value) return '—'; const parsed = new Date(value.replace(' ', 'T')); return Number.isNaN(parsed.getTime()) ? value : parsed.toLocaleString('zh-CN', { hour12: false }); } function number(value?: number, digits = 1) { return value == null || !Number.isFinite(value) ? '—' : value.toLocaleString('zh-CN', { maximumFractionDigits: digits }); } function SourcePolicyRow({ vin, source, diagnostic, editable, onSaved }: { vin: string; source: VehicleLocationSourceEvidence; diagnostic: VehicleSourceDiagnostic; editable: boolean; onSaved: (next: VehicleSourceDiagnostic) => void; }) { const [enabled, setEnabled] = useState(source.enabled); const [priority, setPriority] = useState(source.priority); const [providerName, setProviderName] = useState(source.providerOverride || ''); const [providerEvidence, setProviderEvidence] = useState(''); const [remark, setRemark] = useState(source.policyRemark || ''); useEffect(() => { setEnabled(source.enabled); setPriority(source.priority); setProviderName(source.providerOverride || ''); setProviderEvidence(''); setRemark(source.policyRemark || ''); }, [source.enabled, source.priority, source.providerOverride, source.policyRemark, source.sourceRef]); const save = useMutation({ mutationFn: () => api.updateVehicleSourcePolicy(vin, { version: diagnostic.policy.version, sourceRef: source.sourceRef ?? '', providerName, providerEvidence, enabled, priority, remark }), onSuccess: onSaved }); const providerChanged = providerName.trim() !== (source.providerOverride || ''); const policyEditable = source.sourceKind !== 'CANONICAL'; const policyChanged = enabled !== source.enabled || priority !== source.priority || remark.trim() !== (source.policyRemark || ''); const changed = (policyEditable && policyChanged) || providerChanged; return {source.sourceLabel}{source.terminalLabel || source.sourceKind || '未维护终端'} {source.protocol}{source.selectedWithinProtocol ? '协议内已选' : '协议内候选'} {source.online ? '在线' : '离线'}{source.qualityStatus || '未知'}{source.qualityReason ? ` · ${source.qualityReason}` : ''} {fmt(source.firstSeenAt)}最近 {fmt(source.receivedAt || source.eventTime)} {source.reportIntervalSec == null ? '—' : `${source.reportIntervalSec}s`}{source.reportSampleCount ? `${source.reportSampleCount.toLocaleString('zh-CN')} 个里程样本` : '暂无累计样本'} {source.longitude == null || source.latitude == null ? '—' : `${source.longitude.toFixed(6)}, ${source.latitude.toFixed(6)}`}{number(source.speedKmh)} km/h · {number(source.totalMileageKm)} km {source.recommended ? '当前推荐' : source.selectedWithinProtocol ? '协议首选' : '备用来源'}{source.selectionReason || '等待选举说明'} setPriority(Number(event.target.value))} /> setProviderName(event.target.value)} placeholder="提供方,如 G7s" /> setProviderEvidence(event.target.value)} placeholder={providerChanged ? '权威终端清单、厂商确认记录等(必填)' : '修改提供方后填写核验依据'} /> setRemark(event.target.value)} placeholder={policyEditable ? '启停或优先级调整原因(可选)' : '协议融合快照不可调整策略'} /> {save.isError ? {save.error instanceof Error ? save.error.message : '保存失败'} : null} ; } function SourceDiagnosticWorkspace() { const queryClient = useQueryClient(); const [keyword, setKeyword] = useState(''); const deferredKeyword = useDeferredValue(keyword.trim()); const [selected, setSelected] = useState(); const [candidateOffset, setCandidateOffset] = useState(0); useEffect(() => setCandidateOffset(0), [deferredKeyword]); const candidates = useQuery({ queryKey: ['ops-source-candidates', deferredKeyword, candidateOffset], queryFn: ({ signal }) => api.vehicleCoverage(new URLSearchParams({ keyword: deferredKeyword, bindingStatus: 'bound', limit: '20', offset: String(candidateOffset) }), signal), enabled: deferredKeyword.length > 0, staleTime: 15_000, gcTime: QUERY_MEMORY.optionGcTime }); const session = useQuery({ queryKey: ['ops-session'], queryFn: ({ signal }) => api.session(signal), staleTime: 60_000 }); const diagnostic = useQuery({ queryKey: ['ops-source-diagnostic', selected?.vin], queryFn: ({ signal }) => api.vehicleSourceDiagnostic(selected!.vin, signal), enabled: Boolean(selected?.vin), staleTime: 5_000, gcTime: QUERY_MEMORY.highVolumeGcTime }); const choose = (vehicle: VehicleCoverageRow) => { setSelected(vehicle); setKeyword(vehicle.plate || vehicle.vin); }; const submit = (event: FormEvent) => { event.preventDefault(); const first = candidates.data?.items[0]; if (first) choose(first); }; const data = diagnostic.data; const editable = session.data?.role === 'admin'; return
专业运维工作台单车多来源诊断按需查询,不加载全量 RAW;普通客户无权访问。
{selected ? : null}
{deferredKeyword && !selected ?
{candidates.isFetching ?

正在查询车辆…

: candidates.data?.items.map((vehicle) => )} {!candidates.isFetching && !candidates.data?.items.length ?

没有匹配的已绑定车辆

: null} {(candidates.data?.total ?? 0) > 20 ?
第 {Math.floor(candidateOffset / 20) + 1} / {Math.ceil((candidates.data?.total ?? 0) / 20)} 页
: null}
: null}
{diagnostic.isError ? diagnostic.refetch()} /> : null} {!selected ?
先选择一辆车将展示所有协议和同协议多终端、推荐原因、上报周期与可审计策略。
: null} {selected && diagnostic.isPending ?
正在读取来源证据只查询当前车辆,不会扫描整车队。
: null} {data ? <>
车辆{data.evidence.plate || selected?.plate || '未绑定车牌'}{data.evidence.vin}
当前推荐{data.evidence.recommendedLocationLabel || '暂无推荐'}{data.evidence.recommendedLocationProtocol || '—'}
来源状态{data.evidence.locationSources.filter((item) => item.online).length} / {data.evidence.locationSources.length} 在线{data.evidence.locationConflict ? `位置冲突 ${number(data.evidence.conflictDistanceM)}m` : '未发现实时位置冲突'}
策略版本v{data.policy.version}{data.policy.updatedAt ? `${data.policy.updatedBy} · ${fmt(data.policy.updatedAt)}` : '尚无人工调整'}
推荐说明

{data.recommendationReason}

{data.refreshHint}
{!editable ?

当前账号可查看诊断证据;只有管理员可以调整启停和优先级。

: null}
{data.evidence.locationSources.map((source) => { queryClient.setQueryData(['ops-source-diagnostic', data.evidence.vin], next); void Promise.all([ queryClient.invalidateQueries({ queryKey: ['access-summary'] }), queryClient.invalidateQueries({ queryKey: ['access-vehicles'] }), queryClient.invalidateQueries({ queryKey: ['ops-source-readiness-v2'] }) ]); }} />)}
来源 / 终端协议在线 / 质量首次 / 最近上报上报周期位置 / 里程选举结论运维策略
最近策略审计仅记录实际变更,原始 source_key 不对前端暴露
{data.policy.audit.length ?
    {data.policy.audit.map((item) =>
  1. v{item.version}{item.summary}{item.changeType === 'provider' ? '提供方' : '策略'} · {item.actor} · {fmt(item.changedAt)}
  2. )}
:

该车辆尚无人工来源策略或提供方变更。

}
: null}
; } export default function OperationsPage() { const health = useQuery({ queryKey: ['ops-health-v2'], queryFn: ({ signal }) => api.opsHealth(signal), refetchInterval: 15_000, staleTime: 8_000, gcTime: QUERY_MEMORY.summaryGcTime, ...LIVE_QUERY_POLICY }); const readiness = useQuery({ queryKey: ['ops-source-readiness-v2'], queryFn: ({ signal }) => api.sourceReadiness(signal), refetchInterval: 30_000, staleTime: 15_000, gcTime: QUERY_MEMORY.summaryGcTime, ...LIVE_QUERY_POLICY }); const data = health.data; const sources = readiness.data; const refresh = () => Promise.all([health.refetch(), readiness.refetch()]); return

运维质量

先定位单车多来源问题,再核对服务和协议全局健康;所有结论来自服务端证据。

{health.isError ? : null} {readiness.isError ? readiness.refetch()} /> : null}
运行版本{data?.runtime.platformRelease || '未注入'}{data?.runtime.dataMode || 'unknown'}
活跃连接{data?.activeConnections?.toLocaleString('zh-CN') ?? '—'}capacity-check
Kafka Lag{data?.kafkaLag?.toLocaleString('zh-CN') ?? '—'}{data?.kafkaLag === 0 ? '已回零' : '需检查'}
Redis 在线 Key{data?.redisOnlineKeys?.toLocaleString('zh-CN') ?? '—'}实时探针
服务身份 / 在线{sources ? `${sources.totalVehicles} / ${sources.onlineVehicles}` : '—'}{sources ? `已绑定 ${sources.boundVehicles} · 待绑定 ${sources.identityRequiredVehicles}` : '档案与快照并集'}
数据链路15 秒自动刷新
{data?.linkHealth.map((item) =>
{item.name}

{item.detail || '无补充信息'}

{statusLabel(item.status)}
)}
运行时安全
生产数据模式
{data?.runtime.dataMode === 'production' ? '已启用' : '未启用'}
MySQL 写探针
{data?.mysqlWritable ? '正常' : '异常'}
TDengine 写探针
{data?.tdengineWritable ? '正常' : '异常'}
请求超时
{data?.runtime.requestTimeoutMs ?? '—'} ms
高德安全代理
{data?.runtime.amapSecurityProxyEnabled ? '服务端代理' : '未启用'}
{data?.capacityFindings?.length ?
{data.capacityFindings.map((item) =>

{item}

)}
:

容量检查无待处理项

}
协议来源就绪度验收口径与处置建议
{sources?.sources.map((source) =>
{source.protocol}{source.role}
{source.online} / {source.total} 在线

{source.evidence}

{source.action}

{source.acceptance}
)}
; }