Add per-column filterable flag with persistence and settings toggle
ColumnConfig gains filterable (default false), persisted to localStorage with backward-compat for configs saved before this field existed. The column-settings modal now shows a funnel toggle per row alongside the visibility checkbox. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,14 @@ import {
|
||||
Checkbox,
|
||||
AutoComplete,
|
||||
} from "antd";
|
||||
import { SearchOutlined, SettingOutlined, HolderOutlined, ClockCircleOutlined, DownloadOutlined } from "@ant-design/icons";
|
||||
import {
|
||||
SearchOutlined,
|
||||
SettingOutlined,
|
||||
HolderOutlined,
|
||||
ClockCircleOutlined,
|
||||
DownloadOutlined,
|
||||
FilterOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import type { ColumnsType } from "antd/es/table";
|
||||
import {
|
||||
DndContext,
|
||||
@@ -38,6 +45,7 @@ const { Title, Text } = Typography;
|
||||
interface ColumnConfig {
|
||||
key: string;
|
||||
visible: boolean;
|
||||
filterable: boolean;
|
||||
}
|
||||
|
||||
const COLUMN_DEFS: { key: string; width: number }[] = [
|
||||
@@ -102,6 +110,7 @@ const COLUMN_DEFS: { key: string; width: number }[] = [
|
||||
const DEFAULT_CONFIG: ColumnConfig[] = COLUMN_DEFS.map((d) => ({
|
||||
key: d.key,
|
||||
visible: true,
|
||||
filterable: false,
|
||||
}));
|
||||
|
||||
const STORAGE_KEY = "web-table-column-config";
|
||||
@@ -110,9 +119,15 @@ function loadConfig(): ColumnConfig[] {
|
||||
try {
|
||||
const saved = localStorage.getItem(STORAGE_KEY);
|
||||
if (saved) {
|
||||
const parsed: ColumnConfig[] = JSON.parse(saved);
|
||||
const parsed = JSON.parse(saved) as Partial<ColumnConfig>[];
|
||||
const savedKeys = new Set(parsed.map((c) => c.key));
|
||||
if (COLUMN_DEFS.every((d) => savedKeys.has(d.key))) return parsed;
|
||||
if (COLUMN_DEFS.every((d) => savedKeys.has(d.key))) {
|
||||
return parsed.map((c) => ({
|
||||
key: c.key!,
|
||||
visible: !!c.visible,
|
||||
filterable: !!c.filterable, // 旧配置缺该字段时按 false
|
||||
}));
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
@@ -151,12 +166,16 @@ function SortableRow({
|
||||
id,
|
||||
label,
|
||||
visible,
|
||||
filterable,
|
||||
onToggle,
|
||||
onToggleFilter,
|
||||
}: {
|
||||
id: string;
|
||||
label: string;
|
||||
visible: boolean;
|
||||
filterable: boolean;
|
||||
onToggle: () => void;
|
||||
onToggleFilter: () => void;
|
||||
}) {
|
||||
const {
|
||||
attributes,
|
||||
@@ -188,6 +207,14 @@ function SortableRow({
|
||||
<HolderOutlined />
|
||||
</span>
|
||||
<Checkbox checked={visible} onChange={onToggle} style={{ flexShrink: 0 }} />
|
||||
<Button
|
||||
size="small"
|
||||
type={filterable ? "primary" : "default"}
|
||||
icon={<FilterOutlined />}
|
||||
onClick={onToggleFilter}
|
||||
title={filterable ? "已设为可筛选,点击取消" : "设为可筛选"}
|
||||
style={{ flexShrink: 0, padding: "0 6px" }}
|
||||
/>
|
||||
<span style={{ userSelect: "none" }}>{label}</span>
|
||||
</div>
|
||||
);
|
||||
@@ -240,6 +267,12 @@ function ColumnSettingsModal({
|
||||
);
|
||||
};
|
||||
|
||||
const toggleFilter = (key: string) => {
|
||||
setLocal((prev) =>
|
||||
prev.map((c) => (c.key === key ? { ...c, filterable: !c.filterable } : c))
|
||||
);
|
||||
};
|
||||
|
||||
const selectAll = () => setLocal((prev) => prev.map((c) => ({ ...c, visible: true })));
|
||||
const deselectAll = () => setLocal((prev) => prev.map((c) => ({ ...c, visible: false })));
|
||||
const resetDefault = () => setLocal(DEFAULT_CONFIG.map((c) => ({ ...c })));
|
||||
@@ -288,7 +321,9 @@ function ColumnSettingsModal({
|
||||
id={c.key}
|
||||
label={c.key}
|
||||
visible={c.visible}
|
||||
filterable={c.filterable}
|
||||
onToggle={() => toggle(c.key)}
|
||||
onToggleFilter={() => toggleFilter(c.key)}
|
||||
/>
|
||||
))}
|
||||
</SortableContext>
|
||||
|
||||
Reference in New Issue
Block a user