<template>
|
<el-input
|
v-model="selectedLabel"
|
style="max-width: 600px"
|
placeholder="请选择"
|
class="input-with-select"
|
:disabled="true"
|
@click="handleClick"
|
>
|
<template #append>
|
<el-button icon="Search" @click="handleClick" />
|
</template>
|
</el-input>
|
|
<el-dialog title="选择节点" width="30%" @close="handleClose" v-model="dialogTableVisible" draggable overflow>
|
<el-input v-model="filterText" style="width: 100%" placeholder="查找" />
|
<el-tree
|
ref="treeRef"
|
:data="treeData"
|
:props="treeProps"
|
:show-checkbox="multiple"
|
:node-key="idField"
|
highlight-current
|
:filter-node-method="filterNode"
|
class="scrollable-tree"
|
:default-checked-keys="defaultCheckedKeys"
|
:current-node-key="currentNodeKey"
|
check-strictly
|
default-expand-all
|
/>
|
|
<span slot="footer" class="dialog-footer">
|
<el-button @click="handleCancel">取消</el-button>
|
<el-button type="primary" @click="handleConfirm">确定</el-button>
|
</span>
|
</el-dialog>
|
</template>
|
|
<script setup>
|
import { ref, computed, watch, defineProps, defineEmits, nextTick, onMounted } from 'vue'
|
|
const props = defineProps({
|
selectedNodes: {
|
type: [Array, String],
|
default: () => [],
|
},
|
treeList: {
|
type: Array,
|
required: true,
|
},
|
idField: {
|
type: String,
|
default: 'id',
|
},
|
nameField: {
|
type: String,
|
default: 'name',
|
},
|
multiple: {
|
type: Boolean,
|
default: false,
|
},
|
})
|
|
const emit = defineEmits(['update:selectedValue'])
|
|
const treeData = ref(props.treeList)
|
const selectedValue = ref(null)
|
const dialogTableVisible = ref(false)
|
const filterText = ref('')
|
const selectedLabel = ref('')
|
|
const treeProps = computed(() => ({
|
children: 'children',
|
label: props.nameField,
|
value: props.idField,
|
}))
|
|
const treeRef = ref()
|
|
const defaultCheckedKeys = ref([])
|
const currentNodeKey = ref(null)
|
|
// 处理节点选中变化的方法
|
function handleCheckChange(checkedNodes, checkedKeys, node) {
|
if (props.multiple) {
|
// 多选模式
|
const checkedNodes = treeRef.value.getCheckedNodes() // 获取所有选中的节点
|
selectedValue.value = checkedNodes.map(node => node[props.idField]) // 更新选中的值
|
} else {
|
// 单选模式
|
const selectedNode = checkedNodes[0]
|
selectedValue.value = selectedNode ? selectedNode[props.idField] : null // 更新选中的值
|
}
|
}
|
|
function handleNodeClick(data) {
|
if (!props.multiple) {
|
// 单选模式
|
selectedValue.value = data[props.idField] // 更新选中的值
|
// 直接赋值给 selectedLabel 将在 handleConfirm 中处理
|
} else {
|
// 多选模式
|
// 在多选模式下,选中的节点的处理一般在 handleCheckChange 中进行
|
}
|
}
|
|
function handleConfirm() {
|
setSelectedLabel()
|
emitSelectedValue() // 更新外部组件的选中值
|
dialogTableVisible.value = false
|
}
|
|
function setSelectedLabel() {
|
if (props.multiple) {
|
// 多选模式
|
selectedLabel.value = treeRef.value
|
.getCheckedNodes()
|
.map(node => node[props.nameField])
|
.join(', ') // 更新选中的标签
|
selectedValue.value = treeRef.value.getCheckedNodes().map(node => node[props.idField]) // 更新选中的值
|
} else {
|
// 单选模式
|
const currentNode = treeRef.value.getCurrentNode() // 获取当前选中的节点
|
selectedLabel.value = currentNode ? currentNode[props.nameField] : '' // 更新选中的标签
|
selectedValue.value = currentNode ? currentNode[props.idField] : null // 更新选中的值
|
}
|
}
|
|
function handleCancel() {
|
dialogTableVisible.value = false
|
}
|
|
function handleClose() {
|
dialogTableVisible.value = false
|
}
|
|
function emitSelectedValue() {
|
emit('update:selectedValue', selectedValue.value)
|
}
|
|
function handleClick() {
|
filterText.value = ''
|
dialogTableVisible.value = true
|
}
|
|
watch(
|
() => props.treeList,
|
newValue => {
|
treeData.value = newValue
|
if (Array.isArray(props.selectedNodes)) {
|
defaultCheckedKeys.value = props.selectedNodes
|
currentNodeKey.value = null
|
|
// 设置 selectedLabel
|
const labels = props.selectedNodes.map(id => findLabelById(treeData.value, id)).filter(label => label !== null)
|
selectedLabel.value = labels.join(', ')
|
} else {
|
defaultCheckedKeys.value = []
|
currentNodeKey.value = props.selectedNodes
|
|
// 设置 selectedLabel
|
selectedLabel.value = findLabelById(treeData.value, props.selectedNodes) || ''
|
}
|
},
|
)
|
|
watch(
|
() => props.selectedNodes,
|
newValue => {
|
if (Array.isArray(newValue)) {
|
defaultCheckedKeys.value = newValue
|
currentNodeKey.value = null
|
|
// 设置 selectedLabel
|
const labels = newValue.map(id => findLabelById(treeData.value, id)).filter(label => label !== null)
|
selectedLabel.value = labels.join(', ')
|
} else {
|
defaultCheckedKeys.value = []
|
currentNodeKey.value = newValue
|
|
// 设置 selectedLabel
|
selectedLabel.value = findLabelById(treeData.value, newValue) || ''
|
}
|
},
|
)
|
|
// 递归遍历树数据来设置 selectedLabel
|
function findLabelById(tree, id) {
|
for (const node of tree) {
|
if (node[props.idField] === id) {
|
return node[props.nameField]
|
}
|
if (node.children && node.children.length > 0) {
|
const label = findLabelById(node.children, id)
|
if (label) return label
|
}
|
}
|
return null
|
}
|
|
watch(filterText, val => {
|
treeRef.value.filter(val)
|
})
|
|
onMounted(async () => {})
|
|
const filterNode = (value, data) => {
|
if (!value) return true
|
return data[props.nameField].includes(value)
|
}
|
</script>
|
|
<style scoped>
|
.scrollable-tree {
|
min-height: 400px;
|
max-height: 400px; /* Adjust this value to your desired height */
|
overflow-y: auto;
|
}
|
</style>
|