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.
406 lines
11 KiB
406 lines
11 KiB
|
|
<script lang='ts' setup>
|
|
import { criteriaForPeopleList } from '@/api/hr/org/type'
|
|
import SvgIcon from '@/components/svgIcon/index.vue'
|
|
import { useAttrs,computed, onMounted, nextTick,ref,watch,onBeforeMount} from 'vue'
|
|
import request from '@/utils/axios/index'
|
|
const attrs = useAttrs()
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
modelValue?: string
|
|
disabled?: boolean
|
|
types?:number
|
|
control?:any
|
|
orgAndManTree?: any;
|
|
}>(),
|
|
{}
|
|
)
|
|
interface User {
|
|
id: number
|
|
name: string
|
|
number: string
|
|
key: string
|
|
icon: string
|
|
department: string
|
|
role: string
|
|
label: string
|
|
value: string
|
|
}
|
|
const emits = defineEmits<{
|
|
(e: 'update:modelValue', value: string): void
|
|
}>()
|
|
|
|
const value = ref([])
|
|
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(() => {
|
|
checkorgAndManTree()
|
|
setTimeout(()=>{
|
|
value.value = parseStringToArray(props.modelValue)
|
|
},500 )
|
|
})
|
|
|
|
|
|
|
|
const keys = computed(()=>{
|
|
if(attrs.queryBy == 'role'){
|
|
return attrs.roleRange
|
|
}else{
|
|
return attrs.orgRange
|
|
}
|
|
})
|
|
|
|
|
|
// 使用示例
|
|
const treeData = {
|
|
"id": "102",
|
|
"label": "企管部",
|
|
"parentId": "309",
|
|
"children": [
|
|
{
|
|
"id": "284148167597887488",
|
|
"label": "荣潇亭",
|
|
"parentId": "102",
|
|
"children": null,
|
|
"value": "303086",
|
|
"treeAttrs": null,
|
|
"disabled": null,
|
|
"type": null
|
|
},
|
|
{
|
|
"id": "272",
|
|
"label": "企管",
|
|
"parentId": "102",
|
|
"children": [
|
|
{
|
|
"id": "284148287831805952",
|
|
"label": "吴可楠",
|
|
"parentId": "272",
|
|
"children": null,
|
|
"value": "303122",
|
|
"treeAttrs": null,
|
|
"disabled": null,
|
|
"type": null
|
|
}
|
|
],
|
|
"value": null,
|
|
"treeAttrs": null,
|
|
"disabled": null,
|
|
"type": null
|
|
}
|
|
],
|
|
"value": null,
|
|
"treeAttrs": null,
|
|
"disabled": null,
|
|
"type": null
|
|
};
|
|
|
|
const idList = ["284148167597887488", "284148287831805952"];
|
|
|
|
const resData = ref()
|
|
|
|
const checkorgAndManTree = (()=>{
|
|
if(props.orgAndManTree&&props.orgAndManTree.children&&props.orgAndManTree.children.length>0){
|
|
//alert(1)
|
|
let arr = []
|
|
arr.push(modifyTreeData(props.orgAndManTree,keys.value))
|
|
|
|
resData.value = arr
|
|
}else{
|
|
setTimeout(()=>{
|
|
checkorgAndManTree()
|
|
},100)
|
|
}
|
|
})
|
|
|
|
|
|
|
|
const resultExample = [{
|
|
"id": "102",
|
|
"label": "企管部",
|
|
"parentId": "309",
|
|
"children": [
|
|
{
|
|
"id": "284148167597887488",
|
|
"label": "荣潇亭(303086)",
|
|
"parentId": "102",
|
|
"children": null,
|
|
"value": "303086",
|
|
"treeAttrs": null,
|
|
"disabled": null,
|
|
"type": null,
|
|
"number": "荣潇亭(303086)"
|
|
},
|
|
{
|
|
"id": "272",
|
|
"label": "企管",
|
|
"parentId": "102",
|
|
"children": [
|
|
{
|
|
"id": "284148287831805952",
|
|
"label": "吴可楠(303122)",
|
|
"parentId": "272",
|
|
"children": null,
|
|
"value": "303122",
|
|
"treeAttrs": null,
|
|
"disabled": null,
|
|
"type": null,
|
|
"number": "吴可楠(303122)"
|
|
}
|
|
],
|
|
"value": null,
|
|
"treeAttrs": null,
|
|
"disabled": null,
|
|
"type": null
|
|
}
|
|
],
|
|
"value": null,
|
|
"treeAttrs": null,
|
|
"disabled": null,
|
|
"type": null
|
|
}]
|
|
|
|
|
|
|
|
|
|
|
|
function modifyTreeData(treeData, idList) {
|
|
// 深拷贝树数据,避免修改原数据
|
|
const newTreeData = JSON.parse(JSON.stringify(treeData));
|
|
|
|
// 确保idList是一个数组
|
|
const idArray = Array.isArray(idList) ? idList : [idList];
|
|
if (idArray.length === 0) return Array.isArray(newTreeData) ? [] : null;
|
|
|
|
// 1. 收集所有节点,记录:id→节点映射、id→父节点id映射(检测多父节点)
|
|
const nodeMap = new Map(); // id → 节点
|
|
const parentMap = new Map(); // id → 父节点id(确保每个节点只有一个父节点)
|
|
const multiParentIds = new Set(); // 记录有多个父节点的id
|
|
|
|
function collectNodes(node, parentId) {
|
|
if (!node || typeof node !== 'object' || !node.id) return; // 跳过无效节点
|
|
|
|
// 记录节点映射
|
|
if (!nodeMap.has(node.id)) {
|
|
nodeMap.set(node.id, node);
|
|
}
|
|
|
|
// 记录父节点(检测多父节点)
|
|
if (parentMap.has(node.id)) {
|
|
// 已存在父节点,且与当前父节点不同 → 多父节点
|
|
if (parentMap.get(node.id) !== parentId) {
|
|
multiParentIds.add(node.id);
|
|
}
|
|
} else {
|
|
parentMap.set(node.id, parentId); // 首次记录父节点
|
|
}
|
|
|
|
// 递归处理子节点,传入当前节点id作为父节点id
|
|
if (node.children && Array.isArray(node.children)) {
|
|
node.children.forEach(child => collectNodes(child, node.id));
|
|
}
|
|
}
|
|
|
|
// 处理根节点(可能是单个节点或数组)
|
|
if (Array.isArray(newTreeData)) {
|
|
newTreeData.forEach(root => collectNodes(root, null)); // 根节点父id为null
|
|
} else {
|
|
collectNodes(newTreeData, null);
|
|
}
|
|
|
|
// 警告多父节点问题(核心重复原因)
|
|
if (multiParentIds.size > 0) {
|
|
console.warn(`以下节点存在多个父节点,可能导致重复:${Array.from(multiParentIds).join(', ')}`);
|
|
}
|
|
|
|
// 2. 收集需要保留的节点ID:目标节点+直系祖先(基于parentMap追溯,确保唯一路径)
|
|
const keepIds = new Set();
|
|
idArray.forEach(targetId => {
|
|
let currentId = targetId;
|
|
// 从目标节点向上追溯,直到根节点(parentId为null)
|
|
while (currentId !== null && nodeMap.has(currentId)) {
|
|
keepIds.add(currentId);
|
|
currentId = parentMap.get(currentId); // 基于唯一父节点追溯
|
|
}
|
|
});
|
|
|
|
// 3. 过滤树结构:仅保留keepIds中的节点,且严格校验子节点的parentId是否匹配当前父节点
|
|
function filterTree(node) {
|
|
if (!node || typeof node !== 'object' || !keepIds.has(node.id)) {
|
|
return null;
|
|
}
|
|
|
|
// 复制节点(避免修改原引用)
|
|
const filteredNode = { ...node };
|
|
|
|
// 处理子节点:仅保留符合条件的子节点(在keepIds中,且parentId等于当前节点id)
|
|
if (filteredNode.children && Array.isArray(filteredNode.children)) {
|
|
// 临时存储符合条件的子节点(去重)
|
|
const validChildren = new Map(); // 用id去重
|
|
|
|
filteredNode.children.forEach(child => {
|
|
// 校验:子节点必须在keepIds中,且其父节点id是当前节点id
|
|
if (child && typeof child === 'object' && child.id &&
|
|
keepIds.has(child.id) && parentMap.get(child.id) === filteredNode.id) {
|
|
const filteredChild = filterTree(child);
|
|
if (filteredChild) {
|
|
validChildren.set(filteredChild.id, filteredChild); // 用id去重
|
|
}
|
|
}
|
|
});
|
|
|
|
// 转为数组,保持原数据格式(空数组→null)
|
|
filteredNode.children = Array.from(validChildren.values());
|
|
if (filteredNode.children.length === 0) {
|
|
filteredNode.children = null;
|
|
}
|
|
} else {
|
|
filteredNode.children = null;
|
|
}
|
|
|
|
return filteredNode;
|
|
}
|
|
|
|
// 处理根节点(数组或单个节点)
|
|
let filteredTree;
|
|
if (Array.isArray(newTreeData)) {
|
|
// 根节点必须在keepIds中,且父节点为null
|
|
filteredTree = newTreeData
|
|
.map(root => {
|
|
if (root && keepIds.has(root.id) && parentMap.get(root.id) === null) {
|
|
return filterTree(root);
|
|
}
|
|
return null;
|
|
})
|
|
.filter(Boolean);
|
|
} else {
|
|
filteredTree = (keepIds.has(newTreeData.id) && parentMap.get(newTreeData.id) === null)
|
|
? filterTree(newTreeData)
|
|
: null;
|
|
}
|
|
|
|
// 4. 对目标节点修改label和添加number属性
|
|
function modifyLabels(node) {
|
|
if (!node || typeof node !== 'object') return;
|
|
|
|
if (idArray.includes(node.id)) {
|
|
const newLabel = `${node.label}(${node.value || ''})`;
|
|
node.label = newLabel;
|
|
node.number = newLabel;
|
|
}
|
|
|
|
if (node.children && Array.isArray(node.children)) {
|
|
node.children.forEach(child => modifyLabels(child));
|
|
}
|
|
}
|
|
|
|
// 执行标签修改
|
|
if (Array.isArray(filteredTree)) {
|
|
filteredTree.forEach(root => modifyLabels(root));
|
|
} else {
|
|
modifyLabels(filteredTree);
|
|
}
|
|
|
|
return filteredTree;
|
|
}
|
|
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 />
|
|
<el-text v-else class="wordColor">{{valPrint(value)}}</el-text>
|
|
</template>
|
|
<style lang='scss' >
|
|
.wordColor{
|
|
color:#000000;
|
|
}
|
|
|
|
|
|
|
|
/* ::v-deep .el-tree-node__expand-icon {
|
|
|
|
font-size: 38px;
|
|
|
|
width: 34px;
|
|
height: 34px;
|
|
line-height: 34px;
|
|
}
|
|
|
|
|
|
::v-deep .el-tree-node__expand-icon::before {
|
|
font-size: 38px;
|
|
}
|
|
*/
|
|
|
|
.el-tree-node__expand-icon {
|
|
color: var(--el-tree-expand-icon-color);
|
|
cursor: pointer;
|
|
font-size: 18px;
|
|
transform: rotate(0deg);
|
|
transition: transform var(--el-transition-duration) ease-in-out;
|
|
}
|
|
|
|
.el-tree {
|
|
--el-tree-node-content-height: 30px;
|
|
--el-tree-node-hover-bg-color: var(--el-fill-color-light);
|
|
--el-tree-text-color: var(--el-text-color-regular);
|
|
--el-tree-expand-icon-color: var(--el-text-color-placeholder);
|
|
background: var(--el-fill-color-blank);
|
|
color: var(--el-tree-text-color);
|
|
cursor: default;
|
|
font-size: var(--el-font-size-base);
|
|
position: relative;
|
|
}
|
|
|
|
.el-tree-select__popper .el-tree-node__expand-icon {
|
|
margin-left: 7px;
|
|
margin-right: 7px;
|
|
}
|
|
</style>
|