feat(platform): add single vehicle task board

This commit is contained in:
lingniu
2026-07-05 02:05:44 +08:00
parent 2c881dae7c
commit 7657412b8c
3 changed files with 143 additions and 3 deletions

View File

@@ -786,6 +786,63 @@ export function VehicleDetail({
];
copyText(lines.join('\n'), '单车处理清单');
};
const detailTaskBoard = [
{
title: '看实时位置',
value: lastSeen,
detail: evidenceSourceCount > 0 ? `${evidenceOnlineSourceCount}/${evidenceSourceCount} 来源在线,先确认车辆当前是否仍在上报。` : '暂无来源在线证据,优先确认数据接入。',
color: online ? 'green' as const : 'orange' as const,
primaryAction: '实时监控',
secondaryAction: '复制摘要',
disabled: !hasResolvedVIN,
onPrimary: () => onOpenRealtime(resolvedVIN, activeProtocol),
onSecondary: () => copyUnifiedVehicleService()
},
{
title: '回放轨迹证据',
value: `${formatCompactNumber(overview?.historyCount ?? detail?.history?.total ?? 0)} 条历史`,
detail: evidenceLocatedSourceCount > 0 ? `${evidenceLocatedSourceCount} 个位置来源,可回放定位、速度和里程断点。` : '暂无有效位置来源,先检查实时坐标。',
color: evidenceLocatedSourceCount > 0 ? 'blue' as const : 'grey' as const,
primaryAction: '轨迹回放',
secondaryAction: '处理清单',
disabled: !hasResolvedVIN,
onPrimary: () => onOpenHistory(resolvedVIN, activeProtocol),
onSecondary: () => copyVehicleRunbook()
},
{
title: '导出原始证据',
value: `${formatCompactNumber(overview?.rawCount ?? detail?.raw?.total ?? 0)}`,
detail: latestRaw?.frameType ? `最新原始记录类型 ${latestRaw.frameType},用于核对解析字段。` : '按车辆和来源导出 RAW 与解析字段。',
color: (overview?.rawCount ?? detail?.raw?.total ?? 0) > 0 ? 'blue' as const : 'grey' as const,
primaryAction: '数据导出',
secondaryAction: '导出档案',
disabled: !hasResolvedVIN,
onPrimary: () => onOpenRaw(resolvedVIN, activeProtocol),
onSecondary: () => exportVehicleReport()
},
{
title: '复核里程统计',
value: `${formatCompactNumber(overview?.mileageCount ?? detail?.mileage?.total ?? 0)} 条统计`,
detail: `来源里程差 ${formatCompactNumber(evidenceMileageDelta, ' km')},确认区间和日统计能闭合。`,
color: isFiniteNumber(evidenceMileageDelta) && Math.abs(evidenceMileageDelta) > 1 ? 'orange' as const : 'green' as const,
primaryAction: '里程统计',
secondaryAction: '诊断摘要',
disabled: !hasResolvedVIN,
onPrimary: () => onOpenMileage(resolvedVIN, activeProtocol),
onSecondary: () => copyVehicleDiagnosticSummary()
},
{
title: '闭环告警事件',
value: `${qualityCount.toLocaleString()}`,
detail: priorityQualityIssue ? `${qualityIssueLabel(priorityQualityIssue.issueType)} / ${priorityQualityIssue.lastSeen || '-'}` : '暂无高优先级告警,保持观察。',
color: qualityCount > 0 ? 'orange' as const : 'green' as const,
primaryAction: '告警事件',
secondaryAction: '运营摘要',
disabled: !onOpenQuality || (!hasResolvedVIN && qualityCount <= 0),
onPrimary: () => onOpenQuality?.(qualityFiltersForCurrentVehicle()),
onSecondary: () => copyVehicleOperationsSummary()
}
];
const qualityTable = (
<Table
loading={loading}
@@ -1007,6 +1064,42 @@ export function VehicleDetail({
</div>
</Card>
<Card bordered title="今日单车服务任务板" style={{ marginTop: 16 }}>
<div className="vp-vehicle-task-grid">
{detailTaskBoard.map((item) => (
<div key={item.title} className="vp-vehicle-task-item">
<div className="vp-vehicle-task-head">
<Tag color={item.color}>{item.title}</Tag>
<strong>{item.value}</strong>
</div>
<Typography.Text type="secondary">{item.detail}</Typography.Text>
<Space wrap>
<Button
size="small"
theme="solid"
type="primary"
disabled={item.disabled}
aria-label={`单车任务 ${item.title} ${item.primaryAction}`}
onClick={item.onPrimary}
>
{item.primaryAction}
</Button>
<Button
size="small"
theme="light"
type="primary"
disabled={item.disabled && item.title !== '闭环告警事件'}
aria-label={`单车任务 ${item.title} ${item.secondaryAction}`}
onClick={item.onSecondary}
>
{item.secondaryAction}
</Button>
</Space>
</div>
))}
</div>
</Card>
<Card bordered title="单车运营工作台" style={{ marginTop: 16 }}>
<div className="vp-workbench-grid">
{detailWorkbench.map((item) => (