import { Button, Card, Form, Select, Space, Table, Tabs, Tag, Toast, Typography } from '@douyinfe/semi-ui'; import { IconCopy } from '@douyinfe/semi-icons'; import { useEffect, useState } from 'react'; import { api } from '../api/client'; import type { OpsHealth, VehicleRealtimeRow } from '../api/types'; import { DataEmpty } from '../components/DataEmpty'; import { PageHeader } from '../components/PageHeader'; import { SourceStatusTags } from '../components/SourceStatusTags'; import { StatusTag } from '../components/StatusTag'; import { VehicleMap, type VehicleMapPoint } from '../components/VehicleMap'; import { getAMapConfig, isAMapConfigured } from '../config/appConfig'; import { buildAppHash } from '../domain/appRoute'; import { buildCsv, downloadCsv, type CsvColumn } from '../domain/csvExport'; function canOpenVehicle(vin?: string) { const value = vin?.trim(); return Boolean(value && value !== 'unknown'); } function vehicleServiceStatus(row: VehicleRealtimeRow) { if (row.serviceStatus) { const title = row.serviceStatus.status === 'degraded' || row.serviceStatus.title === '来源不完整' ? '数据通道不完整' : row.serviceStatus.title; return { label: 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: VehicleRealtimeRow) { return `${row.onlineSourceCount}/${row.sourceCount} 来源在线`; } function formatPercent(value: number) { return Number.isFinite(value) ? `${value.toLocaleString(undefined, { maximumFractionDigits: 1 })}%` : '0%'; } function serviceStatusWeight(row: VehicleRealtimeRow) { const severity = row.serviceStatus?.severity; if (severity === 'error') return 4; if (severity === 'warning') return 3; if (row.onlineSourceCount <= 0) return 4; if (row.onlineSourceCount < row.sourceCount) return 3; return 1; } function sourceIssueTags(row: VehicleRealtimeRow) { const tags = (row.sourceStatus ?? []) .filter((source) => !source.online || !source.hasRealtime) .map((source) => `${source.protocol} ${source.hasRealtime ? '离线' : '未接入'}`) ?? []; if (tags.length > 0) return tags; if (row.onlineSourceCount < row.sourceCount) return ['数据通道缺失']; return []; } function hasSourceIssue(row: VehicleRealtimeRow) { const severity = row.serviceStatus?.severity; return severity === 'warning' || severity === 'error' || row.onlineSourceCount < row.sourceCount || sourceIssueTags(row).length > 0; } function isValidCoordinate(row: VehicleRealtimeRow) { return Number.isFinite(row.longitude) && Number.isFinite(row.latitude) && row.longitude !== 0 && row.latitude !== 0; } function realtimeMapPointId(row: VehicleRealtimeRow, index = 0) { return row.vin?.trim() || `${row.primaryProtocol || 'source'}-${index}`; } function formatRefreshTime(date: Date) { return date.toLocaleTimeString('zh-CN', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' }); } function padDatePart(value: number) { return String(value).padStart(2, '0'); } function formatDateTime(value: Date) { return [ value.getFullYear(), padDatePart(value.getMonth() + 1), padDatePart(value.getDate()) ].join('-') + ` ${padDatePart(value.getHours())}:${padDatePart(value.getMinutes())}:${padDatePart(value.getSeconds())}`; } function defaultTimeWindow() { const end = new Date(); const start = new Date(end.getTime() - 24 * 60 * 60 * 1000); return { dateFrom: formatDateTime(start), dateTo: formatDateTime(end) }; } function timeWindowDurationText(dateFrom: string, dateTo: string) { const start = new Date(dateFrom.replace(' ', 'T')).getTime(); const end = new Date(dateTo.replace(' ', 'T')).getTime(); if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) { return '时间窗待确认'; } const minutes = Math.round((end - start) / 60000); if (minutes < 60) return `${minutes} 分钟窗口`; if (minutes < 1440) return `${Math.round(minutes / 60)} 小时窗口`; return `${Math.round(minutes / 1440)} 天窗口`; } function parseVehicleTime(value?: string) { const normalized = value?.trim(); if (!normalized) { return Number.NaN; } return new Date(normalized.replace(' ', 'T')).getTime(); } function dataFreshness(row: VehicleRealtimeRow) { const timestamp = parseVehicleTime(row.lastSeen); if (!Number.isFinite(timestamp)) { return { label: '无时间', color: 'grey' as const, detail: '未上报最后时间', stale: true }; } const ageSeconds = Math.floor((Date.now() - timestamp) / 1000); if (ageSeconds <= 300) { return { label: '数据新鲜', color: 'green' as const, detail: ageSeconds <= 0 ? '刚刚更新' : `${Math.max(1, Math.ceil(ageSeconds / 60))} 分钟内更新`, stale: false }; } if (ageSeconds < 3600) { return { label: '更新超时', color: 'orange' as const, detail: `${Math.ceil(ageSeconds / 60)} 分钟未更新`, stale: true }; } if (ageSeconds < 86400) { return { label: '更新超时', color: 'red' as const, detail: `${Math.ceil(ageSeconds / 3600)} 小时未更新`, stale: true }; } return { label: '更新超时', color: 'red' as const, detail: `${Math.ceil(ageSeconds / 86400)} 天未更新`, stale: true }; } function amapMarkerURL(row: VehicleRealtimeRow) { const name = encodeURIComponent(row.plate || row.vin || '车辆位置'); return `https://uri.amap.com/marker?position=${row.longitude},${row.latitude}&name=${name}&src=lingniu-vehicle-platform`; } const onlineLabel: Record = { online: '在线', offline: '离线' }; const serviceStatusLabel: Record = { healthy: '服务正常', degraded: '数据通道不完整', offline: '车辆离线', identity_required: '身份未绑定' }; const realtimeExportColumns: CsvColumn[] = [ { title: 'VIN', value: (row) => row.vin }, { title: '车牌', value: (row) => row.plate }, { title: '手机号', value: (row) => row.phone }, { title: 'OEM', value: (row) => row.oem }, { title: '主要来源证据', value: (row) => row.primaryProtocol }, { title: '来源证据', value: (row) => row.protocols?.join('|') }, { title: '在线', value: (row) => row.online ? '在线' : '离线' }, { title: '车辆服务状态', value: (row) => vehicleServiceStatus(row).label }, { title: '来源在线', value: (row) => sourceEvidenceText(row) }, { title: '经度', value: (row) => row.longitude }, { title: '纬度', value: (row) => row.latitude }, { title: '速度km/h', value: (row) => row.speedKmh }, { title: 'SOC%', value: (row) => row.socPercent }, { title: '总里程km', value: (row) => row.totalMileageKm }, { title: '最后时间', value: (row) => row.lastSeen }, { title: '绑定状态', value: (row) => row.bindingStatus } ]; type RealtimeSourceCoverage = { protocol: string; total: number; online: number; located: number; degraded: number; stale: number; }; function realtimeExportFileName(filters: Record) { const keyword = filters.keyword?.trim() || 'all'; const protocol = filters.protocol?.trim() || 'all-source'; const online = filters.online?.trim() || 'all-online'; return `realtime-vehicles-${keyword}-${protocol}-${online}.csv`; } function realtimeFilterSummary(filters: Record) { return [ filters.keyword ? `关键词:${filters.keyword}` : '', filters.protocol ? `数据通道:${filters.protocol}` : '', filters.online ? `在线:${onlineLabel[filters.online] ?? filters.online}` : '', filters.serviceStatus ? `服务状态:${serviceStatusLabel[filters.serviceStatus] ?? filters.serviceStatus}` : '' ].filter(Boolean); } function realtimeOperationsSummaryText({ filters, rows, total, onlineCount, locatedCount, degradedCount, sourceTypeCount, amapConfigured, sourceIssueRows }: { filters: Record; rows: VehicleRealtimeRow[]; total: number; onlineCount: number; locatedCount: number; degradedCount: number; sourceTypeCount: number; amapConfigured: boolean; sourceIssueRows: VehicleRealtimeRow[]; }) { const issueLines = sourceIssueRows.length > 0 ? sourceIssueRows.map((row, index) => { const status = vehicleServiceStatus(row); return `${index + 1}. ${row.plate || row.vin} / ${row.primaryProtocol || '-'} / ${status.label} / ${row.serviceStatus?.detail || sourceEvidenceText(row)}`; }).join('\n') : '暂无重点车辆'; return [ '【实时监控摘要】', `当前筛选:${realtimeFilterSummary(filters).join(';') || '全部实时车辆'}`, `车辆总数:${total.toLocaleString()},当前页:${rows.length.toLocaleString()}`, `在线车辆:${onlineCount.toLocaleString()},定位有效:${locatedCount.toLocaleString()}`, `需要关注:${degradedCount.toLocaleString()},数据通道:${sourceTypeCount.toLocaleString()}`, `地图配置:${amapConfigured ? '已配置' : '未配置'}`, '重点车辆:', issueLines, `实时页面:${window.location.origin}${window.location.pathname}${window.location.hash}` ].join('\n'); } function appURL(hash: string) { return `${window.location.origin}${window.location.pathname}${hash}`; } function rawFrameAPIURL(row: VehicleRealtimeRow, protocol: string) { const params = new URLSearchParams({ protocol, vin: row.vin || '', limit: '20', includeFields: 'true' }); return `${window.location.origin}/api/history/raw-frames?${params.toString()}`; } function realtimeIssueLabels(row: VehicleRealtimeRow) { const labels: string[] = []; const freshness = dataFreshness(row); if (freshness.stale) { labels.push(freshness.detail); } if (!isValidCoordinate(row)) { labels.push('坐标无效'); } if (hasSourceIssue(row)) { labels.push(row.serviceStatus?.detail || sourceIssueTags(row).join('、') || sourceEvidenceText(row)); } return labels.length > 0 ? labels : ['暂无异常']; } function realtimeIssueAction(row: VehicleRealtimeRow) { const issues = realtimeIssueLabels(row).join(';'); if (!isValidCoordinate(row)) { return `核对${row.primaryProtocol || '实时数据'}定位字段解析和平台转发`; } if (dataFreshness(row).stale) { return `确认${row.primaryProtocol || '实时数据'}是否持续上报,必要时查看告警事件`; } if (hasSourceIssue(row)) { return '处理离线数据通道,确认车辆实时状态一致'; } return issues === '暂无异常' ? '持续观察' : '结合车辆服务详情继续排查'; } function realtimeIssueChecklistText({ filters, rows, total }: { filters: Record; rows: VehicleRealtimeRow[]; total: number; }) { const issueRows = rows .filter((row) => canOpenVehicle(row.vin) && (dataFreshness(row).stale || !isValidCoordinate(row) || hasSourceIssue(row))) .sort((a, b) => { const statusDelta = serviceStatusWeight(b) - serviceStatusWeight(a); if (statusDelta !== 0) return statusDelta; return Number(dataFreshness(b).stale) - Number(dataFreshness(a).stale); }); const lines = [ '【实时异常处置清单】', `当前筛选:${realtimeFilterSummary(filters).join(';') || '全部实时车辆'}`, `异常车辆:${issueRows.length.toLocaleString()} / 当前页 ${rows.length.toLocaleString()} / 总计 ${total.toLocaleString()}`, '' ]; if (issueRows.length === 0) { lines.push('当前页暂无实时异常车辆。'); } issueRows.forEach((row, index) => { const protocol = filters.protocol || row.primaryProtocol || ''; const status = vehicleServiceStatus(row); const issues = realtimeIssueLabels(row).join(';'); lines.push( `${index + 1}. ${row.plate || '-'} / ${row.vin} / ${protocol || '-'}`, ` 状态:${status.label};在线:${row.online ? '在线' : '离线'};问题:${issues}`, ` 位置:${isValidCoordinate(row) ? `${row.longitude},${row.latitude}` : '无有效坐标'};速度:${row.speedKmh ?? '-'} km/h;SOC:${row.socPercent ?? '-'}%`, ` 最后时间:${row.lastSeen || '-'};建议动作:${realtimeIssueAction(row)}`, ` 车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: row.vin, protocol }))}`, ` 实时监控:${appURL(buildAppHash({ page: 'realtime', keyword: row.vin, protocol }))}`, ` 轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: row.vin, protocol }))}`, ` 告警事件:${appURL(buildAppHash({ page: 'alert-events', keyword: row.vin, protocol }))}` ); }); return lines.join('\n'); } function realtimeDutyHandoffText({ filters, rows, total, onlineCount, locatedCount, degradedCount, staleCount, sourceTypeCount, amapConfigured, runtimeRelease }: { filters: Record; rows: VehicleRealtimeRow[]; total: number; onlineCount: number; locatedCount: number; degradedCount: number; staleCount: number; sourceTypeCount: number; amapConfigured: boolean; runtimeRelease?: string; }) { const sourceCoverage = new Map(); rows.forEach((row) => { row.sourceStatus?.forEach((source) => { const current = sourceCoverage.get(source.protocol) ?? { total: 0, online: 0, realtime: 0 }; current.total += 1; current.online += source.online ? 1 : 0; current.realtime += source.hasRealtime ? 1 : 0; sourceCoverage.set(source.protocol, current); }); }); const sourceLines = [...sourceCoverage.entries()] .sort(([left], [right]) => left.localeCompare(right)) .map(([protocol, item]) => `${protocol}:在线 ${item.online}/${item.total},实时 ${item.realtime}/${item.total}`); const sampleRows = rows .filter((row) => canOpenVehicle(row.vin)) .sort((a, b) => { const statusDelta = serviceStatusWeight(b) - serviceStatusWeight(a); if (statusDelta !== 0) return statusDelta; return Number(dataFreshness(b).stale) - Number(dataFreshness(a).stale); }) .slice(0, 8); const lines = [ '【车辆监控交付包】', `当前筛选:${realtimeFilterSummary(filters).join(';') || '全部实时车辆'}`, `页面车辆:${rows.length.toLocaleString()} / 总计 ${total.toLocaleString()};版本:${runtimeRelease || '未标记'}`, `在线:${onlineCount.toLocaleString()};离线:${(rows.length - onlineCount).toLocaleString()};定位有效:${locatedCount.toLocaleString()};需要关注:${degradedCount.toLocaleString()};超时:${staleCount.toLocaleString()};数据通道:${sourceTypeCount.toLocaleString()}`, `地图:${amapConfigured ? '高德已配置' : '高德未配置'}`, `车辆覆盖:${sourceLines.length > 0 ? sourceLines.join(';') : '当前页暂无数据通道明细'}`, `实时入口:${appURL(buildAppHash({ page: 'realtime', protocol: filters.protocol, filters }))}`, '' ]; if (sampleRows.length === 0) { lines.push('当前页暂无可交接 VIN 样本。'); return lines.join('\n'); } lines.push('车辆样本:'); sampleRows.forEach((row, index) => { const protocol = filters.protocol || row.primaryProtocol || ''; const status = vehicleServiceStatus(row); const freshness = dataFreshness(row); lines.push( `${index + 1}. ${row.plate || '-'} / ${row.vin} / ${protocol || '-'} / ${status.label}`, ` 最后上报:${row.lastSeen || '-'};新鲜度:${freshness.label};位置:${isValidCoordinate(row) ? `${row.longitude},${row.latitude}` : '无有效坐标'};速度:${row.speedKmh ?? '-'} km/h;SOC:${row.socPercent ?? '-'}%`, ` 数据通道:${sourceEvidenceText(row)};问题:${realtimeIssueLabels(row).join(';')}`, ` 车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: row.vin, protocol }))}`, ` 实时监控:${appURL(buildAppHash({ page: 'realtime', keyword: row.vin, protocol }))}`, ` 轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: row.vin, protocol }))}`, ` 里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: row.vin, protocol }))}`, ` 历史查询:${protocol ? rawFrameAPIURL(row, protocol) : '-'}` ); }); return lines.join('\n'); } function realtimeImpactReportText({ filters, rows, total, onlineCount, locatedCount, degradedCount, staleCount, pageCoverageRate, amapConfigured, runtimeRelease }: { filters: Record; rows: VehicleRealtimeRow[]; total: number; onlineCount: number; locatedCount: number; degradedCount: number; staleCount: number; pageCoverageRate: number; amapConfigured: boolean; runtimeRelease?: string; }) { const offlineCount = Math.max(0, rows.length - onlineCount); const impactLevel = degradedCount > 0 || staleCount > 0 || offlineCount > 0 ? '需要处置' : '实时稳定'; return [ '【车辆监控影响】', `当前筛选:${realtimeFilterSummary(filters).join(';') || '全部实时车辆'}`, `运行版本:${runtimeRelease || '未标记'}`, `影响等级:${impactLevel}`, `车辆范围:当前页 ${rows.length.toLocaleString()} / 总计 ${total.toLocaleString()},覆盖率 ${formatPercent(pageCoverageRate)}`, `在线状态:${onlineCount.toLocaleString()} 在线 / ${offlineCount.toLocaleString()} 离线`, `定位影响:${locatedCount.toLocaleString()} 辆有有效坐标`, `服务影响:${degradedCount.toLocaleString()} 辆降级 / ${staleCount.toLocaleString()} 辆超时`, `地图能力:${amapConfigured ? '高德地图可用' : '高德地图未配置,使用坐标预览'}`, `建议动作:${impactLevel === '实时稳定' ? '保持监控并关注告警队列' : '优先处理离线、超时和数据通道不完整车辆,并回到轨迹和历史查询复核'}`, `实时监控:${appURL(buildAppHash({ page: 'realtime', protocol: filters.protocol, filters }))}` ].join('\n'); } function mapCustomerPackageText({ filters, rows, total, onlineCount, locatedCount, attentionCount, staleCount, selectedRow, selectedProtocol, amapConfigured }: { filters: Record; rows: VehicleRealtimeRow[]; total: number; onlineCount: number; locatedCount: number; attentionCount: number; staleCount: number; selectedRow?: VehicleRealtimeRow; selectedProtocol?: string; amapConfigured: boolean; }) { const selectedVIN = selectedRow?.vin || ''; return [ '【客户地图监控包】', `当前筛选:${realtimeFilterSummary(filters).join(';') || '全部车辆'}`, `车辆范围:当前页 ${rows.length.toLocaleString()} / 总计 ${total.toLocaleString()}`, `在线态势:${onlineCount.toLocaleString()} 在线 / ${(rows.length - onlineCount).toLocaleString()} 离线`, `定位态势:${locatedCount.toLocaleString()} 辆有有效坐标`, `关注车辆:${attentionCount.toLocaleString()} 辆;更新超时 ${staleCount.toLocaleString()} 辆`, `地图能力:${amapConfigured ? '高德地图可用' : '坐标预览'}`, `选中车辆:${selectedRow ? `${selectedRow.plate || '-'} / ${selectedVIN} / ${selectedProtocol || selectedRow.primaryProtocol || '-'}` : '未选择'}`, selectedRow ? `选中车辆状态:${vehicleServiceStatus(selectedRow).label};${dataFreshness(selectedRow).detail};${realtimeIssueLabels(selectedRow).join(';')}` : '', selectedRow ? `选中车辆位置:${isValidCoordinate(selectedRow) ? `${selectedRow.longitude},${selectedRow.latitude}` : '无有效坐标'}` : '', `实时地图:${appURL(buildAppHash({ page: 'map', protocol: filters.protocol, filters }))}`, selectedVIN ? `车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', selectedVIN ? `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', selectedVIN ? `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', selectedVIN ? `历史数据:${appURL(buildAppHash({ page: 'history-query', keyword: selectedVIN, protocol: selectedProtocol, filters: { tab: 'raw', includeFields: 'true' } }))}` : '', selectedVIN ? `告警通知:${appURL(buildAppHash({ page: 'alert-events', keyword: selectedVIN, protocol: selectedProtocol }))}` : '' ].filter(Boolean).join('\n'); } function mapExecutiveControlPackageText({ filters, rows, total, onlineCount, locatedCount, attentionCount, selectedRow, selectedProtocol, amapConfigured }: { filters: Record; rows: VehicleRealtimeRow[]; total: number; onlineCount: number; locatedCount: number; attentionCount: number; selectedRow?: VehicleRealtimeRow; selectedProtocol?: string; amapConfigured: boolean; }) { const selectedVIN = selectedRow?.vin || ''; return [ '【客户车辆地图总控包】', `当前筛选:${realtimeFilterSummary(filters).join(';') || '全部车辆'}`, `地图总控:当前页 ${rows.length.toLocaleString()} / 总计 ${total.toLocaleString()}`, `服务链路:实时找车 -> 轨迹回放 -> 围栏告警 -> 报表导出`, `在线定位:${onlineCount.toLocaleString()} 在线;${locatedCount.toLocaleString()} 辆有坐标;${attentionCount.toLocaleString()} 辆关注`, `地图能力:${amapConfigured ? '高德地图可用' : '坐标预览'}`, `选中车辆:${selectedRow ? `${selectedRow.plate || '-'} / ${selectedVIN} / ${selectedProtocol || selectedRow.primaryProtocol || '-'}` : '未选择'}`, selectedRow ? `选中车辆状态:${vehicleServiceStatus(selectedRow).label};${dataFreshness(selectedRow).detail}` : '', `实时地图:${appURL(buildAppHash({ page: 'map', protocol: filters.protocol, filters: { ...filters, online: filters.online || 'online' } }))}`, selectedVIN ? `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', `围栏告警:${appURL(buildAppHash({ page: 'alert-events', filters: { serviceStatus: 'degraded', ...(filters.protocol ? { protocol: filters.protocol } : {}) } }))}`, selectedVIN ? `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', selectedVIN ? `历史导出:${appURL(buildAppHash({ page: 'history-query', keyword: selectedVIN, protocol: selectedProtocol, filters: { tab: 'raw', includeFields: 'true' } }))}` : '' ].filter(Boolean).join('\n'); } function selectedMapVehicleHandoffText(row: VehicleRealtimeRow, protocol: string) { const vin = row.vin || ''; const vehicle = `${row.plate || '-'} / ${vin || '-'} / ${protocol || row.primaryProtocol || '-'}`; const position = isValidCoordinate(row) ? `${row.longitude},${row.latitude}` : '无有效坐标'; return [ '【地图选中车辆交接卡】', `车辆:${vehicle}`, `服务状态:${vehicleServiceStatus(row).label}`, `在线状态:${row.online ? '在线' : '离线'}`, `最后上报:${row.lastSeen || '-'}`, `位置:${position}`, `速度:${row.speedKmh ?? '-'} km/h;SOC:${row.socPercent ?? '-'}%;总里程:${row.totalMileageKm ?? '-'} km`, `问题:${realtimeIssueLabels(row).join(';')}`, `建议动作:${realtimeIssueAction(row)}`, `车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: vin, protocol }))}`, `实时地图:${appURL(buildAppHash({ page: 'map', keyword: vin, protocol }))}`, `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: vin, protocol }))}`, `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: vin, protocol }))}`, `历史数据:${appURL(buildAppHash({ page: 'history-query', keyword: vin, protocol, filters: { tab: 'raw', includeFields: 'true' } }))}`, `告警通知:${appURL(buildAppHash({ page: 'alert-events', keyword: vin, protocol }))}` ].join('\n'); } function mapCustomerDecisionText({ filters, rows, total, onlineCount, locatedCount, attentionRows, selectedRow, selectedProtocol, amapConfigured }: { filters: Record; rows: VehicleRealtimeRow[]; total: number; onlineCount: number; locatedCount: number; attentionRows: VehicleRealtimeRow[]; selectedRow?: VehicleRealtimeRow; selectedProtocol?: string; amapConfigured: boolean; }) { const selectedVIN = selectedRow?.vin || ''; const topAttention = attentionRows[0]; return [ '【地图客户决策说明】', `当前筛选:${realtimeFilterSummary(filters).join(';') || '全部车辆'}`, `车辆范围:当前页 ${rows.length.toLocaleString()} / 总计 ${total.toLocaleString()}`, `在线判断:${onlineCount.toLocaleString()} 在线 / ${(rows.length - onlineCount).toLocaleString()} 离线`, `定位判断:${locatedCount.toLocaleString()} 辆有有效坐标 / ${Math.max(0, rows.length - locatedCount).toLocaleString()} 辆无坐标`, `关注判断:${attentionRows.length.toLocaleString()} 辆需要关注${topAttention ? `;优先车辆 ${topAttention.plate || topAttention.vin}:${realtimeIssueLabels(topAttention).join(';')}` : ''}`, `地图能力:${amapConfigured ? '高德地图可用' : '坐标预览'}`, `选中车辆:${selectedRow ? `${selectedRow.plate || '-'} / ${selectedVIN} / ${selectedProtocol || selectedRow.primaryProtocol || '-'}` : '未选择'}`, selectedRow ? `选中车辆下一步:${vehicleServiceStatus(selectedRow).label};${dataFreshness(selectedRow).detail};${realtimeIssueLabels(selectedRow).join(';')}` : '选中车辆下一步:先从地图或车辆列表选择一辆车', `实时地图:${appURL(buildAppHash({ page: 'map', protocol: filters.protocol, filters }))}`, `在线车辆:${appURL(buildAppHash({ page: 'map', protocol: filters.protocol, filters: { ...filters, online: 'online' } }))}`, selectedVIN ? `车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', selectedVIN ? `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', selectedVIN ? `历史查询导出:${appURL(buildAppHash({ page: 'history-query', keyword: selectedVIN, protocol: selectedProtocol, filters: { tab: 'raw', includeFields: 'true' } }))}` : '' ].filter(Boolean).join('\n'); } function mapAreaMonitorText({ filters, rows, locatedCount, attentionCount, selectedRow, selectedProtocol, amapConfigured }: { filters: Record; rows: VehicleRealtimeRow[]; locatedCount: number; attentionCount: number; selectedRow?: VehicleRealtimeRow; selectedProtocol?: string; amapConfigured: boolean; }) { const selectedVIN = selectedRow?.vin || ''; return [ '【区域围栏监控说明】', `当前筛选:${realtimeFilterSummary(filters).join(';') || '全部车辆'}`, `区域态势:${locatedCount.toLocaleString()} 辆可定位 / ${attentionCount.toLocaleString()} 辆关注 / ${amapConfigured ? '高德地图可用' : '坐标预览'}`, `车辆范围:当前页 ${rows.length.toLocaleString()} 辆`, `围栏建议:先用有效定位车辆作为区域覆盖基础,再对离线、超时、越界和长时间停留车辆触发告警通知。`, selectedRow ? `选中车辆:${selectedRow.plate || '-'} / ${selectedVIN} / ${selectedProtocol || selectedRow.primaryProtocol || '-'}` : '选中车辆:未选择', selectedRow ? `选中车辆位置:${isValidCoordinate(selectedRow) ? `${selectedRow.longitude},${selectedRow.latitude}` : '无有效坐标'}` : '', `实时地图:${appURL(buildAppHash({ page: 'map', protocol: filters.protocol, filters }))}`, `关注车辆:${appURL(buildAppHash({ page: 'map', protocol: filters.protocol, filters: { ...filters, serviceStatus: 'degraded' } }))}`, selectedVIN ? `轨迹复盘:${appURL(buildAppHash({ page: 'history', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', `告警通知:${appURL(buildAppHash({ page: 'alert-events', filters: { serviceStatus: 'degraded' } }))}` ].filter(Boolean).join('\n'); } function buildRealtimeSourceCoverage(rows: VehicleRealtimeRow[]) { const sourceMap = new Map(); rows.forEach((row) => { const protocols = row.sourceStatus?.length ? row.sourceStatus.map((source) => source.protocol) : row.primaryProtocol ? [row.primaryProtocol] : []; protocols.forEach((protocol) => { const source = row.sourceStatus?.find((item) => item.protocol === protocol); const current = sourceMap.get(protocol) ?? { protocol, total: 0, online: 0, located: 0, degraded: 0, stale: 0 }; current.total += 1; current.online += (source ? source.online : row.online) ? 1 : 0; current.located += isValidCoordinate(row) ? 1 : 0; current.degraded += (!source || !source.online || !source.hasRealtime || row.onlineSourceCount < row.sourceCount) ? 1 : 0; current.stale += dataFreshness(row).stale ? 1 : 0; sourceMap.set(protocol, current); }); }); return [...sourceMap.values()].sort((left, right) => right.total - left.total || left.protocol.localeCompare(right.protocol)); } async function copyText(value: string, label: string) { const text = value.trim(); if (!text) { Toast.warning(`${label}为空`); return; } try { await navigator.clipboard.writeText(text); Toast.success(`已复制${label}`); } catch { Toast.error(`复制${label}失败`); } } export function Realtime({ mode = 'realtime', title = '实时监控', description = '以车辆为主对象查看最新位置、在线状态、核心实时数据和地图作业状态', onOpenVehicle, onOpenHistory, onOpenQuality, onFiltersChange, initialFilters = {} }: { mode?: 'realtime' | 'map'; title?: string; description?: string; onOpenVehicle: (vin: string, protocol?: string) => void; onOpenHistory?: (vin: string, protocol?: string) => void; onOpenQuality?: (filters: Record) => void; onFiltersChange?: (filters: Record) => void; initialFilters?: Record; }) { const [rows, setRows] = useState([]); const [loading, setLoading] = useState(true); const [filters, setFilters] = useState>(initialFilters); const [pagination, setPagination] = useState({ currentPage: 1, pageSize: 50, total: 0 }); const [opsHealth, setOpsHealth] = useState(null); const [selectedMapPointId, setSelectedMapPointId] = useState(''); const [lastRefreshAt, setLastRefreshAt] = useState(''); const [autoRefresh, setAutoRefresh] = useState(true); const [timeWindow, setTimeWindow] = useState(defaultTimeWindow); const refreshIntervalSeconds = 15; const amapConfig = getAMapConfig(); const runtime = opsHealth?.runtime; const amapConfigured = runtime?.amapWebJsConfigured ?? isAMapConfigured(amapConfig); const amapSecurityServiceHost = runtime?.amapSecurityServiceHost || amapConfig.securityServiceHost; const amapSecurityProxyEnabled = runtime?.amapSecurityProxyEnabled ?? Boolean(amapSecurityServiceHost); const amapSecurityCodeExposed = runtime?.amapSecurityCodeExposed ?? Boolean(amapConfig.securityJsCode && !amapSecurityServiceHost); const load = (values: Record = filters, page = pagination.currentPage, pageSize = pagination.pageSize) => { setLoading(true); const params = new URLSearchParams({ limit: String(pageSize), offset: String((page - 1) * pageSize) }); if (values?.keyword) params.set('keyword', values.keyword); if (values?.protocol) params.set('protocol', values.protocol); if (values?.online) params.set('online', values.online); if (values?.serviceStatus) params.set('serviceStatus', values.serviceStatus); return api.vehicleRealtime(params) .then((nextPage) => { setRows(nextPage.items); setPagination({ currentPage: page, pageSize, total: nextPage.total }); setLastRefreshAt(formatRefreshTime(new Date())); }) .catch((error: Error) => Toast.error(error.message)) .finally(() => setLoading(false)); }; useEffect(() => { setFilters(initialFilters); load(initialFilters, 1, pagination.pageSize); api.opsHealth() .then(setOpsHealth) .catch(() => setOpsHealth(null)); }, [JSON.stringify(initialFilters)]); useEffect(() => { if (!autoRefresh) { return undefined; } const timer = window.setInterval(() => { load(filters, pagination.currentPage, pagination.pageSize); }, refreshIntervalSeconds * 1000); return () => window.clearInterval(timer); }, [autoRefresh, JSON.stringify(filters), pagination.currentPage, pagination.pageSize]); const applyFilters = (nextFilters: Record) => { setFilters(nextFilters); onFiltersChange?.(nextFilters); load(nextFilters, 1, pagination.pageSize); }; const openQualityEvidence = (row: VehicleRealtimeRow) => { if (!canOpenVehicle(row.vin)) return; onOpenQuality?.({ keyword: row.vin, protocol: filters.protocol || row.primaryProtocol || '' }); }; const exportRealtime = () => { if (rows.length === 0) { Toast.warning('当前没有可导出的实时车辆'); return; } downloadCsv(realtimeExportFileName(filters), buildCsv(realtimeExportColumns, rows)); Toast.success(`已导出 ${rows.length} 条实时车辆`); }; const filterSummary = realtimeFilterSummary(filters); const onlineCount = rows.filter((row) => row.online).length; const locatedCount = rows.filter(isValidCoordinate).length; const degradedCount = rows.filter((row) => row.onlineSourceCount < row.sourceCount).length; const staleCount = rows.filter((row) => dataFreshness(row).stale).length; const onlineRate = rows.length > 0 ? (onlineCount / rows.length) * 100 : 0; const locatedRate = rows.length > 0 ? (locatedCount / rows.length) * 100 : 0; const degradedRate = rows.length > 0 ? (degradedCount / rows.length) * 100 : 0; const pageCoverageRate = pagination.total > 0 ? (rows.length / pagination.total) * 100 : 0; const primaryProtocols = new Set(rows.map((row) => row.primaryProtocol).filter(Boolean)); const sourceCoverageRows = buildRealtimeSourceCoverage(rows); const sourceIssueRows = rows .filter((row) => canOpenVehicle(row.vin) && hasSourceIssue(row)) .sort((a, b) => { const statusDelta = serviceStatusWeight(b) - serviceStatusWeight(a); if (statusDelta !== 0) return statusDelta; return String(b.lastSeen ?? '').localeCompare(String(a.lastSeen ?? '')); }) .slice(0, 4); const mapServiceRows = rows .filter((row) => isValidCoordinate(row) && canOpenVehicle(row.vin)) .sort((a, b) => { const statusDelta = serviceStatusWeight(b) - serviceStatusWeight(a); if (statusDelta !== 0) return statusDelta; return String(b.lastSeen ?? '').localeCompare(String(a.lastSeen ?? '')); }) .slice(0, 5); const defaultMapRow = mapServiceRows[0] ?? rows.find((row) => isValidCoordinate(row) && canOpenVehicle(row.vin)); const selectedMapRow = rows.find((row, index) => realtimeMapPointId(row, index) === selectedMapPointId) ?? defaultMapRow; const selectedMapPointKey = selectedMapRow ? realtimeMapPointId(selectedMapRow, rows.indexOf(selectedMapRow)) : selectedMapPointId; const timeWindowRow = selectedMapRow && canOpenVehicle(selectedMapRow.vin) ? selectedMapRow : rows.find((row) => canOpenVehicle(row.vin)); const timeWindowKeyword = timeWindowRow?.vin || filters.keyword || ''; const timeWindowProtocol = timeWindowRow ? filters.protocol || timeWindowRow.primaryProtocol || '' : filters.protocol || ''; const timeWindowReady = Boolean(timeWindowKeyword && timeWindow.dateFrom && timeWindow.dateTo); const timeWindowDuration = timeWindowDurationText(timeWindow.dateFrom, timeWindow.dateTo); const setTimeWindowPreset = (preset: '15m' | '1h' | 'today' | '24h') => { const end = new Date(); const start = new Date(end); if (preset === '15m') start.setMinutes(end.getMinutes() - 15); if (preset === '1h') start.setHours(end.getHours() - 1); if (preset === '24h') start.setDate(end.getDate() - 1); if (preset === 'today') { start.setHours(0, 0, 0, 0); } setTimeWindow({ dateFrom: formatDateTime(start), dateTo: formatDateTime(end) }); }; const timeWindowFilters = (extra: Record = {}) => ({ keyword: timeWindowKeyword, protocol: timeWindowProtocol, dateFrom: timeWindow.dateFrom, dateTo: timeWindow.dateTo, ...extra }); const openTimeWindowHistory = () => { if (!timeWindowReady) { Toast.warning('请先选择车辆和时间窗'); return; } window.location.hash = buildAppHash({ page: 'history', keyword: timeWindowKeyword, protocol: timeWindowProtocol, filters: timeWindowFilters() }); }; const openTimeWindowRaw = () => { if (!timeWindowReady) { Toast.warning('请先选择车辆和时间窗'); return; } window.location.hash = buildAppHash({ page: 'history-query', keyword: timeWindowKeyword, protocol: timeWindowProtocol, filters: timeWindowFilters({ tab: 'raw', includeFields: 'true' }) }); }; const openTimeWindowMileage = () => { if (!timeWindowReady) { Toast.warning('请先选择车辆和时间窗'); return; } window.location.hash = buildAppHash({ page: 'mileage', keyword: timeWindowKeyword, protocol: timeWindowProtocol, filters: timeWindowFilters() }); }; const openTimeWindowQuality = () => { if (!timeWindowReady || !onOpenQuality) { Toast.warning('请先选择车辆和时间窗'); return; } onOpenQuality(timeWindowFilters()); }; const copyTimeWindowPackage = () => copyText([ '【客户时间窗复盘包】', `车辆:${timeWindowRow ? [timeWindowRow.plate, timeWindowRow.vin].filter(Boolean).join(' / ') : timeWindowKeyword || '-'}`, `来源证据:${timeWindowProtocol || '全部来源证据'}`, `时间窗:${timeWindow.dateFrom} 至 ${timeWindow.dateTo}`, `时间窗判定:${timeWindowDuration}`, `实时状态:${timeWindowRow ? `${vehicleServiceStatus(timeWindowRow).label} / ${dataFreshness(timeWindowRow).detail}` : '未选车辆'}`, `轨迹回放:${timeWindowReady ? window.location.origin + window.location.pathname + buildAppHash({ page: 'history', keyword: timeWindowKeyword, protocol: timeWindowProtocol, filters: timeWindowFilters() }) : '-'}`, `历史数据:${timeWindowReady ? window.location.origin + window.location.pathname + buildAppHash({ page: 'history-query', keyword: timeWindowKeyword, protocol: timeWindowProtocol, filters: timeWindowFilters({ tab: 'raw', includeFields: 'true' }) }) : '-'}`, `里程统计:${timeWindowReady ? window.location.origin + window.location.pathname + buildAppHash({ page: 'mileage', keyword: timeWindowKeyword, protocol: timeWindowProtocol, filters: timeWindowFilters() }) : '-'}`, `告警通知:${timeWindowReady ? window.location.origin + window.location.pathname + buildAppHash({ page: 'alert-events', keyword: timeWindowKeyword, protocol: timeWindowProtocol, filters: timeWindowFilters() }) : '-'}` ].join('\n'), '客户时间窗复盘包'); const timeWindowWorkItems = [ { title: '轨迹回放', value: timeWindowDuration, detail: '按时间窗回放位置、速度、里程断点。', action: '打开轨迹', color: 'blue' as const, disabled: !timeWindowReady, onClick: openTimeWindowHistory }, { title: '历史数据', value: timeWindowProtocol || '全部通道', detail: '查看该时间窗内的历史明细和字段。', action: '查询历史', color: 'blue' as const, disabled: !timeWindowReady, onClick: openTimeWindowRaw }, { title: '里程统计', value: timeWindowRow?.totalMileageKm != null ? `${timeWindowRow.totalMileageKm} km` : '待核对', detail: '核对区间里程、日里程和总里程差值。', action: '查看统计', color: 'orange' as const, disabled: !timeWindowReady, onClick: openTimeWindowMileage }, { title: '告警通知', value: timeWindowRow ? realtimeIssueLabels(timeWindowRow)[0] : '待选择', detail: '查看时间窗内断链、离线、定位异常事件。', action: '查看告警', color: timeWindowRow && hasSourceIssue(timeWindowRow) ? 'orange' as const : 'green' as const, disabled: !timeWindowReady || !onOpenQuality, onClick: openTimeWindowQuality } ]; const timeWindowTaskItems = [ { step: '1', title: '锁定车辆', value: timeWindowRow?.plate || timeWindowKeyword || '未选择车辆', detail: timeWindowReady ? `${timeWindow.dateFrom} 至 ${timeWindow.dateTo}` : '先从实时列表或地图选择车辆,再确认时间窗。', action: timeWindowReady ? '已锁定' : '先选车辆', color: timeWindowReady ? 'green' as const : 'orange' as const, disabled: false, onClick: () => { if (!timeWindowReady) { Toast.warning('请先选择车辆和时间窗'); } } }, { step: '2', title: '轨迹复盘', value: timeWindowDuration, detail: '回放位置、速度、里程断点和停留变化。', action: '轨迹回放', color: 'blue' as const, disabled: !timeWindowReady, onClick: openTimeWindowHistory }, { step: '3', title: '里程核对', value: timeWindowRow?.totalMileageKm != null ? `${timeWindowRow.totalMileageKm} km` : '待核对', detail: '用同一时间窗进入里程统计,核对区间差值和日统计闭合。', action: '里程统计', color: timeWindowRow?.totalMileageKm != null ? 'blue' as const : 'orange' as const, disabled: !timeWindowReady, onClick: openTimeWindowMileage }, { step: '4', title: '历史导出', value: timeWindowProtocol || '全部通道', detail: '导出位置、原始帧和字段证据,支撑客户问询。', action: '导出证据', color: 'blue' as const, disabled: !timeWindowReady, onClick: openTimeWindowRaw }, { step: '5', title: '告警闭环', value: timeWindowRow ? vehicleServiceStatus(timeWindowRow).label : '待选择', detail: '复盘断链、离线、定位异常和通知处理记录。', action: '告警复盘', color: timeWindowRow && hasSourceIssue(timeWindowRow) ? 'orange' as const : timeWindowReady ? 'green' as const : 'grey' as const, disabled: !timeWindowReady || !onOpenQuality, onClick: openTimeWindowQuality } ]; const mapPoints: VehicleMapPoint[] = rows.map((row, index) => ({ id: realtimeMapPointId(row, index), label: row.plate || row.vin || 'unknown', longitude: row.longitude, latitude: row.latitude, online: row.online, title: `${row.plate || row.vin || '-'} ${vehicleServiceStatus(row).label} ${row.primaryProtocol || ''} ${row.lastSeen || ''}` })); const mapIntegrationRows = [ { label: 'Web JS Key', value: amapConfigured ? '已配置' : '未配置', color: amapConfigured ? 'green' as const : 'orange' as const, detail: amapConfigured ? '前端可加载高德 Web JS API。' : '缺少公开 Key,地图将使用坐标预览。' }, { label: '服务端 API Key', value: runtime?.amapApiConfigured ? '已配置' : '未配置', color: runtime?.amapApiConfigured ? 'green' as const : 'orange' as const, detail: runtime?.amapApiConfigured ? '后端可支持地理编码、路线、围栏等服务端地图能力。' : '服务端地图能力未配置,后续地理服务会降级。' }, { label: '安全代理', value: amapSecurityServiceHost || '未启用', color: amapSecurityProxyEnabled ? 'green' as const : 'grey' as const, detail: amapSecurityProxyEnabled ? '安全密钥由服务端追加,不下发到浏览器。' : '未配置代理时会退回前端安全码模式。' }, { label: '安全码', value: amapSecurityCodeExposed ? '已暴露' : '未暴露', color: amapSecurityCodeExposed ? 'red' as const : 'green' as const, detail: amapSecurityCodeExposed ? '当前安全码会下发到浏览器,只建议调试使用。' : '生产安全码保持在服务端环境变量中。' }, { label: '当前版本', value: runtime?.platformRelease || '未标记', color: runtime?.platformRelease ? 'blue' as const : 'grey' as const, detail: runtime?.platformRelease ? '当前 ECS 正在运行的车辆中台 release。' : '未注入 PLATFORM_RELEASE,部署追踪会降级。' }, { label: '定位覆盖', value: `${locatedCount.toLocaleString()} / ${rows.length.toLocaleString()}`, color: locatedCount > 0 ? 'blue' as const : 'orange' as const, detail: '当前页有效经纬度车辆数。' }, { label: '高德 URI', value: '坐标跳转', color: 'blue' as const, detail: '车辆队列可直接打开高德坐标,轨迹页可打开线路。' } ]; const copyRealtimeSummary = () => copyText(realtimeOperationsSummaryText({ filters, rows, total: pagination.total, onlineCount, locatedCount, degradedCount, sourceTypeCount: primaryProtocols.size, amapConfigured, sourceIssueRows }), '实时摘要'); const copyRealtimeIssueChecklist = () => copyText(realtimeIssueChecklistText({ filters, rows, total: pagination.total }), '实时异常处置清单'); const copyRealtimeDutyHandoff = () => copyText(realtimeDutyHandoffText({ filters, rows, total: pagination.total, onlineCount, locatedCount, degradedCount, staleCount, sourceTypeCount: primaryProtocols.size, amapConfigured, runtimeRelease: runtime?.platformRelease }), '车辆监控交付包'); const realtimeImpactLevel = degradedCount > 0 || staleCount > 0 || rows.length - onlineCount > 0 ? '需要处置' : '实时稳定'; const realtimeImpactColor = realtimeImpactLevel === '实时稳定' ? 'green' as const : degradedCount > 0 || staleCount > 0 ? 'orange' as const : 'blue' as const; const realtimeImpactItems = [ { label: '车辆范围', value: `${rows.length.toLocaleString()} / ${pagination.total.toLocaleString()}`, detail: `当前页覆盖 ${formatPercent(pageCoverageRate)}`, color: pageCoverageRate >= 100 ? 'green' as const : 'grey' as const }, { label: '在线影响', value: `${onlineCount.toLocaleString()} 在线`, detail: `${(rows.length - onlineCount).toLocaleString()} 辆离线`, color: rows.length - onlineCount > 0 ? 'orange' as const : 'green' as const }, { label: '定位影响', value: `${locatedCount.toLocaleString()} 辆`, detail: `有效定位率 ${formatPercent(locatedRate)}`, color: locatedCount > 0 ? 'blue' as const : 'orange' as const }, { label: '服务影响', value: `${degradedCount.toLocaleString()} 降级`, detail: `${staleCount.toLocaleString()} 辆更新超时`, color: degradedCount > 0 || staleCount > 0 ? 'orange' as const : 'green' as const }, { label: '地图能力', value: amapConfigured ? '可用' : '坐标预览', detail: amapConfigured ? '高德地图配置就绪' : '高德未配置,页面降级展示坐标。', color: amapConfigured ? 'green' as const : 'orange' as const } ]; const copyRealtimeImpact = () => copyText(realtimeImpactReportText({ filters, rows, total: pagination.total, onlineCount, locatedCount, degradedCount, staleCount, pageCoverageRate, amapConfigured, runtimeRelease: runtime?.platformRelease }), '车辆监控影响'); const selectRealtimeRow = (row: VehicleRealtimeRow) => { const index = rows.indexOf(row); if (index < 0) return; setSelectedMapPointId(realtimeMapPointId(row, index)); }; const selectRealtimeMapPoint = (point: VehicleMapPoint) => { setSelectedMapPointId(point.id); }; const mapAttentionRows = rows .filter((row) => canOpenVehicle(row.vin) && (dataFreshness(row).stale || !isValidCoordinate(row) || hasSourceIssue(row))) .sort((a, b) => serviceStatusWeight(b) - serviceStatusWeight(a) || String(b.lastSeen ?? '').localeCompare(String(a.lastSeen ?? ''))) .slice(0, 8); const mapFleetKpis = [ { label: '车辆总数', value: pagination.total.toLocaleString(), color: 'blue' as const, helper: `当前页 ${rows.length.toLocaleString()} 辆` }, { label: '在线车辆', value: onlineCount.toLocaleString(), color: onlineCount > 0 ? 'green' as const : 'orange' as const, helper: `在线率 ${formatPercent(onlineRate)}` }, { label: '有效定位', value: locatedCount.toLocaleString(), color: locatedCount > 0 ? 'green' as const : 'orange' as const, helper: `定位率 ${formatPercent(locatedRate)}` }, { label: '需关注', value: mapAttentionRows.length.toLocaleString(), color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, helper: `${staleCount.toLocaleString()} 辆更新超时` } ]; const realtimePriorityRows = mapAttentionRows.slice(0, 4); const realtimePrioritySummary = realtimePriorityRows.length > 0 ? `${realtimePriorityRows.length.toLocaleString()} 辆优先处置` : '暂无阻断'; const missingCoordinateCount = Math.max(0, rows.length - locatedCount); const noCoordinateRows = rows.filter((row) => !isValidCoordinate(row)); const selectedVehicleProtocol = selectedMapRow ? filters.protocol || selectedMapRow.primaryProtocol || '' : ''; const selectedVehicleLabel = selectedMapRow?.plate || selectedMapRow?.vin || '未选择车辆'; const mapStatusFilterItems = [ { label: '在线车辆', value: `${onlineCount.toLocaleString()} 在线`, detail: `在线率 ${formatPercent(onlineRate)},客户当前可实时看车。`, color: onlineCount > 0 ? 'green' as const : 'orange' as const, onClick: () => applyFilters({ ...filters, online: 'online' }) }, { label: '离线车辆', value: `${Math.max(0, rows.length - onlineCount).toLocaleString()} 离线`, detail: '优先判断平台是否仍在转发,或车辆是否停止上报。', color: rows.length - onlineCount > 0 ? 'orange' as const : 'green' as const, onClick: () => applyFilters({ ...filters, online: 'offline' }) }, { label: '无坐标车辆', value: `${missingCoordinateCount.toLocaleString()} 无坐标`, detail: '没有有效经纬度时,地图、轨迹和围栏都需要先复核。', color: missingCoordinateCount > 0 ? 'orange' as const : 'green' as const, onClick: () => { const firstNoCoordinate = noCoordinateRows.find((row) => canOpenVehicle(row.vin)); if (firstNoCoordinate) { selectRealtimeRow(firstNoCoordinate); return; } load(filters, pagination.currentPage, pagination.pageSize); } }, { label: '需关注车辆', value: `${mapAttentionRows.length.toLocaleString()} 关注`, detail: mapAttentionRows[0] ? `${mapAttentionRows[0].plate || mapAttentionRows[0].vin}:${realtimeIssueLabels(mapAttentionRows[0]).join(';')}` : '当前筛选下暂无离线、超时或通道异常。', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, onClick: () => applyFilters({ ...filters, serviceStatus: 'degraded' }) } ]; const openSelectedVehicleRaw = () => { if (!selectedMapRow || !canOpenVehicle(selectedMapRow.vin)) { Toast.warning('请先选择可查询的车辆'); return; } window.location.hash = buildAppHash({ page: 'history-query', keyword: selectedMapRow.vin, protocol: selectedVehicleProtocol, filters: { tab: 'raw', includeFields: 'true' } }); }; const copySelectedMapVehicleHandoff = () => { if (!selectedMapRow || !canOpenVehicle(selectedMapRow.vin)) { Toast.warning('请先选择可交接的车辆'); return; } copyText(selectedMapVehicleHandoffText(selectedMapRow, selectedVehicleProtocol), '选中车辆交接卡'); }; const mapVehicleWorkItems = [ { title: '车辆服务', value: selectedVehicleLabel, detail: selectedMapRow ? '查看车辆画像、数据通道状态和最新实时字段。' : '先从地图或车辆列表选择一辆车。', action: '车辆档案', color: selectedMapRow ? vehicleServiceStatus(selectedMapRow).color : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenVehicle(selectedMapRow.vin, selectedVehicleProtocol) }, { title: '轨迹复盘', value: selectedMapRow ? dataFreshness(selectedMapRow).detail : '等待选择', detail: '复核位置、速度、里程和断点,支撑客户问询。', action: '打开轨迹', color: selectedMapRow ? dataFreshness(selectedMapRow).color : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { title: '里程统计', value: selectedMapRow?.totalMileageKm != null ? `${selectedMapRow.totalMileageKm} km` : '无里程', detail: '进入单车里程统计,核对日里程和区间差值。', action: '里程统计', color: selectedMapRow?.totalMileageKm != null ? 'blue' as const : 'orange' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => { if (!selectedMapRow) return; window.location.hash = buildAppHash({ page: 'mileage', keyword: selectedMapRow.vin, protocol: selectedVehicleProtocol }); } }, { title: '告警处置', value: selectedMapRow ? realtimeIssueLabels(selectedMapRow)[0] : '等待选择', detail: '围绕选中车辆查看断链、离线、定位异常等事件。', action: '查看告警', color: selectedMapRow && hasSourceIssue(selectedMapRow) ? 'orange' as const : selectedMapRow ? 'green' as const : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin) || !onOpenQuality, onClick: () => selectedMapRow && onOpenQuality?.({ keyword: selectedMapRow.vin, protocol: selectedVehicleProtocol }) } ]; const mapCustomerTasks = [ { title: '实时盯车', value: `${onlineCount.toLocaleString()} 在线`, detail: '先看在线车辆和有效定位,确认客户当前能看到车在哪里。', color: 'green' as const, primaryAction: '只看在线', secondaryAction: '刷新地图', onPrimary: () => applyFilters({ ...filters, online: 'online' }), onSecondary: () => load(filters, pagination.currentPage, pagination.pageSize), disabled: false, secondaryDisabled: false }, { title: '异常优先', value: `${mapAttentionRows.length.toLocaleString()} 辆关注`, detail: mapAttentionRows[0] ? `${mapAttentionRows[0].plate || mapAttentionRows[0].vin}:${realtimeIssueLabels(mapAttentionRows[0]).join(';')}` : '当前筛选下暂无需要关注的车辆。', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, primaryAction: '关注车辆', secondaryAction: '告警事件', onPrimary: () => applyFilters({ ...filters, serviceStatus: 'degraded' }), onSecondary: () => onOpenQuality?.({ serviceStatus: 'degraded' }), disabled: !onOpenQuality && mapAttentionRows.length === 0, secondaryDisabled: !onOpenQuality }, { title: '轨迹复盘', value: selectedMapRow?.plate || selectedMapRow?.vin || '未选车辆', detail: selectedMapRow ? `围绕 ${selectedMapRow.plate || selectedMapRow.vin} 回放位置、速度和里程变化。` : '从地图或车辆队列选择一辆车后回放轨迹。', color: selectedMapRow ? 'blue' as const : 'grey' as const, primaryAction: '轨迹回放', secondaryAction: '车辆档案', disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onPrimary: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol), onSecondary: () => selectedMapRow && onOpenVehicle(selectedMapRow.vin, selectedVehicleProtocol), secondaryDisabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin) }, { title: '查询导出', value: `${rows.length.toLocaleString()} 辆当前页`, detail: '导出当前车辆清单,或进入选中车辆的历史查询。', color: 'blue' as const, primaryAction: '导出当前页', secondaryAction: '历史查询', onPrimary: exportRealtime, onSecondary: openSelectedVehicleRaw, disabled: false, secondaryDisabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin) } ]; const mapServiceActionItems = [ { title: '在线车辆', value: `${onlineCount.toLocaleString()} 在线`, detail: `在线率 ${formatPercent(onlineRate)},先确认客户当前能看到哪些车。`, action: '只看在线', color: onlineCount > 0 ? 'green' as const : 'orange' as const, disabled: false, onClick: () => applyFilters({ ...filters, online: 'online' }) }, { title: '关注车辆', value: `${mapAttentionRows.length.toLocaleString()} 关注`, detail: mapAttentionRows[0] ? `${mapAttentionRows[0].plate || mapAttentionRows[0].vin}:${realtimeIssueLabels(mapAttentionRows[0]).join(';')}` : '当前没有明显离线、超时或坐标异常车辆。', action: '异常优先', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, disabled: false, onClick: () => applyFilters({ ...filters, serviceStatus: 'degraded' }) }, { title: '路线回放', value: selectedMapRow?.plate || selectedMapRow?.vin || '先选车', detail: selectedMapRow ? `${dataFreshness(selectedMapRow).detail},回放位置、速度和里程变化。` : '从地图或车辆列表选择一辆车后进入轨迹回放。', action: '轨迹回放', color: selectedMapRow ? 'blue' as const : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { title: '里程统计', value: selectedMapRow?.totalMileageKm != null ? `${selectedMapRow.totalMileageKm} km` : '待选车', detail: '按选中车辆进入里程统计,核对区间里程和日报闭合。', action: '里程统计', color: selectedMapRow?.totalMileageKm != null ? 'blue' as const : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => { if (!selectedMapRow) return; window.location.hash = buildAppHash({ page: 'mileage', keyword: selectedMapRow.vin, protocol: selectedVehicleProtocol }); } }, { title: '证据导出', value: `${rows.length.toLocaleString()} 当前页`, detail: '导出当前地图车辆清单,作为客户问询和运营交接证据。', action: '导出CSV', color: rows.length > 0 ? 'blue' as const : 'grey' as const, disabled: rows.length === 0, onClick: exportRealtime } ]; const mapShiftTimeWindowLabel = timeWindowDuration === '1 天窗口' ? '24 小时窗口' : timeWindowDuration; const mapCommandTaskItems = [ { label: '实时监控', value: `${onlineCount.toLocaleString()} 在线`, detail: `${locatedCount.toLocaleString()} 辆有定位,${staleCount.toLocaleString()} 辆更新超时。`, color: onlineCount > 0 ? 'green' as const : 'orange' as const, disabled: false, onClick: () => applyFilters({ ...filters, online: 'online' }) }, { label: '轨迹回放', value: selectedMapRow?.plate || selectedMapRow?.vin || '先选车', detail: selectedMapRow ? `${dataFreshness(selectedMapRow).detail},回放位置、速度和里程。` : '从地图或车辆列表选择一辆车。', color: selectedMapRow ? 'blue' as const : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { label: '历史查询', value: selectedVehicleProtocol || '全部来源', detail: '查看位置、原始帧和解析字段,支撑客户复核。', color: 'blue' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: openSelectedVehicleRaw }, { label: '告警通知', value: `${mapAttentionRows.length.toLocaleString()} 关注`, detail: mapAttentionRows[0] ? `${mapAttentionRows[0].plate || mapAttentionRows[0].vin}:${realtimeIssueLabels(mapAttentionRows[0]).join(';')}` : '当前筛选下暂无关注车辆。', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, disabled: !onOpenQuality, onClick: () => onOpenQuality?.(selectedMapRow && canOpenVehicle(selectedMapRow.vin) ? { keyword: selectedMapRow.vin, protocol: selectedVehicleProtocol } : { serviceStatus: 'degraded' }) }, { label: '统计导出', value: `${rows.length.toLocaleString()} 辆`, detail: '进入里程统计,或导出当前地图车辆清单。', color: 'blue' as const, disabled: rows.length === 0, onClick: exportRealtime } ]; const mapSelectedServiceItems = [ { label: '车辆档案', action: '查看车辆', detail: selectedVehicleLabel, color: selectedMapRow ? vehicleServiceStatus(selectedMapRow).color : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenVehicle(selectedMapRow.vin, selectedVehicleProtocol) }, { label: '轨迹回放', action: '回放轨迹', detail: selectedMapRow ? dataFreshness(selectedMapRow).detail : '等待选择', color: selectedMapRow ? 'blue' as const : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { label: '历史数据', action: '查询历史', detail: selectedVehicleProtocol || '全部来源', color: 'blue' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: openSelectedVehicleRaw }, { label: '告警通知', action: '查看告警', detail: selectedMapRow ? realtimeIssueLabels(selectedMapRow)[0] : '等待选择', color: selectedMapRow && hasSourceIssue(selectedMapRow) ? 'orange' as const : selectedMapRow ? 'green' as const : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin) || !onOpenQuality, onClick: () => selectedMapRow && onOpenQuality?.({ keyword: selectedMapRow.vin, protocol: selectedVehicleProtocol }) }, { label: '交接卡', action: '复制交接', detail: selectedMapRow ? realtimeIssueLabels(selectedMapRow)[0] : '等待选择', color: 'blue' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: copySelectedMapVehicleHandoff } ]; const mapShiftConsoleItems = [ { label: '今日态势', value: `${onlineCount.toLocaleString()} 在线 / ${mapAttentionRows.length.toLocaleString()} 关注`, detail: `当前页 ${rows.length.toLocaleString()} 辆,定位有效率 ${formatPercent(locatedRate)}。`, action: '只看在线', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, disabled: false, onClick: () => applyFilters({ ...filters, online: 'online' }) }, { label: '优先车辆', value: mapAttentionRows[0]?.plate || mapAttentionRows[0]?.vin || selectedVehicleLabel, detail: mapAttentionRows[0] ? realtimeIssueLabels(mapAttentionRows[0]).join(';') : '当前没有必须优先处理的车辆。', action: '处理关注', color: mapAttentionRows.length > 0 ? 'orange' as const : selectedMapRow ? vehicleServiceStatus(selectedMapRow).color : 'grey' as const, disabled: !mapAttentionRows[0] && !selectedMapRow, onClick: () => { if (mapAttentionRows[0]) { selectRealtimeRow(mapAttentionRows[0]); return; } if (selectedMapRow) { selectRealtimeRow(selectedMapRow); } } }, { label: '时间窗复盘', value: mapShiftTimeWindowLabel, detail: timeWindowRow ? `${timeWindowRow.plate || timeWindowRow.vin} / ${timeWindowProtocol || '全部来源证据'}` : '先选择一辆车再复盘。', action: '打开轨迹', color: timeWindowReady ? 'blue' as const : 'orange' as const, disabled: !timeWindowReady, onClick: openTimeWindowHistory }, { label: '交接说明', value: '可复制', detail: mapAttentionRows.length > 0 ? '交接时先说明关注车辆和处理入口。' : '地图态势稳定,可直接复制交接口径。', action: '复制交接', color: 'blue' as const, disabled: false, onClick: copyRealtimeDutyHandoff } ]; const mapFieldCommandItems = [ { title: '全域定位', value: `${locatedCount.toLocaleString()} 辆有坐标`, detail: amapConfigured ? '用高德地图查看车辆分布、在线状态和最近上报位置。' : '高德不可用时先用坐标预览确认车辆分布。', color: locatedCount > 0 ? 'blue' as const : 'orange' as const, action: '刷新地图', disabled: false, onClick: () => load(filters, pagination.currentPage, pagination.pageSize) }, { title: '关注车辆', value: mapAttentionRows.length > 0 ? `${mapAttentionRows.length.toLocaleString()} 辆待处理` : '暂无异常', detail: mapAttentionRows[0] ? `${mapAttentionRows[0].plate || mapAttentionRows[0].vin}:${realtimeIssueLabels(mapAttentionRows[0]).join(';')}` : '当前筛选下车辆在线、定位和新鲜度未形成主要风险。', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, action: '定位关注车', disabled: mapAttentionRows.length === 0, onClick: () => mapAttentionRows[0] && selectRealtimeRow(mapAttentionRows[0]) }, { title: '轨迹复盘', value: selectedVehicleLabel, detail: selectedMapRow ? '打开选中车辆轨迹,核对路径、速度、里程和停留。' : '先选择车辆,再进入轨迹回放和时间窗复盘。', color: selectedMapRow ? 'blue' as const : 'grey' as const, action: '打开轨迹', disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { title: '通知证据', value: mapAttentionRows.length > 0 ? '需通知' : '可交付', detail: mapAttentionRows.length > 0 ? '复制地图监控包后进入告警事件,形成通知和处置闭环。' : '地图态势稳定时,可直接复制地图监控包用于交接。', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, action: mapAttentionRows.length > 0 ? '告警事件' : '复制监控包', disabled: false, onClick: () => mapAttentionRows.length > 0 && onOpenQuality ? onOpenQuality({ serviceStatus: 'degraded' }) : copyMapCustomerPackage() } ]; const copyMapAreaMonitor = () => copyText(mapAreaMonitorText({ filters, rows, locatedCount, attentionCount: mapAttentionRows.length, selectedRow: selectedMapRow, selectedProtocol: selectedVehicleProtocol, amapConfigured }), '区域围栏监控说明'); const mapAreaMonitorItems = [ { title: '电子围栏', value: `${locatedCount.toLocaleString()} 辆可定位`, detail: '先把有效定位车辆作为围栏覆盖基础,后续按区域配置越界和进出围栏规则。', color: locatedCount > 0 ? 'blue' as const : 'orange' as const, action: '关注车辆', disabled: false, onClick: () => applyFilters({ ...filters, serviceStatus: 'degraded' }) }, { title: '停留超时', value: selectedVehicleLabel, detail: selectedMapRow ? '围绕选中车辆回放轨迹,识别停留、低速和异常时间窗。' : '先选择车辆,再进入轨迹复盘判断停留时长。', color: selectedMapRow ? 'blue' as const : 'grey' as const, action: '轨迹复盘', disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { title: '越界通知', value: mapAttentionRows.length > 0 ? `${mapAttentionRows.length.toLocaleString()} 辆关注` : '暂无越界', detail: mapAttentionRows.length > 0 ? '将离线、超时、坐标异常车辆交给告警事件形成通知闭环。' : '当前区域态势稳定,可继续巡检。', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, action: '告警事件', disabled: !onOpenQuality, onClick: () => onOpenQuality?.({ serviceStatus: 'degraded' }) }, { title: '区域报表', value: `${rows.length.toLocaleString()} 辆当前页`, detail: '复制区域监控说明,交付当前围栏态势、关注车辆和后续通知链接。', color: 'blue' as const, action: '复制说明', disabled: false, onClick: copyMapAreaMonitor } ]; const mapDispatchActionItems = [ { title: '关注车辆', value: `${mapAttentionRows.length.toLocaleString()} 辆`, detail: mapAttentionRows[0] ? `${mapAttentionRows[0].plate || mapAttentionRows[0].vin}:${realtimeIssueLabels(mapAttentionRows[0]).join(';')}` : '当前地图范围没有需要立即处置的车辆。', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, action: '告警事件', disabled: mapAttentionRows.length === 0 || !onOpenQuality, onClick: () => onOpenQuality?.({ serviceStatus: 'degraded' }) }, { title: '复盘选中', value: selectedVehicleLabel, detail: selectedMapRow ? `${dataFreshness(selectedMapRow).detail},回放轨迹和里程变化。` : '先从地图或列表选择车辆。', color: selectedMapRow ? dataFreshness(selectedMapRow).color : 'grey' as const, action: '轨迹回放', disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { title: '车辆档案', value: selectedVehicleLabel, detail: selectedMapRow ? `${vehicleServiceStatus(selectedMapRow).label},查看车辆画像和来源证据。` : '选择车辆后进入单车服务。', color: selectedMapRow ? vehicleServiceStatus(selectedMapRow).color : 'grey' as const, action: '车辆服务', disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenVehicle(selectedMapRow.vin, selectedVehicleProtocol) }, { title: '交接证据', value: `${rows.length.toLocaleString()} 辆`, detail: '导出当前地图车辆清单,交接给客户或运营人员继续处理。', color: rows.length > 0 ? 'blue' as const : 'grey' as const, action: '导出CSV', disabled: rows.length === 0, onClick: exportRealtime } ]; const mapCustomerDecisionItems = [ { label: '先看在线', value: `${onlineCount.toLocaleString()} 在线`, detail: `${(rows.length - onlineCount).toLocaleString()} 辆离线,先确认客户能看到哪些车还在上报。`, color: onlineCount > 0 ? 'green' as const : 'orange' as const, action: '只看在线', onClick: () => applyFilters({ ...filters, online: 'online' }) }, { label: '再看定位', value: `${locatedCount.toLocaleString()} 有坐标`, detail: `${missingCoordinateCount.toLocaleString()} 辆无有效坐标,地图可视范围决定客户能否看车。`, color: locatedCount > 0 ? 'blue' as const : 'orange' as const, action: '地图态势', onClick: () => load(filters, pagination.currentPage, pagination.pageSize) }, { label: '优先异常', value: `${mapAttentionRows.length.toLocaleString()} 关注`, detail: mapAttentionRows[0] ? `${mapAttentionRows[0].plate || mapAttentionRows[0].vin}:${realtimeIssueLabels(mapAttentionRows[0]).join(';')}` : '当前没有明显离线、超时或坐标异常车辆。', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, action: '告警事件', onClick: () => onOpenQuality?.({ serviceStatus: 'degraded' }) }, { label: '选车复盘', value: selectedVehicleLabel, detail: selectedMapRow ? `${vehicleServiceStatus(selectedMapRow).label},${dataFreshness(selectedMapRow).detail}` : '从地图或车辆列表选择一辆车后进入轨迹、里程统计和历史查询。', color: selectedMapRow ? vehicleServiceStatus(selectedMapRow).color : 'grey' as const, action: '轨迹回放', disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) } ]; const mapViewModeItems = [ { label: '车辆总览', value: `${rows.length.toLocaleString()} 辆`, detail: `在线 ${onlineCount.toLocaleString()},有效定位 ${locatedCount.toLocaleString()},先确认客户能看到的车辆范围。`, action: '当前页', color: 'blue' as const, disabled: false, onClick: () => load(filters, pagination.currentPage, pagination.pageSize) }, { label: '异常优先', value: `${mapAttentionRows.length.toLocaleString()} 辆`, detail: mapAttentionRows[0] ? `${mapAttentionRows[0].plate || mapAttentionRows[0].vin}:${realtimeIssueLabels(mapAttentionRows[0]).join(';')}` : '当前筛选下暂无离线、定位或通道异常车辆。', action: '关注车辆', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, disabled: false, onClick: () => applyFilters({ ...filters, serviceStatus: 'degraded' }) }, { label: '轨迹复盘', value: selectedVehicleLabel, detail: selectedMapRow ? '围绕选中车辆进入轨迹、统计和历史查询。' : '从地图或车辆列表选择一辆车后复盘。', action: '选中车辆', color: selectedMapRow ? 'blue' as const : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { label: '交付导出', value: `${rows.length.toLocaleString()} 辆`, detail: '导出当前地图车辆清单、在线状态和客户交付证据。', action: '导出证据', color: rows.length > 0 ? 'blue' as const : 'grey' as const, disabled: rows.length === 0, onClick: exportRealtime } ]; const mapCustomerPackageItems = [ { label: '车辆范围', value: `${rows.length.toLocaleString()} / ${pagination.total.toLocaleString()}`, detail: `当前筛选覆盖 ${formatPercent(pageCoverageRate)}`, color: pageCoverageRate >= 100 ? 'green' as const : 'blue' as const }, { label: '在线态势', value: `${onlineCount.toLocaleString()} 在线`, detail: `${(rows.length - onlineCount).toLocaleString()} 辆离线`, color: rows.length - onlineCount > 0 ? 'orange' as const : 'green' as const }, { label: '定位态势', value: `${locatedCount.toLocaleString()} 有坐标`, detail: `定位率 ${formatPercent(locatedRate)}`, color: locatedCount > 0 ? 'green' as const : 'orange' as const }, { label: '关注车辆', value: `${mapAttentionRows.length.toLocaleString()} 辆`, detail: `${staleCount.toLocaleString()} 辆更新超时`, color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const }, { label: '选中车辆', value: selectedVehicleLabel, detail: selectedMapRow ? `${vehicleServiceStatus(selectedMapRow).label} / ${dataFreshness(selectedMapRow).detail}` : '从地图或车辆列表选择', color: selectedMapRow ? vehicleServiceStatus(selectedMapRow).color : 'grey' as const } ]; const liveMapDecisionItems = [ { label: '在线覆盖', value: `${onlineCount.toLocaleString()} / ${rows.length.toLocaleString()}`, detail: `${(rows.length - onlineCount).toLocaleString()} 辆离线,在线率 ${formatPercent(onlineRate)}。`, color: onlineCount > 0 ? 'green' as const : 'orange' as const, onClick: () => applyFilters({ ...filters, online: 'online' }) }, { label: '定位覆盖', value: `${locatedCount.toLocaleString()} / ${rows.length.toLocaleString()}`, detail: `${missingCoordinateCount.toLocaleString()} 辆无坐标,定位率 ${formatPercent(locatedRate)}。`, color: locatedCount > 0 ? 'blue' as const : 'orange' as const, onClick: () => load(filters, pagination.currentPage, pagination.pageSize) }, { label: '优先处理', value: `${mapAttentionRows.length.toLocaleString()} 关注`, detail: mapAttentionRows[0] ? `${mapAttentionRows[0].plate || mapAttentionRows[0].vin}:${realtimeIssueLabels(mapAttentionRows[0]).join(';')}` : '当前没有离线、超时或定位异常车辆。', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, onClick: () => { if (mapAttentionRows[0]) { selectRealtimeRow(mapAttentionRows[0]); return; } applyFilters({ ...filters, serviceStatus: 'degraded' }); } }, { label: '当前选车', value: selectedVehicleLabel, detail: selectedMapRow ? `${vehicleServiceStatus(selectedMapRow).label} / ${dataFreshness(selectedMapRow).detail}` : '从地图或车辆列表选择车辆。', color: selectedMapRow ? vehicleServiceStatus(selectedMapRow).color : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenVehicle(selectedMapRow.vin, selectedVehicleProtocol) } ]; const liveMapDecisionActions = [ { label: '只看在线', action: '在线', color: 'green' as const, disabled: false, onClick: () => applyFilters({ ...filters, online: 'online' }) }, { label: '定位关注', action: '关注车', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, disabled: mapAttentionRows.length === 0, onClick: () => mapAttentionRows[0] && selectRealtimeRow(mapAttentionRows[0]) }, { label: '轨迹复盘', action: '轨迹', color: selectedMapRow ? 'blue' as const : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { label: '导出地图', action: 'CSV', color: rows.length > 0 ? 'blue' as const : 'grey' as const, disabled: rows.length === 0, onClick: exportRealtime } ]; const mapLayerControlItems = [ { label: '在线车辆', value: `${onlineCount.toLocaleString()} 在线`, detail: '只看当前还能实时服务的车辆,适合客户查看在线态势。', color: onlineCount > 0 ? 'green' as const : 'orange' as const, onClick: () => applyFilters({ ...filters, online: 'online' }) }, { label: '关注车辆', value: `${mapAttentionRows.length.toLocaleString()} 关注`, detail: mapAttentionRows[0] ? `优先车辆 ${mapAttentionRows[0].plate || mapAttentionRows[0].vin}` : '当前没有离线、超时或通道异常车辆。', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, onClick: () => mapAttentionRows[0] ? selectRealtimeRow(mapAttentionRows[0]) : applyFilters({ ...filters, serviceStatus: 'degraded' }) }, { label: '定位车辆', value: `${locatedCount.toLocaleString()} 定位`, detail: `有效定位率 ${formatPercent(locatedRate)},决定地图、轨迹和围栏是否可用。`, color: locatedCount > 0 ? 'blue' as const : 'orange' as const, onClick: () => load(filters, pagination.currentPage, pagination.pageSize) }, { label: '选中车辆', value: selectedVehicleLabel, detail: selectedMapRow ? '进入单车服务、轨迹、统计、历史和告警。' : '从地图或车辆列表选择一辆车。', color: selectedMapRow ? vehicleServiceStatus(selectedMapRow).color : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenVehicle(selectedMapRow.vin, selectedVehicleProtocol) } ]; const mapLayerControlActions = [ { label: '只看在线', action: '在线层', color: 'green' as const, disabled: false, onClick: () => applyFilters({ ...filters, online: 'online' }) }, { label: '优先关注', action: '关注层', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, disabled: mapAttentionRows.length === 0, onClick: () => mapAttentionRows[0] && selectRealtimeRow(mapAttentionRows[0]) }, { label: '选车服务', action: '服务层', color: selectedMapRow ? 'blue' as const : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenVehicle(selectedMapRow.vin, selectedVehicleProtocol) }, { label: '导出态势', action: '交付层', color: rows.length > 0 ? 'blue' as const : 'grey' as const, disabled: rows.length === 0, onClick: exportRealtime } ]; const copyMapCustomerPackage = () => copyText(mapCustomerPackageText({ filters, rows, total: pagination.total, onlineCount, locatedCount, attentionCount: mapAttentionRows.length, staleCount, selectedRow: selectedMapRow, selectedProtocol: selectedVehicleProtocol, amapConfigured }), '客户地图监控包'); const copyMapExecutiveControlPackage = () => copyText(mapExecutiveControlPackageText({ filters, rows, total: pagination.total, onlineCount, locatedCount, attentionCount: mapAttentionRows.length, selectedRow: selectedMapRow, selectedProtocol: selectedVehicleProtocol, amapConfigured }), '客户车辆地图总控包'); const copyMapFleetJourneyPackage = () => copyText([ '【车队服务旅程交付包】', `当前筛选:${realtimeFilterSummary(filters).join(';') || '全部车辆'}`, `实时找车:${onlineCount.toLocaleString()} 在线 / ${rows.length.toLocaleString()} 当前页 / ${pagination.total.toLocaleString()} 总计`, `轨迹复盘:${selectedMapRow ? `${selectedMapRow.plate || '-'} / ${selectedMapRow.vin || '-'} / ${selectedVehicleProtocol || selectedMapRow.primaryProtocol || '-'}` : '未选择车辆'}`, `里程核对:${selectedMapRow?.totalMileageKm != null ? `${selectedMapRow.totalMileageKm} km` : '待核对'}`, `导出通知:${mapAttentionRows.length.toLocaleString()} 关注 / ${staleCount.toLocaleString()} 更新超时`, `实时地图:${appURL(buildAppHash({ page: 'map', protocol: filters.protocol, filters }))}`, selectedMapRow && canOpenVehicle(selectedMapRow.vin) ? `车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: selectedMapRow.vin, protocol: selectedVehicleProtocol }))}` : '', selectedMapRow && canOpenVehicle(selectedMapRow.vin) ? `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: selectedMapRow.vin, protocol: selectedVehicleProtocol }))}` : '', selectedMapRow && canOpenVehicle(selectedMapRow.vin) ? `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: selectedMapRow.vin, protocol: selectedVehicleProtocol }))}` : '', selectedMapRow && canOpenVehicle(selectedMapRow.vin) ? `历史导出:${appURL(buildAppHash({ page: 'history-query', keyword: selectedMapRow.vin, protocol: selectedVehicleProtocol, filters: { tab: 'raw', includeFields: 'true' } }))}` : '', `告警通知:${appURL(buildAppHash({ page: 'alert-events', filters: { serviceStatus: 'degraded', ...(filters.protocol ? { protocol: filters.protocol } : {}) } }))}` ].filter(Boolean).join('\n'), '车队服务旅程交付包'); const mapFleetJourneyItems = [ { step: '1', title: '实时找车', value: `${onlineCount.toLocaleString()} 在线`, detail: `${locatedCount.toLocaleString()} 辆有定位,先让客户知道当前能看到哪些车。`, color: onlineCount > 0 ? 'green' as const : 'orange' as const, disabled: false, onClick: () => applyFilters({ ...filters, online: 'online' }) }, { step: '2', title: '轨迹复盘', value: selectedVehicleLabel, detail: selectedMapRow ? `${dataFreshness(selectedMapRow).detail},进入轨迹复盘位置、速度和里程断点。` : '先从地图或车辆列表选择一辆车。', color: selectedMapRow ? 'blue' as const : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { step: '3', title: '里程核对', value: selectedMapRow?.totalMileageKm != null ? `${selectedMapRow.totalMileageKm} km` : '待核对', detail: '进入同一车辆的里程统计,核对区间差值、日统计和总里程。', color: selectedMapRow?.totalMileageKm != null ? 'blue' as const : 'orange' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && (window.location.hash = buildAppHash({ page: 'mileage', keyword: selectedMapRow.vin, protocol: selectedVehicleProtocol })) }, { step: '4', title: '导出通知', value: `${mapAttentionRows.length.toLocaleString()} 关注`, detail: `${staleCount.toLocaleString()} 辆更新超时,交付前进入告警通知或复制交付包。`, color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, disabled: false, onClick: () => mapAttentionRows.length > 0 && onOpenQuality ? onOpenQuality({ serviceStatus: 'degraded', protocol: filters.protocol }) : copyMapFleetJourneyPackage() } ]; const copyMapCustomerDecision = () => copyText(mapCustomerDecisionText({ filters, rows, total: pagination.total, onlineCount, locatedCount, attentionRows: mapAttentionRows, selectedRow: selectedMapRow, selectedProtocol: selectedVehicleProtocol, amapConfigured }), '地图客户决策说明'); const mapExecutiveControlItems = [ { title: '实时找车', value: `${onlineCount.toLocaleString()} 在线`, detail: `${locatedCount.toLocaleString()} 辆有坐标,先确认客户当前能看见哪些车。`, action: '打开地图', color: onlineCount > 0 ? 'green' as const : 'orange' as const, disabled: false, onClick: () => applyFilters({ ...filters, online: 'online' }) }, { title: '轨迹回放', value: selectedMapRow?.plate || selectedMapRow?.vin || '先选车', detail: selectedMapRow ? '围绕选中车辆回放位置、速度、里程和断点。' : '从地图或列表选择一辆车后进入轨迹回放。', action: '回放轨迹', color: selectedMapRow ? 'blue' as const : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { title: '围栏告警', value: `${mapAttentionRows.length.toLocaleString()} 关注`, detail: mapAttentionRows[0] ? `${mapAttentionRows[0].plate || mapAttentionRows[0].vin}:${realtimeIssueLabels(mapAttentionRows[0]).join(';')}` : '当前没有明显离线、超时或定位异常车辆。', action: '告警通知', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, disabled: !onOpenQuality, onClick: () => onOpenQuality?.({ serviceStatus: 'degraded', protocol: filters.protocol }) }, { title: '报表导出', value: `${rows.length.toLocaleString()} 当前页`, detail: '导出当前地图车辆范围、在线状态、位置和服务状态。', action: '导出报表', color: rows.length > 0 ? 'blue' as const : 'grey' as const, disabled: rows.length === 0, onClick: exportRealtime } ]; const realtimeCustomerJourneyItems = [ { step: '01', title: '只看在线', value: `${onlineCount.toLocaleString()} 在线`, detail: '先确认客户当前能看到哪些车辆仍在上报。', action: '在线车辆', color: onlineCount > 0 ? 'green' as const : 'orange' as const, onClick: () => applyFilters({ ...filters, online: 'online' }), disabled: false }, { step: '02', title: '地图态势', value: `${locatedCount.toLocaleString()} 有定位`, detail: '在地图上确认车辆位置、定位有效性和分布情况。', action: '查看地图', color: locatedCount > 0 ? 'blue' as const : 'orange' as const, onClick: () => { window.location.hash = buildAppHash({ page: 'map', protocol: filters.protocol, filters }); }, disabled: false }, { step: '03', title: '异常优先', value: `${Math.max(degradedCount, sourceIssueRows.length).toLocaleString()} 关注`, detail: '优先处理离线、更新超时、坐标无效或服务降级车辆。', action: '关注车辆', color: degradedCount > 0 || sourceIssueRows.length > 0 ? 'orange' as const : 'green' as const, onClick: () => applyFilters({ ...filters, serviceStatus: 'degraded' }), disabled: false }, { step: '04', title: '单车复盘', value: selectedMapRow?.plate || selectedMapRow?.vin || '未选车', detail: selectedMapRow ? '围绕选中车辆回放轨迹、里程统计和告警。' : '先在地图或表格中选择一辆可查询车辆。', action: '轨迹回放', color: selectedMapRow ? 'blue' as const : 'grey' as const, onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol), disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin) }, { step: '05', title: '查询导出', value: `${rows.length.toLocaleString()} 当前页`, detail: '导出当前实时车辆清单,用于客户问询和运营交接。', action: '导出 CSV', color: rows.length > 0 ? 'blue' as const : 'grey' as const, onClick: exportRealtime, disabled: rows.length === 0 } ]; const realtimeSourceEvidenceText = (() => { const protocols: string[] = []; rows.forEach((row) => { const rowProtocols = row.protocols?.length ? row.protocols : row.primaryProtocol ? [row.primaryProtocol] : []; rowProtocols.forEach((protocol) => { if (protocol && !protocols.includes(protocol)) { protocols.push(protocol); } }); }); return protocols.length > 0 ? protocols.join(' / ') : '暂无来源证据'; })(); const realtimeServiceOverviewItems = [ { label: '在线车辆', value: `${onlineCount.toLocaleString()} 在线`, detail: `${(rows.length - onlineCount).toLocaleString()} 辆离线,在线率 ${formatPercent(onlineRate)}`, color: onlineCount > 0 ? 'green' as const : 'orange' as const, onClick: () => applyFilters({ ...filters, online: 'online' }) }, { label: '有效定位', value: `${locatedCount.toLocaleString()} 辆`, detail: `${missingCoordinateCount.toLocaleString()} 辆无坐标,定位率 ${formatPercent(locatedRate)}`, color: locatedCount > 0 ? 'blue' as const : 'orange' as const, onClick: () => { window.location.hash = buildAppHash({ page: 'map', protocol: filters.protocol, filters }); } }, { label: '需关注', value: `${mapAttentionRows.length.toLocaleString()} 辆`, detail: mapAttentionRows[0] ? `${mapAttentionRows[0].plate || mapAttentionRows[0].vin}:${realtimeIssueLabels(mapAttentionRows[0]).join(';')}` : '当前没有离线、超时或定位异常车辆', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, onClick: () => applyFilters({ ...filters, serviceStatus: 'degraded' }) }, { label: '地图能力', displayLabel: '高德能力', value: amapConfigured ? '高德可用' : '坐标预览', detail: amapConfigured ? '高德 Web JS 与安全代理就绪' : '地图降级为坐标预览', color: amapConfigured ? 'green' as const : 'orange' as const, onClick: () => load(filters, pagination.currentPage, pagination.pageSize) } ]; const realtimeServiceActions = [ { label: '打开地图', action: '地图态势', color: 'blue' as const, disabled: false, onClick: () => { window.location.hash = buildAppHash({ page: 'map', protocol: filters.protocol, filters }); } }, { label: '轨迹复盘', action: '轨迹回放', color: selectedMapRow ? 'blue' as const : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { label: '导出清单', action: '导出CSV', color: rows.length > 0 ? 'blue' as const : 'grey' as const, disabled: rows.length === 0, onClick: exportRealtime }, { label: '告警通知', action: '关注车辆', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, disabled: !onOpenQuality, onClick: () => onOpenQuality?.({ serviceStatus: 'degraded' }) } ]; const realtimeCustomerCommandItems = [ { label: '实时地图', value: `${locatedCount.toLocaleString()} 有定位`, detail: '先回答客户车辆在哪里,定位无效车辆进入异常队列。', action: '打开地图', color: locatedCount > 0 ? 'blue' as const : 'orange' as const, disabled: false, onClick: () => { window.location.hash = buildAppHash({ page: 'map', protocol: filters.protocol, filters }); } }, { label: '在线车辆', value: `${onlineCount.toLocaleString()} 在线`, detail: `${(rows.length - onlineCount).toLocaleString()} 辆离线,优先确认当前可服务车辆。`, action: '只看在线', color: onlineCount > 0 ? 'green' as const : 'orange' as const, disabled: false, onClick: () => applyFilters({ ...filters, online: 'online' }) }, { label: '异常车辆', value: `${mapAttentionRows.length.toLocaleString()} 关注`, detail: mapAttentionRows[0] ? `${mapAttentionRows[0].plate || mapAttentionRows[0].vin}:${realtimeIssueLabels(mapAttentionRows[0]).join(';')}` : '当前没有明显离线、超时或坐标异常车辆。', action: '关注异常', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, disabled: false, onClick: () => applyFilters({ ...filters, serviceStatus: 'degraded' }) }, { label: '轨迹复盘', value: selectedMapRow?.plate || selectedMapRow?.vin || '未选车', detail: selectedMapRow ? '围绕选中车辆回放轨迹、核对里程和异常时间窗。' : '先从地图或表格选择一辆车。', action: '轨迹回放', color: selectedMapRow ? 'blue' as const : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { label: '导出交付', value: `${rows.length.toLocaleString()} 当前页`, detail: '导出车辆在线、位置、速度、SOC、里程和状态证据。', action: '导出CSV', color: rows.length > 0 ? 'blue' as const : 'grey' as const, disabled: rows.length === 0, onClick: exportRealtime } ]; const realtimeSingleVehicleItems = [ { label: '车辆服务', value: selectedMapRow?.plate || selectedMapRow?.vin || '未选车辆', detail: selectedMapRow ? `${vehicleServiceStatus(selectedMapRow).label},${sourceEvidenceText(selectedMapRow)}` : '先从地图或列表选择车辆。', color: selectedMapRow ? vehicleServiceStatus(selectedMapRow).color : 'grey' as const, action: '车辆档案', disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenVehicle(selectedMapRow.vin, selectedVehicleProtocol) }, { label: '轨迹回放', value: selectedMapRow ? dataFreshness(selectedMapRow).label : '待选车', detail: selectedMapRow ? `${dataFreshness(selectedMapRow).detail},回看位置、速度和里程断点。` : '选择车辆后进入轨迹回放。', color: selectedMapRow ? dataFreshness(selectedMapRow).color : 'grey' as const, action: '打开轨迹', disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { label: '里程统计', value: selectedMapRow?.totalMileageKm != null ? `${selectedMapRow.totalMileageKm} km` : '无里程', detail: '核对单车总里程、日里程和区间闭合。', color: selectedMapRow?.totalMileageKm != null ? 'blue' as const : 'grey' as const, action: '查里程', disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => { if (!selectedMapRow) return; window.location.hash = buildAppHash({ page: 'mileage', keyword: selectedMapRow.vin, protocol: selectedVehicleProtocol }); } }, { label: '历史导出', value: selectedVehicleProtocol || selectedMapRow?.primaryProtocol || '全部通道', detail: '进入历史查询导出同一车辆的 RAW、位置和字段证据。', color: selectedMapRow ? 'blue' as const : 'grey' as const, action: '导出证据', disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: openSelectedVehicleRaw }, { label: '告警通知', value: selectedMapRow ? vehicleServiceStatus(selectedMapRow).label : '待选车', detail: selectedMapRow ? realtimeIssueLabels(selectedMapRow).join(';') : '选择车辆后查看断链、离线和定位异常。', color: selectedMapRow && hasSourceIssue(selectedMapRow) ? 'orange' as const : selectedMapRow ? 'green' as const : 'grey' as const, action: '查看告警', disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin) || !onOpenQuality, onClick: () => selectedMapRow && onOpenQuality?.({ keyword: selectedMapRow.vin, protocol: selectedVehicleProtocol }) } ]; const realtimeNextActions = [ { level: degradedCount > 0 || staleCount > 0 ? '优先' : '巡检', title: degradedCount > 0 || staleCount > 0 ? '先处理异常车辆' : '先看在线车辆', value: degradedCount > 0 || staleCount > 0 ? `${degradedCount.toLocaleString()} 降级 / ${staleCount.toLocaleString()} 超时` : `${onlineCount.toLocaleString()} 在线`, detail: degradedCount > 0 || staleCount > 0 ? '离线、更新超时、坐标无效或服务降级会直接影响客户看车体验。' : `当前页 ${locatedCount.toLocaleString()} 辆有有效坐标,可进入地图查看分布。`, action: degradedCount > 0 || staleCount > 0 ? '关注异常' : '打开地图', color: degradedCount > 0 || staleCount > 0 ? 'orange' as const : 'green' as const, onClick: () => degradedCount > 0 || staleCount > 0 ? applyFilters({ ...filters, serviceStatus: 'degraded' }) : (window.location.hash = buildAppHash({ page: 'map', protocol: filters.protocol, filters })) }, { level: selectedMapRow ? '单车' : '选车', title: selectedMapRow ? '复盘选中车辆' : '先选择一辆车', value: selectedMapRow?.plate || selectedMapRow?.vin || '等待选车', detail: selectedMapRow ? `${vehicleServiceStatus(selectedMapRow).label},${dataFreshness(selectedMapRow).detail}` : '从地图或实时列表选择车辆后,进入轨迹、里程统计、历史和告警。', action: selectedMapRow ? '轨迹回放' : '查看车辆', color: selectedMapRow ? vehicleServiceStatus(selectedMapRow).color : 'blue' as const, disabled: selectedMapRow ? !canOpenVehicle(selectedMapRow.vin) : false, onClick: () => selectedMapRow && canOpenVehicle(selectedMapRow.vin) ? onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) : applyFilters({ ...filters, online: 'online' }) }, { level: '交付', title: '导出当前实时清单', value: `${rows.length.toLocaleString()} 辆当前页`, detail: '客户问询或交付复盘时,先导出当前筛选的车辆在线、位置、速度和里程。', action: '导出 CSV', color: rows.length > 0 ? 'blue' as const : 'grey' as const, disabled: rows.length === 0, onClick: exportRealtime } ]; const realtimeMapDispatchItems = [ { title: '查看在线车辆', value: `${onlineCount.toLocaleString()} 在线`, detail: `定位有效 ${locatedCount.toLocaleString()} 辆,先确认客户当前能看到哪些车。`, action: '实时地图', color: onlineCount > 0 ? 'green' as const : 'orange' as const, disabled: false, onClick: () => { window.location.hash = buildAppHash({ page: 'map', protocol: filters.protocol, filters: { ...filters, online: 'online' } }); } }, { title: '复盘选中车辆', value: selectedMapRow?.plate || selectedMapRow?.vin || '先选车', detail: selectedMapRow ? `${vehicleServiceStatus(selectedMapRow).label},${dataFreshness(selectedMapRow).detail}` : '从地图或实时列表选择车辆后,回放轨迹和里程变化。', action: '轨迹回放', color: selectedMapRow ? vehicleServiceStatus(selectedMapRow).color : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { title: '处理异常车辆', value: `${mapAttentionRows.length.toLocaleString()} 关注`, detail: mapAttentionRows[0] ? `${mapAttentionRows[0].plate || mapAttentionRows[0].vin}:${realtimeIssueLabels(mapAttentionRows[0]).join(';')}` : '当前筛选下暂无离线、超时或坐标异常车辆。', action: '告警事件', color: mapAttentionRows.length > 0 ? 'orange' as const : 'green' as const, disabled: !onOpenQuality, onClick: () => onOpenQuality?.({ serviceStatus: 'degraded', protocol: filters.protocol }) }, { title: '导出当前态势', value: `${rows.length.toLocaleString()} 辆当前页`, detail: '导出在线、位置、速度、SOC、里程和数据通道证据,用于客户交接。', action: '导出CSV', color: rows.length > 0 ? 'blue' as const : 'grey' as const, disabled: rows.length === 0, onClick: exportRealtime } ]; const realtimeCustomerQuestions = [ { question: '这辆车现在在哪里?', answer: selectedMapRow ? selectedMapRow.plate || selectedMapRow.vin : `${locatedCount.toLocaleString()} 辆有定位`, evidence: selectedMapRow && isValidCoordinate(selectedMapRow) ? `${selectedMapRow.longitude}, ${selectedMapRow.latitude}` : `定位有效率 ${formatPercent(locatedRate)}`, action: '地图定位', color: locatedCount > 0 ? 'blue' as const : 'orange' as const, disabled: false, onClick: () => { if (selectedMapRow) { selectRealtimeRow(selectedMapRow); } window.location.hash = buildAppHash({ page: 'map', protocol: filters.protocol, filters }); } }, { question: '这辆车还在线吗?', answer: selectedMapRow ? selectedMapRow.online ? '在线' : '离线' : `${onlineCount.toLocaleString()} 辆在线`, evidence: selectedMapRow ? dataFreshness(selectedMapRow).detail : `在线率 ${formatPercent(onlineRate)}`, action: '只看在线', color: selectedMapRow ? selectedMapRow.online ? 'green' as const : 'orange' as const : onlineCount > 0 ? 'green' as const : 'orange' as const, disabled: false, onClick: () => applyFilters({ ...filters, online: 'online' }) }, { question: '为什么状态异常?', answer: selectedMapRow ? realtimeIssueLabels(selectedMapRow)[0] : `${Math.max(degradedCount, sourceIssueRows.length).toLocaleString()} 辆关注`, evidence: selectedMapRow ? vehicleServiceStatus(selectedMapRow).label : `${degradedCount.toLocaleString()} 降级 / ${staleCount.toLocaleString()} 超时`, action: '异常清单', color: degradedCount > 0 || staleCount > 0 || sourceIssueRows.length > 0 ? 'orange' as const : 'green' as const, disabled: false, onClick: () => copyRealtimeIssueChecklist() }, { question: '当前状态能交接吗?', answer: realtimeImpactLevel, evidence: `当前页 ${rows.length.toLocaleString()} / 总计 ${pagination.total.toLocaleString()}`, action: '复制交接包', color: realtimeImpactColor, disabled: false, onClick: () => copyRealtimeDutyHandoff() } ]; const timeWindowMonitorBlock = (
自定义时间窗复盘 {timeWindowReady ? '时间窗可用' : '先选车辆'} {timeWindowDuration} 按车辆和时间窗复盘发生了什么 客户问某辆车、某段时间发生了什么时,直接串起轨迹回放、历史数据、里程统计和告警通知。
监控车辆 {timeWindowRow ? [timeWindowRow.plate, timeWindowRow.vin].filter(Boolean).join(' / ') : timeWindowKeyword || '未选择车辆'} {timeWindowProtocol || '全部来源证据'}
{timeWindowWorkItems.map((item) => ( ))}
时间窗监控任务台 {timeWindowReady ? '可交付' : '待锁定'} 把同一辆车、同一时间窗贯穿到轨迹、里程、历史导出和告警说明,避免客户跨页面重复筛选。
{timeWindowTaskItems.map((item) => ( ))}
); if (mode === 'map') { return (
{ applyFilters(values as Record); }}> GB32960 JT808 YUTONG_MQTT 在线 离线 {autoRefresh ? `自动刷新 ${refreshIntervalSeconds}秒` : '自动刷新已暂停'} 最后刷新:{lastRefreshAt || '等待首次刷新'}
车辆服务地图中枢 {amapConfigured ? '高德地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{mapAttentionRows.length.toLocaleString()} 辆关注 把 32960、808、MQTT 收敛成同一张车辆地图:看位置、判在线、选车辆、回放轨迹、处理告警和导出证据。 来源证据仅用于筛选和追溯,不作为客户主路径。
{mapCommandTaskItems.map((item) => ( ))}
车队服务旅程条 0 ? 'orange' : 'green'}> {mapAttentionRows.length > 0 ? `${mapAttentionRows.length.toLocaleString()} 关注` : '态势稳定'} {selectedMapRow ? selectedVehicleLabel : '未选车'} 把客户常用的四件事固定成一条路径:实时找车、轨迹复盘、里程核对、导出通知。 客户不需要理解 32960、808、MQTT 的协议差异,只要沿着这条路径完成看车、复盘、核对和交付。
{mapFleetJourneyItems.map((item) => ( ))}
客户车辆地图总控 {amapConfigured ? '高德地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}> {mapAttentionRows.length > 0 ? `${mapAttentionRows.length.toLocaleString()} 辆关注` : '态势稳定'} 把实时找车、轨迹回放、围栏告警和报表导出收敛成一条客户能直接使用的地图服务链路。 参考现代车队 Live Map 的使用方式,客户先看车辆是否在线和可定位,再围绕选中车辆完成复盘、通知和交付。
{mapExecutiveControlItems.map((item) => ( ))}
Live Map 决策条 {amapConfigured ? '高德可用' : '坐标预览'} 0 ? 'orange' : 'green'}> {mapAttentionRows.length > 0 ? `${mapAttentionRows.length.toLocaleString()} 关注` : '态势稳定'} 客户进来先判断四件事:哪些车在线、哪些车能定位、哪辆车要先处理、选中车辆下一步做什么。 这条决策条把地图、在线、轨迹、统计、导出和告警放到同一条服务路径里,协议来源只保留为证据。
{liveMapDecisionItems.map((item) => ( ))}
{liveMapDecisionActions.map((item) => ( ))}
地图状态筛选条 0 ? 'orange' : 'green'}> {mapAttentionRows.length > 0 ? `${mapAttentionRows.length.toLocaleString()} 关注` : '状态稳定'} 先按客户最关心的在线、离线、无坐标和需关注分组看车,再进入轨迹、统计、导出或告警。
{mapStatusFilterItems.map((item) => ( ))}
地图图层控制台 {amapConfigured ? '高德底图' : '坐标预览'} 0 ? 'orange' : 'green'}> {mapAttentionRows.length > 0 ? '关注优先' : '稳定图层'} 把实时地图拆成客户能理解的图层:在线、关注、定位、选车服务和交付导出。 图层控制不改变底层数据,只改变客户当下的查看重点:先看在线与定位,再处理关注车辆,最后进入单车服务或导出。
{mapLayerControlItems.map((item) => ( ))}
{mapLayerControlActions.map((item) => ( ))}
单车服务台 {selectedMapRow ? ( <> {vehicleServiceStatus(selectedMapRow).label} {dataFreshness(selectedMapRow).detail} ) : ( 等待选车 )} {selectedVehicleLabel}
{mapSelectedServiceItems.map((item) => ( ))}
地图服务行动条 {amapConfigured ? 'Live Map 可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{mapAttentionRows.length.toLocaleString()} 辆关注 把 Live Map 当作客户服务入口:先看在线车辆和关注车辆,再进入路线回放、里程统计和证据导出。 地图页的第一动作要围绕车辆服务,而不是围绕协议来源;客户从地图进入监控、复盘、统计和交付。
{mapServiceActionItems.map((item) => ( ))}
客户地图值班台 0 ? 'orange' : 'green'}> {mapAttentionRows.length > 0 ? '有关注车辆' : '态势稳定'} {selectedMapRow ? '已选车辆' : '待选车辆'} 把实时地图收敛成值班员能执行的四件事:交付状态、优先车辆、时间窗复盘和交接说明。 值班员不需要先理解协议来源,先确认今天是否可交付、哪辆车优先处理、是否要回放轨迹,以及交接时怎么讲。
{mapShiftConsoleItems.map((item) => ( ))}
地图客户决策 {amapConfigured ? '高德地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{mapAttentionRows.length.toLocaleString()} 辆关注 先判断车辆是否在线、是否有位置、是否有异常,再进入单车轨迹和历史查询。 地图页面向客户展示车辆服务状态,数据通道只作为定位、在线和异常追溯依据。
{mapCustomerDecisionItems.map((item) => ( ))}
地图视图模式 0 ? 'orange' : 'green'}> {mapAttentionRows.length > 0 ? '异常优先' : '运营稳定'} {selectedVehicleLabel} 按客户现场使用场景切换地图重点:车辆总览、异常优先、轨迹复盘或交付导出。 视图模式只改变工作重点,底层仍围绕同一批车辆、同一个时间上下文和同一套服务动作。
{mapViewModeItems.map((item) => ( ))}
现场指挥建议 {amapConfigured ? '地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}> {mapAttentionRows.length > 0 ? '先处置关注车辆' : '态势稳定'} 先看车在哪里,再决定回放、告警和导出 现场调度按实时地图、关注车辆、轨迹复盘、通知证据四步工作;围栏和告警后续也应从这里进入。
{mapFieldCommandItems.map((item) => ( ))}
区域围栏监控 0 ? 'green' : 'orange'}>{locatedCount.toLocaleString()} 辆可定位 0 ? 'orange' : 'green'}>{mapAttentionRows.length.toLocaleString()} 辆关注 把地图从“看车在哪里”升级成区域运营工具:围栏、停留、越界和通知都从车辆位置态势进入。 电子围栏先依赖实时定位和关注车辆,后续可接入客户区域配置、进出围栏事件和周期区域报表。
{mapAreaMonitorItems.map((item) => ( ))}
地图调度处置栏 0 ? 'orange' : 'green'}>{mapAttentionRows.length.toLocaleString()} 辆关注 {selectedMapRow ? '已选车辆' : '待选车辆'} 把地图上的车辆直接转成调度动作:先处理关注车辆,再复盘选中车辆,最后导出交接证据。
{mapDispatchActionItems.map((item) => ( ))}
{mapFleetKpis.map((item) => ( ))}
选中车辆服务 {selectedMapRow ? ( <> {vehicleServiceStatus(selectedMapRow).label} {dataFreshness(selectedMapRow).detail} ) : ( 等待选车 )} {selectedVehicleLabel} 客户在地图上选中车辆后,直接进入车辆档案、轨迹回放、里程统计、数据导出和告警处置。
{mapVehicleWorkItems.map((item) => ( ))}
{mapCustomerTasks.map((item) => (
{item.title} {item.value}
{item.detail}
))}
客户地图监控包 {amapConfigured ? '高德地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}> {mapAttentionRows.length > 0 ? '存在关注车辆' : '地图态势稳定'} {selectedVehicleLabel} 面向客户看图时,先确认车辆范围、在线态势、定位态势和选中车辆,再进入轨迹、里程统计、历史数据或告警通知。
{mapCustomerPackageItems.map((item) => (
{item.label} {item.value} {item.detail}
))}
{timeWindowMonitorBlock}
地图车辆作业台 当前车辆:{selectedVehicleLabel}
{selectedMapRow ? ( <> {vehicleServiceStatus(selectedMapRow).label} {dataFreshness(selectedMapRow).detail} {selectedVehicleProtocol || '未知通道'} ) : ( 先选车辆 )}
{mapVehicleWorkItems.map((item) => ( ))}
{amapConfigured ? '高德地图可用' : '坐标预览'} {locatedCount.toLocaleString()} 辆有效定位 {filterSummary.map((item) => {item})}
); } return (
实时车辆服务总览 {amapConfigured ? '高德可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{mapAttentionRows.length.toLocaleString()} 辆需关注 客户先看车辆是否在线、地图是否可见、哪些车辆需要处置,再进入轨迹、统计、导出和告警。 当前范围:{filterSummary.length > 0 ? filterSummary.join(' / ') : '全部车辆'},来源证据:{realtimeSourceEvidenceText}
{realtimeServiceOverviewItems.map((item) => ( ))}
{realtimeServiceActions.map((item) => ( ))}
客户实时监控总控台 {amapConfigured ? '地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{mapAttentionRows.length.toLocaleString()} 关注 实时页先回答客户能不能看到车、车辆在哪里、哪些车辆异常,再进入轨迹、统计、导出和告警。 来源证据仅用于可信度判断:{realtimeSourceEvidenceText}
{realtimeCustomerCommandItems.map((item) => ( ))}
实时处置优先级 0 ? 'orange' : 'green'}>{realtimePrioritySummary} 当前页 {rows.length.toLocaleString()} 辆 按客户影响排序:先处理不能看车、定位无效、数据通道不完整和更新超时的车辆。 这不是运维协议清单,而是车辆监控的处置队列;每辆车都能直接进入告警、轨迹和车辆档案。
{realtimePriorityRows.length === 0 ? (
实时稳定 当前筛选范围暂无优先处置车辆 继续保持自动刷新,并用地图、时间窗和导出能力支撑客户问询。
) : realtimePriorityRows.map((row, index) => { const label = row.plate || row.vin || '未知车辆'; const protocol = filters.protocol || row.primaryProtocol || ''; const issueText = realtimeIssueLabels(row).join(';'); return (
{index + 1}
{vehicleServiceStatus(row).label} {dataFreshness(row).label} {isValidCoordinate(row) ? '有定位' : '无定位'} {label} {issueText} {row.vin} / {protocol || '全部来源证据'} / {row.lastSeen || '-'}
); })}
客户实时监控 {amapConfigured ? '高德地图可用' : '坐标预览'} 0 || staleCount > 0 ? 'orange' : 'green'}>{degradedCount.toLocaleString()} 辆降级 / {staleCount.toLocaleString()} 辆超时 从实时列表直接完成车辆监控闭环 先筛在线车辆,再看地图位置,异常车辆优先处置,最后进入单车轨迹、里程统计、告警或导出当前页。
实时客户常问 {realtimeImpactLevel} {selectedMapRow ? '已选车辆' : '未选车辆'} 把实时数据翻译成客户能直接理解的车辆状态 客户问实时状态时,先回答位置、在线、新鲜度和异常原因,再进入轨迹、告警、历史查询或交接包。
{realtimeCustomerQuestions.map((item) => ( ))}
{realtimeNextActions.map((item) => ( ))}
实时地图调度台 {amapConfigured ? '高德地图可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{mapAttentionRows.length.toLocaleString()} 辆关注 像现代车队 Live Map 一样,把地图作为调度指挥台:先看在线位置,再处理轨迹、告警和导出。 协议来源只作为车辆位置可信度证据,客户主路径是找车、调度、复盘和通知。
{realtimeMapDispatchItems.map((item) => ( ))}
{realtimeCustomerJourneyItems.map((item) => ( ))}
实时单车服务快照 {selectedMapRow ? vehicleServiceStatus(selectedMapRow).label : '未选车辆'} {selectedMapRow ? dataFreshness(selectedMapRow).label : '等待数据'} 客户打开实时监控时,直接围绕选中车辆查看在线、位置、里程、新鲜度,并进入轨迹、统计、历史导出和告警通知。 {selectedMapRow ? `${selectedMapRow.plate || selectedMapRow.vin} / ${selectedVehicleProtocol || selectedMapRow.primaryProtocol || '全部通道'} / ${selectedMapRow.lastSeen || '无最后时间'}` : '从地图或实时列表选择一辆车后,快照会自动聚焦到单车服务。'}
{realtimeSingleVehicleItems.map((item) => ( ))}
{timeWindowMonitorBlock}
{ const nextFilters = values as Record; applyFilters(nextFilters); }} style={{ marginBottom: 12 }}> GB32960 JT808 YUTONG_MQTT 在线 离线 服务正常 数据通道不完整 车辆离线 身份未绑定
自动刷新 {refreshIntervalSeconds}秒 最后刷新:{lastRefreshAt || '等待首次刷新'}
{filterSummary.length > 0 ? ( {filterSummary.map((item) => ( {item} ))} ) : null}
实时作业入口
{[ { label: '在线车辆', value: onlineCount, color: 'green' as const, action: () => applyFilters({ ...filters, online: 'online' }) }, { label: '离线车辆', value: rows.length - onlineCount, color: rows.length - onlineCount > 0 ? 'orange' as const : 'green' as const, action: () => applyFilters({ ...filters, online: 'offline' }) }, { label: '定位有效', value: locatedCount, color: locatedCount > 0 ? 'blue' as const : 'orange' as const }, { label: '需要关注', value: degradedCount, color: degradedCount > 0 ? 'orange' as const : 'green' as const, action: () => applyFilters({ ...filters, serviceStatus: 'degraded' }) }, { label: '更新超时', value: staleCount, color: staleCount > 0 ? 'red' as const : 'green' as const }, { label: '来源证据', value: primaryProtocols.size, color: 'blue' as const } ].map((item) => ( item.action ? ( ) : (
{item.label} {item.value.toLocaleString()}
) ))}
建议处置
{degradedCount > 0 ? ( ) : 服务状态稳定} {staleCount > 0 ? 核对超时车辆 {staleCount.toLocaleString()} : 实时新鲜} {sourceIssueRows.length > 0 && onOpenQuality ? ( ) : null}
车辆来源证据覆盖
{sourceCoverageRows.length === 0 ? ( 当前页暂无车辆实时数据。 ) : sourceCoverageRows.map((item) => ( ))}
{amapConfigured ? '高德地图配置就绪' : '高德地图待配置'} {locatedCount.toLocaleString()} 辆有定位 {onlineCount.toLocaleString()} 辆在线
{[ { label: '当前车辆', value: pagination.total.toLocaleString(), color: 'blue' as const }, { label: '在线车辆', value: onlineCount.toLocaleString(), color: 'green' as const }, { label: '定位有效', value: locatedCount.toLocaleString(), color: 'green' as const }, { label: '超时车辆', value: staleCount.toLocaleString(), color: staleCount > 0 ? 'orange' as const : 'green' as const }, { label: '需要关注', value: degradedCount.toLocaleString(), color: degradedCount > 0 ? 'orange' as const : 'green' as const }, { label: '来源证据', value: primaryProtocols.size.toLocaleString(), color: 'blue' as const } ].map((item) => (
{item.label}
{item.value}
))} 地图用于观察车辆在线、定位新鲜度和异常车辆分布;内部接入状态由系统运维页单独承接。 {selectedMapRow ? (
当前选中车辆
{vehicleServiceStatus(selectedMapRow).label} {dataFreshness(selectedMapRow).label} {selectedMapRow.online ? '在线' : '离线'} {selectedMapRow.primaryProtocol || '未知通道'} {selectedMapRow.plate || selectedMapRow.vin} {selectedMapRow.vin}
速度{selectedMapRow.speedKmh ?? '-'} km/h SOC{selectedMapRow.socPercent ?? '-'}% 里程{selectedMapRow.totalMileageKm ?? '-'} km 新鲜度{dataFreshness(selectedMapRow).detail} 最后时间{selectedMapRow.lastSeen || '-'}
) : null}
地图展示状态
{mapIntegrationRows.map((item) => (
{item.label} {item.detail}
{item.value}
))}
需关注车辆
{sourceIssueRows.length === 0 ? ( 当前页车辆状态稳定 ) : ( sourceIssueRows.map((row) => { const status = vehicleServiceStatus(row); return (
{row.plate || row.vin} {row.vin}
{status.label}
{sourceEvidenceText(row)} {dataFreshness(row).label} {sourceIssueTags(row).map((item) => ( 问题:{item} ))} 处置说明:{row.serviceStatus?.detail || sourceEvidenceText(row)}
{row.lastSeen || '-'}
); }) )}
地图车辆队列
{mapServiceRows.length === 0 ? ( 暂无可定位车辆 ) : ( mapServiceRows.map((row) => { const status = vehicleServiceStatus(row); return (
selectRealtimeRow(row)} onKeyDown={(event) => { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); selectRealtimeRow(row); } }} >
{row.plate || row.vin} {row.vin}
{dataFreshness(row).label} {status.label}
{row.serviceStatus?.detail || sourceEvidenceText(row)} 新鲜度:{dataFreshness(row).detail}
{row.lastSeen || '-'}
); }) )}
车辆监控影响} style={{ marginBottom: 16 }} >
{realtimeImpactLevel}
{pagination.total.toLocaleString()} 辆
当前页 {rows.length.toLocaleString()} 辆,在线 {onlineCount.toLocaleString()} 辆,定位有效 {locatedCount.toLocaleString()} 辆,降级 {degradedCount.toLocaleString()} 辆,超时 {staleCount.toLocaleString()} 辆。 = 100 ? 'green' : 'grey'}>覆盖 {formatPercent(pageCoverageRate)} {amapConfigured ? '高德可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{(rows.length - onlineCount).toLocaleString()} 辆离线
{realtimeImpactItems.map((item) => (
{item.label} {item.value} {item.detail}
))}
{[ { label: '在线率', value: formatPercent(onlineRate), color: onlineRate >= 80 ? 'green' as const : 'orange' as const, detail: `${onlineCount.toLocaleString()} / ${rows.length.toLocaleString()} 辆在线。` }, { label: '定位有效率', value: formatPercent(locatedRate), color: locatedRate >= 80 ? 'green' as const : 'orange' as const, detail: `${locatedCount.toLocaleString()} / ${rows.length.toLocaleString()} 辆坐标有效。` }, { label: '新鲜数据', value: `${(rows.length - staleCount).toLocaleString()} 辆`, color: staleCount > 0 ? 'orange' as const : 'green' as const, detail: `${staleCount.toLocaleString()} 辆超过 5 分钟未更新。` }, { label: '降级率', value: formatPercent(degradedRate), color: degradedCount > 0 ? 'orange' as const : 'green' as const, detail: `${degradedCount.toLocaleString()} 辆存在数据通道不完整或离线。` }, { label: '分页覆盖率', value: formatPercent(pageCoverageRate), color: pageCoverageRate >= 100 ? 'green' as const : 'grey' as const, detail: '当前页车辆数 / 当前筛选总车辆数。' } ].map((item) => ( {item.label}
{item.value}
{item.detail}
))}
当前页 {rows.length.toLocaleString()} 条
{rows.length === 0 && !loading ? ( ) : ( load(filters, page, pagination.pageSize), onPageSizeChange: (pageSize) => load(filters, 1, pageSize) }} columns={[ { title: '车牌', dataIndex: 'plate', width: 120 }, { title: 'VIN', dataIndex: 'vin', width: 190 }, { title: '车辆服务状态', width: 130, render: (_: unknown, row: VehicleRealtimeRow) => { const status = vehicleServiceStatus(row); return {status.label}; } }, { title: '数据新鲜度', width: 130, render: (_: unknown, row: VehicleRealtimeRow) => { const freshness = dataFreshness(row); return {freshness.label}; } }, { title: '车辆核心数据', width: 230, render: (_: unknown, row: VehicleRealtimeRow) => ( {row.speedKmh ?? '-'} km/h SOC {row.socPercent ?? '-'}% {row.totalMileageKm ?? '-'} km ) }, { title: '实时来源证据', width: 260, render: (_: unknown, row: VehicleRealtimeRow) => ( ) }, { title: '来源覆盖', width: 120, render: (_: unknown, row: VehicleRealtimeRow) => sourceEvidenceText(row) }, { title: '在线', width: 90, render: (_: unknown, row: VehicleRealtimeRow) => }, { title: '最后时间', dataIndex: 'lastSeen', width: 170 }, { title: '操作', width: 190, render: (_: unknown, row: VehicleRealtimeRow) => ( ) } ]} /> )} ); }