You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

305 lines
8.5 KiB

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