优化列表分页和数据加载

This commit is contained in:
yml2213
2026-07-24 13:25:27 +08:00
parent 6840728da6
commit f91c05c108
17 changed files with 647 additions and 161 deletions
+53 -10
View File
@@ -6,7 +6,7 @@ import {
import { message } from '../utils/antdMessage';
import type { TableProps } from 'antd';
import { ImportOutlined, DeleteOutlined, TagOutlined, FilterOutlined } from '@ant-design/icons';
import { accountApi, userApi, type AccountItem, type UserInfo } from '../api/modules';
import { accountApi, userApi, type AccountItem, type BasicSummary, type UserInfo } from '../api/modules';
import { usePermissions } from '../hooks/usePermissions';
import { formatTime } from '../utils/time';
import { getErrorMessage } from '../utils/error';
@@ -27,9 +27,12 @@ export default function AccountsPage() {
const [importText, setImportText] = useState('');
const [importing, setImporting] = useState(false);
const [tagFilter, setTagFilter] = useState<string>('');
const [searchText, setSearchText] = useState('');
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [batchTagInput, setBatchTagInput] = useState('');
const [batchTagVisible, setBatchTagVisible] = useState(false);
const [total, setTotal] = useState(0);
const [summary, setSummary] = useState<BasicSummary>({ total: 0, assigned_count: 0, unassigned_count: 0, tag_count: 0 });
const [pageSize, setPageSize] = useState(() => {
const v = localStorage.getItem('account_page_size');
return v ? Number(v) || 20 : 20;
@@ -47,14 +50,30 @@ export default function AccountsPage() {
try {
const params: { tag?: string } = {};
if (tagFilter) params.tag = tagFilter;
const data = await accountApi.list(params);
setAccounts(data);
const data = await accountApi.listPaged({
...params,
page: currentPage,
page_size: pageSize,
search: searchText.trim() || undefined,
include_sensitive: canViewFull,
});
setAccounts(data.items);
setTotal(data.total);
} catch (e: unknown) {
message.error(getErrorMessage(e));
} finally {
setLoading(false);
}
}, [tagFilter]);
}, [canViewFull, currentPage, pageSize, searchText, tagFilter]);
const loadSummary = useCallback(async () => {
try {
const data = await accountApi.summary();
setSummary(data);
} catch {
// 统计加载失败时不影响主列表操作。
}
}, []);
const loadUsers = useCallback(async () => {
try {
@@ -76,9 +95,13 @@ export default function AccountsPage() {
useEffect(() => {
loadAccounts();
}, [loadAccounts]);
useEffect(() => {
if (canAssign) loadUsers();
loadTags();
}, [loadAccounts, canAssign, loadUsers, loadTags]);
loadSummary();
}, [canAssign, loadUsers, loadTags, loadSummary]);
const tagColorMap = useMemo(() => {
const map: Record<string, string> = {};
@@ -101,6 +124,7 @@ export default function AccountsPage() {
setImportText('');
loadAccounts();
loadTags();
loadSummary();
} catch (e: unknown) {
message.error(getErrorMessage(e));
} finally {
@@ -142,6 +166,7 @@ export default function AccountsPage() {
setSelectedRowKeys([]);
loadAccounts();
loadTags();
loadSummary();
} catch (e: unknown) {
message.error(getErrorMessage(e));
}
@@ -154,6 +179,7 @@ export default function AccountsPage() {
setSelectedRowKeys((prev) => prev.filter((k) => k !== id));
loadAccounts();
loadTags();
loadSummary();
} catch (e: unknown) {
message.error(getErrorMessage(e));
}
@@ -170,6 +196,7 @@ export default function AccountsPage() {
setSelectedRowKeys([]);
loadAccounts();
loadTags();
loadSummary();
} catch (e: unknown) {
message.error(getErrorMessage(e));
}
@@ -279,10 +306,24 @@ export default function AccountsPage() {
placeholder="按标签筛选"
style={{ width: 150 }}
value={tagFilter || undefined}
onChange={(val) => setTagFilter(val || '')}
onChange={(val) => {
setTagFilter(val || '');
setCurrentPage(1);
}}
options={tags.map((t) => ({ value: t, label: t }))}
prefix={<FilterOutlined />}
/>
<Input.Search
allowClear
size="small"
placeholder="搜索账号/标签/备注"
style={{ width: 220 }}
value={searchText}
onChange={(e) => {
setSearchText(e.target.value);
setCurrentPage(1);
}}
/>
{canImport && (
<>
<Button
@@ -323,16 +364,16 @@ export default function AccountsPage() {
<Row gutter={16} style={{ marginBottom: 16 }}>
<Col span={6}>
<Card size="small"><Statistic title="账号总数" value={accounts.length} /></Card>
<Card size="small"><Statistic title="账号总数" value={summary.total} /></Card>
</Col>
<Col span={6}>
<Card size="small"><Statistic title="标签数" value={tags.length} /></Card>
<Card size="small"><Statistic title="标签数" value={summary.tag_count || tags.length} /></Card>
</Col>
<Col span={6}>
<Card size="small">
<Statistic
title="已分配"
value={accounts.filter((a) => a.assigned_to).length}
value={summary.assigned_count}
/>
</Card>
</Col>
@@ -340,7 +381,7 @@ export default function AccountsPage() {
<Card size="small">
<Statistic
title="未分配"
value={accounts.filter((a) => !a.assigned_to).length}
value={summary.unassigned_count}
/>
</Card>
</Col>
@@ -350,6 +391,7 @@ export default function AccountsPage() {
rowSelection={canImport ? {
selectedRowKeys,
onChange: (keys) => setSelectedRowKeys(keys),
preserveSelectedRowKeys: true,
} : undefined}
columns={columns}
dataSource={accounts}
@@ -359,6 +401,7 @@ export default function AccountsPage() {
pagination={{
current: currentPage,
pageSize,
total,
showSizeChanger: true,
showTotal: (t) => `${t}`,
onChange: (page, size) => {