|
@@ -0,0 +1,402 @@
|
|
|
+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 } 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'
|
|
|
+
|
|
|
+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"
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export const version = '1.0.0'
|
|
|
+
|
|
|
+function TableData(props: Prosp) {
|
|
|
+
|
|
|
+ /*************************/
|
|
|
+ const { isZj, totalData, scroll, title, dataSource, expandedRowRender, sortData, className, rowClassName, leftChild, page = undefined, pageSize = undefined, size = 'small', total = 0, onChange, config, configName, ajax, fixed = { left: 0, right: 1 }, summary } = 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)
|
|
|
+ // setNewColumns(c)
|
|
|
+ // setNewColumns(newArr.map((newItem: any, index: number) => {
|
|
|
+ // let oldItem = newConfig.find((c: { dataIndex: any }) => c.dataIndex === newItem.dataIndex)
|
|
|
+ // 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'
|
|
|
+ // } else {
|
|
|
+ // oldItem['fixed'] = false
|
|
|
+ // }
|
|
|
+ // let { label, default: a, ...ite } = oldItem
|
|
|
+ // return ite
|
|
|
+ // }))
|
|
|
+ }
|
|
|
+ }, { 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) => {
|
|
|
+ if (configName) {
|
|
|
+ let newSelectData = selectData?.selectData?.map((item) => {
|
|
|
+ if (item.dataIndex === columns.key) {
|
|
|
+ item['width'] = columns['width'].toFixed(2)
|
|
|
+ }
|
|
|
+ return item
|
|
|
+ })
|
|
|
+ localStorage.setItem(`myAdMonitorConfig${version}_` + configName, JSON.stringify(newSelectData))
|
|
|
+ }
|
|
|
+ }, { wait: 100 });
|
|
|
+
|
|
|
+ //拖动宽度设置设置保存
|
|
|
+ const handelResize = useCallback((columns: any) => {
|
|
|
+ runResize(columns)
|
|
|
+ }, [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 }}>{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 >
|
|
|
+ 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);
|
|
|
+ // document.querySelectorAll('.content_table_body .ant-table-body')
|
|
|
+ }
|
|
|
+ () => {
|
|
|
+ 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])
|
|
|
+ let ww = document.body.clientWidth < 415
|
|
|
+
|
|
|
+ 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))}
|
|
|
+ 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))}
|
|
|
+ summary={summary}
|
|
|
+ /> */}
|
|
|
+ <BaseTable
|
|
|
+ columns={getBaseTableColumn(newColumns)}
|
|
|
+ data={dataSource}
|
|
|
+ loading={ajax?.loading}
|
|
|
+ onColumnResizeEnd={({ column }: any) => handelResize(column)}
|
|
|
+ onChange={(data) => onChange?.(data)}
|
|
|
+ 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条开启
|
|
|
+ // onChange: pageChange, //点击页码或条数筛选时触发获取当前页数和每页条数
|
|
|
+ // onShowSizeChange: sizeChange,//点击条数筛选器触发
|
|
|
+ simple: ww ? true : false,//开启简单分页
|
|
|
+ hideOnSinglePage: false,//只有一页数据隐藏分页
|
|
|
+ showLessItems: true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ />
|
|
|
+
|
|
|
+ </div>
|
|
|
+ </Col >
|
|
|
+})
|
|
|
+
|
|
|
+export default React.memo(TableData, (prevProps, nextProps) => {
|
|
|
+ return lodash.isEqual(nextProps, prevProps); // 假设 deepEqual 是一个深层比较函数
|
|
|
+})
|