feat(platform): add online status handoff
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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/3;GB32960 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 () => {
|
||||
|
||||
Reference in New Issue
Block a user