You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
663 lines
19 KiB
663 lines
19 KiB
<template>
|
|
<!-- {{ props.data?.control.fixedOptions }} --><!-- {{transferConfig}} --><!-- {{ resData }} --><!-- {{ count1 }} -->
|
|
<!-- <hr>
|
|
<hr>
|
|
<hr> -->
|
|
<div v-if="dataFinished" class="transfer"><!-- {{props.selectedValue}} -->
|
|
<div class="leftArea"><!-- {{ selectedValueCompu }}{{checkedIdList}} -->
|
|
<div class="transferName">{{ transferConfig.transferName }}</div>
|
|
<div style="padding-left: 15px; padding-right: 25px;margin-top: 10px;margin-bottom: 8px;">
|
|
<ElInput v-model="keyword" placeholder="搜索">
|
|
<template #prefix>
|
|
<ElIcon class="el-input__icon">
|
|
<Search />
|
|
</ElIcon>
|
|
</template>
|
|
</ElInput>
|
|
</div>
|
|
<div class="leftScroll">
|
|
<ElScrollbar height="100%">
|
|
<ElTree ref="treeRef" node-key="id" empty-text="暂无数据" :data="userList" :props="treeProps"
|
|
show-checkbox highlight-current :default-expand-all="isExpandAll"
|
|
:filter-node-method="filterNode" @check="handleCheckList" @check-change="getCheckedList" />
|
|
</ElScrollbar>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rigthArea">
|
|
<div style="margin-bottom: 8px;">
|
|
<div class="transferName"><span>已选: {{ checkList.length }}</span>
|
|
<ElButton link style="float: right;margin-right: 5px;" @click="clearCheckList">清空</ElButton>
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
<ElScrollbar height="calc(100% - 50px)">
|
|
<ElTag v-for="user in checkList" :key="user.id"
|
|
style="display: block; font-size: 13px; letter-spacing: 1.5px;text-align: center;margin-top: 8px;height: 30px;width: 75%;margin-left:40px;padding-top: 6px;"
|
|
closable @close="handleCloseTag(user)">
|
|
{{
|
|
user.label
|
|
}}[{{
|
|
user.parent.data.label
|
|
}}]
|
|
</ElTag>
|
|
|
|
</ElScrollbar>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup name="MultiTreeSelector">
|
|
import { ref, watch, onMounted } from 'vue'
|
|
|
|
import request from '@/utils/request';
|
|
|
|
const props = defineProps({
|
|
// eslint-disable-next-line vue/require-default-prop
|
|
data: {
|
|
type: Object,
|
|
default() {
|
|
return {};
|
|
},
|
|
},
|
|
selectedValue: {
|
|
type: Array,
|
|
default() {
|
|
return [];
|
|
},
|
|
},
|
|
})
|
|
|
|
|
|
const emits = defineEmits(['checkedIdListChanged', 'updateModel','reRenderComponent']);
|
|
/* const fixedOptions = ref([]) */
|
|
/* fixedOptions.value = props.data?.control.fixedOptions */
|
|
|
|
|
|
|
|
//const transferConfig = props.data?.config
|
|
const transferConfig = computed({
|
|
set(){
|
|
|
|
},
|
|
get(){
|
|
|
|
return props.data?.config
|
|
|
|
}
|
|
})
|
|
|
|
const treeProps = {
|
|
value: 'id',
|
|
label: 'label',
|
|
disabled: 'disabled',
|
|
children: 'children'
|
|
}
|
|
let dataFinished = ref(false)
|
|
const treeRef = ref()
|
|
const isExpandAll = ref(false) // 是否全展开
|
|
const keyword = ref('') // 搜索关键字
|
|
const checkList = ref([]) // 选中的list
|
|
const userList = computed({
|
|
|
|
get(){
|
|
if (transferConfig.value.transferDataSource === "数据源") {
|
|
return [{
|
|
id: '全选',
|
|
label: '全选',
|
|
children: [...resData.value]
|
|
}]
|
|
}else{
|
|
return [{
|
|
id: '全选',
|
|
label: '全选',
|
|
children: props.data?.control.fixedOptions
|
|
}]
|
|
}
|
|
|
|
},
|
|
set(){
|
|
|
|
}
|
|
})
|
|
let checkedIdList = ref([]);
|
|
let count = 0
|
|
function waitAndReGet() {
|
|
/* console.log("waitAndReGet")
|
|
console.log(props.selectedValue)
|
|
console.log(props.selectedValue.value) */
|
|
setTimeout(() => {
|
|
let values = props.selectedValue.map(item => {
|
|
// 假设这里需要提取每个元素的特定值,可以根据实际情况进行调整
|
|
return item;
|
|
});
|
|
if (props.selectedValue && values) {
|
|
|
|
/* console.log("有值")
|
|
console.log(props.selectedValue)
|
|
console.log(values) */
|
|
//return props.selectedValue.value
|
|
checkedIdList.value = values
|
|
} else {
|
|
if (count < 3) {
|
|
count++
|
|
waitAndReGet()
|
|
}
|
|
|
|
/* console.log("waitAndReGet---else") */
|
|
|
|
}
|
|
}, 2000)
|
|
}
|
|
/*
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
const selectedValueCompu = computed({
|
|
get() {
|
|
//console.log("get")
|
|
//nextTick(()=>{
|
|
let values = props.selectedValue.map(item => {
|
|
// 假设这里需要提取每个元素的特定值,可以根据实际情况进行调整
|
|
return item;
|
|
});
|
|
if (props.selectedValue && values) {
|
|
/* console.log(props.selectedValue.value)
|
|
console.log("computed---if") */
|
|
return values
|
|
} else {
|
|
waitAndReGet()
|
|
/* console.log("computed---else") */
|
|
return []
|
|
|
|
}
|
|
|
|
//})
|
|
|
|
},
|
|
set() { }
|
|
})
|
|
/* console.log(props.selectedValue) */
|
|
|
|
|
|
|
|
|
|
const url = transferConfig.value.apiUrl;/* '/javasys/lowCode/transfer/getOrgAndManTree' */
|
|
let resData = ref([])
|
|
|
|
|
|
function getDetail() {
|
|
//console.log(11111)
|
|
if (transferConfig.value.transferDataSource === "数据源") {
|
|
return request({
|
|
url: url,
|
|
method: transferConfig.value.method,
|
|
});
|
|
}
|
|
}
|
|
if (transferConfig.value.transferDataSource === "数据源") {
|
|
getDetail().then(({ data }) => {
|
|
//console.log(`获取穿梭框接口数据`);
|
|
resData.value = data.children
|
|
// 全选方法2:插入 全选node
|
|
userList.value = [{
|
|
id: '全选',
|
|
label: '全选',
|
|
children: [...resData.value]
|
|
}]
|
|
treeRef.value.setCheckedKeys(checkedIdList.value, true)
|
|
setTimeout(() => {
|
|
checkedIdList.value.forEach(element => {
|
|
const _node = treeRef?.value?.getNode(element)
|
|
if (!_node) return
|
|
const _checkList = checkList.value
|
|
if (_node.checked) { // 勾选时
|
|
if (_node.checked && _node.childNodes.length === 0) {
|
|
_checkList.push(_node)
|
|
}
|
|
// 通过new Set() 实现数据去重
|
|
checkList.value = Array.from(new Set(_checkList))
|
|
// 遍历子级,递归,直到获取最后一级的人员
|
|
if (_node.childNodes.length > 0) {
|
|
_node.childNodes.map(item => handleCheckList(item.data))
|
|
}
|
|
} else if (!_node.checked) { // 取消勾选
|
|
checkList.value = checkList.value.filter(item => item.checked)
|
|
}
|
|
});
|
|
}, 50);
|
|
|
|
|
|
});
|
|
}
|
|
const getCheckedList = () => {
|
|
checkedIdList.value = treeRef.value.getCheckedKeys(true)
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let resData1 = ref([
|
|
{
|
|
id: '3',
|
|
label: '营销部',
|
|
children: [
|
|
{
|
|
id: '3-1',
|
|
label: '威震天'
|
|
},
|
|
{
|
|
id: '3-2',
|
|
label: '嫦娥'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
id: '2',
|
|
label: '业务部',
|
|
children: [
|
|
{
|
|
id: '2-1-1',
|
|
label: '业务部子部1',
|
|
children: [
|
|
{
|
|
id: '2-1-0001',
|
|
label: '李白'
|
|
},
|
|
{
|
|
id: '2-1-0002',
|
|
label: '萧峰'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
id: '2-2-1',
|
|
label: '业务部子部2',
|
|
children: [
|
|
{
|
|
id: '2-2-00006',
|
|
label: '武则天'
|
|
},
|
|
{
|
|
id: '2-2-00005',
|
|
label: '拿破仑'
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
id: '4',
|
|
label: '软件开发部',
|
|
children: [
|
|
{
|
|
id: '5-3',
|
|
label: '张辽'
|
|
},
|
|
{
|
|
id: '5-9',
|
|
label: '吕布'
|
|
},
|
|
{
|
|
id: '5-0',
|
|
label: '许褚'
|
|
},
|
|
]
|
|
}
|
|
])
|
|
|
|
|
|
// 勾选或者取消勾选
|
|
const handleCheckList = (val) => {
|
|
//console.log(val)
|
|
const valId = val.id;
|
|
//console.log(valId)
|
|
const _node = treeRef?.value?.getNode(valId)
|
|
//console.log(_node)
|
|
|
|
|
|
if (!_node) return
|
|
const _checkList = checkList.value
|
|
if (_node.checked||_node.childNodes.length > 0) {
|
|
//console.log(1)
|
|
if (_node.checked && _node.childNodes.length === 0) {
|
|
_checkList.push(_node)
|
|
}
|
|
// 通过new Set() 实现数据去重
|
|
checkList.value = Array.from(new Set(_checkList))
|
|
// 遍历子级,递归,直到获取最后一级的人员
|
|
if (_node.childNodes.length > 0) {
|
|
_node.childNodes.map(item => handleCheckList(item.data))
|
|
}
|
|
} else if (!_node.checked) { // 取消勾选
|
|
checkList.value = checkList.value.filter(item => item.checked)
|
|
}
|
|
}
|
|
|
|
/* 人员树 父级过滤的递归
|
|
* @node 当前节点
|
|
* @result 存结果的数组
|
|
* @key
|
|
* */
|
|
const getParentNode = (node, result, key) => {
|
|
let isPass = node?.data?.label?.indexOf(key) !== -1
|
|
isPass ? result.push(isPass) : ''
|
|
if (!isPass && node.level !== 1 && node.parent) {
|
|
return getParentNode(node.parent, result, key)
|
|
}
|
|
}
|
|
/*人员树过滤
|
|
* @value 过滤的关键字
|
|
* @data 被过滤的tree
|
|
* @node
|
|
* */
|
|
const filterNode = (value, data, node) => {
|
|
if (!value) {
|
|
data.disabled = false
|
|
return true
|
|
} else {
|
|
//带过滤条件时,所有父级都禁止勾选
|
|
// array.map(k => (!k.disabled) && (_childArr.push(k)))
|
|
(data.children) && (data.disabled = true)
|
|
}
|
|
let _arr = []
|
|
getParentNode(node, _arr, value)
|
|
let result = false
|
|
_arr.forEach(item => {
|
|
result = result || item
|
|
})
|
|
return result
|
|
}
|
|
// 通过tag 取消勾选
|
|
const handleCloseTag = (tag) => {
|
|
|
|
if (!treeRef?.value) return
|
|
checkList.value = checkList.value.filter(item => {
|
|
treeRef.value.setChecked(tag, false)
|
|
if (!item?.data) return
|
|
return item.data.id !== tag.data.id
|
|
})
|
|
}
|
|
|
|
// 清空CheckList
|
|
const clearCheckList = () => {
|
|
if (!treeRef?.value) return
|
|
treeRef.value.setCheckedKeys([])
|
|
while (checkList.value.length > 0) {
|
|
checkList.value.pop()
|
|
}
|
|
}
|
|
|
|
// 全选 /全不选
|
|
const handleCheckAll = (array) => {
|
|
treeRef.value.setCheckedNodes(array)
|
|
array.map(item => {
|
|
handleCheckList(item)
|
|
})
|
|
}
|
|
|
|
// 折叠/展开
|
|
const expandAll = () => {
|
|
const nodesMap = treeRef.value.store.nodesMap
|
|
for (let key in nodesMap) {
|
|
nodesMap[key].expanded = isExpandAll.value
|
|
}
|
|
}
|
|
|
|
// 执行tree数据过滤
|
|
watch(keyword, (newVal) => {
|
|
console.log(keyword)
|
|
console.log(newVal)
|
|
treeRef.value.filter(newVal)
|
|
})
|
|
|
|
|
|
//获取配置接口相应或获取固定选项值
|
|
if (transferConfig.value.transferDataSource === "固定选项") {
|
|
setTimeout(() => {
|
|
|
|
// 全选方法2:插入 全选node
|
|
userList.value = [{
|
|
id: '全选',
|
|
label: '全选',
|
|
children: props.data?.control.fixedOptions
|
|
}]
|
|
//console.log(treeRef)
|
|
/* console.log(checkedIdList.value) */
|
|
treeRef.value.setCheckedKeys(checkedIdList.value, true)
|
|
setTimeout(() => {
|
|
checkedIdList.value.forEach(element => {
|
|
const _node = treeRef?.value?.getNode(element)
|
|
if (!_node) return
|
|
const _checkList = checkList.value
|
|
if (_node.checked) { // 勾选时
|
|
if (_node.checked && _node.childNodes.length === 0) {
|
|
_checkList.push(_node)
|
|
}
|
|
// 通过new Set() 实现数据去重
|
|
checkList.value = Array.from(new Set(_checkList))
|
|
// 遍历子级,递归,直到获取最后一级的人员
|
|
if (_node.childNodes.length > 0) {
|
|
_node.childNodes.map(item => handleCheckList(item.data))
|
|
}
|
|
} else if (!_node.checked) { // 取消勾选
|
|
checkList.value = checkList.value.filter(item => item.checked)
|
|
}
|
|
});
|
|
}, 50);
|
|
}, 50);
|
|
dataFinished.value = true
|
|
} else {
|
|
getDetail
|
|
dataFinished.value = true
|
|
}
|
|
/* setTimeout(()=>{
|
|
console.log("setTimeout")
|
|
if(props.data?.config.transferDataSource==="数据源"){
|
|
//emits('reRenderComponent');
|
|
count1.value++
|
|
}
|
|
},1500) */
|
|
|
|
|
|
|
|
// 监听 checkedIdList 的变化
|
|
watch(checkedIdList, (newValue, oldValue) => {
|
|
//console.log('checkedIdList 发生了变化', newValue);
|
|
emits('checkedIdListChanged', newValue);
|
|
}, { deep: true });
|
|
|
|
let count1 = ref(0);
|
|
|
|
|
|
/* onBeforeMount(() => {
|
|
console.log('onBeforeMount: 组件即将挂载');
|
|
});
|
|
|
|
onMounted(() => {
|
|
console.log('onMounted: 组件已挂载');
|
|
});
|
|
onBeforeUpdate(() => {
|
|
console.log('onBeforeUpdate: 数据即将更新到 DOM');
|
|
|
|
|
|
});
|
|
|
|
onUpdated(() => {
|
|
console.log('onUpdated: DOM 已更新');
|
|
if(props.data?.config.transferDataSource==="数据源"){
|
|
console.log("emits('reRenderComponent');")
|
|
emits('reRenderComponent');
|
|
}
|
|
});
|
|
onBeforeUnmount(() => {
|
|
|
|
console.log('onBeforeUnmount: 组件即将卸载,清除定时器');
|
|
});
|
|
onUnmounted(() => {
|
|
console.log('onUnmounted: 组件已卸载');
|
|
}); */
|
|
|
|
watch(transferConfig, (newValue, oldValue) => {
|
|
|
|
count1.value++
|
|
|
|
//emits('reRenderComponent', newValue);
|
|
try {
|
|
|
|
count1.value++
|
|
if (newValue.transferDataSource === "数据源") {
|
|
emits('reRenderComponent');
|
|
|
|
|
|
getDetail().then(({ data }) => {
|
|
//console.log(`获取穿梭框接口数据`);
|
|
resData.value = data.children
|
|
// 全选方法2:插入 全选node
|
|
userList.value = [{
|
|
id: '全选',
|
|
label: '全选',
|
|
children: [...resData.value]
|
|
}]
|
|
treeRef.value.setCheckedKeys(checkedIdList.value, true)
|
|
setTimeout(() => {
|
|
checkedIdList.value.forEach(element => {
|
|
const _node = treeRef?.value?.getNode(element)
|
|
if (!_node) return
|
|
const _checkList = checkList.value
|
|
if (_node.checked) { // 勾选时
|
|
if (_node.checked && _node.childNodes.length === 0) {
|
|
_checkList.push(_node)
|
|
}
|
|
// 通过new Set() 实现数据去重
|
|
checkList.value = Array.from(new Set(_checkList))
|
|
// 遍历子级,递归,直到获取最后一级的人员
|
|
if (_node.childNodes.length > 0) {
|
|
_node.childNodes.map(item => handleCheckList(item.data))
|
|
}
|
|
} else if (!_node.checked) { // 取消勾选
|
|
checkList.value = checkList.value.filter(item => item.checked)
|
|
}
|
|
});
|
|
}, 50);
|
|
|
|
|
|
});
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Error :', error);
|
|
// 可以在这里进行一些错误处理,比如设置默认值或其他操作
|
|
//parsedData.value = null;
|
|
}
|
|
|
|
}, { deep: true });
|
|
|
|
|
|
watch(selectedValueCompu, (newValue, oldValue) => {
|
|
//console.log('selectedValueCompu 发生了变化', newValue);
|
|
checkedIdList.value = selectedValueCompu.value
|
|
//获取配置接口相应或获取固定选项值
|
|
if (transferConfig.value.transferDataSource === "固定选项") {
|
|
setTimeout(() => {
|
|
|
|
// 全选方法2:插入 全选node
|
|
userList.value = [{
|
|
id: '全选',
|
|
label: '全选',
|
|
children: props.data?.control.fixedOptions
|
|
}]
|
|
//console.log(treeRef)
|
|
/* console.log(checkedIdList.value) */
|
|
treeRef.value.setCheckedKeys(checkedIdList.value, true)
|
|
setTimeout(() => {
|
|
checkedIdList.value.forEach(element => {
|
|
const _node = treeRef?.value?.getNode(element)
|
|
if (!_node) return
|
|
const _checkList = checkList.value
|
|
if (_node.checked) { // 勾选时
|
|
if (_node.checked && _node.childNodes.length === 0) {
|
|
_checkList.push(_node)
|
|
}
|
|
// 通过new Set() 实现数据去重
|
|
checkList.value = Array.from(new Set(_checkList))
|
|
// 遍历子级,递归,直到获取最后一级的人员
|
|
if (_node.childNodes.length > 0) {
|
|
_node.childNodes.map(item => handleCheckList(item.data))
|
|
}
|
|
} else if (!_node.checked) { // 取消勾选
|
|
checkList.value = checkList.value.filter(item => item.checked)
|
|
}
|
|
});
|
|
}, 50);
|
|
}, 50);
|
|
dataFinished.value = true
|
|
} else {
|
|
getDetail
|
|
dataFinished.value = true
|
|
}
|
|
//emits('updateModel',newValue);
|
|
}, { deep: true });
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
.transfer {
|
|
display: flex;
|
|
|
|
|
|
}
|
|
|
|
|
|
.transferName {
|
|
height: 30px;
|
|
padding-top: 8px;
|
|
background-color: #F5F7FA;
|
|
padding-left: 10px;
|
|
border-radius: 5px 5px 0 0;
|
|
border-bottom: 1px solid gainsboro;
|
|
|
|
}
|
|
|
|
.buttonArea {
|
|
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
}
|
|
|
|
.buttonArea2 {
|
|
height: 33px;
|
|
}
|
|
|
|
.leftScroll {
|
|
height: 367px;
|
|
}
|
|
|
|
.leftArea {
|
|
border: 1px solid gainsboro;
|
|
width: 300px;
|
|
border-radius: 5px;
|
|
height: 456px;
|
|
position: relative;
|
|
background-color: white;
|
|
}
|
|
|
|
.rigthArea {
|
|
border: 1px solid gainsboro;
|
|
width: 300px;
|
|
border-radius: 5px;
|
|
height: 456px;
|
|
background-color: white;
|
|
|
|
}
|
|
</style>
|
|
|