From 29cc6fd0588b9b52db7d1c955a66450826cf6232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=98=89=E8=B1=AA?= <42510293+ziyujiahao@users.noreply.github.com> Date: Wed, 21 Jan 2026 11:26:26 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=A4=96=E9=83=A8=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E4=BD=BF=E7=94=A8=E8=BF=87=E6=BB=A4=E9=80=89=E9=A1=B9?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E6=94=AF=E6=8C=81=E5=85=B3=E8=81=94=E8=BF=87?= =?UTF-8?q?=E6=BB=A4=E7=BB=84=E4=BB=B6=E7=9A=84=E5=9B=BE=E8=A1=A8=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E8=BF=87=E6=BB=A4=E9=80=89=E9=A1=B9=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=20(#17846)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/custom-component/v-query/Tree.vue | 98 +++++++++++++++---- core/core-frontend/src/hooks/web/useFilter.ts | 17 +++- .../modules/data-visualization/dvMain.ts | 8 +- 3 files changed, 100 insertions(+), 23 deletions(-) diff --git a/core/core-frontend/src/custom-component/v-query/Tree.vue b/core/core-frontend/src/custom-component/v-query/Tree.vue index e68c9727ae..44d7cabda8 100644 --- a/core/core-frontend/src/custom-component/v-query/Tree.vue +++ b/core/core-frontend/src/custom-component/v-query/Tree.vue @@ -396,35 +396,93 @@ const tagColor = computed(() => { .toRGB() }) -const filterTree = (treeData, filterIds) => { +function filterTree(treeData, filterIds) { if (!filterIds || filterIds.length === 0) { return treeData } - const filterIdSet = new Set(filterIds) - // 递归处理每个节点 - const recursionFilter = node => { - const newNode = { ...node } + const filterSet = new Set(filterIds) - // 2. 处理子节点:有子节点才过滤,无子节点直接返回当前节点 - if (newNode.children && Array.isArray(newNode.children) && newNode.children.length > 0) { - // 筛选出当前节点的子节点中,id在过滤清单里的「命中子节点」 - const hitChildren = newNode.children.filter(child => filterIdSet.has(child.id)) + // 用于存储最终保留的所有节点ID + const keepIds = new Set() - if (hitChildren.length > 0) { - // 规则1:当前层级有命中的子节点 → 只保留命中的,递归过滤其子节点 - newNode.children = hitChildren.map(child => recursionFilter(child)) - } else { - // 规则2:当前层级无命中的子节点 → 完整保留所有子节点,子节点也不做过滤 - newNode.children = [...newNode.children] + // 用于查找节点的Map + const nodeMap = new Map() + // 用于构建节点关系的Map(子节点到父节点) + const parentMap = new Map() + + // 遍历所有节点,构建Map和父子关系 + function traverse(nodes, parentId = null) { + for (const node of nodes) { + nodeMap.set(node.id, node) + if (parentId) { + parentMap.set(node.id, parentId) + } + + // 递归处理子节点 + if (node.children && node.children.length > 0) { + traverse(node.children, node.id) } } - return newNode } - // 根节点过滤:只保留根节点id在过滤清单中的节点,再递归处理子节点 - return treeData - .filter(rootNode => filterIdSet.has(rootNode.id)) - .map(node => recursionFilter(node)) + // 收集所有匹配的节点及其祖先和后代 + function collectRelatedNodes(nodeId) { + if (keepIds.has(nodeId)) return + + keepIds.add(nodeId) + const node = nodeMap.get(nodeId) + + // 1. 收集所有祖先节点 + let currentId = nodeId + while (parentMap.has(currentId)) { + const parentId = parentMap.get(currentId) + keepIds.add(parentId) + currentId = parentId + } + + // 2. 收集所有后代节点(递归) + function collectDescendants(node) { + if (node.children && node.children.length > 0) { + for (const child of node.children) { + keepIds.add(child.id) + collectDescendants(child) + } + } + } + collectDescendants(node) + } + + // 第二步:递归构建过滤后的树 + function buildFilteredTree(nodes) { + const result = [] + + for (const node of nodes) { + // 如果节点ID在保留集合中,则保留该节点 + if (keepIds.has(node.id)) { + const newNode = { ...node } + + // 递归处理子节点 + if (newNode.children && newNode.children.length > 0) { + newNode.children = buildFilteredTree(newNode.children) + } + + result.push(newNode) + } + } + + return result + } + + // 执行遍历和构建 + traverse(treeData) + + for (const filterId of filterIds) { + if (nodeMap.has(filterId)) { + collectRelatedNodes(filterId) + } + } + + return buildFilteredTree(treeData) } diff --git a/core/core-frontend/src/hooks/web/useFilter.ts b/core/core-frontend/src/hooks/web/useFilter.ts index 7fb9b980af..120549b029 100644 --- a/core/core-frontend/src/hooks/web/useFilter.ts +++ b/core/core-frontend/src/hooks/web/useFilter.ts @@ -369,12 +369,25 @@ export const searchQuery = (queryComponentList, filter, curComponentId, firstLoa const isTree = +displayType === 9 if (optionFilter) { + let fieldIdOption = item.checkedFieldsMap[curComponentId] + const optionFilterValue = isTree + ? optionFilter.map(itemOption => itemOption.replace(/-de-/g, ',')) + : optionFilter + if (isTree) { + const [i, r] = getFieldId( + treeFieldList, + optionFilterValue, + relationshipChartIndex, + ids + ) + fieldIdOption = i + } filter.push({ filterId: id, componentId: ele.id, - fieldId: item.checkedFieldsMap[curComponentId], + fieldId: fieldIdOption, operator: 'in', - value: optionFilter, + value: optionFilterValue, parameters: [], isTree }) diff --git a/core/core-frontend/src/store/modules/data-visualization/dvMain.ts b/core/core-frontend/src/store/modules/data-visualization/dvMain.ts index 3d4bb85835..4b58610794 100644 --- a/core/core-frontend/src/store/modules/data-visualization/dvMain.ts +++ b/core/core-frontend/src/store/modules/data-visualization/dvMain.ts @@ -1289,9 +1289,15 @@ export const dvMainStore = defineStore('dataVisualization', { if (element.component === 'VQuery') { element.propValue?.forEach(filterItem => { if (filterItem.id === targetViewId) { - let queryParams = paramValue const targetMatchMode = targetInfoArray[2] // 目标匹配模式 if (targetMatchMode === 'filter') { + paramValue = paramValue.map(option => { + if (typeof option === 'string' && option.includes(',')) { + return option.replace(/,/g, '-de-') + } + return option + }) + const queryParams = paramValue // do filter filterItem['optionFilter'] = queryParams if (filterItem.defaultValueCheck) {