|
@@ -0,0 +1,305 @@
|
|
|
|
|
+import React, {
|
|
|
|
|
+ forwardRef,
|
|
|
|
|
+ useCallback,
|
|
|
|
|
+ useEffect,
|
|
|
|
|
+ useImperativeHandle,
|
|
|
|
|
+ useMemo,
|
|
|
|
|
+ useState
|
|
|
|
|
+} from 'react'
|
|
|
|
|
+import styles from './index.module.scss'
|
|
|
|
|
+import { DatePicker, Form, FormInstance, Input, Table, TableProps } from 'antd'
|
|
|
|
|
+import ImageLazy from '../ImageLazy'
|
|
|
|
|
+import classNames from 'classnames'
|
|
|
|
|
+import dayjs from 'dayjs'
|
|
|
|
|
+import { resJiLianFu } from '@/utils/dataChange'
|
|
|
|
|
+
|
|
|
|
|
+interface MyTableProps extends Omit<TableProps, 'onChange'> {
|
|
|
|
|
+ yHeight?: number //设置表格的高度
|
|
|
|
|
+ list: any //表格数据
|
|
|
|
|
+ columnsTemp: any[][] //表格展示
|
|
|
|
|
+ total?: number //总数
|
|
|
|
|
+ pageNum?: number
|
|
|
|
|
+ pageSize?: number
|
|
|
|
|
+ pagingInfo?: any | boolean
|
|
|
|
|
+ onChange?: (pageNum: number, pageSize: number) => void
|
|
|
|
|
+ lastBtn?: any //后面的操作按钮
|
|
|
|
|
+ startBtn?: any
|
|
|
|
|
+ classKey?: string //一个组件多次使用的时候要传递,分别设置style
|
|
|
|
|
+ // 表格简单的合并
|
|
|
|
|
+ merge?: { type: string; num: number; loc: 'rowSpan' | 'colSpan' }
|
|
|
|
|
+ // 定制化表头
|
|
|
|
|
+ myTitle?: { name: string; Com: React.ReactNode }
|
|
|
|
|
+ // 为空的定制字段
|
|
|
|
|
+ isNull?: string
|
|
|
|
|
+ // 设置宽度
|
|
|
|
|
+ widthSet?: any
|
|
|
|
|
+ rowKey?: string
|
|
|
|
|
+ readOnly?: boolean
|
|
|
|
|
+ // 没有数据的时候展示
|
|
|
|
|
+ emptyText?: boolean
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export interface MyTableMethods {
|
|
|
|
|
+ form: FormInstance<any>
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export const getDesensitizeTxt = (txt: string, frontLen = 3, endLen = 4) => {
|
|
|
|
|
+ if (!txt) return txt
|
|
|
|
|
+ const totalVisible = frontLen + endLen
|
|
|
|
|
+ if (txt.length <= totalVisible) {
|
|
|
|
|
+ return txt
|
|
|
|
|
+ }
|
|
|
|
|
+ const frontStr = txt.substring(0, frontLen)
|
|
|
|
|
+ const endStr = endLen > 0 ? txt.substring(txt.length - endLen) : ''
|
|
|
|
|
+ const maskStr = '*'.repeat(txt.length - frontLen - endLen)
|
|
|
|
|
+
|
|
|
|
|
+ return frontStr + maskStr + endStr
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const MyTable = forwardRef<MyTableMethods, MyTableProps>(
|
|
|
|
|
+ (
|
|
|
|
|
+ {
|
|
|
|
|
+ yHeight,
|
|
|
|
|
+ list,
|
|
|
|
|
+ columnsTemp,
|
|
|
|
|
+ total,
|
|
|
|
|
+ pageNum = 1,
|
|
|
|
|
+ pageSize = 10,
|
|
|
|
|
+ pagingInfo = {
|
|
|
|
|
+ showQuickJumper: true,
|
|
|
|
|
+ position: ['bottomCenter'],
|
|
|
|
|
+ showSizeChanger: true
|
|
|
|
|
+ },
|
|
|
|
|
+ onChange,
|
|
|
|
|
+ lastBtn = [],
|
|
|
|
|
+ startBtn = [],
|
|
|
|
|
+ classKey = '',
|
|
|
|
|
+ merge,
|
|
|
|
|
+ myTitle,
|
|
|
|
|
+ isNull = '(空)',
|
|
|
|
|
+ widthSet,
|
|
|
|
|
+ rowKey = 'id',
|
|
|
|
|
+ readOnly,
|
|
|
|
|
+ emptyText,
|
|
|
|
|
+ ...rest
|
|
|
|
|
+ },
|
|
|
|
|
+ ref
|
|
|
|
|
+ ) => {
|
|
|
|
|
+ // 点击操作高亮
|
|
|
|
|
+ const [clickAc, setClickAc] = useState(0)
|
|
|
|
|
+ const [form] = Form.useForm()
|
|
|
|
|
+
|
|
|
|
|
+ // 表格内容定制化
|
|
|
|
|
+ const tableComObj = useCallback(
|
|
|
|
|
+ (key: string, val: string[], id?: any, backFu?: (id: number) => void) => {
|
|
|
|
|
+ const obj = {
|
|
|
|
|
+ // 超链接打开
|
|
|
|
|
+ A: (
|
|
|
|
|
+ <a href={val[1]} target='_blank' title={val[1]} rel='noreferrer'>
|
|
|
|
|
+ {val[0]}
|
|
|
|
|
+ </a>
|
|
|
|
|
+ ),
|
|
|
|
|
+ // 点击触发事件
|
|
|
|
|
+ S: (
|
|
|
|
|
+ <span
|
|
|
|
|
+ className={classNames('MTclick', clickAc === id ? 'MTclickAc' : '')}
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ if (id && backFu) {
|
|
|
|
|
+ backFu(id)
|
|
|
|
|
+ setClickAc(id)
|
|
|
|
|
+ }
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ {val[1]}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ return Reflect.get(obj, key)
|
|
|
|
|
+ },
|
|
|
|
|
+ [clickAc]
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ const dom = document.querySelector(`.MyTable${classKey} .ant-table-body`) as HTMLDivElement
|
|
|
|
|
+
|
|
|
|
|
+ if (dom && yHeight) dom.style.height = yHeight + 'px'
|
|
|
|
|
+ }, [classKey, yHeight])
|
|
|
|
|
+
|
|
|
|
|
+ // 页码变化
|
|
|
|
|
+ const paginationChange = useCallback(
|
|
|
|
|
+ () => (pageNum: number, pageSize: number) => {
|
|
|
|
|
+ if (onChange) {
|
|
|
|
|
+ onChange(pageNum, pageSize)
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ [onChange]
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ const dataChangeFu = useCallback(
|
|
|
|
|
+ (v: any) => {
|
|
|
|
|
+ /**
|
|
|
|
|
+ * index:序号
|
|
|
|
|
+ * txt:正常数据
|
|
|
|
|
+ * img:图片
|
|
|
|
|
+ * txtChange:判断显示不同字段
|
|
|
|
|
+ * text:文字比较多的情况
|
|
|
|
|
+ */
|
|
|
|
|
+ const obj = {
|
|
|
|
|
+ index: (_: any, __: any, index: number) => index + 1 + (pageNum - 1) * pageSize,
|
|
|
|
|
+ txt: (item: any) =>
|
|
|
|
|
+ v[3] && !item[v[2]] ? (
|
|
|
|
|
+ <div dangerouslySetInnerHTML={{ __html: v[3] }}></div>
|
|
|
|
|
+ ) : item[v[2]] && item[v[2]] !== '0' ? (
|
|
|
|
|
+ item[v[2]]
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ isNull
|
|
|
|
|
+ ),
|
|
|
|
|
+ txtArr: (item: any) => (
|
|
|
|
|
+ <div dangerouslySetInnerHTML={{ __html: (item[v[2]] || []).join('<br/>') }}></div>
|
|
|
|
|
+ ),
|
|
|
|
|
+ // 日期去掉00:00:00
|
|
|
|
|
+ dateRes: (item: any) => {
|
|
|
|
|
+ let res = item[v[2]] ? dayjs(item[v[2]]).format('YYYY-MM-DD') : isNull
|
|
|
|
|
+ return res
|
|
|
|
|
+ },
|
|
|
|
|
+ // 多个字段拼接
|
|
|
|
|
+ ping: (item: any) => (item[v[2]] || '') + (resJiLianFu(item[v[3]]) || '') || isNull,
|
|
|
|
|
+ // 这个模块特有的级联控制
|
|
|
|
|
+ txtC: (item: any) =>
|
|
|
|
|
+ v[1] === '年代' && item[v[2]] === '其他' ? '其他' : resJiLianFu(item[v[2]]),
|
|
|
|
|
+ img: (item: any) =>
|
|
|
|
|
+ v[3] && !item[v[2]] ? (
|
|
|
|
|
+ <div dangerouslySetInnerHTML={{ __html: v[3] }}></div>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <div className='tableImgAuto'>
|
|
|
|
|
+ <ImageLazy
|
|
|
|
|
+ width={60}
|
|
|
|
|
+ height={60}
|
|
|
|
|
+ srcBig={item.thumbPc || item.filePath}
|
|
|
|
|
+ src={item[v[2]] || item.thumb}
|
|
|
|
|
+ offline={(item[v[2]] || item.thumb).includes('http')}
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ ),
|
|
|
|
|
+ // 附件大小
|
|
|
|
|
+ fileSize: (item: any) => {
|
|
|
|
|
+ if (item[v[2]]) {
|
|
|
|
|
+ const resTxt = (item[v[2]] / 1024).toFixed(2)
|
|
|
|
|
+ if (resTxt === '0.00') return '0.01'
|
|
|
|
|
+ else return resTxt
|
|
|
|
|
+ } else return isNull
|
|
|
|
|
+ },
|
|
|
|
|
+ txtChange: (item: any) => Reflect.get(v[3], item[v[2]]) || v[4] || isNull,
|
|
|
|
|
+ text: (item: any) => {
|
|
|
|
|
+ let tempCom: any = item[v[2]] || isNull
|
|
|
|
|
+
|
|
|
|
|
+ if (tempCom.length >= v[3]) {
|
|
|
|
|
+ tempCom = tempCom.substring(0, v[3]) + '...'
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (v[4]) {
|
|
|
|
|
+ tempCom = tableComObj(v[4], [tempCom, item[v[2]]], item.id, v[5])
|
|
|
|
|
+ } else if ((item[v[2]] || '').length >= v[3]) {
|
|
|
|
|
+ tempCom = (
|
|
|
|
|
+ <span style={{ cursor: 'pointer' }} title={item[v[2]]}>
|
|
|
|
|
+ {tempCom}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return tempCom
|
|
|
|
|
+ },
|
|
|
|
|
+ input: (item: any) => {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <Form.Item noStyle name={`${item.id}-${v[2]}`}>
|
|
|
|
|
+ <Input
|
|
|
|
|
+ allowClear
|
|
|
|
|
+ readOnly={readOnly}
|
|
|
|
|
+ maxLength={v[3]?.maxLength}
|
|
|
|
|
+ placeholder={v[3]?.placeholder || '请输入'}
|
|
|
|
|
+ />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ )
|
|
|
|
|
+ },
|
|
|
|
|
+ datePicker: (item: any) => {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <Form.Item noStyle name={`${item.id}-${v[2]}`}>
|
|
|
|
|
+ <DatePicker disabled={readOnly} {...(v[3] || {})} />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ )
|
|
|
|
|
+ },
|
|
|
|
|
+ custom: (item: any) => {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <Form.Item noStyle name={`${item.id}-${v[2]}`}>
|
|
|
|
|
+ {v[3].render(readOnly)}
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ )
|
|
|
|
|
+ },
|
|
|
|
|
+ desensitize: (item: any) => {
|
|
|
|
|
+ const txt = item[v[2]]
|
|
|
|
|
+ if (!txt) return isNull
|
|
|
|
|
+ const frontLen = v[3]?.frontLen || 3
|
|
|
|
|
+ const endLen = v[3]?.endLen || 4
|
|
|
|
|
+
|
|
|
|
|
+ return getDesensitizeTxt(txt, frontLen, endLen)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return Reflect.get(obj, v[0])
|
|
|
|
|
+ },
|
|
|
|
|
+ [isNull, pageNum, pageSize, readOnly, tableComObj]
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ const columns = useMemo(() => {
|
|
|
|
|
+ const arr: any = columnsTemp.map((v: any) => ({
|
|
|
|
|
+ title: myTitle && v.includes(myTitle.name) ? myTitle.Com : v[1],
|
|
|
|
|
+ render: dataChangeFu(v),
|
|
|
|
|
+ width: widthSet && Reflect.get(widthSet, v[2]) ? Reflect.get(widthSet, v[2]) : 'auto',
|
|
|
|
|
+ onCell:
|
|
|
|
|
+ merge && v.includes(merge.type)
|
|
|
|
|
+ ? // {rowSpan:3}
|
|
|
|
|
+ (item: any, index: number) => ({
|
|
|
|
|
+ rowSpan: index === 0 ? merge.num : 0
|
|
|
|
|
+ })
|
|
|
|
|
+ : ''
|
|
|
|
|
+ }))
|
|
|
|
|
+
|
|
|
|
|
+ return arr
|
|
|
|
|
+ }, [columnsTemp, dataChangeFu, merge, myTitle, widthSet])
|
|
|
|
|
+
|
|
|
|
|
+ useImperativeHandle(ref, () => ({
|
|
|
|
|
+ form
|
|
|
|
|
+ }))
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <Form form={form} component={false}>
|
|
|
|
|
+ <Table
|
|
|
|
|
+ className={classNames(
|
|
|
|
|
+ `${styles.MyTable} MyTable${classKey}`,
|
|
|
|
|
+ emptyText ? styles.MyTableNull : ''
|
|
|
|
|
+ )}
|
|
|
|
|
+ scroll={{ y: yHeight ? yHeight : '' }}
|
|
|
|
|
+ dataSource={list}
|
|
|
|
|
+ columns={[...startBtn, ...columns, ...lastBtn]}
|
|
|
|
|
+ rowKey={rowKey}
|
|
|
|
|
+ pagination={
|
|
|
|
|
+ pagingInfo
|
|
|
|
|
+ ? {
|
|
|
|
|
+ ...pagingInfo,
|
|
|
|
|
+ current: pageNum,
|
|
|
|
|
+ pageSize: pageSize,
|
|
|
|
|
+ total: total,
|
|
|
|
|
+ onChange: paginationChange()
|
|
|
|
|
+ }
|
|
|
|
|
+ : false
|
|
|
|
|
+ }
|
|
|
|
|
+ {...rest}
|
|
|
|
|
+ />
|
|
|
|
|
+ </Form>
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+const MemoMyTable = React.memo(MyTable)
|
|
|
|
|
+
|
|
|
|
|
+export default MemoMyTable
|