|
|
@ -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<{ |
|
|
const emits = defineEmits<{ |
|
|
(e: 'update:modelValue', value: string): void |
|
|
(e: 'update:modelValue', value: string): void |
|
|
}>() |
|
|
}>() |
|
|
|
|
|
|
|
|
const value = ref([]) |
|
|
const value = ref([]) |
|
|
const loading = ref(true) |
|
|
|
|
|
watch(value,(newValue)=>{ |
|
|
watch(value,(newValue)=>{ |
|
|
if(newValue.length > 0){ |
|
|
if(newValue.length > 0){ |
|
|
let str = "" |
|
|
let str = "" |
|
|
@ -56,6 +43,8 @@ watch(value,(newValue)=>{ |
|
|
} |
|
|
} |
|
|
},{ deep: true }) |
|
|
},{ deep: true }) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function parseStringToArray(str:string) { |
|
|
function parseStringToArray(str:string) { |
|
|
try { |
|
|
try { |
|
|
// 尝试解析JSON格式字符串 |
|
|
// 尝试解析JSON格式字符串 |
|
|
@ -73,17 +62,14 @@ function parseStringToArray(str:string) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
onBeforeMount(() => { |
|
|
onBeforeMount(() => { |
|
|
// 启动检查 |
|
|
checkorgAndManTree() |
|
|
//checkReady() |
|
|
|
|
|
|
|
|
|
|
|
//getTree() |
|
|
|
|
|
setTimeout(()=>{ |
|
|
setTimeout(()=>{ |
|
|
value.value = parseStringToArray(props.modelValue) |
|
|
value.value = parseStringToArray(props.modelValue) |
|
|
},500 ) |
|
|
},500 ) |
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
|
const url = "/javasys/lowCode/manCont/getManContsByKeys" |
|
|
|
|
|
//console.log(attrs.value) |
|
|
|
|
|
const keys = computed(()=>{ |
|
|
const keys = computed(()=>{ |
|
|
if(attrs.queryBy == 'role'){ |
|
|
if(attrs.queryBy == 'role'){ |
|
|
return attrs.roleRange |
|
|
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) { |
|
|
const treeData = { |
|
|
if (!node) { |
|
|
"id": "102", |
|
|
//console.log(`跳过无效节点: ${node}`); |
|
|
"label": "企管部", |
|
|
return; |
|
|
"parentId": "309", |
|
|
} |
|
|
"children": [ |
|
|
// 记录当前节点信息(方便调试) |
|
|
{ |
|
|
//console.log(`收集节点 [层级${level}]: id=${node.id}, label=${node.label}`); |
|
|
"id": "284148167597887488", |
|
|
// 必须有id才存入映射表(避免非节点元素) |
|
|
"label": "荣潇亭", |
|
|
if (node.id !== undefined && node.id !== null) { |
|
|
"parentId": "102", |
|
|
nodeMap[node.id] = node; |
|
|
"children": null, |
|
|
} else { |
|
|
"value": "303086", |
|
|
//console.warn(`节点缺少id,跳过:`, node); |
|
|
"treeAttrs": null, |
|
|
} |
|
|
"disabled": null, |
|
|
// 处理子节点(确保是数组,且元素有效) |
|
|
"type": null |
|
|
if (Array.isArray(node.children)) { |
|
|
}, |
|
|
node.children.forEach((child, index) => { |
|
|
{ |
|
|
collectNodes(child, level + 1); // 层级+1,方便查看嵌套关系 |
|
|
"id": "272", |
|
|
}); |
|
|
"label": "企管", |
|
|
} else if (node.children !== null && node.children !== undefined) { |
|
|
"parentId": "102", |
|
|
//console.warn(`节点children不是数组,跳过:`, node.children); |
|
|
"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 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* const resData = computed(()=>{ |
|
|
loading.value = false |
|
|
if(props.orgAndManTree&&props.orgAndManTree.children&&props.orgAndManTree.children.length>0){ |
|
|
return enrichTreeWithEmployeeInfo(options.value, data2) |
|
|
console.log(11111) |
|
|
|
|
|
let arr = [] |
|
|
|
|
|
arr.push(modifyTreeData(props.orgAndManTree,keys.value)) |
|
|
|
|
|
return arr |
|
|
}else{ |
|
|
}else{ |
|
|
return [] |
|
|
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(); |
|
|
|
|
|
|
|
|
|
|
|
// 递归函数:检查节点及其子节点是否需要保留 |
|
|
const resultExample = [{ |
|
|
function processNode(node: { id: any; value: unknown; children: string | any[] | null; }) { |
|
|
"id": "102", |
|
|
// 使用节点的id作为唯一标识,避免重复处理 |
|
|
"label": "企管部", |
|
|
const nodeId = node.id; |
|
|
"parentId": "309", |
|
|
if (visitedNodes.has(nodeId)) { |
|
|
"children": [ |
|
|
return false; // 如果已经访问过这个节点,直接返回false |
|
|
{ |
|
|
|
|
|
"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, |
|
|
visitedNodes.add(nodeId); |
|
|
"treeAttrs": null, |
|
|
|
|
|
"disabled": null, |
|
|
// 标记当前节点是否直接匹配 |
|
|
"type": null |
|
|
const isDirectMatch = node.value && numberSet.has(node.value); |
|
|
}] |
|
|
|
|
|
|
|
|
// 如果没有children属性或为null,直接返回是否直接匹配 |
|
|
|
|
|
if (!node.children || node.children === null) { |
|
|
|
|
|
return isDirectMatch; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 = []; |
|
|
if (parentMap.has(node.id)) { |
|
|
|
|
|
// 已存在父节点,且与当前父节点不同 → 多父节点 |
|
|
// 遍历所有子节点 |
|
|
if (parentMap.get(node.id) !== parentId) { |
|
|
for (let i = 0; i < node.children.length; i++) { |
|
|
multiParentIds.add(node.id); |
|
|
const child = node.children[i]; |
|
|
|
|
|
// 递归检查子节点 |
|
|
|
|
|
if (processNode(child)) { |
|
|
|
|
|
// 只有当子节点需要保留时,才将其添加到childrenToKeep数组中 |
|
|
|
|
|
childrenToKeep.push(child); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
parentMap.set(node.id, parentId); // 首次记录父节点 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 更新当前节点的children数组,只保留需要的子节点 |
|
|
// 递归处理子节点,传入当前节点id作为父节点id |
|
|
node.children = childrenToKeep; |
|
|
if (node.children && Array.isArray(node.children)) { |
|
|
|
|
|
node.children.forEach(child => collectNodes(child, node.id)); |
|
|
// 返回当前节点是否应该保留(直接匹配或者有匹配的子节点) |
|
|
|
|
|
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); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return result; |
|
|
// 处理根节点(可能是单个节点或数组) |
|
|
} |
|
|
if (Array.isArray(newTreeData)) { |
|
|
|
|
|
newTreeData.forEach(root => collectNodes(root, null)); // 根节点父id为null |
|
|
|
|
|
} else { |
|
|
|
|
|
collectNodes(newTreeData, null); |
|
|
/** |
|
|
|
|
|
* 将 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 (treeData && treeData.length > 0) { |
|
|
if (multiParentIds.size > 0) { |
|
|
traverse(treeData); |
|
|
console.warn(`以下节点存在多个父节点,可能导致重复:${Array.from(multiParentIds).join(', ')}`); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return treeData; |
|
|
// 2. 收集需要保留的节点ID:目标节点+直系祖先(基于parentMap追溯,确保唯一路径) |
|
|
} |
|
|
const keepIds = new Set(); |
|
|
|
|
|
idArray.forEach(targetId => { |
|
|
function processTreeData(node: any) { |
|
|
let currentId = targetId; |
|
|
|
|
|
// 从目标节点向上追溯,直到根节点(parentId为null) |
|
|
// 检查节点及其所有子孙节点中是否存在id长度大于4的节点 |
|
|
while (currentId !== null && nodeMap.has(currentId)) { |
|
|
function hasLongIdNode(node: { id: string | any[]; children: string | any[]; }) { |
|
|
keepIds.add(currentId); |
|
|
// 检查当前节点id长度 |
|
|
currentId = parentMap.get(currentId); // 基于唯一父节点追溯 |
|
|
if (node.id && node.id.length > 4) { |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
}); |
|
|
// 处理子节点(考虑children为null的情况) |
|
|
|
|
|
if (node.children && Array.isArray(node.children) && node.children.length > 0) { |
|
|
// 3. 过滤树结构:仅保留keepIds中的节点,且严格校验子节点的parentId是否匹配当前父节点 |
|
|
for (const child of node.children) { |
|
|
function filterTree(node) { |
|
|
if (hasLongIdNode(child)) { |
|
|
if (!node || typeof node !== 'object' || !keepIds.has(node.id)) { |
|
|
return true; |
|
|
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) { |
|
|
let filteredTree; |
|
|
// 如果当前节点及其所有子孙都没有长id,则移除该节点 |
|
|
if (Array.isArray(newTreeData)) { |
|
|
if (!hasLongIdNode(node)) { |
|
|
// 根节点必须在keepIds中,且父节点为null |
|
|
return 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)) { |
|
|
const newNode = { ...node }; |
|
|
node.children.forEach(child => modifyLabels(child)); |
|
|
|
|
|
|
|
|
// 处理子节点 |
|
|
|
|
|
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; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return newNode; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return processNode(node); |
|
|
// 执行标签修改 |
|
|
|
|
|
if (Array.isArray(filteredTree)) { |
|
|
|
|
|
filteredTree.forEach(root => modifyLabels(root)); |
|
|
|
|
|
} else { |
|
|
|
|
|
modifyLabels(filteredTree); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return filteredTree; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</script> |
|
|
</script> |
|
|
<template> |
|
|
<template> |
|
|
|
|
|
|
|
|
|