index.tsx 10 KB

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