import { AnForm, AnFormInstance, AnFormModal, AnFormModalInstance, AnFormModalProps, AnFormProps, getModel } from '@/components/AnForm'; import AnEmpty from '@/components/AnEmpty/AnEmpty.vue'; import { Button, PaginationProps, Table, TableColumnData, TableData, TableInstance } from '@arco-design/web-vue'; import { isArray, merge } from 'lodash-es'; import { InjectionKey, PropType, Ref, VNodeChild, defineComponent, ref } from 'vue'; type DataFn = (params: { page: number; size: number; [key: string]: any }) => any | Promise; export type ArcoTableProps = Omit; export const AnTableContextKey = Symbol('AnTableContextKey') as InjectionKey; export type TableColumnRender = (data: { record: TableData; column: TableColumnData; rowIndex: number }) => VNodeChild; export type ArcoTableSlots = { /** * 自定义 th 元素 */ th?: (column: TableColumnData) => any; /** * 自定义 thead 元素 */ thead?: () => any; /** * 空白展示 */ empty?: () => any; /** * 总结行 */ 'summary-cell'?: (column: TableColumnData, record: TableData, rowIndex: number) => any; /** * 分页器右侧内容 */ 'pagination-right'?: () => any; /** * 分页器左侧内容 */ 'pagination-left'?: () => any; /** * 自定义 td 元素 */ td?: (column: TableColumnData, record: TableData, rowIndex: number) => any; /** * 自定义 tr 元素 */ tr?: (column: TableColumnData, record: TableData, rowIndex: number) => any; /** * 自定义 tbody 元素 */ tbody?: () => any; /** * 拖拽锚点图标 */ 'drag-handle-icon'?: () => any; /** * 表格底部 */ footer?: () => any; /** * 展开行内容 */ 'expand-row'?: () => any; /** * 展开行图标 */ 'expand-icon'?: () => any; /** * 表格列定义。启用时会屏蔽 columns 属性 */ columns?: () => any; }; /** * 表格组件 */ export const AnTable = defineComponent({ name: 'AnTable', props: { /** * 表格数据 * @description 数组或函数,函数请返回数组或 `{ data, total }` 对象 * @example * ```ts * async data(params) { * const res = await api.xxx(params); * const { data, total } = res; * return { data, total } * } * ``` */ data: { type: [Array, Function] as PropType, }, /** * 表格列 * @example * ```ts * [ * { * title: "名字", * dataIndex: "name" * } * ] * ``` */ columns: { type: Array as PropType, default: () => [], }, /** * 分页配置 * @example * ```ts * { * showTotal: true * } * ``` */ paging: { type: Object as PropType, }, /** * 搜索表单 * @example * ```ts * [ * { * label: "姓名关键字", * setter: "input", * } * ] * ``` */ search: { type: Object as PropType, }, /** * 新建弹窗 */ create: { type: Object as PropType, }, /** * 修改弹窗 */ modify: { type: Object as PropType, }, /** * 操作按钮 */ actions: { type: Array as PropType, }, /** * 部件 */ widgets: { type: Array as PropType, }, /** * 传递给 Table 组件的属性 */ tableProps: { type: Object as PropType, }, /** * 传递给 Table 组件的插槽 */ tableSlots: { type: Object as PropType, }, }, setup(props) { const loading = ref(false); const renderData = ref([]); const tableRef = ref(null); const searchRef = ref(null); const createRef = ref(null); const modifyRef = ref(null); const selected = ref([]); const selectedKeys = computed(() => selected.value.map(i => i[props.tableProps?.rowKey ?? 'id'])); const setPaging = (paging: PaginationProps) => { if (props.paging) { merge(props.paging, paging); } }; const resetPaging = () => { setPaging({ current: 1, pageSize: 10 }); }; const loadData = async () => { if (!props.data || Array.isArray(props.data)) { return; } if (await searchRef.value?.validate()) { return; } const page = props.paging?.current ?? 1; const size = props.paging?.pageSize ?? 10; const search = getModel(props.search?.model ?? {}); loading.value = true; try { const params = { ...search, page, size }; const resData = await props.data(params); if (resData) { let data: TableData[] = []; let total = 0; if (isArray(resData)) { data = resData; total = resData.length; } else { data = resData.data ?? []; total = resData.total ?? 0; } renderData.value = data; props.paging?.showTotal && (props.paging.total = total); } } catch (e) { console.log('AnTable load fail: ', e); } loading.value = false; }; const load = (page?: number, size?: number) => { if (props.paging) { page && (props.paging.current = page); size && (props.paging.pageSize = size); } loadData(); }; const reload = () => load(1, 10); watchEffect(() => { if (Array.isArray(props.data)) { renderData.value = props.data; resetPaging(); } }); onMounted(() => { loadData(); }); return { loading, renderData, selected, selectedKeys, tableRef, searchRef, createRef, modifyRef, load, reload, refresh: loadData, }; }, render() { return (
{(this.create || this.actions || this.search || this.widgets) && (
{this.create && } {this.actions &&
{this.actions.map(action => action())}
} {this.search && (
)} {this.widgets &&
{this.widgets.map(widget => widget())}
}
)} {{ empty: () => , ...this.tableSlots, }}
{this.modify && }
); }, }); /** * 表格组件实例 */ export type AnTableInstance = InstanceType; /** * 表格组件参数 */ export type AnTableProps = Pick; export interface AnTableContext { /** * 是否加载中 */ loading: Ref; /** * 表格实例 */ tableRef: Ref; /** * 搜索表单实例 */ searchRef: Ref; /** * 新增弹窗实例 */ createRef: Ref; /** * 修改弹窗实例 */ modifyRef: Ref; /** * 当前表格数据 */ renderData: Ref; /** * 加载数据 */ loadData: () => Promise; /** * 重置加载 */ reload: () => Promise; /** * 重新加载 */ refresh: () => Promise; /** * 原表格参数 */ props: AnTableProps; onPageChange: any; onPageSizeChange: any; }