From a5cc4e5e18cbfa09c2a775dfebf1f1cc7acaf5e7 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: Thu, 27 Nov 2025 15:07:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96AI=E6=B6=88=E6=81=AF=E5=A4=84?= =?UTF-8?q?=E7=90=86=E9=80=BB=E8=BE=91=EF=BC=8C=E5=8C=BA=E5=88=86AI?= =?UTF-8?q?=E8=BE=85=E5=8A=A9=E6=A8=A1=E5=BC=8F=E4=B8=8EAI=E6=8E=A5?= =?UTF-8?q?=E7=AE=A1=E6=A8=A1=E5=BC=8F=EF=BC=8C=E7=A1=AE=E4=BF=9D=E5=9C=A8?= =?UTF-8?q?=E6=8E=A5=E7=AE=A1=E6=A8=A1=E5=BC=8F=E4=B8=8B=E7=9B=B4=E6=8E=A5?= =?UTF-8?q?=E5=8F=91=E9=80=81=E6=B6=88=E6=81=AF=E8=80=8C=E4=B8=8D=E7=BB=8F?= =?UTF-8?q?=E8=BF=87MessageEnter=E7=BB=84=E4=BB=B6=E3=80=82=E5=90=8C?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E8=B0=83=E6=95=B4=E7=9B=B8=E5=85=B3=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E7=9A=84=E7=8A=B6=E6=80=81=E7=AE=A1=E7=90=86=EF=BC=8C?= =?UTF-8?q?=E6=8F=90=E5=8D=87=E4=BB=A3=E7=A0=81=E5=8F=AF=E8=AF=BB=E6=80=A7?= =?UTF-8?q?=E5=92=8C=E7=BB=B4=E6=8A=A4=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/MessageEnter/index.tsx | 14 +- Touchkebao/src/store/module/weChat/weChat.ts | 163 ++++++++++++++++-- .../src/store/module/websocket/msgManage.ts | 38 ++-- .../src/store/module/websocket/websocket.ts | 3 +- 4 files changed, 183 insertions(+), 35 deletions(-) diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/index.tsx index 9135624f..e057a728 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/index.tsx @@ -176,19 +176,21 @@ const MessageEnter: React.FC = ({ contract }) => { updateQuoteMessageContent(""); }; - // AI 消息处理 + // AI 消息处理 - 只处理AI辅助模式 + // AI接管模式已经在weChat.ts中直接发送,不经过此组件 + // 快捷语填充:当 quoteMessageContent 更新时,填充到输入框 useEffect(() => { if (quoteMessageContent) { if (isAiAssist) { + // AI辅助模式:直接填充输入框 + setInputValue(quoteMessageContent); + } else { + // 快捷语模式:直接填充输入框(用户主动点击快捷语,应该替换当前内容) setInputValue(quoteMessageContent); - } - - if (isAiTakeover) { - handleSend(quoteMessageContent); } } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [quoteMessageContent, aiQuoteMessageContent, isAiAssist, isAiTakeover]); + }, [quoteMessageContent, aiQuoteMessageContent, isAiAssist]); const handleKeyPress = (e: React.KeyboardEvent) => { if (e.key === "Enter" && !e.shiftKey && !e.ctrlKey) { diff --git a/Touchkebao/src/store/module/weChat/weChat.ts b/Touchkebao/src/store/module/weChat/weChat.ts index 89a001a9..e06e27cd 100644 --- a/Touchkebao/src/store/module/weChat/weChat.ts +++ b/Touchkebao/src/store/module/weChat/weChat.ts @@ -18,6 +18,7 @@ import { getFriendInjectConfig, } from "@/pages/pc/ckbox/api"; import { ChatRecord, ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; +import { useWebSocketStore } from "@/store/module/websocket/websocket"; /** * AI请求防抖管理 @@ -392,13 +393,73 @@ export const manualTriggerAi = async () => { return false; } - // 更新AI回复内容 - state.updateQuoteMessageContent(messageContent?.content || ""); - state.updateIsLoadingAiChat(false); - console.log( - `✅ 手动AI回复成功 [${generationId}]:`, - messageContent?.content, - ); + // 获取当前接待类型 + const aiType = (currentContract as any)?.aiType || 0; // 0=人工, 1=AI辅助, 2=AI接管 + const aiResponseContent = messageContent?.content || ""; + const isWechatGroup = !!(currentContract as any)?.chatroomId; + + // 根据接待类型处理AI回复 + if (aiType === 2 && aiResponseContent) { + // AI接管模式:直接发送消息,不经过MessageEnter组件 + const messageId = +Date.now(); + + // 构造本地消息对象 + const localMessage: ChatRecord = { + id: messageId, + wechatAccountId: currentContract.wechatAccountId, + wechatFriendId: isWechatGroup ? 0 : currentContract.id, + wechatChatroomId: isWechatGroup ? currentContract.id : 0, + tenantId: 0, + accountId: 0, + synergyAccountId: 0, + content: aiResponseContent, + msgType: 1, + msgSubType: 0, + msgSvrId: "", + isSend: true, + createTime: new Date().toISOString(), + isDeleted: false, + deleteTime: "", + sendStatus: 1, + wechatTime: Date.now(), + origin: 0, + msgId: 0, + recalled: false, + seq: messageId, + }; + + // 添加到消息列表 + state.addMessage(localMessage); + + // 直接发送消息 + const { sendCommand } = useWebSocketStore.getState(); + sendCommand("CmdSendMessage", { + wechatAccountId: currentContract.wechatAccountId, + wechatChatroomId: isWechatGroup ? currentContract.id : 0, + wechatFriendId: isWechatGroup ? 0 : currentContract.id, + msgSubType: 0, + msgType: 1, + content: aiResponseContent, + seq: messageId, + }); + + state.updateIsLoadingAiChat(false); + console.log( + `✅ 手动AI接管模式:直接发送消息 [${generationId}]:`, + aiResponseContent, + ); + } else if (aiType === 1) { + // AI辅助模式:设置quoteMessageContent,让MessageEnter组件填充输入框 + state.updateQuoteMessageContent(aiResponseContent); + state.updateIsLoadingAiChat(false); + console.log( + `✅ 手动AI辅助模式:填充输入框 [${generationId}]:`, + aiResponseContent, + ); + } else { + // 其他情况 + state.updateIsLoadingAiChat(false); + } // 清除当前生成ID currentAiGenerationId = null; @@ -837,15 +898,85 @@ export const useWeChatStore = create()( return; } - // 附加生成ID到回复内容 - set(() => ({ - quoteMessageContent: messageContent?.content || "", - isLoadingAiChat: false, - })); - console.log( - `✅ AI回复成功 [${generationId}]:`, - messageContent?.content, - ); + // 获取当前接待类型 + const aiType = (currentContract as any)?.aiType || 0; // 0=人工, 1=AI辅助, 2=AI接管 + const aiResponseContent = messageContent?.content || ""; + + // 根据接待类型处理AI回复 + if (aiType === 2 && aiResponseContent) { + // AI接管模式:直接发送消息,不经过MessageEnter组件 + const messageId = +Date.now(); + + // 构造本地消息对象 + const localMessage: ChatRecord = { + id: messageId, + wechatAccountId: currentContract.wechatAccountId, + wechatFriendId: isWechatGroup ? 0 : currentContract.id, + wechatChatroomId: isWechatGroup + ? currentContract.id + : 0, + tenantId: 0, + accountId: 0, + synergyAccountId: 0, + content: aiResponseContent, + msgType: 1, + msgSubType: 0, + msgSvrId: "", + isSend: true, + createTime: new Date().toISOString(), + isDeleted: false, + deleteTime: "", + sendStatus: 1, + wechatTime: Date.now(), + origin: 0, + msgId: 0, + recalled: false, + seq: messageId, + }; + + // 添加到消息列表 + set(state => ({ + currentMessages: [ + ...state.currentMessages, + localMessage, + ], + isLoadingAiChat: false, + })); + + // 直接发送消息 + const { sendCommand } = useWebSocketStore.getState(); + sendCommand("CmdSendMessage", { + wechatAccountId: currentContract.wechatAccountId, + wechatChatroomId: isWechatGroup + ? currentContract.id + : 0, + wechatFriendId: isWechatGroup ? 0 : currentContract.id, + msgSubType: 0, + msgType: 1, + content: aiResponseContent, + seq: messageId, + }); + + console.log( + `✅ AI接管模式:直接发送消息 [${generationId}]:`, + aiResponseContent, + ); + } else if (aiType === 1) { + // AI辅助模式:设置quoteMessageContent,让MessageEnter组件填充输入框 + set(() => ({ + quoteMessageContent: aiResponseContent, + isLoadingAiChat: false, + })); + console.log( + `✅ AI辅助模式:填充输入框 [${generationId}]:`, + aiResponseContent, + ); + } else { + // 其他情况 + set(() => ({ + isLoadingAiChat: false, + })); + } // 清除当前生成ID currentAiGenerationId = null; diff --git a/Touchkebao/src/store/module/websocket/msgManage.ts b/Touchkebao/src/store/module/websocket/msgManage.ts index 2fcaceb3..a2f31d98 100644 --- a/Touchkebao/src/store/module/websocket/msgManage.ts +++ b/Touchkebao/src/store/module/websocket/msgManage.ts @@ -8,17 +8,23 @@ import { Modal } from "antd"; import { useCustomerStore, updateCustomerList } from "../weChat/customer"; // 消息处理器类型定义 type MessageHandler = (message: WebSocketMessage) => void; -const addMessage = useWeChatStore.getState().addMessage; -const recallMessage = useWeChatStore.getState().recallMessage; -const receivedMsg = useWeChatStore.getState().receivedMsg; -const findMessageBySeq = useWeChatStore.getState().findMessageBySeq; -const findMessageById = useWeChatStore.getState().findMessageById; -const updateMessage = useWeChatStore.getState().updateMessage; -const updateMomentCommonLoading = - useWeChatStore.getState().updateMomentCommonLoading; -const addMomentCommon = useWeChatStore.getState().addMomentCommon; -const setFileDownloadUrl = useWeChatStore.getState().setFileDownloadUrl; -const setFileDownloading = useWeChatStore.getState().setFileDownloading; + +// 延迟获取 store 方法,避免循环依赖问题 +const getWeChatStoreMethods = () => { + const state = useWeChatStore.getState(); + return { + addMessage: state.addMessage, + recallMessage: state.recallMessage, + receivedMsg: state.receivedMsg, + findMessageBySeq: state.findMessageBySeq, + findMessageById: state.findMessageById, + updateMessage: state.updateMessage, + updateMomentCommonLoading: state.updateMomentCommonLoading, + addMomentCommon: state.addMomentCommon, + setFileDownloadUrl: state.setFileDownloadUrl, + setFileDownloading: state.setFileDownloading, + }; +}; // 消息处理器映射 const messageHandlers: Record = { // 微信账号存活状态响应 @@ -46,6 +52,7 @@ const messageHandlers: Record = { }, // 发送消息响应 CmdSendMessageResp: message => { + const { findMessageBySeq, updateMessage } = getWeChatStoreMethods(); const msg = findMessageBySeq(message.seq); if (msg) { updateMessage(message.seq, { @@ -55,6 +62,7 @@ const messageHandlers: Record = { } }, CmdSendMessageResult: message => { + const { updateMessage } = getWeChatStoreMethods(); updateMessage(message.friendMessageId || message.chatroomMessageId, { sendStatus: 0, }); @@ -68,6 +76,7 @@ const messageHandlers: Record = { //收到消息 CmdNewMessage: (message: Messages) => { // 处理消息本身 + const { receivedMsg } = getWeChatStoreMethods(); receivedMsg(message.friendMessage || message.chatroomMessage); // 触发会话列表更新事件 @@ -107,6 +116,7 @@ const messageHandlers: Record = { // setVideoUrl(message.friendMessageId, message.url); }, CmdDownloadFileResult: message => { + const { setFileDownloadUrl, setFileDownloading } = getWeChatStoreMethods(); const messageId = message.friendMessageId || message.chatroomMessageId; if (!messageId) { @@ -124,6 +134,8 @@ const messageHandlers: Record = { }, CmdFetchMomentResult: message => { + const { addMomentCommon, updateMomentCommonLoading } = + getWeChatStoreMethods(); addMomentCommon(message.result); updateMomentCommonLoading(false); }, @@ -162,16 +174,18 @@ const messageHandlers: Record = { //撤回消息 CmdMessageRecalled: message => { + const { recallMessage } = getWeChatStoreMethods(); const MessageId = message.friendMessageId || message.chatroomMessageId; recallMessage(MessageId); }, CmdVoiceToTextResult: message => { + const { findMessageById, updateMessage } = getWeChatStoreMethods(); const msg = findMessageById( message.friendMessageId || message.chatroomMessageId, ); - const content = JSON.parse(msg.content); if (msg) { + const content = JSON.parse(msg.content); updateMessage(msg.id, { content: JSON.stringify({ ...content, diff --git a/Touchkebao/src/store/module/websocket/websocket.ts b/Touchkebao/src/store/module/websocket/websocket.ts index 57ed7f15..59a2fcf3 100644 --- a/Touchkebao/src/store/module/websocket/websocket.ts +++ b/Touchkebao/src/store/module/websocket/websocket.ts @@ -2,7 +2,6 @@ import { createPersistStore } from "@/store/createPersistStore"; import { useUserStore } from "../user"; import { useCkChatStore } from "@/store/module/ckchat/ckchat"; import { useCustomerStore } from "@/store/module/weChat/customer"; -const { getAccountId } = useCkChatStore.getState(); import { msgManageCore } from "./msgManage"; // WebSocket消息类型 export interface WebSocketMessage { @@ -141,6 +140,7 @@ export const useWebSocketStore = createPersistStore( } // 构建WebSocket URL + const { getAccountId } = useCkChatStore.getState(); const params = new URLSearchParams({ client: fullConfig.client.toString(), accountId: getAccountId().toString(), @@ -330,6 +330,7 @@ export const useWebSocketStore = createPersistStore( // console.log("WebSocket连接成功"); const { token2 } = useUserStore.getState(); + const { getAccountId } = useCkChatStore.getState(); // 发送登录命令 if (currentState.config) { currentState.sendCommand("CmdSignIn", {