import { computed, ref } from 'vue'; import type { Ref, VNodeChild } from 'vue'; import useBoolean from './use-boolean'; import useLoading from './use-loading'; export interface PaginationData { data: T[]; pageNum: number; pageSize: number; total: number; } type GetApiData = Pagination extends true ? PaginationData : ApiData[]; type Transform = ( response: ResponseData ) => GetApiData; export type TableColumnCheckTitle = string | ((...args: any) => VNodeChild); export type TableColumnCheck = { key: string; title: TableColumnCheckTitle; checked: boolean; visible: boolean; }; export interface UseTableOptions { /** * api function to get table data */ api: () => Promise; /** * whether to enable pagination */ pagination?: Pagination; /** * transform api response to table data */ transform: Transform; /** * columns factory */ columns: () => Column[]; /** * get column checks */ getColumnChecks: (columns: Column[]) => TableColumnCheck[]; /** * get columns */ getColumns: (columns: Column[], checks: TableColumnCheck[]) => Column[]; /** * callback when response fetched */ onFetched?: (data: GetApiData) => void | Promise; /** * whether to get data immediately * * @default true */ immediate?: boolean; } export default function useTable( options: UseTableOptions ) { const { loading, startLoading, endLoading } = useLoading(); const { bool: empty, setBool: setEmpty } = useBoolean(); const { api, pagination, transform, columns, getColumnChecks, getColumns, onFetched, immediate = true } = options; const data = ref([]) as Ref; const columnChecks = ref(getColumnChecks(columns())) as Ref; const $columns = computed(() => getColumns(columns(), columnChecks.value)); function reloadColumns() { const checkMap = new Map(columnChecks.value.map(col => [col.key, col.checked])); const defaultChecks = getColumnChecks(columns()); columnChecks.value = defaultChecks.map(col => ({ ...col, checked: checkMap.get(col.key) ?? col.checked })); } async function getData() { try { startLoading(); const response = await api(); const transformed = transform(response); data.value = getTableData(transformed, pagination); setEmpty(data.value.length === 0); await onFetched?.(transformed); } finally { endLoading(); } } if (immediate) { getData(); } return { loading, empty, data, columns: $columns, columnChecks, reloadColumns, getData }; } function getTableData( data: GetApiData, pagination?: Pagination ) { if (pagination) { return (data as PaginationData).data; } return data as ApiData[]; }