import { Button, Card, Col, Form, Row, Select, Space, Spin, Table, Tag, Toast, Typography } from '@douyinfe/semi-ui'; import { IconCopy } from '@douyinfe/semi-icons'; import { useEffect, useMemo, useState } from 'react'; import { api } from '../api/client'; import type { DashboardSummary, OpsHealth, QualityIssueRow, VehicleCoverageRow, VehicleRealtimeRow, VehicleServiceSummary } from '../api/types'; import { PageHeader } from '../components/PageHeader'; import { SourceStatusTags } from '../components/SourceStatusTags'; import { StatusTag } from '../components/StatusTag'; import { VehicleMap, type VehicleMapPoint } from '../components/VehicleMap'; import { isAMapConfigured } from '../config/appConfig'; import { buildAppHash } from '../domain/appRoute'; import { buildCsv, downloadCsv, type CsvColumn } from '../domain/csvExport'; import { qualityIssueLabel, qualityProtocolLabel } from '../domain/qualityIssue'; import { qualityIssueVehicleLookup } from '../domain/vehicleLookup'; const serviceStatusTitle: Record = { healthy: '服务正常', degraded: '来源不完整', offline: '车辆离线', no_data: '暂无数据来源', identity_required: '身份未绑定' }; const missingProtocolTitle: Record = { GB32960: '缺 GB32960', JT808: '缺 JT808', YUTONG_MQTT: '缺 YUTONG_MQTT' }; type DashboardSnapshotRow = { section: string; item: string; value: string; detail: string; }; type FocusVehicleService = { label: string; lookupKey: string; protocol?: string; reason: string; statusLabel: string; statusColor: 'green' | 'orange' | 'red' | 'grey' | 'blue'; realtimeEvidence: string; historyEvidence: string; alertEvidence: string; statisticEvidence: string; issueType?: string; }; const dashboardSnapshotColumns: CsvColumn[] = [ { title: '模块', value: (row) => row.section }, { title: '指标', value: (row) => row.item }, { title: '值', value: (row) => row.value }, { title: '说明', value: (row) => row.detail } ]; function formatLag(value?: number | null) { return value == null ? '未接入' : value.toLocaleString(); } function formatCount(value?: number | null) { return value == null ? '0' : value.toLocaleString(); } function vehicleServiceOnlineText(serviceSummary: VehicleServiceSummary | null, summary: DashboardSummary | null) { const onlineVehicles = serviceSummary?.onlineVehicles ?? summary?.onlineVehicles; const totalVehicles = serviceSummary?.totalVehicles; if (onlineVehicles == null || totalVehicles == null) { return '未接入'; } return `${onlineVehicles.toLocaleString()} / ${totalVehicles.toLocaleString()} 在线`; } function rowServiceStatus(row: { serviceStatus?: { title: string; severity: string }; onlineSourceCount: number; sourceCount: number }) { if (row.serviceStatus) { return { label: row.serviceStatus.title, color: row.serviceStatus.severity === 'ok' ? 'green' as const : row.serviceStatus.severity === 'error' ? 'red' as const : 'orange' as const }; } if (row.onlineSourceCount <= 0) { return { label: '车辆离线', color: 'red' as const }; } if (row.onlineSourceCount < row.sourceCount) { return { label: '来源不完整', color: 'orange' as const }; } return { label: '服务正常', color: 'green' as const }; } function sourceEvidenceText(row: { onlineSourceCount: number; sourceCount: number }) { return `${row.onlineSourceCount}/${row.sourceCount} 来源在线`; } function hasValidCoordinate(row: VehicleRealtimeRow) { return Number.isFinite(row.longitude) && Number.isFinite(row.latitude) && row.longitude !== 0 && row.latitude !== 0; } function issueEvidenceDate(value?: string) { const match = String(value ?? '').match(/^(\d{4})-(\d{2})-(\d{2})/); return match ? `${match[1]}-${match[2]}-${match[3]}` : ''; } function nextDate(value: string) { const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value.trim()); if (!match) return ''; const date = new Date(Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3]) + 1)); return date.toISOString().slice(0, 10); } function todayDateString() { const date = new Date(); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } function previousDateString(value: string) { const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value.trim()); if (!match) return value; const date = new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]) - 1); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } function offsetDateString(value: string, offsetDays: number) { const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value.trim()); if (!match) return value; const date = new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]) + offsetDays); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } function weekStartDateString(value: string) { const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value.trim()); if (!match) return value; const date = new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3])); const day = date.getDay(); const mondayOffset = day === 0 ? -6 : 1 - day; return offsetDateString(value, mondayOffset); } function dayRangeText(dateFrom?: string, dateTo?: string) { if (!dateFrom && !dateTo) return '未限定时间'; if (!dateFrom || !dateTo) return '单边时间窗'; const start = new Date(`${dateFrom}T00:00:00+08:00`).getTime(); const end = new Date(`${dateTo}T00:00:00+08:00`).getTime(); if (!Number.isFinite(start) || !Number.isFinite(end)) return '时间格式待确认'; const days = Math.max(0, Math.round((end - start) / 86400000)); return days <= 0 ? '同日或倒置时间窗' : `${days} 天窗口`; } function naturalDayRangeText(dateFrom?: string, dateTo?: string) { if (!dateFrom && !dateTo) return '未限定时间'; if (!dateFrom || !dateTo) return '单边时间窗'; const start = new Date(`${dateFrom}T00:00:00+08:00`).getTime(); const end = new Date(`${dateTo}T00:00:00+08:00`).getTime(); if (!Number.isFinite(start) || !Number.isFinite(end)) return '时间格式待确认'; const days = Math.max(0, Math.round((end - start) / 86400000)) + 1; return days <= 0 ? '同日或倒置时间窗' : `${days} 天窗口`; } function priorityIssueVehicleLabel(row: QualityIssueRow) { const identity = row.vin?.trim() && row.vin !== 'unknown' ? row.vin.trim() : row.phone?.trim(); return [row.plate?.trim(), identity].filter(Boolean).join(' / ') || row.sourceEndpoint || '-'; } function priorityIssueEvidenceFilters(row: QualityIssueRow) { const lookup = qualityIssueVehicleLookup(row); const dateFrom = issueEvidenceDate(row.lastSeen); return { keyword: lookup.key, protocol: row.protocol, ...(dateFrom ? { dateFrom, dateTo: nextDate(dateFrom) } : {}) }; } function appURL(hash: string) { return `${window.location.origin}${window.location.pathname}${hash}`; } async function copyText(value: string, label: string) { try { await navigator.clipboard.writeText(value); Toast.success(`已复制${label}`); } catch { Toast.error(`复制${label}失败`); } } function priorityIssueNotificationText(row: QualityIssueRow) { const lookup = qualityIssueVehicleLookup(row); const filters = priorityIssueEvidenceFilters(row); const rawFilters = { ...filters, tab: 'raw', includeFields: 'true' }; const priority = row.severity === 'error' ? 'P0' : 'P1'; return [ `【${priority} 告警通知】${qualityIssueLabel(row.issueType)}`, `车辆:${priorityIssueVehicleLabel(row)}`, `数据来源:${qualityProtocolLabel(row.protocol)}`, `问题:${qualityIssueLabel(row.issueType)}`, `最后时间:${row.lastSeen || '-'}`, `详情:${row.detail || '-'}`, `实时定位:${appURL(buildAppHash({ page: 'realtime', keyword: lookup.key, protocol: row.protocol }))}`, `轨迹证据:${appURL(buildAppHash({ page: 'history', keyword: filters.keyword, protocol: filters.protocol, filters }))}`, `原始记录:${appURL(buildAppHash({ page: 'history-query', keyword: rawFilters.keyword, protocol: rawFilters.protocol, filters: rawFilters }))}`, `车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: lookup.key, protocol: row.protocol }))}`, `告警筛选:${appURL(buildAppHash({ page: 'alert-events', protocol: row.protocol, filters: { issueType: row.issueType } }))}` ].join('\n'); } function focusVehicleFromIssue(row: QualityIssueRow): FocusVehicleService { const lookup = qualityIssueVehicleLookup(row); const filters = priorityIssueEvidenceFilters(row); const label = priorityIssueVehicleLabel(row); return { label, lookupKey: lookup.key, protocol: row.protocol, reason: `${row.severity === 'error' ? 'P0' : 'P1'} ${qualityIssueLabel(row.issueType)}`, statusLabel: row.severity === 'error' ? '优先处置' : '持续跟踪', statusColor: row.severity === 'error' ? 'red' : 'orange', realtimeEvidence: `来源 ${qualityProtocolLabel(row.protocol)} / 最后 ${row.lastSeen || '-'}`, historyEvidence: filters.dateFrom ? `${filters.dateFrom} 至 ${filters.dateTo}` : '待确认时间窗', alertEvidence: row.detail || qualityIssueLabel(row.issueType), statisticEvidence: '里程统计需回溯车辆口径', issueType: row.issueType }; } function focusVehicleFromRealtime(row: VehicleRealtimeRow): FocusVehicleService { const status = rowServiceStatus(row); const label = [row.plate?.trim(), row.vin?.trim()].filter(Boolean).join(' / ') || row.phone || '-'; const location = hasValidCoordinate(row) ? `${row.longitude.toFixed(6)}, ${row.latitude.toFixed(6)}` : '无有效坐标'; return { label, lookupKey: row.vin || row.phone || row.plate, protocol: row.primaryProtocol, reason: row.online ? '最新在线车辆' : '最新车辆', statusLabel: status.label, statusColor: status.color, realtimeEvidence: `${row.onlineSourceCount}/${row.sourceCount} 来源在线 / ${row.lastSeen || '-'}`, historyEvidence: location, alertEvidence: row.onlineSourceCount < row.sourceCount ? '来源不完整,建议检查缺失协议' : '暂无高优先级告警', statisticEvidence: `速度 ${formatCount(row.speedKmh)} km/h / 里程 ${formatCount(row.totalMileageKm)} km` }; } function sourceConsistencyAction(row: VehicleCoverageRow, onFilter: (filters: Record) => void) { const consistency = row.sourceConsistency; if (!consistency) { return 未诊断; } const color = consistency.severity === 'ok' ? 'green' as const : consistency.severity === 'error' ? 'red' as const : 'orange' as const; const label = consistency.title || consistency.status; if ((consistency.missingProtocols ?? []).length > 0) { return ( ); } return {label}; } function defaultTimeMonitorFilters() { const today = todayDateString(); return { dateFrom: previousDateString(today), dateTo: today }; } export function Dashboard({ onOpenVehicle, onOpenQuality, onOpenMap, onOpenRealtime, onOpenVehicles, onOpenHistory, onOpenMileage, customerTimeWindow, onCopyCustomerScope, onSaveCustomerView, focusMode = 'overview', initialTimeMonitorFilters }: { onOpenVehicle: (vin: string, protocol?: string) => void; onOpenQuality: (filters?: Record) => void; onOpenMap: (filters?: Record) => void; onOpenRealtime: (filters?: Record) => void; onOpenVehicles: (filters?: Record) => void; onOpenHistory: (filters?: Record) => void; onOpenMileage: (filters?: Record) => void; customerTimeWindow?: Record; onCopyCustomerScope?: () => void; onSaveCustomerView?: () => void; focusMode?: 'overview' | 'time-window'; initialTimeMonitorFilters?: Record; }) { const [summary, setSummary] = useState(null); const [serviceSummary, setServiceSummary] = useState(null); const [coverage, setCoverage] = useState([]); const [locations, setLocations] = useState([]); const [qualityIssues, setQualityIssues] = useState([]); const [opsHealth, setOpsHealth] = useState(null); const [timeMonitorFilters, setTimeMonitorFilters] = useState>({ ...defaultTimeMonitorFilters(), ...(initialTimeMonitorFilters ?? {}) }); const [loading, setLoading] = useState(true); const [coverageLoading, setCoverageLoading] = useState(false); const [coverageServiceStatusTitle, setCoverageServiceStatusTitle] = useState(''); const [coverageFilters, setCoverageFilters] = useState>({}); const localAMapConfigured = isAMapConfigured(); const amapConfigured = opsHealth?.runtime?.amapWebJsConfigured ?? localAMapConfigured; const amapApiConfigured = opsHealth?.runtime?.amapApiConfigured ?? false; const amapSecurityProxyEnabled = opsHealth?.runtime?.amapSecurityProxyEnabled ?? false; const amapSecurityCodeExposed = opsHealth?.runtime?.amapSecurityCodeExposed ?? false; const loadCoverage = (values?: Record) => { const nextValues = values ?? {}; setCoverageLoading(true); setCoverageFilters(nextValues); const scopeTitle = [ nextValues.serviceStatus ? serviceStatusTitle[nextValues.serviceStatus] ?? nextValues.serviceStatus : '', nextValues.missingProtocol ? missingProtocolTitle[nextValues.missingProtocol] ?? `缺 ${nextValues.missingProtocol}` : '' ].filter(Boolean).join(' / '); setCoverageServiceStatusTitle(scopeTitle); const params = new URLSearchParams({ limit: '8' }); if (nextValues.keyword) params.set('keyword', nextValues.keyword); if (nextValues.coverage) params.set('coverage', nextValues.coverage); if (nextValues.missingProtocol) params.set('missingProtocol', nextValues.missingProtocol); if (nextValues.online) params.set('online', nextValues.online); if (nextValues.bindingStatus) params.set('bindingStatus', nextValues.bindingStatus); if (nextValues.serviceStatus) params.set('serviceStatus', nextValues.serviceStatus); api.vehicleCoverage(params) .then((page) => setCoverage(page.items)) .catch((error: Error) => Toast.error(error.message)) .finally(() => setCoverageLoading(false)); }; useEffect(() => { const tasks = [ api.dashboardSummary().then(setSummary), api.vehicleServiceSummary().then(setServiceSummary), api.vehicleCoverage(new URLSearchParams({ limit: '8' })).then((page) => setCoverage(page.items)), api.vehicleRealtime(new URLSearchParams({ limit: '8' })).then((page) => setLocations(page.items)), api.alertEvents(new URLSearchParams({ limit: '5' })).then((page) => setQualityIssues(page.items)), api.opsHealth().then(setOpsHealth) ]; Promise.allSettled(tasks) .then((results) => { const failed = results.find((result) => result.status === 'rejected'); if (failed?.status === 'rejected') { const reason = failed.reason; Toast.error(reason instanceof Error ? reason.message : '总览数据加载失败'); } }) .finally(() => setLoading(false)); }, []); useEffect(() => { const dateFrom = customerTimeWindow?.dateFrom?.trim(); const dateTo = customerTimeWindow?.dateTo?.trim(); if (!dateFrom && !dateTo) { return; } setTimeMonitorFilters((previous) => { const next = { ...previous, dateFrom: dateFrom ?? '', dateTo: dateTo ?? '' }; if (previous.dateFrom === next.dateFrom && previous.dateTo === next.dateTo) { return previous; } return next; }); }, [customerTimeWindow?.dateFrom, customerTimeWindow?.dateTo]); const serviceActionQueue = useMemo; detail: string }>>(() => { const items: Array<{ label: string; count: number; filters: Record; detail: string }> = []; if ((serviceSummary?.noDataVehicles ?? 0) > 0) { items.push({ label: '确认平台转发', count: serviceSummary?.noDataVehicles ?? 0, filters: { serviceStatus: 'no_data' }, detail: '车辆没有形成任何来源证据,优先确认上游平台是否持续转发。' }); } if ((serviceSummary?.identityRequiredVehicles ?? 0) > 0) { items.push({ label: '维护身份绑定', count: serviceSummary?.identityRequiredVehicles ?? 0, filters: { serviceStatus: 'identity_required' }, detail: '已有数据但无法稳定归并到 VIN,会影响车辆服务聚合。' }); } if ((serviceSummary?.archiveIncompleteVehicles ?? 0) > 0) { items.push({ label: '完善车辆档案', count: serviceSummary?.archiveIncompleteVehicles ?? 0, filters: { archiveStatus: 'incomplete' }, detail: '车辆缺少车牌、手机号或 OEM 等基础档案,影响后续运营查询和治理。' }); } for (const field of serviceSummary?.archiveMissingFields ?? []) { if (field.count <= 0) continue; items.push({ label: `补齐${field.title}`, count: field.count, filters: { archiveMissing: field.field }, detail: `${field.title}会影响车辆档案检索、绑定确认和运营侧筛选。` }); } for (const source of serviceSummary?.missingSources ?? []) { if (source.count <= 0) continue; items.push({ label: `补齐 ${source.protocol} 来源`, count: source.count, filters: { serviceStatus: 'degraded', missingProtocol: source.protocol }, detail: `${source.protocol} 来源缺失会降低跨来源定位、里程和实时判断可信度。` }); } return items; }, [serviceSummary]); const commandOnlineCount = locations.filter((row) => row.online).length; const commandLocatedCount = locations.filter(hasValidCoordinate).length; const commandDegradedCount = locations.filter((row) => row.onlineSourceCount <= 0 || row.onlineSourceCount < row.sourceCount).length; const kpis: Array<{ label: string; value: string; filters: Record }> = [ { label: '总车辆', value: formatCount(serviceSummary?.totalVehicles), filters: {} }, { label: '在线车辆', value: formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles), filters: { online: 'online' } }, { label: '今日活跃', value: formatCount(summary?.activeToday), filters: { online: 'online' } }, { label: '有效定位', value: commandLocatedCount.toLocaleString(), filters: { online: 'online' } }, { label: '告警车辆', value: formatCount(summary?.issueVehicles), filters: { serviceStatus: 'degraded' } }, { label: '今日数据', value: formatCount(summary?.frameToday), filters: {} }, { label: '档案不完整', value: formatCount(serviceSummary?.archiveIncompleteVehicles), filters: { archiveStatus: 'incomplete' } } ]; const highPriorityIssue = qualityIssues.find((item) => item.severity === 'error') ?? qualityIssues[0]; const highPriorityLookup = highPriorityIssue ? qualityIssueVehicleLookup(highPriorityIssue) : undefined; const highPriorityEvidenceFilters = highPriorityIssue ? priorityIssueEvidenceFilters(highPriorityIssue) : undefined; const focusVehicle = highPriorityIssue ? focusVehicleFromIssue(highPriorityIssue) : locations[0] ? focusVehicleFromRealtime(locations[0]) : undefined; const unhealthyLinkCount = (summary?.linkHealth ?? []).filter((item) => item.status !== 'ok').length; const commandMapPoints: VehicleMapPoint[] = locations.map((row, index) => ({ id: row.vin || `${row.primaryProtocol || 'source'}-${index}`, label: row.plate || row.vin || 'unknown', longitude: row.longitude, latitude: row.latitude, online: row.online, title: `${row.plate || row.vin || '-'} ${row.primaryProtocol || ''} ${row.lastSeen || ''}` })); const customerHeroActions = [ { title: '车辆地图', value: `${commandLocatedCount.toLocaleString()} 辆有定位`, detail: '按车查看实时位置、在线状态、速度和最新上报时间。', action: '进入地图', onClick: () => onOpenMap({ online: 'online' }) }, { title: '轨迹回放', value: `${formatCount(summary?.activeToday)} 今日活跃`, detail: '选择车辆和时间范围,回放历史路线并核对断点。', action: '回放轨迹', onClick: () => onOpenHistory() }, { title: '里程统计', value: `${formatCount(serviceSummary?.totalVehicles)} 辆可统计`, detail: '按自定义时间查询区间里程、日里程和异常记录。', action: '查看统计', onClick: () => onOpenMileage({}) }, { title: '历史数据', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '按车辆、时间和字段裁剪查询历史位置与原始记录。', action: '查询导出', onClick: () => onOpenHistory({ tab: 'raw', includeFields: 'true' }) } ]; const customerJourneySteps = [ { step: '01', title: '定位车辆', detail: '先在地图上确认车辆是否在线、坐标是否可信。', action: '车辆地图', onClick: () => onOpenMap({ online: 'online' }) }, { step: '02', title: '查看状态', detail: '进入实时监控查看速度、SOC、里程和最新上报。', action: '实时监控', onClick: () => onOpenRealtime({ online: 'online' }) }, { step: '03', title: '复盘轨迹', detail: '按自定义时间窗回放位置、速度和里程断点。', action: '轨迹回放', onClick: () => onOpenHistory() }, { step: '04', title: '里程统计', detail: '用同一时间窗核对区间里程和每日统计。', action: '里程统计', onClick: () => onOpenMileage({}) }, { step: '05', title: '查询导出', detail: '导出历史位置、原始记录、字段明细和告警证据。', action: '历史数据', onClick: () => openTimeMonitorRaw() } ]; const customerHealthItems = [ { label: '在线车辆', value: formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles), detail: vehicleServiceOnlineText(serviceSummary, summary), color: 'green' as const, onClick: () => onOpenVehicles({ online: 'online' }) }, { label: '有效定位', value: commandLocatedCount.toLocaleString(), detail: `当前抽样 ${locations.length.toLocaleString()} 辆,定位可用于地图和回放。`, color: commandLocatedCount > 0 ? 'blue' as const : 'orange' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '需要关注', value: formatCount(summary?.issueVehicles), detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警。', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality() }, { label: '时间范围监控', value: formatCount(summary?.activeToday), detail: '支持按任意时间窗查询轨迹、历史数据、里程和导出。', color: 'blue' as const, onClick: () => onOpenHistory() } ]; const taskTimeMonitorSummary = (() => { const vehicle = String(timeMonitorFilters.keyword ?? '').trim() || '全部车辆'; const source = String(timeMonitorFilters.protocol ?? '').trim() || '全部数据通道'; const dateFrom = String(timeMonitorFilters.dateFrom ?? '').trim(); const dateTo = String(timeMonitorFilters.dateTo ?? '').trim(); const range = dateFrom || dateTo ? `${dateFrom || '-'} 至 ${dateTo || '-'}` : '全部时间'; return `${vehicle} / ${source} / ${range}`; })(); const customerTaskBoard = [ { title: '先看全域在线', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: `地图有效定位 ${commandLocatedCount.toLocaleString()} 辆,优先确认车辆是否仍在上报。`, color: 'green' as const, primaryAction: '打开实时地图', secondaryAction: '查看在线车辆', onPrimary: () => onOpenMap({ online: 'online' }), onSecondary: () => onOpenRealtime({ online: 'online' }) }, { title: '再看重点车辆', value: focusVehicle?.label ?? '暂无重点车辆', detail: focusVehicle ? `${focusVehicle.reason},${focusVehicle.realtimeEvidence}` : '当前没有高优先级车辆,保持日常巡检。', color: focusVehicle?.statusColor ?? 'green' as const, primaryAction: '车辆服务', secondaryAction: '复制处置卡', onPrimary: () => focusVehicle?.lookupKey && onOpenVehicle(focusVehicle.lookupKey, focusVehicle.protocol), onSecondary: () => copyFocusVehicleService(), disabled: !focusVehicle?.lookupKey }, { title: '按时间窗复盘', value: taskTimeMonitorSummary, detail: '同一时间窗贯穿轨迹、统计、原始记录和告警,不需要跨页面重复输入。', color: 'blue' as const, primaryAction: '轨迹回放', secondaryAction: '里程统计', onPrimary: () => openTimeMonitorHistory(), onSecondary: () => openTimeMonitorMileage() }, { title: '导出证据数据', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '面向 BI、客户复盘和异常定位,按车辆、时间、字段裁剪导出。', color: 'blue' as const, primaryAction: '历史导出', secondaryAction: '导出概览', onPrimary: () => openTimeMonitorRaw(), onSecondary: () => exportDashboardSnapshot() }, { title: '闭环告警通知', value: `${formatCount(summary?.issueVehicles)} 告警车辆`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警。', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, primaryAction: '告警事件', secondaryAction: '复制交接', onPrimary: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}), onSecondary: () => copyOperationsHandoff() } ]; const capabilities = [ { title: '实时地图', status: `在线态势 ${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)}`, color: 'green' as const, description: '以高德地图为主视角查看车辆在线分布、定位有效性、来源一致性和地图接入状态。', action: '打开地图', onClick: () => onOpenMap({ online: 'online' }) }, { title: '实时监控', status: `在线 ${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)}`, color: 'green' as const, description: '按车辆聚合最新位置、在线状态和多来源实时字段,支持实时地图查看。', action: '查看在线车辆', onClick: () => onOpenRealtime({ online: 'online' }) }, { title: '轨迹回放', status: `有效定位 ${formatCount(commandLocatedCount)}`, color: commandLocatedCount > 0 ? 'blue' as const : 'grey' as const, description: '围绕车辆回放历史位置轨迹,结合高德线路和原始记录定位异常。', action: '打开轨迹', onClick: () => onOpenHistory() }, { title: '历史数据查询', status: `今日帧 ${formatCount(summary?.frameToday)}`, color: 'blue' as const, description: '查询位置历史和原始记录字段,为车辆问题复盘提供依据。', action: '查询历史', onClick: () => onOpenHistory({ tab: 'raw' }) }, { title: '告警事件触发与通知', status: `告警 ${formatCount(summary?.issueVehicles)}`, color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, description: '围绕断链、无来源、VIN 缺失、字段缺失形成告警和通知闭环。', action: '查看告警', onClick: () => onOpenQuality() }, { title: '里程统计', status: `统计车辆 ${formatCount(serviceSummary?.totalVehicles)}`, color: 'green' as const, description: '提供里程等运营里程统计,保证区间总值与每日里程口径闭合。', action: '查看统计', onClick: () => onOpenMileage() } ]; const vehicleServicePrinciples = [ { title: '一车一档', value: formatCount(serviceSummary?.totalVehicles), detail: '以 VIN 为主对象沉淀车牌、手机号、OEM、绑定状态和来源覆盖。' }, { title: '一车一实时', value: formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles), detail: '实时状态合并位置、在线、速度、SOC、里程和来源新鲜度。' }, { title: '一车一轨迹', value: formatCount(commandLocatedCount), detail: '轨迹回放围绕车辆展开,协议来源只作为证据过滤条件。' }, { title: '一车一统计', value: formatCount(serviceSummary?.totalVehicles), detail: '统计指标按车辆口径闭合,再回溯到来源证据。' } ]; const workflowSteps = [ { title: '接入巡检', value: unhealthyLinkCount > 0 ? `${unhealthyLinkCount.toLocaleString()} 项关注` : '链路正常', color: unhealthyLinkCount > 0 ? 'orange' as const : 'green' as const, detail: '检查平台转发、消息队列、缓存和存储等关键链路。', action: '查看告警', onClick: () => onOpenQuality() }, { title: '实时态势', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, color: 'green' as const, detail: '确认车辆是否在线、是否有有效坐标以及来源是否完整。', action: '实时监控', onClick: () => onOpenRealtime({ online: 'online' }) }, { title: '轨迹复盘', value: `${formatCount(summary?.activeToday)} 活跃`, color: 'blue' as const, detail: '按车辆进入历史轨迹,复盘位置、速度、里程和断点。', action: '轨迹回放', onClick: () => onOpenHistory() }, { title: '历史证据', value: `${formatCount(summary?.frameToday)} 帧`, color: 'blue' as const, detail: '查询原始记录和字段明细,形成可追溯的数据依据。', action: '历史查询', onClick: () => onOpenHistory({ tab: 'raw' }) }, { title: '告警事件', value: `${formatCount(summary?.issueVehicles)} 车辆`, color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, detail: '把断链、缺 VIN、字段缺失等问题进入通知和处置队列。', action: '告警事件', onClick: () => onOpenQuality() }, { title: '里程复核', value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, color: 'green' as const, detail: '核对里程口径,保证区间统计和每日统计闭合。', action: '里程统计', onClick: () => onOpenMileage() } ]; const mapReadiness = [ { title: '高德 Web JS', value: amapConfigured ? '已配置' : '待配置', color: amapConfigured ? 'green' as const : 'orange' as const, detail: amapConfigured ? '实时监控和轨迹回放可加载高德底图。' : '缺少 Web JS Key 时降级为坐标预览。' }, { title: '安全代理', value: amapSecurityProxyEnabled ? '已启用' : '未启用', color: amapSecurityProxyEnabled ? 'green' as const : 'orange' as const, detail: amapSecurityProxyEnabled ? '安全码由服务端代理追加,不下发到浏览器。' : '生产环境建议启用 /_AMapService。' }, { title: '服务端 API', value: amapApiConfigured ? '已配置' : '待配置', color: amapApiConfigured ? 'green' as const : 'orange' as const, detail: amapApiConfigured ? '逆地理、路线、围栏等服务端地图能力可扩展。' : '后端地图服务会降级。' }, { title: '安全码暴露', value: amapSecurityCodeExposed ? '需处理' : '未暴露', color: amapSecurityCodeExposed ? 'red' as const : 'green' as const, detail: amapSecurityCodeExposed ? '浏览器端可见安全码,需要切换到安全代理。' : '符合生产密钥收敛要求。' } ]; const mapWorkItems = [ { title: '实时监控', value: `${commandLocatedCount.toLocaleString()} 个有效坐标`, detail: '在线车辆进入地图态势,点击车辆后继续查看车辆服务和实时字段。', action: '实时地图', onClick: () => onOpenMap({ online: 'online' }) }, { title: '轨迹回放', value: `${formatCount(summary?.activeToday)} 今日活跃`, detail: '按车辆和时间窗回放历史位置,支持打开高德线路和原始记录。', action: '轨迹回放', onClick: () => onOpenHistory() }, { title: '历史证据', value: `${formatCount(summary?.frameToday)} 今日帧`, detail: '地图点位异常时直接回查位置历史、解析字段和原始帧。', action: '历史查询', onClick: () => onOpenHistory({ tab: 'raw', includeFields: 'true' }) }, { title: '告警通知', value: `${formatCount(summary?.issueVehicles)} 告警车辆`, detail: '断链、无来源、坐标异常进入告警队列并触发通知闭环。', action: '告警事件', onClick: () => onOpenQuality() } ]; const operationWorkbench = [ { title: '实时监控', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, meta: `有效定位 ${commandLocatedCount.toLocaleString()}`, color: 'green' as const, detail: '面向值班人员确认车辆是否在线、坐标是否有效、来源是否完整。', actions: [ { label: '打开实时地图', onClick: () => onOpenMap({ online: 'online' }) }, { label: '查看在线车辆', onClick: () => onOpenRealtime({ online: 'online' }) } ] }, { title: '轨迹回放', value: `${formatCount(summary?.activeToday)} 今日活跃`, meta: '高德轨迹证据', color: 'blue' as const, detail: '按车辆回看位置、速度、里程和断点,用于定位异常复盘。', actions: [ { label: '打开轨迹回放', onClick: () => onOpenHistory() }, { label: '查历史明细', onClick: () => onOpenHistory({ tab: 'raw', includeFields: 'true' }) } ] }, { title: '历史数据查询', value: `${formatCount(summary?.frameToday)} 今日帧`, meta: '字段裁剪与导出', color: 'blue' as const, detail: '查询位置历史、历史明细和字段明细,为车辆服务提供可追溯依据。', actions: [ { label: '查询历史数据', onClick: () => onOpenHistory({ tab: 'location' }) }, { label: '查询解析字段', onClick: () => onOpenHistory({ tab: 'raw', includeFields: 'true' }) } ] }, { title: '告警事件与通知', value: `${formatCount(summary?.issueVehicles)} 告警车辆`, meta: highPriorityIssue ? `${highPriorityIssue.severity === 'error' ? 'P0' : 'P1'} ${qualityIssueLabel(highPriorityIssue.issueType)}` : '暂无高优先级', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, detail: '把断链、无来源、VIN 缺失、字段缺失转成可通知、可闭环的事件。', actions: [ { label: '查看告警事件', onClick: () => onOpenQuality() }, { label: '处理最高优先级', onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ] }, { title: '里程统计', value: `${formatCount(serviceSummary?.totalVehicles)} 车辆口径`, meta: '区间闭合复核', color: 'green' as const, detail: '统计指标先按车辆口径闭合,再回溯轨迹和原始记录。', actions: [ { label: '打开里程统计', onClick: () => onOpenMileage() }, { label: '查看车辆中心', onClick: () => onOpenVehicles({}) } ] } ]; const timeMonitorScope = (values = timeMonitorFilters) => { const normalized: Record = {}; for (const key of ['keyword', 'protocol', 'dateFrom', 'dateTo'] as const) { const value = String(values[key] ?? '').trim(); if (value) { normalized[key] = value; } } return normalized; }; const openTimeMonitorHistory = () => { onOpenHistory(timeMonitorScope()); }; const openTimeMonitorMileage = () => { onOpenMileage(timeMonitorScope()); }; const openTimeMonitorRaw = () => { onOpenHistory({ ...timeMonitorScope(), tab: 'raw', includeFields: 'true' }); }; const openTimeMonitorAlerts = () => { const scope = timeMonitorScope(); onOpenQuality({ ...(scope.keyword ? { keyword: scope.keyword } : {}), ...(scope.protocol ? { protocol: scope.protocol } : {}) }); }; const timeMonitorSummary = (() => { const scope = timeMonitorScope(); const vehicle = scope.keyword || '全部车辆'; const source = scope.protocol || '全部数据通道'; const range = scope.dateFrom || scope.dateTo ? `${scope.dateFrom || '-'} 至 ${scope.dateTo || '-'}` : '全部时间'; return `${vehicle} / ${source} / ${range}`; })(); const timeMonitorReviewItems = [ { label: '车辆范围', value: timeMonitorScope().keyword || '全部车辆', detail: timeMonitorScope().protocol || '全部数据通道', color: timeMonitorScope().keyword ? 'green' as const : 'blue' as const }, { label: '复盘时间', value: timeMonitorScope().dateFrom || timeMonitorScope().dateTo ? `${timeMonitorScope().dateFrom || '-'} 至 ${timeMonitorScope().dateTo || '-'}` : '全部时间', detail: '同步带入轨迹、统计、历史证据和告警', color: 'blue' as const }, { label: '轨迹证据', value: `${formatCount(summary?.activeToday)} 活跃`, detail: '位置、速度、里程断点同窗复核', color: 'blue' as const }, { label: '统计证据', value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, detail: '区间里程、日统计和异常点闭合', color: 'green' as const }, { label: '风险事件', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? qualityIssueLabel(highPriorityIssue.issueType) : '暂无高优先级', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const } ]; const timeMonitorScopeValue = timeMonitorScope(); const customerServiceScopeLabel = `${timeMonitorScopeValue.keyword || '全部车辆'} / ${timeMonitorScopeValue.protocol || '全部数据通道'} / ${timeMonitorScopeValue.dateFrom || '-'} 至 ${timeMonitorScopeValue.dateTo || '-'}`; const usesCustomerTimeWindow = Boolean( (customerTimeWindow?.dateFrom || customerTimeWindow?.dateTo) && customerTimeWindow?.dateFrom === timeMonitorScopeValue.dateFrom && customerTimeWindow?.dateTo === timeMonitorScopeValue.dateTo ); const timeMonitorWindowLabel = usesCustomerTimeWindow ? naturalDayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo) : dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo); const timeMonitorChecklist = [ { label: '范围可解释', value: timeMonitorScopeValue.keyword ? '单车聚焦' : '全域巡检', detail: `${timeMonitorScopeValue.protocol || '全部数据通道'} / ${timeMonitorWindowLabel}`, color: timeMonitorScopeValue.dateFrom && timeMonitorScopeValue.dateTo ? 'green' as const : 'orange' as const }, { label: '轨迹可复盘', value: `${formatCount(summary?.activeToday)} 活跃车辆`, detail: '可进入轨迹页核对位置、速度、里程断点和停驶片段。', color: (summary?.activeToday ?? 0) > 0 ? 'green' as const : 'orange' as const }, { label: '数据可导出', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '历史查询默认带原始记录与解析字段,支持按字段缩小导出体积。', color: (summary?.frameToday ?? 0) > 0 ? 'blue' as const : 'orange' as const }, { label: '异常可闭环', value: `${formatCount(summary?.issueVehicles)} 告警车辆`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '当前没有高优先级告警。', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const } ]; const timeMonitorHasRange = Boolean(timeMonitorScopeValue.dateFrom && timeMonitorScopeValue.dateTo); const timeMonitorHasTrajectory = (summary?.activeToday ?? 0) > 0; const timeMonitorHasHistory = (summary?.frameToday ?? 0) > 0; const timeMonitorHasAlerts = (summary?.issueVehicles ?? 0) > 0; const timeMonitorDeliveryStatus = !timeMonitorHasRange ? { label: '待补时间', color: 'orange' as const, detail: '开始和结束时间不完整,交付前先锁定复盘窗口。' } : !timeMonitorHasHistory ? { label: '证据不足', color: 'red' as const, detail: '当前没有历史证据,无法支撑客户复盘或导出。' } : timeMonitorHasAlerts ? { label: '带风险交付', color: 'orange' as const, detail: '存在告警车辆,交付时需要附带告警闭环和原始证据。' } : { label: '可交付', color: 'green' as const, detail: '时间窗、轨迹、历史证据和统计入口已准备好。' }; const timeMonitorDeliveryActions = [ { label: '客户结论', value: timeMonitorDeliveryStatus.label, detail: timeMonitorDeliveryStatus.detail, action: '复制复盘包', color: timeMonitorDeliveryStatus.color, onClick: () => copyTimeMonitorReviewPackage() }, { label: '证据准备', value: timeMonitorHasTrajectory && timeMonitorHasHistory ? '证据可用' : '需要补证', detail: `轨迹 ${formatCount(summary?.activeToday)} 活跃 / 历史 ${formatCount(summary?.frameToday)} 帧。`, action: timeMonitorHasHistory ? '历史导出' : '查历史', color: timeMonitorHasHistory ? 'blue' as const : 'orange' as const, onClick: openTimeMonitorRaw }, { label: '异常说明', value: timeMonitorHasAlerts ? `${formatCount(summary?.issueVehicles)} 告警` : '无高风险', detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '当前没有需要额外说明的高优先级告警。', action: '告警复盘', color: timeMonitorHasAlerts ? 'orange' as const : 'green' as const, onClick: openTimeMonitorAlerts } ]; const copyTimeMonitorReviewPackage = () => { const scope = timeMonitorScope(); const rawFilters = { ...scope, tab: 'raw', includeFields: 'true' }; const lines = [ '【客户时间窗复盘包】', `范围:${timeMonitorSummary}`, `交付结论:${timeMonitorDeliveryStatus.label};${timeMonitorDeliveryStatus.detail}`, `时间窗判定:${dayRangeText(scope.dateFrom, scope.dateTo)}`, '平台能力:实时地图 / 轨迹回放 / 里程统计 / 历史数据查询 / 告警通知', `车辆范围:${scope.keyword || '全部车辆'}`, `数据通道:${scope.protocol || '全部数据通道'}`, `时间范围:${scope.dateFrom || '-'} 至 ${scope.dateTo || '-'}`, `轨迹证据:今日活跃 ${formatCount(summary?.activeToday)},用于回放位置、速度、里程断点`, `统计证据:车辆口径 ${formatCount(serviceSummary?.totalVehicles)},用于区间里程和日统计闭合`, `历史证据:今日数据 ${formatCount(summary?.frameToday)},用于原始记录与解析字段复核`, `告警事件:${formatCount(summary?.issueVehicles)} 辆车存在告警`, '交付核对:', ...timeMonitorChecklist.map((item, index) => `${index + 1}. ${item.label}:${item.value};${item.detail}`), '下一步动作:', ...timeMonitorDeliveryActions.map((item, index) => `${index + 1}. ${item.label}:${item.value};${item.detail}`), `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`, `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`, `历史数据查询:${appURL(buildAppHash({ page: 'history-query', keyword: scope.keyword, protocol: scope.protocol, filters: rawFilters }))}`, `告警通知:${appURL(buildAppHash({ page: 'alert-events', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`, `实时地图:${appURL(buildAppHash({ page: 'map', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}` ]; copyText(lines.join('\n'), '时间窗复盘包'); }; const timeMonitorWorkbench = [ { label: '轨迹回放', value: `${formatCount(summary?.activeToday)} 活跃`, detail: '查看时间窗内车辆位置、速度、里程和断点。', action: '打开轨迹', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '里程统计', value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, detail: '用同一范围核对区间里程和日统计闭合。', action: '查看统计', color: 'green' as const, onClick: openTimeMonitorMileage }, { label: '历史证据', value: `${formatCount(summary?.frameToday)} 帧`, detail: '按车辆、时间和字段裁剪导出原始记录与解析字段。', action: '导出证据', color: 'blue' as const, onClick: openTimeMonitorRaw }, { label: '告警复盘', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: '查看该车辆或来源在当前范围内的风险事件。', action: '查看告警', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: openTimeMonitorAlerts } ]; const timeWindowServicePathItems = [ { step: '1', label: '锁定范围', value: timeMonitorWindowLabel, detail: timeMonitorScopeValue.keyword ? `单车 ${timeMonitorScopeValue.keyword}` : '先确认车辆或车辆池,再应用同一时间窗。', action: '应用时间窗', color: timeMonitorHasRange ? 'green' as const : 'orange' as const, onClick: () => setTimeMonitorFilters(timeMonitorScopeValue) }, { step: '2', label: '回放轨迹', value: `${formatCount(summary?.activeToday)} 活跃`, detail: '查看时间窗内位置、速度、停驶和里程断点。', action: '轨迹回放', color: timeMonitorHasTrajectory ? 'blue' as const : 'orange' as const, onClick: openTimeMonitorHistory }, { step: '3', label: '核对里程', value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, detail: '用同一范围核对区间里程、日统计和 BI 口径。', action: '里程统计', color: 'green' as const, onClick: openTimeMonitorMileage }, { step: '4', label: '导出证据', value: `${formatCount(summary?.frameToday)} 帧`, detail: '导出轨迹、原始记录和解析字段,形成客户证据包。', action: '数据导出', color: timeMonitorHasHistory ? 'blue' as const : 'orange' as const, onClick: openTimeMonitorRaw }, { step: '5', label: '告警说明', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '没有高优先级告警时,交付时说明当前无异常。', action: '告警通知', color: timeMonitorHasAlerts ? 'orange' as const : 'green' as const, onClick: openTimeMonitorAlerts } ]; const timeWindowNextPrimary = !timeMonitorHasRange ? '锁定范围' : timeMonitorHasAlerts ? '告警复盘' : timeMonitorHasHistory ? '历史导出' : timeMonitorHasTrajectory ? '轨迹回放' : '应用时间窗'; const runTimeWindowPrimaryAction = () => { if (!timeMonitorHasRange) { setTimeMonitorFilters(timeMonitorScopeValue); return; } if (timeMonitorHasAlerts) { openTimeMonitorAlerts(); return; } if (timeMonitorHasHistory) { openTimeMonitorRaw(); return; } if (timeMonitorHasTrajectory) { openTimeMonitorHistory(); return; } setTimeMonitorFilters(timeMonitorScopeValue); }; const timeWindowNextItems = [ { label: '首要动作', value: timeWindowNextPrimary, detail: timeMonitorHasAlerts ? '存在告警车辆,先给客户解释风险与处置闭环。' : timeMonitorHasHistory ? '历史证据可用,优先导出原始记录与解析字段。' : '先锁定车辆和时间范围。', color: timeMonitorHasAlerts ? 'orange' as const : timeMonitorHasHistory ? 'blue' as const : 'orange' as const, onClick: runTimeWindowPrimaryAction }, { label: '交付状态', value: timeMonitorDeliveryStatus.label, detail: timeMonitorDeliveryStatus.detail, color: timeMonitorDeliveryStatus.color, onClick: () => copyTimeMonitorReviewPackage() }, { label: '证据状态', value: `${formatCount(summary?.frameToday)} 帧`, detail: `${formatCount(summary?.activeToday)} 活跃车辆,可核对轨迹与历史明细。`, color: timeMonitorHasHistory ? 'blue' as const : 'orange' as const, onClick: openTimeMonitorRaw }, { label: '服务范围', value: timeMonitorScopeValue.keyword ? '单车聚焦' : '全域巡检', detail: `${timeMonitorScopeValue.keyword || '全部车辆'} / ${timeMonitorScopeValue.protocol || '全部数据通道'} / ${timeMonitorWindowLabel}`, color: timeMonitorScopeValue.keyword ? 'green' as const : 'blue' as const, onClick: () => setTimeMonitorFilters(timeMonitorScopeValue) } ]; const timeWindowNextActions = [ { label: '处理告警', action: '告警复盘', color: timeMonitorHasAlerts ? 'orange' as const : 'green' as const, disabled: false, onClick: openTimeMonitorAlerts }, { label: '导出证据', action: '历史导出', color: timeMonitorHasHistory ? 'blue' as const : 'orange' as const, disabled: false, onClick: openTimeMonitorRaw }, { label: '核对里程', action: '里程统计', color: 'green' as const, disabled: false, onClick: openTimeMonitorMileage }, { label: '复制复盘', action: '交付包', color: timeMonitorDeliveryStatus.color, disabled: false, onClick: () => copyTimeMonitorReviewPackage() } ]; const copyTimeWindowSlaJob = () => { const scope = timeMonitorScope(); const rawFilters = { ...scope, tab: 'raw', includeFields: 'true' }; const lines = [ '【客户时间窗复盘作业单】', `作业范围:${timeMonitorSummary}`, `交付SLA:${timeMonitorWindowLabel}内完成轨迹复盘、统计核对、历史导出和告警说明`, `交付状态:${timeMonitorDeliveryStatus.label};${timeMonitorDeliveryStatus.detail}`, '交付物:轨迹回放链接 / 里程统计链接 / 历史导出链接 / 告警复盘链接', `升级条件:${formatCount(summary?.issueVehicles)} 告警车辆需要先进入告警复盘`, `责任动作:${timeMonitorHasAlerts ? '先处理告警,再交付证据' : '先完成客户复盘,再按需导出证据'}`, `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`, `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`, `历史导出:${appURL(buildAppHash({ page: 'history-query', keyword: scope.keyword, protocol: scope.protocol, filters: rawFilters }))}`, `告警复盘:${appURL(buildAppHash({ page: 'alert-events', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}` ]; copyText(lines.join('\n'), '时间窗作业单'); }; const timeWindowSlaItems = [ { label: '责任动作', value: '客户复盘', detail: timeMonitorHasAlerts ? '存在告警车辆,先完成告警说明和通知闭环。' : '围绕同一车辆和时间窗完成客户复盘。', action: '复制作业', color: timeMonitorHasAlerts ? 'orange' as const : 'blue' as const, onClick: copyTimeWindowSlaJob }, { label: '交付时限', value: timeMonitorWindowLabel, detail: '在该时间窗内完成轨迹、统计、历史证据和异常说明。', action: '轨迹复盘', color: timeMonitorHasRange ? 'green' as const : 'orange' as const, onClick: openTimeMonitorHistory }, { label: '交付物', value: '轨迹/统计/导出/告警', detail: '交付轨迹回放、里程统计、历史导出和告警复盘四个入口。', action: '导出证据', color: timeMonitorHasHistory ? 'blue' as const : 'orange' as const, onClick: openTimeMonitorRaw }, { label: '升级条件', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: timeMonitorHasAlerts ? '存在告警车辆,交付前先进入告警复盘。' : '无高风险时按常规复盘交付。', action: '告警复盘', color: timeMonitorHasAlerts ? 'orange' as const : 'green' as const, onClick: openTimeMonitorAlerts } ]; const dedicatedTimeMonitorActions = [ { label: '轨迹回放', value: timeMonitorWindowLabel, detail: '按同一辆车和时间窗回放位置、速度、停留和里程断点。', color: timeMonitorHasTrajectory ? 'blue' as const : 'orange' as const, onClick: openTimeMonitorHistory }, { label: '里程统计', value: timeMonitorWindowLabel, detail: '用同一时间窗核对区间里程、日报闭合和异常点。', color: 'green' as const, onClick: openTimeMonitorMileage }, { label: '历史导出', value: `${formatCount(summary?.frameToday)} 帧`, detail: '导出历史位置、原始记录和字段证据,形成客户可复核数据包。', color: timeMonitorHasHistory ? 'blue' as const : 'orange' as const, onClick: openTimeMonitorRaw }, { label: '告警复盘', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: '用同一时间窗解释异常车辆、通知策略和恢复验收。', color: timeMonitorHasAlerts ? 'orange' as const : 'green' as const, onClick: openTimeMonitorAlerts } ]; const dataFlowStages = [ { stage: '01', title: '车辆接入', owner: '接入网关', evidence: `32960 / 808 / MQTT,连接 ${formatCount(opsHealth?.activeConnections)}`, detail: '只接收真实实时数据帧和必要鉴权注册帧,接入来源最终归并到车辆服务。', action: '运维质量', onClick: () => onOpenQuality() }, { stage: '02', title: '统一解析', owner: '字段映射', evidence: `今日帧 ${formatCount(summary?.frameToday)},Kafka Lag ${formatLag(summary?.kafkaLag)}`, detail: '一次解析生成扁平字段、原始证据和车辆身份关联,避免三处重复解析。', action: '历史字段', onClick: () => onOpenHistory({ tab: 'raw', includeFields: 'true' }) }, { stage: '03', title: '实时投影', owner: 'Redis KV', evidence: `在线 Key ${formatCount(opsHealth?.redisOnlineKeys)},在线车辆 ${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)}`, detail: '快速写入车辆最新状态、在线 TTL 和全量协议字段,支撑 0-1 秒监控。', action: '实时监控', onClick: () => onOpenRealtime({ online: 'online' }) }, { stage: '04', title: '车辆归并', owner: 'Vehicle Service', evidence: `多源 ${formatCount(serviceSummary?.multiSourceVehicles)},单源 ${formatCount(serviceSummary?.singleSourceVehicles)}`, detail: '以 VIN 合并来源证据,车牌、手机号和 OEM 只是车辆服务的检索键。', action: '车辆中心', onClick: () => onOpenVehicles({}) }, { stage: '05', title: '历史证据', owner: 'TDengine / MySQL', evidence: `轨迹 ${formatCount(summary?.activeToday)} 活跃,原始记录 ${formatCount(summary?.frameToday)} 帧`, detail: '位置、原始记录和解析字段可分页查询,并能回跳轨迹、车辆服务和告警。', action: '轨迹回放', onClick: () => onOpenHistory() }, { stage: '06', title: '运营闭环', owner: '告警 / 统计', evidence: `告警 ${formatCount(summary?.issueVehicles)},统计车辆 ${formatCount(serviceSummary?.totalVehicles)}`, detail: '断链、缺字段、里程异常和离线时长进入通知、统计和复核工作流。', action: '里程统计', onClick: () => onOpenMileage() } ]; const scenarioNavigation = [ { title: '实时监控', objective: '确认车辆是否在线、位置是否可信、必要接入来源是否齐全。', evidence: `Redis 在线态 / 最新定位 / 有效坐标 ${commandLocatedCount.toLocaleString()}`, sla: '目标 0-1 秒内进入实时视图', primaryAction: '实时监控', secondaryAction: '地图态势', onPrimary: () => onOpenRealtime({ online: 'online' }), onSecondary: () => onOpenMap({ online: 'online' }) }, { title: '轨迹回放', objective: '按车辆复盘位置、速度、里程和断点,定位平台转发或车辆异常。', evidence: `高德轨迹底座 / 今日活跃 ${formatCount(summary?.activeToday)}`, sla: '支持按车辆和时间窗快速回放', primaryAction: '轨迹回放', secondaryAction: '原始记录', onPrimary: () => onOpenHistory(), onSecondary: () => onOpenHistory({ tab: 'raw', includeFields: 'true' }) }, { title: '历史数据查询', objective: '围绕车辆查询位置、原始记录和字段明细,给 BI、运维和业务复盘提供依据。', evidence: `今日数据 ${formatCount(summary?.frameToday)} / 支持字段裁剪与导出`, sla: '优先返回必要字段,避免大 JSON 拖慢查询', primaryAction: '历史查询', secondaryAction: '字段证据', onPrimary: () => onOpenHistory({ tab: 'location' }), onSecondary: () => onOpenHistory({ tab: 'raw', includeFields: 'true' }) }, { title: '告警事件触发和通知', objective: '把断链、无来源、VIN 缺失、字段缺失转换为可通知、可闭环事件。', evidence: `告警车辆 ${formatCount(summary?.issueVehicles)} / 最高优先级 ${highPriorityIssue ? qualityIssueLabel(highPriorityIssue.issueType) : '暂无'}`, sla: 'P0 进入通知队列,超时升级', primaryAction: '告警事件', secondaryAction: '通知规则', onPrimary: () => onOpenQuality(), onSecondary: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) }, { title: '里程统计', objective: '按车辆口径查询里程等指标,保证区间统计和日统计可闭合。', evidence: `车辆口径 ${formatCount(serviceSummary?.totalVehicles)} / 区间统计可追溯轨迹证据`, sla: '统计值必须能追溯轨迹和原始记录', primaryAction: '里程统计', secondaryAction: '车辆中心', onPrimary: () => onOpenMileage(), onSecondary: () => onOpenVehicles({}) } ]; const copyOperationsHandoff = () => { const unhealthyLinks = (summary?.linkHealth ?? []).filter((item) => item.status !== 'ok'); const priorityAction = serviceActionQueue[0]; const highPriorityLookupKey = highPriorityLookup?.key; const highPriorityFilters = highPriorityEvidenceFilters; const lines = [ '【车辆服务中台客户交付摘要】', `在线车辆:${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} / ${formatCount(serviceSummary?.totalVehicles)}`, `今日活跃:${formatCount(summary?.activeToday)}`, `今日帧量:${formatCount(summary?.frameToday)}`, `实时地图有效定位:${commandLocatedCount.toLocaleString()}`, `告警车辆:${formatCount(summary?.issueVehicles)}`, `高德地图:Web JS ${amapConfigured ? '已配置' : '待配置'} / 服务端 API ${amapApiConfigured ? '已配置' : '待配置'} / 安全代理 ${amapSecurityProxyEnabled ? '已启用' : '未启用'}`, `优先动作:${priorityAction ? `${priorityAction.label} ${priorityAction.count.toLocaleString()}辆 - ${priorityAction.detail}` : '暂无待办'}`, highPriorityIssue ? `最高告警:${highPriorityIssue.severity === 'error' ? 'P0' : 'P1'} ${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)} / ${highPriorityIssue.lastSeen || '-'}` : '最高告警:暂无', highPriorityIssue ? `告警详情:${highPriorityIssue.detail || '-'}` : '', `实时监控:${appURL(buildAppHash({ page: 'realtime', filters: { online: 'online' } }))}`, `实时地图:${appURL(buildAppHash({ page: 'map', filters: { online: 'online' } }))}`, `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: highPriorityFilters?.keyword, protocol: highPriorityFilters?.protocol, filters: highPriorityFilters }))}`, `原始记录:${appURL(buildAppHash({ page: 'history-query', keyword: highPriorityFilters?.keyword, protocol: highPriorityFilters?.protocol, filters: { ...highPriorityFilters, tab: 'raw', includeFields: 'true' } }))}`, `告警事件:${appURL(buildAppHash({ page: 'alert-events', filters: highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {} }))}`, `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: highPriorityLookupKey, protocol: highPriorityIssue?.protocol }))}`, `车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: highPriorityLookupKey, protocol: highPriorityIssue?.protocol }))}` ].filter(Boolean); copyText(lines.join('\n'), '客户交付摘要'); }; const copyScenarioBlueprint = () => { const lines = [ '【车辆服务中台功能蓝图】', '定位:32960 / 808 / 宇通 MQTT 都只是车辆接入来源,最终围绕一辆车提供实时、轨迹、历史、告警、统计能力。', `高德地图:Web JS ${amapConfigured ? '已配置' : '待配置'};服务端 API ${amapApiConfigured ? '已配置' : '待配置'};安全代理 ${amapSecurityProxyEnabled ? '已启用' : '未启用'};安全码${amapSecurityCodeExposed ? '已暴露' : '未暴露'}`, `车辆规模:${formatCount(serviceSummary?.totalVehicles)};在线:${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)};告警:${formatCount(summary?.issueVehicles)}`, '', ...scenarioNavigation.map((item, index) => [ `${index + 1}. ${item.title}`, ` 目标:${item.objective}`, ` 证据:${item.evidence}`, ` SLA:${item.sla}` ].join('\n')), '', `入口:${appURL(buildAppHash({ page: 'dashboard' }))}` ]; copyText(lines.join('\n'), '功能蓝图'); }; const copyDataFlowBlueprint = () => { const lines = [ '【车辆服务中台数据流转图】', '原则:32960 / 808 / 宇通 MQTT 是车辆接入来源,最终都归并为同一辆车的车辆服务。', `运行态:连接 ${formatCount(opsHealth?.activeConnections)};在线 Key ${formatCount(opsHealth?.redisOnlineKeys)};Kafka Lag ${formatLag(summary?.kafkaLag)};今日帧 ${formatCount(summary?.frameToday)}`, '', ...dataFlowStages.map((item) => [ `${item.stage}. ${item.title} / ${item.owner}`, ` 证据:${item.evidence}`, ` 说明:${item.detail}` ].join('\n')), '', `实时监控:${appURL(buildAppHash({ page: 'realtime', filters: { online: 'online' } }))}`, `车辆中心:${appURL(buildAppHash({ page: 'vehicles' }))}`, `轨迹回放:${appURL(buildAppHash({ page: 'history' }))}`, `历史查询:${appURL(buildAppHash({ page: 'history-query', filters: { tab: 'raw', includeFields: 'true' } }))}`, `告警事件:${appURL(buildAppHash({ page: 'alert-events' }))}`, `里程统计:${appURL(buildAppHash({ page: 'mileage' }))}`, `运维质量:${appURL(buildAppHash({ page: 'ops-quality' }))}` ]; copyText(lines.join('\n'), '数据流转图'); }; const copyFocusVehicleService = () => { if (!focusVehicle) { Toast.warning('当前没有重点车辆服务可复制'); return; } const commonFilters = { keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol ?? '' }; const lines = [ '【重点车辆服务处置卡】', `车辆:${focusVehicle.label}`, `原因:${focusVehicle.reason}`, `服务状态:${focusVehicle.statusLabel}`, `实时证据:${focusVehicle.realtimeEvidence}`, `轨迹证据:${focusVehicle.historyEvidence}`, `告警证据:${focusVehicle.alertEvidence}`, `统计证据:${focusVehicle.statisticEvidence}`, `车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol }))}`, `实时监控:${appURL(buildAppHash({ page: 'realtime', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol }))}`, `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol }))}`, `原始记录:${appURL(buildAppHash({ page: 'history-query', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol, filters: { ...commonFilters, tab: 'raw', includeFields: 'true' } }))}`, `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol }))}`, `告警事件:${appURL(buildAppHash({ page: 'alert-events', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol, filters: focusVehicle.issueType ? { issueType: focusVehicle.issueType } : {} }))}` ]; copyText(lines.join('\n'), '重点车辆服务处置卡'); }; const buildDashboardSnapshotRows = () => { const unhealthyLinks = (summary?.linkHealth ?? []).filter((item) => item.status !== 'ok'); const priorityAction = serviceActionQueue[0]; const rows: DashboardSnapshotRow[] = [ { section: '车辆服务', item: '在线车辆', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} / ${formatCount(serviceSummary?.totalVehicles)}`, detail: '统一车辆服务在线态势' }, { section: '车辆服务', item: '今日活跃', value: formatCount(summary?.activeToday), detail: '当天有有效上报或历史记录的车辆服务对象' }, { section: '实时监控', item: '有效定位', value: commandLocatedCount.toLocaleString(), detail: `当前预览 ${locations.length.toLocaleString()} 条车辆实时数据` }, { section: '实时监控', item: '来源异常', value: commandDegradedCount.toLocaleString(), detail: '当前预览中离线或来源不完整车辆' }, { section: '历史数据', item: '今日帧量', value: formatCount(summary?.frameToday), detail: '历史查询和导出可按车辆、时间、字段裁剪' }, { section: '告警事件', item: '告警车辆', value: formatCount(summary?.issueVehicles), detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无最高优先级告警' }, { section: '地图能力', item: '高德地图', value: amapConfigured ? '已配置' : '待配置', detail: '用于实时监控和轨迹回放地图底座' }, { section: '优先动作', item: priorityAction?.label ?? '暂无待办', value: priorityAction ? priorityAction.count.toLocaleString() : '0', detail: priorityAction?.detail ?? '当前没有必须立即处理的车辆服务事项' } ]; (serviceSummary?.serviceStatuses ?? summary?.serviceStatuses ?? []).forEach((item) => { rows.push({ section: '服务状态', item: item.title || serviceStatusTitle[item.status] || item.status, value: item.count.toLocaleString(), detail: serviceStatusTitle[item.status] || item.status }); }); return rows; }; const exportDashboardSnapshot = () => { const rows = buildDashboardSnapshotRows(); if (rows.length === 0) { Toast.warning('当前没有可导出的驾驶舱摘要'); return; } downloadCsv('dashboard-snapshot.csv', buildCsv(dashboardSnapshotColumns, rows)); Toast.success(`已导出 ${rows.length.toLocaleString()} 条驾驶舱摘要`); }; const commandCenterItems = [ { title: '全域车辆监控', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: `有效定位 ${commandLocatedCount.toLocaleString()} 辆,先从地图确认车辆分布、在线状态和最新位置。`, color: 'green' as const, primaryAction: '打开车辆地图', secondaryAction: '在线车辆', onPrimary: () => onOpenMap({ online: 'online' }), onSecondary: () => onOpenVehicles({ online: 'online' }) }, { title: '异常车辆闭环', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `最高优先级:${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '当前没有高优先级告警,保持实时巡检。', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, primaryAction: '告警事件', secondaryAction: '通知规则', onPrimary: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}), onSecondary: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) }, { title: '自定义时间复盘', value: taskTimeMonitorSummary, detail: '一个时间窗贯穿轨迹回放、里程统计、历史查询和告警复盘,适合客户问询与 BI 核对。', color: 'blue' as const, primaryAction: '轨迹复盘', secondaryAction: '里程统计', onPrimary: () => openTimeMonitorHistory(), onSecondary: () => openTimeMonitorMileage() }, { title: '数据交付与导出', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '按车辆、时间、字段裁剪导出位置、原始记录和字段证据,交付给业务或客户复盘。', color: 'blue' as const, primaryAction: '历史导出', secondaryAction: '导出概览', onPrimary: () => openTimeMonitorRaw(), onSecondary: () => exportDashboardSnapshot() } ]; const customerServicePathItems = [ { title: '找车', value: formatCount(serviceSummary?.totalVehicles), detail: '按 VIN、车牌、手机号或 OEM 进入车辆服务,协议来源只作为证据。', action: '车辆中心', color: 'blue' as const, onClick: () => onOpenVehicles({}) }, { title: '看位置', value: `${commandLocatedCount.toLocaleString()} 有定位`, detail: '优先打开实时地图,判断车辆是否在线、坐标是否有效、是否存在断链。', action: '实时地图', color: commandLocatedCount > 0 ? 'green' as const : 'orange' as const, onClick: () => onOpenMap({ online: 'online' }) }, { title: '复盘时间', value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo), detail: '同一个时间窗贯穿轨迹回放、里程统计、原始记录和告警复盘。', action: '轨迹回放', color: 'blue' as const, onClick: openTimeMonitorHistory }, { title: '交付数据', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '按车辆、时间、字段裁剪导出位置历史、原始记录和字段明细。', action: '查询导出', color: 'blue' as const, onClick: openTimeMonitorRaw }, { title: '闭环异常', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警,保持日常巡检。', action: '告警事件', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality() } ]; const customerServiceJourneySteps = [ { step: '1', title: '选车', value: formatCount(serviceSummary?.totalVehicles), detail: '先用 VIN、车牌、手机号或 OEM 锁定服务对象。', action: '车辆中心', color: 'blue' as const, onClick: () => onOpenVehicles({}) }, { step: '2', title: '实时看车', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: '打开地图看在线、坐标、最后上报和区域态势。', action: '实时地图', color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { step: '3', title: '锁定时间窗', value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo), detail: '同一范围同步带入轨迹、统计、历史导出和告警。', action: '自定义时间', color: 'blue' as const, onClick: openTimeMonitorHistory }, { step: '4', title: '复盘里程', value: `${formatCount(summary?.activeToday)} 活跃`, detail: '用轨迹、位置历史和里程统计回答这段时间发生了什么。', action: '轨迹里程', color: 'blue' as const, onClick: openTimeMonitorMileage }, { step: '5', title: '交付闭环', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: '导出证据数据,并把异常车辆推到告警通知闭环。', action: '导出通知', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: openTimeMonitorRaw } ]; const copyCustomerServiceGuide = () => { const scope = timeMonitorScope(); const rawFilters = { ...scope, tab: 'raw', includeFields: 'true' }; const lines = [ '【车辆客户服务说明】', '服务对象:车辆,不是接入来源。', `车辆规模:${formatCount(serviceSummary?.totalVehicles)},在线车辆:${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)},有效定位:${commandLocatedCount.toLocaleString()}`, `当前时间窗:${timeMonitorSummary}(${dayRangeText(scope.dateFrom, scope.dateTo)})`, `告警车辆:${formatCount(summary?.issueVehicles)},最高优先级:${highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无'}`, '', '客户服务路径:', '1. 找车:先按 VIN、车牌、手机号或 OEM 锁定车辆。', '2. 看位置:打开实时地图确认车辆在线、坐标和最新上报。', '3. 复盘时间:同一时间窗查看轨迹、统计和告警。', '4. 交付数据:按车辆、时间、字段导出位置历史、原始记录和字段明细。', '5. 闭环异常:告警事件进入通知和处置流程。', `车辆中心:${appURL(buildAppHash({ page: 'vehicles' }))}`, `实时地图:${appURL(buildAppHash({ page: 'map', filters: { online: 'online' } }))}`, `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`, `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`, `历史数据:${appURL(buildAppHash({ page: 'history-query', keyword: scope.keyword, protocol: scope.protocol, filters: rawFilters }))}`, `告警事件:${appURL(buildAppHash({ page: 'alert-events', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}` ]; copyText(lines.join('\n'), '客户服务说明'); }; const customerCockpitMetrics = [ { label: '车辆总数', value: formatCount(serviceSummary?.totalVehicles), detail: '以 VIN 聚合车牌、手机号、OEM 和来源证据', color: 'blue' as const, onClick: () => onOpenVehicles({}) }, { label: '在线车辆', value: formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles), detail: vehicleServiceOnlineText(serviceSummary, summary), color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '有效定位', value: commandLocatedCount.toLocaleString(), detail: '用于实时地图、轨迹回放和客户位置问询', color: commandLocatedCount > 0 ? 'green' as const : 'orange' as const, onClick: () => onOpenRealtime({ online: 'online' }) }, { label: '告警车辆', value: formatCount(summary?.issueVehicles), detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality() } ]; const customerServiceCockpitItems = [ { label: '车辆总览', value: `${formatCount(serviceSummary?.totalVehicles)} 辆`, detail: '按 VIN、车牌、手机号或 OEM 进入车辆服务,不从协议列表开始。', action: '车辆中心', color: 'blue' as const, onClick: () => onOpenVehicles({}) }, { label: '实时可见', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: `${commandLocatedCount.toLocaleString()} 辆有有效坐标,先回答客户车辆在哪里。`, action: '地图看车', color: commandLocatedCount > 0 ? 'green' as const : 'orange' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '轨迹复盘', value: `${formatCount(summary?.activeToday)} 今日活跃`, detail: '同一辆车、同一时间窗回放路线、速度、停驶和里程断点。', action: '回放轨迹', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '里程统计', value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo), detail: '核对区间里程、每日闭合、异常记录和 BI 里程口径。', action: '里程统计', color: 'blue' as const, onClick: openTimeMonitorMileage }, { label: '数据交付', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '按车辆、时间和字段裁剪历史位置、原始记录和解析证据。', action: '导出证据', color: 'blue' as const, onClick: openTimeMonitorRaw }, { label: '告警通知', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警。', action: '闭环处理', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; const customerCockpitWorkflows = [ { title: '实时看车', description: '打开地图确认车辆在哪里、是否在线、最后上报是否新鲜。', action: '实时地图', evidence: `${commandLocatedCount.toLocaleString()} 辆有定位`, onClick: () => onOpenMap({ online: 'online' }) }, { title: '轨迹复盘', description: '用同一辆车和同一时间窗回放位置、速度、里程断点。', action: '轨迹回放', evidence: `${formatCount(summary?.activeToday)} 今日活跃`, onClick: openTimeMonitorHistory }, { title: '里程统计', description: '按车辆口径核对区间里程、日统计和异常来源。', action: '里程统计', evidence: `${formatCount(serviceSummary?.totalVehicles)} 辆可统计`, onClick: openTimeMonitorMileage }, { title: '数据交付', description: '按车辆、时间和字段导出位置历史、原始记录和解析字段。', action: '历史导出', evidence: `${formatCount(summary?.frameToday)} 今日数据`, onClick: openTimeMonitorRaw }, { title: '告警通知', description: '将断链、离线、定位异常和字段缺失变成可通知事件。', action: '告警事件', evidence: `${formatCount(summary?.issueVehicles)} 告警车辆`, onClick: () => onOpenQuality() } ]; const modernFleetOperations = [ { label: 'Live Map', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: `有效定位 ${commandLocatedCount.toLocaleString()} 辆,先确认车辆在哪里。`, action: '打开地图', color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: 'Route Replay', value: `${formatCount(summary?.activeToday)} 活跃`, detail: `时间窗 ${dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo)},用于客户复盘。`, action: '回放轨迹', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: 'Mileage', value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, detail: '按车辆口径查询区间里程、日统计和异常断点。', action: '查里程', color: 'blue' as const, onClick: openTimeMonitorMileage }, { label: 'Export', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '位置、原始记录和字段证据按车辆与时间裁剪交付。', action: '导出数据', color: 'blue' as const, onClick: openTimeMonitorRaw }, { label: 'Alerts', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警。', action: '通知闭环', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; const customerPlatformBlueprintItems = [ { label: '实时地图', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: `有效定位 ${commandLocatedCount.toLocaleString()} 辆,支撑客户看车、调度和在线巡检。`, action: '打开地图', color: commandLocatedCount > 0 ? 'green' as const : 'orange' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '轨迹回放', value: `${formatCount(summary?.activeToday)} 活跃`, detail: '按车辆和时间窗回放路线、速度、停留与里程断点。', action: '回放轨迹', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '围栏告警', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '断链、定位异常、围栏事件进入告警通知闭环。', action: '告警通知', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) }, { label: '报表导出', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '按车辆、时间、字段裁剪轨迹、历史明细、统计和告警说明。', action: '历史导出', color: 'blue' as const, onClick: openTimeMonitorRaw }, { label: '车辆健康', value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, detail: '围绕车辆档案、在线状态、能耗字段和异常维护建立服务视图。', action: '车辆中心', color: 'blue' as const, onClick: () => onOpenVehicles({}) } ]; const customerSavedViewItems = [ { label: '在线车队视图', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: '默认进入车辆地图,按在线车辆、最新位置和定位有效性巡检。', action: '打开地图', color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '轨迹日报模板', value: `${formatCount(summary?.activeToday)} 活跃`, detail: '按当前时间窗复用轨迹回放和历史位置查询,处理每日客户问询。', action: '历史导出', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '里程周报模板', value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, detail: '按车辆口径复用里程统计,支撑周报、对账和 BI 复核。', action: '里程统计', color: 'blue' as const, onClick: openTimeMonitorMileage }, { label: '告警订阅视图', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: '围绕断链、离线、定位异常和字段缺失形成通知闭环。', action: '通知闭环', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; const tenSecondTriageItems = [ { label: '告警车辆', value: `${formatCount(summary?.issueVehicles)} 辆`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警,保持日常巡检。', action: '处理告警', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) }, { label: '无数据车辆', value: `${formatCount(serviceSummary?.noDataVehicles)} 辆`, detail: '优先确认平台转发、车辆是否在线以及是否有任何来源证据。', action: '查车辆', color: (serviceSummary?.noDataVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenVehicles({ serviceStatus: 'no_data' }) }, { label: '身份未绑定', value: `${formatCount(serviceSummary?.identityRequiredVehicles)} 辆`, detail: '已有上报但无法稳定归并到 VIN,会影响地图、轨迹和统计聚合。', action: '维护绑定', color: (serviceSummary?.identityRequiredVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenVehicles({ serviceStatus: 'identity_required' }) } ]; const amapVehicleServiceItems = [ { label: '实时看车', value: `${commandLocatedCount.toLocaleString()} 有定位`, detail: '高德底图承接车辆在线、最新位置、速度和最后上报时间。', action: '打开地图', color: commandLocatedCount > 0 ? 'green' as const : 'orange' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '路线回放', value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo), detail: '同一车辆和时间窗回放路径,核对速度、停留、里程和断点。', action: '轨迹回放', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '区域告警', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '围栏、断链、定位异常后续统一进入告警通知。', action: '告警通知', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) }, { label: '时间窗导出', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '按车辆、时间和字段导出位置、原始记录、解析字段和统计证据。', action: '历史导出', color: 'blue' as const, onClick: openTimeMonitorRaw } ]; const amapCapabilityItems = [ { label: '实时底图', value: amapConfigured ? '可用' : '降级', detail: amapConfigured ? '车辆在线分布、最后位置和地图选车可直接使用高德底图。' : '未配置 Web JS Key 时保留坐标预览。', color: amapConfigured ? 'green' as const : 'orange' as const }, { label: '轨迹路径', value: amapConfigured ? '可回放' : '坐标线', detail: amapConfigured ? '轨迹回放可叠加道路底图,辅助判断停留、绕行和断点。' : '缺少底图时只展示历史坐标证据。', color: amapConfigured ? 'green' as const : 'orange' as const }, { label: '区域围栏', value: amapApiConfigured ? '可扩展' : '待接入', detail: amapApiConfigured ? '服务端 API 可承接围栏、区域、路线和位置服务扩展。' : '围栏和区域能力需要服务端地图 API。', color: amapApiConfigured ? 'blue' as const : 'orange' as const }, { label: '地址解析', value: amapSecurityProxyEnabled ? '代理可用' : '待代理', detail: amapSecurityProxyEnabled ? '逆地理和路线请求可通过安全代理收敛密钥。' : '生产环境建议通过 /_AMapService 代理服务端能力。', color: amapSecurityProxyEnabled ? 'green' as const : 'orange' as const } ]; const customerQuestionActions = [ { question: '这辆车现在在哪里?', answer: `${commandLocatedCount.toLocaleString()} 辆有可用坐标`, action: '打开地图', color: commandLocatedCount > 0 ? 'green' as const : 'orange' as const, onClick: () => onOpenMap({ online: 'online' }) }, { question: '这段时间跑了多少公里?', answer: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo), action: '查里程', color: 'blue' as const, onClick: openTimeMonitorMileage }, { question: '能不能回放轨迹?', answer: `${formatCount(summary?.activeToday)} 辆今日活跃`, action: '轨迹回放', color: 'blue' as const, onClick: openTimeMonitorHistory }, { question: '数据能导出给客户吗?', answer: `${formatCount(summary?.frameToday)} 条今日证据`, action: '查询导出', color: 'blue' as const, onClick: openTimeMonitorRaw }, { question: '哪些车需要马上处理?', answer: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警', action: '告警事件', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; const customerProblemDesk = [ { question: '现在车辆在哪里', answer: `${commandLocatedCount.toLocaleString()} 辆有可用坐标,先进入实时地图确认分布和最新上报。`, metric: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, action: '打开实时地图', color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { question: '这段时间跑了多少', answer: `${dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo)},用同一时间窗核对区间里程和每日统计。`, metric: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, action: '查里程统计', color: 'blue' as const, onClick: openTimeMonitorMileage }, { question: '轨迹能不能回放', answer: `今日活跃 ${formatCount(summary?.activeToday)},可回放位置、速度、停驶和里程断点。`, metric: `${formatCount(summary?.activeToday)} 活跃`, action: '打开轨迹回放', color: 'blue' as const, onClick: openTimeMonitorHistory }, { question: '需要导出哪些证据', answer: `今日数据 ${formatCount(summary?.frameToday)},按车辆、时间、字段裁剪导出位置和原始证据。`, metric: `${formatCount(summary?.frameToday)} 数据`, action: '查询历史导出', color: 'blue' as const, onClick: openTimeMonitorRaw }, { question: '哪些车需要通知处理', answer: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警,保持日常巡检。', metric: `${formatCount(summary?.issueVehicles)} 告警`, action: '查看告警事件', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; const onlineVehicleCount = serviceSummary?.onlineVehicles ?? summary?.onlineVehicles ?? 0; const missingLocationCount = Math.max(onlineVehicleCount - commandLocatedCount, 0); const vehiclePriorityQueue = [ { title: '告警待处理', value: `${formatCount(summary?.issueVehicles)} 辆`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警,保持日常巡检。', action: '告警事件', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) }, { title: '无有效定位', value: `${missingLocationCount.toLocaleString()} 辆`, detail: '在线车辆缺少有效坐标时,客户无法完成地图看车和轨迹复盘。', action: '打开地图', color: missingLocationCount > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { title: '身份未绑定', value: `${formatCount(serviceSummary?.identityRequiredVehicles)} 辆`, detail: '已有数据但无法归并到 VIN,会影响车辆服务、统计和导出。', action: '维护绑定', color: (serviceSummary?.identityRequiredVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenVehicles({ serviceStatus: 'identity_required' }) }, { title: '暂无数据', value: `${formatCount(serviceSummary?.noDataVehicles)} 辆`, detail: '车辆没有形成实时、轨迹或历史证据,优先确认平台转发。', action: '车辆列表', color: (serviceSummary?.noDataVehicles ?? 0) > 0 ? 'red' as const : 'green' as const, onClick: () => onOpenVehicles({ serviceStatus: 'no_data' }) } ]; const customerNextActions = [ { level: (summary?.issueVehicles ?? 0) > 0 ? '优先' : '巡检', title: (summary?.issueVehicles ?? 0) > 0 ? '先处理告警车辆' : '先查看在线车辆地图', detail: (summary?.issueVehicles ?? 0) > 0 ? (highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '存在告警车辆,建议先进入告警事件。') : `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 辆在线,${commandLocatedCount.toLocaleString()} 辆有定位。`, action: (summary?.issueVehicles ?? 0) > 0 ? '进入告警' : '打开地图', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => (summary?.issueVehicles ?? 0) > 0 ? onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) : onOpenMap({ online: 'online' }) }, { level: focusVehicle ? '单车' : '范围', title: focusVehicle ? '复盘重点车辆' : '选择一辆车复盘', detail: focusVehicle ? `${focusVehicle.label},${focusVehicle.reason}` : '从车辆中心或地图选择车辆后,进入轨迹、统计和历史证据。', action: focusVehicle ? '车辆服务' : '车辆中心', color: focusVehicle?.statusColor ?? 'blue' as const, onClick: () => focusVehicle?.lookupKey ? onOpenVehicle(focusVehicle.lookupKey, focusVehicle.protocol) : onOpenVehicles({}) }, { level: '时间窗', title: '按同一范围交付数据', detail: `${dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo)},同步轨迹、统计、历史和告警。`, action: '复制复盘包', color: 'blue' as const, onClick: copyTimeMonitorReviewPackage } ]; const customerTrustSignals = [ { label: '数据来源', value: `${formatCount(serviceSummary?.multiSourceVehicles)} 多源 / ${formatCount(serviceSummary?.singleSourceVehicles)} 单源`, detail: '来源只作为可信度证据,不作为客户主导航。' }, { label: '地图能力', value: amapConfigured ? '高德地图可用' : '坐标预览', detail: amapConfigured ? '支持实时看车和轨迹底图。' : '地图配置缺失时仍可查看坐标证据。' }, { label: '时间窗', value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo), detail: '同一时间范围贯穿轨迹、统计、历史和告警。' } ]; const customerTaskNavigation = [ { title: '看车在哪', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: `${commandLocatedCount.toLocaleString()} 辆有有效定位`, action: '实时地图', color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { title: '查这段时间', value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo), detail: '同窗查看轨迹和里程统计', action: '轨迹里程', color: 'blue' as const, onClick: openTimeMonitorHistory }, { title: '导出数据', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '位置、原始记录和字段证据', action: '历史导出', color: 'blue' as const, onClick: openTimeMonitorRaw }, { title: '处理告警', value: `${formatCount(summary?.issueVehicles)} 告警车辆`, detail: highPriorityIssue ? qualityIssueLabel(highPriorityIssue.issueType) : '当前无高优先级', action: '告警事件', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; const customerDeliveryItems = [ { title: '在线车辆交付', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: `地图有效定位 ${commandLocatedCount.toLocaleString()} 辆,先交付客户最关心的车辆当前位置和在线态势。`, action: '实时地图', color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { title: '时间窗复盘', value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo), detail: '同一时间范围同步到轨迹、统计、历史证据和告警复盘,避免客户反复给条件。', action: '轨迹回放', color: 'blue' as const, onClick: openTimeMonitorHistory }, { title: '数据证据交付', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '按车辆、时间和字段裁剪导出位置、原始记录、解析字段和统计依据。', action: '历史导出', color: 'blue' as const, onClick: openTimeMonitorRaw }, { title: '告警通知交付', value: `${formatCount(summary?.issueVehicles)} 告警车辆`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '当前暂无高优先级告警,保持日常巡检和断链预警。', action: '告警事件', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; const customerVehicleMonitorItems = [ { label: '车辆在哪里', value: `${commandLocatedCount.toLocaleString()} 辆有定位`, detail: '打开地图查看在线车辆、最后上报、速度和坐标可信度。', action: '打开地图', color: commandLocatedCount > 0 ? 'green' as const : 'orange' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '回放这段时间', value: `${formatCount(summary?.activeToday)} 今日活跃`, detail: '用同一时间窗回放轨迹、速度、停驶和里程断点。', action: '轨迹回放', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '里程统计', value: `${formatCount(serviceSummary?.totalVehicles)} 辆可统计`, detail: '按车辆口径核对区间里程、日里程和异常记录。', action: '查里程', color: 'blue' as const, onClick: openTimeMonitorMileage }, { label: '导出客户数据', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '按车辆、时间和字段裁剪导出历史位置与原始证据。', action: '导出数据', color: 'blue' as const, onClick: openTimeMonitorRaw }, { label: '告警通知', value: `${formatCount(summary?.issueVehicles)} 告警车辆`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警。', action: '通知闭环', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; const customerServiceCommandItems = [ { label: '实时地图', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: `${commandLocatedCount.toLocaleString()} 辆有有效定位,优先回答车辆在哪里。`, action: '进入地图', color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '轨迹回放', value: `${formatCount(summary?.activeToday)} 活跃`, detail: `${dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo)},按车辆复盘路线、速度和里程断点。`, action: '回放轨迹', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '里程统计', value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, detail: '按车辆口径核对区间里程、日统计和异常来源。', action: '查里程', color: 'blue' as const, onClick: openTimeMonitorMileage }, { label: '时间窗监控', value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo), detail: '同一时间窗贯穿轨迹、统计、历史导出和告警复盘。', action: '自定义时间', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '数据导出', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '按车辆、时间和字段裁剪位置、原始记录和解析字段。', action: '查询导出', color: 'blue' as const, onClick: openTimeMonitorRaw }, { label: '告警通知', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警。', action: '闭环告警', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; const customerFleetGroupItems = [ { label: '在线运营组', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: '给调度和客服复用:默认进入在线车辆地图,先回答客户车辆在哪里。', action: '打开地图', color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '告警处置组', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: '给运维和业务负责人复用:只看需要通知、升级和验收的车辆。', action: '告警通知', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) }, { label: '身份维护组', value: `${formatCount(serviceSummary?.identityRequiredVehicles)} 待绑定`, detail: '给数据维护人员复用:补齐 VIN、车牌、手机号和客户可查身份。', action: '维护车辆', color: (serviceSummary?.identityRequiredVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenVehicles({ serviceStatus: 'identity_required' }) }, { label: '报表交付组', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '给客户交付人员复用:按同一车辆范围导出历史、轨迹、字段和统计证据。', action: '历史导出', color: 'blue' as const, onClick: openTimeMonitorRaw } ]; const customerSlaItems = [ { label: '断链发现', value: '1 分钟内', detail: 'Redis 在线状态按 1 分钟 TTL 形成准实时断链判断,优先确认车辆是否仍在上报。', action: '在线状态', color: 'green' as const, onClick: () => onOpenRealtime({ online: 'offline' }) }, { label: '异常通知', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} 进入通知和升级闭环。` : '暂无高优先级告警,保持例行巡检。', action: '通知闭环', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) }, { label: '恢复验收', value: '轨迹/统计可查', detail: '恢复不是只看链路 active,还要确认实时、轨迹、里程统计和历史证据都能打开。', action: '验收证据', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '数据交付', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '按客户车辆和时间窗导出历史位置、原始记录、解析字段和统计证据。', action: '导出证据', color: 'blue' as const, onClick: openTimeMonitorRaw } ]; const vehicleHealthEnergyItems = [ { label: '实时工况', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: '查看车辆最新速度、SOC、总里程、在线状态和多来源实时字段。', action: '实时监控', color: 'green' as const, onClick: () => onOpenRealtime({ online: 'online' }) }, { label: 'SOC/氢能字段', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '从历史字段中回查 SOC、燃料电池、氢耗和关键工况字段。', action: '字段证据', color: 'blue' as const, onClick: () => onOpenHistory({ tab: 'fields', includeFields: 'true' }) }, { label: '异常维护', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} 需要进入告警闭环。` : '暂无高优先级异常,继续观察车辆健康状态。', action: '告警事件', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) }, { label: '里程能耗', value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo), detail: '用同一时间窗核对里程、运行状态和能耗相关里程口径。', action: '里程统计', color: 'blue' as const, onClick: openTimeMonitorMileage } ]; const dispatchOperationsHighlights = [ { label: '实时地图', value: `${commandLocatedCount.toLocaleString()} 有定位`, detail: '先看车辆空间分布、在线态势和最新位置。', action: '打开地图', color: commandLocatedCount > 0 ? 'blue' as const : 'orange' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '今日重点', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '没有高优先级告警,保持巡检。', action: '处理告警', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; const dispatchOperationsTasks = [ { title: '看全域位置', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: '打开实时地图,确认在线车辆、有效坐标和重点区域。', action: '实时地图', color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { title: '回放重点轨迹', value: `${formatCount(summary?.activeToday)} 活跃`, detail: '按车辆和时间窗回放路线,核对停驶、偏航和里程断点。', action: '轨迹回放', color: 'blue' as const, onClick: openTimeMonitorHistory }, { title: '核对时间窗里程', value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, detail: '按同一时间范围核对区间里程、每日统计和 BI 口径。', action: '里程统计', color: 'blue' as const, onClick: openTimeMonitorMileage }, { title: '导出客户证据', value: `${formatCount(summary?.frameToday)} 帧`, detail: '导出历史位置、原始记录、解析字段和告警说明。', action: '历史导出', color: 'blue' as const, onClick: openTimeMonitorRaw } ]; const deliveryToday = timeMonitorScopeValue.dateTo || todayDateString(); const customerTimeRangePresets = [ { label: '最近一天', range: `${previousDateString(deliveryToday)} 至 ${deliveryToday}`, filters: { ...timeMonitorScopeValue, dateFrom: previousDateString(deliveryToday), dateTo: deliveryToday } }, { label: '最近三天', range: `${offsetDateString(deliveryToday, -3)} 至 ${deliveryToday}`, filters: { ...timeMonitorScopeValue, dateFrom: offsetDateString(deliveryToday, -3), dateTo: deliveryToday } }, { label: '本周', range: `${weekStartDateString(deliveryToday)} 至 ${deliveryToday}`, filters: { ...timeMonitorScopeValue, dateFrom: weekStartDateString(deliveryToday), dateTo: deliveryToday } }, { label: '自定义复盘', range: '当前范围', filters: timeMonitorScopeValue } ]; const deliveryScopeText = `${timeMonitorScopeValue.keyword || '全部车辆'} / ${timeMonitorScopeValue.protocol || '全部数据通道'} / ${timeMonitorScopeValue.dateFrom || '-'} 至 ${timeMonitorScopeValue.dateTo || '-'}`; const customerDeliveryWorkbenchItems = [ { label: '轨迹回放', value: `${formatCount(summary?.activeToday)} 活跃`, detail: '回放同一时间窗内的路线、速度、停驶和里程断点。', action: '回放轨迹', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '里程统计', value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, detail: '核对区间里程、每日统计和 BI 展示口径。', action: '里程统计', color: 'green' as const, onClick: openTimeMonitorMileage }, { label: '历史明细', value: `${formatCount(summary?.frameToday)} 帧`, detail: '查询位置历史、原始记录和解析字段,作为客户证据。', action: '历史导出', color: 'blue' as const, onClick: openTimeMonitorRaw }, { label: '告警说明', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '当前没有高优先级告警,可作为无异常说明。', action: '告警通知', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: openTimeMonitorAlerts } ]; const customerPrimaryFlowItems = [ { label: '实时地图', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: '先确认车辆在哪里、是否在线、是否有有效坐标。', action: '打开地图', color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '时间窗复盘', value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo), detail: '用同一时间范围串起轨迹、位置、里程、历史明细和导出。', action: '查询导出', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '里程统计', value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, detail: '以车辆为对象核对区间里程、每日统计和 BI 口径。', action: '里程统计', color: 'blue' as const, onClick: openTimeMonitorMileage }, { label: '告警通知', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '无高优先级异常时可交付无异常说明。', action: '通知处理', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: openTimeMonitorAlerts } ]; const customerVehicleServiceHubItems = [ { label: '实时地图', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: '先确认车辆在哪里、是否在线、坐标是否可信。', action: '看车在哪', color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '轨迹回放', value: `${formatCount(summary?.activeToday)} 活跃`, detail: '按车辆和时间窗回放路线、停驶、速度和里程断点。', action: '回放路线', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '里程统计', value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo), detail: '核对区间里程、每日里程和客户 BI 里程口径。', action: '核对里程', color: 'blue' as const, onClick: openTimeMonitorMileage }, { label: '数据导出', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '导出位置、原始记录、解析字段和告警说明。', action: '交付证据', color: 'blue' as const, onClick: openTimeMonitorRaw }, { label: '告警通知', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '没有高优先级异常时可直接说明无异常。', action: '闭环通知', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; const operationsEvidenceItems = [ { label: '链路健康', value: unhealthyLinkCount > 0 ? `${formatCount(unhealthyLinkCount)} 异常` : '正常', detail: '解释车辆实时、轨迹、统计或导出不可用时的链路证据。', action: '查看告警', color: unhealthyLinkCount > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) }, { label: '消息积压', value: formatLag(summary?.kafkaLag), detail: '判断接收、解析和历史落地是否存在排队。', action: '查看运维', color: (summary?.kafkaLag ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality() }, { label: '缓存在线', value: formatCount(opsHealth?.redisOnlineKeys), detail: '辅助解释在线车辆数和实时状态是否可信。', action: '缓存证据', color: (opsHealth?.redisOnlineKeys ?? 0) > 0 ? 'blue' as const : 'orange' as const, onClick: () => onOpenRealtime({ online: 'online' }) } ]; const customerVehicleServiceDashboardItems = [ { question: '车辆在哪里', value: `${commandLocatedCount.toLocaleString()} 有定位`, detail: '进入实时地图查看车辆分布、在线状态、最后上报和当前位置。', action: '打开地图', color: commandLocatedCount > 0 ? 'green' as const : 'orange' as const, onClick: () => onOpenMap({ online: 'online' }) }, { question: '轨迹能否回放', value: `${formatCount(summary?.activeToday)} 活跃`, detail: '按车辆和自定义时间窗回放路线、速度、停驶和里程断点。', action: '轨迹回放', color: 'blue' as const, onClick: openTimeMonitorHistory }, { question: '里程怎么算', value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, detail: '查询区间里程、每日里程和统计闭合情况,支撑 BI 口径复核。', action: '里程统计', color: 'blue' as const, onClick: openTimeMonitorMileage }, { question: '数据怎么导出', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '按车辆、时间和字段裁剪导出位置历史、原始记录和解析证据。', action: '历史导出', color: 'blue' as const, onClick: openTimeMonitorRaw }, { question: '异常谁处理', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警,可保持日常监控。', action: '告警通知', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; const customerVehicleServicePathItems = [ { label: '地图监控', question: '在线在哪里', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: `${commandLocatedCount.toLocaleString()} 辆有有效坐标,先让客户看到车辆位置和在线状态。`, action: '打开地图', color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '时间窗', question: '这段时间怎么跑', value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo), detail: '用同一时间窗串起轨迹、位置、里程、告警和导出证据。', action: '开始复盘', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '里程统计', question: '里程是否可信', value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, detail: '面向客户核对区间里程、每日汇总和 BI 里程口径。', action: '核对统计', color: 'blue' as const, onClick: openTimeMonitorMileage }, { label: '告警通知', question: '异常是否通知', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警,保持日常巡检。', action: '查看告警', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) }, { label: '数据导出', question: '数据能否交付', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '按车辆、时间窗和字段裁剪导出位置、原始记录和解析证据。', action: '导出证据', color: 'blue' as const, onClick: openTimeMonitorRaw } ]; const copyTodayVehicleServiceBrief = () => { const rawFilters = { tab: 'raw', includeFields: 'true' }; const lines = [ '【客户今日车辆服务简报】', `在线车辆:${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} / ${formatCount(serviceSummary?.totalVehicles)}`, `地图可见:${commandLocatedCount.toLocaleString()} 辆有坐标`, `今日活跃:${formatCount(summary?.activeToday)}`, `今日数据:${formatCount(summary?.frameToday)}`, `告警车辆:${formatCount(summary?.issueVehicles)}`, `当前时间窗:${timeMonitorWindowLabel}`, highPriorityIssue ? `优先告警:${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '优先告警:暂无高优先级告警', `车辆地图:${appURL(buildAppHash({ page: 'map', filters: { online: 'online' } }))}`, `实时监控:${appURL(buildAppHash({ page: 'realtime', filters: { online: 'online' } }))}`, `轨迹回放:${appURL(buildAppHash({ page: 'history', filters: timeMonitorScopeValue }))}`, `里程报表:${appURL(buildAppHash({ page: 'mileage', filters: timeMonitorScopeValue }))}`, `历史导出:${appURL(buildAppHash({ page: 'history-query', filters: rawFilters }))}`, `告警通知:${appURL(buildAppHash({ page: 'alert-events', filters: highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {} }))}` ]; copyText(lines.join('\n'), '今日服务简报'); }; const copyFleetOperationsCommand = () => { const rawFilters = { tab: 'raw', includeFields: 'true' }; const lines = [ '【客户车队运营总控包】', '首屏能力:实时地图 / 轨迹回放 / 里程统计 / 数据导出 / 告警通知', '协议来源:仅作为证据层,不作为客户主入口', `车辆规模:${formatCount(serviceSummary?.totalVehicles)},在线:${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)},有效定位:${commandLocatedCount.toLocaleString()}`, `时间窗:${timeMonitorWindowLabel}(${dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo)})`, `今日活跃:${formatCount(summary?.activeToday)},今日数据:${formatCount(summary?.frameToday)}`, `告警车辆:${formatCount(summary?.issueVehicles)}`, highPriorityIssue ? `最高告警:${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '最高告警:暂无高优先级告警', '', `实时地图:${appURL(buildAppHash({ page: 'map', filters: { online: 'online' } }))}`, `轨迹回放:${appURL(buildAppHash({ page: 'history', filters: timeMonitorScopeValue }))}`, `里程统计:${appURL(buildAppHash({ page: 'mileage', filters: timeMonitorScopeValue }))}`, `数据导出:${appURL(buildAppHash({ page: 'history-query', filters: rawFilters }))}`, `告警通知:${appURL(buildAppHash({ page: 'alert-events', filters: highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {} }))}` ]; copyText(lines.join('\n'), '运营总控包'); }; const todayOperationsItems = [ { label: '车辆在线', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: `${formatCount(serviceSummary?.totalVehicles)} 辆车辆服务资产,先确认客户能看到多少车。`, action: '打开地图', color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '地图可见', value: `${commandLocatedCount.toLocaleString()} 有坐标`, detail: '有效坐标决定客户能不能直接看地图态势和位置分布。', action: '实时地图', color: commandLocatedCount > 0 ? 'blue' as const : 'orange' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '轨迹复盘', value: `${formatCount(summary?.activeToday)} 活跃`, detail: '今日活跃车辆可按同一时间窗回放轨迹、速度和停驶片段。', action: '回放轨迹', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '里程报表', value: timeMonitorWindowLabel, detail: '从报表周期进入里程核对,避免客户只看到协议帧量。', action: '核对里程', color: 'blue' as const, onClick: openTimeMonitorMileage }, { label: '告警通知', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警,保持巡检。', action: '闭环处理', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; const fleetOperationsCommandItems = [ { label: '实时地图', value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, detail: `${commandLocatedCount.toLocaleString()} 辆有有效定位,先回答车辆在哪里。`, action: '打开地图', color: 'green' as const, onClick: () => onOpenMap({ online: 'online' }) }, { label: '轨迹回放', value: `${formatCount(summary?.activeToday)} 活跃`, detail: '按客户选择的车辆和时间窗回放路线、速度、停留和里程断点。', action: '回放轨迹', color: 'blue' as const, onClick: openTimeMonitorHistory }, { label: '里程统计', value: timeMonitorWindowLabel, detail: '核对区间里程、每日闭合、异常点和 BI 报表口径。', action: '核对里程', color: 'blue' as const, onClick: openTimeMonitorMileage }, { label: '数据导出', value: `${formatCount(summary?.frameToday)} 今日数据`, detail: '按车辆、时间和字段裁剪位置历史、原始记录和解析字段。', action: '导出报表', color: 'blue' as const, onClick: openTimeMonitorRaw }, { label: '告警通知', value: `${formatCount(summary?.issueVehicles)} 告警`, detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警,保持日常巡检。', action: '闭环处理', color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; return (
{focusMode === 'overview' ? (
客户车辆服务路径 {vehicleServiceOnlineText(serviceSummary, summary)} 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 客户车辆服务路径 客户入口只回答车辆问题:在线在哪里、这段时间怎么跑、里程是否可信、异常是否通知、数据能否交付。 32960 / 808 / MQTT 只是证据通道 默认沉到车辆可信度、历史明细和运维解释里。
{customerVehicleServicePathItems.map((item) => ( ))}
客户服务总览 地图、轨迹、里程、导出是客户能直接使用的车辆服务;协议来源只进入证据和追溯。
{customerHeroActions.map((item) => ( ))}
建议下一步 根据当前告警、车辆在线和时间窗状态,优先给客户一个明确行动。
{customerNextActions.map((item) => ( ))}
当前服务范围 {customerServiceScopeLabel}
客户今日运营台 {vehicleServiceOnlineText(serviceSummary, summary)} 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 客户今日运营台 今天先看在线和地图,再处理告警、复盘轨迹、核对里程,最后把证据导出给客户。
{todayOperationsItems.map((item) => ( ))}
运营总控 {amapConfigured ? '地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 客户车队运营总控 客户首屏只保留车辆地图、在线状态、轨迹回放、里程统计、数据导出和告警通知,协议来源退到证据层。
{fleetOperationsCommandItems.map((item) => ( ))}
) : null} {focusMode === 'time-window' ? (
时间窗监控 {timeMonitorWindowLabel} {timeMonitorDeliveryStatus.label} 当前监控范围:{timeMonitorScopeValue.keyword || '全部车辆'} / {timeMonitorScopeValue.protocol || '全部数据通道'} / {timeMonitorScopeValue.dateFrom || '-'} 至 {timeMonitorScopeValue.dateTo || '-'} 用同一组筛选条件贯穿地图定位、轨迹复盘、里程对账、历史证据导出和告警说明,避免客户跨页面重复输入。
{dedicatedTimeMonitorActions.map((item) => ( ))}
时间窗复盘 SLA 作业台 {timeMonitorDeliveryStatus.label} {timeMonitorHasAlerts ? `${formatCount(summary?.issueVehicles)} 告警` : '无高风险'} 把一个时间窗变成可交付作业:谁处理、多久交付、交付哪些证据、异常如何升级。 作业范围:{timeMonitorSummary};SLA:{timeMonitorWindowLabel}。
{timeWindowSlaItems.map((item) => ( ))}
) : null}
客户进阶工作台 地图大屏、指挥台、车辆服务驾驶舱和态势分析默认收起;客户首页先回答车辆在哪里、时间窗怎么查、里程怎么核、数据怎么交付。
{amapConfigured ? '高德地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警
车辆服务指挥台 客户首屏 10 秒内回答客户最关心的事:车辆在哪里、哪辆车异常、这段时间怎么跑、数据能不能导出。
{customerTaskNavigation.map((item) => ( ))}
优先处理车辆 按影响客户看车、轨迹、统计和导出的程度排序。
{vehiclePriorityQueue.map((item) => ( ))}
客户车辆服务中枢 {amapConfigured ? '地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 客户只关心车怎么服务:在哪里、是否在线、这段时间怎么跑、里程是否可信、异常是否已通知、数据能否交付。 运维接入、队列、存储、协议解析降级为证据层,默认不打断客户主流程。
{customerVehicleServiceHubItems.map((item) => ( ))}
车辆地图态势 {amapConfigured ? '高德地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 先看在线车辆在哪里,再决定是否回放轨迹、核对里程、导出数据或通知处理。
{customerCockpitMetrics.slice(1, 4).map((item) => ( ))}
客户车辆服务驾驶舱 {amapConfigured ? '高德地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 客户进来先看车辆,不先看协议。 把实时地图、轨迹回放、里程统计、历史导出和告警通知收敛成一个可交付的车辆服务入口。
{formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线车辆 {dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo)} 服务时间窗 {focusVehicle?.label ?? '暂无重点车辆'} 今日重点
{customerVehicleServiceDashboardItems.map((item) => ( ))}
车辆服务驾驶舱 客户主入口 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 先看车辆,不先看协议;客户进来先知道哪些车在线、在哪里、今天跑了多少、哪些异常要通知。 32960、808 和宇通 MQTT 都沉到证据层;首页只围绕车辆地图、轨迹回放、里程统计、数据交付和告警通知组织动作。
{customerServiceCockpitItems.map((item) => ( ))}
客户服务配置和说明 把蓝图、常用视图、处置说明和服务闭环收起,默认首页只保留地图、车辆、时间窗、导出和告警。
客户车辆服务中台蓝图 {amapConfigured ? '高德地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 参考主流车联网平台的信息架构,把 Live Map、Route Replay、Geofence Alerts、Reports Export 和 Vehicle Health 收敛成客户可直接使用的车辆服务。 三个接入来源继续作为证据层,客户首页只围绕车辆监控、时间窗复盘、告警通知和报表交付组织路径。
{customerPlatformBlueprintItems.map((item) => ( ))}
客户常用视图库 一个车辆服务入口 一个车辆服务入口,而不是三个数据源入口。 把车队范围、时间窗、地图态势、轨迹回放、里程统计、导出模板和告警订阅保存成客户可复用的车辆服务入口。
{customerSavedViewItems.map((item) => ( ))}
十秒车辆处置台 0 || (serviceSummary?.noDataVehicles ?? 0) > 0 ? 'orange' : 'green'}>先处理异常车辆 登录后先知道哪三类车辆最需要处理,再进入地图、车辆中心或告警通知。 首页只保留能直接行动的优先级:告警车辆、无数据车辆、身份未绑定车辆;协议来源留在证据层解释原因。
{tenSecondTriageItems.map((item) => ( ))}
车辆服务闭环 客户从首页开始,只需要按这五步完成找车、看车、复盘、统计、导出和通知。
{customerServiceJourneySteps.map((item) => ( ))}
客户调度运营首页 {amapConfigured ? '地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 值班人员进来先看地图态势和异常队列,再进入轨迹回放、时间窗统计、历史导出和告警通知。 首页把车辆监控组织成一个调度工作台:地图负责看车,任务队列负责处理今天要交付和要解释的问题。
{dispatchOperationsHighlights.map((item) => ( ))}
今日车辆任务 按客户最常用动作排序,不按协议来源排序。
{dispatchOperationsTasks.map((item) => ( ))}
客户查询导出交付台 {dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo)} {timeMonitorDeliveryStatus.label} 先锁定车辆和时间窗,再选择轨迹、里程、历史明细或告警说明,最终交付一份客户能看懂的数据包。
当前交付范围 {deliveryScopeText}
常用时间范围
{customerTimeRangePresets.map((item) => ( ))}
{customerDeliveryWorkbenchItems.map((item) => ( ))}
客户主流程 一个车辆服务 默认展示车辆地图、时间窗、里程、导出和告警;三类数据源只作为二级证据。
{customerPrimaryFlowItems.map((item) => ( ))}
运维证据层 0 ? 'orange' : 'green'}>{unhealthyLinkCount > 0 ? `${formatCount(unhealthyLinkCount)} 异常` : '链路正常'} 用于解释车辆服务不可用的链路、队列、缓存、存储和来源证据,不作为客户默认入口。
{operationsEvidenceItems.map((item) => ( ))}
客户车辆服务总控台 来源证据收敛层 {amapConfigured ? '地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 把接入来源收敛成一套车辆服务。 协议来源只用于证明车辆服务可信度,客户主流程仍然从车辆、地图、时间窗、统计、导出和告警进入。 三个接入来源统一沉到证据层,首页只回答客户怎么监控车辆、回放轨迹、核对里程、导出数据和处理告警。
来源证据:GB32960 / JT808 / YUTONG_MQTT {vehicleServiceOnlineText(serviceSummary, summary)} {dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo)}
{customerServiceCommandItems.map((item) => ( ))}
客户车队分组工作台 {formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 按客户责任范围组织车辆池:在线运营、告警处置、身份维护和报表交付都能保存成复用视图。 客户不是每次都从全量车辆开始筛选;常用车队视图应该直接带到地图、通知、车辆中心和历史导出。
{customerFleetGroupItems.map((item) => ( ))}
客户服务 SLA 承诺 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 0 ? 'orange' : 'green'}>{unhealthyLinkCount.toLocaleString()} 链路异常 把断链发现、异常通知、恢复验收和数据交付变成客户能看懂的服务承诺。 运维证据仍然独立展示;客户首页只看到哪些承诺正在被满足、哪些异常需要通知和验收。
{customerSlaItems.map((item) => ( ))}
车辆健康与能耗工作台 {formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 把实时工况、SOC/氢能字段、异常维护和里程能耗放到同一辆车的服务视角里。 客户不需要先理解字段来自 32960、808 还是 MQTT;先按车辆查看健康、能耗、异常和统计证据。
{vehicleHealthEnergyItems.map((item) => ( ))}
现代车队运营台 {amapConfigured ? '地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 一屏完成车辆地图、轨迹回放、里程统计、数据导出和告警闭环。
{modernFleetOperations.map((item) => ( ))}
高德地图车辆服务底座 {amapConfigured ? 'Web JS 已配置' : '坐标预览'} {amapApiConfigured ? '服务端 API 已配置' : '服务端 API 待配置'} {amapSecurityProxyEnabled ? '安全代理已启用' : '安全代理未启用'} 高德能力不单独成为页面目标,而是支撑同一辆车的实时看车、路线回放、区域告警和时间窗数据交付。 客户看到的是车辆服务动作;32960、808、MQTT 只作为位置、轨迹、告警和统计可信度的来源证据。
地图服务能力清单 把高德 Web JS 和服务端 API 翻译成客户能使用的车辆服务能力。
{amapCapabilityItems.map((item) => (
{item.label} {item.value} {item.detail}
))}
{amapVehicleServiceItems.map((item) => ( ))}
客户车辆监控台 {amapConfigured ? '地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 先回答客户最常问的车辆问题:车在哪里、这段时间怎么跑、里程怎么算、数据怎么导出、异常谁处理。 32960、808、MQTT 只在证据层出现;首页默认按车辆、时间窗和业务动作组织。
{customerVehicleMonitorItems.map((item) => ( ))}
车辆监控中心 {amapConfigured ? '高德地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警车辆 先看车在哪里,再处理轨迹、统计、告警和导出 客户主流程围绕车辆本身:地图看车、实时状态、时间窗复盘、里程统计、历史数据导出和告警通知。接入来源只作为追溯证据。
{customerCockpitMetrics.map((item) => ( ))}
客户任务导航 先按客户问题进入业务页面
{customerTaskNavigation.map((item) => ( ))}
客户问题处理台 先回答客户问题,再下钻到车辆、轨迹、统计和证据。
车辆服务优先
客户首先关心的是车辆、位置、时间、里程、告警和导出;接入来源只放在证据层。
{customerProblemDesk.map((item) => ( ))}
车辆服务优先级队列 先处理影响客户看车、查轨迹、算里程和收通知的问题车辆。
按车辆问题排序
{vehiclePriorityQueue.map((item) => ( ))}
今日先处理
{customerNextActions.map((item) => ( ))}
车辆服务工作流
{customerCockpitWorkflows.map((item) => ( ))}
客户常问
{customerQuestionActions.map((item) => ( ))}
自定义时间窗 {timeMonitorScope().keyword ? '单车' : '全域'} {timeMonitorSummary} 同一时间窗会同步用于轨迹回放、里程统计、历史查询和告警复盘。
{customerTrustSignals.map((item) => (
{item.label} {item.value} {item.detail}
))}
客户交付驾驶舱 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警车辆 {amapConfigured ? '地图可交付' : '坐标可交付'} 把车辆位置、时间窗、里程统计、历史证据和告警通知组织成客户可以直接使用的服务包。 客户打开首页后,先知道今天能交付什么,再选择地图、轨迹、里程、导出或通知。
{customerDeliveryItems.map((item) => ( ))}
自定义时间窗复盘{timeMonitorSummary}} style={{ marginBottom: 16 }} >
setTimeMonitorFilters(timeMonitorScope(values as Record))} style={{ marginBottom: 12 }} > GB32960 JT808 YUTONG_MQTT
同一时间窗会带入轨迹回放、里程统计和历史数据导出,避免跨页面重复输入。
客户时间窗复盘包 {timeMonitorScope().keyword ? '单车复盘' : '全域复盘'} {timeMonitorSummary} 客户问某辆车、某段时间发生了什么时,直接按这个时间窗串起轨迹、统计、历史数据、告警通知和地图定位。
{timeMonitorReviewItems.map((item) => (
{item.label} {item.value} {item.detail}
))}
时间窗服务路径 {timeMonitorDeliveryStatus.label} 锁定同一辆车和同一时间范围后,按轨迹、里程、历史证据和告警说明形成客户可复盘的交付路径。 这条路径把自定义时间窗从查询条件变成客户交付流程:先确定范围,再按同一范围打开轨迹、统计、导出和告警。
{timeWindowServicePathItems.map((item) => ( ))}
时间窗下一步行动条 {timeMonitorDeliveryStatus.label} {timeMonitorHasAlerts ? `${formatCount(summary?.issueVehicles)} 告警` : '无高风险'} 把客户选择的车辆和时间范围转成下一步动作:先处理风险,再核对轨迹、里程、历史证据和交付说明。 当前范围:{timeMonitorSummary};时间窗:{timeMonitorWindowLabel}。
{timeWindowNextItems.map((item) => ( ))}
{timeWindowNextActions.map((item) => ( ))}
{timeMonitorDeliveryStatus.label} {timeMonitorScopeValue.keyword ? '单车时间窗' : '车辆池时间窗'} 时间窗交付决策 {timeMonitorDeliveryStatus.detail}
{timeMonitorDeliveryActions.map((item) => ( ))}
时间窗服务核对 交付给客户前,先确认范围、轨迹、导出和异常闭环四件事都能讲清楚。
{timeMonitorChecklist.map((item) => (
{item.label} {item.value} {item.detail}
))}
当前时间窗 {timeMonitorScope().keyword ? '单车' : '全域'} {timeMonitorSummary} 这个范围会同步带入轨迹、统计、历史证据和告警复盘,适合客户问询、BI 核对和异常解释。
{timeMonitorWorkbench.map((item) => ( ))}
{[ { title: '今天车辆轨迹', detail: '查看当天活跃车辆的轨迹、速度和里程断点。', action: '查今天', onClick: openTimeMonitorHistory }, { title: '历史时间窗', detail: '按任意起止时间查询位置历史、原始记录和字段明细。', action: '自定义查询', onClick: openTimeMonitorRaw }, { title: '里程统计', detail: '按车辆和时间范围核对区间里程、日统计和异常点。', action: '里程统计', onClick: openTimeMonitorMileage }, { title: '告警复盘', detail: '按车辆或事件回放告警发生前后的轨迹和数据证据。', action: '告警事件', onClick: openTimeMonitorAlerts } ].map((item) => ( ))}
更多车辆服务入口 常用服务、今日任务、KPI 和车辆入口默认收起,主页面优先保留地图、时间窗监控、告警和导出。
{commandCenterItems.map((item) => (
{item.title} {item.value}
{item.detail}
))}
{customerHeroActions.map((item) => ( ))}
{customerTaskBoard.map((item) => (
{item.title} {item.value}
{item.detail}
))}
{kpis.map((item) => ( ))}
客户服务路径 {vehicleServiceOnlineText(serviceSummary, summary)} 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警事件 从车辆出发,完成监控、复盘、统计、导出和告警闭环 客户看到的是车辆服务结果;接入来源只在需要追溯时作为数据通道出现。
{customerServicePathItems.map((item) => ( ))}
运维和证据层 来源覆盖、地图配置、告警预览和实时证据默认收起,客户主流程先看车辆监控、轨迹、统计、告警和导出。
{mapReadiness.map((item) => (
{item.title}
{item.value}
{item.detail}
))}
{mapWorkItems.map((item) => ( ))}
{focusVehicle ? ( 重点车辆服务{focusVehicle.statusLabel}} style={{ marginBottom: 16 }} >
{focusVehicle.reason} {focusVehicle.label} 把实时、轨迹、原始记录、里程和告警集中到同一辆车处理。
{[ { label: '实时证据', value: focusVehicle.realtimeEvidence }, { label: '轨迹证据', value: focusVehicle.historyEvidence }, { label: '告警证据', value: focusVehicle.alertEvidence }, { label: '统计证据', value: focusVehicle.statisticEvidence } ].map((item) => (
{item.label} {item.value}
))}
) : null}
{operationWorkbench.map((item) => (
{item.title} {item.meta}
{item.value}
{item.detail} {item.actions.map((action) => ( ))}
))}
{vehicleServicePrinciples.map((item) => (
{item.title}
{item.value}
{item.detail}
))}
车联网场景导航} style={{ marginBottom: 16 }} >
{scenarioNavigation.map((item) => (
{item.title} {item.objective}
{item.evidence}
{item.sla}
))}
{highPriorityIssue ? (
{highPriorityIssue.severity === 'error' ? 'P0' : 'P1'} {qualityIssueLabel(highPriorityIssue.issueType)} {qualityProtocolLabel(highPriorityIssue.protocol)} {highPriorityIssue.lastSeen || '-'} {priorityIssueVehicleLabel(highPriorityIssue)} {highPriorityIssue.detail || '暂无告警详情'}
) : null}
{capabilities.map((item) => (
{item.title} {item.description}
{item.status}
))}
{amapConfigured ? '高德地图配置就绪' : '高德地图待配置'} 在线 {commandOnlineCount.toLocaleString()} / {locations.length.toLocaleString()} 有效定位 {commandLocatedCount.toLocaleString()} 0 ? 'orange' : 'green'}>降级/离线 {commandDegradedCount.toLocaleString()}
实时作业
{commandOnlineCount.toLocaleString()}
当前预览车辆在线数,进入实时监控可按车辆、来源和服务状态筛选。
0 ? 'orange' : 'green'}>处置优先级
{commandDegradedCount.toLocaleString()}
优先处理离线、无来源、身份未绑定和来源不完整车辆。
{serviceActionQueue.length > 0 ? (
{serviceActionQueue.map((item) => (
{item.label} {item.count.toLocaleString()} {item.detail}
))}
) : null} 告警事件预览} bordered style={{ marginTop: 16 }} > `${row?.protocol ?? ''}-${row?.issueType ?? ''}-${row?.lastSeen ?? ''}-${row?.detail ?? ''}`} dataSource={qualityIssues} columns={[ { title: 'VIN', dataIndex: 'vin', width: 160 }, { title: '车牌', dataIndex: 'plate', width: 110 }, { title: '手机号', dataIndex: 'phone', width: 130 }, { title: '来源地址', dataIndex: 'sourceEndpoint', width: 180 }, { title: '来源', dataIndex: 'protocol', width: 110 }, { title: '问题', dataIndex: 'issueType', width: 140 }, { title: '级别', width: 90, render: (_: unknown, row: QualityIssueRow) => {row.severity} }, { title: '最后时间', dataIndex: 'lastSeen', width: 170 }, { title: '操作', width: 130, render: (_: unknown, row: QualityIssueRow) => { const lookup = qualityIssueVehicleLookup(row); return ; } } ]} /> 车辆服务覆盖} bordered style={{ marginTop: 16 }} > {coverageServiceStatusTitle ? (
当前筛选:{coverageServiceStatusTitle}
) : null}
loadCoverage(values as Record)} style={{ marginBottom: 12 }}> 单源 多源 缺 GB32960 缺 JT808 缺 YUTONG_MQTT 在线 离线 已绑定 未绑定 服务正常 来源不完整 车辆离线 暂无数据来源 身份未绑定
( ) }, { title: '证据覆盖', width: 130, render: (_: unknown, row: VehicleCoverageRow) => sourceEvidenceText(row) }, { title: '服务状态', width: 130, render: (_: unknown, row: VehicleCoverageRow) => { const status = rowServiceStatus(row); return {status.label}; } }, { title: '来源一致性', width: 140, render: (_: unknown, row: VehicleCoverageRow) => sourceConsistencyAction(row, loadCoverage) }, { title: '在线', width: 90, render: (_: unknown, row: VehicleCoverageRow) => }, { title: '绑定', width: 90, render: (_: unknown, row: VehicleCoverageRow) => {row.bindingStatus === 'bound' ? '已绑定' : '未绑定'} }, { title: '最后时间', dataIndex: 'lastSeen', width: 170 }, { title: '操作', width: 110, render: (_: unknown, row: VehicleCoverageRow) => } ]} />
{locations.map((row, index) => ( ))}
( {row.protocols.map((protocol) => {protocol})} ) }, { title: '服务状态', render: (_: unknown, row: VehicleRealtimeRow) => { const status = rowServiceStatus(row); return {status.label}; } }, { title: '最后时间', dataIndex: 'lastSeen' }, { title: '操作', width: 110, render: (_: unknown, row: VehicleRealtimeRow) => } ]} /> ); }