index.tsx 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. import React, { ReactNode, useEffect, useRef, useState } from 'react'
  2. import { Table, Tag, message } from 'antd';
  3. import { Excle } from '@/utils/Excle'
  4. import style from './index.less'
  5. import './index.less'
  6. import { Resizable } from 'react-resizable'
  7. import { SortOrder } from 'antd/lib/table/interface';
  8. import EditableRow from './EditableRow';
  9. import EditableCell from './EditableCell';
  10. export interface DataType {
  11. key: React.Key;
  12. name: string;
  13. age: string;
  14. address: string;
  15. }
  16. const ResizableHeader = (props: { [x: string]: any; onResize: any; width: any }) => {
  17. const { onResize, width, ...restProps } = props;
  18. if (!width) {
  19. return <th {...restProps} />
  20. }
  21. return <Resizable width={width} height={0} onResize={onResize} draggableOpts={{ enableUserSelectHack: false }}>
  22. <th {...restProps} />
  23. </Resizable>
  24. }
  25. /**
  26. * https://ant-design.gitee.io/components/table-cn/#API
  27. */
  28. interface Props {
  29. dataSource: any[],
  30. columns: any[],
  31. excle?: {
  32. fillName: string,//文件名称
  33. filter?: string[]//需要排除的数据,输入数据key
  34. },
  35. total?: number,
  36. current?: number,
  37. pageSize?: number,
  38. rowSelection?: any,//选择
  39. onRow?: {//行操作事件
  40. onClick?: (event?: any) => void, // 点击行
  41. onDoubleClick?: (event?: any) => void,
  42. onContextMenu?: (event?: any) => void,
  43. onMouseEnter?: (event?: any) => void, // 鼠标移入行
  44. onMouseLeave?: (event?: any) => void,
  45. }
  46. pageChange?: (page: number, pageSize?: number) => void,
  47. sizeChange?: (current: number, size?: number) => void,
  48. rowClassName?: string | ((record: any, index: any) => string),//样式
  49. expandedRowRender?: any,//子table
  50. scroll?: { x?: number, y?: number },
  51. summary?: (data: readonly any[]) => ReactNode,
  52. size?: 'small' | 'middle' | 'large',
  53. loading?: boolean,
  54. defaultPageSize?: 10 | 20 | 30 | 100,
  55. bordered?: boolean,
  56. onChange?: (pagination: any, filters: any, sorter: any) => void//服务端排序回调
  57. pagination?: boolean,
  58. showHeader?: 1,
  59. hideOnSinglePage?: boolean,
  60. className?: string,
  61. handelResize?: (columns: any) => void//当表头被拖动改变宽度时回调设置对应的本地保存
  62. sortDirections?: SortOrder[],
  63. isShowTotal?: boolean, // 是否展示总计
  64. myKey?: any,//自定义要用哪个值做key
  65. handleSave?: (row: DataType) => void
  66. }
  67. function Tables(props: Props) {
  68. // //导出数据
  69. let { columns, dataSource, excle, total, handelResize, rowSelection, onRow, isShowTotal = true, hideOnSinglePage, handleSave, rowClassName, className, expandedRowRender, scroll, summary, showHeader, bordered, size = 'small', onChange, sortDirections, pagination, myKey, ...prop } = props
  70. let handleExcle = () => {
  71. if (dataSource.length < 1) {
  72. message.error('请先搜索再导出');
  73. return
  74. }
  75. let thName: any = {};
  76. let obj = columns;
  77. obj.forEach((item: any) => {
  78. thName[item.key] = item.title
  79. })
  80. let fillName = excle?.fillName || ''
  81. let filter = excle?.filter || []
  82. Excle(thName, dataSource, fillName, filter)
  83. }
  84. let ww = document.body.clientWidth < 415
  85. // 拖动宽逻辑
  86. const [cols, setCols] = useState<any>(columns)
  87. const colsRef = useRef<any[]>([])
  88. const components = {
  89. header: {
  90. cell: ResizableHeader
  91. },
  92. body: {
  93. row: EditableRow,
  94. cell: EditableCell
  95. }
  96. }
  97. useEffect(() => {
  98. setCols(columns)
  99. }, [columns])
  100. const handleResize = (index: any) => (e: any, { size }: any) => {
  101. const nextColumns = [...cols]
  102. nextColumns[index] = {
  103. ...nextColumns[index],
  104. width: size.width
  105. }
  106. setCols(nextColumns)
  107. handelResize && handelResize(nextColumns)
  108. }
  109. colsRef.current = (cols || []).map((col: any, index: any) => ({
  110. ...col,
  111. onHeaderCell: (column: any) => ({
  112. width: column.width,
  113. onResize: handleResize(index)
  114. }),
  115. onCell: (record: DataType) => ({
  116. record,
  117. editable: col.editable,
  118. dataIndex: col.dataIndex,
  119. title: col.title,
  120. handleSave: (row: DataType) => { handleSave?.(row) },
  121. }),
  122. }))
  123. return <div className='components-table-resizable-column'>
  124. {
  125. excle && <Tag color='#f50' style={{ margin: '10px 0', float: 'right' }} onClick={handleExcle}><a>导出数据</a></Tag>
  126. }
  127. <Table
  128. components={components}
  129. columns={colsRef?.current}
  130. sortDirections={sortDirections || ['descend', 'ascend', null]}
  131. onChange={(pagination, filters, sorter) => {
  132. onChange && onChange(pagination, filters, sorter)
  133. }}
  134. bordered={bordered ? bordered : false}
  135. dataSource={dataSource}
  136. showHeader={showHeader === 1 ? false : true}
  137. scroll={scroll ? { ...scroll, scrollToFirstRowOnChange: true } : undefined}
  138. size={size}
  139. rowKey={(a: any) => {
  140. if (myKey) {
  141. return JSON.stringify(a[myKey])
  142. }
  143. return (JSON.stringify(a?.id) || JSON.stringify(a?.key))
  144. }}
  145. rowSelection={rowSelection ? rowSelection : undefined}
  146. onRow={record => {
  147. return {
  148. onClick: onRow?.onClick && onRow?.onClick.bind('', record) || undefined,
  149. }
  150. }}
  151. summary={summary}
  152. className={className}
  153. expandable={expandedRowRender ? {
  154. defaultExpandedRowKeys: ['0'],
  155. expandRowByClick: true, expandedRowRender: (data) => {
  156. return expandedRowRender(data)
  157. }
  158. } : {}}
  159. pagination={
  160. {
  161. total: total || 0,//总共多少条数据,服务器给,设置后分页自动计算页数
  162. current: props.current,//当前页数,需state控制配合翻页
  163. pageSize: props?.pageSize,
  164. defaultCurrent: 1,//默认初始的当前页数
  165. defaultPageSize: props?.defaultPageSize || 20,//默认初始的每页条数
  166. pageSizeOptions: ['10', '20', '30', '40', '50', '60', '70', '80', '90', '100'],
  167. showTotal: (total) => isShowTotal ? <Tag color="cyan">总共{total}数据</Tag> : null,
  168. showSizeChanger: true, //手动开启条数筛选器,默认超过50条开启
  169. // size:'small',//设置分页尺寸
  170. //responsive:true,//当 size 未指定时,根据屏幕宽度自动调整尺寸
  171. onChange: props.pageChange, //点击页码或条数筛选时触发获取当前页数和每页条数
  172. onShowSizeChange: props.sizeChange,//点击条数筛选器触发
  173. simple: ww ? true : false,//开启简单分页
  174. hideOnSinglePage: hideOnSinglePage ? hideOnSinglePage : false,//只有一页数据隐藏分页
  175. showLessItems: true
  176. }
  177. }
  178. {...prop}
  179. {...{
  180. rowClassName: typeof rowClassName === 'string' ? (record: any) => {
  181. if (rowClassName && record[rowClassName as string] === 2) {
  182. return style.unfollow
  183. }
  184. if (rowClassName && !record[rowClassName as string]) {
  185. return style.unfollow
  186. }
  187. } : rowClassName
  188. }}
  189. />
  190. </div>
  191. }
  192. export default Tables