refactor: 外部参数使用过滤选项时,支持关联过滤组件的图表使用过滤选项过滤结果 (#17846)

This commit is contained in:
王嘉豪
2026-01-21 11:26:26 +08:00
committed by GitHub
parent ee9a88b496
commit 29cc6fd058
3 changed files with 100 additions and 23 deletions

View File

@@ -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)
}
</script>

View File

@@ -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
})

View File

@@ -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) {