feat: 封装表格分页hooks

This commit is contained in:
rd
2025-07-15 17:45:16 +08:00
parent 054da5dd74
commit 48890fcede
3 changed files with 114 additions and 58 deletions

View File

@ -0,0 +1,87 @@
import { ref, computed } from 'vue';
interface UseTableSelectionWithPaginationOptions {
rowKey?: string; // 主键字段名,默认 'id'
pageInfo?: {
page?: number;
page_size?: number;
total?: number;
};
onPageChange?: (page: number) => void;
onPageSizeChange?: (size: number) => void;
}
const DEFAULT_PAGE_INFO = {
page: 1,
pageSize: 20,
total: 0,
};
export function useTableSelectionWithPagination(options: UseTableSelectionWithPaginationOptions = {}) {
const rowKey = options.rowKey || 'id';
const selectedRowKeys = ref<Array<string | number>>([]);
const selectedRows = ref<any[]>([]);
const pageInfo = ref(merge({}, DEFAULT_PAGE_INFO, options.pageInfo));
const dataSource = ref<any[]>([]);
// 单行选择
const handleSelect = (selectedKeys: (string | number)[], rowKeyValue: string | number, record: any) => {
const select = selectedKeys.includes(rowKeyValue);
selectedRowKeys.value = selectedKeys;
if (select) {
if (!selectedRows.value.some((v) => v[rowKey] === record[rowKey])) {
selectedRows.value.push(record);
}
} else {
selectedRows.value = selectedRows.value.filter((v) => v[rowKey] !== record[rowKey]);
}
};
// 全选/取消全选
const handleSelectAll = (checked: boolean) => {
const currentPageRows = dataSource.value;
const currentPageKeys = currentPageRows.map((v) => v[rowKey]);
if (checked) {
selectedRowKeys.value = Array.from(new Set([...selectedRowKeys.value, ...currentPageKeys]));
const allRows = [...selectedRows.value, ...currentPageRows];
const map = new Map();
allRows.forEach((row) => map.set(row[rowKey], row));
selectedRows.value = Array.from(map.values());
} else {
selectedRowKeys.value = selectedRowKeys.value.filter((key) => !currentPageKeys.includes(key));
selectedRows.value = selectedRows.value.filter((row) => !currentPageKeys.includes(row[rowKey]));
}
};
const onPageChange = (page: number) => {
pageInfo.value.page = page;
options.onPageChange?.(page);
};
const onPageSizeChange = (size: number) => {
pageInfo.value.page_size = size;
pageInfo.value.page = 1;
options.onPageSizeChange?.(size);
};
const rowSelection = computed(() => ({
type: 'checkbox',
showCheckedAll: true,
}));
return {
selectedRowKeys,
selectedRows,
dataSource,
pageInfo,
onPageChange,
onPageSizeChange,
rowSelection,
handleSelect,
handleSelectAll,
};
}

View File

@ -44,16 +44,12 @@
ref="tableRef"
:data="dataSource"
column-resizable
:row-selection="{
type: 'checkbox',
showCheckedAll: true,
width: 48,
}"
row-key="account_id"
:selected-keys="selectedRowKeys"
:row-selection="rowSelection"
:row-key="ROW_KEY"
:pagination="false"
:scroll="{ x: '100%', y: '100%' }"
class="w-100% flex-1 overflow-hidden"
:selected-keys="selectedRowKeys"
bordered
@select="handleSelect"
@select-all="handleSelectAll"
@ -97,7 +93,7 @@
show-jumper
show-page-size
:current="pageInfo.page"
:page-size="pageInfo.pageSize"
:page-size="pageInfo.page_size"
@change="onPageChange"
@page-size-change="onPageSizeChange"
/>
@ -126,6 +122,7 @@
import { INITIAL_FORM, INITIAL_PAGE_INFO, TABLE_COLUMNS } from './constants';
import { formatTableField } from '@/utils/tools';
import { postSubAccount, postAddSubAccount } from '@/api/all/propertyMarketing';
import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPagination';
const emits = defineEmits('confirm');
const update = inject('update');
@ -133,13 +130,29 @@ const closeAddAccountModal = inject('closeAddAccountModal');
const closeAuthorizeAccountModal = inject('closeAuthorizeAccountModal');
const visible = ref(false);
const dataSource = ref([]);
const query = ref(cloneDeep(INITIAL_FORM));
const pageInfo = ref(cloneDeep(INITIAL_PAGE_INFO));
const form = ref(null);
const selectedAccounts = ref([]);
const selectedRowKeys = ref([]);
const ROW_KEY = 'account_id';
const {
selectedRowKeys,
selectedRows: selectedAccounts,
dataSource,
pageInfo,
onPageChange,
onPageSizeChange,
rowSelection,
handleSelect,
handleSelectAll,
} = useTableSelectionWithPagination({
rowKey: ROW_KEY,
onPageChange: () => {
getData();
},
onPageSizeChange: () => {
getData();
},
});
const open = (formData) => {
const { platform, account, password } = formData;
@ -152,16 +165,15 @@ const open = (formData) => {
};
getData();
visible.value = true;
};
const onClose = () => {
form.value = null;
selectedAccounts.value = [];
selectedRowKeys.value = [];
query.value = cloneDeep(INITIAL_FORM);
pageInfo.value = cloneDeep(INITIAL_PAGE_INFO);
visible.value = false;
};
@ -181,12 +193,6 @@ const getData = async () => {
...query.value,
page,
page_size,
// platform: 0,
// account: '543366265@qq.com',
// password: 'Xiaoti2025@',
// // page: 1,
// // page_size: 10,
// account_id: '',
});
if (code === 200) {
dataSource.value = data?.data ?? [];
@ -199,43 +205,6 @@ const reload = () => {
getData();
};
const handleSelect = (selectedKeys, rowKey, record) => {
const select = selectedKeys.includes(rowKey);
selectedRowKeys.value = selectedKeys;
if (select) {
selectedAccounts.value.push(record);
} else {
selectedAccounts.value = selectedAccounts.value.filter((v) => v.account_id !== record.account_id);
}
};
const handleSelectAll = (checked) => {
const currentPageAccounts = dataSource.value;
const currentPageKeys = currentPageAccounts.map((v) => v.account_id);
if (checked) {
selectedRowKeys.value = Array.from(new Set([...selectedRowKeys.value, ...currentPageKeys]));
const allAccounts = [...selectedAccounts.value, ...currentPageAccounts];
const map = new Map();
allAccounts.forEach((acc) => map.set(acc.account_id, acc));
selectedAccounts.value = Array.from(map.values());
} else {
selectedRowKeys.value = selectedRowKeys.value.filter((key) => !currentPageKeys.includes(key));
selectedAccounts.value = selectedAccounts.value.filter((acc) => !currentPageKeys.includes(acc.account_id));
}
};
const onPageChange = (current) => {
pageInfo.value.page = current;
getData();
};
const onPageSizeChange = (pageSize) => {
pageInfo.value.page_size = pageSize;
reload();
};
defineExpose({ open });
</script>