TS使用el-tree拖拽结构+点击写法

1.结构分两块

<template>
  <div style="height:96%;width:100%;max-width:1920px;max-height:1080px;background-color:white;padding:20px;display: flex;flex-direction:row; ">

    <!-- 左侧树 -->
    <div style="height:100%;width:32%;">
    </div>

    <!-- 右侧两个表 -->
    <div style="height:100%;width:68%;" v-show="showTable">
    </div>

    </div>
  </div>

</template>

2.左侧树写法(主要)

  <!-- 左侧树 -->
    <div style="height:100%;width:32%;">
      <el-row style="height:30px">
        <svg-icon icon-class="organizationIcon" />
        <span class="ttac_model_title">{{$t('i18n.organization')}}</span>
      </el-row>

      <el-row style="overflow: hidden; width: 100%; bottom: 0px;height: calc(100% - 30px); ">
        <div style="overflow: auto; width: 100%; height: 100%;" @contextmenu.prevent="onTreeRightClick">
 <!-- 
            node-key	每个树节点用来作为唯一标识的属性,整棵树应该是唯一的
            node-click	节点被点击时的回调
            node-contextmenu	当某一节点被鼠标右键点击时会触发该事件
            data	展示数据
            default-expand-all	是否默认展开所有节点
            node-drag-start	节点开始拖拽时触发的事件
            node-drag-enter	拖拽进入其他节点时触发的事件
            node-drag-leave	拖拽离开某个节点时触发的事件
            node-drag-over	在拖拽节点时触发的事件(类似浏览器的 mouseover 事件)
            node-drag-end	拖拽结束时(可能未成功)触发的事件
            node-drop	拖拽成功完成时触发的事件
            allow-drop	拖拽时判定目标节点能否被放置。type 参数有三种情况:'prev'、'inner' 和 'next',分别表示放置在目标节点前、插入至目标节点和放置在目标节点后
            allow-drag	判断节点能否被拖拽
            expand-on-click-node	是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。
            draggable	是否开启拖拽节点功能
            highlight-current	是否高亮当前选中节点,默认值是 false。
           -->
         <el-tree
            node-key="id"
            @node-click="showOrganizationInfo"
            @node-contextmenu="onTreeNodeRightClick"
            :data="treeData"
            default-expand-all
            @node-drag-start="handleDragStart"
            @node-drag-enter="handleDragEnter"
            @node-drag-leave="handleDragLeave"
            @node-drag-over="handleDragOver"
            @node-drag-end="handleDragEnd"
            @node-drop="handleDrop"
            :allow-drop="allowDrop"
            :allow-drag="allowDrag"
            :expand-on-click-node="false"
            draggable
            highlight-current
          >
           

            <div slot-scope="{node,data}">
              <div v-if="data.type==='people'">
                <btreeNode :value="data.label" style="margin-left: 3px; z-index: 1;" :nodeKey="data.id" :isUser="data.userId? true:false">
                  <template #icon>
                    <svg-icon icon-class="user1" />
                  </template>
                </btreeNode>
              </div>
              <div v-if="data.type==='group'">
                <btreeNode :value="data.label" style="margin-left: 3px; z-index: 1;" :nodeKey="data.id" :isUser="data.userId? true:false"
                  @onValueChanged="(id,title)=>onNodeNameChanged(id,title,data)" @onSureNodeName="(id,title)=>onSureNodeName(id,title,data)">
                  <template #icon>
                    <svg-icon icon-class="department" />
                  </template>
                </btreeNode>
              </div>
            </div>
          </el-tree>
          <chooseUserDialog ref="chooseUserDialog" @onSure="onSelectPeople" />
          <VueContextMenu id="context-menu" ref="ctxMenu" style="cursor: pointer">
            <li v-for="(menu, index) in rightMenus" :key="index" class="ttactheme_hover" style="padding-left: 5px" @click="onRightMenuChoose(menu)">
              <svg-icon :icon-class="getMenuIconByRightMenus(menu)" />
              <span style="margin-left: 3px">&nbsp;&nbsp;{{ menu }}</span>
            </li>
          </VueContextMenu>
        </div>
      </el-row>
    </div>

 data数据 :

//获取tree的数据
private async initData() {
    //所有数据
    let res = await GetAllOranizationInfo()
    //处理成树形
    this.treeData = this.organData(res, null)
  }

处理tree的数据结构,展示树形

private organData(allData: any[], topparentId: string): TreeNodeDC[] {
    let res: TreeNodeDC[] = []
    // 通过使用filter方法,从res数据中筛选出 用户的parentId  等于 大组织id的数据 , 并将结果保存在filters数组中。
    //第一次传入的是null,匹配第一个大的组织
    let filters = allData.filter((o) => o.parentId === topparentId)
    console.log('filter之后的res,', filters)
    //对匹配上的数据进行循环操作
    for (let index = 0; index < filters.length; index++) {
      //把值放到node里形成新的对象
      const element = filters[index]
      //默认组织,因为第一个开头传的null,第一次匹配到的就是最大的组织
      let node: TreeNodeDC = {
        id: element.id,
        userId: element.userId,
        label: element.name,
        parentGroupId: element.parentId,
        index: element.index,
        children: [],
        type: 'group'
      }
      //type==0是组织(group),type==1是用户(people)
      if (element.type === 1) {
        node.type = 'people'
      }
      //递归,调用自身方法,传入 第1(n)次获取到的数据的id,然后走流程
      let nodeChildren = this.organData(allData, node.id)
      console.log('nodeChildren,', nodeChildren, allData, node.id)
      // 通过使用filter方法,从res数据中筛选出 小用户的parentId  等于 大组织id的数据 , 并将结果保存在filters数组中
      //这次的就是子级,用户+组织的形式
      //对匹配上的数据进行循环操作
      //排序
      node.children = nodeChildren.sort(function(a, b) {
        return a.index - b.index
      })
      //返回node数组
      res.push(node)
    }

    return res
  }

2.1点击用户 /  组织

noadeList数据:

 // 点击node触发的方法
  private showOrganizationInfo(nodeList) {
    let idList = []
    // 如果点击的node没有子节点,但是有用户id,说明是用户
    if (nodeList.children.length == 0 && nodeList.userId != null) {
      //点击的id放到idList
      idList = [nodeList.userId]
    } else {
      // 否则点击的是组织
      idList = this.getChildIds(nodeList.children)
    }
    //如果没有点到数据
    if (idList.length == 0) {
      this.showTable = false
      this.userIds = []
    } else {
      //打开table显示
      this.showTable = true
      //没什么作用,赋值方便后续
      this.userIds = idList
    }
  }


//点击组织的处理方法
  //递归当前节点下及其子节点的数据,获取单个组织下包括所有id的集合,返回出来
  private getChildIds(nodeChildList) {
    let userIds = []
    let childUserIds = []
    nodeChildList.forEach((item) => {
      userIds.push(item.userId)
      if (item.children.length > 0) {
        childUserIds = this.getChildIds(item.children) as any
      }
    })
    return [...userIds, ...childUserIds].filter((v) => v)
  }
//节点   拖拽开始 / 进入其他节点 / 拖拽离开 / 在拖拽节点时触发的事件(类似浏览器的 mouseover 事件) / 拖拽结束时(可能未成功)触发的事件
// ***************树********************************************
  private handleDragStart(node, ev) {
    // console.log('drag start', node)
  }
  private handleDragEnter(draggingNode, dropNode, ev) {
    // console.log('tree drag enter: ', dropNode.label)
  }
  private handleDragLeave(draggingNode, dropNode, ev) {
    // console.log('tree drag leave: ', dropNode.label)
  }
  private handleDragOver(draggingNode, dropNode, ev) {
    // console.log('tree drag over: ', dropNode.label)
  }
  private handleDragEnd(draggingNode, dropNode, dropType, ev) {
    // console.log('tree drag end: ', dropNode && dropNode.label, dropType)
  }

3.右击tree的节点发生的事件,阻止冒泡和默认事件,然后启用vue-contextMenu的方法

          <VueContextMenu id="context-menu" ref="ctxMenu" style="cursor: pointer">
            //rightMenus是根据右键点击的是 组织 还是 用户 来控制显示的是什么
            //图标根据rightMenus的数据来决定,switch方法匹配
            <li v-for="(menu, index) in rightMenus" :key="index" class="ttactheme_hover" style="padding-left: 5px" @click="onRightMenuChoose(menu)">
           
              <svg-icon :icon-class="getMenuIconByRightMenus(menu)" />
              <span style="margin-left: 3px">&nbsp;&nbsp;{{ menu }}</span>
            </li>
          </VueContextMenu>
//枚举 i18里的数据
enum rightMenus {
  addPeople = 'i18n.rightMenu_addPeople',
  addGroup = 'i18n.rightMenu_addCombination',
  saveAs = 'i18n.rightMenu_saveAs',
  rename = 'i18n.rightMenu_rename',
  edit = 'i18n.rightMenu_edit',
  delete = 'i18n.rightMenu_delete'
}

 右键打开面板 展示哪些数据 的方法:

//右击菜单树,就是右击空白地方
 private onTreeRightClick(e: any) {
    //window.console.log('右击菜单树', e)
    e.stopPropagation()
    e.preventDefault()
    this.currentRightClickNode = null
    this.rightMenus = []
    this.rightMenus = [this.$t(rightMenus.addGroup).toString()]
    ;(this.$refs.ctxMenu as any).open()
  }




//右击菜单树节点
//el-tree上有个@node-contextmenu="onTreeNodeRightClick"
 private onTreeNodeRightClick(e: any, data: any) {
    // window.console.log('右击菜单树节点的节点数据', data)
    //禁止事件冒泡
    e.stopPropagation()
    //阻止默认事件执行
    e.preventDefault()
    //节点数据
    this.currentRightClickNode = data
    //清空数组
    this.rightMenus = []
    //如果点的用户
    if (data.type === 'people') {
      //只让 枚举数组里 放删除
      this.rightMenus = [this.$t(rightMenus.delete).toString()]
    } else if (data.type === 'group') {
      //添加部门的文字
      this.rightMenus = [this.$t(rightMenus.addGroup).toString(), 
      //添加人员的文字
      this.$t(rightMenus.addPeople).toString(), 
      //添加删除的文字
      this.$t(rightMenus.delete).toString()]
    }
    //通过$refs使用open方法打开框子
    ;(this.$refs.ctxMenu as any).open()
  }


//展示图标的方法
  private getMenuIconByRightMenus(rm: rightMenus): string {
    let iconString
    switch (rm) {
      case this.$t(rightMenus.addPeople).toString():
        iconString = 'rightmenu_add'
        break
      case this.$t(rightMenus.addGroup).toString(): {
        iconString = 'rightmenu_add'
        break
      }
      case this.$t(rightMenus.edit).toString():
        iconString = '&#xe628;'
        break
      case this.$t(rightMenus.saveAs).toString(): {
        iconString = '&#xe61a;'
        break
      }
      case this.$t(rightMenus.rename).toString(): {
        iconString = '&#xe628;'
        break
      }
      case this.$t(rightMenus.delete).toString(): {
        iconString = 'rightmenu_delete'
        break
      }
      default:
        break
    }
    return iconString
  }


//点击menu的数据,进行增删改查的操作
 private async onRightMenuChoose(menuName: string) {
    //window.console.log('onRightMenuChoose:', menuName)
    switch (menuName) {
      case this.$t(rightMenus.addPeople).toString():
        this.addPeople()
        break
      case this.$t(rightMenus.addGroup).toString():
        this.addGroup()
        break
      case this.$t(rightMenus.delete).toString():
        this.deleteNode()
        this.onDeletePage(this.currentRightClickNode.id)
        break
      case this.$t(rightMenus.edit).toString():
        this.onEditPage(this.currentRightClickNode.id)
        break
      default:
        break
    }
  }

4.拖拽成功时触发的事件,基本就是调用接口了

  private async handleDrop(draggingNode, dropNode, dropType, ev) {
    // ****************************************
    let parentGroupId = null
    if (dropType === 'inner') {
      parentGroupId = dropNode.data.id
    } else if (dropType === 'before') {
      parentGroupId = dropNode.data.parentGroupId
    } else if (dropType === 'after') {
      parentGroupId = dropNode.data.parentGroupId
    }
    let dragingNodeData = this.searchNodeById(draggingNode.data.id, this.treeData)
    dragingNodeData.parentGroupId = parentGroupId
    if (dragingNodeData.type === 'people') {
      let data = this.makeDesignPageDCByNode(dragingNodeData)
      await AddOrUpdateOranizationInfo(data)
    } else if (dragingNodeData.type === 'group') {
      let data = this.makeDesignPageGroupDCByNode(dragingNodeData)
      await AddOrUpdateOranizationInfo(data)
    }
    // ****************************************
    let needOrderNodes = []
    if (parentGroupId) {
      let parentNodeData = this.searchNodeById(parentGroupId, this.treeData)
      needOrderNodes = parentNodeData.children
    } else {
      needOrderNodes = this.treeData
    }
    for (let index = 0; index < needOrderNodes.length; index++) {
      needOrderNodes[index].index = index
    }

    let updateIndexData: any[] = []
    for (let index = 0; index < needOrderNodes.length; index++) {
      const element = needOrderNodes[index]
      updateIndexData.push({
        oranizationId: element.id,
        index: element.index
      })
    }

    window.console.log('needOrderNodes:', updateIndexData)
    await UpdateOranizationSort(needOrderNodes)
  }

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/456253.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【刷题节】美团2024年春招第一场笔试【技术】

1.小美的平衡矩阵 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner new Scanner(System.in);int n scanner.nextInt();int[][] nums new int[n][n], sum new int[n][n];char[] chars;for (int i 0; i < n; i) {…

使用Python对文本文件进行分词、词频统计和可视化

目录 一、引言 二、文本分词 三、词频统计 四、可视化 五、案例与总结 六、注意事项与扩展 七、总结与展望 一、引言 在大数据时代&#xff0c;文本处理是信息提取和数据分析的重要一环。分词、词频统计和可视化是文本处理中的基础任务&#xff0c;它们能够帮助…

生产线平衡改善的四大方法及vioovi ECRS工时分析软件的应用

生产线平衡是制造业生产过程中的关键环节&#xff0c;它直接影响到生产效率、成本及产品质量。在追求精益生产的今天&#xff0c;改善生产线平衡成为众多企业的重要目标。生产线平衡改善的四大方法包括&#xff1a;保证各工序之间的先后顺序、组合的工序时间不能大于节拍、各工…

Hadoop大数据应用:HDFS 集群节点扩容

目录 一、实验 1.环境 2.HDFS 集群节点扩容 二、问题 1.rsync 同步报错 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构软件版本IP备注hadoop NameNode &#xff08;已部署&#xff09; SecondaryNameNode &#xff08;已部署&#xff09; Resourc…

迁移学习怎么用

如果想实现一个计算机视觉应用&#xff0c;而不想从零开始训练权重&#xff0c;比方从随机初始化开始训练&#xff0c;更快的方式是下载已经训练好权重的网络结构&#xff0c;把这个作为预训练&#xff0c;迁移到你感兴趣的新任务上。ImageNet、PASCAL等等数据库已经公开在线。…

【OceanBase诊断调优 】——全链路诊断日志看不懂?obdiag来帮你!

最近总结一些诊断OCeanBase的一些经验&#xff0c;出一个【OceanBase诊断调优】专题&#xff0c;也欢迎大家贡献自己的诊断OceanBase的方法。 1. 前言 OceanBase 数据库是分布式数据库&#xff0c;因此调用链路复杂&#xff0c;当出现超时问题的时&#xff0c;往往无法快速定…

【Redis系列】深入了解 Redis:一种高性能的内存数据库

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

EI期刊复现:面向配电网韧性提升的移动储能预布局与动态调度策略程序代码!

适用平台&#xff1a;MatlabYalmipCplex/Gurobi/Mosek 程序提出一种多源协同的两阶段配电网韧性提升策略。在灾前考虑光伏出力不确定性与网络重构&#xff0c;以移动储能配置成本与负荷削减风险成本最小为目标对储能的配置数量与位置进行预布局&#xff1b;在灾后通过多源协同…

离线数仓(六)【ODS 层开发】

前言 今天开始正式的数仓搭建&#xff0c;所谓 ODS 层的工作就是把我们各种数据源采集发送来的各种类型的数据&#xff08;Json、tsv类型&#xff09;映射到 Hive 表中&#xff0c;映射时可以进行一些简单的处理&#xff0c;比如简单的数据清洗&#xff0c;舍弃一些没有必要的字…

3d场景重建图像渲染 | 神经辐射场NeRF(Neural Radiance Fields)

神经辐射场NeRF&#xff08;Neural Radiance Fields&#xff09; 概念 NeRF&#xff08;Neural Radiance Fields&#xff0c;神经辐射场&#xff09;是一种用于3D场景重建和图像渲染的深度学习方法。它由Ben Mildenhall等人在2020年的论文《NeRF: Representing Scenes as Neur…

武汉星起航:创新驱动,共赢未来,引领跨境电商新潮流

在跨境电商这个充满挑战与机遇的领域&#xff0c;武汉星起航凭借其创新思维和共赢理念&#xff0c;正引领着行业发展的新潮流。 武汉星起航深知创新是企业在激烈竞争中立于不败之地的关键。公司始终关注市场动态&#xff0c;紧跟行业趋势&#xff0c;不断探索新的商业模式和运…

京东云主机+京美建站SaaS版

京美建站SaaS版 京美建站搭建企业网站、小程序、3000精美模板 链接:https://daili.jd.com/s?linkNo57UBX34BZMWGNFYTOCPVUE7SN36CCIPKLTFLPCUCPYBKSYYBIPS2BJ57GP7RACLDHU66X526ZOULMIXL2VN7DT7IHU 京东云主机&#xff0c;安全稳定&#xff0c;性能强劲&#xff0c;新客下单…

深入了解RC电路的分类及优化应用方法!

RC电路是由电阻&#xff08;R&#xff09;和电容&#xff08;C&#xff09;组成的电路&#xff0c;它是一种常见的模拟电路&#xff0c;也在数字电路和信号处理中有广泛的应用。RC电路的特性由电阻、电容和电路连接方式决定&#xff0c;它可以用于滤波、时序控制、信号整形等多…

有来团队后台项目-解析6

element-icon 引入 安装 在解析3中&#xff0c;已经安装过 创建plugins 文件夹 icons 文件 import type { App } from "vue"; import * as ElementPlusIconsVue from "element-plus/icons-vue";// 注册所有图标 export function setupElIcons(app: App…

Linux 文件基本属性

Linux 文件基本属性 Linux 系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限。 为了保护系统的安全性,Linux 系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的规定。 在 Linux 中我们通常使用以下两个命令来修改文件或目录的所属用户与…

ASP.NET Core 8.0 WebApi 从零开始学习JWT登录认证

文章目录 前言相关链接Nuget选择知识补充JWT不是加密算法可逆加密和不可逆加密 普通Jwt&#xff08;不推荐&#xff09;项目环境Nuget 最小JWT测试在WebApi中简单使用简单使用运行结果 WebApi 授权&#xff0c;博客太老了&#xff0c;尝试失败 WebApi .net core 8.0 最新版Jwt …

【投稿优惠-EI稳定检索】2024年图像处理与机械系统工程国际学术会议 (ICIPMSE 2024)

【投稿优惠-EI稳定检索】2024年图像处理与机械系统工程国际学术会议 (ICIPMSE 2024) 大会主题: (主题包括但不限于, 更多主题请咨询会务组苏老师) 图像处理 基于图像的渲染 计算机视觉 可视化分析 模式识别 3D打印 渲染和动画 渲染技术 电脑动画 基于草图的建模 机械…

详解Python中%r和%s的区别及用法

首先看下面的定义&#xff1a; %r用rper()方法处理对象 %s用str()方法处理对象 函数str() 用于将值转化为适于人阅读的形式&#xff0c;而repr() 转化为供解释器读取的形式&#xff08;如果没有等价的语法&#xff0c;则会发生SyntaxError 异常&#xff09; 某对象没有适于人…

【leetcode+深度/广度优先搜索】841. 钥匙和房间 (DFS,BFS)

leetcode-cn&#xff1a;leetcode面试75道精华&#xff1a;https://leetcode.cn/studyplan/leetcode-75/ 841.钥匙和房间&#xff1a;https://leetcode.cn/problems/keys-and-rooms/description/ 一、题目&#xff1a;841. 钥匙和房间 有 n 个房间&#xff0c;房间按从 0 到 n…

零代码开发的优势 零代码平台开发的好处

随着数字化浪潮的推进&#xff0c;企业对于数据驱动的需求越来越高&#xff0c;而零代码快速开发平台正是满足这一需求的重要工具之一。零代码开发平台是一种无需编写代码即可开发应用程序的平台&#xff0c;它可以让用户通过拖、拉、拽的方式快速创建高度定制化的应用。这种平…
最新文章