antd4 tree带搜索框的可编辑树实现(hooks+ts)

需求背景

  实现带搜索框的可编辑树,有以下功能在:
1、搜索相关节点高亮
2、配合treeSelect规范数据处理
3、节点可添加和编辑(编辑可修改上级)
4、节点可删除
5、移入显示编辑图标

0、带搜索框的树

默认数据:
在这里插入图片描述
搜索exa后:搜索exa,展开包含exa的相关父节点,并且高亮,收起不包含的父节点

在这里插入图片描述

return (
    <div className={
    
    styles.detail__container}>
      <Search style={
    
    {
    
     marginBottom: 8 }} placeholder={
    
    `搜索`} onChange={
    
    onChange} />
      {
    
    
        treeData?.length > 0 && <Tree
          onExpand={
    
    onExpand}
          autoExpandParent={
    
    autoExpandParent}
          defaultExpandAll
          onCheck={
    
    checkDep}
          checkedKeys={
    
    checkedKeys}
          checkStrictly
          onSelect={
    
    onSelect}
          onMouseEnter={
    
    onMouseEnter}
          onMouseLeave={
    
    onMouseLeave}
          expandedKeys={
    
    expandedKeys}
        >
          {
    
    renderTreeNodes(treeData)}
        </Tree>
      }  
    </div>
  );

1、搜索相关节点高亮

在这里插入图片描述

0.节点渲染时搜索后,高亮显示

const renderTreeNodes = (data: any) => {
    
    
    const menu = (item: any) => {
    
    
      return (
        <Menu>
          <Menu.Item key="1" onClick={
    
    () => onAdd(item, 'edit',)}>修改类别名</Menu.Item>
          <Menu.Item key="2" onClick={
    
    () => handleDelete(item.id)}>删除类别</Menu.Item>
        </Menu>
      )
    }

    let nodeArr = data.map((item: any) => {
    
    
      const index = item && item.name.indexOf(searchValue);
      const beforeStr = item.name.substr(0, index);
      const afterStr = item.name.substr(index + searchValue.length);
      item.value = index > -1 ? (
        <span>
          {
    
    beforeStr}
          <span className={
    
    styles.site_tree_search_value}>{
    
    searchValue}</span>
          {
    
    afterStr}
          {
    
    
          //核心代码
            editVisiable && item.id === key && <span>
              
                 <Dropdown overlay={
    
    menu(item)} trigger={
    
    ['hover']}>
                  <EditOutlined style={
    
    {
    
     marginLeft: 10 }} />
                </Dropdown>          
                 <PlusCircleTwoTone twoToneColor="#ff571a" style={
    
    {
    
     marginLeft: 10 }} onClick={
    
    () => onAdd(item, 'add')} />
            </span>
          }
        </span>
      ) : (
        <div>
          <span>{
    
    item.name}</span>
          {
    
    
          //核心代码
            editVisiable && item.id === key && <span>           
                 <Dropdown overlay={
    
    menu(item)} trigger={
    
    ['hover']}>
                  <EditOutlined style={
    
    {
    
     marginLeft: 10 }} />
                </Dropdown>          
                 <PlusCircleTwoTone twoToneColor="#ff571a" style={
    
    {
    
     marginLeft: 10 }} onClick={
    
    () => onAdd(item, 'add')} />
            </span>
          }
        </div>
      );

      if (item.children) {
    
    
        return (
          <TreeNode title={
    
    item.value} key={
    
    item.id}>
            {
    
    renderTreeNodes(item.children)}
          </TreeNode>
        );
      }
      return <TreeNode title={
    
    item.value} key={
    
    item.id} />;
    });
    return nodeArr;
  };

1.搜索组件

	<Search style={
    
    {
    
     marginBottom: 8 }} placeholder={
    
    `搜索${
      
      typeName}`} onChange={
    
    onChange} />

2.搜索方法(输入触发)
注意:展开拥有相关节点的父节点,收起无关节点

// 搜索节点
  const onChange = (e: any) => {
    
    
    let {
    
     value } = e.target
    if (!value) {
    
    
      setExpandedKeys(defaultExpandedKeys);
      setSearchValue(value)

      return
    }
    value = String(value).trim()
    const dataList: any[] = generateList(treeData, [])
    let expandedKeys: any = dataList
      .map((item: any) => {
    
    
        if (item && item.name.indexOf(value) > -1) {
    
    
          return getParentKey(item.key, treeData)
        }
        return null;
      })
      .filter((item: any, i: number, self: any) => item && self.indexOf(item) === i)

    setExpandedKeys(expandedKeys)
    setAutoExpandParent(true)
    setSearchValue(value)
  }
  // tree树形匹配方法
  const getParentKey = (key: number | string, tree: any): any => {
    
    
    let parentKey
    for (let i = 0; i < tree.length; i++) {
    
    
      const node = tree[i];
      if (node.children) {
    
    
        if (node.children.some((item: any) => item.id === key)) {
    
    
          parentKey = node.id;
        } else if (getParentKey(key, node.children)) {
    
    
          parentKey = getParentKey(key, node.children);
        }
      }
    }
    return parentKey;
  }

  // 树节点展开/收缩
  const onExpand = (expandedKeys: any) => {
    
    
    setExpandedKeys(expandedKeys)
    setAutoExpandParent(false)
  }

2、配合treeSelect规范数据处理

  1. 递归修改data属性值,配合treeSelect规范数据
	// 递归修改data属性值,配合treeSelect规范数据
  const handleData = (data: TList[]) => {
    
    
    let item: TreeData[] = [];
    data.map((list: any, i: number) => {
    
    
      let newItem: any = {
    
    };
      newItem.key = list.id;
      newItem.value = list.id;
      newItem.title = list.name;
      newItem.children = list.children ? handleData(list.children) : []; // 如果还有子集,就再次调用自己
      // 合并新属性和原有属性
      item.push({
    
     ...list, ...newItem });
    });
    return item;
  };

1.将树形节点改为一维数组

  //  将树形节点改为一维数组
  const generateList = (data: any, dataList: any[]) => {
    
    
    for (let i = 0; i < data.length; i++) {
    
    
      const node = data[i];
      const {
    
     name, id, source, role, parentId, level } = node;
      dataList.push({
    
     name, id, source, role, key: id, title: name, parentId, level });
      if (node.children) {
    
    
        generateList(node.children, dataList);
      }
    }
    return dataList
  }

3、节点可添加编辑(编辑可修改上级)

添加
在这里插入图片描述
在这里插入图片描述
编辑
在这里插入图片描述
在这里插入图片描述

0.定义的keyeditVisiable

	const [key, setKey] = useState('');
	const [name, setName] = useState('');
  	const [type, setType] = useState('add');
  	const [currentItem, setCurrentItem] = useState<any>({
    
    })
    const [createVisible, setCreateVisible] = useState(false);

1.添加编辑方法

const onAdd = (item: any, type: string) => {
    
    
    setType(type);
    setName(item.name);
    setKey(item.key);
    setCurrentItem(item);
    if (type === 'edit') {
    
    
      form.setFieldsValue({
    
    
        name: item?.name,
        parentId: item?.parentId,
      })
    } else if (type === 'add') {
    
    
      form.setFieldsValue({
    
    
        parentId: item?.id,
      })
    }
    setCreateVisible(true);
  };

2.在节点render加入添加/编辑图标 – renderAddTree

const renderTreeNodes = (data: any) => {
    
    
    const menu = (item: any) => {
    
    
      return (
        <Menu>
          <Menu.Item key="1" onClick={
    
    () => onAdd(item, 'edit',)}>修改类别名</Menu.Item>
          <Menu.Item key="2" onClick={
    
    () => handleDelete(item.id)}>删除类别</Menu.Item>
        </Menu>
      )
    }

    let nodeArr = data.map((item: any) => {
    
    
      const index = item && item.name.indexOf(searchValue);
      const beforeStr = item.name.substr(0, index);
      const afterStr = item.name.substr(index + searchValue.length);
      item.value = index > -1 ? (
        <span>
          {
    
    beforeStr}
          <span className={
    
    styles.site_tree_search_value}>{
    
    searchValue}</span>
          {
    
    afterStr}
          {
    
    
          //核心代码
            editVisiable && item.id === key && <span>
              
                 <Dropdown overlay={
    
    menu(item)} trigger={
    
    ['hover']}>
                  <EditOutlined style={
    
    {
    
     marginLeft: 10 }} />
                </Dropdown>          
                 <PlusCircleTwoTone twoToneColor="#ff571a" style={
    
    {
    
     marginLeft: 10 }} onClick={
    
    () => onAdd(item, 'add')} />
            </span>
          }
        </span>
      ) : (
        <div>
          <span>{
    
    item.name}</span>
          {
    
    
          //核心代码
            editVisiable && item.id === key && <span>           
                 <Dropdown overlay={
    
    menu(item)} trigger={
    
    ['hover']}>
                  <EditOutlined style={
    
    {
    
     marginLeft: 10 }} />
                </Dropdown>          
                 <PlusCircleTwoTone twoToneColor="#ff571a" style={
    
    {
    
     marginLeft: 10 }} onClick={
    
    () => onAdd(item, 'add')} />
            </span>
          }
        </div>
      );

      if (item.children) {
    
    
        return (
          <TreeNode title={
    
    item.value} key={
    
    item.id}>
            {
    
    renderTreeNodes(item.children)}
          </TreeNode>
        );
      }
      return <TreeNode title={
    
    item.value} key={
    
    item.id} />;
    });
    return nodeArr;
  };

3.添加/编辑弹窗

<Modal
        destroyOnClose
        title={
    
    type === 'add' ? `新建${
      
      typeName}` : `修改${
      
      typeName}`}
        visible={
    
    createVisible}
        onOk={
    
    handleOk}
        confirmLoading={
    
    confirmLoading}
        onCancel={
    
    () => {
    
    
          setCreateVisible(false)
          form.resetFields();
          setCurrentItem({
    
    });
          setUpValue('');
        }}
      >
        <Form
          name="createForm"
          form={
    
    form}
          labelCol={
    
    {
    
     span: 7 }}
          wrapperCol={
    
    {
    
     span: 17 }}
          onFinish={
    
    handleFinish}
        >
          {
    
    
            currentItem.level !== 1 && treeType === 3 && <Form.Item
              label="上级类别"
              name="parentId"
              rules={
    
    [
                {
    
    
                  required: true,
                  message: '请选择上级类别',
                },
              ]}
            >
              <TreeSelect
                showSearch
                style={
    
    {
    
     width: '100%' }}
                value={
    
    upValue || currentItem?.parentId}
                dropdownStyle={
    
    {
    
     maxHeight: 400, overflow: 'auto' }}
                placeholder="请选择上级类别"
                allowClear
                treeDefaultExpandAll
                onChange={
    
    (value, label,) => onUpChange(value, label,)}
              >
                {
    
    renderAddTree(treeTypeList || [])}
              </TreeSelect>

            </Form.Item>

          }
          <Form.Item
            label={
    
    `${
      
      typeName}名称`}
            name="name"
            rules={
    
    [
              {
    
    
                required: true,
                message: `请输入${
      
      typeName}名称`,
              },
            ]}
          >
            <Input placeholder={
    
    `请输入${
      
      typeName}名称`} />
          </Form.Item>
        </Form>
      </Modal>

4.上级列表树节点渲染
注意:编辑限制除了自己以外其他分类可以选,自己不能选

 const renderAddTree = (data: any) =>
    data?.length > 0 && data.map((item: any) => {
    
    
      if (item?.children?.length > 0) {
    
    
        // 编辑限制除了自己以外其他分类可以选,自己不能选
        return (
          <TreeNode
            key={
    
    item.id}
            title={
    
    item.name}
            value={
    
    item.id}
            disabled={
    
    type === 'edit' && item.id === currentItem.id ? true : false}
          >
            {
    
    renderAddTree(item.children)}
          </TreeNode>
        );
      }
      return <TreeNode
        {
    
    ...item}
        key={
    
    item.id}
        title={
    
    item.name}
        value={
    
    item.id}
        disabled={
    
    type === 'edit' && item.id === currentItem.id ? true : false}
      />;
    });

5.添加编辑保存

 const handleOk = () => {
    
    
    form.submit();
  };
const handleFinish = async (values: {
     
      [name: string]: string }) => {
    
    
    setConfirmLoading(true);
    const params = {
    
    
     //参数
    }
    if (type === 'edit') {
    
    
      params.id = currentItem?.id;
    } else if (type === 'add') {
    
    
      params.parentId = currentItem?.id || "";
    }
    //请求接口
  };

4、节点可删除

在这里插入图片描述
在这里插入图片描述
1.在节点render加入删除

	 const menu = (item: any) => {
    
    
      return (
        <Menu>
          <Menu.Item key="1" onClick={
    
    () => onAdd(item, 'edit',)}>修改类别名</Menu.Item>
          <Menu.Item key="2" onClick={
    
    () => handleDelete(item.id)}>删除类别</Menu.Item>
        </Menu>
      )
    }

2.删除方法

  const handleDelete = (id: string) => {
    
    
    Modal.confirm({
    
    
      title: `确认删除${
      
      typeName}`,
      content: `确认删除该${
      
      typeName}?`,
      okText: '确认',
      okType: 'danger',
      cancelText: '取消',
      onOk() {
    
    
        //删除接口
      },
    });
  };

5.移入显示编辑图标

在这里插入图片描述

0.定义的keyeditVisiable

	const [key, setKey] = useState('');
    const [editVisiable, setEditVisible] = useState(false);

1.树组件添加移入移出属性

	onMouseEnter={
    
    onMouseEnter}
    onMouseLeave={
    
    onMouseLeave}

2.移入移出方法

const onMouseEnter = (e: any) => {
    
    
    const key = e?.node?.key;
    setEditVisible(true)
    setKey(key);
  };

  const onMouseLeave = (e: any) => {
    
    
    setEditVisible(false)
  };

3.渲染节点根据editVisiblekey判断是否显示

const renderTreeNodes = (data: any) => {
    
    
    const menu = (item: any) => {
    
    
      return (
        <Menu>
          <Menu.Item key="1" onClick={
    
    () => onAdd(item, 'edit',)}>修改类别名</Menu.Item>
          <Menu.Item key="2" onClick={
    
    () => handleDelete(item.id)}>删除类别</Menu.Item>
        </Menu>
      )
    }

    let nodeArr = data.map((item: any) => {
    
    
      const index = item && item.name.indexOf(searchValue);
      const beforeStr = item.name.substr(0, index);
      const afterStr = item.name.substr(index + searchValue.length);
      item.value = index > -1 ? (
        <span>
          {
    
    beforeStr}
          <span className={
    
    styles.site_tree_search_value}>{
    
    searchValue}</span>
          {
    
    afterStr}
          {
    
    
          //核心代码
            editVisiable && item.id === key && <span>
              
                 <Dropdown overlay={
    
    menu(item)} trigger={
    
    ['hover']}>
                  <EditOutlined style={
    
    {
    
     marginLeft: 10 }} />
                </Dropdown>          
                 <PlusCircleTwoTone twoToneColor="#ff571a" style={
    
    {
    
     marginLeft: 10 }} onClick={
    
    () => onAdd(item, 'add')} />
            </span>
          }
        </span>
      ) : (
        <div>
          <span>{
    
    item.name}</span>
          {
    
    
          //核心代码
            editVisiable && item.id === key && <span>           
                 <Dropdown overlay={
    
    menu(item)} trigger={
    
    ['hover']}>
                  <EditOutlined style={
    
    {
    
     marginLeft: 10 }} />
                </Dropdown>          
                 <PlusCircleTwoTone twoToneColor="#ff571a" style={
    
    {
    
     marginLeft: 10 }} onClick={
    
    () => onAdd(item, 'add')} />
            </span>
          }
        </div>
      );

      if (item.children) {
    
    
        return (
          <TreeNode title={
    
    item.value} key={
    
    item.id}>
            {
    
    renderTreeNodes(item.children)}
          </TreeNode>
        );
      }
      return <TreeNode title={
    
    item.value} key={
    
    item.id} />;
    });
    return nodeArr;
  };

6、完整代码

import React, {
    
     useEffect, useState } from 'react';
import {
    
     dispatch, getState } from '@@/store';
import {
    
     Input, Tree, Modal, Form, Menu, Dropdown, message, TreeSelect } from 'antd';
import styles from './index.less';
import {
    
    
  EditOutlined,
  PlusCircleTwoTone,
  MinusOutlined,
} from "@ant-design/icons";

const {
    
     Search } = Input;
const {
    
     TreeNode } = Tree;
type ITreeTypeProps = {
    
    
  typeName: string;
  changeKey: (visible: string) => void;
  onNode: (node: any) => void;
  onTree?: (tree: any) => void;
  treeType: number;
};

type TreeData = {
    
    
  title?: string,
  value?: number,
  key?: number,
  children?: TreeData[],
}

const treeList = [
  {
    
    
    title: 'parent 1',
    key: '0-0',
    children: [
      {
    
    
        title: 'parent 1-0',
        key: '0-0-0',
        children: [
          {
    
    
            title: 'leaf',
            key: '0-0-0-0',
          },
          {
    
    
            title: 'leaf',
            key: '0-0-0-1',
          },
          {
    
    
            title: 'leaf',
            key: '0-0-0-2',
          },
        ],
      },
      {
    
    
        title: 'parent 1-1',
        key: '0-0-1',
        children: [
          {
    
    
            title: 'leaf',
            key: '0-0-1-0',
          },
        ],
      },
    ]
  }
]

const TreeType: React.FC<ITreeTypeProps> = ({
     
     
  changeKey,
  typeName,
  treeType,
  onNode,
  onTree,
}) => {
    
    
  const [form] = Form.useForm();
  const [createVisible, setCreateVisible] = useState(false);
  const [confirmLoading, setConfirmLoading] = useState(false);
  const [name, setName] = useState('');
  const [upValue, setUpValue] = useState('');
  const [type, setType] = useState('add');
  const [expandedKeys, setExpandedKeys] = useState<any[]>([]);
  const [defaultExpandedKeys, setDefaultExpandedKeys] = useState<any[]>([]);
  const [selectdKeys, setSelectdKeys] = useState<any[]>([]);
  const [checkedKeys, setCheckedKeys] = useState<any[]>([]);
  const [autoExpandParent, setAutoExpandParent] = useState(true);
  const [searchValue, setSearchValue] = useState('')
  const [key, setKey] = useState('');
  const [editVisiable, setEditVisible] = useState(false);
  const [currentItem, setCurrentItem] = useState<any>({
    
    })
  const [treeData, setTreeData] = useState<TCategoryList[]>([]);
  const [treeTypeList, setTreeTypeList] = useState<TreeData[]>([]);

  useEffect(() => {
    
    
    getList()
  }, [])

  //  自定义规则数据
  const getFilter = (treeData: any[],) => {
    
    
    const data = treeData.filter(v => v.source === 1);
    const TreeData = handleData(data);
    onTree && onTree(TreeData);
    setTreeTypeList(TreeData);
  }

  // 递归修改data属性值,配合treeSelect规范数据
  const handleData = (data: TCategoryList[]) => {
    
    
    let item: TreeData[] = [];
    data.map((list: any, i: number) => {
    
    
      let newItem: any = {
    
    };
      newItem.key = list.id;
      newItem.value = list.id;
      newItem.title = list.name;
      newItem.children = list.children ? handleData(list.children) : []; // 如果还有子集,就再次调用自己
      // 合并新属性和原有属性
      item.push({
    
     ...list, ...newItem });
    });
    return item;
  };

  //  将树形节点改为一维数组
  const generateList = (data: any, dataList: any[]) => {
    
    
    for (let i = 0; i < data.length; i++) {
    
    
      const node = data[i];
      const {
    
     name, id, parentId, level } = node;
      dataList.push({
    
     name, id, key: id, title: name, parentId, level });
      if (node.children) {
    
    
        generateList(node.children, dataList);
      }
    }
    return dataList
  }

  // 获取树形节点数据
  const getList = async (params?: TCategoryParams) => {
    
    
    const res = await CATEGORY.categoryList(params);
    setTreeData(res || []);
    getFilter(res);
    if (res) {
    
    
      let list: any[] = generateList(res, [])
      let expendList: any[] = [];
      list?.map((v: any) => {
    
    
        expendList.push(v.id);
        if (v.children) {
    
    
          v?.children?.map((item: any) => {
    
    
            expendList.push(item.id);
          })
        }
      })
      //默认展开所有
      setExpandedKeys(expendList || []);
      setDefaultExpandedKeys(expendList || []);
    }
  }
  // 搜索节点
  const onChange = (e: any) => {
    
    
    let {
    
     value } = e.target
    if (!value) {
    
    
      setExpandedKeys(defaultExpandedKeys);
      setSearchValue(value)

      return
    }
    value = String(value).trim()
    const dataList: any[] = generateList(treeData, [])
    let expandedKeys: any = dataList
      .map((item: any) => {
    
    
        if (item && item.name.indexOf(value) > -1) {
    
    
          
          return getParentKey(item.key, treeData)
        }
        return null;
      })
      .filter((item: any, i: number, self: any) => item && self.indexOf(item) === i)

    setExpandedKeys(expandedKeys)
    setAutoExpandParent(true)
    setSearchValue(value)
  }

  // tree树形匹配方法
  const getParentKey = (key: number | string, tree: any): any => {
    
    
    let parentKey
    for (let i = 0; i < tree.length; i++) {
    
    
      const node = tree[i];
      if (node.children) {
    
    
        if (node.children.some((item: any) => item.id === key)) {
    
    
          parentKey = node.id;
        } else if (getParentKey(key, node.children)) {
    
    
          parentKey = getParentKey(key, node.children);
        }
      }
    }
    // console.log(key, parentKey, tree,)
    return parentKey;
  }

  // 树节点展开/收缩
  const onExpand = (expandedKeys: any) => {
    
    
    setExpandedKeys(expandedKeys)
    setAutoExpandParent(false)
  }

  // 选择节点
  const checkDep = (val: any, data: any) => {
    
    
    if (data && data.checkedNodes && data.checkedNodes.length) {
    
    
      let checkedNodes = [...data.checkedNodes]

      setSelectdKeys(checkedNodes)
      setCheckedKeys(
        checkedNodes.map((subItem: any) => {
    
    
          return subItem.key
        }),
      )
    } else {
    
    
      setSelectdKeys([])
      setCheckedKeys([])
    }
  }

  //选中节点时触发
  const onSelect = (selectedKeys: any, info: any) => {
    
    
    const key = info?.node?.key;
    onCurrent(key)
  }

  //获取当前节点数据
  const onCurrent = (key: any) => {
    
    
    const treeList = generateList(treeData, []);
    const node = treeList.find(v => v.id === key);
    setCurrentItem(node);
    onNode(node);
    changeKey(key);
  }

  const onAdd = (item: any, type: string) => {
    
    
    setType(type);
    setName(item.name);
    setKey(item.key);
    setCurrentItem(item);
    if (type === 'edit') {
    
    
      form.setFieldsValue({
    
    
        name: item?.name,
        parentId: item?.parentId,
      })
    } else if (type === 'add') {
    
    
      form.setFieldsValue({
    
    
        parentId: item?.id,
      })
    }
    setCreateVisible(true);

  };

  const onMouseEnter = (e: any) => {
    
    
    const key = e?.node?.key;
    setEditVisible(true)
    setKey(key);
  };

  const onMouseLeave = (e: any) => {
    
    
    setEditVisible(false)
  };

  const renderTreeNodes = (data: any) => {
    
    
    const menu = (item: any) => {
    
    
      return (
        <Menu>
          <Menu.Item key="1" onClick={
    
    () => onAdd(item, 'edit',)}>修改类别名</Menu.Item>
          <Menu.Item key="2" onClick={
    
    () => handleDelete(item.id)}>删除类别</Menu.Item>
        </Menu>
      )
    }

    let nodeArr = data.map((item: any) => {
    
    
      const index = item && item.name.indexOf(searchValue);
      const beforeStr = item.name.substr(0, index);
      const afterStr = item.name.substr(index + searchValue.length);
      item.value = index > -1 ? (
        <span>
          {
    
    beforeStr}
          <span className={
    
    styles.site_tree_search_value}>{
    
    searchValue}</span>
          {
    
    afterStr}
          {
    
    
          //核心代码
            editVisiable && item.id === key && <span>
              
                 <Dropdown overlay={
    
    menu(item)} trigger={
    
    ['hover']}>
                  <EditOutlined style={
    
    {
    
     marginLeft: 10 }} />
                </Dropdown>          
                 <PlusCircleTwoTone twoToneColor="#ff571a" style={
    
    {
    
     marginLeft: 10 }} onClick={
    
    () => onAdd(item, 'add')} />
            </span>
          }
        </span>
      ) : (
        <div>
          <span>{
    
    item.name}</span>
          {
    
    
          //核心代码
            editVisiable && item.id === key && <span>           
                 <Dropdown overlay={
    
    menu(item)} trigger={
    
    ['hover']}>
                  <EditOutlined style={
    
    {
    
     marginLeft: 10 }} />
                </Dropdown>          
                 <PlusCircleTwoTone twoToneColor="#ff571a" style={
    
    {
    
     marginLeft: 10 }} onClick={
    
    () => onAdd(item, 'add')} />
            </span>
          }
        </div>
      );

      if (item.children) {
    
    
        return (
          <TreeNode title={
    
    item.value} key={
    
    item.id}>
            {
    
    renderTreeNodes(item.children)}
          </TreeNode>
        );
      }
      return <TreeNode title={
    
    item.value} key={
    
    item.id} />;
    });
    return nodeArr;
  };

  const handleFinish = async (values: {
     
      [name: string]: string }) => {
    
    
    setConfirmLoading(true);
    const params = {
    
    
     
    }
    if (type === 'edit') {
    
    
      params.id = currentItem?.id;
      // params.parentId = currentItem?.parentId;
    } else if (type === 'add') {
    
    
        params.parentId = currentItem?.id || "";
    }
    addOrEditCategory(params);
  };

  // 新增/编辑
  const addOrEditCategory = async (params: TCategoryListAdd) => {
    
    
   
  };

  // 删除
  const onDelete = async (id: string) => {
    
    

  };

  const handleOk = () => {
    
    
    form.submit();
  };

  const handleDelete = (id: string) => {
    
    
    Modal.confirm({
    
    
      title: `确认删除${
      
      typeName}类别`,
      content: `确认删除该${
      
      typeName}类别?`,
      okText: '确认',
      okType: 'danger',
      cancelText: '取消',
      onOk() {
    
    
        onDelete(id);
      },
    });
  };

  const onUpChange = (value: any, label: any,) => {
    
    
    setUpValue(value);
  };

  const renderAddTree = (data: any) =>
    data?.length > 0 && data.map((item: any) => {
    
    
      if (item?.children?.length > 0) {
    
    
        // 编辑限制除了自己以外其他分类可以选,自己不能选
        return (
          <TreeNode
            key={
    
    item.id}
            title={
    
    item.name}
            value={
    
    item.id}
            disabled={
    
    type === 'edit' && item.id === currentItem.id ? true : false}
          >
            {
    
    renderAddTree(item.children)}
          </TreeNode>
        );
      }
      return <TreeNode
        {
    
    ...item}
        key={
    
    item.id}
        title={
    
    item.name}
        value={
    
    item.id}
        disabled={
    
    type === 'edit' && item.id === currentItem.id ? true : false}
      />;
    });

  return (
    <div className={
    
    styles.detail__container}>
      <Search style={
    
    {
    
     marginBottom: 8 }} placeholder={
    
    `搜索${
      
      typeName}类别`} onChange={
    
    onChange} />
      {
    
    
        treeData?.length > 0 && <Tree
          onExpand={
    
    onExpand}
          autoExpandParent={
    
    autoExpandParent}
          defaultExpandAll
          onCheck={
    
    checkDep}
          checkedKeys={
    
    checkedKeys}
          checkStrictly
          onSelect={
    
    onSelect}
          onMouseEnter={
    
    onMouseEnter}
          onMouseLeave={
    
    onMouseLeave}
          expandedKeys={
    
    expandedKeys}
        >
          {
    
    renderTreeNodes(treeData)}
        </Tree>
      }
      <Modal
        destroyOnClose
        title={
    
    type === 'add' ? `新建${
      
      typeName}类别` : `修改${
      
      typeName}类别名`}
        visible={
    
    createVisible}
        onOk={
    
    handleOk}
        confirmLoading={
    
    confirmLoading}
        onCancel={
    
    () => {
    
    
          setCreateVisible(false)
          form.resetFields();
          setCurrentItem({
    
    });
          setUpValue('');
        }}
      >
        <Form
          name="createForm"
          form={
    
    form}
          labelCol={
    
    {
    
     span: 7 }}
          wrapperCol={
    
    {
    
     span: 17 }}
          onFinish={
    
    handleFinish}
        >
          {
    
    
            <Form.Item
              label="上级类别"
              name="parentId"
              rules={
    
    [
                {
    
    
                  required: true,
                  message: '请选择上级类别',
                },
              ]}
            >
              <TreeSelect
                showSearch
                style={
    
    {
    
     width: '100%' }}
                value={
    
    upValue || currentItem?.parentId}
                dropdownStyle={
    
    {
    
     maxHeight: 400, overflow: 'auto' }}
                placeholder="请选择上级类别"
                allowClear
                treeDefaultExpandAll
                onChange={
    
    (value, label,) => onUpChange(value, label,)} 
              >
                {
    
    renderAddTree(treeTypeList || [])}
              </TreeSelect>

            </Form.Item>

          }
          <Form.Item
            label={
    
    `${
      
      typeName}名称`}
            name="name"
            rules={
    
    [
              {
    
    
                required: true,
                message: `请输入${
      
      typeName}名称`,
              },
            ]}
          >
            <Input placeholder={
    
    `请输入${
      
      typeName}名称`} />
          </Form.Item>
        </Form>
      </Modal>
    </div>
  );
};

export default TreeType;

猜你喜欢

转载自blog.csdn.net/qq_40657321/article/details/119328338