import type { Ref, VNodeChild } from 'vue' import { computed, ref } 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 interface 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[] }