123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- import { CloseOutlined, ColumnWidthOutlined, SearchOutlined } from "@ant-design/icons"
- import { Button, Checkbox, Input, InputNumber, message, Modal, Popover, Space, Spin, Tooltip } from "antd"
- import React, { useCallback, useEffect, useState } from "react"
- import './index.less'
- import { ReactComponent as DrawStem } from '@/assets/drawStem.svg'
- import { SortableContainer, SortableElement, SortableHandle } from "react-sortable-hoc";
- import arrayMove from "array-move";
- const DragHandle = SortableHandle(() => <DrawStem className='draw' />);
- const SortableItem = SortableElement(({ item, del, setConfig }: any) => {
- const [visible, setVisible] = useState<boolean>(false)
- const [width, setWidth] = useState<number>(item?.width || 0)
- return <li className='liDraw'>
- <div className='lileft'>
- <DragHandle />
- <div>{item?.title}</div>
- </div>
- <Space style={{ float: 'right', marginRight: 10 }}>
- <Popover
- content={
- <div>
- <InputNumber min={0} max={500} onChange={(value: number) => {
- if (value) {
- setWidth(value)
- }
- }} value={width} size='small' />
- <Button type='primary' size='small' onClick={() => {
- setConfig({ ...item, width })
- setVisible(false)
- }}>OK</Button>
- </div>
- }
- trigger="click"
- visible={visible}
- placement='left'
- onVisibleChange={(visible) => { setVisible(visible) }}
- >
- <Tooltip title='宽度设置'><a><ColumnWidthOutlined /></a></Tooltip>
- </Popover>
- </Space>
- {item?.label !== 'pos_type' && <Tooltip title='删除'><div className="clear" onClick={() => { del() }}><a><CloseOutlined /></a></div></Tooltip>}
- </li>
- });
- /** 外层 */
- const SortableList = SortableContainer(({ children }: { children: any }) => (<ul className='selectedList'>{children}</ul>));
- interface dataProps {
- title: string,
- label: string,
- dataIndex: string,
- disabled: boolean
- }
- interface DataProps {
- label: string,
- data: dataProps[],
- fieldSHow?: {
- label: string,
- saveField: string,
- defaultValue: any[],
- data: any[]
- }
- }
- /**
- * 自定义列
- */
- type customProps = {
- visible?: boolean,
- onChange?: (data: any) => void,
- onClose?: () => void,
- config: any[],//配置表
- configName: string,//配置表名称
- columns: any[],//配置菜单
- version: string, // 版本号
- sysFixed?: {
- left: number,
- right: number
- }
- }
- function CustomListModel(props: customProps) {
- const { visible, onChange, onClose, config, configName, columns, version, sysFixed = { left: 0, right: 1 } } = props
- // dataA 总数据
- // 数据开始
- const [dataA, setDataA] = useState<DataProps[]>(config)//备份原始数据
- const [data, setData] = useState<DataProps[]>(config)//变动的数据
- const [search, setSearch] = useState<string>('') // 搜索字段
- const [selectData, setSelectData] = useState<dataProps[]>([])//选择的数据
- const [serverData, setServerData] = useState<dataProps[]>([])//备份的数据
- const [fieldData, setFieldData] = useState<any>({})
- const [fixed, setFixed] = useState<{ left: number, right: number }>(localStorage.getItem(`myAdMonitorConfigFixed${version}_` + configName) ? JSON.parse(localStorage.getItem(`myAdMonitorConfigFixed${version}_` + configName) as any) : { left: sysFixed.left, right: sysFixed.right })
- // 数据结束
- // 处理表格里列字段展示
- useEffect(() => {
- let mySelectFieldData = localStorage.getItem(`myAdFieldConfig${version}_` + configName)
- let newSelectFieldData: any = {}
- if (mySelectFieldData) {
- newSelectFieldData = JSON.parse(mySelectFieldData)
- }
- data?.forEach((item) => {
- if (item?.fieldSHow) {
- const { saveField, defaultValue } = item?.fieldSHow
- if (!newSelectFieldData[saveField]) {
- newSelectFieldData[saveField] = defaultValue
- }
- }
- })
- if (Object.keys(newSelectFieldData).length > 0) {
- setFieldData({ ...newSelectFieldData })
- }
- }, [data])
- // 获取数据
- useEffect(() => {
- getUserList()
- }, [configName])
- // 获取个人配置
- const getUserList = () => {
- let mySelectData = localStorage.getItem(`myAdMonitorConfig${version}_` + configName)
- if (mySelectData) {//获取自定义配置
- let newMySelectData = JSON.parse(mySelectData)
- newMySelectData = newMySelectData.filter((item: any) => item && columns.some(c => c.dataIndex === item.dataIndex))//去除空项,并去除多余不存在的
- setSelectData(newMySelectData)
- setServerData(newMySelectData)
- setListWidth(newMySelectData)
- localStorage.setItem(`myAdMonitorConfig${version}_` + configName, JSON.stringify(newMySelectData))//重新存下本地,避免更新后数据不对
- } else {//使用默认配置
- let newSelectData: any[] = []
- config?.forEach((item) => {
- item?.data?.forEach((d: { default: any }) => {
- if (d.default) {
- newSelectData[d.default - 1] = d
- }
- })
- })
- setSelectData(newSelectData)
- setServerData(newSelectData)
- setListWidth(newSelectData)
- }
- }
- // 首次赋值默认宽
- const setListWidth = useCallback((selectData) => {
- if (selectData?.length === columns?.length && !selectData?.every((item: any) => item.width)) {
- let newSelectData: any[] = []
- newSelectData = selectData?.map((item: { [x: string]: any }, index: string | number) => {
- item['width'] = columns[index]['width']
- return item
- })
- setSelectData(newSelectData)
- setServerData(newSelectData)
- }
- }, [columns])
- //首次赋值默认宽
- // useEffect(() => {
- // console.log('首次赋值默认宽====>',selectData,columns)
- // if (selectData?.length === columns?.length && !selectData?.every((item: any) => item.width)) {
- // let newSelectData: any[] = []
- // newSelectData = selectData?.map((item, index) => {
- // item['width'] = columns[index]['width']
- // return item
- // })
- // setSelectData(newSelectData)
- // setServerData(newSelectData)
- // }
- // }, [selectData,columns])
- // 搜索 过滤
- const searchHandle = useCallback((value: string) => {
- setSearch(value)
- if (search) {
- let newData1: any[] = []
- dataA.forEach((item: DataProps) => {
- let newData = item.data.filter((listItem: dataProps) => {
- if (listItem?.title?.includes(value)) {
- return listItem
- } else {
- return null
- }
- })
- if (newData?.length > 0) {
- newData1.push({ ...item, data: newData })
- }
- })
- setData([...newData1])
- } else {
- setData(dataA)
- }
- }, [data, dataA, search])
- // 选中数据
- const selectHandle = useCallback((checked: boolean, data: dataProps) => {
- if (checked) {
- setSelectData([...selectData, { ...data }])
- } else {
- let newSelectData = selectData.filter((item: dataProps) => {
- if (item.dataIndex === data.dataIndex) {
- return null
- } else {
- return item
- }
- })
- setSelectData(newSelectData)
- }
- }, [selectData])
- // 每个大项 全选
- const checkAllHandle = useCallback((checked: boolean, value: string) => {
- let oldData = data.find((item: DataProps) => item.label === value)
- console.log(oldData)
- if (oldData) {
- if (checked) {
- let newSelectData: any[] = selectData?.filter(item => item)
- oldData.data.forEach((item: dataProps) => {
- if (!item.disabled && selectData.findIndex((selsectItem: dataProps) => selsectItem?.dataIndex === item?.dataIndex) === -1) {
- newSelectData.push(item)
- }
- })
- setSelectData([...newSelectData])
- } else {
- let newSelectData = selectData.filter((item: dataProps) => {
- if (oldData?.data?.some((dataItem: dataProps) => dataItem.dataIndex === 'pos_type' ? false : dataItem?.dataIndex === item.dataIndex)) {
- return null
- } else {
- return item
- }
- })
- setSelectData(newSelectData)
- }
- }
- }, [selectData, data])
- const onSortEnd = ({ oldIndex, newIndex }: { oldIndex: number, newIndex: number }) => {
- setSelectData(arrayMove(selectData, oldIndex, newIndex))
- }
- // 提交
- const onSubmit = useCallback(() => {
- if (selectData.length > 0) {
- localStorage.setItem(`myAdMonitorConfig${version}_` + configName, JSON.stringify(selectData))
- localStorage.setItem(`myAdMonitorConfigFixed${version}_` + configName, JSON.stringify(fixed))
- localStorage.setItem(`myAdFieldConfig${version}_` + configName, JSON.stringify(fieldData))
- message.success('保存成功')
- onChange && onChange({ selectData, fixed })
- onClose && onClose()
- } else {
- message.error('请选择最少一项!!!')
- }
- }, [serverData, selectData, fixed, fieldData])
- // 恢复默认
- const defaultConfig = useCallback(() => {
- localStorage.removeItem(`myAdMonitorConfig${version}_` + configName)
- localStorage.removeItem(`myAdMonitorConfigFixed${version}_` + configName)
- setFixed({ ...sysFixed })
- getUserList()
- message.success('恢复默认成功')
- onChange && onChange('')
- onClose && onClose()
- }, [])
- // 设置悬浮
- const changeFixed = useCallback((name: string, value: number) => {
- let v = Number(value)
- if (!isNaN(v)) {
- setFixed({ ...fixed, [name]: value })
- }
- }, [fixed])
- //取消操作
- const cancel = () => {
- setSelectData(serverData)
- onClose && onClose()
- }
- // 设置配置参数
- const setConfig = useCallback((data) => {
- let newServerData = selectData?.map((item) => {
- if (item.dataIndex === data.dataIndex) {
- item = data
- }
- return item
- })
- setSelectData(newServerData)
- }, [selectData])
- // 处理显示字段
- const fieldHandle = (saveField: string, data: any, checked: boolean) => {
- let newFieldData = JSON.parse(JSON.stringify(fieldData))
- if (checked) {
- if (Object.keys(newFieldData).includes(saveField)) {
- newFieldData[saveField] = [...newFieldData[saveField], data]
- } else {
- newFieldData[saveField] = [data]
- }
- } else {
- newFieldData[saveField] = newFieldData[saveField].filter((item: any) => item.key !== data.key && item.type === data.type)
- }
- setFieldData(newFieldData)
- }
- return <Modal
- title={null}
- footer={null}
- visible={visible}
- width={1100}
- className='customListModel'
- onCancel={cancel}
- >
- <div className='content'>
- <div className='left'>
- <div className='leftSearch'>
- <Input size="small" placeholder="输入关键词,搜索数据指标" onChange={(e) => { searchHandle(e.target.value) }} value={search} prefix={<SearchOutlined style={{ color: '#a3a3a3', fontSize: 18 }} />} allowClear bordered={false} />
- </div>
- <div className="dataList">
- <Spin spinning={false}>
- {data?.map((item: DataProps, index: number) => {
- return <dl key={index}>
- {item?.fieldSHow && <div style={{ backgroundColor: '#f7f7f7' }}>
- <dt style={{ color: '#ff7875' }}>{item.fieldSHow.label}</dt>
- <div style={{ padding: '0 20px', boxSizing: 'border-box' }}>
- {item?.fieldSHow?.data?.map((item1: any, index) => {
- return <dl key={'field' + index}>
- <dt>{item1.label}</dt>
- {item1.data.map((item2: any, index: number) => <dd key={'item2' + index}><Checkbox className='checkbox' onChange={(e) => fieldHandle((item.fieldSHow as any).saveField, item2, e.target.checked)} checked={fieldData[(item.fieldSHow as any).saveField]?.some((field: any) => field.key === item2.key && field.type === item2.type)} disabled={fieldData[(item.fieldSHow as any).saveField]?.length > 0 ? fieldData[(item.fieldSHow as any).saveField][0].type === item1.label ? false : true : false}>{item2?.label}</Checkbox></dd>)}
- </dl>
- })}
- </div>
- </div>}
- <dt>
- <Checkbox onChange={(e) => { checkAllHandle(e.target.checked, item.label) }} className='checkbox'>{item.label}</Checkbox>
- </dt>
- {item.data?.map((listItem: dataProps, listIndex: number) => {
- return <dd key={item.label + listIndex}>
- <Checkbox onChange={(e) => { selectHandle(e.target.checked, listItem) }} disabled={listItem.label === 'pos_type' || listItem?.disabled} checked={selectData.some((selectItem: { dataIndex: string }) => selectItem?.dataIndex === listItem?.dataIndex)} className='checkbox'>{listItem?.title}</Checkbox>
- </dd>
- })}
- </dl>
- })}
- </Spin>
- </div>
- </div>
- <div className='right'>
- <div className='rightTitle'>
- <div className="rightTitleLeft">已选<span>{selectData?.filter(item => item)?.length}</span>项</div>
- <a onClick={defaultConfig} style={{ marginRight: 30 }}>恢复默认</a>
- </div>
- <div style={{ display: 'flex', flexFlow: 'row nowarp', padding: '0 28px', justifyContent: 'space-between' }}>
- <div>左侧固定列数:<InputNumber size='small' style={{ width: 50 }} onChange={(value: number) => { changeFixed('left', value) }} value={fixed.left} max={100} min={0} /></div>
- <div>右侧固定列数:<InputNumber size='small' style={{ width: 50 }} onChange={(value: number) => { changeFixed('right', value) }} value={fixed.right} max={100} min={0} /></div>
- </div>
- <SortableList axis='y' onSortEnd={onSortEnd} useDragHandle>
- {selectData.map((item: dataProps, index: number) => <SortableItem key={'li' + index} index={index} item={item} del={() => { selectHandle(false, item) }} setConfig={setConfig} />)}
- </SortableList>
- <div className='rightOperate'>
- <div style={{ margin: '0 auto' }}>
- <Button onClick={cancel}>取消</Button>
- <Button type='primary' className='confirm' loading={false} onClick={() => { onSubmit() }} disabled={selectData?.length === 0}>确认</Button>
- </div>
- </div>
- </div>
- </div>
- </Modal>
- }
- export default CustomListModel
|