feat(platform): add vehicle detail aggregate api
This commit is contained in:
@@ -8,6 +8,7 @@ import type {
|
||||
QualityIssueRow,
|
||||
RawFrameRow,
|
||||
RealtimeLocationRow,
|
||||
VehicleDetail,
|
||||
VehicleRow
|
||||
} from './types';
|
||||
|
||||
@@ -23,6 +24,7 @@ async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
export const api = {
|
||||
dashboardSummary: () => request<DashboardSummary>('/api/dashboard/summary'),
|
||||
vehicles: (params = new URLSearchParams()) => request<Page<VehicleRow>>(`/api/vehicles?${params.toString()}`),
|
||||
vehicleDetail: (params = new URLSearchParams()) => request<VehicleDetail>(`/api/vehicles/detail?${params.toString()}`),
|
||||
realtimeLocations: (params = new URLSearchParams()) => request<Page<RealtimeLocationRow>>(`/api/realtime/locations?${params.toString()}`),
|
||||
historyLocations: (params = new URLSearchParams()) => request<Page<HistoryLocationRow>>(`/api/history/locations?${params.toString()}`),
|
||||
rawFrames: (params = new URLSearchParams()) => request<Page<RawFrameRow>>(`/api/history/raw-frames?${params.toString()}`),
|
||||
|
||||
@@ -38,6 +38,16 @@ export interface VehicleRow {
|
||||
bindingScore: number;
|
||||
}
|
||||
|
||||
export interface VehicleDetail {
|
||||
vin: string;
|
||||
identity?: VehicleRow;
|
||||
sources: string[];
|
||||
realtime: RealtimeLocationRow[];
|
||||
history: Page<HistoryLocationRow>;
|
||||
raw: Page<RawFrameRow>;
|
||||
mileage: Page<DailyMileageRow>;
|
||||
}
|
||||
|
||||
export interface RealtimeLocationRow {
|
||||
vin: string;
|
||||
plate: string;
|
||||
|
||||
@@ -2,18 +2,10 @@ import { Button, Card, Descriptions, Form, Select, Space, Table, Tabs, Tag, Toas
|
||||
import { IconRefresh, IconSearch } from '@douyinfe/semi-icons';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { api } from '../api/client';
|
||||
import type { DailyMileageRow, HistoryLocationRow, RawFrameRow, RealtimeLocationRow, VehicleRow } from '../api/types';
|
||||
import type { VehicleDetail as VehicleDetailData } from '../api/types';
|
||||
import { PageHeader } from '../components/PageHeader';
|
||||
import { StatusTag } from '../components/StatusTag';
|
||||
|
||||
type VehicleServiceState = {
|
||||
vehicles: VehicleRow[];
|
||||
realtime: RealtimeLocationRow[];
|
||||
history: HistoryLocationRow[];
|
||||
raw: RawFrameRow[];
|
||||
mileage: DailyMileageRow[];
|
||||
};
|
||||
|
||||
type VehicleQuery = {
|
||||
vin: string;
|
||||
protocol?: string;
|
||||
@@ -23,17 +15,9 @@ const defaultQuery: VehicleQuery = {
|
||||
vin: 'LB9A32A24R0LS1426'
|
||||
};
|
||||
|
||||
const emptyState: VehicleServiceState = {
|
||||
vehicles: [],
|
||||
realtime: [],
|
||||
history: [],
|
||||
raw: [],
|
||||
mileage: []
|
||||
};
|
||||
|
||||
export function VehicleDetail() {
|
||||
const [query, setQuery] = useState<VehicleQuery>(defaultQuery);
|
||||
const [state, setState] = useState<VehicleServiceState>(emptyState);
|
||||
const [detail, setDetail] = useState<VehicleDetailData | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const load = (nextQuery = query) => {
|
||||
@@ -43,30 +27,12 @@ export function VehicleDetail() {
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
const scoped = new URLSearchParams({ vin, limit: '20' });
|
||||
const vehicleParams = new URLSearchParams({ keyword: vin, limit: '5' });
|
||||
const rawParams = new URLSearchParams({ vin, limit: '10', includeFields: 'true' });
|
||||
const mileageParams = new URLSearchParams({ vin, limit: '20' });
|
||||
const params = new URLSearchParams({ vin });
|
||||
if (nextQuery.protocol?.trim()) {
|
||||
scoped.set('protocol', nextQuery.protocol.trim());
|
||||
rawParams.set('protocol', nextQuery.protocol.trim());
|
||||
params.set('protocol', nextQuery.protocol.trim());
|
||||
}
|
||||
Promise.all([
|
||||
api.vehicles(vehicleParams),
|
||||
api.realtimeLocations(scoped),
|
||||
api.historyLocations(scoped),
|
||||
api.rawFrames(rawParams),
|
||||
api.dailyMileage(mileageParams)
|
||||
])
|
||||
.then(([vehicles, realtime, history, raw, mileage]) => {
|
||||
setState({
|
||||
vehicles: vehicles.items,
|
||||
realtime: realtime.items,
|
||||
history: history.items,
|
||||
raw: raw.items,
|
||||
mileage: mileage.items
|
||||
});
|
||||
})
|
||||
api.vehicleDetail(params)
|
||||
.then(setDetail)
|
||||
.catch((error: Error) => Toast.error(error.message))
|
||||
.finally(() => setLoading(false));
|
||||
};
|
||||
@@ -75,13 +41,10 @@ export function VehicleDetail() {
|
||||
load(defaultQuery);
|
||||
}, []);
|
||||
|
||||
const identity = state.vehicles[0];
|
||||
const latest = state.realtime[0];
|
||||
const protocols = useMemo(
|
||||
() => Array.from(new Set([...state.vehicles.map((row) => row.protocol), ...state.realtime.map((row) => row.protocol)].filter(Boolean))),
|
||||
[state.realtime, state.vehicles]
|
||||
);
|
||||
const latestRaw = state.raw[0];
|
||||
const identity = detail?.identity;
|
||||
const latest = detail?.realtime[0];
|
||||
const protocols = useMemo(() => detail?.sources ?? [], [detail?.sources]);
|
||||
const latestRaw = detail?.raw.items[0];
|
||||
|
||||
return (
|
||||
<div className="vp-page">
|
||||
@@ -130,7 +93,7 @@ export function VehicleDetail() {
|
||||
loading={loading}
|
||||
pagination={false}
|
||||
rowKey="protocol"
|
||||
dataSource={state.realtime}
|
||||
dataSource={detail?.realtime ?? []}
|
||||
columns={[
|
||||
{ title: '来源', dataIndex: 'protocol', width: 130 },
|
||||
{ title: '经度', dataIndex: 'longitude', width: 120 },
|
||||
@@ -147,7 +110,7 @@ export function VehicleDetail() {
|
||||
loading={loading}
|
||||
pagination={false}
|
||||
rowKey="deviceTime"
|
||||
dataSource={state.history}
|
||||
dataSource={detail?.history.items ?? []}
|
||||
columns={[
|
||||
{ title: '来源', dataIndex: 'protocol', width: 130 },
|
||||
{ title: '经度', dataIndex: 'longitude', width: 120 },
|
||||
@@ -164,7 +127,7 @@ export function VehicleDetail() {
|
||||
loading={loading}
|
||||
pagination={false}
|
||||
rowKey="id"
|
||||
dataSource={state.raw}
|
||||
dataSource={detail?.raw.items ?? []}
|
||||
columns={[
|
||||
{ title: '来源', dataIndex: 'protocol', width: 130 },
|
||||
{ title: '帧类型', dataIndex: 'frameType', width: 190 },
|
||||
@@ -181,7 +144,7 @@ export function VehicleDetail() {
|
||||
loading={loading}
|
||||
pagination={false}
|
||||
rowKey="date"
|
||||
dataSource={state.mileage}
|
||||
dataSource={detail?.mileage.items ?? []}
|
||||
columns={[
|
||||
{ title: '日期', dataIndex: 'date', width: 130 },
|
||||
{ title: '来源', dataIndex: 'source', width: 130 },
|
||||
|
||||
Reference in New Issue
Block a user