import { useState, useEffect, useRef, useCallback } from "react"; import { ErrorBoundary } from "./error"; import styles from "./mask.module.scss"; import { useNavigate } from "react-router-dom"; import { IconButton } from "./button"; import CloseIcon from "../icons/close.svg"; import EyeIcon from "../icons/eye.svg"; import Locale from "../locales"; import { Path } from "../constant"; import { useChatStore } from "../store"; type Item = { id: number; name: string; content: string; }; export function SearchChatPage() { const navigate = useNavigate(); const chatStore = useChatStore(); const sessions = chatStore.sessions; const selectSession = chatStore.selectSession; const [searchResults, setSearchResults] = useState([]); const previousValueRef = useRef(""); const searchInputRef = useRef(null); const doSearch = useCallback((text: string) => { const lowerCaseText = text.toLowerCase(); const results: Item[] = []; sessions.forEach((session, index) => { const fullTextContents: string[] = []; session.messages.forEach((message) => { const content = message.content as string; if (!content.toLowerCase || content === "") return; const lowerCaseContent = content.toLowerCase(); // full text search let pos = lowerCaseContent.indexOf(lowerCaseText); while (pos !== -1) { const start = Math.max(0, pos - 35); const end = Math.min(content.length, pos + lowerCaseText.length + 35); fullTextContents.push(content.substring(start, end)); pos = lowerCaseContent.indexOf( lowerCaseText, pos + lowerCaseText.length, ); } }); if (fullTextContents.length > 0) { results.push({ id: index, name: session.topic, content: fullTextContents.join("... "), // concat content with... }); } }); // sort by length of matching content results.sort((a, b) => b.content.length - a.content.length); return results; }, []); useEffect(() => { const intervalId = setInterval(() => { if (searchInputRef.current) { const currentValue = searchInputRef.current.value; if (currentValue !== previousValueRef.current) { if (currentValue.length > 0) { const result = doSearch(currentValue); setSearchResults(result); } previousValueRef.current = currentValue; } } }, 1000); // Cleanup the interval on component unmount return () => clearInterval(intervalId); }, [doSearch]); return (
{/* header */}
{Locale.SearchChat.Page.Title}
{Locale.SearchChat.Page.SubTitle(searchResults.length)}
} bordered onClick={() => navigate(-1)} />
{/**搜索输入框 */} { if (e.key === "Enter") { e.preventDefault(); const searchText = e.currentTarget.value; if (searchText.length > 0) { const result = doSearch(searchText); setSearchResults(result); } } }} />
{searchResults.map((item) => (
{ navigate(Path.Chat); selectSession(item.id); }} style={{ cursor: "pointer" }} > {/** 搜索匹配的文本 */}
{item.name}
{item.content.slice(0, 70)}
{/** 操作按钮 */}
} text={Locale.SearchChat.Item.View} />
))}
); }