form.tsx 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. import React, {
  2. forwardRef,
  3. useCallback,
  4. useEffect,
  5. useImperativeHandle,
  6. useMemo,
  7. useState
  8. } from 'react'
  9. import styles from './index.module.scss'
  10. import { DatePicker, Form, FormInstance, Input, Table, TableProps } from 'antd'
  11. import ImageLazy from '../ImageLazy'
  12. import classNames from 'classnames'
  13. import dayjs from 'dayjs'
  14. import { resJiLianFu, resTagFu } from '@/utils/dataChange'
  15. interface MyTableProps extends Omit<TableProps, 'onChange'> {
  16. yHeight?: number //设置表格的高度
  17. list: any //表格数据
  18. columnsTemp: any[][] //表格展示
  19. total?: number //总数
  20. pageNum?: number
  21. pageSize?: number
  22. pagingInfo?: any | boolean
  23. onChange?: (pageNum: number, pageSize: number) => void
  24. lastBtn?: any //后面的操作按钮
  25. startBtn?: any
  26. classKey?: string //一个组件多次使用的时候要传递,分别设置style
  27. // 表格简单的合并
  28. merge?: { type: string; num: number; loc: 'rowSpan' | 'colSpan' }
  29. // 定制化表头
  30. myTitle?: { name: string; Com: React.ReactNode }
  31. // 为空的定制字段
  32. isNull?: string
  33. // 设置宽度
  34. widthSet?: any
  35. rowKey?: string
  36. readOnly?: boolean
  37. // 没有数据的时候展示
  38. emptyText?: boolean
  39. }
  40. export interface MyTableMethods {
  41. form: FormInstance<any>
  42. }
  43. export const getDesensitizeTxt = (txt: string, frontLen = 3, endLen = 4) => {
  44. if (!txt) return txt
  45. const totalVisible = frontLen + endLen
  46. if (txt.length <= totalVisible) {
  47. return txt
  48. }
  49. const frontStr = txt.substring(0, frontLen)
  50. const endStr = endLen > 0 ? txt.substring(txt.length - endLen) : ''
  51. const maskStr = '*'.repeat(txt.length - frontLen - endLen)
  52. return frontStr + maskStr + endStr
  53. }
  54. const MyTable = forwardRef<MyTableMethods, MyTableProps>(
  55. (
  56. {
  57. yHeight,
  58. list,
  59. columnsTemp,
  60. total,
  61. pageNum = 1,
  62. pageSize = 10,
  63. pagingInfo = {
  64. showQuickJumper: true,
  65. position: ['bottomCenter'],
  66. showSizeChanger: true
  67. },
  68. onChange,
  69. lastBtn = [],
  70. startBtn = [],
  71. classKey = '',
  72. merge,
  73. myTitle,
  74. isNull = '(空)',
  75. widthSet,
  76. rowKey = 'id',
  77. readOnly,
  78. emptyText,
  79. ...rest
  80. },
  81. ref
  82. ) => {
  83. // 点击操作高亮
  84. const [clickAc, setClickAc] = useState(0)
  85. const [form] = Form.useForm()
  86. // 表格内容定制化
  87. const tableComObj = useCallback(
  88. (key: string, val: string[], id?: any, backFu?: (id: number) => void) => {
  89. const obj = {
  90. // 超链接打开
  91. A: (
  92. <a href={val[1]} target='_blank' title={val[1]} rel='noreferrer'>
  93. {val[0]}
  94. </a>
  95. ),
  96. // 点击触发事件
  97. S: (
  98. <span
  99. className={classNames('MTclick', clickAc === id ? 'MTclickAc' : '')}
  100. onClick={() => {
  101. if (id && backFu) {
  102. backFu(id)
  103. setClickAc(id)
  104. }
  105. }}
  106. >
  107. {val[1]}
  108. </span>
  109. )
  110. }
  111. return Reflect.get(obj, key)
  112. },
  113. [clickAc]
  114. )
  115. useEffect(() => {
  116. const dom = document.querySelector(`.MyTable${classKey} .ant-table-body`) as HTMLDivElement
  117. if (dom && yHeight) dom.style.height = yHeight + 'px'
  118. }, [classKey, yHeight])
  119. // 页码变化
  120. const paginationChange = useCallback(
  121. () => (pageNum: number, pageSize: number) => {
  122. if (onChange) {
  123. onChange(pageNum, pageSize)
  124. }
  125. },
  126. [onChange]
  127. )
  128. const dataChangeFu = useCallback(
  129. (v: any) => {
  130. /**
  131. * index:序号
  132. * txt:正常数据
  133. * img:图片
  134. * txtChange:判断显示不同字段
  135. * text:文字比较多的情况
  136. */
  137. const obj = {
  138. index: (_: any, __: any, index: number) => index + 1 + (pageNum - 1) * pageSize,
  139. txt: (item: any) =>
  140. v[3] && !item[v[2]] ? (
  141. <div dangerouslySetInnerHTML={{ __html: v[3] }}></div>
  142. ) : item[v[2]] && item[v[2]] !== '0' ? (
  143. item[v[2]]
  144. ) : (
  145. isNull
  146. ),
  147. txtArr: (item: any) => (
  148. <div dangerouslySetInnerHTML={{ __html: (item[v[2]] || []).join('<br/>') }}></div>
  149. ),
  150. // 日期去掉00:00:00
  151. dateRes: (item: any) => {
  152. let res = item[v[2]] ? dayjs(item[v[2]]).format('YYYY-MM-DD') : isNull
  153. return res
  154. },
  155. // 多个字段拼接
  156. ping: (item: any) => (item[v[2]] || '') + (resJiLianFu(item[v[3]]) || '') || isNull,
  157. // 这个模块特有的级联控制
  158. txtC: (item: any) =>
  159. v[1] === '年代' && item[v[2]] === '其他' ? '其他' : resJiLianFu(item[v[2]]),
  160. txtCTag: (item: any) => {
  161. // resJiLianFu(item[v[2]], 'tag'),
  162. let resTxt = item[v[2]] || isNull
  163. if (resTxt) {
  164. return resTagFu(resTxt, v[3] || '藏品') || isNull
  165. }
  166. return resTxt || isNull
  167. },
  168. img: (item: any) =>
  169. v[3] && !item[v[2]] ? (
  170. <div dangerouslySetInnerHTML={{ __html: v[3] }}></div>
  171. ) : (
  172. <div className='tableImgAuto'>
  173. <ImageLazy
  174. width={60}
  175. height={60}
  176. srcBig={item.thumbPc || item.filePath}
  177. src={item[v[2]] || item.thumb}
  178. offline={(item[v[2]] || item.thumb).includes('http')}
  179. />
  180. </div>
  181. ),
  182. // 附件大小
  183. fileSize: (item: any) => {
  184. if (item[v[2]]) {
  185. const resTxt = (item[v[2]] / 1024).toFixed(2)
  186. if (resTxt === '0.00') return '0.01'
  187. else return resTxt
  188. } else return isNull
  189. },
  190. txtChange: (item: any) => Reflect.get(v[3], item[v[2]]) || v[4] || isNull,
  191. text: (item: any) => {
  192. let tempCom: any = item[v[2]] || isNull
  193. if (tempCom.length >= v[3]) {
  194. tempCom = tempCom.substring(0, v[3]) + '...'
  195. }
  196. if (v[4]) {
  197. tempCom = tableComObj(v[4], [tempCom, item[v[2]]], item.id, v[5])
  198. } else if ((item[v[2]] || '').length >= v[3]) {
  199. tempCom = (
  200. <span style={{ cursor: 'pointer' }} title={item[v[2]]}>
  201. {tempCom}
  202. </span>
  203. )
  204. }
  205. return tempCom
  206. },
  207. input: (item: any) => {
  208. return (
  209. <Form.Item noStyle name={`${item.id}-${v[2]}`}>
  210. <Input
  211. allowClear
  212. readOnly={readOnly}
  213. maxLength={v[3]?.maxLength}
  214. placeholder={v[3]?.placeholder || '请输入'}
  215. />
  216. </Form.Item>
  217. )
  218. },
  219. datePicker: (item: any) => {
  220. return (
  221. <Form.Item noStyle name={`${item.id}-${v[2]}`}>
  222. <DatePicker disabled={readOnly} {...(v[3] || {})} />
  223. </Form.Item>
  224. )
  225. },
  226. custom: (item: any) => {
  227. return (
  228. <Form.Item noStyle name={`${item.id}-${v[2]}`} initialValue={item[v[2]]}>
  229. {v[3].render(readOnly, item)}
  230. </Form.Item>
  231. )
  232. },
  233. desensitize: (item: any) => {
  234. const txt = item[v[2]]
  235. if (!txt) return isNull
  236. const frontLen = v[3]?.frontLen || 3
  237. const endLen = v[3]?.endLen || 4
  238. return getDesensitizeTxt(txt, frontLen, endLen)
  239. },
  240. select: (item: any) => {
  241. let txt = isNull
  242. const data = v[3]
  243. const id = item[v[2]]
  244. const obj = data.find((v: any) => v.value === id)
  245. if (obj) txt = obj.label
  246. return txt
  247. },
  248. connectTxt: (item: any) => {
  249. const txt1 = v[2] ? item[v[2]] || isNull : isNull
  250. const txt2 = v[3] ? item[v[3]] || isNull : isNull
  251. console.log(txt1, txt2, item[v[2]], item[v[3]])
  252. return !item[v[2]] && !item[v[3]] ? isNull : `${txt1}-${txt2}`
  253. }
  254. }
  255. return Reflect.get(obj, v[0])
  256. },
  257. [isNull, pageNum, pageSize, readOnly, tableComObj]
  258. )
  259. const columns = useMemo(() => {
  260. const arr: any = columnsTemp.map((v: any) => ({
  261. title: myTitle && v.includes(myTitle.name) ? myTitle.Com : v[1],
  262. render: dataChangeFu(v),
  263. width: widthSet && Reflect.get(widthSet, v[2]) ? Reflect.get(widthSet, v[2]) : 'auto',
  264. onCell:
  265. merge && v.includes(merge.type)
  266. ? // {rowSpan:3}
  267. (item: any, index: number) => ({
  268. rowSpan: index === 0 ? merge.num : 0
  269. })
  270. : ''
  271. }))
  272. return arr
  273. }, [columnsTemp, dataChangeFu, merge, myTitle, widthSet])
  274. useImperativeHandle(ref, () => ({
  275. form
  276. }))
  277. return (
  278. <Form form={form} component={false}>
  279. <Table
  280. className={classNames(
  281. `${styles.MyTable} MyTable${classKey}`,
  282. emptyText ? styles.MyTableNull : ''
  283. )}
  284. scroll={{ y: yHeight ? yHeight : '' }}
  285. dataSource={list}
  286. columns={[...startBtn, ...columns, ...lastBtn]}
  287. rowKey={rowKey ? rowKey : 'id'}
  288. pagination={
  289. pagingInfo
  290. ? {
  291. ...pagingInfo,
  292. current: pageNum,
  293. pageSize: pageSize,
  294. total: total,
  295. onChange: paginationChange()
  296. }
  297. : false
  298. }
  299. {...rest}
  300. />
  301. </Form>
  302. )
  303. }
  304. )
  305. const MemoMyTable = React.memo(MyTable)
  306. export default MemoMyTable