From 20658c3ca557becd7c3ae28e749680c2f82e9332 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: Tue, 2 Sep 2025 09:52:38 +0800 Subject: [PATCH] =?UTF-8?q?refactor(websocket):=20=E9=87=8D=E6=9E=84websoc?= =?UTF-8?q?ket=E6=A8=A1=E5=9D=97=E5=B9=B6=E6=B7=BB=E5=8A=A0=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E7=AE=A1=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将websocket模块拆分为多个文件,提高代码可维护性 - 新增msgManage.ts处理不同类型的websocket消息 - 优化消息处理逻辑,减少重复代码 - 更新相关文件引用路径 --- Cunkebao/src/components/WebSocketExample.tsx | 2 +- .../pc/ckbox/components/ChatWindow/index.tsx | 5 +- Cunkebao/src/pages/pc/ckbox/index.tsx | 14 ++- Cunkebao/src/pages/pc/ckbox/main.ts | 2 +- Cunkebao/src/store/index.ts | 4 +- Cunkebao/src/store/module/ckchat/ckchat.ts | 4 +- .../src/store/module/websocket/msgManage.ts | 78 +++++++++++++++ .../store/module/{ => websocket}/websocket.ts | 98 ++++++++++--------- 8 files changed, 151 insertions(+), 56 deletions(-) create mode 100644 Cunkebao/src/store/module/websocket/msgManage.ts rename Cunkebao/src/store/module/{ => websocket}/websocket.ts (81%) diff --git a/Cunkebao/src/components/WebSocketExample.tsx b/Cunkebao/src/components/WebSocketExample.tsx index 67867431..e8816e5b 100644 --- a/Cunkebao/src/components/WebSocketExample.tsx +++ b/Cunkebao/src/components/WebSocketExample.tsx @@ -4,7 +4,7 @@ import { useWebSocketStore, WebSocketStatus, WebSocketMessage, -} from "@/store/module/websocket"; +} from "@/store/module/websocket/websocket"; /** * WebSocket使用示例组件 diff --git a/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx b/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx index 063d4545..198eef65 100644 --- a/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx +++ b/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx @@ -38,7 +38,10 @@ import { import { ChatRecord, ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; import { getMessages } from "@/pages/pc/ckbox/api"; import styles from "./ChatWindow.module.scss"; -import { useWebSocketStore, WebSocketMessage } from "@/store/module/websocket"; +import { + useWebSocketStore, + WebSocketMessage, +} from "@/store/module/websocket/websocket"; import { formatWechatTime } from "@/utils/common"; import { useCkChatStore } from "@/store/module/ckchat/ckchat"; import Person from "./components/Person"; diff --git a/Cunkebao/src/pages/pc/ckbox/index.tsx b/Cunkebao/src/pages/pc/ckbox/index.tsx index 34514aa1..3a972be8 100644 --- a/Cunkebao/src/pages/pc/ckbox/index.tsx +++ b/Cunkebao/src/pages/pc/ckbox/index.tsx @@ -16,8 +16,9 @@ import { weChatGroup, ContractData, } from "@/pages/pc/ckbox/data"; -import { useWebSocketStore } from "@/store/module/websocket"; +import { useWebSocketStore } from "@/store/module/websocket/websocket"; import { useCkChatStore } from "@/store/module/ckchat/ckchat"; + const CkboxPage: React.FC = () => { const [messageApi, contextHolder] = message.useMessage(); const [contracts, setContacts] = useState([]); @@ -25,11 +26,20 @@ const CkboxPage: React.FC = () => { null, ); const status = useWebSocketStore(state => state.status); - const messages = useWebSocketStore(state => state.messages); // 不要在组件初始化时获取sendCommand,而是在需要时动态获取 const [loading, setLoading] = useState(false); const [showProfile, setShowProfile] = useState(true); const kfUserList = useCkChatStore(state => state.kfUserList); + const { sendCommand } = useWebSocketStore.getState(); + useEffect(() => { + if (status == "connected") { + //获取UserId + sendCommand("CmdRequestWechatAccountsAliveStatus", { + wechatAccountIds: kfUserList.map(v => v.id), + seq: +new Date(), + }); + } + }, [status]); useEffect(() => { // 方法一:使用 Promise 链式调用处理异步函数 diff --git a/Cunkebao/src/pages/pc/ckbox/main.ts b/Cunkebao/src/pages/pc/ckbox/main.ts index 47cd85f4..4e62ef87 100644 --- a/Cunkebao/src/pages/pc/ckbox/main.ts +++ b/Cunkebao/src/pages/pc/ckbox/main.ts @@ -6,7 +6,7 @@ import { asyncCountLables, useCkChatStore, } from "@/store/module/ckchat/ckchat"; -import { useWebSocketStore } from "@/store/module/websocket"; +import { useWebSocketStore } from "@/store/module/websocket/websocket"; import { loginWithToken, diff --git a/Cunkebao/src/store/index.ts b/Cunkebao/src/store/index.ts index f4f3d9af..7b74a38e 100644 --- a/Cunkebao/src/store/index.ts +++ b/Cunkebao/src/store/index.ts @@ -2,13 +2,13 @@ export * from "./module/user"; export * from "./module/app"; export * from "./module/settings"; -export * from "./module/websocket"; +export * from "./module/websocket/websocket"; // 导入store实例 import { useUserStore } from "./module/user"; import { useAppStore } from "./module/app"; import { useSettingsStore } from "./module/settings"; -import { useWebSocketStore } from "./module/websocket"; +import { useWebSocketStore } from "./module/websocket/websocket"; // 导出持久化store创建函数 export { diff --git a/Cunkebao/src/store/module/ckchat/ckchat.ts b/Cunkebao/src/store/module/ckchat/ckchat.ts index 623995d0..db1bf9e6 100644 --- a/Cunkebao/src/store/module/ckchat/ckchat.ts +++ b/Cunkebao/src/store/module/ckchat/ckchat.ts @@ -28,7 +28,9 @@ export const useCkChatStore = createPersistStore( }, // 获取客服列表 getkfUserList: async () => { - return await kfUserService.findAll(); + const state = useCkChatStore.getState(); + return state.kfUserList; + // return await kfUserService.findAll(); }, // 异步设置标签列表 asyncCountLables: async (data: ContactGroupByLabel[]) => { diff --git a/Cunkebao/src/store/module/websocket/msgManage.ts b/Cunkebao/src/store/module/websocket/msgManage.ts new file mode 100644 index 00000000..de232538 --- /dev/null +++ b/Cunkebao/src/store/module/websocket/msgManage.ts @@ -0,0 +1,78 @@ +//消息管理器 +import { WebSocketMessage } from "./websocket"; +import { getkfUserList, asyncKfUserList } from "@/store/module/ckchat/ckchat"; +// 消息处理器类型定义 +type MessageHandler = (message: WebSocketMessage) => void; + +// 消息处理器映射 +const messageHandlers: Record = { + // 微信账号存活状态响应 + CmdRequestWechatAccountsAliveStatusResp: message => { + console.log("微信账号存活状态响应", message); + // 获取客服列表 + const kfUserList = getkfUserList(); + const wechatAccountsAliveStatus = message.wechatAccountsAliveStatus || {}; + // 遍历客服列表,更新存活状态 + kfUserList.forEach(kfUser => { + kfUser.isOnline = wechatAccountsAliveStatus[kfUser.id]; + }); + asyncKfUserList(kfUserList); + }, + + // 登录响应 + CmdSignInResp: message => { + console.log("登录响应", message); + // 在这里添加具体的处理逻辑 + }, + + // 通知消息 + CmdNotify: message => { + console.log("通知消息", message); + // 在这里添加具体的处理逻辑 + }, + + // 可以继续添加更多处理器... +}; + +// 默认处理器 +const defaultHandler: MessageHandler = message => { + console.log("未知消息类型", message.cmdType, message); +}; + +// 注册新的消息处理器 +export const registerMessageHandler = ( + cmdType: string, + handler: MessageHandler, +) => { + messageHandlers[cmdType] = handler; +}; + +// 移除消息处理器 +export const unregisterMessageHandler = (cmdType: string) => { + delete messageHandlers[cmdType]; +}; + +// 获取所有已注册的消息类型 +export const getRegisteredMessageTypes = (): string[] => { + return Object.keys(messageHandlers); +}; + +// 消息管理核心函数 +export const msgManageCore = (message: WebSocketMessage) => { + console.log("获取消息---------------------"); + + const cmdType = message.cmdType; + if (!cmdType) { + console.warn("消息缺少cmdType字段", message); + return; + } + + // 获取对应的处理器,如果没有则使用默认处理器 + const handler = messageHandlers[cmdType] || defaultHandler; + + try { + handler(message); + } catch (error) { + console.error(`处理消息类型 ${cmdType} 时发生错误:`, error); + } +}; diff --git a/Cunkebao/src/store/module/websocket.ts b/Cunkebao/src/store/module/websocket/websocket.ts similarity index 81% rename from Cunkebao/src/store/module/websocket.ts rename to Cunkebao/src/store/module/websocket/websocket.ts index 928584fd..08feb6db 100644 --- a/Cunkebao/src/store/module/websocket.ts +++ b/Cunkebao/src/store/module/websocket/websocket.ts @@ -1,9 +1,9 @@ import { createPersistStore } from "@/store/createPersistStore"; import { Toast } from "antd-mobile"; -import { useUserStore } from "./user"; +import { useUserStore } from "../user"; import { useCkChatStore } from "@/store/module/ckchat/ckchat"; const { getAccountId } = useCkChatStore.getState(); - +import { msgManageCore } from "./msgManage"; // WebSocket消息类型 export interface WebSocketMessage { cmdType?: string; @@ -102,16 +102,16 @@ export const useWebSocketStore = createPersistStore( currentState.status === WebSocketStatus.CONNECTED || currentState.status === WebSocketStatus.CONNECTING ) { - console.log("WebSocket已连接或正在连接,跳过重复连接", { - currentStatus: currentState.status, - hasWebSocket: !!currentState.ws, - }); + // console.log("WebSocket已连接或正在连接,跳过重复连接", { + // currentStatus: currentState.status, + // hasWebSocket: !!currentState.ws, + // }); return; } // 如果已经有WebSocket实例,先断开 if (currentState.ws) { - console.log("断开现有WebSocket连接"); + // console.log("断开现有WebSocket连接"); currentState.disconnect(); } @@ -138,19 +138,19 @@ export const useWebSocketStore = createPersistStore( }); // 调试信息:输出配置和环境变量 - console.log("WebSocket配置信息:", { - configUrl: fullConfig.url, - envUrl: (import.meta as any).env?.VITE_API_WS_URL, - fullConfig, - params: params.toString(), - }); + // console.log("WebSocket配置信息:", { + // configUrl: fullConfig.url, + // envUrl: (import.meta as any).env?.VITE_API_WS_URL, + // fullConfig, + // params: params.toString(), + // }); const wsUrl = fullConfig.url + "?" + params; - console.log("最终WebSocket URL:", wsUrl); + // console.log("最终WebSocket URL:", wsUrl); // 检查URL是否为localhost,如果是则不连接 if (wsUrl.includes("localhost") || wsUrl.includes("127.0.0.1")) { - console.error("WebSocket连接被拦截:不允许连接到本地地址", wsUrl); + // console.error("WebSocket连接被拦截:不允许连接到本地地址", wsUrl); Toast.show({ content: "WebSocket连接被拦截:不允许连接到本地地址", position: "top", @@ -175,9 +175,9 @@ export const useWebSocketStore = createPersistStore( set({ ws }); - console.log("WebSocket连接创建成功", wsUrl); + // console.log("WebSocket连接创建成功", wsUrl); } catch (error) { - console.error("WebSocket连接失败:", error); + // console.error("WebSocket连接失败:", error); set({ status: WebSocketStatus.ERROR }); Toast.show({ content: "WebSocket连接失败", position: "top" }); } @@ -199,7 +199,7 @@ export const useWebSocketStore = createPersistStore( reconnectAttempts: 0, }); - console.log("WebSocket连接已断开"); + // console.log("WebSocket连接已断开"); }, // 发送消息 @@ -220,9 +220,9 @@ export const useWebSocketStore = createPersistStore( try { currentState.ws.send(JSON.stringify(fullMessage)); - console.log("消息发送成功:", fullMessage); + // console.log("消息发送成功:", fullMessage); } catch (error) { - console.error("消息发送失败:", error); + // console.error("消息发送失败:", error); Toast.show({ content: "消息发送失败", position: "top" }); } }, @@ -246,9 +246,9 @@ export const useWebSocketStore = createPersistStore( try { currentState.ws.send(JSON.stringify(command)); - console.log("命令发送成功:", command); + // console.log("命令发送成功:", command); } catch (error) { - console.error("命令发送失败:", error); + // console.error("命令发送失败:", error); Toast.show({ content: "命令发送失败", position: "top" }); } }, @@ -270,7 +270,7 @@ export const useWebSocketStore = createPersistStore( if (currentState.config) { // 检查是否允许重连 if (!currentState.config.autoReconnect) { - console.log("自动重连已禁用,不再尝试重连"); + // console.log("自动重连已禁用,不再尝试重连"); return; } currentState.connect(currentState.config); @@ -286,7 +286,7 @@ export const useWebSocketStore = createPersistStore( reconnectAttempts: 0, }); - console.log("WebSocket连接成功"); + // console.log("WebSocket连接成功"); const { token2 } = useUserStore.getState(); // 发送登录命令 if (currentState.config) { @@ -305,13 +305,13 @@ export const useWebSocketStore = createPersistStore( _handleMessage: (event: MessageEvent) => { try { const data = JSON.parse(event.data); - console.log("收到WebSocket消息:", data); + // console.log("收到WebSocket消息:", data); // 处理特定的通知消息 if (data.cmdType === "CmdNotify") { // 处理Auth failed通知 if (data.notify === "Auth failed" || data.notify === "Kicked out") { - console.error(`WebSocket ${data.notify},断开连接`); + // console.error(`WebSocket ${data.notify},断开连接`); Toast.show({ content: `WebSocket ${data.notify},断开连接`, position: "top", @@ -347,11 +347,13 @@ export const useWebSocketStore = createPersistStore( messages: [...currentState.messages, newMessage], unreadCount: currentState.unreadCount + 1, }); + //消息处理器 + msgManageCore(data); // 可以在这里添加消息处理逻辑 // 比如播放提示音、显示通知等 } catch (error) { - console.error("解析WebSocket消息失败:", error); + // console.error("解析WebSocket消息失败:", error); } }, @@ -359,7 +361,7 @@ export const useWebSocketStore = createPersistStore( _handleClose: (event: CloseEvent) => { const currentState = get(); - console.log("WebSocket连接关闭:", event.code, event.reason); + // console.log("WebSocket连接关闭:", event.code, event.reason); set({ status: WebSocketStatus.DISCONNECTED, @@ -372,10 +374,10 @@ export const useWebSocketStore = createPersistStore( currentState.reconnectAttempts < (currentState.config?.maxReconnectAttempts || 5) ) { - console.log("尝试自动重连..."); + // console.log("尝试自动重连..."); currentState._startReconnectTimer(); } else if (!currentState.config?.autoReconnect) { - console.log("自动重连已禁用,不再尝试重连"); + // console.log("自动重连已禁用,不再尝试重连"); // 重置重连计数 set({ reconnectAttempts: 0 }); } @@ -383,7 +385,7 @@ export const useWebSocketStore = createPersistStore( // 内部方法:处理连接错误 _handleError: (event: Event) => { - console.error("WebSocket连接错误:", event); + // console.error("WebSocket连接错误:", event); set({ status: WebSocketStatus.ERROR }); @@ -402,9 +404,9 @@ export const useWebSocketStore = createPersistStore( }); const timer = setTimeout(() => { - console.log( - `尝试重连 (${currentState.reconnectAttempts + 1}/${currentState.config?.maxReconnectAttempts})`, - ); + // console.log( + // `尝试重连 (${currentState.reconnectAttempts + 1}/${currentState.config?.maxReconnectAttempts})`, + // ); currentState.reconnect(); }, currentState.config?.reconnectInterval || 3000); @@ -434,10 +436,10 @@ export const useWebSocketStore = createPersistStore( onRehydrateStorage: () => state => { // 页面刷新后,如果之前是连接状态,尝试重新连接 if (state && state.status === WebSocketStatus.CONNECTED && state.config) { - console.log("页面刷新后恢复WebSocket连接", { - persistedConfig: state.config, - currentDefaultConfig: DEFAULT_CONFIG, - }); + // console.log("页面刷新后恢复WebSocket连接", { + // persistedConfig: state.config, + // currentDefaultConfig: DEFAULT_CONFIG, + // }); // 使用最新的默认配置,而不是持久化的配置 const freshConfig = { @@ -448,24 +450,24 @@ export const useWebSocketStore = createPersistStore( autoReconnect: state.config.autoReconnect, }; - console.log("使用刷新后的配置重连:", freshConfig); + // console.log("使用刷新后的配置重连:", freshConfig); // 延迟一下再重连,确保页面完全加载 // 同时检查当前状态,避免重复连接 setTimeout(() => { // 重新获取最新的状态,而不是使用闭包中的state const currentState = useWebSocketStore.getState(); - console.log("页面刷新后检查状态", { - status: currentState.status, - hasWs: !!currentState.ws, - }); + // console.log("页面刷新后检查状态", { + // status: currentState.status, + // hasWs: !!currentState.ws, + // }); // 强制重置状态为disconnected,因为页面刷新后WebSocket实例已失效 if ( currentState.status === WebSocketStatus.CONNECTED && !currentState.ws ) { - console.log("检测到状态不一致,重置为disconnected"); + // console.log("检测到状态不一致,重置为disconnected"); useWebSocketStore.setState({ status: WebSocketStatus.DISCONNECTED, }); @@ -477,12 +479,12 @@ export const useWebSocketStore = createPersistStore( latestState.status === WebSocketStatus.DISCONNECTED || latestState.status === WebSocketStatus.ERROR ) { - console.log("页面刷新后开始重连"); + // console.log("页面刷新后开始重连"); latestState.connect(freshConfig); } else { - console.log("WebSocket已连接或正在连接,跳过页面刷新重连", { - status: latestState.status, - }); + // console.log("WebSocket已连接或正在连接,跳过页面刷新重连", { + // status: latestState.status, + // }); } }, 1000); }