fix: paginate operational list pages

This commit is contained in:
hectorzhao
2026-07-28 23:20:13 +08:00
parent 87c5b1eccc
commit b8560372cc
40 changed files with 1208 additions and 422 deletions
+41 -33
View File
@@ -1,4 +1,4 @@
import { Fragment, useEffect, useMemo, useState } from 'react';
import { Fragment, useEffect, useState } from 'react';
import { Clock3, Eye, FileText, Search, StopCircle } from 'lucide-react';
import {
Button,
@@ -99,6 +99,8 @@ export function ClientBatchTasksPage() {
const [tasks, setTasks] = useState<BatchTask[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
const [total, setTotal] = useState(0);
const [applications, setApplications] = useState<Array<{ id: string; name: string }>>([]);
const [keyword, setKeyword] = useState('');
const [application, setApplication] = useState('all');
const [submittedDateRange, setSubmittedDateRange] = useState<DateRangeValue>({});
@@ -106,11 +108,21 @@ export function ClientBatchTasksPage() {
const [page, setPage] = useState(1);
const [selectedTask, setSelectedTask] = useState<BatchTask | null>(null);
function loadTasks() {
const pageSize = 10;
function loadTasks(targetPage = page) {
setLoading(true);
clientApi.listBatchTasks()
.then((items) => {
setTasks(items.map(mapTask));
clientApi.listBatchTasksPage({
keyword: keyword.trim() || undefined,
applicationKeyword: application === 'all' ? undefined : application,
createdAtFrom: submittedDateRange.start,
createdAtTo: submittedDateRange.end,
page: targetPage,
pageSize,
})
.then((result) => {
setTasks(result.items.map(mapTask));
setTotal(result.total);
setError('');
})
.catch((reason: Error) => setError(reason.message || '批量任务加载失败'))
@@ -118,39 +130,28 @@ export function ClientBatchTasksPage() {
}
useEffect(() => {
loadTasks();
}, []);
const applicationOptions = useMemo(() => {
const names = Array.from(new Set(tasks.map((item) => item.applicationName)));
return [
{ label: '全部应用', value: 'all' },
...names.map((name) => ({ label: name, value: name })),
];
}, [tasks]);
const filteredTasks = tasks.filter((item) => {
const matchesKeyword = !keyword || item.id.includes(keyword);
const matchesApplication = application === 'all' || item.applicationName === application;
const submittedDate = item.submittedAt.slice(0, 10);
const matchesStartDate = !submittedDateRange.start || submittedDate >= submittedDateRange.start;
const matchesEndDate = !submittedDateRange.end || submittedDate <= submittedDateRange.end;
return matchesKeyword && matchesApplication && matchesStartDate && matchesEndDate;
});
const pageSize = 10;
const totalPages = Math.max(1, Math.ceil(filteredTasks.length / pageSize));
const currentPage = Math.min(page, totalPages);
const visibleTasks = filteredTasks.slice((currentPage - 1) * pageSize, currentPage * pageSize);
loadTasks(page);
}, [page]);
useEffect(() => {
setPage(1);
}, [application, keyword, submittedDateRange.end, submittedDateRange.start, tasks.length]);
clientApi.listApplicationOptions()
.then((items) => setApplications(items.map((item) => ({ id: item.id, name: item.name }))))
.catch(() => undefined);
}, []);
const applicationOptions = [
{ label: '全部应用', value: 'all' },
...applications.map((item) => ({ label: item.name, value: item.name })),
];
const totalPages = Math.max(1, Math.ceil(total / pageSize));
const currentPage = Math.min(page, totalPages);
const visibleTasks = tasks;
function terminateTask(id: string) {
const source = tasks.find((item) => item.id === id);
if (!source) return;
clientApi.cancelBatchTask(source.backendId)
.then(loadTasks)
.then(() => loadTasks(page))
.catch((reason: Error) => setError(reason.message || '发送批次终止失败'));
}
@@ -236,17 +237,24 @@ export function ClientBatchTasksPage() {
<QueryPanel
title="查询条件"
summary={<> <strong>{filteredTasks.length}</strong> </>}
summary={<> <strong>{total}</strong> </>}
>
<Input
label="发送批次号"
onChange={(event) => setKeyword(event.target.value)}
onKeyDown={(event) => {
if (event.key === 'Enter') {
setPage(1);
loadTasks(1);
}
}}
placeholder="输入发送批次号搜索"
prefix={<Search size={16} />}
value={keyword}
/>
<Select label="选择应用" onChange={(event) => setApplication(event.target.value)} options={applicationOptions} value={application} />
<DateRangeInput label="提交时间" onChange={setSubmittedDateRange} value={submittedDateRange} />
<Button onClick={() => { setPage(1); loadTasks(1); }} variant="primary"></Button>
</QueryPanel>
<div className="surface batch-table-card">
@@ -301,7 +309,7 @@ export function ClientBatchTasksPage() {
totalPages={totalPages}
onPageChange={setPage}
previousDisabled={currentPage <= 1}
total={filteredTasks.length}
total={total}
/>
</div>