feat(platform): preview quality issues on dashboard

This commit is contained in:
lingniu
2026-07-03 22:48:51 +08:00
parent d3c2d8dac5
commit ad76eb45e4

View File

@@ -1,7 +1,7 @@
import { Button, Card, Col, Form, Row, Select, Space, Spin, Table, Tag, Toast, Typography } from '@douyinfe/semi-ui';
import { useEffect, useState } from 'react';
import { api } from '../api/client';
import type { DashboardSummary, LinkHealth, ProtocolStat, RealtimeLocationRow, VehicleCoverageRow, VehicleRow } from '../api/types';
import type { DashboardSummary, LinkHealth, ProtocolStat, QualityIssueRow, RealtimeLocationRow, VehicleCoverageRow, VehicleRow } from '../api/types';
import { PageHeader } from '../components/PageHeader';
import { StatusTag } from '../components/StatusTag';
@@ -20,6 +20,7 @@ export function Dashboard({ onOpenVehicle }: { onOpenVehicle: (vin: string) => v
const [vehicles, setVehicles] = useState<VehicleRow[]>([]);
const [coverage, setCoverage] = useState<VehicleCoverageRow[]>([]);
const [locations, setLocations] = useState<RealtimeLocationRow[]>([]);
const [qualityIssues, setQualityIssues] = useState<QualityIssueRow[]>([]);
const [loading, setLoading] = useState(true);
const [coverageLoading, setCoverageLoading] = useState(false);
@@ -41,13 +42,15 @@ export function Dashboard({ onOpenVehicle }: { onOpenVehicle: (vin: string) => v
api.dashboardSummary(),
api.vehicles(new URLSearchParams({ limit: '5' })),
api.vehicleCoverage(new URLSearchParams({ limit: '8' })),
api.realtimeLocations(new URLSearchParams({ limit: '8' }))
api.realtimeLocations(new URLSearchParams({ limit: '8' })),
api.qualityIssues(new URLSearchParams({ limit: '5' }))
])
.then(([nextSummary, vehiclePage, coveragePage, locationPage]) => {
.then(([nextSummary, vehiclePage, coveragePage, locationPage, qualityPage]) => {
setSummary(nextSummary);
setVehicles(vehiclePage.items);
setCoverage(coveragePage.items);
setLocations(locationPage.items);
setQualityIssues(qualityPage.items);
})
.catch((error: Error) => Toast.error(error.message))
.finally(() => setLoading(false));
@@ -110,6 +113,22 @@ export function Dashboard({ onOpenVehicle }: { onOpenVehicle: (vin: string) => v
<Card title="实时积压" bordered style={{ marginTop: 16 }}>
<Typography.Text>Kafka {formatLag(summary?.kafkaLag)}</Typography.Text>
</Card>
<Card title="质量问题预览" bordered style={{ marginTop: 16 }}>
<Table
pagination={false}
rowKey={(row?: QualityIssueRow) => `${row?.protocol ?? ''}-${row?.issueType ?? ''}-${row?.lastSeen ?? ''}-${row?.detail ?? ''}`}
dataSource={qualityIssues}
columns={[
{ title: 'VIN', dataIndex: 'vin', width: 160 },
{ title: '车牌', dataIndex: 'plate', width: 110 },
{ title: '来源', dataIndex: 'protocol', width: 110 },
{ title: '问题', dataIndex: 'issueType', width: 140 },
{ title: '级别', width: 90, render: (_: unknown, row: QualityIssueRow) => <Tag color={row.severity === 'error' ? 'red' : 'orange'}>{row.severity}</Tag> },
{ title: '最后时间', dataIndex: 'lastSeen', width: 170 },
{ title: '说明', dataIndex: 'detail' }
]}
/>
</Card>
<Card title="车辆服务覆盖" bordered style={{ marginTop: 16 }}>
<Form layout="horizontal" onSubmit={(values) => loadCoverage(values as Record<string, string>)} style={{ marginBottom: 12 }}>
<Form.Input field="keyword" label="关键词" placeholder="VIN / 车牌 / 手机号 / OEM" style={{ width: 240 }} />