fix: paginate operational list pages
This commit is contained in:
@@ -419,6 +419,10 @@ export function AdminSmsRecordsPage() {
|
||||
const [segmentLoading, setSegmentLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
const [page, setPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [filterTenants, setFilterTenants] = useState<Array<{ id: string; name: string }>>([]);
|
||||
const [filterApplications, setFilterApplications] = useState<Array<{ id: string; tenantId: string; name: string }>>([]);
|
||||
|
||||
type MessageFilters = {
|
||||
tenantId?: string;
|
||||
@@ -444,19 +448,30 @@ export function AdminSmsRecordsPage() {
|
||||
};
|
||||
}
|
||||
|
||||
function loadData(filters = currentFilters()) {
|
||||
adminApi.listOperationMessages(filters)
|
||||
.then((items) => {
|
||||
setRecords(items);
|
||||
setSelectedRecord((current) => current ? items.find((item) => item.id === current.id) ?? null : null);
|
||||
setPage(1);
|
||||
function loadData(filters = currentFilters(), targetPage = page) {
|
||||
setLoading(true);
|
||||
adminApi.listOperationMessages({ ...filters, page: targetPage, pageSize })
|
||||
.then((result) => {
|
||||
setRecords(result.items);
|
||||
setTotal(result.total);
|
||||
setSelectedRecord((current) => current ? result.items.find((item) => item.id === current.id) ?? null : null);
|
||||
setError('');
|
||||
})
|
||||
.catch((failure: Error) => setError(failure.message || '短信记录加载失败'));
|
||||
.catch((failure: Error) => setError(failure.message || '短信记录加载失败'))
|
||||
.finally(() => setLoading(false));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
loadData(currentFilters(), page);
|
||||
}, [page]);
|
||||
|
||||
useEffect(() => {
|
||||
Promise.all([adminApi.listTenants(), adminApi.listEnterpriseApplicationOptions()])
|
||||
.then(([tenants, applications]) => {
|
||||
setFilterTenants(tenants.filter((item) => item.status !== 'deleted').map((item) => ({ id: item.id, name: item.name })));
|
||||
setFilterApplications(applications.filter((item) => item.status !== 'deleted').map((item) => ({ id: item.id, tenantId: item.tenantId, name: item.name })));
|
||||
})
|
||||
.catch((failure: Error) => setError(failure.message || '短信记录筛选项加载失败'));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -475,31 +490,19 @@ export function AdminSmsRecordsPage() {
|
||||
}, [selectedRecord]);
|
||||
|
||||
const enterpriseOptions = useMemo(() => {
|
||||
const tenants = new Map<string, string>();
|
||||
records.forEach((record) => {
|
||||
if (record.tenantId) {
|
||||
tenants.set(record.tenantId, record.tenant?.name ?? record.tenantId);
|
||||
}
|
||||
});
|
||||
return [{ label: '全部企业', value: 'all' }, ...Array.from(tenants, ([value, label]) => ({ label, value }))];
|
||||
}, [records]);
|
||||
return [{ label: '全部企业', value: 'all' }, ...filterTenants.map((item) => ({ label: item.name, value: item.id }))];
|
||||
}, [filterTenants]);
|
||||
|
||||
const applicationOptions = useMemo(() => {
|
||||
const applications = new Map<string, string>();
|
||||
records
|
||||
.filter((record) => enterprise === 'all' || record.tenantId === enterprise)
|
||||
.forEach((record) => {
|
||||
if (record.applicationId) {
|
||||
applications.set(record.applicationId, record.application?.name ?? record.applicationId);
|
||||
}
|
||||
});
|
||||
return [{ label: '全部应用', value: 'all' }, ...Array.from(applications, ([value, label]) => ({ label, value }))];
|
||||
}, [enterprise, records]);
|
||||
return [{ label: '全部应用', value: 'all' }, ...filterApplications
|
||||
.filter((item) => enterprise === 'all' || item.tenantId === enterprise)
|
||||
.map((item) => ({ label: item.name, value: item.id }))];
|
||||
}, [enterprise, filterApplications]);
|
||||
|
||||
const filteredRows = records;
|
||||
const totalPages = Math.max(1, Math.ceil(filteredRows.length / pageSize));
|
||||
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
||||
const currentPage = Math.min(page, totalPages);
|
||||
const visibleRows = filteredRows.slice((currentPage - 1) * pageSize, currentPage * pageSize);
|
||||
const visibleRows = filteredRows;
|
||||
|
||||
function resetFilters() {
|
||||
const defaultDateRange = defaultSmsRecordDateRange();
|
||||
@@ -510,7 +513,22 @@ export function AdminSmsRecordsPage() {
|
||||
setContentKeyword('');
|
||||
setChannelKeyword('');
|
||||
setStatus('all');
|
||||
loadData({ queuedAtFrom: defaultDateRange.start, queuedAtTo: defaultDateRange.end });
|
||||
if (page !== 1) setPage(1);
|
||||
else loadData({ queuedAtFrom: defaultDateRange.start, queuedAtTo: defaultDateRange.end }, 1);
|
||||
}
|
||||
|
||||
async function exportRecords() {
|
||||
try {
|
||||
const blob = await adminApi.exportOperationMessages(currentFilters());
|
||||
const url = URL.createObjectURL(blob);
|
||||
const anchor = document.createElement('a');
|
||||
anchor.href = url;
|
||||
anchor.download = `sms-records-${new Date().toISOString().slice(0, 10)}.csv`;
|
||||
anchor.click();
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (failure) {
|
||||
setError(failure instanceof Error ? failure.message : '短信记录导出失败');
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -551,17 +569,17 @@ export function AdminSmsRecordsPage() {
|
||||
value={status}
|
||||
/>
|
||||
<div className="admin-sms-record-filter__actions">
|
||||
<Button icon={<Search size={16} />} onClick={() => loadData()}>查询</Button>
|
||||
<Button icon={<Search size={16} />} onClick={() => { if (page !== 1) setPage(1); else loadData(currentFilters(), 1); }}>查询</Button>
|
||||
<Button onClick={resetFilters} variant="ghost">重置</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="surface admin-sms-record-table-card">
|
||||
<div className="admin-sms-record-toolbar">
|
||||
<Button icon={<Download size={16} />} onClick={() => downloadCsv(filteredRows)} variant="ghost">导出CSV</Button>
|
||||
<Button icon={<Download size={16} />} onClick={() => void exportRecords()} variant="ghost">导出CSV</Button>
|
||||
</div>
|
||||
<div className="admin-sms-record-list">
|
||||
{filteredRows.length === 0 ? <div className="ui-table__empty">暂无短信记录</div> : visibleRows.map((record) => (
|
||||
{loading ? <div className="ui-table__empty">正在加载真实短信记录...</div> : filteredRows.length === 0 ? <div className="ui-table__empty">暂无短信记录</div> : visibleRows.map((record) => (
|
||||
<article className="admin-sms-record-card" key={record.id}>
|
||||
<header>
|
||||
<div className="admin-sms-record-sender">
|
||||
@@ -588,7 +606,7 @@ export function AdminSmsRecordsPage() {
|
||||
onPrevious={() => setPage((current) => Math.max(1, current - 1))}
|
||||
page={currentPage}
|
||||
previousDisabled={currentPage <= 1}
|
||||
total={filteredRows.length}
|
||||
total={total}
|
||||
totalPages={totalPages}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user