feat(platform): center navigation on vehicle service

This commit is contained in:
lingniu
2026-07-03 23:49:01 +08:00
parent fe92b34356
commit 6c53172ba7
8 changed files with 24 additions and 23 deletions

View File

@@ -16,12 +16,12 @@ export type PageKey = 'dashboard' | 'vehicles' | 'realtime' | 'detail' | 'histor
const navItems = [
{ itemKey: 'dashboard', text: '总览工作台', icon: <IconHome /> },
{ itemKey: 'vehicles', text: '车辆台账', icon: <IconServer /> },
{ itemKey: 'realtime', text: '实时状态', icon: <IconActivity /> },
{ itemKey: 'vehicles', text: '车辆服务', icon: <IconServer /> },
{ itemKey: 'realtime', text: '实时车辆', icon: <IconActivity /> },
{ itemKey: 'detail', text: '车辆详情', icon: <IconSetting /> },
{ itemKey: 'history', text: '历史查询', icon: <IconMapPin /> },
{ itemKey: 'mileage', text: '里程分析', icon: <IconBarChartHStroked /> },
{ itemKey: 'quality', text: '数据质量', icon: <IconHistogram /> }
{ itemKey: 'history', text: '历史数据', icon: <IconMapPin /> },
{ itemKey: 'mileage', text: '里程统计', icon: <IconBarChartHStroked /> },
{ itemKey: 'quality', text: '质量治理', icon: <IconHistogram /> }
];
function linkHealthClassName(count: number | null) {
@@ -61,7 +61,7 @@ export function AppShell({
<aside className="vp-sidebar">
<div className="vp-brand">
<span className="vp-brand-mark" />
<span></span>
<span></span>
</div>
<Nav
selectedKeys={[activePage]}
@@ -85,6 +85,7 @@ export function AppShell({
</Space>
<Space spacing={12}>
<Tag color="blue"></Tag>
<Tag color="grey"> / </Tag>
<Button size="small" className={linkHealthClassName(linkIssueCount)} onClick={() => onChange('quality')}>
{linkIssueCount == null ? '链路监控' : linkIssueCount > 0 ? `链路 ${linkIssueCount} 项关注` : '链路正常'}
</Button>

View File

@@ -62,7 +62,7 @@ export function Dashboard({ onOpenVehicle, onOpenQuality }: { onOpenVehicle: (vi
return (
<div className="vp-page">
<PageHeader title="总览工作台" description="车辆在线、协议分布、数据质量和链路健康的统一入口" />
<PageHeader title="总览工作台" description="车辆服务为中心汇总在线状态、数据来源覆盖、质量问题和链路健康" />
<Spin spinning={loading}>
<div className="vp-kpi-grid">
{kpis.map((item) => (
@@ -74,12 +74,12 @@ export function Dashboard({ onOpenVehicle, onOpenQuality }: { onOpenVehicle: (vi
</div>
<Row gutter={16}>
<Col span={14}>
<Card title="协议在线分布" bordered>
<Card title="数据来源在线分布" bordered>
<Table
pagination={false}
dataSource={summary?.protocols ?? []}
columns={[
{ title: '协议', dataIndex: 'protocol' },
{ title: '数据来源', dataIndex: 'protocol' },
{ title: '在线', dataIndex: 'online' },
{ title: '总数', dataIndex: 'total' },
{

View File

@@ -101,11 +101,11 @@ export function History({ initialVin, onOpenVehicle }: { initialVin: string; onO
return (
<div className="vp-page">
<PageHeader title="历史查询" description="按车辆查询位置历史和 RAW 帧历史,协议作为来源过滤和诊断维度" />
<PageHeader title="历史数据" description="按车辆查询位置历史和 RAW 帧历史,数据来源只作为过滤和诊断维度" />
<Card bordered>
<Form key={`${filters.vin ?? ''}-${filters.protocol ?? ''}-${filters.includeFields ? 'fields' : 'light'}`} initValues={filters} layout="horizontal" onSubmit={(values) => submit(values)}>
<Form.Input field="vin" label="VIN" placeholder="输入 VIN" style={{ width: 260 }} />
<Form.Select field="protocol" label="协议" placeholder="全部协议" style={{ width: 190 }}>
<Form.Select field="protocol" label="数据来源" placeholder="全部来源" style={{ width: 190 }}>
<Select.Option value="GB32960">GB32960</Select.Option>
<Select.Option value="JT808">JT808</Select.Option>
<Select.Option value="YUTONG_MQTT">YUTONG_MQTT</Select.Option>
@@ -145,7 +145,7 @@ export function History({ initialVin, onOpenVehicle }: { initialVin: string; onO
}}
columns={[
{ title: 'VIN', dataIndex: 'vin', width: 190 },
{ title: '协议', dataIndex: 'protocol', width: 120 },
{ title: '数据来源', dataIndex: 'protocol', width: 120 },
{ title: '经度', dataIndex: 'longitude', width: 120 },
{ title: '纬度', dataIndex: 'latitude', width: 120 },
{ title: '速度 km/h', dataIndex: 'speedKmh', width: 120 },
@@ -179,7 +179,7 @@ export function History({ initialVin, onOpenVehicle }: { initialVin: string; onO
{ title: 'ID', dataIndex: 'id', width: 260 },
{ title: 'VIN', dataIndex: 'vin', width: 190 },
{ title: '车牌', dataIndex: 'plate', width: 120 },
{ title: '协议', dataIndex: 'protocol', width: 120 },
{ title: '数据来源', dataIndex: 'protocol', width: 120 },
{ title: '帧类型', dataIndex: 'frameType', width: 190 },
{ title: '大小 B', dataIndex: 'rawSizeBytes', width: 100 },
{ title: '设备时间', dataIndex: 'deviceTime', width: 190 },

View File

@@ -68,7 +68,7 @@ export function Mileage({ initialVin, onOpenVehicle }: { initialVin: string; onO
return (
<div className="vp-page">
<PageHeader title="里程分析" description="每日里程、区间里程和异常差值分析" />
<PageHeader title="里程统计" description="按车辆汇总每日里程、区间里程和异常差值分析" />
<Card bordered>
<Form key={filters.vin ?? ''} initValues={filters} layout="horizontal" onSubmit={(values) => {
const nextFilters = values as Record<string, string>;
@@ -77,7 +77,7 @@ export function Mileage({ initialVin, onOpenVehicle }: { initialVin: string; onO
load(nextFilters, 1, pagination.pageSize);
}}>
<Form.Input field="vin" 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="JT808">JT808</Select.Option>
<Select.Option value="YUTONG_MQTT">YUTONG_MQTT</Select.Option>

View File

@@ -111,7 +111,7 @@ export function Quality({
return (
<div className="vp-page">
<PageHeader title="数据质量" description="断链、VIN 缺失、字段缺失和链路健康的排查入口" />
<PageHeader title="质量治理" description="围绕车辆服务排查断链、VIN 缺失、字段缺失和链路健康" />
<div className="vp-kpi-grid">
{[
{ label: '问题车辆', value: summary.issueVehicleCount.toLocaleString() },
@@ -145,7 +145,7 @@ export function Quality({
loadIssues(nextFilters, 1, pagination.pageSize);
}} style={{ marginBottom: 12 }}>
<Form.Input field="keyword" label="关键词" placeholder="手机号 / 来源地址 / 车牌" style={{ width: 260 }} />
<Form.Select field="protocol" label="协议" placeholder="全部协议" style={{ width: 160 }}>
<Form.Select field="protocol" label="数据来源" placeholder="全部来源" style={{ width: 160 }}>
<Select.Option value="JT808">JT808</Select.Option>
</Form.Select>
<Space>
@@ -174,7 +174,7 @@ export function Quality({
{ title: '车牌', dataIndex: 'plate' },
{ title: '手机号', dataIndex: 'phone' },
{ title: '来源地址', dataIndex: 'sourceEndpoint' },
{ title: '协议', dataIndex: 'protocol' },
{ title: '数据来源', dataIndex: 'protocol' },
{ title: '问题', dataIndex: 'issueType' },
{ title: '级别', render: (_: unknown, row: QualityIssueRow) => <Tag color={row.severity === 'error' ? 'red' : 'orange'}>{row.severity}</Tag> },
{ title: '最后时间', dataIndex: 'lastSeen' },

View File

@@ -38,7 +38,7 @@ export function Realtime({ onOpenVehicle }: { onOpenVehicle: (vin: string) => vo
return (
<div className="vp-page">
<PageHeader title="实时状态" description="以车辆为主对象查看最新位置、在线来源和核心实时数据" />
<PageHeader title="实时车辆" description="以车辆为主对象查看最新位置、在线来源和核心实时数据" />
<Card bordered>
<Form layout="horizontal" onSubmit={(values) => {
const nextFilters = values as Record<string, string>;
@@ -46,7 +46,7 @@ export function Realtime({ onOpenVehicle }: { onOpenVehicle: (vin: string) => vo
load(nextFilters, 1, pagination.pageSize);
}} style={{ marginBottom: 12 }}>
<Form.Input field="vin" 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="JT808">JT808</Select.Option>
<Select.Option value="YUTONG_MQTT">YUTONG_MQTT</Select.Option>

View File

@@ -57,7 +57,7 @@ export function Vehicles({ onOpenVehicle }: { onOpenVehicle: (vin: string) => vo
return (
<div className="vp-page">
<PageHeader title="车辆台账" description="以 VIN 为主对象维护车辆身份、源覆盖、在线状态和绑定状态" />
<PageHeader title="车辆服务" description="以 VIN 为主对象维护车辆身份、数据来源覆盖、在线状态和绑定状态" />
<Card bordered>
<Form layout="horizontal" onSubmit={(values) => {
const nextFilters = values as Record<string, string>;
@@ -65,7 +65,7 @@ export function Vehicles({ onOpenVehicle }: { onOpenVehicle: (vin: string) => vo
load(nextFilters, 1, pagination.pageSize);
}}>
<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="JT808">JT808</Select.Option>
<Select.Option value="YUTONG_MQTT">YUTONG_MQTT</Select.Option>

View File

@@ -4,6 +4,6 @@ import App from '../App';
test('renders vehicle platform shell', () => {
render(<App />);
expect(screen.getByText('车辆数据中台')).toBeInTheDocument();
expect(screen.getByText('车辆服务中台')).toBeInTheDocument();
expect(screen.getAllByText('总览工作台').length).toBeGreaterThanOrEqual(1);
});