diff --git a/packages/components/table/src/composables/useDataSource.ts b/packages/components/table/src/composables/useDataSource.ts index 2393253ff..5f2a42239 100644 --- a/packages/components/table/src/composables/useDataSource.ts +++ b/packages/components/table/src/composables/useDataSource.ts @@ -110,7 +110,7 @@ function convertDataMap(mergedData: MergedData[], map: Map) { } function sortData(mergedData: MergedData[], activeSorters: ActiveSorter[], expandedRowKeys: VKey[]) { - const sorters = activeSorters.filter(item => item.orderBy && item.sorter) + const sorters = activeSorters.filter(item => item.sorter) const sorterLength = sorters.length if (sorterLength === 0) { @@ -135,13 +135,14 @@ function sortData(mergedData: MergedData[], activeSorters: ActiveSorter[], expan } function filterData(mergedData: MergedData[], activeFilters: ActiveFilter[], expandedRowKeys: VKey[]): MergedData[] { - if (activeFilters.length === 0) { + const filters = activeFilters.filter(item => item.filter) + if (filters.length === 0) { return mergedData } return mergedData .map(item => { - const valid = activeFilters.every(({ filter, filterBy }) => filter(filterBy, item.record)) + const valid = filters.every(({ filter, filterBy }) => filter!(filterBy, item.record)) const { rowKey, children } = item const isExpanded = expandedRowKeys.includes(rowKey) @@ -152,7 +153,7 @@ function filterData(mergedData: MergedData[], activeFilters: ActiveFilter[], exp newItem = { ...item, children: newChildren } } } - return valid || (isExpanded && newItem.children) ? newItem : null + return valid || (isExpanded && newItem.children && newItem.children.length) ? newItem : null }) .filter(item => item !== null) as MergedData[] } diff --git a/packages/components/table/src/composables/useFilterable.ts b/packages/components/table/src/composables/useFilterable.ts index a6dd5cf94..f7cdb6be6 100644 --- a/packages/components/table/src/composables/useFilterable.ts +++ b/packages/components/table/src/composables/useFilterable.ts @@ -7,35 +7,43 @@ import { type ComputedRef, computed, reactive, watch } from 'vue' -import { type VKey } from '@idux/cdk/utils' +import { type VKey, callEmit } from '@idux/cdk/utils' +import { type TableColumnFilterable } from '../types' import { type TableColumnMerged } from './useColumns' -export interface ActiveFilter { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - filter: (currFilterBy: VKey[], record: any) => boolean - filterBy: VKey[] -} - export interface FilterableContext { activeFilters: ComputedRef - filterByMap: Record - setFilterBy: (key: VKey, filterBy: VKey[]) => void + activeFilterByMap: Record + handleFilter: (key: VKey, filterable: TableColumnFilterable, filterBy: VKey[]) => void +} + +export interface ActiveFilter { + key: VKey + filter?: (currFilterBy: VKey[], record: unknown) => boolean + filterBy: VKey[] } export function useFilterable(flattedColumns: ComputedRef): FilterableContext { - const filterByMap = reactive>({}) - const setFilterBy = (key: VKey, filterBy: VKey[]) => { - filterByMap[key] = filterBy - } + const filterableColumns = computed(() => flattedColumns.value.filter(column => column.filterable)) + const activeFilterByMap = reactive>({}) - const filterableColumns = computed(() => flattedColumns.value.filter(column => !!column.filterable)) watch( filterableColumns, - columns => { - columns.forEach(column => { - if (filterByMap[column.key] === undefined) { - filterByMap[column.key] = column.filterable?.filterBy || [] + (currColumns, prevColumns) => { + currColumns.forEach(currColumn => { + const { key, filterable } = currColumn + const currFilterBy = filterable!.filterBy + if (currFilterBy || activeFilterByMap[key] === undefined) { + activeFilterByMap[key] = currFilterBy || [] + return + } + + // 受控模式 + const prevColumn = prevColumns ? prevColumns.find(column => column.key === key) : undefined + const prevFilterBy = prevColumn?.filterable!.filterBy + if (prevFilterBy) { + activeFilterByMap[key] = [] } }) }, @@ -46,17 +54,24 @@ export function useFilterable(flattedColumns: ComputedRef): () => filterableColumns.value .map(column => { - const filterable = column.filterable! - const filter = filterable.filter - const filterBy = filterable.filterBy || filterByMap[column.key] - return { filter, filterBy } + const { key, filterable } = column + const { filter, filterBy = activeFilterByMap[key] } = filterable! + return { key, filter, filterBy } }) .filter(item => item.filter && item.filterBy.length > 0) as ActiveFilter[], ) + const handleFilter = (activeKey: VKey, activeFilterable: TableColumnFilterable, filterBy: VKey[]) => { + const { onChange } = activeFilterable + + activeFilterByMap[activeKey] = filterBy + + callEmit(onChange, filterBy, activeFilters.value) + } + return { activeFilters, - filterByMap, - setFilterBy, + activeFilterByMap, + handleFilter, } } diff --git a/packages/components/table/src/main/head/HeadCell.tsx b/packages/components/table/src/main/head/HeadCell.tsx index 72e425b23..1c9f97278 100644 --- a/packages/components/table/src/main/head/HeadCell.tsx +++ b/packages/components/table/src/main/head/HeadCell.tsx @@ -9,7 +9,7 @@ import { ComputedRef, type Slots, type VNodeChild, computed, defineComponent, in import { isFunction, isString } from 'lodash-es' -import { type VKey, callEmit, convertCssPixel } from '@idux/cdk/utils' +import { type VKey, convertCssPixel } from '@idux/cdk/utils' import { type TableColumnMergedExtra } from '../../composables/useColumns' import { TABLE_TOKEN } from '../../token' @@ -41,8 +41,8 @@ export default defineComponent({ isSticky, handleSort, activeOrderByMap, - filterByMap, - setFilterBy, + activeFilterByMap, + handleFilter, } = inject(TABLE_TOKEN)! const classes = computed(() => { @@ -96,11 +96,10 @@ export default defineComponent({ }) const activeSortOrderBy = computed(() => activeOrderByMap[props.column.key]) - const activeFilterBy = computed(() => filterByMap[props.column.key]) + const activeFilterBy = computed(() => activeFilterByMap[props.column.key]) const onUpdateFilterBy = (filterBy: VKey[]) => { const { key, filterable } = props.column - setFilterBy(key, filterBy) - callEmit(filterable?.onChange, filterBy) + handleFilter(key, filterable!, filterBy) } const onClick = () => { diff --git a/packages/components/table/src/types.ts b/packages/components/table/src/types.ts index 4a347a612..5b5ffc0d3 100644 --- a/packages/components/table/src/types.ts +++ b/packages/components/table/src/types.ts @@ -20,6 +20,7 @@ import { type SpinProps } from '@idux/components/spin' import { type TableColumnMerged, type TableColumnMergedExtra } from './composables/useColumns' import { type FlattedData } from './composables/useDataSource' +import { type ActiveFilter } from './composables/useFilterable' import { type ActiveSorter } from './composables/useSortable' export const tableProps = { @@ -194,12 +195,12 @@ export interface TableColumnSortable { } export interface TableColumnFilterable { - filter?: (currFilterBy: VKey[], record: T) => boolean + filter?: (filterBy: VKey[], record: T) => boolean filterBy?: VKey[] footer?: boolean menus: MenuData[] multiple?: boolean - onChange?: (currFilterBy: VKey[]) => void + onChange?: (filterBy: VKey[], filters: ActiveFilter[]) => void customTrigger?: string | (() => VNodeChild) customMenu?: string | (() => VNodeChild)