feat(platform): add vehicle service task board

This commit is contained in:
lingniu
2026-07-05 01:55:54 +08:00
parent 7642f9c9eb
commit 2c881dae7c
3 changed files with 159 additions and 1 deletions

View File

@@ -445,6 +445,67 @@ export function Dashboard({
onClick: () => onOpenHistory()
}
];
const taskTimeMonitorSummary = (() => {
const vehicle = String(timeMonitorFilters.keyword ?? '').trim() || '全部车辆';
const source = String(timeMonitorFilters.protocol ?? '').trim() || '全部数据通道';
const dateFrom = String(timeMonitorFilters.dateFrom ?? '').trim();
const dateTo = String(timeMonitorFilters.dateTo ?? '').trim();
const range = dateFrom || dateTo ? `${dateFrom || '-'}${dateTo || '-'}` : '全部时间';
return `${vehicle} / ${source} / ${range}`;
})();
const customerTaskBoard = [
{
title: '先看全域在线',
value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`,
detail: `地图有效定位 ${commandLocatedCount.toLocaleString()} 辆,优先确认车辆是否仍在上报。`,
color: 'green' as const,
primaryAction: '打开实时地图',
secondaryAction: '查看在线车辆',
onPrimary: () => onOpenMap({ online: 'online' }),
onSecondary: () => onOpenRealtime({ online: 'online' })
},
{
title: '再看重点车辆',
value: focusVehicle?.label ?? '暂无重点车辆',
detail: focusVehicle ? `${focusVehicle.reason}${focusVehicle.realtimeEvidence}` : '当前没有高优先级车辆,保持日常巡检。',
color: focusVehicle?.statusColor ?? 'green' as const,
primaryAction: '车辆服务',
secondaryAction: '复制处置卡',
onPrimary: () => focusVehicle?.lookupKey && onOpenVehicle(focusVehicle.lookupKey, focusVehicle.protocol),
onSecondary: () => copyFocusVehicleService(),
disabled: !focusVehicle?.lookupKey
},
{
title: '按时间窗复盘',
value: taskTimeMonitorSummary,
detail: '同一时间窗贯穿轨迹、里程、RAW 和告警,不需要跨页面重复输入。',
color: 'blue' as const,
primaryAction: '轨迹回放',
secondaryAction: '里程统计',
onPrimary: () => openTimeMonitorHistory(),
onSecondary: () => openTimeMonitorMileage()
},
{
title: '导出证据数据',
value: `${formatCount(summary?.frameToday)} 今日数据`,
detail: '面向 BI、客户复盘和异常定位按车辆、时间、字段裁剪导出。',
color: 'blue' as const,
primaryAction: '历史导出',
secondaryAction: '导出概览',
onPrimary: () => openTimeMonitorRaw(),
onSecondary: () => exportDashboardSnapshot()
},
{
title: '闭环告警通知',
value: `${formatCount(summary?.issueVehicles)} 告警车辆`,
detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '暂无高优先级告警。',
color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const,
primaryAction: '告警事件',
secondaryAction: '复制交接',
onPrimary: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}),
onSecondary: () => copyOperationsHandoff()
}
];
const capabilities = [
{
title: '实时地图',
@@ -1039,6 +1100,41 @@ export function Dashboard({
))}
</div>
</Card>
<Card bordered title="今日车辆服务任务板" style={{ marginBottom: 16 }}>
<div className="vp-customer-task-grid">
{customerTaskBoard.map((item) => (
<div key={item.title} className="vp-customer-task-item">
<div className="vp-customer-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.secondaryAction !== '复制处置卡'}
aria-label={`今日任务 ${item.title} ${item.secondaryAction}`}
onClick={item.onSecondary}
>
{item.secondaryAction}
</Button>
</Space>
</div>
))}
</div>
</Card>
<div className="vp-kpi-grid">
{kpis.map((item) => (
<Card key={item.label} bordered className="vp-kpi-card" bodyStyle={{ padding: 0 }}>