谷粒商城实战笔记-55-商品服务-API-三级分类-修改-拖拽数据收集
文章目录
- 一,拖拽后结点的parentCid的更新
- 二,拖拽后结点的父节点下所有结点的sort排序属性的变化
- 更新排序的逻辑
- 代码分析
- 三,拖拽后结点及其子节点catLevel的变化
- 判断是否需要更新 `catLevel`
- 获取拖动后的新节点
- 更新 `catLevel`
- 完整代码
这一节的主要内容是收集拖拽后的要更新的节点的数据,逻辑比较复杂。
- 1,拖拽后结点的parentCid的更新;
- 2,拖拽后结点的父节点下所有结点的sort排序属性的变化;
- 3,拖拽后结点及其子节点catLevel的变化;
所有这些数据都用收集到,然后发送给后台更新。
拖拽结束后,触发拖拽结束事件,所以要在el-tree上绑定这个事件。

事件函数nodeDrop定义如下。

然后定义一个全局数组,用来收集需要更新的节点数据。

一,拖拽后结点的parentCid的更新
var draggingNodeNewPId = 0;// 1,更新draggingNode的parentCid,根据dropPosition的不同值,分为两种情况if (dropPosition === "before" || dropPosition === "after") {draggingNodeNewPId = dropNode.data.parentCid;} else {draggingNodeNewPId = dropNode.data.cid;}
这段代码是在处理 el-tree 组件中拖拽结束后的逻辑,特别是更新被拖动节点的 parentCid 字段,以反映新的父节点关系。parentCid 假设是数据库中用来标识父节点的一个字段,通常在树形结构的数据模型中使用。
代码中的逻辑分为两种情况:
-
当拖动节点放置在目标节点之前 (
prev) 或之后 (next):if (dropPosition === "prev" || dropPosition === "next") {draggingNode.parentCid = dropNode.data.parentCid; }在这种情况下,拖动的节点将变为与目标节点同级,但它们共同的父节点会成为新的父节点。因此,
draggingNode的parentCid被设置为dropNode.data.parentCid,即目标节点的父节点ID。这种写法还兼容了没有父节点的情况,没有父节点时,parentCid为0。 -
当拖动节点放置在目标节点内部 (
inner):else if (dropPosition === "inner") {draggingNode.parentCid = dropNode.data.cid; }如果拖动的节点被放置在目标节点内部,那么它将成为目标节点的子节点。因此,
draggingNode的parentCid被设置为dropNode.data.cid,即目标节点自身的ID。
这段代码确保了在拖拽结束后,树形结构在逻辑上保持一致,parentCid 的更新反映了新的父子关系。这在维护树形数据结构的完整性方面非常重要,特别是在需要同步这些变化到后端数据库的场景下。
二,拖拽后结点的父节点下所有结点的sort排序属性的变化
// 2,更新draggingNode及其子节点的sort// 2.1如果draggingNode的parentCid没有更新,只需要重排draggingNode的兄弟结点的sort;// 2.2如果draggingNode的parentCid有更新,不仅需要重排draggingNode的原来的兄弟结点的sort,还需要重排draggingNode新的兄弟结点的sortvar siblingNodesOld = [];var siblingNodesNew = [];// draggingNode.parent为空,所以要根据parentCid找到其parent。// 写一个根据cid从menus中查询结点的函数let draggingNodeOldParentNode = this.getNodeByCid(draggingNode.data.parentCid, this.getLevel1Nodes(dropNode));console.log("draggingNodeOldParentNode:", draggingNodeOldParentNode);siblingNodesOld = draggingNodeOldParentNode.childNodes;;console.log("siblingNodesOld:", siblingNodesOld);if (draggingNode.data.parentCid !== draggingNodeNewPId) {if (dropPosition === "before" || dropPosition === "after") {siblingNodesNew = dropNode.parent.childNodes;} else {siblingNodesNew = dropNode.childNodes;}}for (var i = 0; i < siblingNodesOld.length; i++) {this.nodesInfoAfterDrop.push({catId: siblingNodesOld[i].data.catId, sort: i});}console.log("update sortu0....", siblingNodesNew, siblingNodesOld, dropNode, dropPosition);for (var i = 0; i < siblingNodesNew.length; i++) {this.nodesInfoAfterDrop.push({catId: siblingNodesNew[i].data.catId, sort: i});}console.log("update sort....", siblingNodesNew, siblingNodesOld, dropNode, dropPosition);
这段代码涉及到了在 el-tree 拖拽操作后更新节点排序(sort 属性)的逻辑,以便反映节点在树结构中的新位置。这里主要关注两个方面:更新拖动节点 draggingNode 及其子节点的排序,以及根据 draggingNode 的父节点是否改变来决定哪些节点的排序需要被更新。
更新排序的逻辑
-
确定旧的和新的兄弟节点集合:
siblingNodesOld是拖动前draggingNode的兄弟节点集合,即它原本的同级节点。siblingNodesNew是拖动后draggingNode的兄弟节点集合,这取决于拖动的目标位置(放置在目标节点之前、之后还是内部)。
-
判断是否需要更新新的兄弟节点集合:
- 如果
draggingNode的父节点ID(parentCid)没有改变,意味着拖动只改变了顺序而没有改变层级,此时只需要更新旧的兄弟节点集合的排序。 - 如果
draggingNode的父节点ID改变了,意味着节点的层级发生了变化,此时需要更新旧的和新的兄弟节点集合的排序。
- 如果
-
更新兄弟节点的排序:
- 遍历
siblingNodesOld和siblingNodesNew集合,将每个节点的sort属性设置为其在集合中的索引。这是因为索引反映了节点在数组中的位置,可以作为排序的依据。
- 遍历
代码分析
-
在
siblingNodesNew的赋值中,对于放置在目标节点之前或之后的情况,代码似乎直接将dropNode.data.parentCid赋值给了siblingNodesNew,但实际上dropNode.data.parentCid不应直接作为节点集合,这看起来像是一个错误或代码片段的不完整展示。正确的做法应该是获取dropNode的父节点的子节点集合。 -
对于放置在目标节点内部的情况,代码正确地从
dropNode的父节点获取了子节点集合。
三,拖拽后结点及其子节点catLevel的变化
// 3,更新draggingNode及其子节点的catLevelvar catLevelNeedUpdate = true;if (draggingNode.data.catLevel === dropNode.data.catLevel && (dropPosition === "before" || dropPosition === "after")) {catLevelNeedUpdate = false;}var draggingNodeAfterDrop = {};if (catLevelNeedUpdate) {var draggingParentNodeAfterDrop = {};if (dropPosition === "before" || dropPosition === "after") {draggingParentNodeAfterDrop = dropNode.parent;} else {draggingParentNodeAfterDrop = dropNode;}draggingParentNodeAfterDrop.childNodes.forEach((child) => {if (child.cid === draggingNode.data.cid) {draggingNodeAfterDrop = child;}})// 递归变量draggingNodeAfterDrop及其childNodes,将其data属性的cateLevel置为level属性值this.updateCatLevel(draggingNodeAfterDrop);}
updateCatLevel的定义如下:
// 递归更新draggingNode及其子节点的catLevel
updateCatLevel(node) {node.catLevel = node.level;if (node.childNodes && node.childNodes.length > 0) {node.childNodes.forEach((child) => {this.updateCatLevel(child);});}
},
这段代码的主要作用是,在 el-tree 组件的拖拽操作完成后,更新拖动节点 draggingNode 及其所有子节点的 catLevel 属性,以反映新的层级关系。catLevel 通常用于表示节点在树结构中的层级深度,这对于保持树结构的一致性和完整性是非常重要的。
判断是否需要更新 catLevel
首先,代码检查是否需要更新 catLevel:
var catLevelNeedUpdate = true;
if (draggingNode.data.catLevel === dropNode.data.catLevel && (dropPosition === "prev" || dropPosition === "next")) {catLevelNeedUpdate = false;
}
如果拖动节点和目标节点的层级相同,并且拖动位置是目标节点的前后,那么 catLevel 不需要更新,因为拖动操作不会改变节点的层级深度。
获取拖动后的新节点
接下来,代码尝试获取拖动操作完成后的拖动节点 draggingNodeAfterDrop,这通常是通过查找父节点的子节点列表来完成的:
var draggingNodeAfterDrop = {};
if (catLevelNeedUpdate) {var draggingParentNodeAfterDrop = {};if (dropPosition === "prev" || dropPosition === "next") {draggingParentNodeAfterDrop = dropNode.parent;} else {draggingParentNodeAfterDrop = dropNode;}draggingParentNodeAfterDrop.childNodes.forEach((child) => {if (child.cid === draggingNode.data.cid) {draggingNodeAfterDrop = child;}})
}
这里,draggingParentNodeAfterDrop 根据拖动位置确定,然后遍历其子节点找到具有相同 cid 的节点,即拖动后的拖动节点。
更新 catLevel
最后,如果需要更新 catLevel,调用 updateCatLevel 方法来递归更新拖动节点及其所有子节点的 catLevel:
this.updateCatLevel(draggingNodeAfterDrop, dropNode.data.catLevel + deep);
updateCatLevel 方法如下:
// 递归更新draggingNode及其子节点的catLevelupdateCatLevel(node) {if (!node) {return;}this.nodesInfoAfterDrop.push({catId: node.data.catId, catLevel: node.level});if (node.childNodes && node.childNodes.length > 0) {node.childNodes.forEach((child) => {this.updateCatLevel(child);});}},
在这个方法中,node.catLevel 被设置为 node.level,后者通常反映了节点的实际层级深度。如果节点有子节点,递归地调用 updateCatLevel 方法来更新所有子节点的 catLevel。
完整代码
<template><div><el-treenode-key="catId":data="menus":props="defaultProps":expand-on-click-node="false"show-checkbox:default-expanded-keys="expandedKeys":allow-drop="allowDrag"@node-drop="nodeDrop"draggable><span class="custom-tree-node" slot-scope="{ node, data }"><span>{{ node.label }}</span><span><el-buttonv-if="node.level <= 2"size="mini"@click="() => append(data)">Append</el-button><el-button size="mini" @click="() => edit(data)"> Edit </el-button><el-buttonv-if="node.childNodes.length == 0"type="text"size="mini"@click="() => remove(node, data)">Delete</el-button></span></span></el-tree><el-dialog:title="dialogTitle":visible.sync="dialogFormVisible":close-on-click-modal="false"><el-form :model="category"><el-form-item label="分类名称"><el-input v-model="category.name" autocomplete="off"></el-input></el-form-item><el-form-item label="图标"><el-input v-model="category.icon" autocomplete="off"></el-input></el-form-item><el-form-item label="计量单位"><el-inputv-model="category.productUnit"autocomplete="off"></el-input></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button @click="dialogFormVisible = false">取 消</el-button><el-button type="primary" @click="submitCategory">确 定</el-button></div></el-dialog></div>
</template><script>
export default {components: {},props: {},data() {return {nodesInfoAfterDrop: [],dialogTitle: "", // 编辑窗口标题,新增分类,修改分类dialogType: "", // 编辑窗口类型,create表示append,edit表示editdialogFormVisible: false,menus: [],category: {name: "",parentCid: 0,catLevel: 0,sort: 0,showStatus: 1,icon: "",productUnit: "",catId: null,},expandedKeys: [],defaultProps: {children: "children",label: "name",},};},methods: {nodeDrop(draggingNode, dropNode, dropPosition) {console.log("draggingNode:", draggingNode, dropNode, dropPosition);var draggingNodeNewPId = 0;// 1,更新draggingNode的parentCid,根据dropPosition的不同值,分为两种情况if (dropPosition === "before" || dropPosition === "after") {draggingNodeNewPId = dropNode.data.parentCid;} else {draggingNodeNewPId = dropNode.data.cid;}// 2,更新draggingNode及其子节点的sort// 2.1如果draggingNode的parentCid没有更新,只需要重排draggingNode的兄弟结点的sort;// 2.2如果draggingNode的parentCid有更新,不仅需要重排draggingNode的原来的兄弟结点的sort,还需要重排draggingNode新的兄弟结点的sortvar siblingNodesOld = [];var siblingNodesNew = [];// draggingNode.parent为空,所以要根据parentCid找到其parent。// 写一个根据cid从menus中查询结点的函数let draggingNodeOldParentNode = this.getNodeByCid(draggingNode.data.parentCid, this.getLevel1Nodes(dropNode));console.log("draggingNodeOldParentNode:", draggingNodeOldParentNode);siblingNodesOld = draggingNodeOldParentNode.childNodes;;console.log("siblingNodesOld:", siblingNodesOld);if (draggingNode.data.parentCid !== draggingNodeNewPId) {if (dropPosition === "before" || dropPosition === "after") {siblingNodesNew = dropNode.parent.childNodes;} else {siblingNodesNew = dropNode.childNodes;}}for (var i = 0; i < siblingNodesOld.length; i++) {this.nodesInfoAfterDrop.push({catId: siblingNodesOld[i].data.catId, sort: i});}console.log("update sortu0....", siblingNodesNew, siblingNodesOld, dropNode, dropPosition);for (var i = 0; i < siblingNodesNew.length; i++) {this.nodesInfoAfterDrop.push({catId: siblingNodesNew[i].data.catId, sort: i});}console.log("update sort....", siblingNodesNew, siblingNodesOld, dropNode, dropPosition);// 3,更新draggingNode及其子节点的catLevelvar catLevelNeedUpdate = true;if (draggingNode.data.catLevel === dropNode.data.catLevel && (dropPosition === "before" || dropPosition === "after")) {catLevelNeedUpdate = false;}var draggingNodeAfterDrop = null;if (catLevelNeedUpdate) {var draggingParentNodeAfterDrop = {};if (dropPosition === "before" || dropPosition === "after") {draggingParentNodeAfterDrop = dropNode.parent;} else {draggingParentNodeAfterDrop = dropNode;}draggingParentNodeAfterDrop.childNodes.forEach((child) => {if (child.data.catId === draggingNode.data.catId) {draggingNodeAfterDrop = child;}})// 递归变量draggingNodeAfterDrop及其childNodes,将其data属性的cateLevel置为level属性值this.updateCatLevel(draggingNodeAfterDrop);}this.nodesInfoAfterDrop.push({catId: draggingNode.data.catId, parentCid: draggingNodeNewPId});console.log(this.nodesInfoAfterDrop);// 4,调用后端接口,将数组nodesInfoAfterDrop发送给后端this.$http({url: this.$http.adornUrl("/product/category/update/sort"),method: "post",data: this.$http.adornData(this.nodesInfoAfterDrop, false),}).then(({ data }) => {if (data && data.code === 0) {this.$message({message: "操作成功",type: "success",duration: 1500,onClose: () => {console.log("删除成功,关闭消息提示");this.getMenus(); // 重新获取数据this.expandedKeys = [draggingNodeNewPId]; // 重置展开节点},});} else {this.$message.error(data.msg);}});},getLevel1Nodes(node) {var tmpNode = node;while(tmpNode.parent) {tmpNode = tmpNode.parent;}return tmpNode.childNodes;},// 写一个根据cid从menus中查询结点的函数getNodeByCid(cid, nodes) {if (cid === 0) {return null;}// 递归查询for (var i = 0; i < nodes.length; i++) {if (nodes[i].data.catId === cid) {return nodes[i];}if (nodes[i].childNodes && nodes[i].childNodes.length > 0) {var node = this.getNodeByCid(cid, nodes[i].childNodes);if (node) {return node;}}}return null;},// 递归更新draggingNode及其子节点的catLevelupdateCatLevel(node) {if (!node) {return;}this.nodesInfoAfterDrop.push({catId: node.data.catId, catLevel: node.level});if (node.childNodes && node.childNodes.length > 0) {node.childNodes.forEach((child) => {this.updateCatLevel(child);});}},allowDrag(draggingNode, dropNode, dropPosition) {var deep = this.countDraggingNodeDeep(draggingNode);// 根据dropPosition结合dropNode.catLevel来判断draggingNode新位置的位置是否合法if (dropPosition === "prev" || dropPosition === "next") {return dropNode.data.catLevel + deep - 1 <= 3;} else if (dropPosition === "inner") {return dropNode.data.catLevel + deep <= 3;}},// 递归计算draggingNode子树的深度countDraggingNodeDeep(draggingNode) {var deep = 0;if (draggingNode.childNodes && draggingNode.childNodes.length > 0) {debugger;draggingNode.childNodes.forEach((child) => {deep = Math.max(deep, this.countDraggingNodeDeep(child));});}return deep + 1;},append(data) {console.log(data);this.dialogType = "create";this.dialogTitle = "新增分类";this.dialogFormVisible = true;this.category = {name: "",parentCid: data.catId,catLevel: data.level + 1,sort: 0,showStatus: 1,};},edit(data) {console.log(data);this.dialogType = "edit";this.dialogTitle = "修改分类";this.dialogFormVisible = true;// 根据catId查询最新数据this.$http({url: this.$http.adornUrl(`/product/category/info/${data.catId}`),method: "get",data: this.$http.adornData({ catId: data.catId }, false),}).then(({ data }) => {if (data && data.code === 0) {this.category = { ...data.data };} else {this.$message.error(data.msg);}});},submitCategory() {if (this.dialogType === "create") {this.addCategory();} else if (this.dialogType === "edit") {this.updateCategory();}},updateCategory() {var { catId, name, icon, productUnit } = this.category;console.log(this.category);this.$http({url: this.$http.adornUrl("/product/category/update"),method: "post",data: this.$http.adornData({ catId, name, icon, productUnit }, false),}).then(({ data }) => {if (data && data.code === 0) {this.$message({message: "修改成功",type: "success",duration: 1500,onClose: () => {console.log("修改成功,关闭消息提示");this.dialogFormVisible = false;this.getMenus(); // 重新获取数据this.expandedKeys = [this.category.parentCid == 0? this.category.catId: this.category.parentCid,]; // 重置展开节点console.log(this.expandedKeys);},});} else {this.$message.error(data.msg);}});},addCategory() {this.$http({url: this.$http.adornUrl("/product/category/save"),method: "post",data: this.$http.adornData(this.category, false),}).then(({ data }) => {if (data && data.code === 0) {this.$message({message: "添加成功",type: "success",duration: 1500,onClose: () => {console.log("添加成功,关闭消息提示");this.dialogFormVisible = false;this.getMenus(); // 重新获取数据this.expandedKeys = [this.category.parentCid]; // 重置展开节点},});} else {this.$message.error(data.msg);}});},remove(node, data) {console.log(node, data);var ids = [node.data.catId];this.$confirm(`确定对[id=${ids.join(",")}]进行[${ids.length == 1 ? "删除" : "批量删除"}]操作?`,"提示",{confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",}).then(() => {this.$http({url: this.$http.adornUrl("/product/category/delete"),method: "post",data: this.$http.adornData(ids, false),}).then(({ data }) => {if (data && data.code === 0) {this.$message({message: "操作成功",type: "success",duration: 1500,onClose: () => {console.log("删除成功,关闭消息提示");this.getMenus(); // 重新获取数据this.expandedKeys = [node.parent.data.catId]; // 重置展开节点},});} else {this.$message.error(data.msg);}});}).catch(() => {});},// 获取分类数据getMenus() {this.dataListLoading = true;this.$http({url: this.$http.adornUrl("/product/category/list/tree"),method: "get",}).then(({ data }) => {console.log(data);this.dataListLoading = false;this.menus = data.data;});},},created() {this.getMenus(); // 获取分类数据},
};
</script>
<style scoped>
</style>
相关文章:
谷粒商城实战笔记-55-商品服务-API-三级分类-修改-拖拽数据收集
文章目录 一,拖拽后结点的parentCid的更新二,拖拽后结点的父节点下所有结点的sort排序属性的变化更新排序的逻辑代码分析 三,拖拽后结点及其子节点catLevel的变化判断是否需要更新 catLevel获取拖动后的新节点 更新 catLevel完整代码 这一节的…...
AI绘画入门实践|Midjourney:使用 --seed 制作情侣头像与漫画
在 Midjourney 中,seed 是指一个种子,用于生成图像时的起点或基础。 使用格式:--seed 获取的seed值 获取 seed 值 使用 seed 生成图像 a cute boys avatar, background with blue sky and white cloud, Ghibli Studio style, Hayao Miyazaki…...
笔记:Enum中FlagsAttribute特性的用法
一、目的:分享Enum中FlagsAttribute特性的用法 在C#中,Enum(枚举)类型可以使用[Flags]属性来表示一个枚举可以存储多个值。这是通过按位运算符(如|(或)和&(与)&#…...
QWidget如何切换ui
在Qt中,QWidget及其子类用于构建图形用户界面。如果你想要在不同的UI之间切换,可以使用QStackedWidget,它可以管理一组QWidget,并且每次只显示其中一个。 以下是一个简单的例子,展示如何使用QStackedWidget切换UI&…...
web网站组成
web网站由四部分组成:浏览器 前端服务器 后端服务器 数据库服务器 流程: 1.浏览器输入网站后,向前端服务器发送请求,前端服务器响应,静态的数据给浏览器。 2.前端代码中script中有url,这个是向后台发送请求的网…...
带您详细了解安全漏洞的产生和防护
什么是漏洞? 漏洞是 IT、网络、云、Web 或移动应用程序系统中的弱点或缺陷,可能使其容易受到成功的外部攻击。攻击者经常试图寻找网络安全中的各种类型的漏洞来组合和利用系统。 一些最常见的漏洞: 1.SQL注入 注入诸如 SQL 查询之类的小代…...
【接口测试】params传参与body传参区别
文章目录 一.params传参二.body传参三.两者区别说明 一.params传参 params传参一般用于get请求 params传参时,参数会附于URL后面以问号形式展示。 示例: http://ip地址:端口号/login?usernamexm&pwd111二.body传参 body传参一般用于post请求 body传参时需…...
【docker】部署证书过期监控系统mouday/domain-admin
证书过期了再去部署证书容易被骂,就找了一个开源的证书过期系统来部署一下 过程 官方文档:https://domain-admin.readthedocs.io/zh-cn/latest/manual/install.html#docker 直接下载镜像是超时的,切换一下文档推荐的镜像源 新建docker配置…...
高级java每日一道面试题-2024年7月17日
面试官: java中都有哪些引用类型? 我回答: 强引用(Strong Reference) 描述:这是最常见和最直观的引用类型,我们通常在代码中创建的对象引用就是强引用。例如,Object obj new Object();。只要强引用存在,…...
css中如何清除浮动
在CSS中,可以使用clear:both属性来清除浮动。以下是几种常见的清除浮动的方法: 使用clearfix类:在CSS中定义一个clearfix类,并将其应用于需要清除浮动的父元素上。 .clearfix::after {content: "";display: table;cle…...
【网络】tcp_socket
tcp_socket 一、tcp_server与udp_server一样的部分二、listen接口(监听)三、accept接收套接字1、为什么还要多一个套接字(明明已经有了个socket套接字文件了,为什么要多一个accept套接字文件?)2、底层拿到新…...
Live555源码阅读笔记:哈希表的实现
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...
vue3创建vite项目
一、创建vue3 vite项目: 命令行创建:npm create vitelatest vue3-tdly-demo -- --template vue (1)先进入项目文件夹,cd vue3-tdly-demo (2)之后执行, npm install (3)最后运行,npm run dev 将main.js文件内容改成…...
Maven概述
目录 1.Maven简介 2.Maven开发环境搭建 2.1下载Maven服务器 2.2安装,配置Maven 1.配置本地仓库地址 2.配置阿里云镜像地址 2.3在idea中配置maven 2.4在idea中创建maven项目 3.pom.xml配置 1.项目基本信息 2.依赖信息 3.构建信息 4.Maven命令 5.打包Jav…...
Easyu中datagrid点击时获取所在行的数据
问题 双击单元格时,获取该行的记录内容 $(#list).datagrid({method: post,url: user/list,queryParams:{sex : "f",age : "18~25"},fitColumns: true,pageList: [ 5, 10, 15, 20 ],singleSelect: false,pagination: true,fit: true,rownumber…...
java项目中添加SDK项目作为依赖使用(无需上传Maven)
需求: 当需要多次调用某个函数或算法时,不想每次调用接口都自己编写,可以将该项目打包,以添加依赖的方式实现调用 适用于: 无需上线的项目,仅公司或团队内部使用的项目 操作步骤: 以下面这…...
区块链和数据要素融合的价值及应用
一、数据要素面临的关键障碍 在构建数据要素基石的过程中,首要任务是明确并解决产权架构的难题,特别是使用权的确立与流转机制的顺畅,此乃数字经济蓬勃发展的命脉所在。一个高效的数据流转体系对于激发数据潜能、加速经济发展及优化数据资源…...
以太坊的可扩展性危机:探索执行层的瓶颈
导读:以太坊执行层承担着交易处理、智能合约执行以及保持一致和安全状态的维护等工作。Fuel Labs 撰文解析了以太坊执行层的工作原理,及其在可扩展性方面的发展瓶颈和影响。 Fuel Labs: 执行是指在区块链上执行交易和执行状态更改所需的计算。此计算通常…...
静态解析activiti文本,不入库操作流程
说明: activiti本身状态存库,导致效率太低,把中间状态封装成一个载荷类,返回给上游,下次请求时给带着载荷类即可。 1.pom依赖 <dependency><groupId>net.sf.json-lib</groupId><artifactId>js…...
100个python的基本语法知识【上】
0. 变量和赋值: x 5 name “John” 1. 数据类型: 整数(int) 浮点数(float) 字符串(str) 布尔值(bool) 2. 注释: # 这是单行注释 ""…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...
nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...
