/*
|
* @Company: hugeInfo
|
* @Author: ldh
|
* @Date: 2022-02-25 18:16:28
|
* @LastEditTime: 2024-08-26 10:27:36
|
* @LastEditors: dminyi 1301963064@qq.com
|
* @Version: 1.0.0
|
* @Description: 自定义带操作的树结构
|
*/
|
import React, { useState, useEffect, useRef, useMemo } from 'react';
|
import PropTypes from 'prop-types';
|
import './index.less';
|
import { Dropdown, Tooltip } from 'antd';
|
import { useVirtual } from 'react-virtual';
|
import { CaretDownOutlined, EllipsisOutlined } from '@ant-design/icons';
|
import * as $$ from '../../utils/utility';
|
|
/*
|
* active, // 当前点击的treeNode的key
|
* keyStr, // 树结构唯一值的字段名
|
* nameStr, // treeNode名称字段名
|
* data:[{'keyStr':'','nameStr':'',children:[]}], // tree数据
|
* searchValue, // tree搜索值
|
* dropdownOption, // treeNode的操作
|
* isChildren, // 是否有子结构
|
* handleClickTreeNode, // 点击treeNode
|
*/
|
const MyTree = ({ active, keyStr, nameStr, data, searchValue = '', dropdownOption, isChildren, handleClickTreeNode }) => {
|
const recordRef = useRef();
|
|
const [treeData, setTreeData] = useState({ data: [], expandedKeys: [] });
|
|
const treeDataMap = useMemo(() => {
|
let arr = [];
|
function loop(_data, num, parentKeys) {
|
num = num + 1;
|
_data.forEach((x) => {
|
x.parentKeys = [...parentKeys, x.parentId];
|
x.num = num;
|
arr.push(x);
|
if (x.children) {
|
loop(x.children, num, x.parentKeys);
|
}
|
});
|
}
|
loop(data, 1, []);
|
return arr;
|
}, [data]);
|
|
useEffect(() => {
|
let expandedKeys = [];
|
let arr = [],
|
arr2 = [];
|
treeDataMap.forEach((item) => {
|
const strTitle = item[nameStr];
|
const index = strTitle?.indexOf(searchValue);
|
if (index > -1) {
|
expandedKeys = Array.from(new Set([...expandedKeys, ...item.parentKeys]));
|
}
|
arr.push({
|
...item,
|
children: item.children ? [] : null,
|
});
|
});
|
if (searchValue) {
|
arr.forEach((item) => {
|
if (expandedKeys.includes(item[keyStr]) || item[nameStr]?.indexOf(searchValue) > -1) {
|
arr2.push(item);
|
}
|
});
|
}
|
setTreeData({ data: searchValue ? arr2 : arr, expandedKeys });
|
}, [nameStr, searchValue, treeDataMap]);
|
|
return treeData?.data?.length !== 0 ? (
|
<RowVirtualizer
|
rows={treeData.data || []}
|
recordRef={recordRef}
|
isChildren={isChildren}
|
active={active}
|
keyStr={keyStr}
|
nameStr={nameStr}
|
dropdownOption={dropdownOption}
|
isChildrenOpen={treeData.expandedKeys}
|
setIsChildrenOpen={(value) => {
|
let arr = [];
|
treeDataMap.forEach((item) => {
|
if (item.parentKeys.filter((x) => value.includes(x)).length === item.parentKeys.length) {
|
arr.push(item);
|
}
|
});
|
setTreeData({ data: arr, expandedKeys: value });
|
}}
|
handleClickTreeNode={handleClickTreeNode}
|
/>
|
) : (
|
$$.MyEmpty()
|
);
|
};
|
|
function RowVirtualizer({
|
rows,
|
recordRef,
|
isChildren,
|
active,
|
keyStr,
|
nameStr,
|
dropdownOption,
|
isChildrenOpen,
|
setIsChildrenOpen,
|
handleClickTreeNode,
|
}) {
|
const rowVirtualizer = useVirtual({
|
size: rows.length,
|
parentRef: recordRef,
|
});
|
|
return (
|
<div className="tree" ref={recordRef}>
|
<div style={{ height: rowVirtualizer.totalSize, width: '100%', position: 'relative' }}>
|
{rowVirtualizer.virtualItems.map((virtualRow) => {
|
let x = rows[virtualRow.index];
|
return (
|
<div
|
key={virtualRow.index}
|
ref={virtualRow.measureRef}
|
style={{
|
position: 'absolute',
|
top: 0,
|
left: 0,
|
width: '100%',
|
transform: `translateY(${virtualRow.start}px)`,
|
}}
|
>
|
<div>
|
<div
|
className={`tree-item ${active === x[keyStr] && 'tree-itemActive'}`}
|
onMouseEnter={() => {
|
if (document.getElementById(`ellipsis${x[keyStr]}`)) {
|
document.getElementById(`ellipsis${x[keyStr]}`).style.display = 'inline-block';
|
}
|
}}
|
onMouseLeave={() => {
|
if (document.getElementById(`ellipsis${x[keyStr]}`)) {
|
document.getElementById(`ellipsis${x[keyStr]}`).style.display = 'none';
|
}
|
}}
|
style={{ paddingLeft: `${16 * x.num}px` }}
|
>
|
{isChildren && (
|
<div
|
className={`tree-item-leftIcon ${isChildrenOpen.includes(x[keyStr]) ? '' : 'tree-item-rotate'}`}
|
style={{ visibility: x.children ? '' : 'hidden' }}
|
onClick={() => {
|
let index = isChildrenOpen.indexOf(x[keyStr]);
|
if (index !== -1) {
|
isChildrenOpen.splice(index, 1);
|
} else {
|
isChildrenOpen.push(x[keyStr]);
|
}
|
setIsChildrenOpen([...isChildrenOpen]);
|
}}
|
>
|
<CaretDownOutlined />
|
</div>
|
)}
|
<div onClick={() => handleClickTreeNode(x)} className="tree-item-title">
|
<Tooltip title={x[nameStr]}>{x[nameStr]}</Tooltip>
|
</div>
|
{dropdownOption && (
|
<Dropdown overlay={dropdownOption({ num: x.num, value: x })}>
|
<EllipsisOutlined className="tree-item-rightIcon" id={`ellipsis${x[keyStr]}`} />
|
</Dropdown>
|
)}
|
</div>
|
</div>
|
</div>
|
);
|
})}
|
</div>
|
</div>
|
);
|
}
|
|
MyTree.propTypes = {
|
key: PropTypes.any,
|
keyStr: PropTypes.string,
|
data: PropTypes.array,
|
searchValue: PropTypes.string,
|
dropdownOption: PropTypes.any,
|
isChildren: PropTypes.bool,
|
handleClickTreeNode: PropTypes.func,
|
};
|
|
export default MyTree;
|