diff --git a/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/components/MessageEnter/index.tsx b/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/components/MessageEnter/index.tsx index 0f4650d2..edd49db9 100644 --- a/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/components/MessageEnter/index.tsx +++ b/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/components/MessageEnter/index.tsx @@ -12,7 +12,7 @@ import { EnvironmentOutlined, StarOutlined, } from "@ant-design/icons"; -import { ChatRecord, ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; +import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; import { useWebSocketStore } from "@/store/module/websocket/websocket"; import styles from "./MessageEnter.module.scss"; @@ -21,15 +21,11 @@ const { TextArea } = Input; interface MessageEnterProps { contract: ContractData | weChatGroup; - onSendMessage: (message: string) => void; } const { sendCommand } = useWebSocketStore.getState(); -const MessageEnter: React.FC = ({ - contract, - onSendMessage, -}) => { +const MessageEnter: React.FC = ({ contract }) => { const [inputValue, setInputValue] = useState(""); const [showMaterialModal, setShowMaterialModal] = useState(false); diff --git a/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx b/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx index 22e96c0f..087029ff 100644 --- a/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx +++ b/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx @@ -1,14 +1,5 @@ import React, { useState, useEffect, useRef } from "react"; -import { - Layout, - Button, - Avatar, - Space, - Dropdown, - Menu, - message, - Tooltip, -} from "antd"; +import { Layout, Button, Avatar, Space, Dropdown, Menu, Tooltip } from "antd"; import { PhoneOutlined, VideoCameraOutlined, @@ -26,7 +17,6 @@ import { EnvironmentOutlined, } from "@ant-design/icons"; import { ChatRecord, ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; -import { getChatMessages } from "@/pages/pc/ckbox/api"; import styles from "./ChatWindow.module.scss"; import { useWebSocketStore, @@ -35,51 +25,27 @@ import { import { formatWechatTime } from "@/utils/common"; import Person from "./components/Person"; import MessageEnter from "./components/MessageEnter"; +import { useWeChatStore } from "@/store/module/weChat/weChat"; const { Header, Content } = Layout; interface ChatWindowProps { contract: ContractData | weChatGroup; - onSendMessage: (message: string) => void; showProfile?: boolean; onToggleProfile?: () => void; } const ChatWindow: React.FC = ({ contract, - onSendMessage, showProfile = true, onToggleProfile, }) => { - const [, contextHolder] = message.useMessage(); const [messages, setMessages] = useState([]); const [loading, setLoading] = useState(false); const [pendingVideoRequests, setPendingVideoRequests] = useState< Record >({}); const messagesEndRef = useRef(null); - - useEffect(() => { - setLoading(true); - const params: any = { - wechatAccountId: contract.wechatAccountId, - From: 1, - To: 4704624000000, - Count: 5, - olderData: true, - }; - if (contract.chatroomId) { - params.wechatChatroomId = contract.id; - } else { - params.wechatFriendId = contract.id; - } - getChatMessages(params) - .then(msg => { - setMessages(msg); - }) - .finally(() => { - setLoading(false); - }); - }, [contract.id]); + const currentMessages = useWeChatStore(state => state.currentMessages); useEffect(() => { // 只有在非视频加载操作时才自动滚动到底部 @@ -709,7 +675,6 @@ const ChatWindow: React.FC = ({ return ( - {contextHolder} {/* 聊天主体区域 */} {/* 聊天头部 */} @@ -775,7 +740,7 @@ const ChatWindow: React.FC = ({ {/* 消息输入组件 */} - + {/* 右侧个人资料卡片 */} diff --git a/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/MessageList/index.tsx b/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/MessageList/index.tsx index 877b9c9e..3507fc6d 100644 --- a/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/MessageList/index.tsx +++ b/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/MessageList/index.tsx @@ -2,19 +2,19 @@ import React from "react"; import { List, Avatar, Badge } from "antd"; import { UserOutlined, TeamOutlined } from "@ant-design/icons"; import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; +import { useWeChatStore } from "@/store/module/weChat/weChat"; import styles from "./MessageList.module.scss"; import { formatWechatTime } from "@/utils/common"; interface MessageListProps { chatSessions: ContractData[] | weChatGroup[]; - currentChat: ContractData | weChatGroup; - onContactClick: (chat: ContractData | weChatGroup) => void; } -const MessageList: React.FC = ({ - chatSessions, - currentChat, - onContactClick, -}) => { +const MessageList: React.FC = ({ chatSessions }) => { + const { setCurrentContact, currentContract } = useWeChatStore(); + + const onContactClick = (session: ContractData | weChatGroup) => { + setCurrentContact(session); + }; return (
= ({ onContactClick(session)} > diff --git a/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/WechatFriends/index.tsx b/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/WechatFriends/index.tsx index 24ae993f..76f5f981 100644 --- a/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/WechatFriends/index.tsx +++ b/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/WechatFriends/index.tsx @@ -7,16 +7,13 @@ import { searchContactsAndGroups, } from "@/store/module/ckchat/ckchat"; import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; +import { addChatSession } from "@/store/module/ckchat/ckchat"; +import { useWeChatStore } from "@/store/module/weChat/weChat"; interface WechatFriendsProps { - contracts: ContractData[] | weChatGroup[]; - onContactClick: (contract: ContractData | weChatGroup) => void; selectedContactId?: ContractData | weChatGroup; } - const ContactListSimple: React.FC = ({ - contracts, - onContactClick, selectedContactId, }) => { const [newContractList, setNewContractList] = useState([]); @@ -64,6 +61,11 @@ const ContactListSimple: React.FC = ({ const [loading, setLoading] = useState<{ [key: string]: boolean }>({}); const [hasMore, setHasMore] = useState<{ [key: string]: boolean }>({}); const [page, setPage] = useState<{ [key: string]: number }>({}); + const { setCurrentContact } = useWeChatStore(); + const onContactClick = (contact: ContractData | weChatGroup) => { + addChatSession(contact); + setCurrentContact(contact); + }; // 渲染联系人项 const renderContactItem = (contact: ContractData | weChatGroup) => { @@ -219,7 +221,7 @@ const ContactListSimple: React.FC = ({
未找到匹配的联系人
)} - ) : newContractList && newContractList.length > 0 ? ( + ) : ( // 正常模式:显示分组 = ({ onChange={keys => setActiveKey(keys as string[])} items={getCollapseItems()} /> - ) : ( - // 备用模式:显示传入的联系人列表 - <> -
全部联系人
- - )}
); diff --git a/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/index.tsx b/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/index.tsx index 4704cf38..d9152f95 100644 --- a/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/index.tsx +++ b/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/index.tsx @@ -6,24 +6,19 @@ import { ChromeOutlined, MessageOutlined, } from "@ant-design/icons"; -import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; import WechatFriends from "./WechatFriends"; import MessageList from "./MessageList/index"; import styles from "./SidebarMenu.module.scss"; import { useCkChatStore } from "@/store/module/ckchat/ckchat"; - +import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; interface SidebarMenuProps { - contracts: ContractData[] | weChatGroup[]; - currentChat: ContractData | weChatGroup; - onContactClick: (contract: ContractData | weChatGroup) => void; loading?: boolean; + currentContract?: ContractData | weChatGroup; } const SidebarMenu: React.FC = ({ - contracts, - currentChat, - onContactClick, loading = false, + currentContract, }) => { const chatSessions = useCkChatStore(state => state.getChatSessions()); const searchKeyword = useCkChatStore(state => state.searchKeyword); @@ -133,21 +128,9 @@ const SidebarMenu: React.FC = ({ const renderContent = () => { switch (activeTab) { case "chats": - return ( - - ); + return ; case "contracts": - return ( - - ); + return ; case "groups": return (
diff --git a/Cunkebao/src/pages/pc/ckbox/index.tsx b/Cunkebao/src/pages/pc/ckbox/index.tsx index e02d5739..38c9cf84 100644 --- a/Cunkebao/src/pages/pc/ckbox/index.tsx +++ b/Cunkebao/src/pages/pc/ckbox/index.tsx @@ -10,23 +10,15 @@ import styles from "./index.module.scss"; import { addChatSession } from "@/store/module/ckchat/ckchat"; const { Header, Content, Sider } = Layout; import { chatInitAPIdata, initSocket } from "./main"; -import { clearUnreadCount, updateConfig } from "@/pages/pc/ckbox/api"; -import { - KfUserListData, - weChatGroup, - ContractData, -} from "@/pages/pc/ckbox/data"; +import { useWeChatStore } from "@/store/module/weChat/weChat"; + +import { KfUserListData } from "@/pages/pc/ckbox/data"; const CkboxPage: React.FC = () => { - const [messageApi, contextHolder] = message.useMessage(); - const [contracts, setContacts] = useState([]); - const [currentChat, setCurrentChat] = useState( - null, - ); // 不要在组件初始化时获取sendCommand,而是在需要时动态获取 const [loading, setLoading] = useState(false); const [showProfile, setShowProfile] = useState(true); - + const currentContract = useWeChatStore(state => state.currentContract); useEffect(() => { // 方法一:使用 Promise 链式调用处理异步函数 setLoading(true); @@ -48,8 +40,6 @@ const CkboxPage: React.FC = () => { addChatSession(v); }); - setContacts(isChatList); - // 数据加载完成后初始化WebSocket连接 initSocket(); }) @@ -61,50 +51,9 @@ const CkboxPage: React.FC = () => { }); }, []); - //开始开启聊天 - const handleContactClick = (contract: ContractData | weChatGroup) => { - clearUnreadCount([contract.id]).then(() => { - contract.unreadCount = 0; - addChatSession(contract); - setCurrentChat(contract); - updateConfig({ - id: contract.id, - config: { chat: true }, - }); - }); - }; - - const handleSendMessage = async (message: string) => { - if (!currentChat || !message.trim()) return; - - try { - // 更新当前聊天会话 - const updatedSession = { - ...currentChat, - lastMessage: message, - lastTime: dayjs().toISOString(), - unreadCount: 0, - }; - - setCurrentChat(updatedSession); - - messageApi.success("消息发送成功"); - } catch (error) { - messageApi.error("消息发送失败"); - } - }; - - // 处理垂直侧边栏用户选择 - const handleVerticalUserSelect = (userId: string) => { - // setActiveVerticalUserId(userId); - // 这里可以根据选择的用户类别筛选不同的联系人列表 - // 例如:根据userId加载不同分类的联系人 - }; - return ( - {contextHolder}
触客宝
{/* 垂直侧边栏 */} @@ -115,17 +64,12 @@ const CkboxPage: React.FC = () => { {/* 左侧联系人边栏 */} - + {/* 主内容区 */} - {currentChat ? ( + {currentContract ? (
@@ -142,8 +86,7 @@ const CkboxPage: React.FC = () => {
setShowProfile(!showProfile)} /> diff --git a/Cunkebao/src/store/module/weChat.ts b/Cunkebao/src/store/module/weChat.ts deleted file mode 100644 index e1cf17a4..00000000 --- a/Cunkebao/src/store/module/weChat.ts +++ /dev/null @@ -1,601 +0,0 @@ -import { create } from "zustand"; -import { createPersistStore } from "../createPersistStore"; -import { getChatMessages } from "@/pages/pc/ckbox/api"; -import { ChatRecord, ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; -import { useWebSocketStore } from "./websocket/websocket"; - -// 聊天列表项类型定义 -export interface ChatListItem { - id: string; - name: string; - avatar?: string; - type: "friend" | "group"; - lastMessage?: ChatRecord; - unreadCount: number; - isOnline?: boolean; - lastActiveTime: number; // 最后活跃时间,用于排序 - contractData: ContractData | weChatGroup; // 保存完整的联系人数据 -} - -// 微信聊天相关的类型定义 -export interface WeChatState { - // 当前选中的联系人/群组 - currentContract: ContractData | weChatGroup | null; - - // 当前聊天用户的消息列表(只存储当前聊天用户的消息) - currentMessages: ChatRecord[]; - - // 联系人列表(所有好友和群组) - contacts: (ContractData | weChatGroup)[]; - - // 聊天列表(有聊天记录的联系人/群组,按最后活跃时间排序) - chatList: ChatListItem[]; - - // 消息发送状态 - sendingStatus: Record; // key为消息临时ID,value为发送状态 - - // 消息加载状态 - loadingMessages: boolean; - - // 待处理的视频请求 - pendingVideoRequests: Record; // messageId -> requestId - - // 输入框内容状态 - 按联系人/群组ID分组存储 - inputValues: Record; - - // 素材模态框状态 - showMaterialModal: boolean; - selectedMaterialType: string; -} - -export interface WeChatActions { - // 设置当前选中的联系人/群组 - setCurrentContract: (contract: ContractData | weChatGroup | null) => void; - - // 获取聊天消息 - fetchChatMessages: (contract: ContractData | weChatGroup) => Promise; - - // 设置当前消息列表 - setCurrentMessages: (messages: ChatRecord[]) => void; - - // 添加消息到当前聊天 - addMessageToCurrentChat: (message: ChatRecord) => void; - - // 更新消息内容(用于视频加载状态更新等) - updateMessage: (messageId: number, updates: Partial) => void; - - // 发送消息 - sendMessage: ( - contract: ContractData | weChatGroup, - content: string, - msgType?: number, - ) => Promise; - - // 处理视频播放请求 - handleVideoPlayRequest: ( - tencentUrl: string, - messageId: number, - contract: ContractData | weChatGroup, - ) => void; - - // 设置待处理的视频请求 - setPendingVideoRequest: (messageId: string, requestId: string) => void; - - // 移除待处理的视频请求 - removePendingVideoRequest: (messageId: string) => void; - - // 处理视频下载响应 - handleVideoDownloadResponse: (messageId: string, videoUrl: string) => void; - - // 设置输入框内容 - setInputValue: (contractId: string, value: string) => void; - - // 获取输入框内容 - getInputValue: (contractId: string) => string; - - // 清空输入框内容 - clearInputValue: (contractId: string) => void; - - // 素材模态框相关操作 - setShowMaterialModal: (show: boolean) => void; - setSelectedMaterialType: (type: string) => void; - - // 新消息处理 - handleNewMessage: ( - message: ChatRecord, - fromContract: ContractData | weChatGroup, - ) => void; - - // 聊天列表管理 - setContacts: (contacts: (ContractData | weChatGroup)[]) => void; - setChatList: (chatList: ChatListItem[]) => void; - updateChatListItem: ( - contractId: string, - updates: Partial, - ) => void; - moveToTopOfChatList: (contractId: string) => void; - addToChatList: (contract: ContractData | weChatGroup) => void; - - // 未读消息管理 - incrementUnreadCount: (contractId: string) => void; - clearUnreadCount: (contractId: string) => void; - - // 便捷选择器 - getUnreadTotal: () => number; - getChatListSorted: () => ChatListItem[]; - - // 清理指定联系人的数据 - clearContractData: (contractId: string) => void; - - // 清理所有数据 - clearAllData: () => void; -} - -type WeChatStore = WeChatState & WeChatActions; - -// 生成联系人/群组的唯一ID -const getContractId = (contract: ContractData | weChatGroup): string => { - if ("chatroomId" in contract && contract.chatroomId) { - return `group_${contract.chatroomId}`; - } - return `friend_${contract.id}`; -}; - -export const useWeChatStore = create()( - createPersistStore( - (set, get) => ({ - // 初始状态 - currentContract: null, - currentMessages: [], - contacts: [], - chatList: [], - sendingStatus: {}, - loadingMessages: false, - pendingVideoRequests: {}, - inputValues: {}, - showMaterialModal: false, - selectedMaterialType: "", - - // Actions - setCurrentContract: contract => { - set({ currentContract: contract }); - // 切换联系人时清空当前消息,等待重新加载 - set({ currentMessages: [] }); - // 清除该联系人的未读数 - if (contract) { - const contractId = getContractId(contract); - get().clearUnreadCount(contractId); - } - }, - - fetchChatMessages: async contract => { - const { currentMessages } = get(); - - // 如果已经有消息数据,不重复加载 - if (currentMessages.length > 0) { - return; - } - - set({ loadingMessages: true }); - - try { - const params: any = { - wechatAccountId: contract.wechatAccountId, - From: 1, - To: 4704624000000, - Count: 10, - olderData: true, - }; - - if ("chatroomId" in contract && contract.chatroomId) { - params.wechatChatroomId = contract.chatroomId; - } else { - params.wechatFriendId = contract.id; - } - - const messages = await getChatMessages(params); - - set({ currentMessages: messages }); - } catch (error) { - console.error("获取聊天消息失败:", error); - } finally { - set({ loadingMessages: false }); - } - }, - - setCurrentMessages: messages => { - set({ currentMessages: messages }); - }, - - addMessageToCurrentChat: message => { - set(state => ({ - currentMessages: [...state.currentMessages, message], - })); - }, - - updateMessage: (messageId, updates) => { - set(state => ({ - currentMessages: state.currentMessages.map(msg => - msg.id === messageId ? { ...msg, ...updates } : msg, - ), - })); - }, - - sendMessage: async (contract, content, msgType = 1) => { - const contractId = getContractId(contract); - const tempId = `temp_${Date.now()}`; - - // 设置发送状态 - set(state => ({ - sendingStatus: { - ...state.sendingStatus, - [tempId]: true, - }, - })); - - try { - const params = { - wechatAccountId: contract.wechatAccountId, - wechatChatroomId: - "chatroomId" in contract && contract.chatroomId - ? contract.chatroomId - : 0, - wechatFriendId: - "chatroomId" in contract && contract.chatroomId ? 0 : contract.id, - msgSubType: 0, - msgType, - content, - }; - - // 通过WebSocket发送消息 - const { sendCommand } = useWebSocketStore.getState(); - await sendCommand("CmdSendMessage", params); - - // 清空对应的输入框内容 - get().clearInputValue(contractId); - } catch (error) { - console.error("发送消息失败:", error); - } finally { - // 移除发送状态 - set(state => { - const newSendingStatus = { ...state.sendingStatus }; - delete newSendingStatus[tempId]; - return { sendingStatus: newSendingStatus }; - }); - } - }, - - handleVideoPlayRequest: (tencentUrl, messageId, contract) => { - const requestSeq = `${Date.now()}`; - - console.log("发送视频下载请求:", { messageId, requestSeq }); - - // 构建socket请求数据 - const { sendCommand } = useWebSocketStore.getState(); - sendCommand("CmdDownloadVideo", { - chatroomMessageId: - "chatroomId" in contract && contract.chatroomId ? messageId : 0, - friendMessageId: - "chatroomId" in contract && contract.chatroomId ? 0 : messageId, - seq: requestSeq, - tencentUrl: tencentUrl, - wechatAccountId: contract.wechatAccountId, - }); - - // 添加到待处理队列 - get().setPendingVideoRequest( - messageId.toString(), - messageId.toString(), - ); - - // 更新消息状态为加载中 - const messages = get().currentMessages; - const targetMessage = messages.find(msg => msg.id === messageId); - if (targetMessage) { - try { - const originalContent = - typeof targetMessage.content === "string" - ? JSON.parse(targetMessage.content) - : targetMessage.content; - - get().updateMessage(messageId, { - content: JSON.stringify({ - ...originalContent, - isLoading: true, - }), - }); - } catch (e) { - console.error("解析消息内容失败:", e); - } - } - }, - - setPendingVideoRequest: (messageId, requestId) => { - set(state => ({ - pendingVideoRequests: { - ...state.pendingVideoRequests, - [messageId]: requestId, - }, - })); - }, - - removePendingVideoRequest: messageId => { - set(state => { - const newRequests = { ...state.pendingVideoRequests }; - delete newRequests[messageId]; - return { pendingVideoRequests: newRequests }; - }); - }, - - handleVideoDownloadResponse: (messageId, videoUrl) => { - const { currentMessages } = get(); - const targetMessage = currentMessages.find( - msg => msg.id === Number(messageId), - ); - - if (targetMessage) { - try { - const msgContent = - typeof targetMessage.content === "string" - ? JSON.parse(targetMessage.content) - : targetMessage.content; - - // 更新消息内容,添加视频URL并移除加载状态 - get().updateMessage(Number(messageId), { - content: JSON.stringify({ - ...msgContent, - videoUrl: videoUrl, - isLoading: false, - }), - }); - - // 从待处理队列中移除 - get().removePendingVideoRequest(messageId); - } catch (e) { - console.error("解析消息内容失败:", e); - } - } - }, - - setInputValue: (contractId, value) => { - set(state => ({ - inputValues: { - ...state.inputValues, - [contractId]: value, - }, - })); - }, - - getInputValue: contractId => { - return get().inputValues[contractId] || ""; - }, - - clearInputValue: contractId => { - set(state => { - const newInputValues = { ...state.inputValues }; - delete newInputValues[contractId]; - return { inputValues: newInputValues }; - }); - }, - - setShowMaterialModal: show => { - set({ showMaterialModal: show }); - }, - - setSelectedMaterialType: type => { - set({ selectedMaterialType: type }); - }, - - // 新消息处理 - handleNewMessage: (message, fromContract) => { - const { currentContract } = get(); - const contractId = getContractId(fromContract); - - // 如果是当前聊天用户的消息,直接添加到当前消息列表 - if (currentContract && getContractId(currentContract) === contractId) { - get().addMessageToCurrentChat(message); - } else { - // 如果不是当前聊天用户,更新聊天列表 - get().incrementUnreadCount(contractId); - get().moveToTopOfChatList(contractId); - - // 更新聊天列表项的最后消息 - get().updateChatListItem(contractId, { - lastMessage: message, - lastActiveTime: message.createTime || Date.now(), - }); - } - }, - - // 聊天列表管理 - setContacts: contacts => { - set({ contacts }); - }, - - setChatList: chatList => { - set({ chatList }); - }, - - updateChatListItem: (contractId, updates) => { - set(state => ({ - chatList: state.chatList.map(item => - getContractId(item.contractData) === contractId - ? { ...item, ...updates } - : item, - ), - })); - }, - - moveToTopOfChatList: contractId => { - set(state => { - const chatList = [...state.chatList]; - const itemIndex = chatList.findIndex( - item => getContractId(item.contractData) === contractId, - ); - - if (itemIndex > 0) { - // 移动到顶部 - const item = chatList.splice(itemIndex, 1)[0]; - chatList.unshift({ ...item, lastActiveTime: Date.now() }); - } else if (itemIndex === -1) { - // 如果不在聊天列表中,从联系人列表找到并添加 - const contract = state.contacts.find( - c => getContractId(c) === contractId, - ); - if (contract) { - get().addToChatList(contract); - } - } - - return { chatList }; - }); - }, - - addToChatList: contract => { - set(state => { - const contractId = getContractId(contract); - // 检查是否已存在 - const exists = state.chatList.some( - item => getContractId(item.contractData) === contractId, - ); - if (exists) return state; - - const newChatItem: ChatListItem = { - id: contractId, - name: contract.nickName || contract.name || "", - avatar: contract.avatar, - type: "chatroomId" in contract ? "group" : "friend", - unreadCount: 0, - lastActiveTime: Date.now(), - contractData: contract, - }; - - return { - chatList: [newChatItem, ...state.chatList], - }; - }); - }, - - // 未读消息管理 - incrementUnreadCount: contractId => { - // 更新聊天列表中的未读数 - set(state => ({ - chatList: state.chatList.map(item => - getContractId(item.contractData) === contractId - ? { ...item, unreadCount: item.unreadCount + 1 } - : item, - ), - })); - }, - - clearUnreadCount: contractId => { - // 清除聊天列表中的未读数 - set(state => ({ - chatList: state.chatList.map(item => - getContractId(item.contractData) === contractId - ? { ...item, unreadCount: 0 } - : item, - ), - })); - }, - - // 便捷选择器 - getUnreadTotal: () => { - const { chatList } = get(); - return chatList.reduce((total, item) => total + item.unreadCount, 0); - }, - - getChatListSorted: () => { - const { chatList } = get(); - return [...chatList].sort( - (a, b) => b.lastActiveTime - a.lastActiveTime, - ); - }, - - clearContractData: contractId => { - set(state => { - const newInputValues = { ...state.inputValues }; - delete newInputValues[contractId]; - - return { - inputValues: newInputValues, - chatList: state.chatList.filter( - item => getContractId(item.contractData) !== contractId, - ), - }; - }); - }, - - clearAllData: () => { - set({ - currentContract: null, - currentMessages: [], - contacts: [], - chatList: [], - sendingStatus: {}, - loadingMessages: false, - pendingVideoRequests: {}, - inputValues: {}, - showMaterialModal: false, - selectedMaterialType: "", - }); - }, - }), - { - name: "wechat-store", - // 只持久化部分状态,排除临时状态 - partialize: state => ({ - contacts: state.contacts, - chatList: state.chatList, - inputValues: state.inputValues, - }), - }, - ), -); - -// 导出便捷的选择器函数 -export const useCurrentContract = () => - useWeChatStore(state => state.currentContract); -export const useCurrentMessages = () => - useWeChatStore(state => state.currentMessages); -export const useCurrentInputValue = () => { - const { currentContract, getInputValue } = useWeChatStore(); - if (!currentContract) return ""; - const contractId = getContractId(currentContract); - return getInputValue(contractId); -}; -export const useChatList = () => - useWeChatStore(state => state.getChatListSorted()); -export const useUnreadTotal = () => - useWeChatStore(state => state.getUnreadTotal()); - -// 初始化WebSocket消息监听 -if (typeof window !== "undefined") { - // 监听WebSocket消息,处理视频下载响应 - useWebSocketStore.subscribe(state => { - const messages = state.messages as any[]; - const { pendingVideoRequests, handleVideoDownloadResponse } = - useWeChatStore.getState(); - - // 只有当有待处理的视频请求时才处理消息 - if (Object.keys(pendingVideoRequests).length === 0) { - return; - } - - messages.forEach(message => { - if (message?.content?.cmdType === "CmdDownloadVideoResult") { - console.log("收到视频下载响应:", message.content); - - // 检查是否是我们正在等待的视频响应 - const messageId = Object.keys(pendingVideoRequests).find( - id => pendingVideoRequests[id] === message.content.friendMessageId, - ); - - if (messageId) { - console.log("找到对应的消息ID:", messageId); - handleVideoDownloadResponse(messageId, message.content.url); - } - } - }); - }); -} diff --git a/Cunkebao/src/store/module/weChat/weChat.data.ts b/Cunkebao/src/store/module/weChat/weChat.data.ts new file mode 100644 index 00000000..3bd851eb --- /dev/null +++ b/Cunkebao/src/store/module/weChat/weChat.data.ts @@ -0,0 +1,14 @@ +import { ChatRecord, ContractData, weChatGroup } from "@/pages/pc/ckbox/data"; +// 微信聊天相关的类型定义 +export interface WeChatState { + // 当前选中的联系人/群组 + currentContract: ContractData | weChatGroup | null; + + // 当前聊天用户的消息列表(只存储当前聊天用户的消息) + currentMessages: ChatRecord[]; + + setCurrentContact: (contract: ContractData | weChatGroup) => void; + // 消息加载状态 + messagesLoading: boolean; + loadChatMessages: (contact: ContractData | weChatGroup) => Promise; +} diff --git a/Cunkebao/src/store/module/weChat/weChat.ts b/Cunkebao/src/store/module/weChat/weChat.ts new file mode 100644 index 00000000..66ee7818 --- /dev/null +++ b/Cunkebao/src/store/module/weChat/weChat.ts @@ -0,0 +1,106 @@ +import { create } from "zustand"; +import { persist } from "zustand/middleware"; +import { getChatMessages } from "@/pages/pc/ckbox/api"; +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"; +export const useWeChatStore = create()( + persist( + (set, get) => ({ + // 初始状态 + currentContract: null, + currentMessages: [], + messagesLoading: false, + + // Actions + setCurrentContact: (contract: ContractData | weChatGroup) => { + const state = useWeChatStore.getState(); + // 切换联系人时清空当前消息,等待重新加载 + set({ currentMessages: [] }); + clearUnreadCount([contract.id]).then(() => { + contract.unreadCount = 0; + addChatSession(contract); + set({ currentContract: contract }); + updateConfig({ + id: contract.id, + config: { chat: true }, + }); + state.loadChatMessages(contract); + }); + }, + + loadChatMessages: async contact => { + set({ messagesLoading: true }); + + try { + const params: any = { + wechatAccountId: contact.wechatAccountId, + From: 1, + To: 4704624000000, + Count: 10, + olderData: true, + }; + + if ("chatroomId" in contact && contact.chatroomId) { + params.wechatChatroomId = contact.chatroomId; + } else { + params.wechatFriendId = contact.id; + } + + const messages = await getChatMessages(params); + set({ currentMessages: messages }); + } catch (error) { + console.error("获取聊天消息失败:", error); + } finally { + set({ messagesLoading: false }); + } + }, + + setMessageLoading: loading => { + set({ messagesLoading: loading }); + }, + + addMessage: message => { + set(state => ({ + currentMessages: [...state.currentMessages, message], + })); + }, + + updateMessage: (messageId, updates) => { + set(state => ({ + currentMessages: state.currentMessages.map(msg => + msg.id === messageId ? { ...msg, ...updates } : msg, + ), + })); + }, + + // 便捷选择器 + getCurrentContact: () => get().currentContract, + getCurrentMessages: () => get().currentMessages, + getMessagesLoading: () => get().messagesLoading, + + clearAllData: () => { + set({ + currentContract: null, + currentMessages: [], + messagesLoading: false, + }); + }, + }), + { + name: "wechat-storage", + partialize: state => ({ + currentContract: state.currentContract, + }), + }, + ), +); + +// 导出便捷的选择器函数 +export const useCurrentContact = () => + useWeChatStore(state => state.currentContract); +export const useCurrentMessages = () => + useWeChatStore(state => state.currentMessages); +export const useMessagesLoading = () => + useWeChatStore(state => state.messagesLoading);