优化搜索算法,更新图标
This commit is contained in:
parent
cd920364f8
commit
3da5284a07
|
@ -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 + keyword.length + 35);
|
const end = Math.min(content.length, pos + lowerCaseText.length + 35);
|
||||||
contents.push(content.substring(start, end));
|
fullTextContents.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();
|
||||||
|
|
|
@ -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={() =>
|
||||||
|
|
|
@ -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 |
|
@ -523,7 +523,7 @@ const cn = {
|
||||||
Name: "搜索",
|
Name: "搜索",
|
||||||
Page: {
|
Page: {
|
||||||
Title: "搜索聊天记录",
|
Title: "搜索聊天记录",
|
||||||
Search: "输入多个关键词(空格分隔), 回车搜索",
|
Search: "输入搜索关键词",
|
||||||
NoResult: "没有找到结果",
|
NoResult: "没有找到结果",
|
||||||
NoData: "没有数据",
|
NoData: "没有数据",
|
||||||
Loading: "加载中",
|
Loading: "加载中",
|
||||||
|
|
|
@ -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...",
|
||||||
|
|
|
@ -248,8 +248,7 @@ const jp: PartialLocaleType = {
|
||||||
Name: "検索",
|
Name: "検索",
|
||||||
Page: {
|
Page: {
|
||||||
Title: "チャット履歴を検索",
|
Title: "チャット履歴を検索",
|
||||||
Search:
|
Search: "キーワードを入力してください",
|
||||||
"複数のキーワードを入力してください(スペースで区切る)、エンターキーを押して検索",
|
|
||||||
NoResult: "結果が見つかりませんでした",
|
NoResult: "結果が見つかりませんでした",
|
||||||
NoData: "データがありません",
|
NoData: "データがありません",
|
||||||
Loading: "読み込み中...",
|
Loading: "読み込み中...",
|
||||||
|
|
|
@ -196,8 +196,7 @@ const ru: PartialLocaleType = {
|
||||||
Name: "Поиск",
|
Name: "Поиск",
|
||||||
Page: {
|
Page: {
|
||||||
Title: "Поиск в истории чата",
|
Title: "Поиск в истории чата",
|
||||||
Search:
|
Search: "Введите текст для поиска",
|
||||||
"Введите несколько ключевых слов (разделенных пробелами), нажмите Enter для поиска",
|
|
||||||
NoResult: "Результаты не найдены",
|
NoResult: "Результаты не найдены",
|
||||||
NoData: "Данные отсутствуют",
|
NoData: "Данные отсутствуют",
|
||||||
Loading: "Загрузка...",
|
Loading: "Загрузка...",
|
||||||
|
|
Loading…
Reference in New Issue