feat(platform): align console with vehicle operations center

This commit is contained in:
lingniu
2026-07-04 18:53:52 +08:00
parent 48642726aa
commit 504a49a13c
8 changed files with 70 additions and 26 deletions

View File

@@ -455,7 +455,7 @@ export default function App() {
const pages: Record<PageKey, JSX.Element> = {
dashboard: <Dashboard onOpenVehicle={openVehicle} onOpenQuality={openQuality} onOpenMap={openMap} onOpenRealtime={openRealtime} onOpenVehicles={openVehicles} onOpenHistory={openHistoryWithFilters} onOpenMileage={openMileageWithFilters} />,
vehicles: <Vehicles onOpenVehicle={openVehicle} onOpenQuality={openQuality} onOpenRealtime={openRealtime} onOpenHistory={openHistoryWithFilters} onFiltersChange={updateVehicleFilters} initialFilters={vehicleFilters} />,
map: <Realtime title="地图态势" description="以车辆服务为中心查看实时位置、在线状态、来源一致性和高德地图接入状态" onOpenVehicle={openVehicle} onOpenHistory={openHistoryForVehicle} onOpenQuality={openQuality} onFiltersChange={updateMapFilters} initialFilters={realtimeFilters} />,
map: <Realtime title="实时地图" description="以车辆服务为中心查看实时位置、在线状态、来源一致性和高德地图接入状态" onOpenVehicle={openVehicle} onOpenHistory={openHistoryForVehicle} onOpenQuality={openQuality} onFiltersChange={updateMapFilters} initialFilters={realtimeFilters} />,
realtime: <Realtime onOpenVehicle={openVehicle} onOpenHistory={openHistoryForVehicle} onOpenQuality={openQuality} onFiltersChange={updateRealtimeFilters} initialFilters={realtimeFilters} />,
detail: <VehicleDetail vin={activeVin} protocol={activeProtocol} platformRelease={platformRelease} onOpenRealtime={openRealtimeForVehicle} onOpenHistory={openHistoryForVehicle} onOpenRaw={openRawForVehicle} onOpenMileage={openMileageForVehicle} onOpenVehicles={openVehicles} onOpenQuality={openQuality} onOpenHistoryEvidence={openHistoryWithFilters} onOpenRawEvidence={openRawWithFilters} onQueryChange={updateVehicleDetailQuery} />,
history: <History mode="trajectory" initialVin={analysisVin} initialProtocol={activeProtocol} initialTab={historyTab} initialFilters={historyFilters} onFiltersChange={updateHistoryFilters} onOpenVehicle={openVehicle} onOpenMileage={openMileageWithFilters} onOpenRaw={openRawWithFilters} />,

View File

@@ -19,14 +19,14 @@ import { isAMapConfigured } from '../config/appConfig';
export type PageKey = 'dashboard' | 'vehicles' | 'map' | 'realtime' | 'detail' | 'history' | 'history-query' | 'mileage' | 'alert-events' | 'quality' | 'notification-rules' | 'ops-quality';
const navItems = [
{ itemKey: 'dashboard', text: '车辆服务总览', icon: <IconHome /> },
{ itemKey: 'dashboard', text: '运营驾驶舱', icon: <IconHome /> },
{ itemKey: 'map', text: '实时地图', icon: <IconMapPin /> },
{ itemKey: 'vehicles', text: '车辆中心', icon: <IconServer /> },
{ itemKey: 'map', text: '地图态势', icon: <IconMapPin /> },
{ itemKey: 'realtime', text: '实时监控', icon: <IconActivity /> },
{ itemKey: 'realtime', text: '实时数据', icon: <IconActivity /> },
{ itemKey: 'detail', text: '车辆档案', icon: <IconSetting /> },
{ itemKey: 'history', text: '轨迹回放', icon: <IconMapPin /> },
{ itemKey: 'history-query', text: '历史查询', icon: <IconHistogram /> },
{ itemKey: 'mileage', text: '统计分析', icon: <IconBarChartHStroked /> },
{ itemKey: 'mileage', text: '统计查询', icon: <IconBarChartHStroked /> },
{ itemKey: 'alert-events', text: '告警事件', icon: <IconHistogram /> },
{ itemKey: 'notification-rules', text: '通知规则', icon: <IconBell /> },
{ itemKey: 'ops-quality', text: '运维质量', icon: <IconPulse /> }
@@ -111,7 +111,10 @@ export function AppShell({
<aside className="vp-sidebar">
<div className="vp-brand">
<span className="vp-brand-mark" />
<span></span>
<span className="vp-brand-copy">
<span></span>
<span> / / / </span>
</span>
</div>
<Nav
selectedKeys={[selectedPage]}
@@ -147,9 +150,9 @@ export function AppShell({
) : null}
<Tag color="blue"></Tag>
{platformRelease ? <Tag color="blue"> {platformRelease}</Tag> : null}
<Tag color="grey"> / </Tag>
<Tag color="grey">32960 / 808 / MQTT </Tag>
<Tag color={amapConfigured ? 'green' : 'orange'}>{amapConfigured ? '地图就绪' : '地图待配置'}</Tag>
<Button size="small" aria-label="顶部地图态势" onClick={() => onChange('map')}></Button>
<Button size="small" aria-label="顶部地图态势" onClick={() => onChange('map')}></Button>
<Button size="small" aria-label="顶部实时监控" onClick={() => onChange('realtime')}></Button>
<Button size="small" aria-label="顶部轨迹回放" onClick={() => onChange('history')}></Button>
<Button size="small" aria-label="顶部历史查询" onClick={() => onChange('history-query')}></Button>

View File

@@ -312,10 +312,10 @@ export function Dashboard({
}));
const capabilities = [
{
title: '地图态势',
title: '实时地图',
status: `在线态势 ${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)}`,
color: 'green' as const,
description: '以地图为主视角查看车辆在线分布、定位有效性、来源一致性和高德接入状态。',
description: '以高德地图为主视角查看车辆在线分布、定位有效性、来源一致性和地图接入状态。',
action: '打开地图',
onClick: () => onOpenMap({ online: 'online' })
},
@@ -323,7 +323,7 @@ export function Dashboard({
title: '实时监控',
status: `在线 ${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)}`,
color: 'green' as const,
description: '按车辆聚合最新位置、在线状态和多来源实时字段,支持地图态势查看。',
description: '按车辆聚合最新位置、在线状态和多来源实时字段,支持实时地图查看。',
action: '查看在线车辆',
onClick: () => onOpenRealtime({ online: 'online' })
},
@@ -413,7 +413,7 @@ export function Dashboard({
return (
<div className="vp-page">
<PageHeader title="车辆服务总览" description="三个数据源最终汇总为一个车辆服务,统一承载实时监控、轨迹回放、历史查询、告警通知、统计查询和链路质量" />
<PageHeader title="运营驾驶舱" description="三个数据源最终汇总为一个车辆服务,统一承载实时监控、轨迹回放、历史查询、告警通知、统计查询和链路质量" />
<Spin spinning={loading}>
<div className="vp-kpi-grid">
{kpis.map((item) => (

View File

@@ -34,7 +34,7 @@ body {
}
.vp-brand {
height: 44px;
min-height: 54px;
display: flex;
align-items: center;
gap: 10px;
@@ -50,6 +50,25 @@ body {
background: linear-gradient(135deg, var(--vp-primary), var(--vp-cyan));
}
.vp-brand-copy {
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
line-height: 18px;
}
.vp-brand-copy span:first-child {
font-size: 15px;
}
.vp-brand-copy span:last-child {
color: var(--vp-text-muted);
font-size: 11px;
font-weight: 500;
white-space: nowrap;
}
.vp-main {
min-width: 0;
}

View File

@@ -12,7 +12,7 @@ afterEach(() => {
test('renders vehicle platform shell', () => {
render(<App />);
expect(screen.getByText('车辆服务中台')).toBeInTheDocument();
expect(screen.getAllByText('车辆服务总览').length).toBeGreaterThanOrEqual(1);
expect(screen.getAllByText('运营驾驶舱').length).toBeGreaterThanOrEqual(1);
});
test('exposes AMap operations shortcuts when map key is configured', async () => {
@@ -82,7 +82,7 @@ test('exposes AMap operations shortcuts when map key is configured', async () =>
expect(screen.getByText('版本 platform-20260704153357')).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '顶部地图态势' }));
expect(window.location.hash).toBe('#/map');
expect(await screen.findByRole('heading', { name: '地图态势' })).toBeInTheDocument();
expect(await screen.findByRole('heading', { name: '实时地图' })).toBeInTheDocument();
expect(screen.getByText('地图车辆服务队列')).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '顶部实时监控' }));
expect(window.location.hash).toBe('#/realtime');
@@ -452,7 +452,7 @@ test('dashboard exposes vehicle data center capability matrix', async () => {
};
await renderDashboard();
expect(screen.getAllByText('地图态势').length).toBeGreaterThanOrEqual(1);
expect(screen.getAllByText('实时地图').length).toBeGreaterThanOrEqual(1);
expect(screen.getAllByText('实时监控').length).toBeGreaterThanOrEqual(1);
expect(screen.getAllByText('轨迹回放').length).toBeGreaterThanOrEqual(1);
expect(screen.getAllByText('历史数据查询').length).toBeGreaterThanOrEqual(1);
@@ -470,7 +470,7 @@ test('dashboard exposes vehicle data center capability matrix', async () => {
cleanup();
await renderDashboard();
fireEvent.click(screen.getByRole('button', { name: '能力入口 地图态势' }));
fireEvent.click(screen.getByRole('button', { name: '能力入口 实时地图' }));
expect(window.location.hash).toBe('#/map?online=online');
cleanup();
@@ -7923,7 +7923,7 @@ test('shows realtime freshness status for recently updated and stale vehicles',
render(<App />);
expect(await screen.findByRole('heading', { name: '地图态势' })).toBeInTheDocument();
expect(await screen.findByRole('heading', { name: '实时地图' })).toBeInTheDocument();
expect(screen.getAllByText('数据新鲜').length).toBeGreaterThan(0);
expect(screen.getAllByText('更新超时').length).toBeGreaterThan(0);
expect(screen.getByText('超时车辆')).toBeInTheDocument();