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:
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user