优化列表分页和数据加载
This commit is contained in:
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user