|
|
@@ -0,0 +1,117 @@
|
|
|
+<script lang="ts" setup>
|
|
|
+import { defaultProps, handleTree } from '@/utils/tree'
|
|
|
+import { ElTree } from 'element-plus'
|
|
|
+import * as DeptApi from '@/api/system/dept'
|
|
|
+import { Search } from '@element-plus/icons-vue'
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ deptId: {
|
|
|
+ type: Number,
|
|
|
+ default: 157
|
|
|
+ },
|
|
|
+ modelValue: {
|
|
|
+ type: Number,
|
|
|
+ default: undefined
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const emits = defineEmits(['update:modelValue', 'node-click'])
|
|
|
+
|
|
|
+const deptName = ref('')
|
|
|
+
|
|
|
+const deptList = ref<Tree[]>([])
|
|
|
+
|
|
|
+const treeRef = ref<InstanceType<typeof ElTree>>()
|
|
|
+
|
|
|
+const expandedKeys = ref<number[]>([])
|
|
|
+
|
|
|
+const loadTree = async () => {
|
|
|
+ try {
|
|
|
+ const res = await DeptApi.specifiedSimpleDepts(props.deptId)
|
|
|
+ deptList.value = handleTree(res)
|
|
|
+
|
|
|
+ // 加载完成后,如果有选中值,尝试高亮并展开
|
|
|
+ nextTick(() => {
|
|
|
+ if (props.modelValue && treeRef.value) {
|
|
|
+ treeRef.value.setCurrentKey(props.modelValue)
|
|
|
+ expandedKeys.value = [props.modelValue] // 默认展开选中的节点
|
|
|
+ } else if (deptList.value.length > 0) {
|
|
|
+ // 默认展开第一级
|
|
|
+ expandedKeys.value = deptList.value.map((item) => item.id)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载部门树失败:', error)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleNodeClick = (data: Tree) => {
|
|
|
+ // 1. 更新 v-model
|
|
|
+ emits('update:modelValue', data.id)
|
|
|
+ // 2. 抛出点击事件供父组件其他用途
|
|
|
+ emits('node-click', data)
|
|
|
+}
|
|
|
+
|
|
|
+/** 筛选节点逻辑 */
|
|
|
+const filterNode = (value: string, data: Tree) => {
|
|
|
+ if (!value) return true
|
|
|
+ return data.name.includes(value)
|
|
|
+}
|
|
|
+
|
|
|
+/** 监听输入框进行过滤 */
|
|
|
+watch(deptName, (val) => {
|
|
|
+ treeRef.value?.filter(val)
|
|
|
+})
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => props.deptId,
|
|
|
+ (newVal, oldVal) => {
|
|
|
+ if (newVal !== oldVal) {
|
|
|
+ loadTree()
|
|
|
+ }
|
|
|
+ }
|
|
|
+)
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => props.modelValue,
|
|
|
+ (newVal) => {
|
|
|
+ if (newVal && treeRef.value) {
|
|
|
+ // 设置高亮
|
|
|
+ treeRef.value.setCurrentKey(newVal)
|
|
|
+ // 自动展开该节点 (将新ID加入展开数组)
|
|
|
+ if (!expandedKeys.value.includes(newVal)) {
|
|
|
+ expandedKeys.value.push(newVal)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+)
|
|
|
+
|
|
|
+/** 初始化 */
|
|
|
+onMounted(() => {
|
|
|
+ loadTree()
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <h1 class="text-lg font-medium">部门</h1>
|
|
|
+ <el-input
|
|
|
+ v-model="deptName"
|
|
|
+ size="default"
|
|
|
+ placeholder="请输入部门名称"
|
|
|
+ clearable
|
|
|
+ :prefix-icon="Search"
|
|
|
+ />
|
|
|
+ <el-scrollbar max-height="700px">
|
|
|
+ <el-tree
|
|
|
+ ref="treeRef"
|
|
|
+ :data="deptList"
|
|
|
+ :props="defaultProps"
|
|
|
+ :expand-on-click-node="false"
|
|
|
+ :filter-node-method="filterNode"
|
|
|
+ node-key="id"
|
|
|
+ highlight-current
|
|
|
+ :default-expanded-keys="expandedKeys"
|
|
|
+ @node-click="handleNodeClick"
|
|
|
+ />
|
|
|
+ </el-scrollbar>
|
|
|
+</template>
|