import React, { useContext, useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { Button, Input, Radio, Modal, Checkbox, Row, Col, Tree, ConfigProvider } from 'antd'; import Empty from '@wisdom-components/empty'; import { ExclamationCircleFilled, SearchOutlined, CloseOutlined } from '@ant-design/icons'; import './index.less'; const { TreeNode } = Tree; const QuotaSelect = ({ buttonProps, width, title, cancelText, okText, onModalOk, onModalCancel, onModalClose, searchPrefix, placeholder, maximum, dataSource, selectData, onCheckboxChange, onCancelSelect, treeProps, onTreeDrop, }) => { const { getPrefixCls } = useContext(ConfigProvider.ConfigContext); const prefixCls = getPrefixCls('quota-select'); const [visible, setVisible] = useState(false); const [targetValue, setTargetValue] = useState('emphasis'); const [allQuotaList, setAllQuotaList] = useState([]); const [quotaList, setQuotaList] = useState([]); useEffect(() => { if (dataSource.length > 0) { let data = dataSource.map((item) => ({ ...item, checked: false, title: item.name, key: item.name, })); setAllQuotaList(data); } }, [dataSource]); useEffect(() => { if (targetValue === 'emphasis') { filterEmphasisQuota(); } }, [allQuotaList]); useEffect(() => { let data = [...allQuotaList]; data.forEach((item) => { item.checked = false; if (selectData.length > 0) { selectData.forEach((child) => { if (child.key === item.key) { item.checked = true; } }); } }); setAllQuotaList(data); }, [selectData]); // 过滤重点指标 const filterEmphasisQuota = () => { let newQuotaList = [...allQuotaList]; newQuotaList = newQuotaList.filter((item) => item.isShow === '1'); setQuotaList(newQuotaList); }; // 展示模态框 const showModal = () => { setVisible(true); }; // 关闭模态框 const handleCancel = (e) => { if (e.target.innerHTML === cancelText) { onModalCancel && onModalCancel(); } else { onModalClose && onModalClose(); setVisible(false); } }; const onOk = () => { onModalOk && onModalOk(); setVisible(false); }; // 切换重点与全部 const onRadioChange = (e) => { if (e.target.value === 'all') { setQuotaList(allQuotaList); } else { filterEmphasisQuota(); } setTargetValue(e.target.value); }; // 搜索指标 const onSearch = (e) => { if (e.type === 'keydown' || e.target.value === '') { if (e.target.value !== '') { let newQuotaList = []; quotaList.forEach((item) => { if (item.name.indexOf(e.target.value) > -1) newQuotaList.push(item); }); setQuotaList(newQuotaList); } else { if (targetValue === 'all') { setQuotaList(allQuotaList); } else { filterEmphasisQuota(); } } } }; // 处理复选框点击事件 const handleCheckboxChange = (e) => { let newQuotaList = [...allQuotaList]; let curSelectKey = []; let curSelectList = [...selectData]; let data = curSelectList.filter((item) => item.title === e.target.value); if (data.length) { curSelectList = curSelectList.filter((item) => item.title !== e.target.value); } else { curSelectList.push({ key: e.target.value, title: e.target.value }); } newQuotaList.forEach((item) => { if (item.title === e.target.value) { item.checked = !item.checked; } }); curSelectKey = curSelectList.map((item) => item.key); onCheckboxChange({ selectKey: curSelectKey, selectList: curSelectList, }); setAllQuotaList(newQuotaList); }; // 处理取消选择按钮点击事件 const handleCancelSelect = ({ title }) => { let data = [...selectData]; data = data.filter((item) => item.title !== title); onCancelSelect({ selectKey: data.map((item) => item.key), selectList: data, }); }; // 拖动选中树节点 const handleDrop = (info) => { const dropKey = info.node.key; const dragKey = info.dragNode.key; const dropPos = info.node.pos.split('-'); const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]); const loop = (data, key, callback) => { for (let i = 0; i < data.length; i++) { if (data[i].key === key) { return callback(data[i], i, data); } if (data[i].children) { loop(data[i].children, key, callback); } } }; const data = [...selectData]; let dragObj; loop(data, dragKey, (item, index, arr) => { arr.splice(index, 1); dragObj = item; }); if (!info.dropToGap) { loop(data, dropKey, (item) => { item.children = item.children || []; item.children.unshift(dragObj); }); } else if ( (info.node.props.children || []).length > 0 && // Has children info.node.props.expanded && // Is expanded dropPosition === 1 // On the bottom gap ) { loop(data, dropKey, (item) => { item.children = item.children || []; item.children.unshift(dragObj); }); } else { let ar; let i; loop(data, dropKey, (item, index, arr) => { ar = arr; i = index; }); if (dropPosition === -1) { ar.splice(i, 0, dragObj); } else { ar.splice(i + 1, 0, dragObj); } } onTreeDrop({ selectKey: data.map((item) => item.key), selectList: data, }); }; return ( <div className={classNames(prefixCls)}> <Button {...buttonProps} onClick={showModal} /> {visible && ( <Modal centered width={width} title={title} cancelText={cancelText} okText={okText} visible={true} onCancel={handleCancel} onOk={onOk} className={classNames(`${prefixCls}-modal`)} > <div className={classNames(`${prefixCls}-modal-wrap`)}> <div className={classNames(`${prefixCls}-modal-left`)}> <div className={classNames(`${prefixCls}-modal-select-wrap`)}> <Input className={classNames(`${prefixCls}-modal-search`)} placeholder={placeholder} bordered={false} prefix={searchPrefix} onChange={onSearch} onPressEnter={onSearch} /> <div className={classNames(`${prefixCls}-modal-target`)}> <div>指标:</div> <Radio.Group onChange={onRadioChange} defaultValue={targetValue}> <Radio.Button value="emphasis">重点指标</Radio.Button> <Radio.Button value="all">全部</Radio.Button> </Radio.Group> </div> <div className={classNames(`${prefixCls}-modal-select`, { warning: !(selectData.length < maximum), })} > {selectData.length < maximum ? ( <> <ExclamationCircleFilled /> <div>已选择 {selectData.length} 个指标</div> </> ) : ( <> <ExclamationCircleFilled /> <div>已达上限,最多选择 {maximum} 个指标</div> </> )} </div> </div> <div className={classNames(`${prefixCls}-modal-option-wrap`)}> {!quotaList.length && <Empty />} <Row gutter={[0, 6]}> {!!quotaList.length && quotaList.map((item) => ( <Col span={8} key={item.key}> <Checkbox value={item.title} checked={item.checked} disabled={ (selectData.length > maximum || selectData.length === maximum) && !item.checked } onChange={handleCheckboxChange} > {item.title} </Checkbox> </Col> ))} </Row> </div> </div> <div className={classNames(`${prefixCls}-modal-right`)}> <div className={classNames(`${prefixCls}-modal-number`)}> 已选:{selectData.length}/{maximum} </div> <div className={classNames(`${prefixCls}-modal-tree`)}> <Tree draggable={true} onDrop={handleDrop} {...treeProps}> {selectData.map((item) => ( <TreeNode key={item.key} title={ <div className={classNames(`${prefixCls}-modal-tree-title`)}> <div>{item.title}</div> <CloseOutlined onClick={() => handleCancelSelect(item)} /> </div> } /> ))} </Tree> </div> </div> </div> </Modal> )} </div> ); }; QuotaSelect.defaultProps = { buttonProps: {}, width: 900, title: '选择显示字段', cancelText: '取消选择', okText: '确定', placeholder: '搜索关键词', searchPrefix: <SearchOutlined />, maximum: 0, dataSource: [], selectData: [], treeProps: {}, onModalCancel: () => {}, onModalOk: () => {}, onModalClose: () => {}, onCancelSelect: () => {}, onTreeDrop: () => {}, }; QuotaSelect.propTypes = { buttonProps: PropTypes.object, width: PropTypes.number, title: PropTypes.string, cancelText: PropTypes.string, okText: PropTypes.string, placeholder: PropTypes.string, searchPrefix: PropTypes.node, maximum: PropTypes.number, dataSource: PropTypes.array, selectData: PropTypes.array, treeProps: PropTypes.object, onModalCancel: PropTypes.func, onModalOk: PropTypes.func, onModalClose: PropTypes.func, onCancelSelect: PropTypes.func, onTreeDrop: PropTypes.func, }; export default QuotaSelect;