From 2c66faf207e4aaa560a4204522e33c50786633b1 Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Wed, 10 Jun 2026 12:19:24 +0800 Subject: [PATCH] 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 --- src/app/page.tsx | 88 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 13 deletions(-) diff --git a/src/app/page.tsx b/src/app/page.tsx index a751b22..6821c54 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -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; onClear: () => void; onOpenColumnSettings: () => void; }) { const [inputValue, setInputValue] = useState(""); + const [history, setHistory] = useState(() => 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: ( + + + {h} + + ), + })); 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 (
- } - placeholder="请输入车间号,如 R05697" + 0} + options={options} value={inputValue} - onChange={(e) => setInputValue(e.target.value)} - onPressEnter={handleSearch} - allowClear + onChange={(val) => setInputValue(val)} + onSelect={handleSelect} + onFocus={() => setOpen(true)} + onBlur={() => setOpen(false)} style={{ width: 320 }} - /> + > + } + placeholder="请输入车间号,如 R05697" + onPressEnter={handleSearch} + allowClear + /> +