feat(platform): add realtime operations impact board

This commit is contained in:
lingniu
2026-07-04 22:39:10 +08:00
parent 6803d51b78
commit a005dba2d4
3 changed files with 181 additions and 0 deletions

View File

@@ -396,6 +396,46 @@ function realtimeDutyHandoffText({
return lines.join('\n');
}
function realtimeImpactReportText({
filters,
rows,
total,
onlineCount,
locatedCount,
degradedCount,
staleCount,
pageCoverageRate,
amapConfigured,
runtimeRelease
}: {
filters: Record<string, string>;
rows: VehicleRealtimeRow[];
total: number;
onlineCount: number;
locatedCount: number;
degradedCount: number;
staleCount: number;
pageCoverageRate: number;
amapConfigured: boolean;
runtimeRelease?: string;
}) {
const offlineCount = Math.max(0, rows.length - onlineCount);
const impactLevel = degradedCount > 0 || staleCount > 0 || offlineCount > 0 ? '需要处置' : '实时稳定';
return [
'【实时运营影响】',
`当前筛选:${realtimeFilterSummary(filters).join('') || '全部实时车辆'}`,
`运行版本:${runtimeRelease || '未标记'}`,
`影响等级:${impactLevel}`,
`车辆范围:当前页 ${rows.length.toLocaleString()} / 总计 ${total.toLocaleString()},覆盖率 ${formatPercent(pageCoverageRate)}`,
`在线状态:${onlineCount.toLocaleString()} 在线 / ${offlineCount.toLocaleString()} 离线`,
`定位影响:${locatedCount.toLocaleString()} 辆有有效坐标`,
`服务影响:${degradedCount.toLocaleString()} 辆降级 / ${staleCount.toLocaleString()} 辆超时`,
`地图能力:${amapConfigured ? '高德地图可用' : '高德地图未配置,使用坐标预览'}`,
`建议动作:${impactLevel === '实时稳定' ? '保持监控并关注告警队列' : '优先处理离线、超时和来源不完整车辆,并回到轨迹/RAW证据复核'}`,
`实时监控:${appURL(buildAppHash({ page: 'realtime', protocol: filters.protocol, filters }))}`
].join('\n');
}
function buildRealtimeSourceCoverage(rows: VehicleRealtimeRow[]) {
const sourceMap = new Map<string, RealtimeSourceCoverage>();
rows.forEach((row) => {
@@ -624,6 +664,52 @@ export function Realtime({
amapConfigured,
runtimeRelease: runtime?.platformRelease
}), '实时值班交接包');
const realtimeImpactLevel = degradedCount > 0 || staleCount > 0 || rows.length - onlineCount > 0 ? '需要处置' : '实时稳定';
const realtimeImpactColor = realtimeImpactLevel === '实时稳定' ? 'green' as const : degradedCount > 0 || staleCount > 0 ? 'orange' as const : 'blue' as const;
const realtimeImpactItems = [
{
label: '车辆范围',
value: `${rows.length.toLocaleString()} / ${pagination.total.toLocaleString()}`,
detail: `当前页覆盖 ${formatPercent(pageCoverageRate)}`,
color: pageCoverageRate >= 100 ? 'green' as const : 'grey' as const
},
{
label: '在线影响',
value: `${onlineCount.toLocaleString()} 在线`,
detail: `${(rows.length - onlineCount).toLocaleString()} 辆离线`,
color: rows.length - onlineCount > 0 ? 'orange' as const : 'green' as const
},
{
label: '定位影响',
value: `${locatedCount.toLocaleString()}`,
detail: `有效定位率 ${formatPercent(locatedRate)}`,
color: locatedCount > 0 ? 'blue' as const : 'orange' as const
},
{
label: '服务影响',
value: `${degradedCount.toLocaleString()} 降级`,
detail: `${staleCount.toLocaleString()} 辆更新超时`,
color: degradedCount > 0 || staleCount > 0 ? 'orange' as const : 'green' as const
},
{
label: '地图能力',
value: amapConfigured ? '可用' : '坐标预览',
detail: amapConfigured ? '高德地图配置就绪' : '高德未配置,页面降级展示坐标。',
color: amapConfigured ? 'green' as const : 'orange' as const
}
];
const copyRealtimeImpact = () => copyText(realtimeImpactReportText({
filters,
rows,
total: pagination.total,
onlineCount,
locatedCount,
degradedCount,
staleCount,
pageCoverageRate,
amapConfigured,
runtimeRelease: runtime?.platformRelease
}), '实时运营影响');
const selectRealtimeRow = (row: VehicleRealtimeRow) => {
const index = rows.indexOf(row);
if (index < 0) return;
@@ -931,6 +1017,35 @@ export function Realtime({
</div>
</div>
</div>
<Card
bordered
title={<Space><span></span><Button size="small" icon={<IconCopy />} onClick={copyRealtimeImpact}></Button></Space>}
style={{ marginBottom: 16 }}
>
<div className="vp-realtime-impact-board">
<div className="vp-realtime-impact-summary">
<Tag color={realtimeImpactColor}>{realtimeImpactLevel}</Tag>
<div className="vp-monitor-metric-value">{pagination.total.toLocaleString()} </div>
<Typography.Text type="secondary">
{rows.length.toLocaleString()} 线 {onlineCount.toLocaleString()} {locatedCount.toLocaleString()} {degradedCount.toLocaleString()} {staleCount.toLocaleString()}
</Typography.Text>
<Space wrap>
<Tag color={pageCoverageRate >= 100 ? 'green' : 'grey'}> {formatPercent(pageCoverageRate)}</Tag>
<Tag color={amapConfigured ? 'green' : 'orange'}>{amapConfigured ? '高德可用' : '坐标预览'}</Tag>
<Tag color={rows.length - onlineCount > 0 ? 'orange' : 'green'}>{(rows.length - onlineCount).toLocaleString()} 线</Tag>
</Space>
</div>
<div className="vp-realtime-impact-grid">
{realtimeImpactItems.map((item) => (
<div key={item.label} className="vp-realtime-impact-item">
<Tag color={item.color}>{item.label}</Tag>
<strong>{item.value}</strong>
<Typography.Text type="secondary">{item.detail}</Typography.Text>
</div>
))}
</div>
</div>
</Card>
<Card bordered title="实时覆盖判读" style={{ marginBottom: 16 }}>
<div className="vp-stat-insight-grid">
{[