import React, { useState, forwardRef, useImperativeHandle, useRef, ReactNode, FC } from 'react' import { Table } from 'antd' import useService from '@/utils/tableHook' import SearchView from '@/components/SearchForm' /** * 封装列表、分页、多选、搜索组件 * @param {RefType} ref 表格的实例,用于调用内部方法 * @param {object[]} columns 表格列的配置 * @param {function} apiFun 表格数据的请求方法 * @param {object[]} searchConfigList 搜索栏配置 * @param {function} beforeSearch 搜索前的操作(如处理一些特殊数据) * @param {function} onFieldsChange 处理搜索栏表单联动事件 * @param {object} extraProps 额外的搜索参数(不在搜索配置内的) * @param {function} onSelectRow 复选框操作回调 * @param {string} rowKey 表格行的key * @param {function} sortConfig 自定义表格排序字段 * @param {function} expandedRowRender 额外的展开行 * @param {function} onExpand 点击展开图标时触发 * @param {string} rowClassName 表格行的样式名 * @param {boolean} small 表格和分页的展示大小 * @param {string[]} extraPagation 额外的分页大小 */ interface TableProps { columns: object[]; apiFun: (arg0?: unknown[]) => Promise<{}>; ref?: RefType; searchConfigList?: object[]; extraProps?: object; rowKey?: string; rowClassName?: string; small?: boolean; showHeader?: boolean; extraPagation?: string[]; beforeSearch?: (arg0?: unknown) => void; onSelectRow?: (arg0?: string[], arg1?: string[]) => void; onFieldsChange?: (arg0?: unknown, arg1?: unknown) => void; sortConfig?: (arg0?: object) => any; expandedRowRender?: () => ReactNode; onExpand?: () => void; header?: JSX.Element } const MyTable: FC = forwardRef( (props: TableProps, ref: RefType) => { /** * @forwardRef * 引用父组件的ref实例,成为子组件的一个参数 * 可以引用父组件的ref绑定到子组件自身的节点上. */ const searchForm: RefType = useRef(null) const { columns, apiFun, searchConfigList, extraProps, rowKey, rowClassName, small, showHeader, extraPagation, beforeSearch, onSelectRow, onFieldsChange, sortConfig, expandedRowRender, onExpand, header } = props // 搜索参数,如果有特殊需要处理的参数,就处理 const searchObj = searchConfigList.reduce( (prev: CommonObjectType, next: CommonObjectType) => { return Object.assign(prev, { [next.key]: next.fn ? next.fn(next.initialValue) : next.initialValue }) }, {} ) // 初始参数 const initParams = { ...searchObj, ...extraProps, page: 1, page_size: 20 } // 多选框的选择值 const [selectedKeys, setSelectedKeys] = useState([]) // 列表所有的筛选参数(包括搜索、分页、排序等) const [tableParams, setTableParams] = useState(initParams) // 列表搜索参数 const [searchParams, setSearchParams] = useState(searchObj) // 列表排序参数 const [sortParams, setSortParams] = useState({}) // 列表分页参数 const [curPageNo, setCurPageNo] = useState(initParams.page) const [curPageSize, setCurPageSize] = useState(initParams.page_size) const { loading = false, response = {} }: CommonObjectType = useService( apiFun, tableParams ); let tableData = []; let total = 0; const validData = response?.data ? response.data : []; if (Array.isArray(validData) && validData.length >= 0) { tableData = validData; total = validData.length; } if (validData.rows) { tableData = validData.rows; total = validData.total; } // const validData = response?.data ? response.data : {} // const { rows: tableData = [], total } = validData // 执行搜索操作 const handleSearch = (val: CommonObjectType): void => { if (val.login) { val.login = Number(val.login) } const obj = { ...val } if (Array.isArray(obj.chain_id)) { obj.chain_id = Number(obj.chain_id[0]) } setSearchParams(obj) setTableParams({ ...tableParams, ...obj, page: 1 }) } // 重置列表部分状态 const resetAction = (page?: number): void => { setSelectedKeys([]) const nextPage = page || curPageNo const nextParmas = page === 1 ? {} : { ...searchParams, ...sortParams } setCurPageNo(nextPage) setTableParams({ ...initParams, ...nextParmas, page: nextPage, page_size: curPageSize }) } // 列表复选框选中变化 const onSelectChange = ( selectedRowKeys: any[], selectedRows: any[] ): void => { setSelectedKeys(selectedRowKeys) onSelectRow(selectedRowKeys, selectedRows) } // 复选框配置 const rowSelection = { selectedRowKeys: selectedKeys, onChange: onSelectChange } // 判断是否有复选框显示 const showCheckbox = onSelectRow ? { rowSelection } : {} // 展开配置 const expendConfig = { expandedRowRender, onExpand, rowClassName } // 判断是否有展开行 const showExpend = expandedRowRender ? expendConfig : {} // 表格和分页的大小 const tableSize = small ? 'small' : 'middle' const pagationSize = small ? 'small' : 'default' // 分页、筛选、排序变化时触发 const onTableChange = ( pagination: CommonObjectType, filters: CommonObjectType, sorter: object ): void => { // 如果有sort排序并且sort参数改变时,优先排序 const sortObj = sortConfig ? sortConfig(sorter) : {} setSortParams(sortObj) const { current: page, pageSize } = pagination setCurPageNo(page) setCurPageSize(pageSize) setTableParams({ ...initParams, ...searchParams, ...sortObj, page, page_size: pageSize }) } /** * @useImperativeHandle * 第一个参数,接收一个通过forwardRef引用父组件的ref实例 * 第二个参数一个回调函数,返回一个对象,对象里面存储需要暴露给父组件的属性或方法 */ useImperativeHandle(ref, () => ({ // 更新列表 update(page?: number): void { resetAction(page) }, // 更新列表,并重置搜索字段 resetForm(page?: number): void { if (searchForm.current) searchForm.current.resetFields() setSearchParams({}) resetAction(page) }, // 仅重置搜索字段 resetField(field?: string[]): void { return field ? searchForm.current.resetFields([...field]) : searchForm.current.resetFields() }, // 获取当前列表数据 getTableData(): CommonObjectType[] { return tableData } })) return (
{/* 搜索栏 */} {searchConfigList.length > 0 && (
{header}
)} { header && searchConfigList.length <= 0 &&
{header}
} {/* 列表 */} `共 ${all} 条` }} /> ) } ) MyTable.defaultProps = { searchConfigList: [], ref: null, extraProps: {}, rowKey: 'id', rowClassName: '', small: false, showHeader: true, extraPagation: [], beforeSearch: () => { }, onSelectRow: () => { }, onFieldsChange: () => { }, sortConfig: () => { }, expandedRowRender: null, onExpand: () => { } } export default MyTable