Files
wms-ui/src/hooks/modules/useTable.ts
2026-02-26 17:31:18 +08:00

128 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { TableData, TableInstance } from '@arco-design/web-vue'
import { Message, Modal } from '@arco-design/web-vue'
import type { Options as paginationOptions } from './usePagination'
import { useBreakpoint, usePagination } from '@/hooks'
interface Options<T, U> {
formatResult?: (data: T[]) => U[]
onSuccess?: () => void
immediate?: boolean
rowKey?: keyof T
paginationOption?: paginationOptions
}
interface PaginationParams { page: number, size: number }
type Api<T> = (params: PaginationParams) => Promise<ApiRes<PageRes<T[]>>> | Promise<ApiRes<T[]>>
export function useTable<T extends U, U = T>(api: Api<T>, options?: Options<T, U>) {
const { formatResult, onSuccess, immediate, rowKey } = options || {}
const { pagination, setTotal } = usePagination(() => getTableData(), options?.paginationOption)
const loading = ref(false)
const tableData: Ref<U[]> = ref([])
async function getTableData() {
try {
loading.value = true
const res = await api({ page: pagination.current, size: pagination.pageSize })
const data = !Array.isArray(res.data) ? res.data.list : res.data
tableData.value = formatResult ? formatResult(data) : data
const total = !Array.isArray(res.data) ? res.data.total : data.length
setTotal(total)
// eslint-disable-next-line ts/no-unused-expressions
onSuccess && onSuccess()
} finally {
loading.value = false
}
}
// 是否立即触发
const isImmediate = immediate ?? true
// eslint-disable-next-line ts/no-unused-expressions
isImmediate && getTableData()
// 多选
const selectedKeys = ref<(string | number)[]>([])
const select: TableInstance['onSelect'] = (rowKeys) => {
selectedKeys.value = rowKeys
}
// 全选
const selectAll: TableInstance['onSelectAll'] = (checked) => {
const key = rowKey ?? 'id'
const arr = (tableData.value as TableData[]).filter((i) => !(i?.disabled ?? false))
selectedKeys.value = checked ? arr.map((i) => i[key as string]) : []
}
// 查询
const search = () => {
selectedKeys.value = []
pagination.onChange(1)
}
// 刷新
const refresh = () => {
getTableData()
}
// 删除
const handleDelete = async <T>(
deleteApi: () => Promise<ApiRes<T>>,
options?: { title?: string, content?: string, successTip?: string, showModal?: boolean },
): Promise<boolean | undefined> => {
const onDelete = async () => {
try {
const res = await deleteApi()
if (res.success) {
Message.success(options?.successTip || '删除成功')
selectedKeys.value = []
await getTableData()
}
return res.success
} catch (error) {
return false
}
}
const flag = options?.showModal ?? true // 是否显示对话框
if (!flag) {
return onDelete()
}
Modal.warning({
title: options?.title || '提示',
content: options?.content || '是否确定删除该条数据?',
okButtonProps: { status: 'danger' },
hideCancel: false,
maskClosable: false,
onBeforeOk: onDelete,
})
}
const { breakpoint } = useBreakpoint()
// 表格操作列在小屏下不固定在右侧
const fixed = computed(() => !['xs', 'sm'].includes(breakpoint.value) ? 'right' : undefined)
return {
/** 表格加载状态 */
loading,
/** 表格数据 */
tableData,
/** 获取表格数据 */
getTableData,
/** 搜索页码会重置为1 */
search,
/** 分页的传参 */
pagination,
/** 选择的行keys */
selectedKeys,
/** 选择行 */
select,
/** 全选行 */
selectAll,
/** 处理删除、批量删除 */
handleDelete,
/** 刷新表格数据,页码会缓存 */
refresh,
/** 操作列在小屏场景下不固定在右侧 */
fixed,
}
}