DeviceCategoryTree.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. <template>
  2. <div class="head-container">
  3. <el-input v-model="deviceCategoryName" class="mb-20px" 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="deviceCategoryList"
  13. :expand-on-click-node="false"
  14. :filter-node-method="filterNode"
  15. :props="defaultProps"
  16. :default-expand-all="false"
  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 DeviceCategoryApi from '@/api/pms/productclassify'
  39. import { defaultProps, handleTree } from '@/utils/tree'
  40. import { useTreeStore } from '@/store/modules/treeStore'
  41. defineOptions({ name: 'DeviceCategoryTree' })
  42. const treeStore = useTreeStore();
  43. const deviceCategoryName = ref('')
  44. const deviceCategoryList = 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. let selectedNode = null;
  50. const firstLevelKeys = ref([])
  51. const handleRightClick = (event, { node, data }) => {
  52. event.preventDefault();
  53. menuX.value = event.clientX;
  54. menuY.value = event.clientY;
  55. selectedNode = data; // 存储当前操作的节点数据 ‌:ml-citation{ref="7" data="citationList"}
  56. menuVisible.value = true;
  57. };
  58. const treeContainer = ref(null)
  59. const setHeight = () => {
  60. if (!treeContainer.value) return
  61. const windowHeight = window.innerHeight
  62. const containerTop = treeContainer.value.offsetTop
  63. treeContainer.value.style.height = `${windowHeight * 0.78}px` // 60px 底部预留
  64. }
  65. const handleMenuClick = (action) => {
  66. switch(action) {
  67. case 'add':
  68. // 调用新增节点逻辑 ‌:ml-citation{ref="4" data="citationList"}
  69. break;
  70. case 'edit':
  71. // 调用编辑节点逻辑 ‌:ml-citation{ref="7" data="citationList"}
  72. break;
  73. case 'delete':
  74. // 调用删除节点逻辑 ‌:ml-citation{ref="4" data="citationList"}
  75. break;
  76. }
  77. menuVisible.value = false;
  78. };
  79. /** 获得 设备分类 树 */
  80. const getTree = async () => {
  81. const res = await DeviceCategoryApi.IotProductClassifyApi.getSimpleProductClassifyList()
  82. deviceCategoryList.value = []
  83. deviceCategoryList.value.push(...handleTree(res))
  84. }
  85. /** 基于名字过滤 */
  86. const filterNode = (name: string, data: Tree) => {
  87. if (!name) return true
  88. return data.name.includes(name)
  89. }
  90. /** 处理 设备分类 被点击 */
  91. const handleNodeClick = async (row: { [key: string]: any }) => {
  92. emits('node-click', row)
  93. treeStore.setSelectedId(row.id);
  94. }
  95. const emits = defineEmits(['node-click'])
  96. /** 监听 deviceCategoryName */
  97. watch(deviceCategoryName, (val) => {
  98. treeRef.value!.filter(val)
  99. })
  100. /** 初始化 */
  101. onMounted(async () => {
  102. await getTree()
  103. setHeight()
  104. window.addEventListener('resize', setHeight)
  105. })
  106. onUnmounted(() => {
  107. window.removeEventListener('resize', setHeight)
  108. })
  109. </script>
  110. <style lang="scss" scoped>
  111. .custom-menu {
  112. position: fixed;
  113. background: white;
  114. border: 1px solid #ccc;
  115. box-shadow: 2px 2px 5px rgba(0,0,0,0.1);
  116. z-index: 1000;
  117. }
  118. .custom-menu ul {
  119. list-style: none;
  120. padding: 0;
  121. margin: 0;
  122. }
  123. .custom-menu li {
  124. padding: 8px 20px;
  125. cursor: pointer;
  126. }
  127. .custom-menu li:hover {
  128. background: #f5f5f5;
  129. }
  130. .tree-container {
  131. overflow-y: auto;
  132. min-width: 100%;
  133. border: 1px solid #e4e7ed;
  134. border-radius: 4px;
  135. }
  136. </style>