From 2f3cd9fa0693ee3ee2622e9a596810c77697b41a Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Thu, 18 Jun 2026 09:52:51 +0800 Subject: [PATCH] Wire controlled column filters and clear-filters button buildTableColumns now attaches antd controlled filter props (via buildColumnFilterProps) to columns marked filterable; filters state is controlled via Table onChange. A 'clear filters' button in the search bar resets all filters and is disabled when none are active. Filters and row lock reset on search/clear. Also renames the component module table-filters.tsx -> table-filter-ui.tsx to avoid a same-base-name resolution collision with the logic module table-filters.ts. Co-Authored-By: Claude --- src/app/page.tsx | 38 +++++++++++++++++-- ...{table-filters.tsx => table-filter-ui.tsx} | 0 2 files changed, 34 insertions(+), 4 deletions(-) rename src/app/{table-filters.tsx => table-filter-ui.tsx} (100%) diff --git a/src/app/page.tsx b/src/app/page.tsx index 2f16162..365c3f6 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -39,6 +39,7 @@ import { } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; import { nextLockedRow, type DataRow } from "./table-filters"; +import { buildColumnFilterProps } from "./table-filter-ui"; const { Title, Text } = Typography; @@ -141,14 +142,16 @@ function saveConfig(config: ColumnConfig[]) { function buildTableColumns( config: ColumnConfig[], - dataColumns: string[] + dataColumns: string[], + data: DataRow[], + filters: Record ): ColumnsType { const available = new Set(dataColumns); return config .filter((c) => c.visible && available.has(c.key)) .map((c) => { const def = COLUMN_DEFS.find((d) => d.key === c.key); - return { + const base = { title: c.key, dataIndex: c.key, key: c.key, @@ -157,6 +160,9 @@ function buildTableColumns( render: (val: string | number | null) => val === null || val === undefined ? "" : String(val), }; + return c.filterable + ? { ...base, ...buildColumnFilterProps(c.key, data, filters[c.key] ?? null) } + : base; }); } @@ -367,6 +373,8 @@ function SearchBar({ onOpenColumnSettings, exporting, onExport, + hasActiveFilters, + onClearFilters, }: { loading: boolean; resultCount: number; @@ -376,6 +384,8 @@ function SearchBar({ onOpenColumnSettings: () => void; exporting: boolean; onExport: () => void; + hasActiveFilters: boolean; + onClearFilters: () => void; }) { const [inputValue, setInputValue] = useState(""); const [history, setHistory] = useState(() => loadHistory()); @@ -461,6 +471,13 @@ function SearchBar({ > 导出全部 + {searched && !loading && ( @@ -483,6 +500,7 @@ export default function Home() { const [modalOpen, setModalOpen] = useState(false); const [exporting, setExporting] = useState(false); const [lockedRowKey, setLockedRowKey] = useState(null); + const [filters, setFilters] = useState>({}); // Persist config useEffect(() => { @@ -505,6 +523,7 @@ export default function Home() { setData(json.data); setSearched(true); setLockedRowKey(null); + setFilters({}); } catch { setError("网络请求失败"); } finally { @@ -518,6 +537,7 @@ export default function Home() { setSearched(false); setError(null); setLockedRowKey(null); + setFilters({}); }, []); const handleExport = useCallback(async () => { @@ -551,9 +571,14 @@ export default function Home() { }, []); const tableColumns = useMemo( - () => buildTableColumns(columnConfig, columns), - [columnConfig, columns] + () => buildTableColumns(columnConfig, columns, data, filters), + [columnConfig, columns, data, filters] ); + const hasActiveFilters = useMemo( + () => Object.values(filters).some((arr) => arr && arr.length > 0), + [filters] + ); + const clearFilters = useCallback(() => setFilters({}), []); const totalWidth = useMemo( () => tableColumns.reduce((sum, col) => sum + (col.width as number), 0), [tableColumns] @@ -574,6 +599,8 @@ export default function Home() { onOpenColumnSettings={() => setModalOpen(true)} exporting={exporting} onExport={handleExport} + hasActiveFilters={hasActiveFilters} + onClearFilters={clearFilters} />
@@ -624,6 +651,9 @@ export default function Home() { rowClassName={(record) => String(record.ID) === lockedRowKey ? "row-locked" : "" } + onChange={(_pagination, tableFilters) => + setFilters(tableFilters as Record) + } bordered size="small" pagination={false} diff --git a/src/app/table-filters.tsx b/src/app/table-filter-ui.tsx similarity index 100% rename from src/app/table-filters.tsx rename to src/app/table-filter-ui.tsx