feat(platform): customerize realtime monitoring view
This commit is contained in:
@@ -34,7 +34,7 @@ function vehicleServiceStatus(row: VehicleRealtimeRow) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sourceEvidenceText(row: VehicleRealtimeRow) {
|
function sourceEvidenceText(row: VehicleRealtimeRow) {
|
||||||
return `${row.onlineSourceCount}/${row.sourceCount} 来源在线`;
|
return `${row.onlineSourceCount}/${row.sourceCount} 通道在线`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatPercent(value: number) {
|
function formatPercent(value: number) {
|
||||||
@@ -154,11 +154,11 @@ const realtimeExportColumns: CsvColumn<VehicleRealtimeRow>[] = [
|
|||||||
{ title: '车牌', value: (row) => row.plate },
|
{ title: '车牌', value: (row) => row.plate },
|
||||||
{ title: '手机号', value: (row) => row.phone },
|
{ title: '手机号', value: (row) => row.phone },
|
||||||
{ title: 'OEM', value: (row) => row.oem },
|
{ title: 'OEM', value: (row) => row.oem },
|
||||||
{ title: '主来源', value: (row) => row.primaryProtocol },
|
{ title: '主通道', value: (row) => row.primaryProtocol },
|
||||||
{ title: '来源列表', value: (row) => row.protocols?.join('|') },
|
{ title: '数据通道', value: (row) => row.protocols?.join('|') },
|
||||||
{ title: '在线', value: (row) => row.online ? '在线' : '离线' },
|
{ title: '在线', value: (row) => row.online ? '在线' : '离线' },
|
||||||
{ title: '车辆服务状态', value: (row) => vehicleServiceStatus(row).label },
|
{ title: '车辆服务状态', value: (row) => vehicleServiceStatus(row).label },
|
||||||
{ title: '来源在线', value: (row) => sourceEvidenceText(row) },
|
{ title: '通道在线', value: (row) => sourceEvidenceText(row) },
|
||||||
{ title: '经度', value: (row) => row.longitude },
|
{ title: '经度', value: (row) => row.longitude },
|
||||||
{ title: '纬度', value: (row) => row.latitude },
|
{ title: '纬度', value: (row) => row.latitude },
|
||||||
{ title: '速度km/h', value: (row) => row.speedKmh },
|
{ title: '速度km/h', value: (row) => row.speedKmh },
|
||||||
@@ -187,7 +187,7 @@ function realtimeExportFileName(filters: Record<string, string>) {
|
|||||||
function realtimeFilterSummary(filters: Record<string, string>) {
|
function realtimeFilterSummary(filters: Record<string, string>) {
|
||||||
return [
|
return [
|
||||||
filters.keyword ? `关键词:${filters.keyword}` : '',
|
filters.keyword ? `关键词:${filters.keyword}` : '',
|
||||||
filters.protocol ? `数据来源:${filters.protocol}` : '',
|
filters.protocol ? `数据通道:${filters.protocol}` : '',
|
||||||
filters.online ? `在线:${onlineLabel[filters.online] ?? filters.online}` : '',
|
filters.online ? `在线:${onlineLabel[filters.online] ?? filters.online}` : '',
|
||||||
filters.serviceStatus ? `服务状态:${serviceStatusLabel[filters.serviceStatus] ?? filters.serviceStatus}` : ''
|
filters.serviceStatus ? `服务状态:${serviceStatusLabel[filters.serviceStatus] ?? filters.serviceStatus}` : ''
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
@@ -265,13 +265,13 @@ function realtimeIssueLabels(row: VehicleRealtimeRow) {
|
|||||||
function realtimeIssueAction(row: VehicleRealtimeRow) {
|
function realtimeIssueAction(row: VehicleRealtimeRow) {
|
||||||
const issues = realtimeIssueLabels(row).join(';');
|
const issues = realtimeIssueLabels(row).join(';');
|
||||||
if (!isValidCoordinate(row)) {
|
if (!isValidCoordinate(row)) {
|
||||||
return `核对${row.primaryProtocol || '实时来源'}定位字段解析和平台转发`;
|
return `核对${row.primaryProtocol || '实时数据'}定位字段解析和平台转发`;
|
||||||
}
|
}
|
||||||
if (dataFreshness(row).stale) {
|
if (dataFreshness(row).stale) {
|
||||||
return `确认${row.primaryProtocol || '实时来源'}是否持续上报,必要时检查接入链路`;
|
return `确认${row.primaryProtocol || '实时数据'}是否持续上报,必要时查看告警事件`;
|
||||||
}
|
}
|
||||||
if (hasSourceIssue(row)) {
|
if (hasSourceIssue(row)) {
|
||||||
return '补齐离线来源,确认多来源实时状态一致';
|
return '处理离线数据通道,确认车辆实时状态一致';
|
||||||
}
|
}
|
||||||
return issues === '暂无异常' ? '持续观察' : '结合车辆服务详情继续排查';
|
return issues === '暂无异常' ? '持续观察' : '结合车辆服务详情继续排查';
|
||||||
}
|
}
|
||||||
@@ -385,12 +385,12 @@ function realtimeDutyHandoffText({
|
|||||||
lines.push(
|
lines.push(
|
||||||
`${index + 1}. ${row.plate || '-'} / ${row.vin} / ${protocol || '-'} / ${status.label}`,
|
`${index + 1}. ${row.plate || '-'} / ${row.vin} / ${protocol || '-'} / ${status.label}`,
|
||||||
` 最后上报:${row.lastSeen || '-'};新鲜度:${freshness.label};位置:${isValidCoordinate(row) ? `${row.longitude},${row.latitude}` : '无有效坐标'};速度:${row.speedKmh ?? '-'} km/h;SOC:${row.socPercent ?? '-'}%`,
|
` 最后上报:${row.lastSeen || '-'};新鲜度:${freshness.label};位置:${isValidCoordinate(row) ? `${row.longitude},${row.latitude}` : '无有效坐标'};速度:${row.speedKmh ?? '-'} km/h;SOC:${row.socPercent ?? '-'}%`,
|
||||||
` 来源:${sourceEvidenceText(row)};问题:${realtimeIssueLabels(row).join(';')}`,
|
` 数据覆盖:${sourceEvidenceText(row)};问题:${realtimeIssueLabels(row).join(';')}`,
|
||||||
` 车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: row.vin, protocol }))}`,
|
` 车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: row.vin, protocol }))}`,
|
||||||
` 实时监控:${appURL(buildAppHash({ page: 'realtime', keyword: row.vin, protocol }))}`,
|
` 实时监控:${appURL(buildAppHash({ page: 'realtime', keyword: row.vin, protocol }))}`,
|
||||||
` 轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: row.vin, protocol }))}`,
|
` 轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: row.vin, protocol }))}`,
|
||||||
` 里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: row.vin, protocol }))}`,
|
` 里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: row.vin, protocol }))}`,
|
||||||
` 历史RAW:${protocol ? rawFrameAPIURL(row, protocol) : '-'}`
|
` 原始记录:${protocol ? rawFrameAPIURL(row, protocol) : '-'}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
return lines.join('\n');
|
return lines.join('\n');
|
||||||
@@ -431,7 +431,7 @@ function realtimeImpactReportText({
|
|||||||
`定位影响:${locatedCount.toLocaleString()} 辆有有效坐标`,
|
`定位影响:${locatedCount.toLocaleString()} 辆有有效坐标`,
|
||||||
`服务影响:${degradedCount.toLocaleString()} 辆降级 / ${staleCount.toLocaleString()} 辆超时`,
|
`服务影响:${degradedCount.toLocaleString()} 辆降级 / ${staleCount.toLocaleString()} 辆超时`,
|
||||||
`地图能力:${amapConfigured ? '高德地图可用' : '高德地图未配置,使用坐标预览'}`,
|
`地图能力:${amapConfigured ? '高德地图可用' : '高德地图未配置,使用坐标预览'}`,
|
||||||
`建议动作:${impactLevel === '实时稳定' ? '保持监控并关注告警队列' : '优先处理离线、超时和来源不完整车辆,并回到轨迹/RAW证据复核'}`,
|
`建议动作:${impactLevel === '实时稳定' ? '保持监控并关注告警队列' : '优先处理离线、超时和来源不完整车辆,并回到轨迹和原始记录复核'}`,
|
||||||
`实时监控:${appURL(buildAppHash({ page: 'realtime', protocol: filters.protocol, filters }))}`
|
`实时监控:${appURL(buildAppHash({ page: 'realtime', protocol: filters.protocol, filters }))}`
|
||||||
].join('\n');
|
].join('\n');
|
||||||
}
|
}
|
||||||
@@ -728,7 +728,7 @@ export function Realtime({
|
|||||||
applyFilters(nextFilters);
|
applyFilters(nextFilters);
|
||||||
}} style={{ marginBottom: 12 }}>
|
}} style={{ marginBottom: 12 }}>
|
||||||
<Form.Input field="keyword" label="车辆关键词" placeholder="VIN / 车牌 / 手机号 / OEM" style={{ width: 260 }} />
|
<Form.Input field="keyword" label="车辆关键词" placeholder="VIN / 车牌 / 手机号 / OEM" style={{ width: 260 }} />
|
||||||
<Form.Select field="protocol" label="数据来源" placeholder="全部来源" style={{ width: 180 }}>
|
<Form.Select field="protocol" label="数据通道" placeholder="全部数据通道" style={{ width: 180 }}>
|
||||||
<Select.Option value="GB32960">GB32960</Select.Option>
|
<Select.Option value="GB32960">GB32960</Select.Option>
|
||||||
<Select.Option value="JT808">JT808</Select.Option>
|
<Select.Option value="JT808">JT808</Select.Option>
|
||||||
<Select.Option value="YUTONG_MQTT">YUTONG_MQTT</Select.Option>
|
<Select.Option value="YUTONG_MQTT">YUTONG_MQTT</Select.Option>
|
||||||
@@ -815,7 +815,7 @@ export function Realtime({
|
|||||||
{staleCount > 0 ? <Tag color="red">核对超时车辆 {staleCount.toLocaleString()}</Tag> : <Tag color="green">实时新鲜</Tag>}
|
{staleCount > 0 ? <Tag color="red">核对超时车辆 {staleCount.toLocaleString()}</Tag> : <Tag color="green">实时新鲜</Tag>}
|
||||||
{sourceIssueRows.length > 0 && onOpenQuality ? (
|
{sourceIssueRows.length > 0 && onOpenQuality ? (
|
||||||
<Button size="small" theme="light" type="warning" onClick={() => onOpenQuality({ serviceStatus: 'degraded' })}>
|
<Button size="small" theme="light" type="warning" onClick={() => onOpenQuality({ serviceStatus: 'degraded' })}>
|
||||||
查看质量告警 {sourceIssueRows.length.toLocaleString()}
|
查看告警事件 {sourceIssueRows.length.toLocaleString()}
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
@@ -825,7 +825,7 @@ export function Realtime({
|
|||||||
<div className="vp-current-service-title">车辆覆盖概览</div>
|
<div className="vp-current-service-title">车辆覆盖概览</div>
|
||||||
<div className="vp-source-coverage-grid">
|
<div className="vp-source-coverage-grid">
|
||||||
{sourceCoverageRows.length === 0 ? (
|
{sourceCoverageRows.length === 0 ? (
|
||||||
<Typography.Text type="tertiary">当前页暂无车辆数据通道。</Typography.Text>
|
<Typography.Text type="tertiary">当前页暂无车辆实时数据。</Typography.Text>
|
||||||
) : sourceCoverageRows.map((item) => (
|
) : sourceCoverageRows.map((item) => (
|
||||||
<button
|
<button
|
||||||
key={item.protocol}
|
key={item.protocol}
|
||||||
@@ -894,7 +894,7 @@ export function Realtime({
|
|||||||
<Tag color={vehicleServiceStatus(selectedMapRow).color}>{vehicleServiceStatus(selectedMapRow).label}</Tag>
|
<Tag color={vehicleServiceStatus(selectedMapRow).color}>{vehicleServiceStatus(selectedMapRow).label}</Tag>
|
||||||
<Tag color={dataFreshness(selectedMapRow).color}>{dataFreshness(selectedMapRow).label}</Tag>
|
<Tag color={dataFreshness(selectedMapRow).color}>{dataFreshness(selectedMapRow).label}</Tag>
|
||||||
<Tag color={selectedMapRow.online ? 'green' : 'orange'}>{selectedMapRow.online ? '在线' : '离线'}</Tag>
|
<Tag color={selectedMapRow.online ? 'green' : 'orange'}>{selectedMapRow.online ? '在线' : '离线'}</Tag>
|
||||||
<Tag color="blue">{selectedMapRow.primaryProtocol || '未知来源'}</Tag>
|
<Tag color="blue">{selectedMapRow.primaryProtocol || '未知通道'}</Tag>
|
||||||
</Space>
|
</Space>
|
||||||
<Typography.Title heading={6} style={{ margin: '8px 0 0' }}>
|
<Typography.Title heading={6} style={{ margin: '8px 0 0' }}>
|
||||||
{selectedMapRow.plate || selectedMapRow.vin}
|
{selectedMapRow.plate || selectedMapRow.vin}
|
||||||
@@ -915,7 +915,7 @@ export function Realtime({
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="vp-map-integration-panel">
|
<div className="vp-map-integration-panel">
|
||||||
<div className="vp-map-service-queue-title">地图能力状态</div>
|
<div className="vp-map-service-queue-title">地图展示状态</div>
|
||||||
{mapIntegrationRows.map((item) => (
|
{mapIntegrationRows.map((item) => (
|
||||||
<div key={item.label} className="vp-map-integration-row">
|
<div key={item.label} className="vp-map-integration-row">
|
||||||
<div>
|
<div>
|
||||||
@@ -927,9 +927,9 @@ export function Realtime({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="vp-source-consistency-panel">
|
<div className="vp-source-consistency-panel">
|
||||||
<div className="vp-map-service-queue-title">车辆数据一致性检查</div>
|
<div className="vp-map-service-queue-title">需关注车辆</div>
|
||||||
{sourceIssueRows.length === 0 ? (
|
{sourceIssueRows.length === 0 ? (
|
||||||
<Typography.Text type="tertiary">当前页车辆来源一致</Typography.Text>
|
<Typography.Text type="tertiary">当前页车辆状态稳定</Typography.Text>
|
||||||
) : (
|
) : (
|
||||||
sourceIssueRows.map((row) => {
|
sourceIssueRows.map((row) => {
|
||||||
const status = vehicleServiceStatus(row);
|
const status = vehicleServiceStatus(row);
|
||||||
@@ -946,16 +946,16 @@ export function Realtime({
|
|||||||
<Tag color="blue">{sourceEvidenceText(row)}</Tag>
|
<Tag color="blue">{sourceEvidenceText(row)}</Tag>
|
||||||
<Tag color={dataFreshness(row).color}>{dataFreshness(row).label}</Tag>
|
<Tag color={dataFreshness(row).color}>{dataFreshness(row).label}</Tag>
|
||||||
{sourceIssueTags(row).map((item) => (
|
{sourceIssueTags(row).map((item) => (
|
||||||
<Tag key={item} color="orange">一致性:{item}</Tag>
|
<Tag key={item} color="orange">问题:{item}</Tag>
|
||||||
))}
|
))}
|
||||||
</Space>
|
</Space>
|
||||||
<Typography.Text type="secondary" size="small">
|
<Typography.Text type="secondary" size="small">
|
||||||
一致性诊断:{row.serviceStatus?.detail || sourceEvidenceText(row)}
|
处置说明:{row.serviceStatus?.detail || sourceEvidenceText(row)}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
<div className="vp-map-service-item-footer">
|
<div className="vp-map-service-item-footer">
|
||||||
<Typography.Text type="tertiary" size="small">{row.lastSeen || '-'}</Typography.Text>
|
<Typography.Text type="tertiary" size="small">{row.lastSeen || '-'}</Typography.Text>
|
||||||
<Space spacing={4} wrap>
|
<Space spacing={4} wrap>
|
||||||
<Button size="small" disabled={!onOpenQuality} onClick={() => openQualityEvidence(row)}>检查质量</Button>
|
<Button size="small" disabled={!onOpenQuality} onClick={() => openQualityEvidence(row)}>查看告警</Button>
|
||||||
<Button size="small" onClick={() => onOpenVehicle(row.vin, filters.protocol || row.primaryProtocol)}>查看服务</Button>
|
<Button size="small" onClick={() => onOpenVehicle(row.vin, filters.protocol || row.primaryProtocol)}>查看服务</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
@@ -965,7 +965,7 @@ export function Realtime({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="vp-map-service-queue">
|
<div className="vp-map-service-queue">
|
||||||
<div className="vp-map-service-queue-title">地图车辆服务队列</div>
|
<div className="vp-map-service-queue-title">地图车辆队列</div>
|
||||||
{mapServiceRows.length === 0 ? (
|
{mapServiceRows.length === 0 ? (
|
||||||
<Typography.Text type="tertiary">暂无可定位车辆</Typography.Text>
|
<Typography.Text type="tertiary">暂无可定位车辆</Typography.Text>
|
||||||
) : (
|
) : (
|
||||||
@@ -1006,8 +1006,8 @@ export function Realtime({
|
|||||||
<Space spacing={4} wrap>
|
<Space spacing={4} wrap>
|
||||||
<Button size="small" onClick={() => window.open(amapMarkerURL(row), '_blank', 'noopener,noreferrer')}>高德坐标</Button>
|
<Button size="small" onClick={() => window.open(amapMarkerURL(row), '_blank', 'noopener,noreferrer')}>高德坐标</Button>
|
||||||
<Button size="small" onClick={() => onOpenHistory?.(row.vin, filters.protocol || row.primaryProtocol)}>轨迹回放</Button>
|
<Button size="small" onClick={() => onOpenHistory?.(row.vin, filters.protocol || row.primaryProtocol)}>轨迹回放</Button>
|
||||||
<Button size="small" disabled={!onOpenQuality} onClick={() => openQualityEvidence(row)}>质量问题</Button>
|
<Button size="small" disabled={!onOpenQuality} onClick={() => openQualityEvidence(row)}>告警事件</Button>
|
||||||
<Button size="small" onClick={() => onOpenVehicle(row.vin, filters.protocol || row.primaryProtocol)}>地图车辆服务</Button>
|
<Button size="small" onClick={() => onOpenVehicle(row.vin, filters.protocol || row.primaryProtocol)}>车辆详情</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1117,13 +1117,13 @@ export function Realtime({
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '来源证据',
|
title: '实时通道',
|
||||||
width: 260,
|
width: 260,
|
||||||
render: (_: unknown, row: VehicleRealtimeRow) => (
|
render: (_: unknown, row: VehicleRealtimeRow) => (
|
||||||
<SourceStatusTags sourceStatus={row.sourceStatus} protocols={row.protocols} lastSeen={row.lastSeen} />
|
<SourceStatusTags sourceStatus={row.sourceStatus} protocols={row.protocols} lastSeen={row.lastSeen} />
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{ title: '证据覆盖', width: 120, render: (_: unknown, row: VehicleRealtimeRow) => sourceEvidenceText(row) },
|
{ title: '数据覆盖', width: 120, render: (_: unknown, row: VehicleRealtimeRow) => sourceEvidenceText(row) },
|
||||||
{ title: '在线', width: 90, render: (_: unknown, row: VehicleRealtimeRow) => <StatusTag status={row.online ? 'ok' : 'offline'} /> },
|
{ title: '在线', width: 90, render: (_: unknown, row: VehicleRealtimeRow) => <StatusTag status={row.online ? 'ok' : 'offline'} /> },
|
||||||
{ title: '最后时间', dataIndex: 'lastSeen', width: 170 },
|
{ title: '最后时间', dataIndex: 'lastSeen', width: 170 },
|
||||||
{
|
{
|
||||||
@@ -1133,7 +1133,7 @@ export function Realtime({
|
|||||||
<Space spacing={4} wrap>
|
<Space spacing={4} wrap>
|
||||||
<Button disabled={!isValidCoordinate(row)} onClick={() => selectRealtimeRow(row)}>地图定位</Button>
|
<Button disabled={!isValidCoordinate(row)} onClick={() => selectRealtimeRow(row)}>地图定位</Button>
|
||||||
<Button disabled={!canOpenVehicle(row.vin)} onClick={() => onOpenVehicle(row.vin, filters.protocol || row.primaryProtocol)}>车辆服务</Button>
|
<Button disabled={!canOpenVehicle(row.vin)} onClick={() => onOpenVehicle(row.vin, filters.protocol || row.primaryProtocol)}>车辆服务</Button>
|
||||||
<Button disabled={!canOpenVehicle(row.vin) || !onOpenQuality} onClick={() => openQualityEvidence(row)}>质量问题</Button>
|
<Button disabled={!canOpenVehicle(row.vin) || !onOpenQuality} onClick={() => openQualityEvidence(row)}>告警事件</Button>
|
||||||
</Space>
|
</Space>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ test('exposes AMap operations shortcuts when map key is configured', async () =>
|
|||||||
fireEvent.click(screen.getByRole('button', { name: '顶部地图态势' }));
|
fireEvent.click(screen.getByRole('button', { name: '顶部地图态势' }));
|
||||||
expect(window.location.hash).toBe('#/map');
|
expect(window.location.hash).toBe('#/map');
|
||||||
expect(await screen.findByRole('heading', { name: '实时地图' })).toBeInTheDocument();
|
expect(await screen.findByRole('heading', { name: '实时地图' })).toBeInTheDocument();
|
||||||
expect(screen.getByText('地图车辆服务队列')).toBeInTheDocument();
|
expect(screen.getByText('地图车辆队列')).toBeInTheDocument();
|
||||||
fireEvent.click(screen.getByRole('button', { name: '顶部实时监控' }));
|
fireEvent.click(screen.getByRole('button', { name: '顶部实时监控' }));
|
||||||
expect(window.location.hash).toBe('#/realtime');
|
expect(window.location.hash).toBe('#/realtime');
|
||||||
fireEvent.click(screen.getByRole('button', { name: '顶部轨迹回放' }));
|
fireEvent.click(screen.getByRole('button', { name: '顶部轨迹回放' }));
|
||||||
@@ -8791,11 +8791,11 @@ test('frames realtime page as one vehicle service with source evidence', async (
|
|||||||
expect(screen.getByText('高德地图待配置')).toBeInTheDocument();
|
expect(screen.getByText('高德地图待配置')).toBeInTheDocument();
|
||||||
expect(screen.getAllByText('定位有效').length).toBeGreaterThan(0);
|
expect(screen.getAllByText('定位有效').length).toBeGreaterThan(0);
|
||||||
expect(screen.getByText('车辆核心数据')).toBeInTheDocument();
|
expect(screen.getByText('车辆核心数据')).toBeInTheDocument();
|
||||||
expect(screen.getByText('来源证据')).toBeInTheDocument();
|
expect(screen.getByText('实时通道')).toBeInTheDocument();
|
||||||
expect(screen.getByText('GB32960 在线')).toBeInTheDocument();
|
expect(screen.getByText('GB32960 在线')).toBeInTheDocument();
|
||||||
expect(screen.getByText('JT808 在线')).toBeInTheDocument();
|
expect(screen.getByText('JT808 在线')).toBeInTheDocument();
|
||||||
expect(screen.getByText('YUTONG_MQTT 未接入')).toBeInTheDocument();
|
expect(screen.getByText('YUTONG_MQTT 未接入')).toBeInTheDocument();
|
||||||
expect(screen.getAllByText('2/2 来源在线').length).toBeGreaterThan(0);
|
expect(screen.getAllByText('2/2 通道在线').length).toBeGreaterThan(0);
|
||||||
expect(screen.getByText('实时运营影响')).toBeInTheDocument();
|
expect(screen.getByText('实时运营影响')).toBeInTheDocument();
|
||||||
expect(screen.getByRole('button', { name: /复制影响报告/ })).toBeInTheDocument();
|
expect(screen.getByRole('button', { name: /复制影响报告/ })).toBeInTheDocument();
|
||||||
expect(screen.getByText('需要处置')).toBeInTheDocument();
|
expect(screen.getByText('需要处置')).toBeInTheDocument();
|
||||||
@@ -9177,7 +9177,7 @@ test('copies realtime operations summary from realtime page', 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('当前筛选:数据来源:JT808;在线:在线'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('当前筛选:数据通道:JT808;在线:在线'));
|
||||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆总数:3,当前页:3'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆总数:3,当前页:3'));
|
||||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('在线车辆:2,定位有效:2'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('在线车辆:2,定位有效:2'));
|
||||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('需要关注:2,数据通道:3'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('需要关注:2,数据通道:3'));
|
||||||
@@ -9187,7 +9187,7 @@ test('copies realtime operations summary from realtime page', async () => {
|
|||||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('实时页面:http://localhost:3000/#/realtime?protocol=JT808&online=online'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('实时页面:http://localhost:3000/#/realtime?protocol=JT808&online=online'));
|
||||||
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('当前筛选:数据来源:JT808;在线:在线'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('当前筛选:数据通道:JT808;在线:在线'));
|
||||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('异常车辆:3 / 当前页 3 / 总计 3'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('异常车辆:3 / 当前页 3 / 总计 3'));
|
||||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('粤A摘要3 / VIN-RT-SUMMARY-003 / JT808'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('粤A摘要3 / VIN-RT-SUMMARY-003 / JT808'));
|
||||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('状态:车辆离线;在线:离线;问题:'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('状态:车辆离线;在线:离线;问题:'));
|
||||||
@@ -9205,7 +9205,7 @@ test('copies realtime operations summary from realtime page', async () => {
|
|||||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('实时入口:http://localhost:3000/#/realtime?protocol=JT808&online=online'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('实时入口:http://localhost:3000/#/realtime?protocol=JT808&online=online'));
|
||||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆服务:http://localhost:3000/#/detail?keyword=VIN-RT-SUMMARY-003&protocol=JT808'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆服务:http://localhost:3000/#/detail?keyword=VIN-RT-SUMMARY-003&protocol=JT808'));
|
||||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('里程统计:http://localhost:3000/#/mileage?keyword=VIN-RT-SUMMARY-003&protocol=JT808'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('里程统计:http://localhost:3000/#/mileage?keyword=VIN-RT-SUMMARY-003&protocol=JT808'));
|
||||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('历史RAW:http://localhost:3000/api/history/raw-frames?protocol=JT808&vin=VIN-RT-SUMMARY-003&limit=20&includeFields=true'));
|
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('原始记录:http://localhost:3000/api/history/raw-frames?protocol=JT808&vin=VIN-RT-SUMMARY-003&limit=20&includeFields=true'));
|
||||||
fireEvent.click(screen.getByRole('button', { name: '实时筛选 需要关注 2' }));
|
fireEvent.click(screen.getByRole('button', { name: '实时筛选 需要关注 2' }));
|
||||||
expect(window.location.hash).toBe('#/realtime?protocol=JT808&serviceStatus=degraded&online=online');
|
expect(window.location.hash).toBe('#/realtime?protocol=JT808&serviceStatus=degraded&online=online');
|
||||||
fireEvent.click(screen.getByRole('button', { name: '筛选数据通道 GB32960' }));
|
fireEvent.click(screen.getByRole('button', { name: '筛选数据通道 GB32960' }));
|
||||||
@@ -9313,7 +9313,7 @@ test('shows production AMap integration status on realtime page', async () => {
|
|||||||
|
|
||||||
render(<App />);
|
render(<App />);
|
||||||
|
|
||||||
expect(await screen.findByText('地图能力状态')).toBeInTheDocument();
|
expect(await screen.findByText('地图展示状态')).toBeInTheDocument();
|
||||||
expect(screen.getByText('Web JS Key')).toBeInTheDocument();
|
expect(screen.getByText('Web JS Key')).toBeInTheDocument();
|
||||||
expect(screen.getByText('服务端 API Key')).toBeInTheDocument();
|
expect(screen.getByText('服务端 API Key')).toBeInTheDocument();
|
||||||
expect(screen.getAllByText('已配置').length).toBeGreaterThan(0);
|
expect(screen.getAllByText('已配置').length).toBeGreaterThan(0);
|
||||||
@@ -9508,10 +9508,10 @@ test('opens vehicle service from realtime map service queue', async () => {
|
|||||||
|
|
||||||
render(<App />);
|
render(<App />);
|
||||||
|
|
||||||
expect(await screen.findByText('地图车辆服务队列')).toBeInTheDocument();
|
expect(await screen.findByText('地图车辆队列')).toBeInTheDocument();
|
||||||
expect(screen.getAllByText('粤AMAP01').length).toBeGreaterThan(0);
|
expect(screen.getAllByText('粤AMAP01').length).toBeGreaterThan(0);
|
||||||
expect(screen.getByText('JT808 离线,GB32960 仍可支撑车辆服务')).toBeInTheDocument();
|
expect(screen.getByText('JT808 离线,GB32960 仍可支撑车辆服务')).toBeInTheDocument();
|
||||||
fireEvent.click(screen.getByRole('button', { name: '地图车辆服务' }));
|
fireEvent.click(screen.getByRole('button', { name: '车辆详情' }));
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(window.location.hash).toBe('#/detail?keyword=VIN-MAP-001&protocol=GB32960');
|
expect(window.location.hash).toBe('#/detail?keyword=VIN-MAP-001&protocol=GB32960');
|
||||||
@@ -9579,7 +9579,7 @@ test('opens amap coordinate and trajectory playback from realtime map service qu
|
|||||||
|
|
||||||
render(<App />);
|
render(<App />);
|
||||||
|
|
||||||
expect(await screen.findByText('地图车辆服务队列')).toBeInTheDocument();
|
expect(await screen.findByText('地图车辆队列')).toBeInTheDocument();
|
||||||
fireEvent.click(screen.getByRole('button', { name: '高德坐标' }));
|
fireEvent.click(screen.getByRole('button', { name: '高德坐标' }));
|
||||||
expect(openSpy).toHaveBeenCalledWith(
|
expect(openSpy).toHaveBeenCalledWith(
|
||||||
expect.stringContaining('https://uri.amap.com/marker?position=113.24567,23.12345'),
|
expect.stringContaining('https://uri.amap.com/marker?position=113.24567,23.12345'),
|
||||||
@@ -9682,11 +9682,11 @@ test('surfaces multi-source realtime consistency issues with quality drilldown',
|
|||||||
|
|
||||||
render(<App />);
|
render(<App />);
|
||||||
|
|
||||||
expect(await screen.findByText('车辆数据一致性检查')).toBeInTheDocument();
|
expect(await screen.findByText('需关注车辆')).toBeInTheDocument();
|
||||||
expect(screen.getAllByText('粤A一致监控').length).toBeGreaterThan(0);
|
expect(screen.getAllByText('粤A一致监控').length).toBeGreaterThan(0);
|
||||||
expect(screen.getByText('一致性诊断:YUTONG_MQTT 离线,GB32960/JT808 仍可支撑车辆服务')).toBeInTheDocument();
|
expect(screen.getByText('处置说明:YUTONG_MQTT 离线,GB32960/JT808 仍可支撑车辆服务')).toBeInTheDocument();
|
||||||
expect(screen.getByText('一致性:YUTONG_MQTT 离线')).toBeInTheDocument();
|
expect(screen.getByText('问题:YUTONG_MQTT 离线')).toBeInTheDocument();
|
||||||
fireEvent.click(screen.getByRole('button', { name: '检查质量' }));
|
fireEvent.click(screen.getByRole('button', { name: '查看告警' }));
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(window.location.hash).toBe('#/alert-events?keyword=VIN-RT-CONSISTENCY&protocol=GB32960');
|
expect(window.location.hash).toBe('#/alert-events?keyword=VIN-RT-CONSISTENCY&protocol=GB32960');
|
||||||
@@ -9816,7 +9816,7 @@ test('opens quality issues from realtime vehicle row with source evidence', asyn
|
|||||||
render(<App />);
|
render(<App />);
|
||||||
|
|
||||||
expect((await screen.findAllByText('VIN-RT-QUALITY')).length).toBeGreaterThan(0);
|
expect((await screen.findAllByText('VIN-RT-QUALITY')).length).toBeGreaterThan(0);
|
||||||
fireEvent.click(screen.getAllByRole('button', { name: '质量问题' })[0]);
|
fireEvent.click(screen.getAllByRole('button', { name: '告警事件' })[0]);
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(window.location.hash).toBe('#/alert-events?keyword=VIN-RT-QUALITY&protocol=JT808');
|
expect(window.location.hash).toBe('#/alert-events?keyword=VIN-RT-QUALITY&protocol=JT808');
|
||||||
@@ -9991,7 +9991,7 @@ test('shows and clears current realtime service filters', async () => {
|
|||||||
|
|
||||||
expect(await screen.findByText('当前实时筛选')).toBeInTheDocument();
|
expect(await screen.findByText('当前实时筛选')).toBeInTheDocument();
|
||||||
expect(screen.getByText('关键词:粤ART002')).toBeInTheDocument();
|
expect(screen.getByText('关键词:粤ART002')).toBeInTheDocument();
|
||||||
expect(screen.getByText('数据来源:JT808')).toBeInTheDocument();
|
expect(screen.getByText('数据通道:JT808')).toBeInTheDocument();
|
||||||
expect(screen.getByText('在线:在线')).toBeInTheDocument();
|
expect(screen.getByText('在线:在线')).toBeInTheDocument();
|
||||||
expect(screen.getByText('服务状态:来源不完整')).toBeInTheDocument();
|
expect(screen.getByText('服务状态:来源不完整')).toBeInTheDocument();
|
||||||
fireEvent.click(screen.getByRole('button', { name: '清空筛选' }));
|
fireEvent.click(screen.getByRole('button', { name: '清空筛选' }));
|
||||||
@@ -10030,7 +10030,7 @@ test('updates realtime hash when source filters are submitted', async () => {
|
|||||||
|
|
||||||
await screen.findByRole('heading', { name: '实时监控' });
|
await screen.findByRole('heading', { name: '实时监控' });
|
||||||
fireEvent.change(screen.getByPlaceholderText('VIN / 车牌 / 手机号 / OEM'), { target: { value: '粤ART002' } });
|
fireEvent.change(screen.getByPlaceholderText('VIN / 车牌 / 手机号 / OEM'), { target: { value: '粤ART002' } });
|
||||||
fireEvent.click(screen.getByText('全部来源'));
|
fireEvent.click(screen.getByText('全部数据通道'));
|
||||||
fireEvent.click(await screen.findByText('JT808'));
|
fireEvent.click(await screen.findByText('JT808'));
|
||||||
fireEvent.click(screen.getByRole('button', { name: '查询' }));
|
fireEvent.click(screen.getByRole('button', { name: '查询' }));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user