From ef853d273692757564007c1dcf2dfb1886516a89 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: Wed, 3 Sep 2025 16:06:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(weChat):=20=E9=87=8D=E6=9E=84=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E6=B6=88=E6=81=AF=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E5=B9=B6=E4=BC=98=E5=8C=96=E5=8A=A0=E8=BD=BD=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除旧的待处理视频请求队列及相关方法 - 新增setVideoLoading和setVideoUrl方法简化视频状态管理 - 优化ChatWindow组件中的视频加载状态检测和滚动行为 - 添加CmdDownloadVideoResult消息处理器自动更新视频URL --- .../pc/ckbox/components/ChatWindow/index.tsx | 113 +++++++++-------- .../src/store/module/weChat/weChat.data.ts | 14 +-- Cunkebao/src/store/module/weChat/weChat.ts | 116 +++++------------- .../src/store/module/websocket/msgManage.ts | 6 + 4 files changed, 96 insertions(+), 153 deletions(-) diff --git a/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx b/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx index c4473c64..bb9edc97 100644 --- a/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx +++ b/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx @@ -38,9 +38,37 @@ const ChatWindow: React.FC = ({ }) => { const messagesEndRef = useRef(null); const currentMessages = useWeChatStore(state => state.currentMessages); + const prevMessagesRef = useRef(currentMessages); useEffect(() => { - // 只有在非视频加载操作时才自动滚动到底部 + const prevMessages = prevMessagesRef.current; + + // 检查是否有视频状态变化(从加载中变为已完成) + const hasVideoStateChange = currentMessages.some((msg, index) => { + const prevMsg = prevMessages[index]; + if (!prevMsg) 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; + + // 检查是否从加载中变为已完成(有videoUrl) + return ( + prevContent.isLoading === true && + currentContent.isLoading === false && + currentContent.videoUrl + ); + } catch (e) { + return false; + } + }); + // 检查是否有视频正在加载中 const hasLoadingVideo = currentMessages.some(msg => { try { @@ -54,16 +82,14 @@ const ChatWindow: React.FC = ({ } }); - if (!hasLoadingVideo) { + // 只有在没有视频加载且没有视频状态变化时才自动滚动到底部 + if (!hasLoadingVideo && !hasVideoStateChange) { scrollToBottom(); } - }, [currentMessages]); - // 初始化WebSocket监听 - useEffect(() => { - const unsubscribe = useWeChatStore.getState().initWebSocketListener(); - return unsubscribe; - }, []); + // 更新上一次的消息状态 + prevMessagesRef.current = currentMessages; + }, [currentMessages]); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); @@ -71,26 +97,19 @@ const ChatWindow: React.FC = ({ // 处理视频播放请求,发送socket请求获取真实视频地址 const handleVideoPlayRequest = (tencentUrl: string, messageId: number) => { - // 生成请求ID (使用当前时间戳作为唯一标识) - const requestSeq = `${+new Date()}`; - console.log("发送视频下载请求:", { messageId, requestSeq }); + 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: requestSeq, // 使用唯一的请求ID + seq: `${+new Date()}`, // 使用时间戳作为请求序列号 tencentUrl: tencentUrl, wechatAccountId: contract.wechatAccountId, }); - - // 将消息ID添加到待处理队列 - useWeChatStore - .getState() - .addPendingVideoRequest(messageId.toString(), messageId.toString()); - - // 更新消息状态为加载中 - useWeChatStore.getState().setMessageLoading(messageId.toString(), true); }; // 解析消息内容,判断消息类型并返回对应的渲染内容 @@ -121,21 +140,22 @@ const ChatWindow: React.FC = ({ content.trim().endsWith("}") ) { const videoData = JSON.parse(content); - // 处理用户提供的JSON格式 {"previewImage":"https://...", "tencentUrl":"..."} + // 处理视频消息格式 {"previewImage":"https://...", "tencentUrl":"...", "videoUrl":"...", "isLoading":true} if (videoData.previewImage && videoData.tencentUrl) { // 提取预览图URL,去掉可能的引号 const previewImageUrl = videoData.previewImage.replace(/[`"']/g, ""); - // 创建点击处理函数,调用handleVideoPlayRequest发送socket请求获取真实视频地址 + // 创建点击处理函数 const handlePlayClick = (e: React.MouseEvent) => { e.stopPropagation(); - // 调用处理函数,传入tencentUrl和消息ID - handleVideoPlayRequest(videoData.tencentUrl, msg.id); + // 如果没有视频URL且不在加载中,则发起下载请求 + if (!videoData.videoUrl && !videoData.isLoading) { + handleVideoPlayRequest(videoData.tencentUrl, msg.id); + } }; - // 检查是否已下载视频URL + // 如果已有视频URL,显示视频播放器 if (videoData.videoUrl) { - // 已获取到视频URL,显示视频播放器 return (
@@ -158,30 +178,7 @@ const ChatWindow: React.FC = ({ ); } - // 检查是否处于加载状态 - if (videoData.isLoading) { - return ( -
-
- 视频预览 -
-
-
-
-
- ); - } - - // 默认显示预览图和播放按钮 + // 显示预览图,根据加载状态显示不同的图标 return (
@@ -189,12 +186,20 @@ const ChatWindow: React.FC = ({ src={previewImageUrl} alt="视频预览" className={styles.videoThumbnail} - style={{ maxWidth: "100%", borderRadius: "8px" }} + style={{ + maxWidth: "100%", + borderRadius: "8px", + opacity: videoData.isLoading ? "0.7" : "1", + }} />
- + {videoData.isLoading ? ( +
+ ) : ( + + )}
diff --git a/Cunkebao/src/store/module/weChat/weChat.data.ts b/Cunkebao/src/store/module/weChat/weChat.data.ts index 955ce031..1f938d32 100644 --- a/Cunkebao/src/store/module/weChat/weChat.data.ts +++ b/Cunkebao/src/store/module/weChat/weChat.data.ts @@ -10,19 +10,11 @@ export interface WeChatState { // 消息加载状态 messagesLoading: boolean; - // 待处理的视频请求队列 - pendingVideoRequests: Record; - // Actions setCurrentContact: (contract: ContractData | weChatGroup) => void; loadChatMessages: (contact: ContractData | weChatGroup) => Promise; - // 视频请求相关方法 - addPendingVideoRequest: (messageId: string, requestId: string) => void; - removePendingVideoRequest: (messageId: string) => void; - updateMessageWithVideo: (messageId: string, videoUrl: string) => void; - setMessageLoading: (messageId: string, isLoading: boolean) => void; - - // WebSocket监听初始化 - initWebSocketListener: () => void; + // 视频消息处理方法 + setVideoLoading: (messageId: number, isLoading: boolean) => void; + setVideoUrl: (messageId: number, videoUrl: string) => void; } diff --git a/Cunkebao/src/store/module/weChat/weChat.ts b/Cunkebao/src/store/module/weChat/weChat.ts index 633969b8..30d02e14 100644 --- a/Cunkebao/src/store/module/weChat/weChat.ts +++ b/Cunkebao/src/store/module/weChat/weChat.ts @@ -5,10 +5,7 @@ import { WeChatState } from "./weChat.data"; import { clearUnreadCount, updateConfig } from "@/pages/pc/ckbox/api"; import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; import { addChatSession } from "@/store/module/ckchat/ckchat"; -import { - useWebSocketStore, - WebSocketMessage, -} from "@/store/module/websocket/websocket"; + export const useWeChatStore = create()( persist( (set, get) => ({ @@ -16,7 +13,6 @@ export const useWeChatStore = create()( currentContract: null, currentMessages: [], messagesLoading: false, - pendingVideoRequests: {}, // Actions setCurrentContact: (contract: ContractData | weChatGroup) => { @@ -85,43 +81,22 @@ export const useWeChatStore = create()( getCurrentMessages: () => get().currentMessages, getMessagesLoading: () => get().messagesLoading, - // 视频请求相关方法 - addPendingVideoRequest: (messageId: string, requestId: string) => { - set(state => ({ - pendingVideoRequests: { - ...state.pendingVideoRequests, - [messageId]: requestId, - }, - })); - }, - - removePendingVideoRequest: (messageId: string) => { - set(state => { - const newRequests = { ...state.pendingVideoRequests }; - delete newRequests[messageId]; - return { pendingVideoRequests: newRequests }; - }); - }, - - updateMessageWithVideo: (messageId: string, videoUrl: string) => { + // 视频消息处理方法 + setVideoLoading: (messageId: number, isLoading: boolean) => { set(state => ({ currentMessages: state.currentMessages.map(msg => { - if (msg.id === Number(messageId)) { + if (msg.id === messageId) { try { - const msgContent = - typeof msg.content === "string" - ? JSON.parse(msg.content) - : msg.content; + const content = JSON.parse(msg.content); + // 更新加载状态 + const updatedContent = { ...content, isLoading }; return { ...msg, - content: JSON.stringify({ - ...msgContent, - videoUrl: videoUrl, - isLoading: false, - }), + content: JSON.stringify(updatedContent), }; } catch (e) { - console.error("解析消息内容失败:", e); + console.error("更新视频加载状态失败:", e); + return msg; } } return msg; @@ -129,77 +104,42 @@ export const useWeChatStore = create()( })); }, - setMessageLoadingStatus: (messageId: string, isLoading: boolean) => { + setVideoUrl: (messageId: number, videoUrl: string) => { set(state => ({ currentMessages: state.currentMessages.map(msg => { - if (msg.id === Number(messageId)) { + if (msg.id === messageId) { try { - const originalContent = msg.content; + const content = JSON.parse(msg.content); + // 检查视频是否已经下载完毕,避免重复更新 + if (content.videoUrl && content.videoUrl === videoUrl) { + console.log("视频已下载,跳过重复更新:", messageId); + return msg; + } + + // 设置视频URL并清除加载状态 + const updatedContent = { + ...content, + videoUrl, + isLoading: false, + }; return { ...msg, - content: JSON.stringify({ - ...JSON.parse(originalContent), - isLoading: isLoading, - }), + content: JSON.stringify(updatedContent), }; } catch (e) { - console.error("解析消息内容失败:", e); + console.error("更新视频URL失败:", e); + return msg; } } return msg; }), })); }, - - // WebSocket监听初始化 - initWebSocketListener: () => { - const unsubscribe = useWebSocketStore.subscribe(state => { - const messages = state.messages as WebSocketMessage[]; - const currentState = get(); - - // 只有当有待处理的视频请求时才处理 - if (Object.keys(currentState.pendingVideoRequests).length === 0) { - return; - } - - messages.forEach(message => { - if (message?.content?.cmdType === "CmdDownloadVideoResult") { - console.log("收到视频下载响应:", message.content); - - // 检查是否是我们正在等待的视频响应 - const messageId = Object.keys( - currentState.pendingVideoRequests, - ).find( - id => - currentState.pendingVideoRequests[id] === - message.content.friendMessageId, - ); - - if (messageId) { - console.log("找到对应的消息ID:", messageId); - - // 从待处理队列中移除 - currentState.removePendingVideoRequest(messageId); - - // 更新消息内容,添加视频URL - currentState.updateMessageWithVideo( - messageId, - message.content.url, - ); - } - } - }); - }); - - return unsubscribe; - }, - clearAllData: () => { set({ currentContract: null, currentMessages: [], messagesLoading: false, - pendingVideoRequests: {}, }); }, }), diff --git a/Cunkebao/src/store/module/websocket/msgManage.ts b/Cunkebao/src/store/module/websocket/msgManage.ts index 484058af..4efc7a56 100644 --- a/Cunkebao/src/store/module/websocket/msgManage.ts +++ b/Cunkebao/src/store/module/websocket/msgManage.ts @@ -3,6 +3,8 @@ import { deepCopy } from "@/utils/common"; import { WebSocketMessage } from "./websocket"; import { getkfUserList, asyncKfUserList } from "@/store/module/ckchat/ckchat"; import { Messages } from "./msg.data"; + +import { useWeChatStore } from "@/store/module/weChat/weChat"; // 消息处理器类型定义 type MessageHandler = (message: WebSocketMessage) => void; @@ -52,6 +54,10 @@ const messageHandlers: Record = { } }, + CmdDownloadVideoResult: message => { + // 在这里添加具体的处理逻辑 + useWeChatStore.getState().setVideoUrl(message.friendMessageId, message.url); + }, // 可以继续添加更多处理器... };