feat(platform): add online status handoff

This commit is contained in:
lingniu
2026-07-04 20:44:07 +08:00
parent 4b34a2bf4c
commit e8f0ebff35
2 changed files with 62 additions and 0 deletions

View File

@@ -202,6 +202,44 @@ function mileageEvidencePackageText(row: DailyMileageRow) {
].join('\n');
}
function onlineStatusHandoffText({
filters,
summary,
rows,
total
}: {
filters: Record<string, string>;
summary: OnlineStatisticsSummary;
rows: OnlineVehicleStatusRow[];
total: number;
}) {
const keyword = filters.keyword?.trim() || '全部车辆';
const protocol = filters.protocol?.trim() || '全部来源';
const offlineRows = rows.filter((row) => !row.online);
const protocolLines = (summary.protocolStats ?? []).length > 0
? summary.protocolStats.map((item) => `${item.protocol} ${item.online.toLocaleString()}/${item.total.toLocaleString()}`).join('')
: '-';
return [
'【车辆在线状态交接】',
`车辆范围:${keyword}`,
`数据来源:${protocol}`,
`在线概览:${summary.onlineVehicleCount.toLocaleString()} 在线 / ${summary.offlineVehicleCount.toLocaleString()} 离线 / 在线率 ${formatPercent(summary.onlineRatePercent)}`,
`Redis 在线 Key${summary.redisOnlineKeys == null ? '-' : summary.redisOnlineKeys.toLocaleString()}`,
`协议在线:${protocolLines}`,
`统计证据:${summary.evidence || '-'}`,
`当前页离线:${offlineRows.length.toLocaleString()} 辆 / 当前筛选 ${total.toLocaleString()}`,
'',
'离线车辆:',
...(offlineRows.length > 0 ? offlineRows.map((row, index) => [
`${index + 1}. ${row.plate || '-'} / ${row.vin || '-'} / ${row.oem || '-'}`,
` 离线时长:${formatOfflineDuration(row.offlineDurationMinutes)};最后上报:${row.lastSeen || '-'}`,
` 来源覆盖:${row.onlineSourceCount}/${row.sourceCount};协议:${(row.protocols ?? []).join('、') || '-'}`,
` 车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: row.vin, protocol: filters.protocol?.trim() || row.protocols?.[0] || '' }))}`,
` 实时监控:${appURL(buildAppHash({ page: 'realtime', keyword: row.vin, protocol: filters.protocol?.trim() || row.protocols?.[0] || '' }))}`
].join('\n')) : ['当前页暂无离线车辆'])
].join('\n');
}
async function copyText(value: string, label: string) {
const text = value.trim();
if (!text) {
@@ -379,6 +417,17 @@ export function Mileage({
'统计摘要'
);
};
const copyOnlineStatusHandoff = () => {
copyText(
onlineStatusHandoffText({
filters,
summary: onlineSummary,
rows: onlineRows,
total: onlinePagination.total
}),
'在线状态交接'
);
};
useEffect(() => {
const nextFilters = mergeInitialFilters(initialVin, initialProtocol, initialFilters);
@@ -592,6 +641,7 @@ export function Mileage({
<Tag color="green">线 {onlineVehicleCount.toLocaleString()} </Tag>
<Tag color="orange">线 {offlineVehicleCount.toLocaleString()} </Tag>
<Typography.Text type="secondary"> VIN线</Typography.Text>
<Button size="small" onClick={copyOnlineStatusHandoff}>线</Button>
</Space>
</div>
<Table

View File

@@ -7023,6 +7023,11 @@ test('shows mileage statistics workspace with trend source and definition', asyn
test('shows vehicle-first statistics domains for one vehicle service', async () => {
window.history.replaceState(null, '', '/#/mileage?keyword=VIN-STATS-SERVICE&protocol=JT808');
const writeText = vi.fn(() => Promise.resolve());
Object.defineProperty(navigator, 'clipboard', {
configurable: true,
value: { writeText }
});
vi.spyOn(globalThis, 'fetch').mockImplementation(async (input) => {
const path = String(input);
if (path.includes('/api/mileage/summary')) {
@@ -7145,6 +7150,13 @@ test('shows vehicle-first statistics domains for one vehicle service', async ()
expect(await screen.findByText('VIN-STATS-SERVICE-OFFLINE')).toBeInTheDocument();
expect(screen.getByText('粤A离线1')).toBeInTheDocument();
expect(screen.getByText('2 小时')).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '复制在线状态清单' }));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【车辆在线状态交接】'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆范围VIN-STATS-SERVICE'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('在线概览3 在线 / 1 离线 / 在线率 75%'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('协议在线JT808 2/3GB32960 1/2'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('1. 粤A离线1 / VIN-STATS-SERVICE-OFFLINE / 广安车联'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('离线时长2 小时最后上报2026-07-03 18:12:10'));
});
test('copies mileage statistics summary for operations reporting', async () => {