Add search history with AutoComplete dropdown
- Show last 10 search records on input focus with clock icon - Filter history as user types - Click history item to search directly - Deduplicate and persist to localStorage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,8 +12,9 @@ import {
|
||||
Empty,
|
||||
Modal,
|
||||
Checkbox,
|
||||
AutoComplete,
|
||||
} from "antd";
|
||||
import { SearchOutlined, SettingOutlined, HolderOutlined } from "@ant-design/icons";
|
||||
import { SearchOutlined, SettingOutlined, HolderOutlined, ClockCircleOutlined } from "@ant-design/icons";
|
||||
import type { ColumnsType } from "antd/es/table";
|
||||
import {
|
||||
DndContext,
|
||||
@@ -300,6 +301,29 @@ function ColumnSettingsModal({
|
||||
);
|
||||
}
|
||||
|
||||
/* ─── Search History ─── */
|
||||
|
||||
const HISTORY_KEY = "web-table-search-history";
|
||||
const MAX_HISTORY = 10;
|
||||
|
||||
function loadHistory(): string[] {
|
||||
try {
|
||||
const saved = localStorage.getItem(HISTORY_KEY);
|
||||
return saved ? JSON.parse(saved) : [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function saveHistoryToStorage(history: string[]) {
|
||||
localStorage.setItem(HISTORY_KEY, JSON.stringify(history));
|
||||
}
|
||||
|
||||
function addToHistory(value: string, history: string[]): string[] {
|
||||
const filtered = history.filter((h) => h !== value);
|
||||
return [value, ...filtered].slice(0, MAX_HISTORY);
|
||||
}
|
||||
|
||||
/* ─── Search Bar (isolated) ─── */
|
||||
|
||||
function SearchBar({
|
||||
@@ -313,17 +337,47 @@ function SearchBar({
|
||||
loading: boolean;
|
||||
resultCount: number;
|
||||
searched: boolean;
|
||||
onSearch: (workshopNo: string) => void;
|
||||
onSearch: (workshopNo: string) => Promise<void>;
|
||||
onClear: () => void;
|
||||
onOpenColumnSettings: () => void;
|
||||
}) {
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
const [history, setHistory] = useState<string[]>(() => loadHistory());
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const filteredHistory = inputValue
|
||||
? history.filter((h) => h.toLowerCase().includes(inputValue.toLowerCase()))
|
||||
: history;
|
||||
|
||||
const options = filteredHistory.map((h) => ({
|
||||
value: h,
|
||||
label: (
|
||||
<span style={{ display: "flex", alignItems: "center", gap: 8 }}>
|
||||
<ClockCircleOutlined style={{ color: "#bbb" }} />
|
||||
{h}
|
||||
</span>
|
||||
),
|
||||
}));
|
||||
|
||||
const handleSearch = useCallback(() => {
|
||||
if (inputValue.trim()) {
|
||||
onSearch(inputValue.trim());
|
||||
}
|
||||
}, [inputValue, onSearch]);
|
||||
const val = inputValue.trim();
|
||||
if (!val) return;
|
||||
const updated = addToHistory(val, history);
|
||||
setHistory(updated);
|
||||
saveHistoryToStorage(updated);
|
||||
onSearch(val);
|
||||
}, [inputValue, history, onSearch]);
|
||||
|
||||
const handleSelect = useCallback(
|
||||
(val: string) => {
|
||||
setInputValue(val);
|
||||
const updated = addToHistory(val, history);
|
||||
setHistory(updated);
|
||||
saveHistoryToStorage(updated);
|
||||
onSearch(val);
|
||||
},
|
||||
[history, onSearch]
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -339,15 +393,23 @@ function SearchBar({
|
||||
</Title>
|
||||
<Space>
|
||||
<Space.Compact>
|
||||
<AutoComplete
|
||||
open={open && filteredHistory.length > 0}
|
||||
options={options}
|
||||
value={inputValue}
|
||||
onChange={(val) => setInputValue(val)}
|
||||
onSelect={handleSelect}
|
||||
onFocus={() => setOpen(true)}
|
||||
onBlur={() => setOpen(false)}
|
||||
style={{ width: 320 }}
|
||||
>
|
||||
<Input
|
||||
prefix={<SearchOutlined />}
|
||||
placeholder="请输入车间号,如 R05697"
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
onPressEnter={handleSearch}
|
||||
allowClear
|
||||
style={{ width: 320 }}
|
||||
/>
|
||||
</AutoComplete>
|
||||
<Button type="primary" onClick={handleSearch} loading={loading}>
|
||||
查询
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user