DeptTree.vue 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. <template>
  2. <div class="head-container">
  3. <el-input v-model="deptName" class="mb-20px" clearable placeholder="请输入部门名称">
  4. <template #prefix>
  5. <Icon icon="ep:search" />
  6. </template>
  7. </el-input>
  8. </div>
  9. <div class="head-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-expand-all
  17. highlight-current
  18. node-key="id"
  19. @node-click="handleNodeClick"
  20. @node-contextmenu="handleRightClick"
  21. style="height: 35em"
  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. defineOptions({ name: 'SystemUserDeptTree' })
  41. const deptName = ref('')
  42. const deptList = ref<Tree[]>([]) // 树形结构
  43. const treeRef = ref<InstanceType<typeof ElTree>>()
  44. const menuVisible = ref(false);
  45. const menuX = ref(0);
  46. const menuY = ref(0);
  47. let selectedNode = null;
  48. const handleRightClick = (event, { node, data }) => {
  49. event.preventDefault();
  50. menuX.value = event.clientX;
  51. menuY.value = event.clientY;
  52. selectedNode = data; // 存储当前操作的节点数据 ‌:ml-citation{ref="7" data="citationList"}
  53. //menuVisible.value = true;
  54. };
  55. const handleMenuClick = (action) => {
  56. switch(action) {
  57. case 'add':
  58. // 调用新增节点逻辑 ‌:ml-citation{ref="4" data="citationList"}
  59. break;
  60. case 'edit':
  61. // 调用编辑节点逻辑 ‌:ml-citation{ref="7" data="citationList"}
  62. break;
  63. case 'delete':
  64. // 调用删除节点逻辑 ‌:ml-citation{ref="4" data="citationList"}
  65. break;
  66. }
  67. menuVisible.value = false;
  68. };
  69. /** 获得部门树 */
  70. const getTree = async () => {
  71. const res = await DeptApi.getSimpleDeptList()
  72. deptList.value = []
  73. deptList.value.push(...handleTree(res))
  74. }
  75. /** 基于名字过滤 */
  76. const filterNode = (name: string, data: Tree) => {
  77. if (!name) return true
  78. return data.name.includes(name)
  79. }
  80. /** 处理部门被点击 */
  81. const handleNodeClick = async (row: { [key: string]: any }) => {
  82. emits('node-click', row)
  83. }
  84. const emits = defineEmits(['node-click'])
  85. /** 监听deptName */
  86. watch(deptName, (val) => {
  87. treeRef.value!.filter(val)
  88. })
  89. /** 初始化 */
  90. onMounted(async () => {
  91. await getTree()
  92. })
  93. </script>
  94. <style lang="scss" scoped>
  95. .custom-menu {
  96. position: fixed;
  97. background: white;
  98. border: 1px solid #ccc;
  99. box-shadow: 2px 2px 5px rgba(0,0,0,0.1);
  100. z-index: 1000;
  101. }
  102. .custom-menu ul {
  103. list-style: none;
  104. padding: 0;
  105. margin: 0;
  106. }
  107. .custom-menu li {
  108. padding: 8px 20px;
  109. cursor: pointer;
  110. }
  111. .custom-menu li:hover {
  112. background: #f5f5f5;
  113. }
  114. </style>