feat(platform): preview quality issues on dashboard
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { Button, Card, Col, Form, Row, Select, Space, Spin, Table, Tag, Toast, Typography } from '@douyinfe/semi-ui';
|
import { Button, Card, Col, Form, Row, Select, Space, Spin, Table, Tag, Toast, Typography } from '@douyinfe/semi-ui';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { api } from '../api/client';
|
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 { PageHeader } from '../components/PageHeader';
|
||||||
import { StatusTag } from '../components/StatusTag';
|
import { StatusTag } from '../components/StatusTag';
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@ export function Dashboard({ onOpenVehicle }: { onOpenVehicle: (vin: string) => v
|
|||||||
const [vehicles, setVehicles] = useState<VehicleRow[]>([]);
|
const [vehicles, setVehicles] = useState<VehicleRow[]>([]);
|
||||||
const [coverage, setCoverage] = useState<VehicleCoverageRow[]>([]);
|
const [coverage, setCoverage] = useState<VehicleCoverageRow[]>([]);
|
||||||
const [locations, setLocations] = useState<RealtimeLocationRow[]>([]);
|
const [locations, setLocations] = useState<RealtimeLocationRow[]>([]);
|
||||||
|
const [qualityIssues, setQualityIssues] = useState<QualityIssueRow[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [coverageLoading, setCoverageLoading] = useState(false);
|
const [coverageLoading, setCoverageLoading] = useState(false);
|
||||||
|
|
||||||
@@ -41,13 +42,15 @@ export function Dashboard({ onOpenVehicle }: { onOpenVehicle: (vin: string) => v
|
|||||||
api.dashboardSummary(),
|
api.dashboardSummary(),
|
||||||
api.vehicles(new URLSearchParams({ limit: '5' })),
|
api.vehicles(new URLSearchParams({ limit: '5' })),
|
||||||
api.vehicleCoverage(new URLSearchParams({ limit: '8' })),
|
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);
|
setSummary(nextSummary);
|
||||||
setVehicles(vehiclePage.items);
|
setVehicles(vehiclePage.items);
|
||||||
setCoverage(coveragePage.items);
|
setCoverage(coveragePage.items);
|
||||||
setLocations(locationPage.items);
|
setLocations(locationPage.items);
|
||||||
|
setQualityIssues(qualityPage.items);
|
||||||
})
|
})
|
||||||
.catch((error: Error) => Toast.error(error.message))
|
.catch((error: Error) => Toast.error(error.message))
|
||||||
.finally(() => setLoading(false));
|
.finally(() => setLoading(false));
|
||||||
@@ -110,6 +113,22 @@ export function Dashboard({ onOpenVehicle }: { onOpenVehicle: (vin: string) => v
|
|||||||
<Card title="实时积压" bordered style={{ marginTop: 16 }}>
|
<Card title="实时积压" bordered style={{ marginTop: 16 }}>
|
||||||
<Typography.Text>Kafka 当前消费积压:{formatLag(summary?.kafkaLag)}</Typography.Text>
|
<Typography.Text>Kafka 当前消费积压:{formatLag(summary?.kafkaLag)}</Typography.Text>
|
||||||
</Card>
|
</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 }}>
|
<Card title="车辆服务覆盖" bordered style={{ marginTop: 16 }}>
|
||||||
<Form layout="horizontal" onSubmit={(values) => loadCoverage(values as Record<string, string>)} style={{ marginBottom: 12 }}>
|
<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 }} />
|
<Form.Input field="keyword" label="关键词" placeholder="VIN / 车牌 / 手机号 / OEM" style={{ width: 240 }} />
|
||||||
|
|||||||
Reference in New Issue
Block a user