diff --git a/src/components/DesignForm/public/expand/rangedUserTree.vue b/src/components/DesignForm/public/expand/rangedUserTree.vue index 901d947..bce5ecb 100644 --- a/src/components/DesignForm/public/expand/rangedUserTree.vue +++ b/src/components/DesignForm/public/expand/rangedUserTree.vue @@ -15,24 +15,11 @@ const props = withDefaults( ) - -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([]) -const loading = ref(true) watch(value,(newValue)=>{ if(newValue.length > 0){ let str = "" @@ -56,6 +43,8 @@ watch(value,(newValue)=>{ } },{ deep: true }) + + function parseStringToArray(str:string) { try { // 尝试解析JSON格式字符串 @@ -73,17 +62,14 @@ function parseStringToArray(str:string) { } } onBeforeMount(() => { - // 启动检查 - //checkReady() - - //getTree() + checkorgAndManTree() setTimeout(()=>{ value.value = parseStringToArray(props.modelValue) },500 ) }) -const url = "/javasys/lowCode/manCont/getManContsByKeys" -//console.log(attrs.value) + + const keys = computed(()=>{ if(attrs.queryBy == 'role'){ return attrs.roleRange @@ -92,295 +78,273 @@ const keys = computed(()=>{ } }) -const options = ref([]) -const convertToAFormatComplate = ref(false) -function convertToAFormat(bTree, idArray) { - const nodeMap = {}; - // 递归收集节点,增加详细日志 - function collectNodes(node, level = 0) { - if (!node) { - //console.log(`跳过无效节点: ${node}`); - return; - } - // 记录当前节点信息(方便调试) - //console.log(`收集节点 [层级${level}]: id=${node.id}, label=${node.label}`); - // 必须有id才存入映射表(避免非节点元素) - if (node.id !== undefined && node.id !== null) { - nodeMap[node.id] = node; - } else { - //console.warn(`节点缺少id,跳过:`, node); - } - // 处理子节点(确保是数组,且元素有效) - if (Array.isArray(node.children)) { - node.children.forEach((child, index) => { - collectNodes(child, level + 1); // 层级+1,方便查看嵌套关系 - }); - } else if (node.children !== null && node.children !== undefined) { - //console.warn(`节点children不是数组,跳过:`, node.children); +// 使用示例 +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) } +}) - // 处理根节点(兼容数组或单个对象) - if (Array.isArray(bTree)) { - //console.log(`bTree是数组,共${bTree.length}个根节点`); - bTree.forEach((root, index) => { - //console.log(`处理根节点${index + 1}`); - collectNodes(root); - }); - } else { - //console.log(`bTree是单个根节点`); - collectNodes(bTree); - } - - // 打印收集到的所有节点id(关键调试信息) - //console.log(`收集到的节点id列表:`, Object.keys(nodeMap)); - - // 匹配idArray并转换 - const result = idArray.map(id => { - // 打印当前匹配的id,检查是否在nodeMap中 - //console.log(`匹配id: ${id},是否存在: ${id in nodeMap}`); - const targetNode = nodeMap[id]; - if (!targetNode) return null; - - return { - id: targetNode.id, - number: targetNode.value ?? '', // 用空字符串替代null/undefined - name: targetNode.label ?? '', - icon: null, - key: String(targetNode.id), // 确保key是字符串(与a格式一致) - role: '', - deparment: '', - parentId: targetNode.parentId ?? '' - }; - }).filter(Boolean); - - //console.log(`最终转换结果:`, result); - convertToAFormatComplate.value = true - return result; -} - -function getManConts(){ - - - let data = convertToAFormat(props.orgAndManTree,keys.value) - data.forEach((element: any) => { - element.icon = element.name+"("+element.number+")" - element.deparment = ""+element.deparment+">"+element.icon - element.label = element.deparment - element.value = element.icon - }); - options.value = data - - -} - -/** -@ 作者: 秦东 -@ 时间: 2025-06-10 11:13:06 -@ 功能: 输出结果 -*/ -const valPrint = (val:any) => { - - if(Array.isArray(val)){ - return val.join("、") - } - -} - - - -const resData = computed(()=>{ - if(props.orgAndManTree){ - let data1 = processTreeData(props.orgAndManTree) - //console.log(data1) - getManConts() - - let data2 = filterTreeByList(data1.children, options.value) - data1.children = data2 - - loading.value = false - return enrichTreeWithEmployeeInfo(options.value, data2) +/* const resData = computed(()=>{ + if(props.orgAndManTree&&props.orgAndManTree.children&&props.orgAndManTree.children.length>0){ + console.log(11111) + let arr = [] + arr.push(modifyTreeData(props.orgAndManTree,keys.value)) + return arr }else{ return [] } - - }) - -/** - * 根据列表数据过滤树形数据,保留value值在列表number中匹配的节点及其祖先 - * @param {Array} treeData - 树形数据 - * @param {Array} listData - 列表数据 - * @returns {Array} 过滤后的树形数据 */ -function filterTreeByList(treeData: string | any[], listData: any[]) { - // 提取列表中的number值,用于快速查找 - const numberSet = new Set(); - listData.forEach((item: { number: unknown; }) => { - numberSet.add(item.number); - }); - - // 用于追踪已访问的节点,避免重复 - const visitedNodes = new Set(); - // 递归函数:检查节点及其子节点是否需要保留 - function processNode(node: { id: any; value: unknown; children: string | any[] | null; }) { - // 使用节点的id作为唯一标识,避免重复处理 - const nodeId = node.id; - if (visitedNodes.has(nodeId)) { - return false; // 如果已经访问过这个节点,直接返回false +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 } - - // 标记当前节点已访问 - visitedNodes.add(nodeId); - - // 标记当前节点是否直接匹配 - const isDirectMatch = node.value && numberSet.has(node.value); - - // 如果没有children属性或为null,直接返回是否直接匹配 - if (!node.children || node.children === null) { - return isDirectMatch; + ], + "value": null, + "treeAttrs": null, + "disabled": null, + "type": null +}] + + + + + +function modifyTreeData(treeData, idList) { + console.log("modifyTreeData 执行了") + // 深拷贝树数据,避免修改原数据 + 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); } - - // 临时存储需要保留的子节点 - const childrenToKeep = []; - - // 遍历所有子节点 - for (let i = 0; i < node.children.length; i++) { - const child = node.children[i]; - // 递归检查子节点 - if (processNode(child)) { - // 只有当子节点需要保留时,才将其添加到childrenToKeep数组中 - childrenToKeep.push(child); + + // 记录父节点(检测多父节点) + if (parentMap.has(node.id)) { + // 已存在父节点,且与当前父节点不同 → 多父节点 + if (parentMap.get(node.id) !== parentId) { + multiParentIds.add(node.id); } + } else { + parentMap.set(node.id, parentId); // 首次记录父节点 } - - // 更新当前节点的children数组,只保留需要的子节点 - node.children = childrenToKeep; - - // 返回当前节点是否应该保留(直接匹配或者有匹配的子节点) - return isDirectMatch || childrenToKeep.length > 0; - } - - // 处理每个根节点 - const result = []; - for (let i = 0; i < treeData.length; i++) { - // 创建节点副本以避免修改原始数据 - const nodeCopy = JSON.parse(JSON.stringify(treeData[i])); - if (processNode(nodeCopy)) { - result.push(nodeCopy); + + // 递归处理子节点,传入当前节点id作为父节点id + if (node.children && Array.isArray(node.children)) { + node.children.forEach(child => collectNodes(child, node.id)); } } - - return result; -} - - - -/** - * 将 a 类型员工数据映射到树形结构中,为匹配的节点添加 number、role、deparment、empType 属性 - * @param {Array} employees - a 类型员工数组,每个元素包含 number, name, role, deparment, empType, key 等字段 - * @param {Array} treeData - 树形结构数据(可能包含嵌套的 children) - * @returns {Array} - 更新后的树形结构 - */ -function enrichTreeWithEmployeeInfo(employees: any[], treeData: string | any[]) { - // 构建以 value 为 key 的员工信息映射表,便于快速查找 - const employeeMap = new Map(); - employees.forEach((emp: { number: any; }) => { - employeeMap.set(emp.number, emp); // 注意:树节点用 value 字段匹配 a 类型的 number - }); - - // 递归处理树节点 - function traverse(nodes: any[]) { - if (!Array.isArray(nodes)) return; - - nodes.forEach(node => { - // 如果当前节点有 value(即叶子员工节点) - if (node.value !== null && node.value !== undefined) { - const emp = employeeMap.get(node.value); - if (emp) { - // 添加 a 类型中的字段到树节点 - node.label = node.label + "(" + emp.number + ")"; - node.number = node.label - node.role = emp.role; - node.deparment = emp.deparment; - node.empType = emp.empType; - // 可选:也可以添加 name、key 等其他字段 - // node.name = emp.name; - // node.key = emp.key; - } - } - - // 递归处理子节点 - if (Array.isArray(node.children)) { - traverse(node.children); - } - }); + + // 处理根节点(可能是单个节点或数组) + if (Array.isArray(newTreeData)) { + newTreeData.forEach(root => collectNodes(root, null)); // 根节点父id为null + } else { + collectNodes(newTreeData, null); } - - // 处理根节点(注意:你的树外层有个 "全选" 节点) - if (treeData && treeData.length > 0) { - traverse(treeData); + + // 警告多父节点问题(核心重复原因) + if (multiParentIds.size > 0) { + console.warn(`以下节点存在多个父节点,可能导致重复:${Array.from(multiParentIds).join(', ')}`); } - - return treeData; -} - -function processTreeData(node: any) { - - // 检查节点及其所有子孙节点中是否存在id长度大于4的节点 - function hasLongIdNode(node: { id: string | any[]; children: string | any[]; }) { - // 检查当前节点id长度 - if (node.id && node.id.length > 4) { - return true; + + // 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); // 基于唯一父节点追溯 } - - // 处理子节点(考虑children为null的情况) - if (node.children && Array.isArray(node.children) && node.children.length > 0) { - for (const child of node.children) { - if (hasLongIdNode(child)) { - return true; + }); + + // 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 false; + + return filteredNode; } - - // 递归处理节点 - function processNode(node: any) { - // 如果当前节点及其所有子孙都没有长id,则移除该节点 - if (!hasLongIdNode(node)) { - return null; + + // 处理根节点(数组或单个节点) + 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; } - - // 复制节点避免修改原对象 - const newNode = { ...node }; - - // 处理子节点 - if (newNode.children && Array.isArray(newNode.children) && newNode.children.length > 0) { - // 递归处理每个子节点并过滤掉需要移除的 - newNode.children = newNode.children - .map((child: any) => processNode(child)) - .filter((child: null) => child !== null); - - // 如果所有子节点都被移除,保持children为null - if (newNode.children.length === 0) { - newNode.children = null; - } + + if (node.children && Array.isArray(node.children)) { + node.children.forEach(child => modifyLabels(child)); } - - return newNode; } - - return processNode(node); + + // 执行标签修改 + if (Array.isArray(filteredTree)) { + filteredTree.forEach(root => modifyLabels(root)); + } else { + modifyLabels(filteredTree); + } + + return filteredTree; } - -