import { computed, effectScope, onScopeDispose, reactive, ref, watch } from 'vue'; import type { Ref } from 'vue'; import type { TablePaginationConfig } from 'ant-design-vue'; import { useBoolean, useHookTable } from '@sa/hooks'; import { useAppStore } from '@/store/modules/app'; import { $t } from '@/locales'; type TableData = AntDesign.TableData; type GetTableData = AntDesign.GetTableData; type TableColumn = AntDesign.TableColumn; export function useTable(config: AntDesign.AntDesignTableConfig) { const scope = effectScope(); const appStore = useAppStore(); const { apiFn, apiParams, immediate, rowKey } = config; const { loading, empty, data, columns, columnChecks, reloadColumns, getData, searchParams, updateSearchParams, resetSearchParams } = useHookTable, TableColumn>>>({ apiFn, apiParams, columns: config.columns, transformer: res => { const { rows = [], total = 0 } = res.data || {}; return { rows: rows.map((row, index) => ({ ...row, id: rowKey ? row[rowKey] : index })), total }; }, getColumnChecks: cols => { const checks: AntDesign.TableColumnCheck[] = []; cols.forEach(column => { if (column.key) { checks.push({ key: column.key as string, title: column.title as string, checked: true }); } }); return checks; }, getColumns: (cols, checks) => { const columnMap = new Map>>(); cols.forEach(column => { if (column.key) { columnMap.set(column.key as string, column); } }); const filteredColumns = checks .filter(item => item.checked) .map(check => columnMap.get(check.key) as TableColumn>); return filteredColumns; }, onFetched: async transformed => { const { total } = transformed; updatePagination({ total }); }, immediate }); const pagination: TablePaginationConfig = reactive({ showSizeChanger: true, pageSizeOptions: [10, 15, 20, 25, 30], total: 0, simple: false, // size: 'f', current: 1, pageSize: 10, onChange: async (current: number, pageSize: number) => { pagination.current = current; updateSearchParams({ pageNum: current, pageSize }); getData(); } }); // this is for mobile, if the system does not support mobile, you can use `pagination` directly const mobilePagination = computed(() => { const p: TablePaginationConfig = { ...pagination, simple: appStore.isMobile }; return p; }); function updatePagination(update: Partial) { Object.assign(pagination, update); } scope.run(() => { watch( () => appStore.locale, () => { reloadColumns(); } ); }); onScopeDispose(() => { scope.stop(); }); return { loading, empty, data, columns, columnChecks, reloadColumns, pagination, mobilePagination, updatePagination, getData, searchParams, updateSearchParams, resetSearchParams }; } export function useTableOperate>( data: Ref, options: { getData: () => Promise; idKey?: string; } ) { const { bool: drawerVisible, setTrue: openDrawer, setFalse: closeDrawer } = useBoolean(); const operateType = ref('add'); const { getData, idKey = 'id' } = options; /** the editing row data */ const editingData: Ref = ref(null); function handleAdd() { operateType.value = 'add'; editingData.value = null; openDrawer(); } function handleEdit(id: any) { operateType.value = 'edit'; editingData.value = data.value.find(item => item[idKey] === id) || null; openDrawer(); } /** the checked row keys of table */ const checkedRowKeys = ref([]); /** the hook after the batch delete operation is completed */ async function onBatchDeleted() { $message?.success($t('common.deleteSuccess')); checkedRowKeys.value = []; await getData(); } /** the hook after the delete operation is completed */ async function onDeleted() { $message?.success($t('common.deleteSuccess')); await getData(); } return { drawerVisible, openDrawer, closeDrawer, operateType, handleAdd, editingData, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted }; }