From 18ec2752badc2324057b9e8fd93b61a5dbe35a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E8=80=81=E7=99=BD=E5=85=94?= Date: Fri, 5 Sep 2025 15:36:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pc/ckbox/components/ChatWindow/index.tsx | 616 +----------------- 1 file changed, 5 insertions(+), 611 deletions(-) diff --git a/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx b/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx index 1b1b155c..e90aab2a 100644 --- a/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx +++ b/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx @@ -5,24 +5,15 @@ import { VideoCameraOutlined, MoreOutlined, UserOutlined, - DownloadOutlined, - FileOutlined, - FilePdfOutlined, - FileWordOutlined, - FileExcelOutlined, - FilePptOutlined, - PlayCircleFilled, TeamOutlined, - FolderOutlined, - EnvironmentOutlined, } from "@ant-design/icons"; -import { ChatRecord, ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; +import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; import styles from "./ChatWindow.module.scss"; -import { useWebSocketStore } from "@/store/module/websocket/websocket"; -import { formatWechatTime } from "@/utils/common"; + import ProfileCard from "./components/ProfileCard"; import MessageEnter from "./components/MessageEnter"; -import { useWeChatStore } from "@/store/module/weChat/weChat"; +import MessageRecord from "./components/MessageRecord"; + const { Header, Content } = Layout; interface ChatWindowProps { @@ -36,595 +27,6 @@ const ChatWindow: React.FC = ({ showProfile = true, onToggleProfile, }) => { - const messagesEndRef = useRef(null); - const currentMessages = useWeChatStore(state => state.currentMessages); - const currentGroupMembers = useWeChatStore( - state => state.currentGroupMembers, - ); - const prevMessagesRef = useRef(currentMessages); - - useEffect(() => { - const prevMessages = prevMessagesRef.current; - - const hasVideoStateChange = currentMessages.some((msg, index) => { - // 首先检查消息对象本身是否为null或undefined - if (!msg || !msg.content) return false; - - const prevMsg = prevMessages[index]; - if (!prevMsg || !prevMsg.content || prevMsg.id !== msg.id) return false; - - try { - const currentContent = - typeof msg.content === "string" - ? JSON.parse(msg.content) - : msg.content; - const prevContent = - typeof prevMsg.content === "string" - ? JSON.parse(prevMsg.content) - : prevMsg.content; - - // 检查视频状态是否发生变化(开始加载、完成加载、获得URL) - const currentHasVideo = - currentContent.previewImage && currentContent.tencentUrl; - const prevHasVideo = prevContent.previewImage && prevContent.tencentUrl; - - if (currentHasVideo && prevHasVideo) { - // 检查加载状态变化或视频URL变化 - return ( - currentContent.isLoading !== prevContent.isLoading || - currentContent.videoUrl !== prevContent.videoUrl - ); - } - - return false; - } catch (e) { - return false; - } - }); - - // 只有在没有视频状态变化时才自动滚动到底部 - if (!hasVideoStateChange) { - scrollToBottom(); - } - - // 更新上一次的消息状态 - prevMessagesRef.current = currentMessages; - }, [currentMessages]); - - const scrollToBottom = () => { - messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); - }; - - // 处理视频播放请求,发送socket请求获取真实视频地址 - const handleVideoPlayRequest = (tencentUrl: string, messageId: number) => { - console.log("发送视频下载请求:", { messageId, tencentUrl }); - - // 先设置加载状态 - useWeChatStore.getState().setVideoLoading(messageId, true); - - // 构建socket请求数据 - useWebSocketStore.getState().sendCommand("CmdDownloadVideo", { - chatroomMessageId: contract.chatroomId ? messageId : 0, - friendMessageId: contract.chatroomId ? 0 : messageId, - seq: `${+new Date()}`, // 使用时间戳作为请求序列号 - tencentUrl: tencentUrl, - wechatAccountId: contract.wechatAccountId, - }); - }; - - // 解析消息内容,判断消息类型并返回对应的渲染内容 - const parseMessageContent = ( - content: string | null | undefined, - msg: ChatRecord, - ) => { - // 处理null或undefined的内容 - if (content === null || content === undefined) { - return
消息内容不可用
; - } - // 检查是否为表情包 - if ( - typeof content === "string" && - content.includes("ac-weremote-s2.oss-cn-shenzhen.aliyuncs.com") && - content.includes("#") - ) { - return ( -
- 表情包 window.open(content, "_blank")} - /> -
- ); - } - - // 检查是否为带预览图的视频消息 - try { - if ( - typeof content === "string" && - content.trim().startsWith("{") && - content.trim().endsWith("}") - ) { - const videoData = JSON.parse(content); - // 处理视频消息格式 {"previewImage":"https://...", "tencentUrl":"...", "videoUrl":"...", "isLoading":true} - if (videoData.previewImage && videoData.tencentUrl) { - // 提取预览图URL,去掉可能的引号 - const previewImageUrl = videoData.previewImage.replace(/[`"']/g, ""); - - // 创建点击处理函数 - const handlePlayClick = (e: React.MouseEvent) => { - e.stopPropagation(); - // 如果没有视频URL且不在加载中,则发起下载请求 - if (!videoData.videoUrl && !videoData.isLoading) { - handleVideoPlayRequest(videoData.tencentUrl, msg.id); - } - }; - - // 如果已有视频URL,显示视频播放器 - if (videoData.videoUrl) { - return ( -
-
-
-
- ); - } - - // 显示预览图,根据加载状态显示不同的图标 - return ( -
-
- 视频预览 -
- {videoData.isLoading ? ( -
- ) : ( - - )} -
-
-
- ); - } - // 保留原有的视频处理逻辑 - else if ( - videoData.type === "video" && - videoData.url && - videoData.thumb - ) { - return ( -
-
window.open(videoData.url, "_blank")} - > - 视频预览 -
- -
-
- e.stopPropagation()} - > - - -
- ); - } - } - } catch (e) { - // 解析JSON失败,不是视频消息 - console.log("解析视频消息失败:", e); - } - - // 检查是否为图片链接 - if ( - typeof content === "string" && - (content.match(/\.(jpg|jpeg|png|gif)$/i) || - (content.includes("oss-cn-shenzhen.aliyuncs.com") && - content.includes(".jpg"))) - ) { - return ( -
- 图片消息 window.open(content, "_blank")} - /> -
- ); - } - - // 检查是否为视频链接 - if ( - typeof content === "string" && - (content.match(/\.(mp4|avi|mov|wmv|flv)$/i) || - (content.includes("oss-cn-shenzhen.aliyuncs.com") && - content.includes(".mp4"))) - ) { - return ( -
-
- ); - } - - // 检查是否为音频链接 - if ( - typeof content === "string" && - (content.match(/\.(mp3|wav|ogg|m4a)$/i) || - (content.includes("oss-cn-shenzhen.aliyuncs.com") && - content.includes(".mp3"))) - ) { - return ( -
-
- ); - } - - // 检查是否为Office文件链接 - if ( - typeof content === "string" && - content.match(/\.(doc|docx|xls|xlsx|ppt|pptx|pdf)$/i) - ) { - const fileName = content.split("/").pop() || "文件"; - const fileExt = fileName.split(".").pop()?.toLowerCase(); - - // 根据文件类型选择不同的图标 - let fileIcon = ( - - ); - - if (fileExt === "pdf") { - fileIcon = ( - - ); - } else if (fileExt === "doc" || fileExt === "docx") { - fileIcon = ( - - ); - } else if (fileExt === "xls" || fileExt === "xlsx") { - fileIcon = ( - - ); - } else if (fileExt === "ppt" || fileExt === "pptx") { - fileIcon = ( - - ); - } - - return ( - - ); - } - - // 检查是否为文件消息(JSON格式) - try { - if ( - typeof content === "string" && - content.trim().startsWith("{") && - content.trim().endsWith("}") - ) { - const fileData = JSON.parse(content); - if (fileData.type === "file" && fileData.title) { - // 检查是否为Office文件 - const fileExt = fileData.title.split(".").pop()?.toLowerCase(); - let fileIcon = ( - - ); - - if (fileExt === "pdf") { - fileIcon = ( - - ); - } else if (fileExt === "doc" || fileExt === "docx") { - fileIcon = ( - - ); - } else if (fileExt === "xls" || fileExt === "xlsx") { - fileIcon = ( - - ); - } else if (fileExt === "ppt" || fileExt === "pptx") { - fileIcon = ( - - ); - } - - return ( -
- {fileIcon} -
-
- {fileData.title} -
- {fileData.totalLen && ( -
- {Math.round(fileData.totalLen / 1024)} KB -
- )} -
- { - e.stopPropagation(); - if (!fileData.url) { - console.log("文件URL不存在"); - } - }} - rel="noreferrer" - > - - -
- ); - } - } - } catch (e) { - // 解析JSON失败,不是文件消息 - } - - // 检查是否为位置信息 - if ( - typeof content === "string" && - (content.includes(" - -
-
{label}
- {coordinates && ( -
- {coordinates} -
- )} -
- - ); - } - - // 默认为文本消息 - return
{content}
; - }; - - // 用于分组消息并添加时间戳的辅助函数 - const groupMessagesByTime = (messages: ChatRecord[]) => { - return messages - .filter(msg => msg !== null && msg !== undefined) // 过滤掉null和undefined的消息 - .map(msg => ({ - time: formatWechatTime(msg?.wechatTime), - messages: [msg], - })); - }; - const groupMemberAvatar = (msg: ChatRecord) => { - if (!msg?.sender) { - return undefined; - } - const groupMember = currentGroupMembers.find( - (v) => v?.wechatId === msg.sender.wechatId - ); - return groupMember?.avatar; - }; - const clearWechatidInContent = (sender, content: string) => { - if (!sender || !sender.wechatId || !content) return content; - return content.replace(new RegExp(`${sender.wechatId}:\n`, "g"), ""); - }; - const renderMessage = (msg: ChatRecord) => { - console.log(msg); - // 添加null检查,防止访问null对象的属性 - if (!msg) return null; - - const isOwn = msg?.isSend; - const isGroup = !!contract.chatroomId; - return ( -
-
- {/* 如果不是群聊 */} - {!isGroup && !isOwn && ( - <> - } - className={styles.messageAvatar} - /> - -
- {!isOwn && ( -
- {contract.nickname} -
- )} - {parseMessageContent(msg?.content, msg)} -
- - )} - {/* 如果是群聊 */} - {isGroup && !isOwn && ( - <> - } - className={styles.messageAvatar} - /> - -
- {!isOwn && ( -
- {msg?.sender?.nickname} -
- )} - {parseMessageContent( - clearWechatidInContent(msg?.sender, msg?.content), - msg, - )} -
- - )} - - {isOwn && ( -
- {parseMessageContent(msg?.content, msg)} -
- )} -
-
- ); - }; - const chatMenu = ( }> @@ -693,15 +95,7 @@ const ChatWindow: React.FC = ({ {/* 聊天内容 */} -
- {groupMessagesByTime(currentMessages).map((group, groupIndex) => ( - -
{group.time}
- {group.messages.map(renderMessage)} -
- ))} -
-
+ {/* 消息输入组件 */}