feat(platform): add source readiness handoff copy
This commit is contained in:
@@ -765,6 +765,36 @@ export function Dashboard({
|
|||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
copyText(lines.join('\n'), '运营交接摘要');
|
copyText(lines.join('\n'), '运营交接摘要');
|
||||||
};
|
};
|
||||||
|
const copySourceReadinessHandoff = () => {
|
||||||
|
const plan = sourceReadiness;
|
||||||
|
if (!plan?.sources?.length) {
|
||||||
|
Toast.warning('暂无数据源就绪度数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const lines = [
|
||||||
|
'【三源接入到车辆服务交接摘要】',
|
||||||
|
`车辆规模:${formatCount(plan.onlineVehicles)} / ${formatCount(plan.totalVehicles)} 在线`,
|
||||||
|
`接入运行:连接 ${formatCount(plan.activeConnections)};Redis 在线 Key ${formatCount(plan.redisOnlineKeys)};Kafka Lag ${formatLag(plan.kafkaLag)}`,
|
||||||
|
`平台版本:${plan.platformRelease || '-'}`,
|
||||||
|
'',
|
||||||
|
...plan.sources.map((item, index) => [
|
||||||
|
`${index + 1}. ${item.protocol} - ${item.status}`,
|
||||||
|
` 角色:${item.role}`,
|
||||||
|
` 在线:${formatCount(item.online)} / ${formatCount(item.total)},在线率 ${item.onlineRate.toLocaleString(undefined, { maximumFractionDigits: 1 })}%`,
|
||||||
|
` 缺失车辆:${formatCount(item.missingVehicles)}`,
|
||||||
|
` 证据:${item.evidence}`,
|
||||||
|
` 动作:${item.action}`,
|
||||||
|
` 验收:${item.acceptance}`,
|
||||||
|
` 实时:${appURL(item.realtimeHash)}`,
|
||||||
|
` 车辆:${appURL(item.vehiclesHash)}`,
|
||||||
|
` RAW:${appURL(item.historyHash)}`,
|
||||||
|
` 告警:${appURL(item.alertHash)}`
|
||||||
|
].join('\n')),
|
||||||
|
'',
|
||||||
|
`驾驶舱:${appURL(buildAppHash({ page: 'dashboard' }))}`
|
||||||
|
];
|
||||||
|
copyText(lines.join('\n'), '三源接入交接摘要');
|
||||||
|
};
|
||||||
const copyScenarioBlueprint = () => {
|
const copyScenarioBlueprint = () => {
|
||||||
const lines = [
|
const lines = [
|
||||||
'【车辆数据中台功能蓝图】',
|
'【车辆数据中台功能蓝图】',
|
||||||
@@ -965,7 +995,11 @@ export function Dashboard({
|
|||||||
<Button size="small" theme="light" type="primary" onClick={exportDashboardSnapshot}>导出驾驶舱 CSV</Button>
|
<Button size="small" theme="light" type="primary" onClick={exportDashboardSnapshot}>导出驾驶舱 CSV</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
<Card bordered title="数据源到车辆服务就绪度" style={{ marginBottom: 16 }}>
|
<Card
|
||||||
|
bordered
|
||||||
|
title={<Space wrap><span>数据源到车辆服务就绪度</span><Button size="small" theme="light" disabled={!sourceReadiness?.sources?.length} onClick={copySourceReadinessHandoff}>复制接入交接</Button></Space>}
|
||||||
|
style={{ marginBottom: 16 }}
|
||||||
|
>
|
||||||
<div className="vp-source-readiness-grid">
|
<div className="vp-source-readiness-grid">
|
||||||
{(sourceReadiness?.sources ?? []).map((item) => (
|
{(sourceReadiness?.sources ?? []).map((item) => (
|
||||||
<div key={item.protocol} className="vp-source-readiness-item">
|
<div key={item.protocol} className="vp-source-readiness-item">
|
||||||
|
|||||||
@@ -174,146 +174,6 @@ test('exposes AMap operations shortcuts when map key is configured', async () =>
|
|||||||
})
|
})
|
||||||
} as Response;
|
} as Response;
|
||||||
}
|
}
|
||||||
if (path.includes('/api/ops/source-readiness')) {
|
|
||||||
return {
|
|
||||||
ok: true,
|
|
||||||
json: async () => ({
|
|
||||||
data: {
|
|
||||||
totalVehicles: 1033,
|
|
||||||
onlineVehicles: 208,
|
|
||||||
kafkaLag: 0,
|
|
||||||
activeConnections: 1234,
|
|
||||||
redisOnlineKeys: 368,
|
|
||||||
platformRelease: 'platform-dashboard-test',
|
|
||||||
sources: [
|
|
||||||
{
|
|
||||||
protocol: 'GB32960',
|
|
||||||
role: '整车与氢能实时数据主来源',
|
|
||||||
online: 73,
|
|
||||||
total: 340,
|
|
||||||
onlineRate: 21.47,
|
|
||||||
missingVehicles: 693,
|
|
||||||
severity: 'warning',
|
|
||||||
status: '覆盖不足',
|
|
||||||
evidence: '在线 73/340,缺失车辆 693,Kafka Lag 0',
|
|
||||||
action: '核对现代和交投平台转发清单。',
|
|
||||||
acceptance: '缺失来源车辆下降,单源车辆可解释。',
|
|
||||||
vehiclesHash: '#/vehicles?protocol=GB32960&missingProtocol=GB32960',
|
|
||||||
realtimeHash: '#/realtime?protocol=GB32960&online=online',
|
|
||||||
historyHash: '#/history-query?protocol=GB32960&tab=raw&includeFields=true',
|
|
||||||
alertHash: '#/alert-events?protocol=GB32960'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
protocol: 'JT808',
|
|
||||||
role: '位置、总里程和设备在线主来源',
|
|
||||||
online: 174,
|
|
||||||
total: 424,
|
|
||||||
onlineRate: 41.04,
|
|
||||||
missingVehicles: 609,
|
|
||||||
severity: 'warning',
|
|
||||||
status: '覆盖不足',
|
|
||||||
evidence: '在线 174/424,缺失车辆 609,Kafka Lag 0',
|
|
||||||
action: '补齐手机号绑定和注册缺失车辆。',
|
|
||||||
acceptance: '未知 VIN 注册下降,位置与里程持续可查。',
|
|
||||||
vehiclesHash: '#/vehicles?protocol=JT808&missingProtocol=JT808',
|
|
||||||
realtimeHash: '#/realtime?protocol=JT808&online=online',
|
|
||||||
historyHash: '#/history-query?protocol=JT808&tab=raw&includeFields=true',
|
|
||||||
alertHash: '#/alert-events?protocol=JT808'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
protocol: 'YUTONG_MQTT',
|
|
||||||
role: '宇通派生工况与燃料电池补充来源',
|
|
||||||
online: 11,
|
|
||||||
total: 50,
|
|
||||||
onlineRate: 22,
|
|
||||||
missingVehicles: 983,
|
|
||||||
severity: 'ok',
|
|
||||||
status: '生产可用',
|
|
||||||
evidence: '在线 11/50,缺失车辆 983,Kafka Lag 0',
|
|
||||||
action: '保持实时、轨迹、RAW 和统计链路巡检。',
|
|
||||||
acceptance: '车辆服务可回查实时、轨迹和 RAW 证据。',
|
|
||||||
vehiclesHash: '#/vehicles?protocol=YUTONG_MQTT&missingProtocol=YUTONG_MQTT',
|
|
||||||
realtimeHash: '#/realtime?protocol=YUTONG_MQTT&online=online',
|
|
||||||
historyHash: '#/history-query?protocol=YUTONG_MQTT&tab=raw&includeFields=true',
|
|
||||||
alertHash: '#/alert-events?protocol=YUTONG_MQTT'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
traceId: 'trace-test',
|
|
||||||
timestamp: 1783094400000
|
|
||||||
})
|
|
||||||
} as Response;
|
|
||||||
}
|
|
||||||
if (path.includes('/api/ops/source-readiness')) {
|
|
||||||
return {
|
|
||||||
ok: true,
|
|
||||||
json: async () => ({
|
|
||||||
data: {
|
|
||||||
totalVehicles: 1033,
|
|
||||||
onlineVehicles: 208,
|
|
||||||
kafkaLag: 0,
|
|
||||||
activeConnections: 1234,
|
|
||||||
redisOnlineKeys: 368,
|
|
||||||
platformRelease: 'platform-dashboard-test',
|
|
||||||
sources: [
|
|
||||||
{
|
|
||||||
protocol: 'GB32960',
|
|
||||||
role: '整车与氢能实时数据主来源',
|
|
||||||
online: 73,
|
|
||||||
total: 340,
|
|
||||||
onlineRate: 21.47,
|
|
||||||
missingVehicles: 693,
|
|
||||||
severity: 'warning',
|
|
||||||
status: '覆盖不足',
|
|
||||||
evidence: '在线 73/340,缺失车辆 693,Kafka Lag 0',
|
|
||||||
action: '核对现代和交投平台转发清单。',
|
|
||||||
acceptance: '缺失来源车辆下降,单源车辆可解释。',
|
|
||||||
vehiclesHash: '#/vehicles?protocol=GB32960&missingProtocol=GB32960',
|
|
||||||
realtimeHash: '#/realtime?protocol=GB32960&online=online',
|
|
||||||
historyHash: '#/history-query?protocol=GB32960&tab=raw&includeFields=true',
|
|
||||||
alertHash: '#/alert-events?protocol=GB32960'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
protocol: 'JT808',
|
|
||||||
role: '位置、总里程和设备在线主来源',
|
|
||||||
online: 174,
|
|
||||||
total: 424,
|
|
||||||
onlineRate: 41.04,
|
|
||||||
missingVehicles: 609,
|
|
||||||
severity: 'warning',
|
|
||||||
status: '覆盖不足',
|
|
||||||
evidence: '在线 174/424,缺失车辆 609,Kafka Lag 0',
|
|
||||||
action: '补齐手机号绑定和注册缺失车辆。',
|
|
||||||
acceptance: '未知 VIN 注册下降,位置与里程持续可查。',
|
|
||||||
vehiclesHash: '#/vehicles?protocol=JT808&missingProtocol=JT808',
|
|
||||||
realtimeHash: '#/realtime?protocol=JT808&online=online',
|
|
||||||
historyHash: '#/history-query?protocol=JT808&tab=raw&includeFields=true',
|
|
||||||
alertHash: '#/alert-events?protocol=JT808'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
protocol: 'YUTONG_MQTT',
|
|
||||||
role: '宇通派生工况与燃料电池补充来源',
|
|
||||||
online: 11,
|
|
||||||
total: 50,
|
|
||||||
onlineRate: 22,
|
|
||||||
missingVehicles: 983,
|
|
||||||
severity: 'ok',
|
|
||||||
status: '生产可用',
|
|
||||||
evidence: '在线 11/50,缺失车辆 983,Kafka Lag 0',
|
|
||||||
action: '保持实时、轨迹、RAW 和统计链路巡检。',
|
|
||||||
acceptance: '车辆服务可回查实时、轨迹和 RAW 证据。',
|
|
||||||
vehiclesHash: '#/vehicles?protocol=YUTONG_MQTT&missingProtocol=YUTONG_MQTT',
|
|
||||||
realtimeHash: '#/realtime?protocol=YUTONG_MQTT&online=online',
|
|
||||||
historyHash: '#/history-query?protocol=YUTONG_MQTT&tab=raw&includeFields=true',
|
|
||||||
alertHash: '#/alert-events?protocol=YUTONG_MQTT'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
traceId: 'trace-test',
|
|
||||||
timestamp: 1783094400000
|
|
||||||
})
|
|
||||||
} as Response;
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
ok: true,
|
ok: true,
|
||||||
json: async () => ({
|
json: async () => ({
|
||||||
@@ -983,6 +843,10 @@ test('dashboard exposes vehicle data center capability matrix', async () => {
|
|||||||
fireEvent.click(screen.getByRole('button', { name: '复制流转图' }));
|
fireEvent.click(screen.getByRole('button', { name: '复制流转图' }));
|
||||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【车辆数据中台数据流转图】'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【车辆数据中台数据流转图】'));
|
||||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('03. 实时投影 / Redis KV'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('03. 实时投影 / Redis KV'));
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: '复制接入交接' }));
|
||||||
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【三源接入到车辆服务交接摘要】'));
|
||||||
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('1. GB32960 - 覆盖不足'));
|
||||||
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('RAW:http://localhost:3000/#/history-query?protocol=GB32960&tab=raw&includeFields=true'));
|
||||||
|
|
||||||
fireEvent.click(screen.getAllByRole('button', { name: '实时' })[0]);
|
fireEvent.click(screen.getAllByRole('button', { name: '实时' })[0]);
|
||||||
expect(window.location.hash).toBe('#/realtime?protocol=GB32960&online=online');
|
expect(window.location.hash).toBe('#/realtime?protocol=GB32960&online=online');
|
||||||
|
|||||||
Reference in New Issue
Block a user