feat(platform): paginate history queries
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Button, Card, Form, Select, SideSheet, Space, Table, Tabs, Toast, Typography } from '@douyinfe/semi-ui';
|
||||
import { IconChevronLeft, IconChevronRight, IconRefresh, IconSearch } from '@douyinfe/semi-icons';
|
||||
import { IconRefresh, IconSearch } from '@douyinfe/semi-icons';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { api } from '../api/client';
|
||||
import type { HistoryLocationRow, Page, RawFrameRow } from '../api/types';
|
||||
@@ -29,6 +29,8 @@ export function History() {
|
||||
const [selectedRaw, setSelectedRaw] = useState<RawFrameRow | null>(null);
|
||||
const [loadingLocations, setLoadingLocations] = useState(false);
|
||||
const [loadingRaw, setLoadingRaw] = useState(false);
|
||||
const [locationPagination, setLocationPagination] = useState({ currentPage: 1, pageSize: 10 });
|
||||
const [rawPagination, setRawPagination] = useState({ currentPage: 1, pageSize: 10 });
|
||||
|
||||
const buildParams = (nextFilters: HistoryFilters, limit: number, offset: number, raw: boolean) => {
|
||||
const params = new URLSearchParams({ limit: String(limit), offset: String(offset) });
|
||||
@@ -41,18 +43,24 @@ export function History() {
|
||||
return params;
|
||||
};
|
||||
|
||||
const loadLocations = (nextFilters = filters, offset = locations.offset) => {
|
||||
const loadLocations = (nextFilters = filters, page = locationPagination.currentPage, pageSize = locationPagination.pageSize) => {
|
||||
setLoadingLocations(true);
|
||||
api.historyLocations(buildParams(nextFilters, locations.limit || 10, offset, false))
|
||||
.then(setLocations)
|
||||
api.historyLocations(buildParams(nextFilters, pageSize, (page - 1) * pageSize, false))
|
||||
.then((nextPage) => {
|
||||
setLocations(nextPage);
|
||||
setLocationPagination({ currentPage: page, pageSize });
|
||||
})
|
||||
.catch((error: Error) => Toast.error(error.message))
|
||||
.finally(() => setLoadingLocations(false));
|
||||
};
|
||||
|
||||
const loadRawFrames = (nextFilters = filters, offset = rawFrames.offset) => {
|
||||
const loadRawFrames = (nextFilters = filters, page = rawPagination.currentPage, pageSize = rawPagination.pageSize) => {
|
||||
setLoadingRaw(true);
|
||||
api.rawFrames(buildParams(nextFilters, rawFrames.limit || 10, offset, true))
|
||||
.then(setRawFrames)
|
||||
api.rawFrames(buildParams(nextFilters, pageSize, (page - 1) * pageSize, true))
|
||||
.then((nextPage) => {
|
||||
setRawFrames(nextPage);
|
||||
setRawPagination({ currentPage: page, pageSize });
|
||||
})
|
||||
.catch((error: Error) => Toast.error(error.message))
|
||||
.finally(() => setLoadingRaw(false));
|
||||
};
|
||||
@@ -67,19 +75,19 @@ export function History() {
|
||||
includeFields: Boolean(values.includeFields)
|
||||
};
|
||||
setFilters(nextFilters);
|
||||
loadLocations(nextFilters, 0);
|
||||
loadRawFrames(nextFilters, 0);
|
||||
loadLocations(nextFilters, 1, locationPagination.pageSize);
|
||||
loadRawFrames(nextFilters, 1, rawPagination.pageSize);
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
setFilters(defaultFilters);
|
||||
loadLocations(defaultFilters, 0);
|
||||
loadRawFrames(defaultFilters, 0);
|
||||
loadLocations(defaultFilters, 1, locationPagination.pageSize);
|
||||
loadRawFrames(defaultFilters, 1, rawPagination.pageSize);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadLocations(defaultFilters, 0);
|
||||
loadRawFrames(defaultFilters, 0);
|
||||
loadLocations(defaultFilters, 1, locationPagination.pageSize);
|
||||
loadRawFrames(defaultFilters, 1, rawPagination.pageSize);
|
||||
}, []);
|
||||
|
||||
const rawFieldCount = useMemo(() => Object.keys(selectedRaw?.parsedFields ?? {}).length, [selectedRaw]);
|
||||
@@ -120,7 +128,14 @@ export function History() {
|
||||
rowKey="deviceTime"
|
||||
dataSource={locations.items}
|
||||
loading={loadingLocations}
|
||||
pagination={false}
|
||||
pagination={{
|
||||
currentPage: locationPagination.currentPage,
|
||||
pageSize: locationPagination.pageSize,
|
||||
total: locations.total,
|
||||
showSizeChanger: true,
|
||||
onPageChange: (page) => loadLocations(filters, page, locationPagination.pageSize),
|
||||
onPageSizeChange: (pageSize) => loadLocations(filters, 1, pageSize)
|
||||
}}
|
||||
columns={[
|
||||
{ title: 'VIN', dataIndex: 'vin', width: 190 },
|
||||
{ title: '协议', dataIndex: 'protocol', width: 120 },
|
||||
@@ -132,19 +147,20 @@ export function History() {
|
||||
{ title: '入库时间', dataIndex: 'serverTime', width: 190 }
|
||||
]}
|
||||
/>
|
||||
<HistoryPager
|
||||
page={locations}
|
||||
loading={loadingLocations}
|
||||
onPrev={() => loadLocations(filters, Math.max(0, locations.offset - locations.limit))}
|
||||
onNext={() => loadLocations(filters, locations.offset + locations.limit)}
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab="RAW 帧" itemKey="raw">
|
||||
<Table
|
||||
rowKey="id"
|
||||
dataSource={rawFrames.items}
|
||||
loading={loadingRaw}
|
||||
pagination={false}
|
||||
pagination={{
|
||||
currentPage: rawPagination.currentPage,
|
||||
pageSize: rawPagination.pageSize,
|
||||
total: rawFrames.total,
|
||||
showSizeChanger: true,
|
||||
onPageChange: (page) => loadRawFrames(filters, page, rawPagination.pageSize),
|
||||
onPageSizeChange: (pageSize) => loadRawFrames(filters, 1, pageSize)
|
||||
}}
|
||||
columns={[
|
||||
{ title: 'ID', dataIndex: 'id', width: 260 },
|
||||
{ title: 'VIN', dataIndex: 'vin', width: 190 },
|
||||
@@ -156,12 +172,6 @@ export function History() {
|
||||
{ title: '操作', width: 100, render: (_: unknown, row: RawFrameRow) => <Button onClick={() => setSelectedRaw(row)}>字段</Button> }
|
||||
]}
|
||||
/>
|
||||
<HistoryPager
|
||||
page={rawFrames}
|
||||
loading={loadingRaw}
|
||||
onPrev={() => loadRawFrames(filters, Math.max(0, rawFrames.offset - rawFrames.limit))}
|
||||
onNext={() => loadRawFrames(filters, rawFrames.offset + rawFrames.limit)}
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
</Card>
|
||||
@@ -179,31 +189,3 @@ export function History() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function HistoryPager<T>({
|
||||
page,
|
||||
loading,
|
||||
onPrev,
|
||||
onNext
|
||||
}: {
|
||||
page: Page<T>;
|
||||
loading: boolean;
|
||||
onPrev: () => void;
|
||||
onNext: () => void;
|
||||
}) {
|
||||
const start = page.offset + 1;
|
||||
const end = page.offset + page.items.length;
|
||||
const hasPrevious = page.offset > 0;
|
||||
const hasNext = page.items.length >= page.limit;
|
||||
return (
|
||||
<div className="vp-table-footer">
|
||||
<Typography.Text type="tertiary">
|
||||
当前 {page.items.length === 0 ? 0 : start}-{end} 条,每页 {page.limit} 条
|
||||
</Typography.Text>
|
||||
<Space>
|
||||
<Button icon={<IconChevronLeft />} disabled={!hasPrevious || loading} onClick={onPrev}>上一页</Button>
|
||||
<Button icon={<IconChevronRight />} disabled={!hasNext || loading} onClick={onNext}>下一页</Button>
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user