From 26bcba02efedb4660955fc954873199f95212922 Mon Sep 17 00:00:00 2001 From: PoorShawn <18352979520@163.com> Date: Thu, 18 Dec 2025 17:22:23 +0800 Subject: [PATCH 1/2] fix: resolve filter malfunction in grouped header scenarios --- packages/vtable-plugins/demo/filter/group.ts | 106 ++++++++++++++++++ packages/vtable-plugins/demo/menu.ts | 4 + packages/vtable-plugins/src/filter/filter.ts | 13 ++- .../vtable-plugins/src/filter/value-filter.ts | 2 +- 4 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 packages/vtable-plugins/demo/filter/group.ts diff --git a/packages/vtable-plugins/demo/filter/group.ts b/packages/vtable-plugins/demo/filter/group.ts new file mode 100644 index 0000000000..3f9b9085e1 --- /dev/null +++ b/packages/vtable-plugins/demo/filter/group.ts @@ -0,0 +1,106 @@ +import * as VTable from '@visactor/vtable'; +import { bindDebugTool } from '@visactor/vtable/es/scenegraph/debug-tool'; +import { FilterPlugin } from '../../src/filter'; +const CONTAINER_ID = 'vTable'; + +export function createTable() { + const records = [ + { + id: 1, + name: 'name.1', + name_1: 'name_1.1', + name_2: 'name_2.1', + name_2_1: 'name_2_1.1', + name_2_2: 'name_2_2.1' + }, + { + id: 2, + name: 'name.2', + name_1: 'name_1.2', + name_2: 'name_2.2', + name_2_1: 'name_2_1.2', + name_2_2: 'name_2_2.2' + }, + { + id: 3, + name: 'name.3', + name_1: 'name_1.3', + name_2: 'name_2.3', + name_2_1: 'name_2_1.3', + name_2_2: 'name_2_2.3' + }, + { + id: 4, + name: 'name.4', + name_1: 'name_1.4', + name_2: 'name_2.4', + name_2_1: 'name_2_1.4', + name_2_2: 'name_2_2.4' + }, + { + id: 5, + name: 'name.5', + name_1: 'name_1.5', + name_2: 'name_2.5', + name_2_1: 'name_2_1.5', + name_2_2: 'name_2_2.5' + } + ]; + + const columns = [ + { + field: 'id', + title: 'ID', + width: 100 + }, + { + field: 'name', + title: 'Name', + columns: [ + { + field: 'name_1', + title: 'Name_1', + width: 120 + }, + { + field: 'name_2', + title: 'Name_2', + width: 150, + columns: [ + { + field: 'name_2_1', + title: 'Name_2_1', + width: 150 + }, + { + field: 'name_2_2', + title: 'Name_2_2', + width: 150 + } + ] + } + ] + } + ]; + + const filterPlugin = new FilterPlugin({}); + (window as any).filterPlugin = filterPlugin; + + const option = { + records, + columns, + headerHierarchyType: 'grid-tree', // 启用树形折叠 + headerExpandLevel: 2, // 默认展开至第二级 + widthMode: 'standard', + defaultRowHeight: 40, + plugins: [filterPlugin] + }; + + const tableInstance = new VTable.ListTable(document.getElementById(CONTAINER_ID), option); + + (window as any).tableInstance = tableInstance; + + bindDebugTool(tableInstance.scenegraph.stage, { + customGrapicKeys: ['col', 'row'] + }); +} diff --git a/packages/vtable-plugins/demo/menu.ts b/packages/vtable-plugins/demo/menu.ts index 13219508c2..651d35fea0 100644 --- a/packages/vtable-plugins/demo/menu.ts +++ b/packages/vtable-plugins/demo/menu.ts @@ -23,6 +23,10 @@ export const menus = [ path: 'filter', name: 'value-filter' }, + { + path: 'filter', + name: 'group' + }, { path: 'header-highlight', name: '(deprecated)header-highlight' diff --git a/packages/vtable-plugins/src/filter/filter.ts b/packages/vtable-plugins/src/filter/filter.ts index 21bb737cdc..2d88c08087 100644 --- a/packages/vtable-plugins/src/filter/filter.ts +++ b/packages/vtable-plugins/src/filter/filter.ts @@ -243,7 +243,18 @@ export class FilterPlugin implements pluginsDefinition.IVTablePlugin { const compactIcons = (list: any[]) => (list.length === 0 ? undefined : list.length === 1 ? list[0] : list); - columns.forEach(column => { + const stack = [...columns]; + const subColumns = []; + while (stack.length > 0) { + const currentCol = stack.pop(); + if (currentCol.columns) { + currentCol.columns.forEach(col => stack.push(col)); + } else { + subColumns.push(currentCol); + } + } + + subColumns.forEach(column => { const shouldShow = this.shouldEnableFilterForColumn(column.field as string | number, column); const isFiltering = !!this.filterStateManager.getFilterState(column.field as string | number)?.enable; let icons = toIconList(column.headerIcon); diff --git a/packages/vtable-plugins/src/filter/value-filter.ts b/packages/vtable-plugins/src/filter/value-filter.ts index 270ebf1af8..d387c3ffaa 100644 --- a/packages/vtable-plugins/src/filter/value-filter.ts +++ b/packages/vtable-plugins/src/filter/value-filter.ts @@ -139,7 +139,7 @@ export class ValueFilter { records = this.table.internalProps.records; } else { const recordsList = this.getRecords(this.table, true); // 已筛选:使用原始表格数据 - const records = recordsList.filter(record => + records = recordsList.filter(record => filteredFields.every(field => { const filterType = this.filterStateManager.getFilterState(field)?.type; if (filterType !== 'byValue' && filterType !== null && filterType !== undefined) { From 631ee3efa61012cd494b8c9170a08187d7f9986a Mon Sep 17 00:00:00 2001 From: PoorShawn <18352979520@163.com> Date: Mon, 22 Dec 2025 16:21:41 +0800 Subject: [PATCH 2/2] fix: properly handle null or undefined data in filter plugin --- packages/vtable-plugins/src/filter/value-filter.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/vtable-plugins/src/filter/value-filter.ts b/packages/vtable-plugins/src/filter/value-filter.ts index 270ebf1af8..7f503c4551 100644 --- a/packages/vtable-plugins/src/filter/value-filter.ts +++ b/packages/vtable-plugins/src/filter/value-filter.ts @@ -105,7 +105,7 @@ export class ValueFilter { // 空行不做处理 if (isValid(record)) { const originalValue = record[fieldId]; - const formattedValue = formatFn(record); + const formattedValue = formatFn(record) ?? '(空白)'; if (formattedValue !== undefined && formattedValue !== null) { countMap.set(formattedValue, (countMap.get(formattedValue) || 0) + 1); @@ -139,7 +139,7 @@ export class ValueFilter { records = this.table.internalProps.records; } else { const recordsList = this.getRecords(this.table, true); // 已筛选:使用原始表格数据 - const records = recordsList.filter(record => + records = recordsList.filter(record => filteredFields.every(field => { const filterType = this.filterStateManager.getFilterState(field)?.type; if (filterType !== 'byValue' && filterType !== null && filterType !== undefined) { @@ -155,7 +155,7 @@ export class ValueFilter { // 空行不做处理 if (isValid(record)) { const originalValue = record[candidateField]; - const formattedValue = formatFn(record); + const formattedValue = formatFn(record) ?? '(空白)'; countMap.set(formattedValue, (countMap.get(formattedValue) || 0) + 1); if (formattedValue !== undefined && formattedValue !== null) { const unformattedSet = toUnformatted.get(formattedValue);