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 <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-06-18 09:52:51 +08:00
parent f8914fb287
commit 2f3cd9fa06
2 changed files with 34 additions and 4 deletions

View File

@@ -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<string, React.Key[]>
): ColumnsType<DataRow> {
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<string[]>(() => loadHistory());
@@ -461,6 +471,13 @@ function SearchBar({
>
</Button>
<Button
icon={<FilterOutlined />}
onClick={onClearFilters}
disabled={!hasActiveFilters}
>
</Button>
</Space>
{searched && !loading && (
<Text type="secondary" style={{ marginLeft: 16 }}>
@@ -483,6 +500,7 @@ export default function Home() {
const [modalOpen, setModalOpen] = useState(false);
const [exporting, setExporting] = useState(false);
const [lockedRowKey, setLockedRowKey] = useState<string | null>(null);
const [filters, setFilters] = useState<Record<string, React.Key[]>>({});
// 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}
/>
<div style={{ flex: 1, minHeight: 0 }}>
@@ -624,6 +651,9 @@ export default function Home() {
rowClassName={(record) =>
String(record.ID) === lockedRowKey ? "row-locked" : ""
}
onChange={(_pagination, tableFilters) =>
setFilters(tableFilters as Record<string, React.Key[]>)
}
bordered
size="small"
pagination={false}