feat(platform): add history delivery task board

This commit is contained in:
lingniu
2026-07-05 02:27:00 +08:00
parent 751d290f1b
commit 12caed6310
3 changed files with 117 additions and 0 deletions

View File

@@ -1036,6 +1036,84 @@ export function History({
</Space>
</Card>
) : null}
<Card bordered title="历史数据交付任务板" style={{ marginTop: 16 }}>
<div className="vp-history-delivery-grid">
{[
{
title: '轨迹回放',
tag: validLocations.length > 0 ? '可回放' : '待查询',
tagColor: validLocations.length > 0 ? 'green' as const : 'orange' as const,
value: `${validLocations.length.toLocaleString()} 个有效点`,
detail: currentVehicleKeyword
? '围绕当前车辆生成可播放轨迹,用于定位复盘和客户问询。'
: '先输入 VIN、车牌或手机号再生成单车轨迹。',
primaryText: '播放轨迹',
secondaryText: '复制摘要',
disabled: validLocations.length === 0,
onPrimary: () => openQueryTab('location'),
onSecondary: copyTrajectorySummary
},
{
title: '位置导出',
tag: locations.total > 0 ? '可交付' : '无数据',
tagColor: locations.total > 0 ? 'green' as const : 'grey' as const,
value: `${locations.total.toLocaleString()} 条位置`,
detail: '导出当前筛选范围的位置历史支撑客户定位、BI 核对和离线复盘。',
primaryText: '导出位置',
secondaryText: '车辆服务',
disabled: locations.items.length === 0,
secondaryDisabled: !currentVehicleKeyword,
onPrimary: exportLocations,
onSecondary: () => currentVehicleKeyword && onOpenVehicle(currentVehicleKeyword, currentProtocol)
},
{
title: '原始证据',
tag: (rawFrames.total ?? 0) > 0 ? '有证据' : '待加载',
tagColor: (rawFrames.total ?? 0) > 0 ? 'blue' as const : 'orange' as const,
value: `${(rawFrames.total ?? 0).toLocaleString()}`,
detail: '保留接入侧原始记录,用于解释位置、里程和字段值的来源。',
primaryText: '看原始',
secondaryText: '导出RAW',
disabled: false,
secondaryDisabled: rawFrames.items.length === 0,
onPrimary: () => openQueryTab('raw'),
onSecondary: exportRawFrames
},
{
title: '字段裁剪',
tag: selectedFieldCount > 0 ? `${selectedFieldCount} 个字段` : '全量字段',
tagColor: rawFieldRows.length > 0 ? 'green' as const : 'blue' as const,
value: `${rawFieldRows.length.toLocaleString()} 个字段`,
detail: selectedFieldCount > 0
? '按配置字段返回明细,减少接口体积并加快复核。'
: '需要字段级核对时,切到字段明细或填写字段裁剪。',
primaryText: '字段明细',
secondaryText: '导出字段',
disabled: false,
secondaryDisabled: rawFieldRows.length === 0,
onPrimary: () => openQueryTab('fields'),
onSecondary: exportRawFields
}
].map((task) => (
<div key={task.title} className="vp-history-delivery-item">
<div className="vp-history-delivery-head">
<Typography.Text strong>{task.title}</Typography.Text>
<Tag color={task.tagColor}>{task.tag}</Tag>
</div>
<strong>{task.value}</strong>
<Typography.Text type="secondary">{task.detail}</Typography.Text>
<Space wrap>
<Button size="small" theme="solid" type="primary" disabled={task.disabled} onClick={task.onPrimary}>
{task.primaryText}
</Button>
<Button size="small" disabled={task.secondaryDisabled} onClick={task.onSecondary}>
{task.secondaryText}
</Button>
</Space>
</div>
))}
</div>
</Card>
<Card bordered title={mode === 'query' ? '历史数据质量' : '轨迹运营影响'} style={{ marginTop: 16 }}>
<div className="vp-trajectory-impact-board">
<div className="vp-trajectory-impact-summary">

View File

@@ -2328,6 +2328,38 @@ button.vp-realtime-command-item:focus-visible {
word-break: break-word;
}
.vp-history-delivery-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 12px;
}
.vp-history-delivery-item {
min-height: 184px;
padding: 12px;
border: 1px solid var(--vp-border);
border-radius: var(--vp-radius);
background: #fbfcff;
display: grid;
gap: 10px;
align-content: start;
}
.vp-history-delivery-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.vp-history-delivery-item strong {
color: var(--vp-text);
font-size: 20px;
line-height: 26px;
font-weight: 700;
word-break: break-word;
}
.vp-playback-layout {
display: grid;
grid-template-columns: minmax(0, 1fr) 260px;
@@ -3338,6 +3370,7 @@ button.vp-realtime-command-item:focus-visible {
.vp-trajectory-impact-grid,
.vp-history-query-workbench,
.vp-history-query-grid,
.vp-history-delivery-grid,
.vp-source-fusion-grid,
.vp-source-fusion-facts,
.vp-vehicle-map-layout,

View File

@@ -6488,6 +6488,12 @@ test('shows trajectory playback workspace from history locations', async () => {
render(<App />);
expect(await screen.findByRole('heading', { name: '轨迹回放' })).toBeInTheDocument();
expect(screen.getByText('历史数据交付任务板')).toBeInTheDocument();
expect(screen.getByText('2 个有效点')).toBeInTheDocument();
expect(screen.getByText('围绕当前车辆生成可播放轨迹,用于定位复盘和客户问询。')).toBeInTheDocument();
expect(screen.getByText('位置导出')).toBeInTheDocument();
expect(screen.getByText('原始证据')).toBeInTheDocument();
expect(screen.getAllByText('字段裁剪').length).toBeGreaterThanOrEqual(1);
expect(screen.getByText('轨迹运营影响')).toBeInTheDocument();
expect(screen.getByText('轨迹范围')).toBeInTheDocument();
expect(screen.getByText('定位覆盖')).toBeInTheDocument();