树形结构-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…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...
【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...
电脑桌面太单调,用Python写一个桌面小宠物应用。
下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡,可以响应鼠标点击,并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...
拟合问题处理
在机器学习中,核心任务通常围绕模型训练和性能提升展开,但你提到的 “优化训练数据解决过拟合” 和 “提升泛化性能解决欠拟合” 需要结合更准确的概念进行梳理。以下是对机器学习核心任务的系统复习和修正: 一、机器学习的核心任务框架 机…...
手动给中文分词和 直接用神经网络RNN做有什么区别
手动分词和基于神经网络(如 RNN)的自动分词在原理、实现方式和效果上有显著差异,以下是核心对比: 1. 实现原理对比 对比维度手动分词(规则 / 词典驱动)神经网络 RNN 分词(数据驱动)…...
基于Python的气象数据分析及可视化研究
目录 一.🦁前言二.🦁开源代码与组件使用情况说明三.🦁核心功能1. ✅算法设计2. ✅PyEcharts库3. ✅Flask框架4. ✅爬虫5. ✅部署项目 四.🦁演示效果1. 管理员模块1.1 用户管理 2. 用户模块2.1 登录系统2.2 查看实时数据2.3 查看天…...
