From 13ae8bd76f4235ec0de33146ed7448f810b7dc1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=98=E9=A3=8E?= Date: Mon, 1 Dec 2025 10:38:27 +0800 Subject: [PATCH 01/10] Enhance message filtering to support WeChat red packet messages, allowing for sender identification in chat records. --- Touchkebao/src/utils/filter.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Touchkebao/src/utils/filter.ts b/Touchkebao/src/utils/filter.ts index 22887a8b..c2fa1a6b 100644 --- a/Touchkebao/src/utils/filter.ts +++ b/Touchkebao/src/utils/filter.ts @@ -40,6 +40,18 @@ export const messageFilter = (message: string) => { case !!parsed.linkUrl: return "[链接]"; + // 微信红包消息:包含 paymsgid 或 nativeurl 中包含红包链接 + case !!( + parsed.paymsgid || + (parsed.nativeurl && + parsed.nativeurl.includes( + "wxpay://c2cbizmessagehandler/hongbao/receivehongbao", + )) + ): + return parsed.sendertitle + ? `[微信红包] ${parsed.sendertitle}` + : "[微信红包]"; + // 文本消息:包含 text 或 content case !!(parsed.text || parsed.content): return parsed.text || parsed.content; From b9bc0a71a9ef4901ec5d1a172c48ab86909e66cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=98=E9=A3=8E?= Date: Mon, 1 Dec 2025 10:56:05 +0800 Subject: [PATCH 02/10] =?UTF-8?q?=E5=9C=A8MessageRecord=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E4=B8=AD=E5=A2=9E=E5=8A=A0=E5=BE=AE=E4=BF=A1=E8=BD=AC=E8=B4=A6?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=94=AF=E6=8C=81=EF=BC=8C=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E8=BF=87=E6=BB=A4=E9=80=BB=E8=BE=91=E3=80=82?= =?UTF-8?q?=E8=B0=83=E6=95=B4RedPacketMessage=E6=A0=B7=E5=BC=8F=E4=BB=A5?= =?UTF-8?q?=E8=8E=B7=E5=BE=97=E6=9B=B4=E5=A5=BD=E7=9A=84=E5=B8=83=E5=B1=80?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RedPacketMessage.module.scss | 2 +- .../TransferMessage.module.scss | 124 ++++++++++++++++++ .../components/TransferMessage/index.tsx | 71 ++++++++++ .../components/MessageRecord/index.tsx | 9 ++ Touchkebao/src/utils/filter.ts | 7 + 5 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/TransferMessage.module.scss create mode 100644 Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/index.tsx diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/RedPacketMessage/RedPacketMessage.module.scss b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/RedPacketMessage/RedPacketMessage.module.scss index 1d8603b0..11aa32a0 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/RedPacketMessage/RedPacketMessage.module.scss +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/RedPacketMessage/RedPacketMessage.module.scss @@ -2,7 +2,7 @@ .redPacketMessage { background: transparent; box-shadow: none; - max-width: 300px; + width: 260px; } .redPacketCard { diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/TransferMessage.module.scss b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/TransferMessage.module.scss new file mode 100644 index 00000000..1f5aa75f --- /dev/null +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/TransferMessage.module.scss @@ -0,0 +1,124 @@ +// 转账消息样式 +.transferMessage { + background: transparent; + box-shadow: none; + width: 260px; + max-width: 260px; +} + +.transferCard { + position: relative; + display: flex; + flex-direction: column; + padding: 12px; + background: #ff9500; // 橙色背景 + border-radius: 8px; + cursor: pointer; + transition: all 0.2s ease; + box-shadow: 0 2px 8px rgba(255, 149, 0, 0.2); + + &:hover { + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(255, 149, 0, 0.3); + } + + &:active { + transform: translateY(0); + } +} + +.transferHeader { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 5px; +} + +.transferIcon { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + background: #ffffff; + border-radius: 50%; + flex-shrink: 0; + font-size: 18px; + color: #ff9500; +} + +.transferAmount { + font-size: 20px; + font-weight: 600; + color: #ffffff; + line-height: 1.2; + flex: 1; +} + +.transferStatus { + font-size: 13px; + color: #ffffff; + margin-bottom: 5px; + opacity: 0.95; +} + +.transferDivider { + height: 1px; + background: rgba(255, 255, 255, 0.3); + margin-bottom: 6px; +} + +.transferFooter { + display: flex; + align-items: center; + justify-content: flex-start; +} + +.transferLabel { + font-size: 12px; + color: rgba(255, 255, 255, 0.9); + font-weight: 400; + line-height: 1.4; +} + +// 消息文本样式(用于错误提示) +.messageText { + line-height: 1.4; + white-space: pre-wrap; + word-break: break-word; + color: #8c8c8c; + font-size: 13px; +} + +// 响应式设计 +@media (max-width: 768px) { + .transferMessage { + max-width: 200px; + } + + .transferCard { + padding: 12px; + } + + .transferIcon { + width: 28px; + height: 28px; + + svg { + width: 18px; + height: 18px; + } + } + + .transferAmount { + font-size: 18px; + } + + .transferStatus { + font-size: 12px; + } + + .transferLabel { + font-size: 11px; + } +} diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/index.tsx new file mode 100644 index 00000000..c46c3926 --- /dev/null +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/index.tsx @@ -0,0 +1,71 @@ +import React from "react"; +import { SwapOutlined } from "@ant-design/icons"; +import styles from "./TransferMessage.module.scss"; + +interface TransferData { + title?: string; + feedesc?: string; + payMemo?: string; + transferid?: string; + transcationid?: string; + invalidtime?: string; + paysubtype?: string; + [key: string]: any; +} + +interface TransferMessageProps { + content: string; +} + +const TransferMessage: React.FC = ({ content }) => { + const renderErrorMessage = (fallbackText: string) => ( +
{fallbackText}
+ ); + + if (typeof content !== "string" || !content.trim()) { + return renderErrorMessage("[转账消息 - 无效内容]"); + } + + try { + const trimmedContent = content.trim(); + const jsonData: TransferData = JSON.parse(trimmedContent); + + // 验证是否为转账消息 + const isTransfer = + jsonData.title === "微信转账" || + (jsonData.transferid && jsonData.feedesc); + + if (!isTransfer) { + return renderErrorMessage("[转账消息 - 格式错误]"); + } + + const amount = jsonData.feedesc || "¥0.00"; + const memo = jsonData.payMemo || ""; + // 根据转账状态显示不同的提示文字 + // 可以根据实际业务逻辑判断状态,这里默认显示"待朋友确认收钱" + const statusText = "待朋友确认收钱"; + + return ( +
+
+
+
+ +
+
{amount}
+
+
{statusText}
+
+
+ 微信转账 +
+
+
+ ); + } catch (e) { + console.warn("转账消息解析失败:", e); + return renderErrorMessage("[转账消息 - 解析失败]"); + } +}; + +export default TransferMessage; diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx index ccd4759b..ad11cec5 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx @@ -8,6 +8,7 @@ import ClickMenu from "./components/ClickMeau"; import LocationMessage from "./components/LocationMessage"; import SystemRecommendRemarkMessage from "./components/SystemRecommendRemarkMessage/index"; import RedPacketMessage from "./components/RedPacketMessage"; +import TransferMessage from "./components/TransferMessage"; import { ChatRecord, ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; import { formatWechatTime } from "@/utils/common"; import { getEmojiPath } from "@/components/EmojiSeclection/wechatEmoji"; @@ -274,6 +275,14 @@ const MessageRecord: React.FC = ({ contract }) => { return ; } + // 判断是否为转账消息 + if ( + jsonData.title === "微信转账" || + (jsonData.transferid && jsonData.feedesc) + ) { + return ; + } + if (jsonData.type === "file" && msg && contract) { return ( { ? `[微信红包] ${parsed.sendertitle}` : "[微信红包]"; + // 微信转账消息:包含 title="微信转账" 或 transferid + feedesc + case !!( + parsed.title === "微信转账" || + (parsed.transferid && parsed.feedesc) + ): + return parsed.feedesc ? `[微信转账] ${parsed.feedesc}` : "[微信转账]"; + // 文本消息:包含 text 或 content case !!(parsed.text || parsed.content): return parsed.text || parsed.content; From 1ca5b30c1582e98f4f1b4d04a6abb631996f0c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=98=E9=A3=8E?= Date: Mon, 1 Dec 2025 10:59:50 +0800 Subject: [PATCH 03/10] Refactor TransferMessage component to improve layout and styling. Adjust icon size and add status display for better user experience. --- .../TransferMessage/TransferMessage.module.scss | 12 +++++------- .../components/TransferMessage/index.tsx | 9 ++++++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/TransferMessage.module.scss b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/TransferMessage.module.scss index 1f5aa75f..731e418c 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/TransferMessage.module.scss +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/TransferMessage.module.scss @@ -38,20 +38,18 @@ display: flex; align-items: center; justify-content: center; - width: 32px; - height: 32px; - background: #ffffff; + width: 36px; + height: 36px; border-radius: 50%; flex-shrink: 0; font-size: 18px; - color: #ff9500; + color: #ffffff; + border: 2px solid #ffffff; } .transferAmount { - font-size: 20px; - font-weight: 600; + font-size: 16px; color: #ffffff; - line-height: 1.2; flex: 1; } diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/index.tsx index c46c3926..be9f9312 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/index.tsx @@ -50,11 +50,14 @@ const TransferMessage: React.FC = ({ content }) => {
- + +
+
+
{amount}
+
{statusText}
-
{amount}
-
{statusText}
+
微信转账 From 8659049ae9eb388c8e736dbb8f12fceff59a02ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=98=E9=A3=8E?= Date: Mon, 1 Dec 2025 12:23:19 +0800 Subject: [PATCH 04/10] =?UTF-8?q?=E5=A2=9E=E5=BC=BAMessageRecord=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E4=BB=A5=E6=94=AF=E6=8C=81RedPacketMessage=E5=92=8CTr?= =?UTF-8?q?ansferMessage=E7=9A=84=E9=A2=9D=E5=A4=96=E9=81=93=E5=85=B7?= =?UTF-8?q?=EF=BC=8C=E4=BB=8E=E8=80=8C=E6=9B=B4=E5=A5=BD=E5=9C=B0=E5=A4=84?= =?UTF-8?q?=E7=90=86=E5=8D=95=E5=87=BB=E4=BA=8B=E4=BB=B6=E5=92=8C=E5=A5=97?= =?UTF-8?q?=E6=8E=A5=E5=AD=97=E8=AF=B7=E6=B1=82=E3=80=82=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=A6=81=E7=94=A8=E7=9A=84=E8=BD=AC=E6=8E=A5=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E7=9A=84=E6=A0=B7=E5=BC=8F=E4=BB=A5=E6=94=B9=E5=96=84=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E4=BD=93=E9=AA=8C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/RedPacketMessage/index.tsx | 44 ++++++++- .../TransferMessage.module.scss | 10 ++ .../components/TransferMessage/index.tsx | 92 +++++++++++++++++-- .../components/MessageRecord/index.tsx | 13 ++- 4 files changed, 148 insertions(+), 11 deletions(-) diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/RedPacketMessage/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/RedPacketMessage/index.tsx index 75bf86ff..1d462caf 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/RedPacketMessage/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/RedPacketMessage/index.tsx @@ -1,4 +1,6 @@ import React from "react"; +import { useWebSocketStore } from "@/store/module/websocket/websocket"; +import { ChatRecord, ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; import styles from "./RedPacketMessage.module.scss"; interface RedPacketData { @@ -10,9 +12,15 @@ interface RedPacketData { interface RedPacketMessageProps { content: string; + msg?: ChatRecord; + contract?: ContractData | weChatGroup; } -const RedPacketMessage: React.FC = ({ content }) => { +const RedPacketMessage: React.FC = ({ + content, + msg, + contract, +}) => { const renderErrorMessage = (fallbackText: string) => (
{fallbackText}
); @@ -39,10 +47,42 @@ const RedPacketMessage: React.FC = ({ content }) => { const title = jsonData.sendertitle || "恭喜发财,大吉大利"; const paymsgid = jsonData.paymsgid || ""; + const nativeurl = jsonData.nativeurl || ""; + + // 处理红包点击事件,发送 socket 请求 + const handleRedPacketClick = () => { + if (!contract || !paymsgid || !nativeurl) { + console.warn("红包点击失败:缺少必要参数", { + contract, + paymsgid, + nativeurl, + }); + return; + } + + const isGroup = !!contract.chatroomId; + const wechatFriendId = isGroup ? 0 : contract.id; + + // 发送 socket 请求 + useWebSocketStore.getState().sendCommand("CmdOpenLuckyMoney", { + wechatAccountId: contract.wechatAccountId, + wechatFriendId: wechatFriendId, + paymsgid: paymsgid, + nativeurl: nativeurl, + }); + + console.log("发送红包打开请求:", { + cmdType: "CmdOpenLuckyMoney", + wechatAccountId: contract.wechatAccountId, + wechatFriendId: wechatFriendId, + paymsgid: paymsgid, + nativeurl: nativeurl, + }); + }; return (
-
+
🧧
{title}
diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/TransferMessage.module.scss b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/TransferMessage.module.scss index 731e418c..006691c6 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/TransferMessage.module.scss +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/TransferMessage.module.scss @@ -25,6 +25,16 @@ &:active { transform: translateY(0); } + + &.transferDisabled { + opacity: 0.5; + cursor: not-allowed; + + &:hover { + transform: none; + box-shadow: 0 2px 8px rgba(255, 149, 0, 0.2); + } + } } .transferHeader { diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/index.tsx index be9f9312..7c6f2f68 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/components/TransferMessage/index.tsx @@ -1,5 +1,7 @@ import React from "react"; import { SwapOutlined } from "@ant-design/icons"; +import { useWebSocketStore } from "@/store/module/websocket/websocket"; +import { ChatRecord, ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; import styles from "./TransferMessage.module.scss"; interface TransferData { @@ -15,9 +17,16 @@ interface TransferData { interface TransferMessageProps { content: string; + msg?: ChatRecord; + contract?: ContractData | weChatGroup; } -const TransferMessage: React.FC = ({ content }) => { +const TransferMessage: React.FC = ({ + content, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + msg, // 保留参数以保持与 RedPacketMessage 组件的一致性,未来可能会用到 + contract, +}) => { const renderErrorMessage = (fallbackText: string) => (
{fallbackText}
); @@ -40,14 +49,85 @@ const TransferMessage: React.FC = ({ content }) => { } const amount = jsonData.feedesc || "¥0.00"; - const memo = jsonData.payMemo || ""; - // 根据转账状态显示不同的提示文字 - // 可以根据实际业务逻辑判断状态,这里默认显示"待朋友确认收钱" - const statusText = "待朋友确认收钱"; + + // 判断转账状态 + const getTransferStatus = ( + data: TransferData, + ): { text: string; canClick: boolean } => { + const paySubType = data.paysubtype || ""; + + switch (paySubType) { + case "1": + return { text: "待朋友确认收钱", canClick: true }; + case "2": + return { text: "已过期", canClick: false }; + case "3": + return { text: "已领取", canClick: false }; + case "4": + return { text: "已退回", canClick: false }; + default: + // 默认情况:可能是待领取 + return { text: "待朋友确认收钱", canClick: true }; + } + }; + + const { text: statusText, canClick } = getTransferStatus(jsonData); + + // 处理转账点击事件,发送 socket 请求 + const handleTransferClick = () => { + // 如果状态不允许点击,直接返回 + if (!canClick) { + console.log("转账状态不允许点击:", statusText); + return; + } + + if ( + !contract || + !jsonData.transferid || + !jsonData.transcationid || + !jsonData.invalidtime || + !jsonData.paysubtype + ) { + console.warn("转账点击失败:缺少必要参数", { + contract, + transferid: jsonData.transferid, + transcationid: jsonData.transcationid, + invalidtime: jsonData.invalidtime, + paysubtype: jsonData.paysubtype, + }); + return; + } + + const isGroup = !!contract.chatroomId; + const wechatFriendId = isGroup ? 0 : contract.id; + + // 发送 socket 请求 + useWebSocketStore.getState().sendCommand("CmdReceiveTransMoney", { + wechatAccountId: contract.wechatAccountId, + wechatFriendId: wechatFriendId, + transcationid: jsonData.transcationid, + transferid: jsonData.transferid, + invalidtime: jsonData.invalidtime, + paysubtype: jsonData.paysubtype, + }); + + console.log("发送转账接收请求:", { + cmdType: "CmdReceiveTransMoney", + wechatAccountId: contract.wechatAccountId, + wechatFriendId: wechatFriendId, + transcationid: jsonData.transcationid, + transferid: jsonData.transferid, + invalidtime: jsonData.invalidtime, + paysubtype: jsonData.paysubtype, + }); + }; return (
-
+
diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx index ad11cec5..44b01c97 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx @@ -256,7 +256,6 @@ const MessageRecord: React.FC = ({ contract }) => { msg?: ChatRecord, contract?: ContractData | weChatGroup, ) => { - console.log("红包"); if (isLegacyEmojiContent(trimmedContent)) { return renderEmojiContent(rawContent); } @@ -272,7 +271,13 @@ const MessageRecord: React.FC = ({ contract }) => { "wxpay://c2cbizmessagehandler/hongbao/receivehongbao", ) ) { - return ; + return ( + + ); } // 判断是否为转账消息 @@ -280,7 +285,9 @@ const MessageRecord: React.FC = ({ contract }) => { jsonData.title === "微信转账" || (jsonData.transferid && jsonData.feedesc) ) { - return ; + return ( + + ); } if (jsonData.type === "file" && msg && contract) { From 7d9f94984cfec45d1b8dcf5cff48d51ba24ffe14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=98=E9=A3=8E?= Date: Mon, 1 Dec 2025 14:23:10 +0800 Subject: [PATCH 05/10] =?UTF-8?q?=E5=9C=A8MessageRecord=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E4=B8=AD=E5=AE=9E=E7=8E=B0parseSystemMessage=E5=AE=9E=E7=94=A8?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=EF=BC=8C=E4=BB=8E=E7=B3=BB=E7=BB=9F=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E4=B8=AD=E6=8F=90=E5=8F=96=E7=BA=AF=E6=96=87=E6=9C=AC?= =?UTF-8?q?=EF=BC=8C=E9=80=9A=E8=BF=87=E5=88=A0=E9=99=A4HTML=E6=A0=87?= =?UTF-8?q?=E7=AD=BE=E5=B9=B6=E4=B8=BA=E7=9B=B8=E5=85=B3=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=BA=A2=E5=8C=85=E5=9B=BE=E6=A0=87=E6=9D=A5?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E6=B6=88=E6=81=AF=E6=B8=B2=E6=9F=93=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/MessageRecord/index.tsx | 17 ++++++---- Touchkebao/src/utils/filter.ts | 34 +++++++++++++++++++ 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx index 44b01c97..23ea4a23 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx @@ -12,6 +12,7 @@ import TransferMessage from "./components/TransferMessage"; import { ChatRecord, ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; import { formatWechatTime } from "@/utils/common"; import { getEmojiPath } from "@/components/EmojiSeclection/wechatEmoji"; +import { parseSystemMessage } from "@/utils/filter"; import styles from "./com.module.scss"; import { useWeChatStore } from "@/store/module/weChat/weChat"; import { useContactStore } from "@/store/module/weChat/contacts"; @@ -856,13 +857,15 @@ const MessageRecord: React.FC = ({ contract }) => { {group.messages .filter(v => [10000].includes(v.msgType)) - .map(msg => ( -
- ))} + .map(msg => { + // 解析系统消息,提取纯文本(移除img标签和_wc_custom_link_标签) + const parsedText = parseSystemMessage(msg.content); + return ( +
+ {parsedText} +
+ ); + })} {group.messages .filter(v => [570425393, 90000].includes(v.msgType)) diff --git a/Touchkebao/src/utils/filter.ts b/Touchkebao/src/utils/filter.ts index 199c2ce8..04058d51 100644 --- a/Touchkebao/src/utils/filter.ts +++ b/Touchkebao/src/utils/filter.ts @@ -86,3 +86,37 @@ export const messageFilter = (message: string) => { return message; } }; + +/** + * 解析系统消息中的HTML标签,提取纯文本 + * 例如: 你领取了许老板的<_wc_custom_link_>红包。 + * 提取为:🧧 你领取了许老板的红包 + */ +export const parseSystemMessage = (html: string): string => { + if (!html) return ""; + + let text = html; + + // 移除所有 标签 + text = text.replace(/]*>/gi, ""); + + // 提取 <_wc_custom_link_> 标签内的文本内容 + // 匹配 <_wc_custom_link_ ...>内容 + text = text.replace( + /<_wc_custom_link_[^>]*>(.*?)<\/_wc_custom_link_>/gi, + "$1", + ); + + // 清理多余的空格(将多个连续空格替换为单个空格) + text = text.replace(/\s+/g, " "); + + // 去除首尾空格 + text = text.trim(); + + // 如果消息内容包含红包相关关键词,在前面添加🧧图标 + if (/红包|hongbao/i.test(text)) { + text = `🧧 ${text}`; + } + + return text; +}; From 57c398f537e5f692bd09ca4d6664ca256fb2ffd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=98=E9=A3=8E?= Date: Mon, 1 Dec 2025 14:27:39 +0800 Subject: [PATCH 06/10] =?UTF-8?q?=E6=9B=B4=E6=96=B0MessageRecord=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E4=B8=AD=E7=9A=84=E6=B6=88=E6=81=AF=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BB=A5=E5=8C=85=E6=8B=AC=E5=85=B6?= =?UTF-8?q?=E4=BB=96=E6=B6=88=E6=81=AF=E7=B1=BB=E5=9E=8B=EF=BC=88-10001?= =?UTF-8?q?=EF=BC=89=EF=BC=8C=E4=BB=A5=E6=94=B9=E8=BF=9B=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E7=9A=84=E5=A4=84=E7=90=86=E5=B9=B6=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/ChatWindow/components/MessageRecord/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx index 23ea4a23..c6a78cb8 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx @@ -856,7 +856,7 @@ const MessageRecord: React.FC = ({ contract }) => { {groupMessagesByTime(currentMessages).map((group, groupIndex) => ( {group.messages - .filter(v => [10000].includes(v.msgType)) + .filter(v => [10000, -10001].includes(v.msgType)) .map(msg => { // 解析系统消息,提取纯文本(移除img标签和_wc_custom_link_标签) const parsedText = parseSystemMessage(msg.content); @@ -893,7 +893,7 @@ const MessageRecord: React.FC = ({ contract }) => { })}
{group.time}
{group.messages - .filter(v => ![10000, 570425393, 90000].includes(v.msgType)) + .filter(v => ![10000, 570425393, 90000, -10001].includes(v.msgType)) .map(msg => { return renderMessage(msg); })} From 2cc21840026a84c85096cd31e4638d45a3de4c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=98=E9=A3=8E?= Date: Mon, 1 Dec 2025 14:34:19 +0800 Subject: [PATCH 07/10] =?UTF-8?q?=E5=A2=9E=E5=BC=BAMessageRecord=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E4=BB=A5=E7=AE=A1=E7=90=86=E6=B6=88=E6=81=AF=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E6=9C=9F=E9=97=B4=E7=9A=84=E6=BB=9A=E5=8A=A8=E8=A1=8C?= =?UTF-8?q?=E4=B8=BA=E3=80=82=E4=B8=BA=E6=B6=88=E6=81=AF=E5=AE=B9=E5=99=A8?= =?UTF-8?q?=E5=92=8C=E5=8A=A0=E8=BD=BD=E7=8A=B6=E6=80=81=E5=BC=95=E5=85=A5?= =?UTF-8?q?=E5=BC=95=E7=94=A8=EF=BC=8C=E9=80=9A=E8=BF=87=E5=9C=A8=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E6=9B=B4=E5=A4=9A=E6=B6=88=E6=81=AF=E6=97=B6=E4=BF=9D?= =?UTF-8?q?=E7=95=99=E6=BB=9A=E5=8A=A8=E4=BD=8D=E7=BD=AE=E6=9D=A5=E7=A1=AE?= =?UTF-8?q?=E4=BF=9D=E5=B9=B3=E6=BB=91=E7=9A=84=E7=94=A8=E6=88=B7=E4=BD=93?= =?UTF-8?q?=E9=AA=8C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/MessageRecord/index.tsx | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx index c6a78cb8..c534fe9d 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageRecord/index.tsx @@ -150,6 +150,7 @@ type GroupRenderItem = { const MessageRecord: React.FC = ({ contract }) => { const messagesEndRef = useRef(null); + const messagesContainerRef = useRef(null); // 右键菜单状态 const [contextMenu, setContextMenu] = useState({ visible: false, @@ -171,6 +172,8 @@ const MessageRecord: React.FC = ({ contract }) => { const isLoadingData = useWeChatStore(state => state.isLoadingData); const showCheckbox = useWeChatStore(state => state.showCheckbox); const prevMessagesRef = useRef(currentMessages); + const isLoadingMoreRef = useRef(false); + const scrollPositionRef = useRef(0); const updateShowCheckbox = useWeChatStore(state => state.updateShowCheckbox); const updateEnterModule = useWeChatStore(state => state.updateEnterModule); const currentCustomer = useCustomerStore(state => @@ -460,7 +463,10 @@ const MessageRecord: React.FC = ({ contract }) => { } }); - if (currentMessages.length > prevLength && !hasVideoStateChange) { + // 如果正在加载更早的消息,不自动滚动到底部 + if (isLoadingMoreRef.current && currentMessages.length > prevLength) { + // 不滚动,等待加载完成后在另一个 useEffect 中恢复滚动位置 + } else if (currentMessages.length > prevLength && !hasVideoStateChange) { scrollToBottom(); } else if (isLoadingData && !hasVideoStateChange) { scrollToBottom(); @@ -470,6 +476,22 @@ const MessageRecord: React.FC = ({ contract }) => { prevMessagesRef.current = currentMessages; }, [currentMessages, isLoadingData]); + // 监听加载状态,当加载完成时恢复滚动位置 + useEffect(() => { + if (!messagesLoading && isLoadingMoreRef.current) { + // 等待DOM更新后恢复滚动位置 + requestAnimationFrame(() => { + const container = messagesContainerRef.current; + if (container) { + const scrollHeight = container.scrollHeight; + const newScrollTop = scrollHeight - scrollPositionRef.current; + container.scrollTop = newScrollTop; + } + isLoadingMoreRef.current = false; + }); + } + }, [messagesLoading]); + const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }; @@ -762,6 +784,12 @@ const MessageRecord: React.FC = ({ contract }) => { if (messagesLoading || !currentMessagesHasMore) { return; } + // 保存当前滚动位置(距离底部的距离) + const container = messagesContainerRef.current; + if (container) { + scrollPositionRef.current = container.scrollHeight - container.scrollTop; + isLoadingMoreRef.current = true; + } loadChatMessages(false); }; @@ -840,7 +868,7 @@ const MessageRecord: React.FC = ({ contract }) => { }; return ( -
+
loadMoreMessages()} From 75aab08a72e24ed34139e867c9c1ce32148478e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=98=E9=A3=8E?= Date: Mon, 1 Dec 2025 14:43:33 +0800 Subject: [PATCH 08/10] =?UTF-8?q?=E5=9C=A8MessageList=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E4=B8=AD=E5=AE=9E=E7=8E=B0=E5=AF=B9=E4=B8=A2=E5=A4=B1=E5=A4=B4?= =?UTF-8?q?=E5=83=8F=E6=88=96=E6=98=B5=E7=A7=B0=E7=9A=84=E8=AF=A6=E7=BB=86?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=EF=BC=8C=E5=B9=B6=E7=9B=B8=E5=BA=94=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E4=BC=9A=E8=AF=9D=E7=8A=B6=E6=80=81=E5=92=8C=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=EF=BC=8C=E4=BB=A5=E7=A1=AE=E4=BF=9D=E5=87=86?= =?UTF-8?q?=E7=A1=AE=E6=98=BE=E7=A4=BA=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SidebarMenu/MessageList/index.tsx | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/MessageList/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/MessageList/index.tsx index 1e57ed74..1e08ff0a 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/MessageList/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/MessageList/index.tsx @@ -805,6 +805,59 @@ const MessageList: React.FC = () => { // 设置当前会话 setCurrentContact(session as any); + // 如果头像或昵称缺失,则尝试拉取详情并更新列表 + const needFetchDetail = + !session.avatar || + !(session.conRemark || session.nickname || session.wechatId); + + if (needFetchDetail) { + try { + let detailResult: any = null; + if (session.type === "friend") { + detailResult = await getWechatFriendDetail({ id: session.id }); + } else { + detailResult = await getWechatChatroomDetail({ id: session.id }); + } + + const detail = detailResult?.detail; + if (detail) { + // 1. 更新会话列表中的该条记录(驱动 UI 立即更新头像和昵称) + setSessionState(prev => + prev.map(s => + s.id === session.id && s.type === session.type + ? { + ...s, + avatar: + session.type === "group" + ? detail.chatroomAvatar || s.avatar + : detail.avatar || s.avatar, + nickname: detail.nickname || s.nickname, + conRemark: detail.conRemark || s.conRemark, + wechatId: detail.wechatId || s.wechatId, + } + : s, + ), + ); + + // 2. 同步到会话数据库,保证刷新后数据仍然是最新的 + await MessageManager.updateSession({ + userId: currentUserId, + id: session.id, + type: session.type, + avatar: + session.type === "group" + ? detail.chatroomAvatar || session.avatar + : detail.avatar || session.avatar, + nickname: detail.nickname || session.nickname, + conRemark: detail.conRemark || session.conRemark, + wechatId: detail.wechatId || session.wechatId, + }); + } + } catch (e) { + console.error("点击会话补拉详情失败:", e); + } + } + // 标记为已读(不更新时间和排序) if (session.config.unreadCount > 0) { // 立即更新UI(只更新未读数量) From 11a4ec8c676bb918fce001001d6e8ea5cba155cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=98=E9=A3=8E?= Date: Mon, 1 Dec 2025 15:09:25 +0800 Subject: [PATCH 09/10] =?UTF-8?q?=E5=9C=A8MessageList=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E4=B8=AD=E6=B7=BB=E5=8A=A0=E6=9C=AA=E7=9F=A5=E8=81=94=E7=B3=BB?= =?UTF-8?q?=E4=BA=BA=E8=A1=A5=E5=85=85=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=BC=82?= =?UTF-8?q?=E6=AD=A5=E6=8B=89=E5=8F=96=E7=BC=BA=E5=A4=B1=E7=9A=84=E5=A4=B4?= =?UTF-8?q?=E5=83=8F=E5=92=8C=E6=98=B5=E7=A7=B0=E4=BF=A1=E6=81=AF=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E6=9B=B4=E6=96=B0=E4=BC=9A=E8=AF=9D=E5=92=8C=E8=81=94?= =?UTF-8?q?=E7=B3=BB=E4=BA=BA=E6=95=B0=E6=8D=AE=E5=BA=93=EF=BC=8C=E4=BB=A5?= =?UTF-8?q?=E6=8F=90=E5=8D=87=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AF=E7=9A=84?= =?UTF-8?q?=E5=87=86=E7=A1=AE=E6=80=A7=E5=92=8C=E5=AE=8C=E6=95=B4=E6=80=A7?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SidebarMenu/MessageList/index.tsx | 181 ++++++++++++------ 1 file changed, 127 insertions(+), 54 deletions(-) diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/MessageList/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/MessageList/index.tsx index 1e08ff0a..efbcbad8 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/MessageList/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/SidebarMenu/MessageList/index.tsx @@ -47,6 +47,7 @@ const MessageList: React.FC = () => { } = useMessageStore(); const [filteredSessions, setFilteredSessions] = useState([]); const [syncing, setSyncing] = useState(false); // 同步状态 + const hasEnrichedRef = useRef(false); // 是否已做过未知联系人补充 // 右键菜单相关状态 const [contextMenu, setContextMenu] = useState<{ @@ -296,7 +297,130 @@ const MessageList: React.FC = () => { }; }, [contextMenu.visible]); - // ==================== 数据加载 ==================== + // ==================== 数据加载 & 未知联系人补充 ==================== + + // 同步完成后,检查是否存在“未知联系人”或缺失头像/昵称的会话,并异步补充详情 + const enrichUnknownContacts = async () => { + if (!currentUserId) return; + if (hasEnrichedRef.current) return; // 避免重复执行 + + // 只在会话有数据时执行 + if (!sessions || sessions.length === 0) return; + + const needEnrich = sessions.filter(s => { + const noName = !s.conRemark && !s.nickname && !s.wechatId; + const isUnknownNickname = s.nickname === "未知联系人"; + const noAvatar = !s.avatar; + return noName || isUnknownNickname || noAvatar; + }); + + if (needEnrich.length === 0) { + hasEnrichedRef.current = true; + return; + } + + hasEnrichedRef.current = true; + + // 逐个异步拉取详情,失败不打断整体流程 + for (const session of needEnrich) { + try { + let detailResult: any = null; + if (session.type === "friend") { + detailResult = await getWechatFriendDetail({ id: session.id }); + } else { + detailResult = await getWechatChatroomDetail({ id: session.id }); + } + + const detail = detailResult?.detail; + if (!detail) continue; + + // 更新会话列表 UI + setSessionState(prev => + prev.map(s => + s.id === session.id && s.type === session.type + ? { + ...s, + avatar: + session.type === "group" + ? detail.chatroomAvatar || s.avatar + : detail.avatar || s.avatar, + nickname: detail.nickname || s.nickname, + conRemark: detail.conRemark || s.conRemark, + wechatId: detail.wechatId || s.wechatId, + } + : s, + ), + ); + + // 同步到会话数据库 + await MessageManager.updateSession({ + userId: currentUserId, + id: session.id, + type: session.type, + avatar: + session.type === "group" + ? detail.chatroomAvatar || session.avatar + : detail.avatar || session.avatar, + nickname: detail.nickname || session.nickname, + conRemark: detail.conRemark || session.conRemark, + wechatId: detail.wechatId || session.wechatId, + }); + + // 同步到联系人数据库(方便后续搜索、其它页面使用) + const contactBase: any = { + serverId: `${session.type}_${session.id}`, + userId: currentUserId, + id: session.id, + type: session.type, + wechatAccountId: detail.wechatAccountId, + nickname: detail.nickname || "", + conRemark: detail.conRemark || "", + avatar: + session.type === "group" + ? detail.chatroomAvatar || "" + : detail.avatar || "", + lastUpdateTime: new Date().toISOString(), + sortKey: "", + searchKey: (detail.conRemark || detail.nickname || "").toLowerCase(), + }; + + if (session.type === "group") { + Object.assign(contactBase, { + chatroomId: detail.chatroomId, + chatroomOwner: detail.chatroomOwner, + selfDisplayName: detail.selfDisplyName, + notice: detail.notice, + }); + } else { + Object.assign(contactBase, { + wechatFriendId: detail.id, + wechatId: detail.wechatId, + alias: detail.alias, + gender: detail.gender, + region: detail.region, + signature: detail.signature, + phone: detail.phone, + quanPin: detail.quanPin, + groupId: detail.groupId, + }); + } + + // 使用 upsert 逻辑:如果已存在就更新,不存在则新增 + const existContact = await ContactManager.getContactByIdAndType( + currentUserId, + session.id, + session.type, + ); + if (existContact) { + await ContactManager.updateContact(contactBase); + } else { + await ContactManager.addContact(contactBase); + } + } catch (error) { + console.error("补拉未知联系人详情失败:", error, session); + } + } + }; // 与服务器同步数据(优化版:逐页同步,立即更新UI) const syncWithServer = async () => { @@ -379,6 +503,8 @@ const MessageList: React.FC = () => { console.log( `会话同步完成: 成功${successCount}页, 失败${failCount}页, 共处理${totalProcessed}条数据`, ); + // 同步完成后,异步补充未知联系人信息 + enrichUnknownContacts(); } catch (error) { console.error("同步服务器数据失败:", error); } finally { @@ -805,59 +931,6 @@ const MessageList: React.FC = () => { // 设置当前会话 setCurrentContact(session as any); - // 如果头像或昵称缺失,则尝试拉取详情并更新列表 - const needFetchDetail = - !session.avatar || - !(session.conRemark || session.nickname || session.wechatId); - - if (needFetchDetail) { - try { - let detailResult: any = null; - if (session.type === "friend") { - detailResult = await getWechatFriendDetail({ id: session.id }); - } else { - detailResult = await getWechatChatroomDetail({ id: session.id }); - } - - const detail = detailResult?.detail; - if (detail) { - // 1. 更新会话列表中的该条记录(驱动 UI 立即更新头像和昵称) - setSessionState(prev => - prev.map(s => - s.id === session.id && s.type === session.type - ? { - ...s, - avatar: - session.type === "group" - ? detail.chatroomAvatar || s.avatar - : detail.avatar || s.avatar, - nickname: detail.nickname || s.nickname, - conRemark: detail.conRemark || s.conRemark, - wechatId: detail.wechatId || s.wechatId, - } - : s, - ), - ); - - // 2. 同步到会话数据库,保证刷新后数据仍然是最新的 - await MessageManager.updateSession({ - userId: currentUserId, - id: session.id, - type: session.type, - avatar: - session.type === "group" - ? detail.chatroomAvatar || session.avatar - : detail.avatar || session.avatar, - nickname: detail.nickname || session.nickname, - conRemark: detail.conRemark || session.conRemark, - wechatId: detail.wechatId || session.wechatId, - }); - } - } catch (e) { - console.error("点击会话补拉详情失败:", e); - } - } - // 标记为已读(不更新时间和排序) if (session.config.unreadCount > 0) { // 立即更新UI(只更新未读数量) From 1dbdee155e3f5af2023a294266a7f45d8e67ac50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=98=E9=A3=8E?= Date: Mon, 1 Dec 2025 16:58:58 +0800 Subject: [PATCH 10/10] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=AB=98=E9=A2=91?= =?UTF-8?q?=E8=BD=AE=E8=AF=A2=E6=8E=A5=E5=8F=A3=E7=99=BD=E5=90=8D=E5=8D=95?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E8=AF=B7=E6=B1=82=E6=88=AA=E6=B5=81?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E4=BB=A5=E6=94=AF=E6=8C=81=E7=89=B9=E5=AE=9A?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=9A=84=E6=97=A0=E6=88=AA=E6=B5=81=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E3=80=82=E5=85=81=E8=AE=B8=E9=80=9A=E8=BF=87=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=8E=A7=E5=88=B6=E6=88=AA=E6=B5=81=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8C=E6=8F=90=E5=8D=87=E8=AF=B7=E6=B1=82=E5=A4=84=E7=90=86?= =?UTF-8?q?=E7=9A=84=E7=81=B5=E6=B4=BB=E6=80=A7=E5=92=8C=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=BD=93=E9=AA=8C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Touchkebao/src/api/request.ts | 37 +++++++++++++++++++++++++--------- Touchkebao/src/api/request2.ts | 34 +++++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/Touchkebao/src/api/request.ts b/Touchkebao/src/api/request.ts index adfa7ea5..35e7bbe5 100644 --- a/Touchkebao/src/api/request.ts +++ b/Touchkebao/src/api/request.ts @@ -10,6 +10,13 @@ const { token } = useUserStore.getState(); const DEFAULT_DEBOUNCE_GAP = 1000; const debounceMap = new Map(); +// 需要高频轮询、不走截流的接口白名单(按实际接口路径调整) +const NO_DEBOUNCE_URLS = [ + "/wechat/friend/list", // 好友列表 + "/wechat/group/list", // 群组列表 + "/wechat/message/list", // 消息列表 +]; + const instance: AxiosInstance = axios.create({ baseURL: (import.meta as any).env?.VITE_API_BASE_URL || "/api", timeout: 20000, @@ -64,21 +71,31 @@ export function request( url: string, data?: any, method: Method = "GET", - config?: AxiosRequestConfig, + // 允许通过 config.debounce 控制是否开启截流,默认开启 + config?: AxiosRequestConfig & { debounce?: boolean }, debounceGap?: number, ): Promise { const gap = typeof debounceGap === "number" ? debounceGap : DEFAULT_DEBOUNCE_GAP; - const key = `${method}_${url}_${JSON.stringify(data)}`; - const now = Date.now(); - const last = debounceMap.get(key) || 0; - if (gap > 0 && now - last < gap) { - // Toast.show({ content: '请求过于频繁,请稍后再试', position: 'top' }); - return Promise.reject("请求过于频繁,请稍后再试"); - } - debounceMap.set(key, now); - const axiosConfig: AxiosRequestConfig = { + const enableDebounce = config?.debounce !== false; + const isInNoDebounceList = NO_DEBOUNCE_URLS.some(pattern => + url.includes(pattern), + ); + const shouldDebounce = enableDebounce && !isInNoDebounceList; + + if (shouldDebounce) { + const key = `${method}_${url}_${JSON.stringify(data)}`; + const now = Date.now(); + const last = debounceMap.get(key) || 0; + if (gap > 0 && now - last < gap) { + // Toast.show({ content: '请求过于频繁,请稍后再试', position: 'top' }); + return Promise.reject("请求过于频繁,请稍后再试"); + } + debounceMap.set(key, now); + } + + const axiosConfig: AxiosRequestConfig & { debounce?: boolean } = { url, method, ...config, diff --git a/Touchkebao/src/api/request2.ts b/Touchkebao/src/api/request2.ts index deb3d9bf..13732be0 100644 --- a/Touchkebao/src/api/request2.ts +++ b/Touchkebao/src/api/request2.ts @@ -9,11 +9,20 @@ import { useUserStore } from "@/store/module/user"; const DEFAULT_DEBOUNCE_GAP = 1000; const debounceMap = new Map(); +// 需要高频轮询、不走截流的接口白名单(按实际接口路径调整) +const NO_DEBOUNCE_URLS = [ + "/wechat/friend/list", + "/wechat/group/list", + "/wechat/message/list", +]; + interface RequestConfig extends AxiosRequestConfig { - headers: { + headers?: { Client?: string; "Content-Type"?: string; }; + // 是否开启截流,默认开启 + debounce?: boolean; } const instance: AxiosInstance = axios.create({ @@ -63,14 +72,23 @@ export function request( ): Promise { const gap = typeof debounceGap === "number" ? debounceGap : DEFAULT_DEBOUNCE_GAP; - const key = `${method}_${url}_${JSON.stringify(data)}`; - const now = Date.now(); - const last = debounceMap.get(key) || 0; - if (gap > 0 && now - last < gap) { - // Toast.show({ content: '请求过于频繁,请稍后再试', position: 'top' }); - return Promise.reject("请求过于频繁,请稍后再试"); + + const enableDebounce = config?.debounce !== false; + const isInNoDebounceList = NO_DEBOUNCE_URLS.some(pattern => + url.includes(pattern), + ); + const shouldDebounce = enableDebounce && !isInNoDebounceList; + + if (shouldDebounce) { + const key = `${method}_${url}_${JSON.stringify(data)}`; + const now = Date.now(); + const last = debounceMap.get(key) || 0; + if (gap > 0 && now - last < gap) { + // Toast.show({ content: '请求过于频繁,请稍后再试', position: 'top' }); + return Promise.reject("请求过于频繁,请稍后再试"); + } + debounceMap.set(key, now); } - debounceMap.set(key, now); const axiosConfig: RequestConfig = { url,