feat(platform): add vehicle service decision board

This commit is contained in:
lingniu
2026-07-05 02:36:59 +08:00
parent e8d745949e
commit 7bef3c7e33
3 changed files with 131 additions and 3 deletions

View File

@@ -599,6 +599,53 @@ export function Vehicles({
onClick: exportVehicles
}
], [exportVehicles, filters.keyword, onOpenHistory, onOpenMap, onOpenMileage, onOpenRealtime, rows.length, serviceScopeFilters, summary?.onlineVehicles]);
const primaryAction = actionQueue[0];
const vehicleDecisionItems = [
{
title: '在线车辆',
value: `${(summary?.onlineVehicles ?? 0).toLocaleString()}`,
detail: '先看当前仍在上报的车辆,直接进入地图和实时状态。',
color: 'green' as const,
primaryAction: '实时监控',
secondaryAction: '车辆地图',
onPrimary: () => onOpenRealtime?.({ ...serviceScopeFilters, online: 'online' }),
onSecondary: () => onOpenMap?.({ ...serviceScopeFilters, online: 'online' }),
disabled: !onOpenRealtime
},
{
title: '异常车辆',
value: `${(summary?.noDataVehicles ?? 0).toLocaleString()} 无来源`,
detail: primaryAction ? primaryAction.detail : '当前没有必须立即处理的车辆服务事项。',
color: (summary?.noDataVehicles ?? 0) > 0 || primaryAction ? 'orange' as const : 'green' as const,
primaryAction: primaryAction?.label ?? '查看结果',
secondaryAction: '告警事件',
onPrimary: () => primaryAction ? applyFilters({ ...filters, ...primaryAction.filters }) : applyFilters(filters),
onSecondary: () => onOpenQuality?.(serviceScopeFilters),
disabled: !primaryAction
},
{
title: '单车服务',
value: filters.keyword?.trim() || '输入车辆',
detail: filters.keyword?.trim() ? '当前已进入单车范围,可查看车辆详情、轨迹和里程。' : '输入 VIN、车牌或手机号后进入完整车辆服务。',
color: filters.keyword?.trim() ? 'blue' as const : 'grey' as const,
primaryAction: '车辆详情',
secondaryAction: '轨迹回放',
onPrimary: () => filters.keyword?.trim() && onOpenVehicle(filters.keyword.trim(), filters.protocol),
onSecondary: () => onOpenHistory?.({ ...serviceScopeFilters, tab: 'location' }),
disabled: !filters.keyword?.trim()
},
{
title: '数据交付',
value: `${rows.length.toLocaleString()} 当前页`,
detail: '导出当前车辆清单继续进入历史页交付轨迹、RAW 和字段证据。',
color: rows.length > 0 ? 'blue' as const : 'grey' as const,
primaryAction: '导出清单',
secondaryAction: '历史导出',
onPrimary: exportVehicles,
onSecondary: () => onOpenHistory?.({ ...serviceScopeFilters, tab: 'raw', includeFields: 'true' }),
disabled: rows.length === 0
}
];
useEffect(() => {
setFilters(initialFilters);
@@ -742,6 +789,41 @@ export function Vehicles({
</div>
</div>
</Card>
<Card bordered title="车辆服务决策板" style={{ marginTop: 16 }}>
<div className="vp-vehicle-decision-grid">
{vehicleDecisionItems.map((item) => (
<div key={item.title} className="vp-vehicle-decision-item">
<div className="vp-vehicle-decision-head">
<Tag color={item.color}>{item.title}</Tag>
<strong>{item.value}</strong>
</div>
<span>{item.detail}</span>
<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.title === '单车服务' && item.disabled}
aria-label={`车辆服务决策 ${item.title} ${item.secondaryAction}`}
onClick={item.onSecondary}
>
{item.secondaryAction}
</Button>
</Space>
</div>
))}
</div>
</Card>
<Card bordered>
<Form key={JSON.stringify(filters)} initValues={filters} layout="horizontal" onSubmit={(values) => {
const nextFilters = values as Record<string, string>;