import { Space, Button, Transfer, Empty, Tree } from 'antd';
import {
Form,
Icon,
Input,
Loading,
Modal
} from 'antd';
import empty from '@/Images/others/empty.png';
const lodash = require('lodash');
const { cloneDeep, isEmpty } = lodash;
import { useEffect, useState } from 'react';
import { connect } from 'dva';
import styles from './index.less';
interface Props {
onCancel: () => void;
submitRegion: (data: any) => void;
aList: any[];
}
const SelectRegion = (props: Props) => {
const { onCancel, aList } = props;
// 封装后的树形数据
const [newTree, setNewTree] = useState<any>();
// 搜索后的tree列表
const [searchTree, setSearchTree] = useState<Array<any>>([]);
// 搜索框中的值
const [searchValue, setSearchValue] = useState<string>('');
// 展开的树节点id
const [expandedKeys, setExpandedKeys] = useState<Array<React.Key>>([]);
// 是否自动展开树节点的父节点
const [autoExpandParent, setAutoExpandParent] = useState(true);
// 当前选中的规格项
const [targetKeys, setTargetKeys] = useState<any>([]);
// 平铺数组
const [newDataSource, setNewDataSource] = useState<Array<any>>([]);
// // 原始的平铺数组
// const [originalData, setOriginalData] = useState<Array<any>>([]);
// form表单实例
const [forms] = Form.useForm();
// 实时转平铺数组
useEffect(() => {
if (aList) {
const tempList: Array<any> = [];
const flatten = (list: Array<any>) => {
if (Array.isArray(list) && list.length > 0) {
list.forEach((item: any) => {
tempList.push(item);
flatten(item.children);
});
}
};
flatten(aList);
setNewDataSource(tempList);
}
setNewTree(aList);
}, [aList]);
/**
* 封装树形数据方法
* @param tree 要封装的数据数树
* @returns 返回封装的数组
*/
const _packageTree = (tree: Array<any>) => {
if (Array.isArray(tree) && tree.length > 0) {
const list: Array<any> = tree.map((item: any) => ({
title: item.fullName,
key: item.deptId,
deptId: item.deptId,
children: item.childrenDeptList
? _packageTree(item.childrenDeptList)
: null
}));
return list;
}
};
// 删除按钮样式
const transferTitles = [
'',
<Icon
icon="deleteIcon"
onClick={() => {
setTargetKeys([]);
}}
/>
];
// 关键字搜索树数据回调
useEffect(() => {
if (newTree && Array.isArray(newTree) && newTree.length > 0) {
const loop = (data: Array<any>): Array<any> =>
data.map((item) => {
const strTitle = item.title;
const index = strTitle.indexOf(searchValue);
const beforeStr = strTitle.substring(0, index);
const afterStr = strTitle.slice(index + searchValue.length);
const title =
index > -1 ? (
<span>
{beforeStr}
<span className={styles.selectRegion_searchText}>
{searchValue}
</span>
{afterStr}
</span>
) : (
<span>{strTitle}</span>
);
if (item.children) {
return { title, key: item.key, children: loop(item.children) };
}
return {
title,
key: item.key
};
});
const treeData = loop(newTree);
setSearchTree(treeData);
}
}, [searchValue]);
/**
* @method 选项在两栏间转移的回调
* @param {Array} keys 右栏当前数组
*/
const _handleTransferChange = (keys: any) => {
setTargetKeys(keys);
};
/**
* @method 搜索的回调
* @param {String} value 当前搜索框的值
*/
const _handleSearch = (value: string) => {
if (value) {
const newExpandedKeys: Array<any> = newDataSource
.map((item: any) => {
if (item.title.indexOf(value) > -1) {
return _getParentKey(item.key, newDataSource);
}
return null;
})
.filter(
(item: any, i: number, self: Array<any>) =>
item && self.indexOf(item) === i
);
setExpandedKeys(newExpandedKeys);
setAutoExpandParent(true);
} else {
setExpandedKeys([]);
}
setSearchValue(value);
};
/**
* @method 展开树的回调
* @param {Array} keys 当前展开的key数组
*/
const _handleExpand = (keys: React.Key[]) => {
setExpandedKeys(keys);
setAutoExpandParent(false);
};
/**
* @method 根据节点的key获取其父节点的key
* @param {Number} key 节点的key值
* @param {Array} tree 树数据
* @return 返回展开的的父节点
*/
const _getParentKey = (key: number, tree: Array<any>): React.Key => {
let parentKey: React.Key = '';
for (let i = 0; i < tree.length; i++) {
const node = tree[i];
if (node.children) {
if (node.children.some((item: any) => item.key === key)) {
parentKey = node.key;
} else if (_getParentKey(key, node.children)) {
parentKey = _getParentKey(key, node.children);
}
}
}
return parentKey;
};
/**
* 生成搜索后的tree列表
* @param tree
* @param checkedKeys
* @returns 返回搜索后的tree列表
*/
const _generateTree = (tree: any, checkedKeys: any) => {
let list: any = [];
if (Array.isArray(tree) && tree.length > 0) {
list = tree.map(({ children, ...props }) => ({
...props,
disabled: checkedKeys.includes(props.key),
children: _generateTree(children, checkedKeys)
}));
}
return list;
};
/**
* 选中方法
* @param selectedKeys 当前已选择的数组
* @param key 循环遍历的每一个树数据的key
* @returns 返回选中状态
*/
const isChecked = (selectedKeys: any, key: any) => selectedKeys.includes(key);
/**
* 提交区域
*/
const _submitRegion = () => {
console.log('222');
const targetList: any[] = [];
newDataSource.forEach((item: any) => {
if (targetKeys.includes(item.key)) {
targetList.push(item);
}
});
console.log('targetList', targetList);
};
console.log('newDataSource11', newDataSource);
return (
<Modal
title={intl.formatMessage({ id: 'Select the country/region' })}
canDragm
visible
onCancel={onCancel}
footer={
<Space>
<Button type="primary" onClick={_submitRegion}>
{intl.formatMessage({ id: 'OK' })}
</Button>
<Button onClick={onCancel}>
{intl.formatMessage({ id: 'Cancel' })}
</Button>
</Space>
}
className={styles.selectRegion}
>
<Transfer
className={styles.selectRegion_transfers}
oneWay
showSelectAll={false}
selectAllLabels={['', intl.formatMessage({ id: 'Selected3' })]}
titles={transferTitles}
dataSource={newDataSource}
targetKeys={targetKeys}
render={(item: any) => item.title}
onChange={_handleTransferChange}
>
{({ direction, onItemSelect, selectedKeys }) => {
if (direction === 'left') {
const checkedKeys: any = [...selectedKeys, ...targetKeys];
return (
<>
<Input
className={styles.selectRegion_input}
allowClear
value={searchValue}
onChange={_handleSearch}
onSearch={_handleSearch}
placeholder={intl.formatMessage({
id: 'Please enter...'
})}
/>
{isEmpty(searchTree) ? (
<Empty
image={empty}
className={styles.selectRegion_empty}
description={intl.formatMessage({ id: 'No data' })}
/>
) : (
<Tree
className={styles.selectRegion_tree}
blockNode
checkable
checkStrictly
defaultExpandAll
checkedKeys={checkedKeys}
treeData={_generateTree(searchTree, targetKeys)}
expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
onExpand={_handleExpand}
onCheck={(_, { node: { key } }) => {
onItemSelect(key as any, !isChecked(checkedKeys, key));
}}
onSelect={(_, { node: { key } }) => {
onItemSelect(key as any, !isChecked(checkedKeys, key));
}}
/>
)}
</>
);
}
}}
</Transfer>
{/* </Form.Item>
</Form> */}
</Modal>
);
};
export default connect(({ saleCountry }: any) => {
const { aList } = saleCountry;
return {
aList
};
})(SelectRegion);
CSS样式
.selectRegion {
width: 720px !important;
:global {
.ant4-modal-footer {
button {
width: 80px;
height: 30px;
}
}
.ant-transfer {
.ant-transfer-list {
margin-top: 7px;
width: 260px !important;
height: 425px !important;
.ant-transfer-list-header {
background-color: #f2f3f5;
}
.ant-transfer-list-body {
height: 440px;
padding: 10px;
.ant-tree-node-selected {
background-color: #fff;
}
.ant-empty-image {
margin-bottom: 6px;
}
.ant-empty-description {
color: rgba(0, 0, 0, 0.7);
}
.ant-transfer-list-content-item {
&:hover {
background-color: #edf8ff;
.ant-transfer-list-content-item-remove {
visibility: visible;
}
}
.ant-transfer-list-content-item-remove {
visibility: hidden;
.anticon-delete {
svg {
color: #999;
border-radius: 50%;
path {
d: path('M513.43007 1019.262092c-280.20375 0-507.388982-227.207745-507.388982-507.410472 0-280.224216 227.185232-507.409448 507.388982-507.409448 280.247752 0 507.391029 227.185232 507.391029 507.409448C1020.821099 792.054347 793.678846 1019.262092 513.43007 1019.262092zM746.107387 363.903034c9.540284-9.53926 9.540284-25.021883 0-34.539654l-51.822272-51.800783c-9.535167-9.558703-24.977881-9.558703-34.518165 0L512.976746 424.334381 366.184495 277.562597c-9.53619-9.558703-24.977881-9.558703-34.518165 0l-51.822272 51.800783c-9.538237 9.517771-9.538237 25.001417 0 34.539654l146.793274 146.770761-146.793274 146.790204c-9.538237 9.518794-9.538237 25.004487 0 34.540677l51.822272 51.79976c9.540284 9.538237 24.981974 9.538237 34.518165 0L512.976746 597.014232l146.790204 146.790204c9.540284 9.538237 24.982998 9.538237 34.518165 0l51.822272-51.79976c9.540284-9.53619 9.540284-25.021883 0-34.540677L599.317183 510.674818 746.107387 363.903034z'
);
}
}
}
}
}
}
&:first-child {
// .ant-transfer-list-content {
// width: 210px;
// margin-top: 5px;
// border-top: 1px solid rgb(214, 214, 214);
// }
.ant-transfer-list-header {
display: none;
}
.ant-transfer-list-body-search-wrapper {
position: relative;
flex: none;
padding: 0;
width: 250px;
margin-top: -6px;
margin-left: -6px;
}
}
&:last-child {
.ant-transfer-list-header {
background-color: rgba(242, 243, 245, 1);
}
.ant-transfer-list-body-search-wrapper {
display: none;
}
}
}
.ant-transfer-operation {
width: 50px;
height: 50px;
button {
margin-bottom: 0;
width: 100%;
height: 100%;
border-radius: 50%;
color: #0183cc;
background-color: #fff;
border-color: #2993ce;
.anticon-right {
svg {
font-size: 22px;
path {
d: path('M885.113 489.373L628.338 232.599c-12.496-12.497-32.758-12.497-45.254 0-12.497 12.497-12.497 32.758 0 45.255l203.3 203.3H158.025c-17.036 0-30.846 13.811-30.846 30.846 0 17.036 13.811 30.846 30.846 30.846h628.36L583.084 746.147c-12.497 12.496-12.497 32.758 0 45.255 6.248 6.248 14.438 9.372 22.627 9.372s16.379-3.124 22.627-9.372l256.775-256.775a31.999 31.999 0 0 0 0-45.254z'
);
}
}
}
&:hover {
color: #2993ce !important;
background-color: #eef9ff !important;
border-color: #1394dd !important;
}
&:active {
color: #287bab !important;
background-color: #f7faff !important;
border-color: #287bab !important;
}
&[disabled] {
color: rgba(0, 0, 0, 0.25) !important;
border-color: #d9d9d9 !important;
background-color: #f5f5f5 !important;
}
}
}
}
}
// .selectRegion_form {
.selectRegion_transfers {
margin-left: 5px;
.selectRegion_searchText {
color: #ff0000;
}
.selectRegion_input {
width: 287px;
margin-left: -4.5px;
margin-top: -5px;
border-radius: 0;
}
.selectRegion_empty {
padding-top: 47%;
}
.selectRegion_tree {
padding-top: 5px;
margin-left: -5px;
border-top: 1px solid rgb(240, 240, 240);
margin-top: 5px;
width: 300px;
height: 388px;
overflow-y: auto;
border-radius: 0;
}
}
// }
}