新增聊天记录搜索功能:在聊天窗口中引入ChatRecordSearch组件,优化消息输入区域,更新状态管理以支持聊天记录模型的显示与隐藏,提升用户体验和代码可读性。

This commit is contained in:
超级老白兔
2025-10-10 15:45:28 +08:00
parent be5a848342
commit b067134ae7
7 changed files with 158 additions and 159 deletions

View File

@@ -0,0 +1,27 @@
.chatRecordSearch {
flex: 1;
display: flex;
justify-content: space-between;
.searchContentContainer {
display: flex;
align-items: center;
gap: 10px;
font-size: 12px;
.timeRange {
display: flex;
align-items: center;
gap: 10px;
.timeRangeTitle {
width: 80px;
}
}
.searchContent {
display: flex;
align-items: center;
gap: 10px;
.searchContentTitle {
width: 100px;
}
}
}
}

View File

@@ -0,0 +1,86 @@
import React, { useState } from "react";
import { Button, Input, DatePicker, message } from "antd";
import dayjs from "dayjs";
import { CloseOutlined } from "@ant-design/icons";
import { useWeChatStore } from "@/store/module/weChat/weChat";
import styles from "./index.module.scss";
const { RangePicker } = DatePicker;
const ChatRecordSearch: React.FC = () => {
const [searchContent, setSearchContent] = useState<string>("");
const [dateRange, setDateRange] = useState<[dayjs.Dayjs, dayjs.Dayjs] | null>(
null,
);
const [loading, setLoading] = useState(false);
const SearchMessage = useWeChatStore(state => state.SearchMessage);
const updateShowChatRecordModel = useWeChatStore(
state => state.updateShowChatRecordModel,
);
// 执行查找
const handleSearch = async () => {
if (!dateRange) {
message.warning("请选择时间范围");
return;
}
try {
setLoading(true);
const [From, To] = dateRange;
const searchData = {
From: From.unix() * 1000,
To: To.unix() * 1000,
keyword: searchContent.trim(),
};
await SearchMessage(searchData);
message.success("查找完成");
} catch (error) {
console.error("查找失败:", error);
message.error("查找失败,请重试");
} finally {
setLoading(false);
}
};
const handleCancel = () => {
setSearchContent("");
setDateRange(null);
setLoading(false);
handleSearch();
updateShowChatRecordModel(false);
};
return (
<div className={styles.chatRecordSearch}>
<div className={styles.searchContentContainer}>
{/* 时间范围选择 */}
<div className={styles.timeRange}>
<div className={styles.timeRangeTitle}></div>
<RangePicker
value={dateRange}
onChange={setDateRange}
style={{ width: "100%" }}
disabled={loading}
placeholder={["开始日期", "结束日期"]}
/>
</div>
{/* 查找内容输入 */}
<div className={styles.searchContent}>
<div className={styles.searchContentTitle}></div>
<Input
placeholder="请输入要查找的关键词或内容"
value={searchContent}
onChange={e => setSearchContent(e.target.value)}
disabled={loading}
/>
<Button type="primary" loading={loading} onClick={handleSearch}>
</Button>
</div>
</div>
<CloseOutlined style={{ fontSize: 20 }} onClick={handleCancel} />
</div>
);
};
export default ChatRecordSearch;

View File

@@ -1,150 +0,0 @@
import React, { useState } from "react";
import { Button, Modal, Input, DatePicker, message } from "antd";
import { MessageOutlined } from "@ant-design/icons";
import dayjs from "dayjs";
import { useWeChatStore } from "@/store/module/weChat/weChat";
const { RangePicker } = DatePicker;
interface ChatRecordProps {
className?: string;
disabled?: boolean;
}
const ChatRecord: React.FC<ChatRecordProps> = ({
className,
disabled = false,
}) => {
const [visible, setVisible] = useState(false);
const [searchContent, setSearchContent] = useState<string>("");
const [dateRange, setDateRange] = useState<[dayjs.Dayjs, dayjs.Dayjs] | null>(
null,
);
const [loading, setLoading] = useState(false);
const SearchMessage = useWeChatStore(state => state.SearchMessage);
// 打开弹窗
const openModal = () => {
setVisible(true);
};
// 关闭弹窗并重置状态
const closeModal = () => {
setVisible(false);
setSearchContent("");
setDateRange(null);
setLoading(false);
};
// 执行查找
const handleSearch = async () => {
if (!dateRange) {
message.warning("请选择时间范围");
return;
}
try {
setLoading(true);
const [From, To] = dateRange;
const searchData = {
From: From.unix() * 1000,
To: To.unix() * 1000,
keyword: searchContent.trim(),
};
await SearchMessage(searchData);
message.success("查找完成");
closeModal();
} catch (error) {
console.error("查找失败:", error);
message.error("查找失败,请重试");
} finally {
setLoading(false);
}
};
return (
<>
<div
className={className}
onClick={openModal}
style={{
cursor: disabled ? "not-allowed" : "pointer",
opacity: disabled ? 0.5 : 1,
}}
>
<MessageOutlined />
</div>
<Modal
title="查找聊天记录"
open={visible}
onCancel={closeModal}
width={450}
centered
maskClosable={!loading}
footer={[
<div
key="footer"
style={{
display: "flex",
justifyContent: "flex-end",
width: "100%",
}}
>
<Button
onClick={closeModal}
disabled={loading}
style={{ marginRight: "8px" }}
>
</Button>
<Button type="primary" loading={loading} onClick={handleSearch}>
</Button>
</div>,
]}
>
<div style={{ padding: "20px 0" }}>
{/* 时间范围选择 */}
<div style={{ marginBottom: "20px" }}>
<div
style={{ marginBottom: "8px", fontSize: "14px", color: "#333" }}
>
</div>
<RangePicker
value={dateRange}
onChange={setDateRange}
style={{ width: "100%" }}
size="large"
disabled={loading}
placeholder={["开始日期", "结束日期"]}
/>
</div>
{/* 查找内容输入 */}
<div>
<div
style={{ marginBottom: "8px", fontSize: "14px", color: "#333" }}
>
</div>
<Input
placeholder="请输入要查找的关键词或内容"
value={searchContent}
onChange={e => setSearchContent(e.target.value)}
size="large"
maxLength={100}
showCount
disabled={loading}
/>
</div>
</div>
</Modal>
</>
);
};
export default ChatRecord;

View File

@@ -6,6 +6,7 @@ import {
PictureOutlined,
ExportOutlined,
CloseOutlined,
MessageOutlined,
} from "@ant-design/icons";
import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data";
import { useWebSocketStore } from "@/store/module/websocket/websocket";
@@ -14,7 +15,6 @@ import { EmojiInfo } from "@/components/EmojiSeclection/wechatEmoji";
import SimpleFileUpload from "@/components/Upload/SimpleFileUpload";
import AudioRecorder from "@/components/Upload/AudioRecorder";
import ToContract from "./components/toContract";
import ChatRecord from "./components/chatRecord";
import styles from "./MessageEnter.module.scss";
import { useWeChatStore } from "@/store/module/weChat/weChat";
const { Footer } = Layout;
@@ -35,6 +35,12 @@ const MessageEnter: React.FC<MessageEnterProps> = ({ contract }) => {
const updateTransmitModal = useWeChatStore(
state => state.updateTransmitModal,
);
const showChatRecordModel = useWeChatStore(
state => state.showChatRecordModel,
);
const updateShowChatRecordModel = useWeChatStore(
state => state.updateShowChatRecordModel,
);
const quoteMessageContent = useWeChatStore(
state => state.quoteMessageContent,
@@ -154,6 +160,9 @@ const MessageEnter: React.FC<MessageEnterProps> = ({ contract }) => {
const handTurnRignt = () => {
updateTransmitModal(true);
};
const openChatRecordModel = () => {
updateShowChatRecordModel(!showChatRecordModel);
};
return (
<>
@@ -202,7 +211,17 @@ const MessageEnter: React.FC<MessageEnterProps> = ({ contract }) => {
</div>
<div className={styles.rightTool}>
<ToContract className={styles.rightToolItem} />
<ChatRecord className={styles.rightToolItem} />
<div
style={{
fontSize: "12px",
cursor: "pointer",
color: "#666",
}}
onClick={openChatRecordModel}
>
<MessageOutlined />
&nbsp;
</div>
</div>
</div>
<div className={styles.inputArea}>

View File

@@ -16,6 +16,7 @@ import MessageEnter from "./components/MessageEnter";
import MessageRecord from "./components/MessageRecord";
import FollowupReminderModal from "./components/FollowupReminderModal";
import TodoListModal from "./components/TodoListModal";
import ChatRecordSearch from "./components/ChatRecordSearch";
import { setFriendInjectConfig } from "@/pages/pc/ckbox/weChat/api";
import { useWeChatStore } from "@/store/module/weChat/weChat";
const { Header, Content } = Layout;
@@ -37,6 +38,9 @@ const ChatWindow: React.FC<ChatWindowProps> = ({ contract }) => {
const aiQuoteMessageContent = useWeChatStore(
state => state.aiQuoteMessageContent,
);
const showChatRecordModel = useWeChatStore(
state => state.showChatRecordModel,
);
const [showProfile, setShowProfile] = useState(true);
const [followupModalVisible, setFollowupModalVisible] = useState(false);
const [todoModalVisible, setTodoModalVisible] = useState(false);
@@ -136,12 +140,18 @@ const ChatWindow: React.FC<ChatWindowProps> = ({ contract }) => {
</Space>
</Header>
<div className={styles.extend}>
<Button icon={<BellOutlined />} onClick={handleFollowupClick}>
</Button>
<Button icon={<CheckSquareOutlined />} onClick={handleTodoClick}>
</Button>
{showChatRecordModel ? (
<ChatRecordSearch />
) : (
<>
<Button icon={<BellOutlined />} onClick={handleFollowupClick}>
</Button>
<Button icon={<CheckSquareOutlined />} onClick={handleTodoClick}>
</Button>
</>
)}
</div>
{/* 聊天内容 */}

View File

@@ -10,6 +10,8 @@ import {
* 包含聊天消息、联系人管理、朋友圈等功能的状态和方法
*/
export interface WeChatState {
showChatRecordModel: boolean;
updateShowChatRecordModel: (show: boolean) => void;
aiQuoteMessageContent: number;
updateAiQuoteMessageContent: (message: number) => void;
quoteMessageContent: string;

View File

@@ -33,6 +33,10 @@ import {
export const useWeChatStore = create<WeChatState>()(
persist(
(set, get) => ({
showChatRecordModel: false,
updateShowChatRecordModel: (show: boolean) => {
set({ showChatRecordModel: show });
},
//当前用户的ai接管状态
aiQuoteMessageContent: 0,
updateAiQuoteMessageContent: (message: number) => {
@@ -159,7 +163,8 @@ export const useWeChatStore = create<WeChatState>()(
} else {
params.wechatChatroomId = contract.id;
}
//重置动作
set({ showChatRecordModel: false });
clearUnreadCount1(params);
clearUnreadCount2([contract.id]);
getFriendInjectConfig({