|
|
|
@ -1,6 +1,4 @@ |
|
|
|
|
|
|
|
<script lang='ts' setup> |
|
|
|
|
|
|
|
import { computed, ref, watch, onBeforeMount } from 'vue' |
|
|
|
|
|
|
|
const props = withDefaults( |
|
|
|
@ -20,57 +18,75 @@ const emits = defineEmits<{ |
|
|
|
}>() |
|
|
|
|
|
|
|
const value = ref([]) |
|
|
|
const treeData = ref([]) // 存储懒加载的数据 |
|
|
|
const isDataLoaded = ref(false) // 标记数据是否已加载 |
|
|
|
|
|
|
|
watch(value, (newValue) => { |
|
|
|
if (newValue.length > 0) { |
|
|
|
let str = "" |
|
|
|
|
|
|
|
let userAry = new Array |
|
|
|
|
|
|
|
newValue.forEach(item => { |
|
|
|
//console.log(item) |
|
|
|
userAry.push(item) |
|
|
|
|
|
|
|
}) |
|
|
|
str = userAry.join(',') |
|
|
|
//console.log(str) |
|
|
|
emits('update:modelValue', str) |
|
|
|
// userlist.value = userAry.join(',') |
|
|
|
// |
|
|
|
} else { |
|
|
|
let str = "" |
|
|
|
//console.log(str) |
|
|
|
emits('update:modelValue', str) |
|
|
|
} |
|
|
|
}, { deep: true }) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function parseStringToArray(str: string) { |
|
|
|
try { |
|
|
|
// 尝试解析JSON格式字符串 |
|
|
|
const result = JSON.parse(str); |
|
|
|
// 验证解析结果是否为数组 |
|
|
|
if (Array.isArray(result)) { |
|
|
|
return result; |
|
|
|
} else { |
|
|
|
//console.error("解析结果不是数组"); |
|
|
|
return []; |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
//console.error("字符串格式错误,无法解析为数组:", error.message); |
|
|
|
return []; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
onBeforeMount(() => { |
|
|
|
setTimeout(() => { |
|
|
|
value.value = parseStringToArray(props.modelValue) |
|
|
|
}, 500) |
|
|
|
}) |
|
|
|
|
|
|
|
// 加载完整数据的函数 |
|
|
|
const loadFullData = async () => { |
|
|
|
if (isDataLoaded.value) return treeData.value; |
|
|
|
|
|
|
|
try { |
|
|
|
const result = checkorgAndManTree1(); |
|
|
|
treeData.value = result; |
|
|
|
isDataLoaded.value = true; |
|
|
|
return result; |
|
|
|
} catch (error) { |
|
|
|
console.error('加载组织数据失败:', error); |
|
|
|
return []; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 点击树选择器时的处理 |
|
|
|
const handleTreeSelectClick = async () => { |
|
|
|
if (!isDataLoaded.value) { |
|
|
|
await loadFullData(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 下拉框显示状态变化时的处理 |
|
|
|
const handleVisibleChange = async (visible: boolean) => { |
|
|
|
if (visible && !isDataLoaded.value) { |
|
|
|
await loadFullData(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const resData = computed(() => { |
|
|
|
return checkorgAndManTree1() |
|
|
|
return treeData.value; |
|
|
|
}) |
|
|
|
|
|
|
|
function checkorgAndManTree1() { |
|
|
|
@ -83,12 +99,10 @@ function checkorgAndManTree1(){ |
|
|
|
}); |
|
|
|
if (i == props.orgAndManTree.length) { |
|
|
|
props.orgAndManTree.forEach((item: any) => { |
|
|
|
|
|
|
|
if (props.data.name == item.name) { |
|
|
|
console.log(item.tree) |
|
|
|
result = item.tree |
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
return result |
|
|
|
} else { |
|
|
|
@ -96,75 +110,78 @@ function checkorgAndManTree1(){ |
|
|
|
checkorgAndManTree1() |
|
|
|
}, 100) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 判断树形结构是否存在节点 |
|
|
|
* @param {Array} tree 树形结构数组(最外层为数组,每个节点可能包含children属性) |
|
|
|
* @returns {boolean} 存在节点返回true,否则返回false |
|
|
|
*/ |
|
|
|
function hasNodesInTree(tree) { |
|
|
|
// 边界条件:如果输入不是数组,直接返回false |
|
|
|
if (!Array.isArray(tree)) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// 递归检查节点及其子节点 |
|
|
|
function checkNode(node) { |
|
|
|
// 节点本身存在(非null/undefined)即算一个节点 |
|
|
|
if (node == null) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
// 只要当前节点存在,就返回true |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
// 遍历根节点数组,只要有一个节点存在,就返回true |
|
|
|
for (const node of tree) { |
|
|
|
if (checkNode(node)) { |
|
|
|
// 即使当前节点没有子节点,自身也算一个节点 |
|
|
|
return true; |
|
|
|
} |
|
|
|
// 如果当前节点有子节点,递归检查子节点(防止极端情况:当前节点为空但子节点存在) |
|
|
|
if (Array.isArray(node?.children) && hasNodesInTree(node.children)) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 所有层级都没有节点 |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const valPrint = (val: any) => { |
|
|
|
|
|
|
|
if (Array.isArray(val)) { |
|
|
|
return val.join("、") |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
</script> |
|
|
|
|
|
|
|
<template> |
|
|
|
<div></div> |
|
|
|
|
|
|
|
<el-tree-select v-if="props.types!=3" node-key="number" v-model="value" :data="resData" multiple :render-after-expand="false" |
|
|
|
show-checkbox clearable collapse-tags collapse-tags-tooltip :max-collapse-tags="1" filterable /> |
|
|
|
<div class="tree-select-wrapper" v-if="props.types != 3"> |
|
|
|
<el-tree-select |
|
|
|
node-key="number" |
|
|
|
v-model="value" |
|
|
|
:data="resData" |
|
|
|
multiple |
|
|
|
:render-after-expand="false" |
|
|
|
show-checkbox |
|
|
|
clearable |
|
|
|
collapse-tags |
|
|
|
collapse-tags-tooltip |
|
|
|
:max-collapse-tags="1" |
|
|
|
filterable |
|
|
|
@click="handleTreeSelectClick" |
|
|
|
@visible-change="handleVisibleChange" |
|
|
|
:disabled="props.disabled" |
|
|
|
:popper-append-to-body="false" |
|
|
|
/> |
|
|
|
</div> |
|
|
|
<el-text v-else class="wordColor">{{ valPrint(value) }}</el-text> |
|
|
|
</template> |
|
|
|
|
|
|
|
<style lang='scss'> |
|
|
|
.tree-select-wrapper { |
|
|
|
position: relative; |
|
|
|
min-height: 40px; |
|
|
|
width: 100%; |
|
|
|
} |
|
|
|
|
|
|
|
.wordColor { |
|
|
|
color: #000000; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.el-tree-node__expand-icon { |
|
|
|
color: var(--el-tree-expand-icon-color); |
|
|
|
cursor: pointer; |
|
|
|
|