123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- import React, { ReactNode, useEffect, useState, MouseEvent } from 'react'
- import { Input, Spin, Image, Popconfirm } from 'antd';
- import { PlusOutlined } from '@ant-design/icons';
- import DirectoryTree from './components/DirectoryTree';
- import NodeTextArea from './components/NodeTextArea';
- import './index.less'
- import DelActionIcon from './images/del14px.png';
- import EditActionIcon from './images/edit14px.png';
- import AddActionIcon from './images/add.png';
- import FileIcon from './images/file.png';
- // const { DirectoryTree } = Tree;
- const { Search } = Input;
- //树形文件组件
- enum Types { 'add', 'del', 'edit', 'search' };
- type TypeVals = keyof typeof Types;
- type MccsFileTreeProps = {
- onSelectHandle?: (data: MccsFileTree.childTree) => void, //选中回调
- actionHandle?: ({ type, data }: { type: string, data: MccsFileTree.childTree }) => void, //操作回调,包括编辑/删除/新增/搜索
- searchHandle?: (val: any) => void,
- switcherIcon?: ReactNode,
- treeData: MccsFileTree.childTree[] | [],
- defaultSelected?: string, //传id
- formContent?: ReactNode,
- editable?: boolean,
- renderFilter?: () => ReactNode,//添加自定义过滤操作
- }
- const MccsFileTree: React.FC<MccsFileTreeProps> = (props) => {
- const { treeData, onSelectHandle, actionHandle, defaultSelected, searchHandle, editable, renderFilter } = props;
- const [isLoading, setIsLoading] = useState(true);
- //当前选中的
- const [currentActivedIndex, setcurrentActivedIndex] = useState('');
- const actionFunc = (event: MouseEvent | undefined, type: TypeVals, data: MccsFileTree.childTree) => {
- event?.stopPropagation();
- actionHandle && actionHandle({ type, data: data });
- }
- //操作
- const Action = (props: MccsFileTree.childTree) => {
- const { isLeaf } = props;
- return (
- <div className='action'>
- {
- !isLeaf && ( //非叶子结点才可以新增
- <>
- <Image width={15} preview={false} onClick={(e) => actionFunc(e, 'add', props)} src={AddActionIcon} />
- <div style={{ width: 5 }}></div>
- </>
- )
- }
- <Image width={15} preview={false} onClick={(e) => actionFunc(e, 'edit', props)} src={EditActionIcon} />
- <div style={{ width: 5 }}></div>
- <Popconfirm
- title="是否确定删除?"
- onConfirm={(e) => { actionFunc(e, 'del', props) }}
- okText="确定"
- cancelText="取消"
- >
- <Image width={15} preview={false} onClick={e => e.stopPropagation()} src={DelActionIcon} />
- </Popconfirm>
- </div>
- )
- }
- //叶子结点结构
- const TreeNode = (nodeProps: MccsFileTree.childTree) => {
- const { title, id, code, ...rest } = nodeProps;
- return (
- <div className={currentActivedIndex == id ? 'treeNode actived' : 'treeNode'} onClick={onSelectHandle ? () => {
- setcurrentActivedIndex(id);
- onSelectHandle(nodeProps)
- } : () => { setcurrentActivedIndex(id); }}>
- <div style={{ display: 'flex', marginRight: 5, justifyContent: 'center', alignItems: 'center' }} ><Image width={15} preview={false} src={FileIcon} /> </div>
- {/* <div className='treeNodeInner'>{`${code} ${title}`}</div> */}
- <NodeTextArea className="treeNodeInner" text={`${code} ${title}`}></NodeTextArea>
- {(currentActivedIndex == id && editable) && <Action {...nodeProps} /> /*点击展示操作项*/}
- </div>
- )
- }
- //递归树形结构
- const loop = (data: MccsFileTree.childTree, i: number) => {
- const { title, children = [], ...restProps } = data;
- // const node = <div className="node">{`${restProps.code} ${title}`}</div>;
- const node = <NodeTextArea className="node" text={`${restProps.code} ${title}`}></NodeTextArea>
- if (data.isLeaf) {
- return <TreeNode key={data.id} currentActivedIndex={currentActivedIndex} setcurrentActivedIndex={setcurrentActivedIndex} title={title} {...restProps} />
- }
- return (
- <DirectoryTree key={data.id} currentActivedIndex={currentActivedIndex} setcurrentActivedIndex={setcurrentActivedIndex}
- nodeLabel={node} {...data} onClick={() => onSelectHandle ? onSelectHandle(data) : () => { }}
- action={editable && <Action {...data} />} defaultCollapsed={!(currentActivedIndex==data.id)}
- >
- {
- children.map((item, index) => {
- if (item.isLeaf) {
- return <TreeNode currentActivedIndex={currentActivedIndex} setcurrentActivedIndex={setcurrentActivedIndex} key={index} {...item} />
- } else {
- return loop({...item,isLeaf:item.leaf}, index);
- }
- })
- }
- </DirectoryTree>
- )
- }
- const deepGetVal = (dataToDeep: any[], key: string, subArr: string, findVal: number) => {
- // console.log({dataToDeep,key,subArr});
- let needVal = {};
- function looper(dataToDeep: any[], key: string, subArr: string) {
- dataToDeep.forEach(item => {
- if (item[key] == findVal) {
- needVal = item;
- return;
- }
-
- if (item[subArr] && item[subArr].length > 0) {
- looper(item[subArr], key, subArr);
- }
-
- });
- }
- looper(dataToDeep, key, subArr);
- return needVal
- }
- useEffect(() => {
- //当设置默认激活项时触发
- if (defaultSelected != currentActivedIndex) {
- setcurrentActivedIndex(defaultSelected ? defaultSelected : '');
- const result = deepGetVal(treeData,'id','children',Number(defaultSelected));
- onSelectHandle&&onSelectHandle(result as MccsFileTree.childTree);
- }
- }, [defaultSelected]);
- useEffect(() => {
- if (treeData.length > 0) {
- setIsLoading(false);
- }
- }, [treeData]);
- return (
- <div className='fileTree'>
- <div className="searchBar">
- {
- editable && (
- <div className="add" onClick={e => actionFunc(e, 'add', {
- title: '',
- id: `0`,
- isLeaf: false,
- code: `${new Date().getTime()}`,
- children: []
- })}><PlusOutlined /></div>
- )
- }
- <Search placeholder='请输入' className="inputArea" allowClear onSearch={(val, e) => searchHandle && searchHandle(val)} />
- </div>
- {
- renderFilter && (
- <div className='filter'>
- {
- renderFilter()
- }
- </div>
- )
- }
- <div className='treeContainer'>
- {
- isLoading ? <div className='spinWrap'><Spin delay={500} /></div> : (
- <>
- {treeData.map((node, i) => {
- return loop({...node,isLeaf:node.leaf}, i);
- })}
- </>
- )
- }
- </div>
- </div>
- );
- };
- export default MccsFileTree
|