140 lines
2.8 KiB
Vue
140 lines
2.8 KiB
Vue
<template>
|
||
<el-tree-select
|
||
:model-value="modelVal"
|
||
:data="treeData"
|
||
style="width: 300px;"
|
||
:props="defaultProps"
|
||
searchable
|
||
clearable
|
||
v-bind="$attrs"
|
||
@update:model-value="updateValue"
|
||
@change="handleChange"
|
||
/>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted, computed } from 'vue'
|
||
import { listDept } from '@/api/system/dept'
|
||
import { listUser } from '@/api/system/user'
|
||
|
||
defineOptions({
|
||
name: 'UserSelect'
|
||
})
|
||
|
||
const emit = defineEmits(['update:modelValue', 'change'])
|
||
const props = defineProps({
|
||
modelValue: {
|
||
type: [String, Number, Array],
|
||
default: undefined
|
||
},
|
||
// 是否只选择用户,false 表示部门也可以选择
|
||
userOnly: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
// 是否多选
|
||
multiple: {
|
||
type: Boolean,
|
||
default: false
|
||
}
|
||
})
|
||
|
||
const treeData = ref([])
|
||
const defaultProps = {
|
||
value: 'id',
|
||
label: 'label',
|
||
children: 'children'
|
||
}
|
||
|
||
// 加载部门和用户数据
|
||
const loadData = async () => {
|
||
try {
|
||
// 获取部门列表
|
||
const { data: deptList } = await listDept()
|
||
// 获取用户列表
|
||
const { rows: userList } = await listUser()
|
||
|
||
// 转换部门数据
|
||
const transformedDeptList = deptList.map(dept => ({
|
||
id: `dept_${dept.deptId}`,
|
||
label: dept.deptName,
|
||
parentId: dept.parentId === 0 ? null : `dept_${dept.parentId}`,
|
||
type: 'dept'
|
||
}))
|
||
|
||
// 转换用户数据
|
||
const transformedUserList = userList.map(user => ({
|
||
id: `${user.userId}`,
|
||
label: user.nickName || user.userName,
|
||
parentId: `dept_${user.deptId}`,
|
||
type: 'user'
|
||
}))
|
||
|
||
// 如果只选择用户,过滤掉部门节点
|
||
let allNodes = props.userOnly
|
||
? transformedUserList
|
||
: [...transformedDeptList, ...transformedUserList]
|
||
|
||
// 构建树形结构
|
||
treeData.value = buildTree(allNodes)
|
||
} catch (error) {
|
||
console.error('加载数据失败:', error)
|
||
}
|
||
}
|
||
|
||
// 构建树形结构
|
||
const buildTree = (nodes) => {
|
||
const map = {}
|
||
const result = []
|
||
|
||
// 创建节点映射
|
||
nodes.forEach(node => {
|
||
map[node.id] = { ...node, children: [] }
|
||
})
|
||
|
||
// 构建树形关系
|
||
nodes.forEach(node => {
|
||
const current = map[node.id]
|
||
if (node.parentId) {
|
||
const parent = map[node.parentId]
|
||
if (parent) {
|
||
parent.children.push(current)
|
||
}
|
||
} else {
|
||
result.push(current)
|
||
}
|
||
})
|
||
|
||
return result
|
||
}
|
||
|
||
// 使用计算属性处理双向绑定
|
||
const modelVal = computed({
|
||
get: () => props.modelValue,
|
||
set: (value) => {
|
||
emit('update:modelValue', value)
|
||
}
|
||
})
|
||
|
||
// 处理值更新
|
||
const updateValue = (value) => {
|
||
modelVal.value = value
|
||
}
|
||
|
||
// 处理选择变化
|
||
const handleChange = (value) => {
|
||
emit('change', value)
|
||
}
|
||
|
||
// 组件挂载时加载数据
|
||
onMounted(() => {
|
||
loadData()
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.el-tree-select {
|
||
width: 100%;
|
||
}
|
||
</style>
|