123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- import CustomListModel from '@/components/CustomList'
- import Tables from '@/components/Tables'
- import { FullscreenExitOutlined, FullscreenOutlined, QuestionCircleOutlined, RedoOutlined, SearchOutlined, SettingOutlined } from '@ant-design/icons'
- import { useDebounceFn, useFullscreen, useThrottleFn, useUpdateEffect } from 'ahooks'
- import { Button, Card, Col, Row, Space, Tag, Tooltip, } from 'antd'
- import React, { useEffect, useRef, useState, useCallback } from 'react'
- import style from './index.less'
- import moment from 'moment'
- import lodash from 'lodash';
- import BaseTable from '@/components/BaseTable'
- import { getBaseTableColumn } from '@/components/BaseTable/utils'
- import IsVirtually from './isVirtually'
- interface Prosp {
- isZj?: boolean,//是否查总计
- tableTotal?: { [key: string]: string },//是个开启总计
- scroll?: { x?: number, y?: number },//开启行滑动并设置容器最大宽度
- title?: string,//tabel的标题
- tooltip?: JSX.Element,//是否在标题后加问号展示说明
- dataSource: any[],//table的数据
- expandedRowRender?: (data: any) => JSX.Element,
- className?: string,//自定义class
- isdownload?: boolean,
- leftChild?: JSX.Element,
- config?: any,
- configName?: any,
- page?: number,
- pageSize?: number,
- size?: 'small' | 'middle' | 'large',
- total?: number,
- onChange?: (props: {
- pagination?: { current?: number, pageSize?: number, gzh?: string },
- filters?: any,
- sortData?: {
- column: { dataIndex: string },
- order?: "ascend" | "descend"
- }
- }) => void,
- ajax?: any,//接口刷新
- fixed?: {
- left: number,
- right: number
- },
- totalData?: any[]
- summary?: ((data: readonly any[]) => React.ReactNode)
- rowClassName?: string | ((record: any, index: any) => string)
- sortData?: {
- field?: string,
- order?: "descend" | "ascend"
- }
- estimatedRowHeight?: number | (() => number)
- headerHeight?: number
- isVirtually?: boolean
- }
- export const version = '1.0.0'
- function TableData(props: Prosp) {
- /*************************/
- const { isZj, totalData, scroll, title, dataSource, expandedRowRender, isVirtually = true, sortData, headerHeight, className, rowClassName, leftChild, page = undefined, pageSize = undefined, size = 'small', total = 0, onChange, config, configName, ajax, fixed = { left: 0, right: 1 }, summary, estimatedRowHeight } = props
- const [visible, setVisible] = useState<boolean>(false)
- const [isFullscreen, setIsFullscreen] = useState<boolean>(true)
- const [oldSelectData, setoldSelectData] = useState<any[]>([])
- const [oldFixed, setoldFixed] = useState<any>({ left: '0', right: '0' })
- const [newColumns, setNewColumns] = useState<any[]>([])
- const [originalColumns, setOriginalColumns] = useState<any[]>([])
- const [timer, setTimer] = useState<string>(moment().format('HH:mm:ss'))
- const [selectData, setSelectData] = useState<{ selectData: any[], fixed: { left: number, right: number } }>({ selectData: [], fixed: { left: fixed.left, right: fixed.right } })
- const ref = useRef(null)
- const [isFull, { toggleFull }] = useFullscreen(ref);
- const oldName = useRef(null)
- /*************************/
- useEffect(() => {
- if (originalColumns.length > 0) {
- if (sortData?.field && sortData.order) {
- setNewColumns(originalColumns.map((item: any) => {
- if (item.dataIndex === sortData?.field) {
- item.sortOrder = sortData.order
- } else if (item?.sortOrder) {
- delete item.sortOrder
- }
- return item
- }))
- } else {
- setNewColumns(originalColumns.map((item: any) => {
- const { sortOrder, ...ite } = item
- return ite
- }))
- }
- }
- }, [originalColumns, sortData])
-
- const { run: runSet } = useThrottleFn((newArr, newConfig, fixedData) => {
- console.log('设置配置改变重新赋值')
- setoldSelectData(selectData.selectData)
- setoldFixed(selectData.fixed)
- if (newArr.length > 0) {
- console.log('改变---->')
- let c: any[] = []
- newArr.forEach((newItem: any, index: number) => {
- let oldItem = newConfig.find((c: { dataIndex: any }) => c.dataIndex === newItem.dataIndex)
- if (oldItem) {
- // if (newItem?.width !== oldItem?.width) {
- oldItem.width = newItem?.width
- // }
- if (index < Number(fixedData.left)) {//设置左悬浮
- oldItem['fixed'] = 'left'
- } else if (index > (newArr?.length - Number(fixedData.right) - 1)) {//设置右悬浮
- oldItem['fixed'] = 'right'
- if (oldItem?.children?.length > 0) {
- oldItem['children'] = oldItem?.children.map((item: { [x: string]: string }) => {
- item['fixed'] = 'right'
- return item
- })
- }
- } else {
- oldItem['fixed'] = false
- if (oldItem?.children?.length > 0) {
- oldItem['children'] = oldItem?.children.map((item: { [x: string]: any }) => {
- item['fixed'] = false
- return item
- })
- }
- }
- let { label, default: a, tips, title, ...ite } = oldItem
- if (tips) {
- ite.title = <Space size={2}>
- {title}
- <Tooltip title={tips} placement='bottom'>
- <QuestionCircleOutlined />
- </Tooltip>
- </Space>
- } else {
- ite.title = title
- }
- c.push(ite)
- }
- })
- setOriginalColumns(c)
- }
- }, { wait: 500 });
- /**重组选中的字段 */
- useEffect(() => {
- let oldConfigName = oldName.current || ''
- let oldSelectDataString = JSON.stringify(oldSelectData)
- if (configName !== oldConfigName && oldSelectData.length > 0) {
- oldSelectDataString = ''
- }
- if (configName) {
- const defSelectData = localStorage.getItem(`myAdMonitorConfig${version}_` + configName)
- const defFixed = localStorage.getItem(`myAdMonitorConfigFixed${version}_` + configName)
- let newArr: any = [], fixedData: { left: number, right: number } = selectData.fixed
- const newConfig = config?.map((item: { data: any }) => item.data)?.flat()
- if (defSelectData) {
- newArr = JSON.parse(defSelectData)
- }
- if (defSelectData && (selectData?.selectData?.length === 0 || configName !== oldConfigName)) {//首次查找个人配置是否存在,并且selectData为空,存在用个人配置设置selectData
- console.log('首次使用个人配置赋值')
- let newDefSelectData = JSON.parse(defSelectData)
- newDefSelectData = newDefSelectData.filter((item: any) => !!item && newConfig.some((c: { dataIndex: any }) => c.dataIndex === item.dataIndex))//去除空项
- setSelectData(() => ({ selectData: newDefSelectData, fixed: defFixed ? JSON.parse(defFixed) : { left: 0, right: 0 } }))
- fixedData = defFixed ? JSON.parse(defFixed) : { left: 0, right: 0 }
- newArr = newDefSelectData
- }
- if (!defSelectData && (selectData?.selectData?.length === 0 || configName !== oldConfigName)) {//首次查找个人配置是否存在,并且selectData为空,不存在默认配置设置selectData
- let newSelectData: any[] = []
- config?.forEach((item: { data: { default: any }[] }) => {
- item?.data?.forEach((d: { default: any }) => {
- if (d.default) {
- newSelectData[d.default - 1] = d
- }
- })
- })
- console.log('首次使用默认配置赋值')
- setSelectData(() => ({ ...selectData, selectData: newSelectData }))
- newArr = newSelectData
- }
- if ((JSON.stringify(oldSelectDataString) !== JSON.stringify(selectData?.selectData)) || (JSON.stringify(selectData.fixed) !== JSON.stringify(oldFixed))) {
- runSet(newArr, newConfig, fixedData)
- }
- }
- if (configName !== oldConfigName) {
- oldName.current = configName
- }
- }, [selectData, oldSelectData, dataSource, oldFixed, configName, config, timer])
- const { run: runResize } = useDebounceFn((columns, type: string) => {
- if (configName) {
- let newSelectData = selectData?.selectData?.map((item, index) => {
- if (type === 'vir') {
- if (item.dataIndex === columns.key) {
- item['width'] = Math.ceil(columns['width'])
- }
- } else {
- item['width'] = columns[index]['width']
- }
- return item
- })
- localStorage.setItem(`myAdMonitorConfig${version}_` + configName, JSON.stringify(newSelectData))
- }
- }, { wait: 100 });
- //拖动宽度设置设置保存
- const handelResize = useCallback((columns: any, type: string) => {
- runResize(columns, type)
- }, [configName, selectData])
- const header = <Col span={24}>
- <Row gutter={[0, 10]} align='bottom'>
- <Col flex='1 1 150px'>
- {isFullscreen && leftChild}
- </Col>
- <Col flex='0 1 150px'>
- {/*紧凑*/}
- <Space style={{ float: 'right', marginBottom: 4 }}>
- <Button size='small' type='text' style={{ color: '#F56C6C' }} onClick={() => { setIsFullscreen(!isFullscreen) }}>
- <Tooltip title={isFullscreen ? '隐藏搜索' : '显示搜索'}><SearchOutlined /></Tooltip>
- </Button>
- {ajax && <Button
- size='small'
- type='text'
- style={{ color: '#67C23A' }}
- onClick={() => {
- ajax.refresh()
- }}>
- {/* <span style={{ fontSize: 10, color: '#999' }}>刷新时间:{ajax?.data?.reqTime}</span> */}
- <Tooltip title='刷新'><RedoOutlined /></Tooltip>
- </Button>}
- <Button
- size='small'
- type='text'
- style={{ color: '#E6A23C' }}
- onClick={() => {
- setVisible(true)
- }}>
- <Tooltip title='设置'><SettingOutlined /></Tooltip>
- </Button>
- <Button
- type='text'
- size='small'
- style={{ color: '#409EFF' }}
- onClick={toggleFull}>
- {<Tooltip title={!isFull ? '全屏' : '退出全屏'}>{!isFull ? <FullscreenOutlined /> : <FullscreenExitOutlined />}</Tooltip>}
- </Button>
- {visible && <CustomListModel
- sysFixed={fixed}
- version={version}
- config={config}
- configName={configName}
- visible={visible}
- onClose={() => { setVisible(false) }}
- onChange={(arr: any) => {
- setTimer(moment().format('HH:mm:ss'));
- if (arr) {
- setSelectData({ selectData: [], fixed: { left: fixed.left, right: fixed.right } })
- } else {
- setSelectData({ selectData: [], fixed: { left: fixed.left, right: fixed.right } })
- }
- }}
- columns={newColumns}
- />}
- </Space>
- </Col>
- </Row>
- </Col>
- const content = <Row gutter={[0, 20]} ref={ref} style={isFull ? { background: '#fff' } : {}}>
- {/**table */}
- <Col span={24}>
- <Card
- style={{ borderRadius: 8 }}
- // title={<div style={{ textAlign: 'center', fontWeight: 'bold' }}>{title}</div>}
- headStyle={{ textAlign: 'left' }}
- bodyStyle={{ padding: '5px 10px' }}
- >
- <div style={{ textAlign: 'center', fontWeight: 'bold', padding: '4px 6px 6px', fontSize: 16, marginBottom: 4, position: 'relative' }}>
- {title}
- {isVirtually && <IsVirtually title={title} />}
- </div>
- <Row gutter={[0, 16]}>
- {header}
- <Tab {...{ size, newColumns, handelResize, className, isZj, totalData, rowClassName, scroll, isFull, page, pageSize, dataSource, onChange, expandedRowRender, total, ajax, summary }} />
- </Row>
- </Card>
- </Col>
- </Row>
- const content1 = <Row gutter={[0, 20]} ref={ref} style={isFull ? { background: '#fff' } : {}}>
- {/**table */}
- <Col span={24}>
- <Card
- style={{ borderRadius: 8 }}
- headStyle={{ textAlign: 'left' }}
- bodyStyle={{ padding: '5px 10px' }}
- >
- <div style={{ textAlign: 'center', fontWeight: 'bold', padding: '4px 6px 6px', fontSize: 16, marginBottom: 4, position: 'relative' }}>
- {title}
- {isVirtually && <IsVirtually title={title} />}
- </div>
- <Row gutter={[0, 16]}>
- {header}
- <Tab1 {...{ size, newColumns, className, handelResize, headerHeight, page, pageSize, totalData, dataSource, onChange, total, ajax, estimatedRowHeight }} />
- </Row>
- </Card>
- </Col>
- </Row >
- const tableNames = localStorage.getItem('TABLENAMES')
- if (tableNames && title && tableNames.split(',').includes(title)) {
- return <>
- {content1}
- </>
- } else {
- return <>
- {content}
- </>
- }
- }
- /**表格 */
- const Tab = React.memo((props: any) => {
- const { size, newColumns, className, handelResize, scroll, isFull, page, isZj, rowClassName, pageSize, totalData, dataSource, onChange, expandedRowRender, total, ajax, summary } = props
- let ran = Math.ceil(Math.random() * 100)
- useEffect(() => {
- const contentBodyScroll = (e: any) => {
- let el = document.querySelector(`.header_table_body_${ran} .ant-table-body`);
- if (el) {
- el.scrollLeft = e.target.scrollLeft
- }
- }
- const headerBodyScroll = (e: any) => {
- let el = document.querySelector(`.content_table_body_${ran} .ant-table-body`);
- if (el) {
- el.scrollLeft = e.target.scrollLeft
- }
- }
- if (isZj) {
- document.querySelector(`.content_table_body_${ran} .ant-table-body`)?.addEventListener('scroll', contentBodyScroll);
- document.querySelector(`.header_table_body_${ran} .ant-table-body`)?.addEventListener('scroll', headerBodyScroll);
- }
- () => {
- if (isZj) {
- document.querySelector(`.content_table_body_${ran} .ant-table-body`)?.removeEventListener('scroll', contentBodyScroll);
- document.querySelector(`.header_table_body_${ran} .ant-table-body`)?.removeEventListener('scroll', headerBodyScroll);
- }
- }
- }, [isZj, ran])
- return < Col span={24} >
- <div className={`${style[size]} ${className ? style[className] : ''} `}>
- {
- isZj && <Tables
- bordered
- columns={newColumns}
- dataSource={totalData?.length > 0 ? [...totalData] : [{ id: 1 }]}
- scroll={scroll ? isFull ? { ...scroll, y: document.body.clientHeight - 300 } : scroll : {}}
- size={size}
- pagination={false}
- hideOnSinglePage
- current={page}
- pageSize={pageSize}
- loading={ajax?.loading}
- className={`all_table header_table_body header_table_body_${ran} ${className ? className : ''}`}
- sortDirections={['ascend', 'descend', null]}
- handelResize={((columns: any) => handelResize(columns, 'antd'))}
- onChange={(pagination: any, filters: any, sorter: any) => onChange && onChange({ pagination, filters, sortData: sorter })}
- />
- }
- <Tables
- showHeader={!isZj}
- className={`all_table content_table_body content_table_body_${ran} ${className ? className : ''}`}
- bordered
- sortDirections={['ascend', 'descend', null]}
- current={page}
- pageSize={pageSize}
- columns={newColumns}
- dataSource={dataSource}
- scroll={scroll ? isFull ? { ...scroll, y: document.body.clientHeight - 300 } : scroll : {}}
- onChange={(pagination: any, filters: any, sorter: any) => onChange && onChange({ pagination, filters, sortData: sorter })}
- rowClassName={rowClassName}
- expandedRowRender={expandedRowRender ? expandedRowRender : undefined}
- size={size}
- total={total}
- loading={ajax?.loading}
- defaultPageSize={20}
- handelResize={((columns: any) => handelResize(columns, 'antd'))}
- summary={summary}
- />
- </div>
- </Col >
- })
- const Tab1 = React.memo((props: any) => {
- const { size, newColumns, className, handelResize, page, pageSize, headerHeight = 65, totalData, dataSource, onChange, total, ajax, estimatedRowHeight } = props
- let ww = document.body.clientWidth < 415
- return < Col span={24} >
- <div className={`${style[size]} ${className ? style[className] : ''} `}>
- <BaseTable
- columns={getBaseTableColumn(newColumns)}
- data={dataSource}
- loading={ajax?.loading}
- onColumnResizeEnd={({ column }: any) => handelResize(column, 'vir')}
- onChange={(data) => onChange?.(data)}
- estimatedRowHeight={estimatedRowHeight}
- frozenData={totalData}
- headerHeight={headerHeight}
- pagination={
- {
- size: 'small',
- total: total || 0,//总共多少条数据,服务器给,设置后分页自动计算页数
- current: page,//当前页数,需state控制配合翻页
- pageSize: pageSize,
- defaultCurrent: 1,//默认初始的当前页数
- defaultPageSize: 20,//默认初始的每页条数
- pageSizeOptions: ['10', '20', '30', '40', '50', '60', '70', '80', '90', '100'],
- showTotal: (total) => <Tag color="cyan">总共{total}数据</Tag>,
- showSizeChanger: true, //手动开启条数筛选器,默认超过50条开启
- simple: ww ? true : false,//开启简单分页
- hideOnSinglePage: false,//只有一页数据隐藏分页
- showLessItems: true
- }
- }
- />
- </div>
- </Col >
- })
- export default React.memo(TableData, (prevProps, nextProps) => {
- return lodash.isEqual(nextProps, prevProps); // 假设 deepEqual 是一个深层比较函数
- })
|