|
@@ -0,0 +1,142 @@
|
|
|
+<template>
|
|
|
+ <div class="head-container" style="display: flex;flex-direction: row;">
|
|
|
+ <el-input v-model="deptName" class="mb-18px" clearable placeholder="请输入部门名称">
|
|
|
+ <template #prefix>
|
|
|
+ <Icon icon="ep:search" />
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ </div>
|
|
|
+ <div ref="treeContainer" class="tree-container">
|
|
|
+ <el-tree
|
|
|
+ ref="treeRef"
|
|
|
+ :data="deptList"
|
|
|
+ :expand-on-click-node="false"
|
|
|
+ :filter-node-method="filterNode"
|
|
|
+ :props="defaultProps"
|
|
|
+ :default-expanded-keys="firstLevelKeys"
|
|
|
+ highlight-current
|
|
|
+ node-key="id"
|
|
|
+ show-checkbox
|
|
|
+ @node-click="handleNodeClick"
|
|
|
+ @node-contextmenu="handleRightClick"
|
|
|
+ style="height: 52em"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ v-show="menuVisible"
|
|
|
+ class="custom-menu"
|
|
|
+ :style="{ left: menuX + 'px', top: menuY + 'px' }"
|
|
|
+ >
|
|
|
+ <ul>
|
|
|
+ <li @click="handleMenuClick('add')">新增子节点</li>
|
|
|
+ <li @click="handleMenuClick('edit')">重命名</li>
|
|
|
+ <li @click="handleMenuClick('delete')">删除</li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+import { ElTree } from 'element-plus'
|
|
|
+import * as DeptApi from '@/api/system/dept'
|
|
|
+import { defaultProps, handleTree } from '@/utils/tree'
|
|
|
+
|
|
|
+defineOptions({ name: 'SystemUserDeptTree' })
|
|
|
+
|
|
|
+const deptName = ref('')
|
|
|
+const deptList = ref<Tree[]>([]) // 树形结构
|
|
|
+const treeRef = ref<InstanceType<typeof ElTree>>()
|
|
|
+const menuVisible = ref(false);
|
|
|
+const menuX = ref(0);
|
|
|
+const menuY = ref(0);
|
|
|
+const firstLevelKeys = ref([])
|
|
|
+let selectedNode = null;
|
|
|
+const handleRightClick = (event, { node, data }) => {
|
|
|
+ event.preventDefault();
|
|
|
+ menuX.value = event.clientX;
|
|
|
+ menuY.value = event.clientY;
|
|
|
+ selectedNode = data; // 存储当前操作的节点数据 :ml-citation{ref="7" data="citationList"}
|
|
|
+ //menuVisible.value = true;
|
|
|
+};
|
|
|
+const treeContainer = ref(null)
|
|
|
+const setHeight = () => {
|
|
|
+ if (!treeContainer.value) return
|
|
|
+ const windowHeight = window.innerHeight
|
|
|
+ const containerTop = treeContainer.value.offsetTop
|
|
|
+ treeContainer.value.style.height = `${windowHeight * 0.78}px` // 60px 底部预留
|
|
|
+}
|
|
|
+const handleMenuClick = (action) => {
|
|
|
+ switch(action) {
|
|
|
+ case 'add':
|
|
|
+ // 调用新增节点逻辑 :ml-citation{ref="4" data="citationList"}
|
|
|
+ break;
|
|
|
+ case 'edit':
|
|
|
+ // 调用编辑节点逻辑 :ml-citation{ref="7" data="citationList"}
|
|
|
+ break;
|
|
|
+ case 'delete':
|
|
|
+ // 调用删除节点逻辑 :ml-citation{ref="4" data="citationList"}
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ menuVisible.value = false;
|
|
|
+};
|
|
|
+/** 获得部门树 */
|
|
|
+const getTree = async () => {
|
|
|
+ const res = await DeptApi.getSimpleDeptList()
|
|
|
+ deptList.value = []
|
|
|
+ deptList.value.push(...handleTree(res))
|
|
|
+ firstLevelKeys.value = deptList.value.map(node => node.id);
|
|
|
+}
|
|
|
+
|
|
|
+/** 基于名字过滤 */
|
|
|
+const filterNode = (name: string, data: Tree) => {
|
|
|
+ if (!name) return true
|
|
|
+ return data.name.includes(name)
|
|
|
+}
|
|
|
+
|
|
|
+/** 处理部门被点击 */
|
|
|
+const handleNodeClick = async (row: { [key: string]: any }) => {
|
|
|
+ emits('node-click', row)
|
|
|
+}
|
|
|
+const emits = defineEmits(['node-click'])
|
|
|
+
|
|
|
+/** 监听deptName */
|
|
|
+watch(deptName, (val) => {
|
|
|
+ treeRef.value!.filter(val)
|
|
|
+})
|
|
|
+
|
|
|
+/** 初始化 */
|
|
|
+onMounted(async () => {
|
|
|
+ await getTree()
|
|
|
+ setHeight()
|
|
|
+ window.addEventListener('resize', setHeight)
|
|
|
+})
|
|
|
+onUnmounted(() => {
|
|
|
+ window.removeEventListener('resize', setHeight)
|
|
|
+})
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.custom-menu {
|
|
|
+ position: fixed;
|
|
|
+ background: white;
|
|
|
+ border: 1px solid #ccc;
|
|
|
+ box-shadow: 2px 2px 5px rgba(0,0,0,0.1);
|
|
|
+ z-index: 1000;
|
|
|
+}
|
|
|
+.custom-menu ul {
|
|
|
+ list-style: none;
|
|
|
+ padding: 0;
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
+.custom-menu li {
|
|
|
+ padding: 8px 20px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+.custom-menu li:hover {
|
|
|
+ background: #f5f5f5;
|
|
|
+}
|
|
|
+.tree-container {
|
|
|
+ overflow-y: auto;
|
|
|
+ min-width: 100%;
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+</style>
|