feat(platform): add realtime next actions
This commit is contained in:
@@ -1214,6 +1214,39 @@ export function Realtime({
|
||||
disabled: rows.length === 0
|
||||
}
|
||||
];
|
||||
const realtimeNextActions = [
|
||||
{
|
||||
level: degradedCount > 0 || staleCount > 0 ? '优先' : '巡检',
|
||||
title: degradedCount > 0 || staleCount > 0 ? '先处理异常车辆' : '先看在线车辆',
|
||||
value: degradedCount > 0 || staleCount > 0 ? `${degradedCount.toLocaleString()} 降级 / ${staleCount.toLocaleString()} 超时` : `${onlineCount.toLocaleString()} 在线`,
|
||||
detail: degradedCount > 0 || staleCount > 0
|
||||
? '离线、更新超时、坐标无效或服务降级会直接影响客户看车体验。'
|
||||
: `当前页 ${locatedCount.toLocaleString()} 辆有有效坐标,可进入地图查看分布。`,
|
||||
action: degradedCount > 0 || staleCount > 0 ? '关注异常' : '打开地图',
|
||||
color: degradedCount > 0 || staleCount > 0 ? 'orange' as const : 'green' as const,
|
||||
onClick: () => degradedCount > 0 || staleCount > 0 ? applyFilters({ ...filters, serviceStatus: 'degraded' }) : (window.location.hash = buildAppHash({ page: 'map', protocol: filters.protocol, filters }))
|
||||
},
|
||||
{
|
||||
level: selectedMapRow ? '单车' : '选车',
|
||||
title: selectedMapRow ? '复盘选中车辆' : '先选择一辆车',
|
||||
value: selectedMapRow?.plate || selectedMapRow?.vin || '等待选车',
|
||||
detail: selectedMapRow ? `${vehicleServiceStatus(selectedMapRow).label},${dataFreshness(selectedMapRow).detail}` : '从地图或实时列表选择车辆后,进入轨迹、里程、历史和告警。',
|
||||
action: selectedMapRow ? '轨迹回放' : '查看车辆',
|
||||
color: selectedMapRow ? vehicleServiceStatus(selectedMapRow).color : 'blue' as const,
|
||||
disabled: selectedMapRow ? !canOpenVehicle(selectedMapRow.vin) : false,
|
||||
onClick: () => selectedMapRow && canOpenVehicle(selectedMapRow.vin) ? onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) : applyFilters({ ...filters, online: 'online' })
|
||||
},
|
||||
{
|
||||
level: '交付',
|
||||
title: '导出当前实时清单',
|
||||
value: `${rows.length.toLocaleString()} 辆当前页`,
|
||||
detail: '客户问询或运营交接时,先导出当前筛选的车辆在线、位置、速度和里程。',
|
||||
action: '导出 CSV',
|
||||
color: rows.length > 0 ? 'blue' as const : 'grey' as const,
|
||||
disabled: rows.length === 0,
|
||||
onClick: exportRealtime
|
||||
}
|
||||
];
|
||||
const timeWindowMonitorBlock = (
|
||||
<Card bordered className="vp-time-window-monitor">
|
||||
<div className="vp-time-window-summary">
|
||||
@@ -1634,6 +1667,24 @@ export function Realtime({
|
||||
<Button size="small" theme="light" onClick={copyRealtimeSummary}>复制监控摘要</Button>
|
||||
</Space>
|
||||
</div>
|
||||
<div className="vp-realtime-next-actions">
|
||||
{realtimeNextActions.map((item) => (
|
||||
<button
|
||||
key={item.title}
|
||||
type="button"
|
||||
className="vp-realtime-next-action"
|
||||
disabled={item.disabled}
|
||||
onClick={item.onClick}
|
||||
aria-label={`实时运营建议 ${item.title} ${item.action}`}
|
||||
>
|
||||
<Tag color={item.color}>{item.level}</Tag>
|
||||
<strong>{item.title}</strong>
|
||||
<span>{item.value}</span>
|
||||
<small>{item.detail}</small>
|
||||
<em>{item.action}</em>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="vp-realtime-customer-steps">
|
||||
{realtimeCustomerJourneyItems.map((item) => (
|
||||
<button
|
||||
|
||||
@@ -1414,6 +1414,70 @@ body {
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
.vp-realtime-next-actions {
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid var(--vp-border);
|
||||
background: #ffffff;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.vp-realtime-next-action {
|
||||
min-height: 126px;
|
||||
padding: 12px;
|
||||
border: 1px solid rgba(22, 100, 255, 0.16);
|
||||
border-radius: var(--vp-radius);
|
||||
background: #fbfcff;
|
||||
color: inherit;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
display: grid;
|
||||
gap: 7px;
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
.vp-realtime-next-action:hover,
|
||||
.vp-realtime-next-action:focus-visible {
|
||||
border-color: rgba(22, 100, 255, 0.42);
|
||||
background: #f5f9ff;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.vp-realtime-next-action:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.58;
|
||||
}
|
||||
|
||||
.vp-realtime-next-action strong {
|
||||
color: var(--vp-text);
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.vp-realtime-next-action span {
|
||||
color: var(--vp-primary);
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
font-weight: 700;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.vp-realtime-next-action small {
|
||||
color: var(--vp-text-muted);
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.vp-realtime-next-action em {
|
||||
color: var(--vp-primary);
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.vp-realtime-customer-steps {
|
||||
padding: 16px;
|
||||
display: grid;
|
||||
@@ -5883,6 +5947,7 @@ button.vp-realtime-command-item:focus-visible {
|
||||
.vp-time-audit-strip,
|
||||
.vp-time-audit-grid,
|
||||
.vp-realtime-customer-board .semi-card-body,
|
||||
.vp-realtime-next-actions,
|
||||
.vp-realtime-customer-steps,
|
||||
.vp-time-window-monitor .semi-card-body,
|
||||
.vp-time-window-controls,
|
||||
|
||||
@@ -9097,6 +9097,9 @@ test('frames realtime page as one vehicle service with source evidence', async (
|
||||
expect(screen.getAllByText('高德地图待配置').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.getByRole('button', { name: '实时运营建议 导出当前实时清单 导出 CSV' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '实时监控路径 只看在线 在线车辆' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '实时监控路径 地图态势 查看地图' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '实时监控路径 异常优先 关注车辆' })).toBeInTheDocument();
|
||||
|
||||
Reference in New Issue
Block a user