|
|
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<TableProps> = 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 ( <div> {/* 搜索栏 */} {searchConfigList.length > 0 && ( <div style={{ display: 'flex', justifyContent: 'space-between' }}> <SearchView ref={searchForm} config={searchConfigList} beforeSearch={beforeSearch} handleSearch={handleSearch} onFieldsChange={onFieldsChange} /> {header} </div> )} { header && searchConfigList.length <= 0 && <div>{header}</div> } {/* 列表 */} <Table {...showCheckbox} {...showExpend} rowKey={rowKey} loading={loading} dataSource={tableData} columns={columns} onChange={onTableChange} size={tableSize} showHeader={showHeader} scroll={{ x: 1800 }} pagination={{ size: pagationSize, total, pageSize: tableParams.page_size, current: tableParams.page, showQuickJumper: true, showSizeChanger: true, pageSizeOptions: ['20', '50', '100', '200', ...extraPagation], showTotal: (all) => `共 ${all} 条` }} /> </div> ) } )
MyTable.defaultProps = { searchConfigList: [], ref: null, extraProps: {}, rowKey: 'id', rowClassName: '', small: false, showHeader: true, extraPagation: [], beforeSearch: () => { }, onSelectRow: () => { }, onFieldsChange: () => { }, sortConfig: () => { }, expandedRowRender: null, onExpand: () => { } }
export default MyTable
|