优化搜索算法,更新图标

This commit is contained in:
heweikang 2024-08-15 12:38:20 +08:00
parent cd920364f8
commit 3da5284a07
7 changed files with 65 additions and 49 deletions

View File

@ -1,4 +1,4 @@
import { useState, useEffect } from "react"; import { useState, useEffect, useRef } from "react";
import { ErrorBoundary } from "./error"; import { ErrorBoundary } from "./error";
import styles from "./mask.module.scss"; import styles from "./mask.module.scss";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@ -25,63 +25,80 @@ export function SearchChatPage() {
const [searchResults, setSearchResults] = useState<Item[]>([]); const [searchResults, setSearchResults] = useState<Item[]>([]);
const setDefaultItems = () => { // const setDefaultItems = () => {
setSearchResults( // setSearchResults(
sessions.slice(1, 7).map((session, index) => { // sessions.slice(1, 7).map((session, index) => {
console.log(session.messages[0]); // return {
return { // id: index,
id: index, // name: session.topic,
name: session.topic, // content: session.messages[0].content as string, //.map((m) => m.content).join("\n")
content: session.messages[0].content as string, //.map((m) => m.content).join("\n") // };
}; // }),
}), // );
); // };
}; // useEffect(() => {
useEffect(() => { // setDefaultItems();
setDefaultItems(); // }, []);
}, []);
const previousValueRef = useRef<string>("");
const searchInputRef = useRef<HTMLInputElement>(null);
const doSearch = (text: string) => { const doSearch = (text: string) => {
// 分割关键词 const lowerCaseText = text.toLowerCase();
const keywords = text.split(" "); const results: Item[] = [];
// 存储每个会话的匹配结果
const searchResults: Item[] = [];
sessions.forEach((session, index) => { sessions.forEach((session, index) => {
let matchCount = 0; const fullTextContents: string[] = [];
const contents: string[] = [];
session.messages.forEach((message) => { session.messages.forEach((message) => {
const content = message.content as string; const content = message.content as string;
const lowerCaseContent = content.toLowerCase(); const lowerCaseContent = content.toLowerCase();
keywords.forEach((keyword) => {
const pos = lowerCaseContent.indexOf(keyword.toLowerCase()); // 全文搜索
if (pos !== -1) { let pos = lowerCaseContent.indexOf(lowerCaseText);
matchCount++; while (pos !== -1) {
// 提取关键词前后70个字符的内容 const start = Math.max(0, pos - 35);
const start = Math.max(0, pos - 35); const end = Math.min(content.length, pos + lowerCaseText.length + 35);
const end = Math.min(content.length, pos + keyword.length + 35); fullTextContents.push(content.substring(start, end));
contents.push(content.substring(start, end)); pos = lowerCaseContent.indexOf(
} lowerCaseText,
}); pos + lowerCaseText.length,
);
}
}); });
if (matchCount > 0) { if (fullTextContents.length > 0) {
searchResults.push({ results.push({
id: index, id: index,
name: session.topic, name: session.topic,
content: contents.join("... "), // 使用...连接不同消息中的内容 content: fullTextContents.join("... "), // 使用...连接不同消息中的内容
}); });
} }
}); });
// 按匹配数量排序取前10个结果 // 按内容长度排序
return searchResults results.sort((a, b) => b.content.length - a.content.length);
.sort((a, b) => b.content.length - a.content.length)
.slice(0, 10); 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);
}, []);
return ( return (
<ErrorBoundary> <ErrorBoundary>
<div className={styles["mask-page"]}> <div className={styles["mask-page"]}>
@ -115,6 +132,7 @@ export function SearchChatPage() {
className={styles["search-bar"]} className={styles["search-bar"]}
placeholder={Locale.SearchChat.Page.Search} placeholder={Locale.SearchChat.Page.Search}
autoFocus autoFocus
ref={searchInputRef}
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === "Enter") { if (e.key === "Enter") {
e.preventDefault(); e.preventDefault();

View File

@ -12,7 +12,7 @@ import DeleteIcon from "../icons/delete.svg";
import MaskIcon from "../icons/mask.svg"; import MaskIcon from "../icons/mask.svg";
import DragIcon from "../icons/drag.svg"; import DragIcon from "../icons/drag.svg";
import DiscoveryIcon from "../icons/discovery.svg"; import DiscoveryIcon from "../icons/discovery.svg";
import SearchIcon from "../icons/zoom.svg";
import Locale from "../locales"; import Locale from "../locales";
import { useAppConfig, useChatStore } from "../store"; import { useAppConfig, useChatStore } from "../store";
@ -251,7 +251,7 @@ export function SideBar(props: { className?: string }) {
shadow shadow
/> />
<IconButton <IconButton
icon={<DiscoveryIcon />} icon={<SearchIcon />}
text={shouldNarrow ? undefined : Locale.SearchChat.Name} text={shouldNarrow ? undefined : Locale.SearchChat.Name}
className={styles["sidebar-bar-button"]} className={styles["sidebar-bar-button"]}
onClick={() => onClick={() =>

1
app/icons/zoom.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1.2rem" height="1.2rem" viewBox="0 0 24 24"><g fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></g></svg>

After

Width:  |  Height:  |  Size: 285 B

View File

@ -523,7 +523,7 @@ const cn = {
Name: "搜索", Name: "搜索",
Page: { Page: {
Title: "搜索聊天记录", Title: "搜索聊天记录",
Search: "输入多个关键词(空格分隔), 回车搜索", Search: "输入搜索关键词",
NoResult: "没有找到结果", NoResult: "没有找到结果",
NoData: "没有数据", NoData: "没有数据",
Loading: "加载中", Loading: "加载中",

View File

@ -531,8 +531,7 @@ const en: LocaleType = {
Name: "Search", Name: "Search",
Page: { Page: {
Title: "Search Chat History", Title: "Search Chat History",
Search: Search: "Enter search query to search chat history",
"Enter multiple keywords (separated by spaces), press Enter to search",
NoResult: "No results found", NoResult: "No results found",
NoData: "No data", NoData: "No data",
Loading: "Loading...", Loading: "Loading...",

View File

@ -248,8 +248,7 @@ const jp: PartialLocaleType = {
Name: "検索", Name: "検索",
Page: { Page: {
Title: "チャット履歴を検索", Title: "チャット履歴を検索",
Search: Search: "キーワードを入力してください",
"複数のキーワードを入力してください(スペースで区切る)、エンターキーを押して検索",
NoResult: "結果が見つかりませんでした", NoResult: "結果が見つかりませんでした",
NoData: "データがありません", NoData: "データがありません",
Loading: "読み込み中...", Loading: "読み込み中...",

View File

@ -196,8 +196,7 @@ const ru: PartialLocaleType = {
Name: "Поиск", Name: "Поиск",
Page: { Page: {
Title: "Поиск в истории чата", Title: "Поиск в истории чата",
Search: Search: "Введите текст для поиска",
"Введите несколько ключевых слов (разделенных пробелами), нажмите Enter для поиска",
NoResult: "Результаты не найдены", NoResult: "Результаты не найдены",
NoData: "Данные отсутствуют", NoData: "Данные отсутствуют",
Loading: "Загрузка...", Loading: "Загрузка...",