diff --git a/Cunkebao/dist/.vite/manifest.json b/Cunkebao/dist/.vite/manifest.json
index 07c2448c..0e0486f5 100644
--- a/Cunkebao/dist/.vite/manifest.json
+++ b/Cunkebao/dist/.vite/manifest.json
@@ -33,7 +33,7 @@
"name": "vendor"
},
"index.html": {
- "file": "assets/index-CTEriEiT.js",
+ "file": "assets/index-PSLRJs-x.js",
"name": "index",
"src": "index.html",
"isEntry": true,
@@ -44,7 +44,7 @@
"_charts-ghR_XExL.js"
],
"css": [
- "assets/index-ZHlr-6NP.css"
+ "assets/index-2A02LaoT.css"
]
}
}
\ No newline at end of file
diff --git a/Cunkebao/dist/index.html b/Cunkebao/dist/index.html
index cc6295d6..9401fa4c 100644
--- a/Cunkebao/dist/index.html
+++ b/Cunkebao/dist/index.html
@@ -11,13 +11,13 @@
-
+
-
+
diff --git a/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/VideoMessage/VideoMessage.module.scss b/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/VideoMessage/VideoMessage.module.scss
new file mode 100644
index 00000000..a90b90a8
--- /dev/null
+++ b/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/VideoMessage/VideoMessage.module.scss
@@ -0,0 +1,153 @@
+// 通用消息文本样式
+.messageText {
+ color: #666;
+ font-style: italic;
+ padding: 8px 12px;
+ background: #f5f5f5;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+// 消息气泡样式
+.messageBubble {
+ display: inline-block;
+ max-width: 70%;
+ padding: 8px 12px;
+ border-radius: 12px;
+ word-wrap: break-word;
+ position: relative;
+}
+
+// 视频消息样式
+.videoMessage {
+ position: relative;
+ display: inline-block;
+ border-radius: 12px;
+ overflow: hidden;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ background: #000;
+
+ .videoContainer {
+ position: relative;
+ display: inline-block;
+ cursor: pointer;
+
+ video {
+ display: block;
+ max-width: 300px;
+ max-height: 400px;
+ border-radius: 8px;
+ }
+ }
+
+ .videoThumbnail {
+ display: block;
+ max-width: 300px;
+ max-height: 400px;
+ border-radius: 8px;
+ cursor: pointer;
+ transition: opacity 0.3s ease;
+ }
+
+ .videoPlayIcon {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ pointer-events: none;
+ z-index: 2;
+
+ .loadingSpinner {
+ width: 48px;
+ height: 48px;
+ border: 4px solid rgba(255, 255, 255, 0.3);
+ border-top: 4px solid #fff;
+ border-radius: 50%;
+ animation: spin 1s linear infinite;
+ }
+ }
+
+ .downloadButton {
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ width: 32px;
+ height: 32px;
+ background: rgba(0, 0, 0, 0.6);
+ border-radius: 50%;
+ color: white;
+ border: none;
+ cursor: pointer;
+ transition: background 0.2s;
+ text-decoration: none;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 3;
+
+ &:hover {
+ background: rgba(0, 0, 0, 0.8);
+ color: white;
+ }
+ }
+
+ .playButton {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 48px;
+ height: 48px;
+ background: rgba(0, 0, 0, 0.6);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: background 0.2s;
+
+ svg {
+ margin-left: 2px; // 视觉居中调整
+ }
+ }
+}
+
+@keyframes spin {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+}
+
+// 响应式设计
+@media (max-width: 768px) {
+ .messageBubble {
+ padding: 6px 10px;
+ }
+
+ .videoMessage .videoThumbnail,
+ .videoMessage .videoContainer video {
+ max-width: 200px;
+ max-height: 250px;
+ }
+
+ .videoMessage .videoPlayIcon {
+ .loadingSpinner {
+ width: 36px;
+ height: 36px;
+ border-width: 3px;
+ }
+ }
+
+ .videoMessage .downloadButton {
+ width: 28px;
+ height: 28px;
+ top: 6px;
+ right: 6px;
+
+ svg {
+ font-size: 14px !important;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/VideoMessage/index.tsx b/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/VideoMessage/index.tsx
new file mode 100644
index 00000000..1edbcd30
--- /dev/null
+++ b/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/VideoMessage/index.tsx
@@ -0,0 +1,182 @@
+import React from "react";
+import { DownloadOutlined, PlayCircleFilled } from "@ant-design/icons";
+import { ChatRecord, ContractData, weChatGroup } from "@/pages/pc/ckbox/data";
+import { useWeChatStore } from "@/store/module/weChat/weChat";
+import { useWebSocketStore } from "@/store/module/websocket/websocket";
+import styles from "./VideoMessage.module.scss";
+
+interface VideoMessageProps {
+ content: string;
+ msg: ChatRecord;
+ contract: ContractData | weChatGroup;
+}
+
+const VideoMessage: React.FC = ({
+ content,
+ msg,
+ contract,
+}) => {
+ // 检测是否为直接视频链接的函数
+ const isDirectVideoLink = (content: string): boolean => {
+ const trimmedContent = content.trim();
+ return (
+ trimmedContent.startsWith("http") &&
+ (trimmedContent.includes(".mp4") ||
+ trimmedContent.includes(".mov") ||
+ trimmedContent.includes(".avi") ||
+ trimmedContent.includes("video"))
+ );
+ };
+
+ // 处理视频播放请求,发送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 renderErrorMessage = (message: string) => (
+ {message}
+ );
+
+ if (typeof content !== "string" || !content.trim()) {
+ return renderErrorMessage("[视频消息 - 无效内容]");
+ }
+
+ // 如果content是直接的视频链接(已预览过或下载好的视频)
+ if (isDirectVideoLink(content)) {
+ return (
+
+ );
+ }
+
+ try {
+ // 尝试解析JSON格式的视频数据
+ if (content.startsWith("{") && content.endsWith("}")) {
+ const videoData = JSON.parse(content);
+
+ // 验证必要的视频数据字段
+ if (
+ videoData &&
+ typeof videoData === "object" &&
+ videoData.previewImage &&
+ videoData.tencentUrl
+ ) {
+ const previewImageUrl = String(videoData.previewImage).replace(
+ /[`"']/g,
+ "",
+ );
+
+ // 创建点击处理函数
+ const handlePlayClick = (e: React.MouseEvent, msg: ChatRecord) => {
+ e.stopPropagation();
+ // 如果没有视频URL且不在加载中,则发起下载请求
+ if (!videoData.videoUrl && !videoData.isLoading) {
+ handleVideoPlayRequest(videoData.tencentUrl, msg.id);
+ }
+ };
+
+ // 如果已有视频URL,显示视频播放器
+ if (videoData.videoUrl) {
+ return (
+
+ );
+ }
+
+ // 显示预览图,根据加载状态显示不同的图标
+ return (
+
+
+
handlePlayClick(e, msg)}
+ >
+

{
+ const target = e.target as HTMLImageElement;
+ const parent = target.parentElement?.parentElement;
+ if (parent) {
+ parent.innerHTML = `
[视频预览加载失败]
`;
+ }
+ }}
+ />
+
+ {videoData.isLoading ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ );
+ }
+ }
+ return renderErrorMessage("[视频消息]");
+ } catch (e) {
+ console.warn("视频消息解析失败:", e);
+ return renderErrorMessage("[视频消息 - 解析失败]");
+ }
+};
+
+export default VideoMessage;
diff --git a/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx b/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx
index dfebaab4..001c0954 100644
--- a/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx
+++ b/Cunkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx
@@ -1,19 +1,14 @@
-import React, { useEffect, useRef, useState } from "react";
+import React, { useEffect, useRef } from "react";
import { Avatar, Divider } from "antd";
-import {
- UserOutlined,
- LoadingOutlined,
- DownloadOutlined,
- PlayCircleFilled,
-} from "@ant-design/icons";
+import { UserOutlined, LoadingOutlined } from "@ant-design/icons";
import AudioMessage from "./components/AudioMessage/AudioMessage";
import SmallProgramMessage from "./components/SmallProgramMessage";
+import VideoMessage from "./components/VideoMessage";
import { ChatRecord, ContractData, weChatGroup } from "@/pages/pc/ckbox/data";
-import { formatWechatTime, parseWeappMsgStr } from "@/utils/common";
+import { formatWechatTime } from "@/utils/common";
import { getEmojiPath } from "@/components/EmojiSeclection/wechatEmoji";
import styles from "./MessageRecord.module.scss";
import { useWeChatStore } from "@/store/module/weChat/weChat";
-import { useWebSocketStore } from "@/store/module/websocket/websocket";
interface MessageRecordProps {
contract: ContractData | weChatGroup;
@@ -30,18 +25,6 @@ const MessageRecord: React.FC = ({ contract }) => {
);
const prevMessagesRef = useRef(currentMessages);
- // 检测是否为直接视频链接的函数
- const isDirectVideoLink = (content: string): boolean => {
- const trimmedContent = content.trim();
- return (
- trimmedContent.startsWith("http") &&
- (trimmedContent.includes(".mp4") ||
- trimmedContent.includes(".mov") ||
- trimmedContent.includes(".avi") ||
- trimmedContent.includes("video"))
- );
- };
-
// 判断是否为表情包URL的工具函数
const isEmojiUrl = (content: string): boolean => {
return (
@@ -156,23 +139,6 @@ const MessageRecord: React.FC = ({ contract }) => {
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,
- });
- };
-
// 解析消息内容,根据msgType判断消息类型并返回对应的渲染内容
const parseMessageContent = (
content: string | null | undefined,
@@ -228,136 +194,9 @@ const MessageRecord: React.FC = ({ contract }) => {
);
case 43: // 视频消息
- if (typeof content !== "string" || !content.trim()) {
- return renderErrorMessage("[视频消息 - 无效内容]");
- }
-
- // 如果content是直接的视频链接(已预览过或下载好的视频)
- if (isDirectVideoLink(content)) {
- return (
-
- );
- }
-
- try {
- // 尝试解析JSON格式的视频数据
- if (content.startsWith("{") && content.endsWith("}")) {
- const videoData = JSON.parse(content);
-
- // 验证必要的视频数据字段
- if (
- videoData &&
- typeof videoData === "object" &&
- videoData.previewImage &&
- videoData.tencentUrl
- ) {
- const previewImageUrl = String(videoData.previewImage).replace(
- /[`"']/g,
- "",
- );
-
- // 创建点击处理函数
- const handlePlayClick = (
- e: React.MouseEvent,
- msg: ChatRecord,
- ) => {
- e.stopPropagation();
- // 如果没有视频URL且不在加载中,则发起下载请求
- if (!videoData.videoUrl && !videoData.isLoading) {
- handleVideoPlayRequest(videoData.tencentUrl, msg.id);
- }
- };
-
- // 如果已有视频URL,显示视频播放器
- if (videoData.videoUrl) {
- return (
-
- );
- }
-
- // 显示预览图,根据加载状态显示不同的图标
- return (
-
-
-
handlePlayClick(e, msg)}
- >
-

{
- const target = e.target as HTMLImageElement;
- const parent = target.parentElement?.parentElement;
- if (parent) {
- parent.innerHTML = `
[视频预览加载失败]
`;
- }
- }}
- />
-
- {videoData.isLoading ? (
-
- ) : (
-
- )}
-
-
-
-
- );
- }
- }
- return renderErrorMessage("[视频消息]");
- } catch (e) {
- console.warn("视频消息解析失败:", e);
- return renderErrorMessage("[视频消息 - 解析失败]");
- }
+ return (
+
+ );
case 47: // 动图表情包(gif、其他表情包)
if (typeof content !== "string" || !content.trim()) {