import AniEmpty from "@/components/AnEmpty/AnEmpty.vue"; import { TableColumnData as BaseColumn, TableData as BaseData, Table as BaseTable } from "@arco-design/web-vue"; import { merge } from "lodash-es"; import { PropType, computed, defineComponent, reactive, ref } from "vue"; import { Form, FormInstance, FormModal, FormModalInstance, FormModalProps, FormProps } from "../form"; import { config } from "./table.config"; type DataFn = (search: Record, paging: { page: number; size: number }) => Promise; /** * 表格组件 * @see src/components/table/table.tsx */ export const Table = defineComponent({ name: "Table", props: { /** * 表格数据 * @description 可以是数组或者函数,函数返回值为`{ data: BaseData[], total: number }`类型 */ data: { type: [Array, Function] as PropType, }, /** * 表格列设置 */ columns: { type: Array as PropType, default: () => [], }, /** * 分页参数配置 */ pagination: { type: Object as PropType, default: () => reactive(config.pagination), }, /** * 搜索表单配置 */ search: { type: Object as PropType, }, /** * 新建弹窗配置 */ create: { type: Object as PropType, }, /** * 修改弹窗配置 */ modify: { type: Object as PropType, }, /** * 详情弹窗配置 */ detail: { type: Object as PropType, }, /** * 传递给 Table 组件的属性 */ tableProps: { type: Object as PropType["$props"]>, }, }, setup(props) { const loading = ref(false); const tableRef = ref>(); const searchRef = ref(); const createRef = ref(); const modifyRef = ref(); const renderData = ref([]); const inlined = computed(() => (props.search?.items?.length ?? 0) <= config.searchInlineCount); const reloadData = () => loadData({ current: 1, pageSize: 10 }); const openModifyModal = (data: any) => modifyRef.value?.open(data); /** * 加载数据 * @param pagination 自定义分页 */ const loadData = async (pagination: Partial = {}) => { const merged = { ...props.pagination, ...pagination }; const paging = { page: merged.current, size: merged.pageSize }; const model = searchRef.value?.getModel() ?? {}; // 本地加载 if (Array.isArray(props.data)) { const filters = Object.entries(model); const data = props.data.filter((item) => { return filters.every(([key, value]) => { if (typeof value === "string") { return item[key].includes(value); } return item[key] === value; }); }); renderData.value = data; props.pagination.total = renderData.value.length; props.pagination.current = 1; } // 远程加载 if (typeof props.data === "function") { try { loading.value = true; const resData = await props.data(model, paging); const { data = [], total = 0 } = resData?.data || {}; renderData.value = data; props.pagination.total = total; props.pagination.current = paging.page; } catch (e) { // todo } finally { loading.value = false; } } }; watchEffect(() => { if (Array.isArray(props.data)) { renderData.value = props.data; props.pagination.total = props.data.length; props.pagination.current = 1; } }); onMounted(() => { loadData(); }); if (props.search) { merge(props.search, { formProps: { layout: "inline" } }); } const state = { loading, inlined, tableRef, searchRef, createRef, modifyRef, renderData, loadData, reloadData, openModifyModal, }; provide("ref:table", { ...state, ...props }); return state; }, render() { (this.columns as any).instance = this; return (
{!this.inlined && (
)}
{this.create && ( )} {this.modify && ( )} {this.$slots.action?.()}
{this.inlined &&
}
this.loadData({ current })} > {{ empty: () => , ...this.$slots, }}
); }, }); /** * 表格组件实例 */ export type TableInstance = InstanceType; /** * 表格组件参数 */ export type TableProps = TableInstance["$props"];