From 32ea075e90112bbad8ecfe758781fe8b9a99749c 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: Fri, 22 Aug 2025 14:21:35 +0800 Subject: [PATCH] =?UTF-8?q?FEAT=20=3D>=20=E6=9C=AC=E6=AC=A1=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E9=A1=B9=E7=9B=AE=E4=B8=BA=EF=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pc/ckbox/components/ChatWindow/index.tsx | 26 +-- .../SidebarMenu/SidebarMenu.module.scss | 2 +- ...ListSimple.tsx => WechatFriendsModule.tsx} | 8 +- .../pc/ckbox/components/SidebarMenu/data.ts | 47 ++++++ .../pc/ckbox/components/SidebarMenu/index.tsx | 103 ++++++------ Cunkebao/src/pages/pc/ckbox/data.ts | 72 ++++++--- Cunkebao/src/pages/pc/ckbox/index.tsx | 149 ++---------------- Cunkebao/src/pages/pc/ckbox/main.ts | 47 +++--- Cunkebao/src/store/module/websocket.ts | 2 - 9 files changed, 206 insertions(+), 250 deletions(-) rename Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/{ContactListSimple.tsx => WechatFriendsModule.tsx} (85%) create mode 100644 Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/data.ts diff --git a/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx b/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx index f3f76a2f..3ba0b11b 100644 --- a/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx +++ b/Cunkebao/src/pages/pc/ckbox/components/ChatWindow/index.tsx @@ -78,16 +78,16 @@ const ChatWindow: React.FC = ({ const fetchChatHistory = async () => { try { setLoading(true); - + // 从chat对象中提取wechatFriendId // 假设chat.id存储的是wechatFriendId const wechatFriendId = parseInt(chat.id); - + if (isNaN(wechatFriendId)) { messageApi.error("无效的聊天ID"); return; } - + // 调用API获取聊天历史 const response = await getChatMessage({ wechatAccountId: 32686452, // 使用实际的wechatAccountId @@ -98,9 +98,9 @@ const ChatWindow: React.FC = ({ olderData: false, keyword: "", }); - + console.log("聊天历史响应:", response); - + if (response && Array.isArray(response)) { // 将API返回的消息记录转换为MessageData格式 const chatMessages: MessageData[] = response.map(item => { @@ -112,24 +112,28 @@ const ChatWindow: React.FC = ({ } catch (e) { msgContent = item.content; } - + // 判断消息是发送还是接收 const isSend = item.isSend === true; - + return { id: item.id.toString(), senderId: isSend ? "me" : "other", senderName: isSend ? "我" : chat.name, content: msgContent, type: MessageType.TEXT, // 默认为文本类型,实际应根据msgType字段判断 - timestamp: item.createTime || new Date(item.wechatTime).toISOString(), + timestamp: + item.createTime || new Date(item.wechatTime).toISOString(), isRead: true, // 默认已读 }; }); - + // 按时间排序 - chatMessages.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()); - + chatMessages.sort( + (a, b) => + new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(), + ); + setMessages(chatMessages); } else { // 如果没有消息,显示空数组 diff --git a/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/SidebarMenu.module.scss b/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/SidebarMenu.module.scss index 614120fb..1b77fa4d 100644 --- a/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/SidebarMenu.module.scss +++ b/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/SidebarMenu.module.scss @@ -60,4 +60,4 @@ padding: 20px; text-align: center; } -} \ No newline at end of file +} diff --git a/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/ContactListSimple.tsx b/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/WechatFriendsModule.tsx similarity index 85% rename from Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/ContactListSimple.tsx rename to Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/WechatFriendsModule.tsx index 9a5dfba3..c3fd5e2c 100644 --- a/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/ContactListSimple.tsx +++ b/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/WechatFriendsModule.tsx @@ -1,12 +1,12 @@ import React from "react"; import { List, Avatar, Badge } from "antd"; -import { ContactData } from "../../data"; +import { ContactData } from "./data"; import styles from "./ContactListSimple.module.scss"; interface ContactListSimpleProps { contacts: ContactData[]; onContactClick: (contact: ContactData) => void; - selectedContactId?: string; + selectedContactId?: number; } const ContactListSimple: React.FC = ({ @@ -31,14 +31,14 @@ const ContactListSimple: React.FC = ({ {contact.name.charAt(0)} + !contact.avatar && {contact.nickname.charAt(0)} } className={styles.avatar} />
-
{contact.name}
+
{contact.nickname}
)} diff --git a/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/data.ts b/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/data.ts new file mode 100644 index 00000000..afe7cb81 --- /dev/null +++ b/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/data.ts @@ -0,0 +1,47 @@ +// 联系人数据接口 +export interface ContactData { + id?: number; + wechatAccountId: number; + wechatId: string; + alias: string; + conRemark: string; + nickname: string; + quanPin: string; + avatar?: string; + gender: number; + region: string; + addFrom: number; + phone: string; + labels: string[]; + signature: string; + accountId: number; + extendFields: null; + city?: string; + lastUpdateTime: string; + isPassed: boolean; + tenantId: number; + groupId: number; + thirdParty: null; + additionalPicture: string; + desc: string; + config: null; + lastMessageTime: number; + unreadCount: number; + duplicate: boolean; +} +//聊天会话类型 +export type ChatType = "private" | "group"; +// 聊天会话接口 +export interface ChatSession { + id: string; + type: ChatType; + name: string; + avatar?: string; + lastMessage: string; + lastTime: string; + unreadCount: number; + online: boolean; + members?: string[]; + pinned?: boolean; + muted?: boolean; +} diff --git a/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/index.tsx b/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/index.tsx index e4da3996..edfc2c74 100644 --- a/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/index.tsx +++ b/Cunkebao/src/pages/pc/ckbox/components/SidebarMenu/index.tsx @@ -6,12 +6,13 @@ import { TeamOutlined, MessageOutlined, } from "@ant-design/icons"; -import { ContactData, ChatSession } from "../../data"; -import ContactListSimple from "./ContactListSimple"; +import { ContactData, ChatSession } from "./data"; +import WechatFriendsModule from "./WechatFriendsModule"; import MessageList from "../MessageList/index"; import styles from "./SidebarMenu.module.scss"; const { Sider } = Layout; +const { TabPane } = Tabs; interface SidebarMenuProps { contacts: ContactData[]; @@ -41,7 +42,7 @@ const SidebarMenu: React.FC = ({ if (!searchText) return contacts; return contacts.filter( contact => - contact.name.toLowerCase().includes(searchText.toLowerCase()) || + contact.nickname.toLowerCase().includes(searchText.toLowerCase()) || contact.phone.includes(searchText), ); }; @@ -71,56 +72,52 @@ const SidebarMenu: React.FC = ({ activeKey={activeTab} onChange={setActiveTab} className={styles.tabs} - items={[ - { - key: "chats", - label: ( - - - 聊天 - - ), - children: ( - - ), - }, - { - key: "contacts", - label: ( - - - 联系人 - - ), - children: ( - - ), - }, - { - key: "groups", - label: ( - - - 群组 - - ), - children: ( -
- -

暂无群组

-
- ), - }, - ]} - /> + > + + + 聊天 + + } + key="chats" + > + + + + + 联系人 + + } + key="contacts" + > + + + + + 群组 + + } + key="groups" + > +
+ +

暂无群组

+
+
+ ); }; diff --git a/Cunkebao/src/pages/pc/ckbox/data.ts b/Cunkebao/src/pages/pc/ckbox/data.ts index f8f52b59..118b9fa0 100644 --- a/Cunkebao/src/pages/pc/ckbox/data.ts +++ b/Cunkebao/src/pages/pc/ckbox/data.ts @@ -1,14 +1,52 @@ // 联系人数据接口 export interface ContactData { - id: string; - name: string; - phone: string; + id?: number; + wechatAccountId: number; + wechatId: string; + alias: string; + conRemark: string; + nickname: string; + quanPin: string; avatar?: string; - online: boolean; - lastSeen?: string; - status?: string; - department?: string; - position?: string; + gender: number; + region: string; + addFrom: number; + phone: string; + labels: string[]; + signature: string; + accountId: number; + extendFields: null; + city?: string; + lastUpdateTime: string; + isPassed: boolean; + tenantId: number; + groupId: number; + thirdParty: null; + additionalPicture: string; + desc: string; + config: null; + lastMessageTime: number; + unreadCount: number; + duplicate: boolean; +} + +/** + * 微信好友基本信息接口 + * 包含主要字段和兼容性字段 + */ +export interface WechatFriend { + // 主要字段 + id: number; // 好友ID + wechatAccountId: number; // 微信账号ID + wechatId: string; // 微信ID + nickname: string; // 昵称 + conRemark: string; // 备注名 + avatar: string; // 头像URL + gender: number; // 性别:1-男,2-女,0-未知 + region: string; // 地区 + phone: string; // 电话 + labels: string[]; // 标签列表 + [key: string]: any; } // 消息类型枚举 @@ -52,18 +90,6 @@ export interface ChatSession { muted?: boolean; } -// 群组信息接口 -export interface GroupData { - id: string; - name: string; - avatar?: string; - description?: string; - members: ContactData[]; - adminIds: string[]; - createdAt: string; - updatedAt: string; -} - // 聊天历史响应接口 export interface ChatHistoryResponse { messages: MessageData[]; @@ -79,12 +105,6 @@ export interface SendMessageRequest { replyTo?: string; } -// 联系人列表响应接口 -export interface ContactListResponse { - contacts: ContactData[]; - total: number; -} - // 搜索联系人请求接口 export interface SearchContactRequest { keyword: string; diff --git a/Cunkebao/src/pages/pc/ckbox/index.tsx b/Cunkebao/src/pages/pc/ckbox/index.tsx index 58533e02..dd782295 100644 --- a/Cunkebao/src/pages/pc/ckbox/index.tsx +++ b/Cunkebao/src/pages/pc/ckbox/index.tsx @@ -1,19 +1,17 @@ -import React, { useState, useEffect, useRef } from "react"; +import React, { useState, useEffect } from "react"; import { Layout, Button, Space, message, Tooltip } from "antd"; import { InfoCircleOutlined, MessageOutlined } from "@ant-design/icons"; import dayjs from "dayjs"; -import { ContactData, MessageData, ChatSession } from "./data"; +import { ChatSession } from "./data"; +import { ContactData } from "./components/SidebarMenu/data"; import ChatWindow from "./components/ChatWindow/index"; import SidebarMenu from "./components/SidebarMenu/index"; import styles from "./index.module.scss"; -import { getContactList, getChatMessage } from "./api"; -const { Content } = Layout; -import { loginWithToken, getChuKeBaoUserInfo } from "@/pages/login/api"; -import { useCkChatStore } from "@/store/module/ckchat"; +const { Content } = Layout; +import { loginWithToken } from "@/pages/login/api"; import { useUserStore } from "@/store/module/user"; -import { useWebSocketStore } from "@/store/module/websocket"; -import { chatInitAPIdata, getChatInfo } from "./main"; +import { chatInitAPIdata } from "./main"; const CkboxPage: React.FC = () => { const [messageApi, contextHolder] = message.useMessage(); @@ -22,12 +20,19 @@ const CkboxPage: React.FC = () => { const [currentChat, setCurrentChat] = useState(null); const [loading, setLoading] = useState(false); const [showProfile, setShowProfile] = useState(true); - const { setUserInfo, getAccountId } = useCkChatStore(); const { login2 } = useUserStore(); useEffect(() => { - const contactList = chatInitAPIdata(); - console.log(contactList); + // 方法一:使用 Promise 链式调用处理异步函数 + chatInitAPIdata() + .then(contactList => { + console.log(contactList); + // 如果需要可以设置联系人列表 + setContacts(contactList); + }) + .catch(error => { + console.error("获取联系人列表失败:", error); + }); }, []); const getToken2 = () => { @@ -48,116 +53,6 @@ const CkboxPage: React.FC = () => { }); }; - const fetchContacts = async () => { - try { - setLoading(true); - // 使用API获取联系人数据 - const response = await getContactList({ prevId: 0, count: 500 }); - if (response) { - // 转换API返回的数据结构为组件所需的ContactData结构 - const contactList: ContactData[] = response.map((item: any) => ({ - id: item.id.toString(), - name: item.nickname || item.conRemark || item.alias || "", - phone: item.phone || "", - avatar: item.avatar || "", - online: true, // 假设所有联系人都在线,实际应根据API返回数据调整 - status: "在线", // 假设状态,实际应根据API返回数据调整 - department: "", // API中没有对应字段,可以根据需要添加 - position: "", // API中没有对应字段,可以根据需要添加 - })); - setContacts(contactList); - } - } catch (error) { - messageApi.error("获取联系人失败"); - console.error("获取联系人失败:", error); - } finally { - setLoading(false); - } - }; - - const fetchChatSessions = async () => { - try { - // 先确保联系人列表已加载 - if (contacts.length === 0) { - await fetchContacts(); - } - - const response = await getChatMessage({ - wechatAccountId: 32686452, // 使用实际的wechatAccountId - wechatFriendId: 0, // 可以设置为0获取所有好友的消息 - From: 0, - To: 0, - Count: 50, // 获取最近的50条消息 - olderData: false, - keyword: "", - }); - - console.log("聊天消息响应:", response); - - if (response && Array.isArray(response)) { - // 创建一个Map来存储每个好友ID对应的最新消息 - const friendMessageMap = new Map(); - - // 遍历所有消息,只保留每个好友的最新消息 - response.forEach(item => { - const friendId = item.wechatFriendId; - const existingMessage = friendMessageMap.get(friendId); - - // 如果Map中没有这个好友的消息,或者当前消息比已存在的更新,则更新Map - if ( - !existingMessage || - new Date(item.createTime) > new Date(existingMessage.createTime) - ) { - friendMessageMap.set(friendId, item); - } - }); - - // 将Map转换为数组 - const latestMessages = Array.from(friendMessageMap.values()); - - // 将API返回的消息记录转换为ChatSession格式 - const sessions: ChatSession[] = latestMessages.map(item => { - // 解析content字段,它是一个JSON字符串 - let msgContent = ""; - try { - const contentObj = JSON.parse(item.content); - msgContent = contentObj.content || ""; - } catch (e) { - msgContent = item.content; - } - - // 尝试从联系人列表中找到对应的联系人信息 - const contact = contacts.find( - c => c.id === item.wechatFriendId.toString(), - ); - - return { - id: item.id.toString(), - type: "private", // 假设都是私聊 - name: contact ? contact.name : `联系人 ${item.wechatFriendId}`, // 使用联系人名称或默认名称 - avatar: contact?.avatar || "", // 使用联系人头像或默认空字符串 - lastMessage: msgContent, - lastTime: - item.createTime || new Date(item.wechatTime).toISOString(), - unreadCount: 0, // 未读消息数需要另外获取 - online: contact?.online || false, // 使用联系人在线状态或默认为false - }; - }); - - // 按最后消息时间排序 - sessions.sort( - (a, b) => - new Date(b.lastTime).getTime() - new Date(a.lastTime).getTime(), - ); - - setChatSessions(sessions); - } - } catch (error) { - console.error("获取聊天记录失败:", error); - messageApi.error("获取聊天记录失败"); - } - }; - const handleContactClick = (contact: ContactData) => { // 查找或创建聊天会话 let session = chatSessions.find(s => s.id === contact.id); @@ -165,7 +60,7 @@ const CkboxPage: React.FC = () => { session = { id: contact.id, type: "private", - name: contact.name, + name: contact.nickname, avatar: contact.avatar, lastMessage: "", lastTime: dayjs().toISOString(), @@ -181,16 +76,6 @@ const CkboxPage: React.FC = () => { if (!currentChat || !message.trim()) return; try { - const newMessage: MessageData = { - id: Date.now().toString(), - senderId: "me", - senderName: "我", - content: message, - type: "text" as any, - timestamp: dayjs().toISOString(), - isRead: false, - }; - // 更新当前聊天会话 const updatedSession = { ...currentChat, diff --git a/Cunkebao/src/pages/pc/ckbox/main.ts b/Cunkebao/src/pages/pc/ckbox/main.ts index 986e5f6a..366f77b6 100644 --- a/Cunkebao/src/pages/pc/ckbox/main.ts +++ b/Cunkebao/src/pages/pc/ckbox/main.ts @@ -9,30 +9,35 @@ const { connect } = useWebSocketStore.getState(); const { setUserInfo, getAccountId } = useCkChatStore.getState(); //获取触客宝基础信息 export const chatInitAPIdata = async () => { - //获取Token - const Token = await getToken(); - //获取用户信息 - const userInfo = await getChuKeBaoUserInfo(); - setUserInfo(userInfo); + try { + //获取Token + const Token = await getToken(); + //获取用户信息 + const userInfo = await getChuKeBaoUserInfo(); + setUserInfo(userInfo); - //获取用户账号Id - const accountId = getAccountId(); + //获取用户账号Id + const accountId = getAccountId(); - //发起链接 - connect({ - accessToken: String(Token), - accountId: accountId, - client: "kefu-client", - cmdType: "CmdSignIn", - seq: 1, - }); - //获取联系人列表 - const contactList = await getContactList({ - prevId: userInfo.tenant.tenantType, - count: 100, - }); + //发起链接 + connect({ + accessToken: String(Token), + accountId: accountId, + client: "kefu-client", + cmdType: "CmdSignIn", + seq: 1, + }); + //获取联系人列表 + const contactList = await getContactList({ + prevId: userInfo.tenant.tenantType, + count: 100, + }); - return contactList; + return contactList; + } catch (error) { + console.error("获取联系人列表失败:", error); + return []; + } }; export const getChatInfo = () => { diff --git a/Cunkebao/src/store/module/websocket.ts b/Cunkebao/src/store/module/websocket.ts index a000f1a3..2d330f66 100644 --- a/Cunkebao/src/store/module/websocket.ts +++ b/Cunkebao/src/store/module/websocket.ts @@ -114,8 +114,6 @@ export const useWebSocketStore = createPersistStore( return; } - console.log("获取connect参数", getAccountId()); - // 构建WebSocket URL const params = new URLSearchParams({ client: fullConfig.client.toString(),