feat(platform): align vehicle detail with service delivery

This commit is contained in:
lingniu
2026-07-06 04:53:34 +08:00
parent 7ac1390394
commit 286840c19c
2 changed files with 14 additions and 14 deletions

View File

@@ -714,13 +714,13 @@ export function VehicleDetail({
}; };
const copyVehicleOperationsSummary = () => { const copyVehicleOperationsSummary = () => {
if (!detail) { if (!detail) {
Toast.warning('当前没有可复制的运营摘要'); Toast.warning('当前没有可复制的车辆服务摘要');
return; return;
} }
const vehicleName = [archivePlate, displayVIN].filter((item) => item && item !== '-').join(' / ') || displayLookupKey; const vehicleName = [archivePlate, displayVIN].filter((item) => item && item !== '-').join(' / ') || displayLookupKey;
const actionLines = serviceActions.map((item, index) => `${index + 1}. ${item.label}${item.description}`); const actionLines = serviceActions.map((item, index) => `${index + 1}. ${item.label}${item.description}`);
const lines = [ const lines = [
'【车辆服务运营摘要】', '【车辆服务摘要】',
`车辆:${vehicleName}`, `车辆:${vehicleName}`,
`当前范围:${scopeText}`, `当前范围:${scopeText}`,
`服务状态:${customerStatusTitle(serviceStatus?.title) || serviceConclusion.status}`, `服务状态:${customerStatusTitle(serviceStatus?.title) || serviceConclusion.status}`,
@@ -738,7 +738,7 @@ export function VehicleDetail({
`历史数据:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, `历史数据:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`,
`统计查询:${vehicleServiceURL(vehicleServiceHash('mileage'))}` `统计查询:${vehicleServiceURL(vehicleServiceHash('mileage'))}`
]; ];
copyText(lines.join('\n'), '运营摘要'); copyText(lines.join('\n'), '车辆服务摘要');
}; };
const detailWorkbench = [ const detailWorkbench = [
{ {
@@ -963,7 +963,7 @@ export function VehicleDetail({
detail: priorityQualityIssue ? `${qualityIssueLabel(priorityQualityIssue.issueType)} / ${priorityQualityIssue.lastSeen || '-'}` : '暂无高优先级告警,保持观察。', detail: priorityQualityIssue ? `${qualityIssueLabel(priorityQualityIssue.issueType)} / ${priorityQualityIssue.lastSeen || '-'}` : '暂无高优先级告警,保持观察。',
color: qualityCount > 0 ? 'orange' as const : 'green' as const, color: qualityCount > 0 ? 'orange' as const : 'green' as const,
primaryAction: '告警事件', primaryAction: '告警事件',
secondaryAction: '运营摘要', secondaryAction: '服务摘要',
disabled: !onOpenQuality || (!hasResolvedVIN && qualityCount <= 0), disabled: !onOpenQuality || (!hasResolvedVIN && qualityCount <= 0),
onPrimary: () => onOpenQuality?.(qualityFiltersForCurrentVehicle()), onPrimary: () => onOpenQuality?.(qualityFiltersForCurrentVehicle()),
onSecondary: () => copyVehicleOperationsSummary() onSecondary: () => copyVehicleOperationsSummary()
@@ -1262,7 +1262,7 @@ export function VehicleDetail({
<Button icon={<IconRefresh />} onClick={() => load(query)} loading={loading}></Button> <Button icon={<IconRefresh />} onClick={() => load(query)} loading={loading}></Button>
<Button icon={<IconCopy />} onClick={copyVehicleServiceURL}></Button> <Button icon={<IconCopy />} onClick={copyVehicleServiceURL}></Button>
<Button disabled={!detail} icon={<IconCopy />} onClick={copyVehicleDiagnosticSummary}></Button> <Button disabled={!detail} icon={<IconCopy />} onClick={copyVehicleDiagnosticSummary}></Button>
<Button disabled={!detail} icon={<IconCopy />} onClick={copyVehicleOperationsSummary}></Button> <Button disabled={!detail} icon={<IconCopy />} onClick={copyVehicleOperationsSummary}></Button>
<Button disabled={!detail} icon={<IconDownload />} onClick={exportVehicleReport}> CSV</Button> <Button disabled={!detail} icon={<IconDownload />} onClick={exportVehicleReport}> CSV</Button>
<Button disabled={!hasResolvedVIN} onClick={() => onOpenRealtime(resolvedVIN, activeProtocol)}></Button> <Button disabled={!hasResolvedVIN} onClick={() => onOpenRealtime(resolvedVIN, activeProtocol)}></Button>
<Button disabled={!hasResolvedVIN} onClick={() => onOpenHistory(resolvedVIN, activeProtocol)}></Button> <Button disabled={!hasResolvedVIN} onClick={() => onOpenHistory(resolvedVIN, activeProtocol)}></Button>
@@ -1491,7 +1491,7 @@ export function VehicleDetail({
<Card <Card
bordered bordered
title={<Space><span></span><Button size="small" disabled={!detail} icon={<IconCopy />} onClick={copyUnifiedVehicleService}></Button></Space>} title={<Space><span></span><Button size="small" disabled={!detail} icon={<IconCopy />} onClick={copyUnifiedVehicleService}></Button></Space>}
style={{ marginTop: 16 }} style={{ marginTop: 16 }}
> >
<div className="vp-unified-service-board"> <div className="vp-unified-service-board">
@@ -1690,7 +1690,7 @@ export function VehicleDetail({
</div> </div>
</Card> </Card>
<Card bordered title="单车运营工作台" style={{ marginTop: 16 }}> <Card bordered title="单车服务任务台" style={{ marginTop: 16 }}>
<div className="vp-workbench-grid"> <div className="vp-workbench-grid">
{detailWorkbench.map((item) => ( {detailWorkbench.map((item) => (
<div key={item.title} className="vp-workbench-item"> <div key={item.title} className="vp-workbench-item">
@@ -1708,7 +1708,7 @@ export function VehicleDetail({
theme="light" theme="light"
type="primary" type="primary"
disabled={item.disabled || (item.title === '告警处置' && !onOpenQuality)} disabled={item.disabled || (item.title === '告警处置' && !onOpenQuality)}
aria-label={`单车运营工作${item.title} ${action.label}`} aria-label={`单车服务任务${item.title} ${action.label}`}
onClick={action.onClick} onClick={action.onClick}
> >
{action.label} {action.label}

View File

@@ -13432,7 +13432,7 @@ test('shows unified service overview on vehicle detail', async () => {
expect(screen.getAllByText('查询历史数据').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText('查询历史数据').length).toBeGreaterThanOrEqual(1);
expect(screen.getByText('复核统计查询')).toBeInTheDocument(); expect(screen.getByText('复核统计查询')).toBeInTheDocument();
expect(screen.getByText('闭环告警事件')).toBeInTheDocument(); expect(screen.getByText('闭环告警事件')).toBeInTheDocument();
expect(screen.getByText('单车运营工作台')).toBeInTheDocument(); expect(screen.getByText('单车服务任务台')).toBeInTheDocument();
expect(screen.getByText('单车服务处理清单')).toBeInTheDocument(); expect(screen.getByText('单车服务处理清单')).toBeInTheDocument();
expect(screen.getAllByText('档案完整度').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText('档案完整度').length).toBeGreaterThanOrEqual(1);
expect(screen.getByText('实时')).toBeInTheDocument(); expect(screen.getByText('实时')).toBeInTheDocument();
@@ -13463,7 +13463,7 @@ test('shows unified service overview on vehicle detail', async () => {
expect(screen.getByRole('button', { name: '单车任务 查询历史数据 历史数据' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车任务 查询历史数据 历史数据' })).toBeInTheDocument();
expect(screen.getByRole('button', { name: '单车任务 复核统计查询 统计查询' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车任务 复核统计查询 统计查询' })).toBeInTheDocument();
expect(screen.getByRole('button', { name: '单车任务 闭环告警事件 告警事件' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车任务 闭环告警事件 告警事件' })).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '单车运营工作台 历史数据 查看历史数据' })); fireEvent.click(screen.getByRole('button', { name: '单车服务任务台 历史数据 查看历史数据' }));
expect(window.location.hash).toBe('#/history-query?keyword=VIN001&tab=raw'); expect(window.location.hash).toBe('#/history-query?keyword=VIN001&tab=raw');
}); });
@@ -13947,7 +13947,7 @@ test('copies vehicle service diagnostic summary', async () => {
render(<App />); render(<App />);
expect(await screen.findByText('车辆运营总览')).toBeInTheDocument(); expect(await screen.findByText('车辆服务总览')).toBeInTheDocument();
expect(screen.getByRole('button', { name: /复制归一摘要/ })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /复制归一摘要/ })).toBeInTheDocument();
expect(screen.getByText('车辆身份')).toBeInTheDocument(); expect(screen.getByText('车辆身份')).toBeInTheDocument();
expect(screen.getByText('实时主数据通道')).toBeInTheDocument(); expect(screen.getByText('实时主数据通道')).toBeInTheDocument();
@@ -14054,12 +14054,12 @@ test('copies vehicle service diagnostic summary', async () => {
expect(copied).toContain('历史数据http://localhost:3000/#/history-query?keyword=VIN-SUMMARY-001&protocol=JT808&tab=raw&includeFields=true'); expect(copied).toContain('历史数据http://localhost:3000/#/history-query?keyword=VIN-SUMMARY-001&protocol=JT808&tab=raw&includeFields=true');
expect(copied).toContain('统计查询http://localhost:3000/#/mileage?keyword=VIN-SUMMARY-001&protocol=JT808'); expect(copied).toContain('统计查询http://localhost:3000/#/mileage?keyword=VIN-SUMMARY-001&protocol=JT808');
fireEvent.click(screen.getByRole('button', { name: /复制运营摘要/ })); fireEvent.click(screen.getByRole('button', { name: /复制服务摘要/ }));
await waitFor(() => { await waitFor(() => {
expect(writeText.mock.calls.some((call) => String(call[0]).includes('【车辆服务运营摘要】'))).toBe(true); expect(writeText.mock.calls.some((call) => String(call[0]).includes('【车辆服务摘要】'))).toBe(true);
}); });
const operationsCopied = String(writeText.mock.lastCall?.[0] ?? ''); const operationsCopied = String(writeText.mock.lastCall?.[0] ?? '');
expect(operationsCopied).toContain('【车辆服务运营摘要】'); expect(operationsCopied).toContain('【车辆服务摘要】');
expect(operationsCopied).toContain('车辆粤A诊断1 / VIN-SUMMARY-001'); expect(operationsCopied).toContain('车辆粤A诊断1 / VIN-SUMMARY-001');
expect(operationsCopied).toContain('当前范围单一数据通道JT808'); expect(operationsCopied).toContain('当前范围单一数据通道JT808');
expect(operationsCopied).toContain('服务状态:数据通道不完整'); expect(operationsCopied).toContain('服务状态:数据通道不完整');