DeptTree2.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. <template>
  2. <div class="head-container" style="display: flex;flex-direction: row;">
  3. <el-input v-model="deptName" class="mb-18px" clearable placeholder="请输入部门名称">
  4. <template #prefix>
  5. <Icon icon="ep:search" />
  6. </template>
  7. </el-input>
  8. </div>
  9. <div ref="treeContainer" class="tree-container">
  10. <el-tree
  11. ref="treeRef"
  12. :data="deptList"
  13. :expand-on-click-node="false"
  14. :filter-node-method="filterNode"
  15. :props="defaultProps"
  16. :default-expanded-keys="firstLevelKeys"
  17. highlight-current
  18. node-key="id"
  19. @node-click="handleNodeClick"
  20. @node-contextmenu="handleRightClick"
  21. style="height: 52em"
  22. />
  23. </div>
  24. <div
  25. v-show="menuVisible"
  26. class="custom-menu"
  27. :style="{ left: menuX + 'px', top: menuY + 'px' }"
  28. >
  29. <ul>
  30. <li @click="handleMenuClick('add')">新增子节点</li>
  31. <li @click="handleMenuClick('edit')">重命名</li>
  32. <li @click="handleMenuClick('delete')">删除</li>
  33. </ul>
  34. </div>
  35. </template>
  36. <script lang="ts" setup>
  37. import { ElTree } from 'element-plus'
  38. import * as DeptApi from '@/api/system/dept'
  39. import { defaultProps, handleTree } from '@/utils/tree'
  40. import { useTreeStore } from '@/store/modules/usersTreeStore'
  41. import {specifiedSimpleDepts} from "@/api/system/dept";
  42. defineOptions({ name: 'DeptTree2' })
  43. const deptName = ref('')
  44. const deptList = ref<Tree[]>([]) // 树形结构
  45. const treeRef = ref<InstanceType<typeof ElTree>>()
  46. const menuVisible = ref(false);
  47. const menuX = ref(0);
  48. const menuY = ref(0);
  49. const firstLevelKeys = ref([])
  50. let selectedNode = null;
  51. const treeStore = useTreeStore();
  52. const handleRightClick = (event, { node, data }) => {
  53. event.preventDefault();
  54. menuX.value = event.clientX;
  55. menuY.value = event.clientY;
  56. selectedNode = data; // 存储当前操作的节点数据 ‌:ml-citation{ref="7" data="citationList"}
  57. //menuVisible.value = true;
  58. };
  59. const treeContainer = ref(null)
  60. const setHeight = () => {
  61. if (!treeContainer.value) return
  62. const windowHeight = window.innerHeight
  63. const containerTop = treeContainer.value.offsetTop
  64. treeContainer.value.style.height = `${windowHeight * 0.78}px` // 60px 底部预留
  65. }
  66. const handleMenuClick = (action) => {
  67. switch(action) {
  68. case 'add':
  69. // 调用新增节点逻辑 ‌:ml-citation{ref="4" data="citationList"}
  70. break;
  71. case 'edit':
  72. // 调用编辑节点逻辑 ‌:ml-citation{ref="7" data="citationList"}
  73. break;
  74. case 'delete':
  75. // 调用删除节点逻辑 ‌:ml-citation{ref="4" data="citationList"}
  76. break;
  77. }
  78. menuVisible.value = false;
  79. };
  80. /** 获得部门树 */
  81. const getTree = async () => {
  82. const res = await DeptApi.specifiedSimpleDepts(157)
  83. deptList.value = []
  84. deptList.value.push(...handleTree(res))
  85. firstLevelKeys.value = deptList.value.map(node => node.id);
  86. }
  87. /** 基于名字过滤 */
  88. const filterNode = (name: string, data: Tree) => {
  89. if (!name) return true
  90. return data.name.includes(name)
  91. }
  92. /** 处理部门被点击 */
  93. const handleNodeClick = async (row: { [key: string]: any }) => {
  94. emits('node-click', row)
  95. treeStore.setSelectedId(row.id);
  96. }
  97. const emits = defineEmits(['node-click'])
  98. /** 监听deptName */
  99. watch(deptName, (val) => {
  100. treeRef.value!.filter(val)
  101. })
  102. /** 初始化 */
  103. onMounted(async () => {
  104. await getTree()
  105. setHeight()
  106. window.addEventListener('resize', setHeight)
  107. })
  108. onUnmounted(() => {
  109. window.removeEventListener('resize', setHeight)
  110. })
  111. </script>
  112. <style lang="scss" scoped>
  113. .custom-menu {
  114. position: fixed;
  115. background: white;
  116. border: 1px solid #ccc;
  117. box-shadow: 2px 2px 5px rgba(0,0,0,0.1);
  118. z-index: 1000;
  119. }
  120. .custom-menu ul {
  121. list-style: none;
  122. padding: 0;
  123. margin: 0;
  124. }
  125. .custom-menu li {
  126. padding: 8px 20px;
  127. cursor: pointer;
  128. }
  129. .custom-menu li:hover {
  130. background: #f5f5f5;
  131. }
  132. .tree-container {
  133. overflow-y: auto;
  134. min-width: 100%;
  135. border: 1px solid #e4e7ed;
  136. border-radius: 4px;
  137. }
  138. </style>