树形结构-CRUD接口
先看一下效果:整体的效果
新增效果 --默认值是 default
修改效果 -
大致效果如上
---------------------------------------------------------------------------------------------------------------------------------
下面讲解代码如何实现的
根据你使用的UI的框架中的树结构---形成相应的数据结构(递归形式)-如果后端给你分好了(感谢他)
这个是给我的是一个 数组包裹的对象形式 进行递归
这个我写在--一个通用的 js 导出形式 这边我需要是的是两种类型 所以分了一下(效果图上的是第一个)
解释一下:data:后端给你的数据
parentId是 从0 或者 -1 开始 看你的需求 我这边是 -1show:我这是区分我要的是那种类型
递归形式走的
export function buildTree(data, parentId, show) {const result = [];data?.filter(item => item.parentId === parentId).forEach(items => {const children = buildTree(data, items.id, show);let node = ''if (!show) {node = {value: `${items.categoryName}`,key: `${items.id}`,defaultValue: `${items.categoryName}`,isEditable: false,parentId: `${items.parentId}`,children: children.length ? children : undefined,};} else {node = {value: `${items.id}`,title: `${items.categoryName}`,children: children.length ? children : undefined,};}result.push(node);});return result;
}
这边都是实现的代码了-------可以详细看下 ---谢谢 -如果不懂-请评论
import { DownOutlined, EditOutlined, PlusOutlined, MinusOutlined, CloseOutlined, CheckOutlined } from '@ant-design/icons';
import { Input, Tree, message } from 'antd';
import React, { useEffect, useState } from 'react';
import moment from 'moment';
import { GetclubGoodsCategoryList, PostclubGoodsCategoryRemove, PostclubGoodsCategorySave, PostclubGoodsCategoryUpdate } from '@/services/commodity';
import { buildTree } from '@/utils/utils';const { TreeNode } = Tree;
// 三张图
import reduce from '@/assets/icon/reduce.png';
import addIng from '@/assets/icon/addIng.png';
import editIng from '@/assets/icon/editIng.png';
function TreeData({ onNodeClick }) {// 佛祖保佑,不会报错const [selectedNode, setSelectedNode] = useState(null);// const treeData = buildTree(data1, 0);const expandedKeyArr = ["0"];const [data, setData] = useState();const [listObj, setListObj] = useState({});let isMounted = true;const getDate = async () => {try {
//获取最初的数据 ------------接口let res = await GetclubGoodsCategoryList();if (isMounted && res && res.code == "200") {const treeData = buildTree(res.data, 0);setData(treeData);}} catch (error) {console.error("Error fetching data: ", error);}};useEffect(() => {getDate();return () => {isMounted = false;};}, []);const [expandedKeys, setExpandedKeys] = useState(expandedKeyArr);// 修改---树结构 有值---接口const onChangeUpdate = async () => {if (Object.keys(listObj).length > 0) {let res = await PostclubGoodsCategoryUpdate({categoryName: listObj.value,// parentId: listObj.key,id: listObj.key,});if (res && res.code == "200") {message.success("修改成功");
//重新获取树形结构getDate();}}}const onExpand = (expandedKeys) => {setExpandedKeys(expandedKeys);};const handleNodeClick = (node) => {setSelectedNode(node);// 进行暴露---作为一个组件调用你所点击的值对象onNodeClick(node);};const renderTreeNodes = (data, depth = 0) => {return data?.map((item) => {const title = item.isEditable ? (<div style={{display: 'flex',justifyContent: 'space-between',alignItems: 'center',}}>{/* 输入框显示 和 一个对号 一个 叉号*/}<Input placeholder="输入名称" defaultValue={item.defaultValue}onChange={(e) => onChange(e, item)} /><CheckOutlined style={{margin: '0 4px',}} onClick={() => onSave(item)} /><CloseOutlined onClick={() => onClose(item.parentKey, item.defaultValue)} /></div>) : (<div onClick={() => handleNodeClick(item)}style={{display: 'flex',justifyContent: 'space-between',alignItems: 'center',}}><divstyle={{whiteSpace: 'nowrap'}}>{item.value}</div><divstyle={{display: 'flex',flexWrap: 'nowrap',alignItems: 'center',}}>{/* <EditOutlined onClick={() => onEdit(item.key)} /><PlusOutlined onClick={() => onAdd(item.key)} />{item.parentKey !== "0" && (<MinusOutlined onClick={() => onDelete(item.key)} />)} */}{/* 两层之上就没有图标l 效果上的左边字 右边图片 */}{item.value &&<><img style={{ margin: '0 4px' }} width='15px' onClick={() => onEdit(item.key)} height='15px' src={editIng} alt="" />{depth < 2 && <img width='15px' onClick={() => onAdd(item.key)} height='15px' src={addIng} alt="" />}<img style={{ margin: '0 4px' }} onClick={() => onDelete(item.key)} width='15px' height='15px' src={reduce} alt="" /></>}</div></div>);if (item.children) {return (<TreeNode title={title} key={item.key}>{renderTreeNodes(item.children, depth + 1)}</TreeNode>);}return <TreeNode title={title} key={item.key} />;});};const onAdd = (key) => {if (expandedKeys.indexOf(key) === -1) {expandedKeys.push(key);}setExpandedKeys(expandedKeys.slice());addNode(key, data);setData([...data]);};const onEdit = (key) => {editNode(key, data);setData([...data]);};const editNode = (key, data) =>data.forEach((item) => {if (item.key === key) {item.isEditable = true;} else {item.isEditable = false;}item.value = item.defaultValue;if (item.children) {editNode(key, item.children);}});const getRandomNumber = (min = 1, max = 10000) => {return Math.floor(Math.random() * (max - min + 1)) + min;};const addNode = (key, data) =>data.forEach((item) => {if (item.key === key) {if (item.children) {item.children.push({value: "default",key: getRandomNumber(),parentKey: key,isEditable: false,showAdd: true});} else {item.children = [{value: "default",key: getRandomNumber(),parentKey: key,isEditable: false,showAdd: true},];}return;}if (item.children) {addNode(key, item.children);}});const onChange = (e, key) => {changeNode(key.parentKey ? key : key, e.target.value, data);setData([...data]);};const changeNode = (key, value, data) =>data.forEach((item) => {if (item.parentKey || item.key == key.key) {item.value = value;}if (item.children) {changeNode(key, value, item.children);}});// 保存---数据新增---接口const onSaveObj = async () => {let res = await PostclubGoodsCategorySave({categoryName: listObj.value,parentId: listObj.parentKey,})if (res && res.code === 200) {message.success('新增成功')getDate();} else {message.error('新增失败')}};useEffect(() => {if (listObj.showAdd) {onSaveObj();} else {onChangeUpdate()}}, [listObj])const onSave = (key) => {if (key.value == undefined) {message.error('请输入分类名称')return}setListObj(key)saveNode(key, data);setData([...data]);};const saveNode = (key, data) =>data.forEach((item) => {if (item.parentKey === key) {item.defaultValue = item.value;}if (item.children) {saveNode(key, item.children);}item.isEditable = false;});const onClose = (key, defaultValue) => {closeNode(key, defaultValue, data);setData([...data]);};const closeNode = (key, defaultValue, data) =>data.forEach((item, index) => {item.isEditable = false;if (item.parentKey === key) {data.splice(index, 1);item.value = defaultValue;}if (item.children) {closeNode(key, defaultValue, item.children);}});const onDelete = (key) => {deleteNode(key, data);setData([...data]);};//删除节点---接口const deleteIds = async (key) => {let data = await PostclubGoodsCategoryRemove({ids: key,})if (data && data.code === 200) {message.success('删除成功')getDate();}}const deleteNode = (key, data) =>data.forEach((item, index) => {if (item.key === key) {if (!item.showAdd) {deleteIds(key);}data.splice(index, 1);return;} else {if (item.children) {deleteNode(key, item.children);}}});return (<div style={{position: 'relative',left: '-14px'}}><Tree onExpand={onExpand} expandedKeys={expandedKeys}>{renderTreeNodes(data)}</Tree></div>);
}export default TreeData;
相关文章:

树形结构-CRUD接口
先看一下效果:整体的效果 新增效果 --默认值是 default 修改效果 - 大致效果如上 --------------------------------------------------------------------------------------------------------------------------------- 下面讲解代码如何实现的 根据你使用…...

【Qt知识】Qt窗口坐标系
Qt的窗口坐标体系遵循标准的计算机图形坐标系统规则 Qt窗口坐标体系特点 坐标原点:窗口坐标体系的原点位于窗口的左上角,即坐标(0, 0)位置。 轴方向: X轴:向右为正方向,随着X坐标值的增加,元素在窗口中从…...

SAP Build引言
前言 SAP Build 似乎是一个整合了很多低代码或无代码产品的平台,最早的时候应该都是各自分开的几个产品,近年合并到一块上了SAP Build平台 现在看官网的介绍应该是有三四个产品被集成进来了,分别是SAP IRPA,SAP Workflow…...

2024上海国际钢丝绳及吊索具展览会
2024上海国际钢丝绳及吊索具展览会 2024 Shanghai International Wire Rope and Hanger Exhibition 时间:2024年12月18日--20日 地点:上海新国际博览中心 详询主办方陆先生 I38(前三位) I82I(中间四位ÿ…...

记一次mysql索引优化
生产日志告警出现一条慢 sql 告警, 通过 sql 监控平台拿到 这条sql 语句是 : SELECTid,report_id,report_detail_id,item_code,report_type,photo FROM**** 表 WHEREdel_flag 0 AND (report_type 1 AND report_detail_id IN ( 1742 )) 之后用 explain 分析这条 sql 的命中…...

【Javascript系列】Terser通过调用API来实现代码的压缩和优化功能
Terser通过调用API来实现代码的压缩和优化功能 起源通过API来调用API调用过程中的一个隐含的技术点 - 异步调用和Promise对象官方文档中的一个有点容易忽略和混淆的地方关于Promise 起源 书接 上回,对Terser的功能做了一个初步的探索。在官方的主页上,有…...

嵌入式期末复习
一、选择题(20) 二、判断题(10) 三、填空题(10) 主机-目标机的文件传输方式主要有串口传输方式、网络传输方式、USB接口传输方式、JTAG接口传输方式、移动存储设备方式。常用的远程调试技术主要有 插桩/st…...

生信算法7 - 核酸序列Fasta和蛋白PDB文件读写与检索
python 3.9实现以下算法。 1. 简单的写文件和读文件 # 写 file1 open(count.txt,w) file1.write(this is a test) file1.close()# 读 file2 open(my_file) print(file2.read())2. 将列表内容写入文本文件 # 生成100-500数字列表 data [i * 100 for i in range(1, 6)] pri…...

【Python】Python异步编程
Python 异步编程 异步编程 异步编程是一种编程范式,通过非阻塞的方式执行任务,允许程序在等待某些操作(如I/O操作、网络请求、数据库查询等)完成时,继续执行其他任务。这与同步编程(或阻塞编程)…...

pytorch笔记:自动混合精度(AMP)
1 理论部分 1.1 FP16 VS FP32 FP32具有八个指数位和23个小数位,而FP16具有五个指数位和十个小数位Tensor内核支持混合精度数学,即输入为半精度(FP16),输出为全精度(FP32) 1.1.1 使用FP16的优缺…...

R语言ggplot2包绘制世界地图
数据和代码获取:请查看主页个人信息!!! 1. 数据读取与处理 首先,从CSV文件中读取数据,并计算各国每日收入的平均签证成本。 library(tidyverse) df <- read_csv("df.csv") %>% group_…...

【Linux】Linux的权限_1
文章目录 三、权限1. shell外壳2. Linux的用户3. Linux权限管理文件访问者的分类文件类型和访问权限 未完待续 三、权限 1. shell外壳 为什么要使用shell外壳 由于用户不擅长直接与操作系统直接接触和操作系统的易用程度、安全性考虑,用户不能直接访问操作系统。 什…...

日语_远程办公常用日语单词
基本词汇 リモートワーク(Rimōto Wāku):远程工作テレワーク(Terewāku):远程工作(Telework)在宅勤務(ざいたくきんむ,Zaitaku Kinmu)ÿ…...

MTK 平台项目security boot 开启/关闭 及 系统签名流程
以 https://online.mediatek.com/FAQ#/SW/FAQ26691 为基础做如下记录以做备忘: How to Enable/Disable Secure Boot for Security 3.0: 1、 How to Enable Path Enable Preloader /vendor/mediatek/proprietary/bootable/bootloader/preloader/custom/{…...

JDBC连接MySQL
目录 1.数据库编程的必备条件 2.Java的数据库编程JDBC 3.JDBC的工作原理 4.第三方库connector的下载和导包 5.JDBC的使用 使用步骤 (1)创建数据源对象DataSource (2)给对象设置必要的属性 (3)和数据…...

【Qt】【模型视图架构】 在项目视图中启用拖放
文章目录 1. 在便捷类中启用拖放2. 在模型/视图类中启用拖放 模型/视图框架支持Qt的拖放应用。 列表、表格和树中的项目可以在视图中被拖拽,数据作为MIME编码的数据被导入和导出。标准视图可以自动支持内部的拖放。 默认视图的拖放功能并没有被启用,如果…...

B端产品无爆款,说有的都是忽悠和外行!
前言:网上经常有人讲运营,把C端那一套硬搬到B端,讲的自我陶醉,稍微有点常识的人就知道不能这么玩。 一、什么是B端和C端 B端(Business-to-Business)是指面向企业客户的市场和产品。B端产品或服务主要是为…...

腾讯云的身份证核验,找不到这个类
文件上传功能在许多Web应用程序中是非常常见的需求之一。然而,由于文件上传存在安全风险,保护用户上传的文件的安全性,以及防止黑客利用上传功能进行攻击是非常重要的。在本文中,我们将讨论一些常见的安全漏洞,并提供一…...

vue3 vue-draggable-next 实现拖拽穿梭框效果
一、vue3 vue-draggable-next 实现拖拽穿梭框效果 <template> <div> <h2>列表 1</h2> <draggable v-model"list1" group"items" tag"transition-group" end"onDragEnd"> <div v-for"(item…...

FreeRTOS【16】直达任务通知使用
1.开发背景 直达任务通知,FreeRTOS 的线程任务提供的接口,可以用作线程唤醒,或者是传递数据,因为是基于线程本身的操作,是轻量级,速度响应更快,适合小内存芯片使用。 事实上本人使用得比较少&am…...

关于软件<PDF文档管理系统V1.0>的介绍
<PDF文档管理系统V1.0>(下载地址在最下面)是我在2023年发布的<知识辅助系统>的改善以及重新开发版本,软件在重新开发提供了<知识辅助系统>的所有功能的基础上,添加了一些新的功能。软件尽量提供简单、实用的功能…...

Java面试题-Tomcat初级面试题
Tomcat是什么?请简述它的主要功能。 Tomcat是一个开源的Web应用服务器,由Apache软件基金会开发。它是一个实现了Java Servlet和JavaServer Pages(JSP)技术的容器,用于处理客户端的请求并返回响应。Tomcat的主要功能如…...

红队内网攻防渗透:内网渗透之windows内网权限提升技术:数据库篇
红队内网攻防渗透 1. 内网权限提升技术1.1 数据库权限提升技术1.1.1 数据库提权流程1.1.1.1 先获取到数据库用户密码1.1.1.2 利用数据库提权工具进行连接1.1.1.3 利用建立代理解决不支持外联1.1.1.4 利用数据库提权的条件及技术1.1.2 Web到Win-数据库提权-MSSQL1.1.3 Web到Win-…...

rust嵌入式开发之总结
我们用rust开发的新版产品刚刚交付,已经在海上安装测试完毕并顺利投产。终于松了口气,同时也有时间和精力来做个全面的总结了。 这个产品,目前差不多有三版: 第一个版本是用crt-thread写的,投产后出了一个内存泄露的…...

【制作100个unity游戏之27】使用unity复刻经典游戏《植物大战僵尸》,制作属于自己的植物大战僵尸随机版和杂交版6(附带项目源码)
最终效果 系列导航 文章目录 最终效果系列导航前言方法一、使用excel配置表excel转txt文本读取txt数据按配置信息生成僵尸 方法二、使用ScriptableObject 配置关卡信息源码结束语 前言 本节主要是推荐两种实现配置关卡信息,并按表生成僵尸和关卡波次 方法一、使用…...

回溯算法指组合总和
题目: 找出所有相加之和为 n 的 k 个数的组合,且满足下列条件: 只使用数字1到9每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。 思路: 这种问题…...

java-stream转换map key重复报错解决小记
解决key重复问题 在用stream转成map过程中会有key重复的隐患,如果数据没重复还好,如果重复了会提示 java.lang.IllegalStateException: Duplicate key 8753444332651at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)at ja…...

王春城 | 如何解决精益转型过程中的信任问题?
实践证明,精益转型不仅仅是技术和管理方法的更新,更是一场深刻的文化变革。在这个过程中,涉及到多个部门、多个层级的协同合作,需要团队成员之间的深度沟通和高度信任。如果缺乏信任,团队成员之间就会产生隔阂和抵触情…...

Ubuntu Nvidia Docker单机多卡环境配置
ubuntu版本是22.04,现在最新版本是24.xx,截止当前,Nvidia的驱动最高还是22.04版本,不建议更新至最新版本。本部分是从0开始安装Nvidia docker的记录,若已安装Nvdia驱动,请直接跳至3。 1、更新软件软件列表…...

小公司的软件开发IT工具箱
目录 工具链困境 难题的解决 达到的效果 资源要求低 工具箱一览 1、代码管理工具 2、自动化发版(测试)工具 3、依赖库(制品包)管理 4、镜像管理 5、授权管理(可选) 待讨论:为什么不是…...