增强SidebarMenu和MessageList组件,新增对currentContact变化的监听,自动切换聊天tab,优化联系人点击处理逻辑,调整置顶标识为数字类型,提升代码可读性和用户体验。
This commit is contained in:
@@ -37,9 +37,15 @@ const CustomerList: React.FC = () => {
|
||||
const session = chatSessions.filter(
|
||||
v => v.wechatAccountId === customerId,
|
||||
);
|
||||
return session.reduce((pre, cur) => pre + cur.config.unreadCount, 0);
|
||||
return session.reduce(
|
||||
(pre, cur) => pre + (cur.config.unreadCount || 0),
|
||||
0,
|
||||
);
|
||||
} else {
|
||||
return chatSessions.reduce((pre, cur) => pre + cur.config.unreadCount, 0);
|
||||
return chatSessions.reduce(
|
||||
(pre, cur) => pre + (cur.config?.unreadCount || 0),
|
||||
0,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ interface MessageListProps {}
|
||||
|
||||
const MessageList: React.FC<MessageListProps> = () => {
|
||||
const searchKeyword = useContactStore(state => state.searchKeyword);
|
||||
const selectedContact = useContactStore(state => state.currentContact);
|
||||
const { setCurrentContact, currentContract } = useWeChatStore();
|
||||
const { currentCustomer } = useCustomerStore();
|
||||
const { sendCommand } = useWebSocketStore();
|
||||
@@ -94,8 +95,8 @@ const MessageList: React.FC<MessageListProps> = () => {
|
||||
|
||||
// 置顶/取消置顶
|
||||
const handleTogglePin = async (session: ChatSession) => {
|
||||
const currentPinned = session.config?.top || false;
|
||||
const newPinned = !currentPinned;
|
||||
const currentPinned = session.config?.top || 0;
|
||||
const newPinned = currentPinned === 1 ? 0 : 1;
|
||||
|
||||
try {
|
||||
// 1. 立即更新UI并重新排序(乐观更新)
|
||||
@@ -132,7 +133,7 @@ const MessageList: React.FC<MessageListProps> = () => {
|
||||
newPinned,
|
||||
);
|
||||
|
||||
message.success(`${newPinned ? "置顶" : "取消置顶"}成功`);
|
||||
message.success(`${newPinned === 1 ? "置顶" : "取消置顶"}成功`);
|
||||
} catch (error) {
|
||||
// 4. 失败时回滚UI
|
||||
setSessions(prev =>
|
||||
@@ -434,6 +435,33 @@ const MessageList: React.FC<MessageListProps> = () => {
|
||||
setFilteredSessions(filtered);
|
||||
}, [sessions, currentCustomer, searchKeyword]);
|
||||
|
||||
// ==================== 监听联系人选中 ====================
|
||||
|
||||
// 监听 contacts store 中的 currentContact 变化
|
||||
useEffect(() => {
|
||||
if (!selectedContact || !currentUserId) return;
|
||||
|
||||
const handleContactSelection = async () => {
|
||||
try {
|
||||
// 从数据库中查找该联系人对应的会话
|
||||
const session = await MessageManager.getSessionByContactId(
|
||||
currentUserId,
|
||||
selectedContact.id,
|
||||
selectedContact.type,
|
||||
);
|
||||
|
||||
if (session) {
|
||||
// 直接选中该会话
|
||||
setCurrentContact(session as any, true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("处理联系人选中失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
handleContactSelection();
|
||||
}, [selectedContact, currentUserId, setCurrentContact]);
|
||||
|
||||
// ==================== WebSocket消息处理 ====================
|
||||
|
||||
// 监听WebSocket消息更新
|
||||
@@ -482,7 +510,7 @@ const MessageList: React.FC<MessageListProps> = () => {
|
||||
lastUpdateTime: new Date().toISOString(),
|
||||
config: {
|
||||
unreadCount: 1,
|
||||
top: false,
|
||||
top: 0,
|
||||
},
|
||||
sortKey: "",
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React, { useState, useCallback, useEffect } from "react";
|
||||
import { List, Avatar, Skeleton, Collapse } from "antd";
|
||||
import type { CollapseProps } from "antd";
|
||||
import dayjs from "dayjs";
|
||||
import styles from "./com.module.scss";
|
||||
import { Contact } from "@/utils/db";
|
||||
import { ContactManager } from "@/utils/dbAction";
|
||||
import { Contact, ChatSession } from "@/utils/db";
|
||||
import { ContactManager, MessageManager } from "@/utils/dbAction";
|
||||
import { ContactGroupByLabel } from "@/pages/pc/ckbox/data";
|
||||
import { useContactStore } from "@weChatStore/contacts";
|
||||
import { useWeChatStore } from "@weChatStore/weChat";
|
||||
import { useCustomerStore } from "@weChatStore/customer";
|
||||
import { useUserStore } from "@storeModule/user";
|
||||
import {
|
||||
@@ -47,7 +47,6 @@ const ContactListSimple: React.FC<WechatFriendsProps> = ({
|
||||
// 获取用户和客服信息
|
||||
const currentUser = useUserStore(state => state.user);
|
||||
const currentCustomer = useCustomerStore(state => state.currentCustomer);
|
||||
const { setCurrentContact: setWeChatCurrentContact } = useWeChatStore();
|
||||
|
||||
// 从服务器同步数据(静默同步,不显示提示)
|
||||
const syncWithServer = useCallback(
|
||||
@@ -244,13 +243,64 @@ const ContactListSimple: React.FC<WechatFriendsProps> = ({
|
||||
);
|
||||
|
||||
// 联系人点击处理
|
||||
const onContactClick = (contact: Contact) => {
|
||||
setCurrentContact(contact);
|
||||
// 这里需要将 Contact 转换为 weChat 需要的格式
|
||||
// 暂时使用 any 类型,后续需要完善转换逻辑
|
||||
setWeChatCurrentContact(contact as any);
|
||||
};
|
||||
const onContactClick = async (contact: Contact) => {
|
||||
if (!currentUser?.id) return;
|
||||
|
||||
try {
|
||||
// 1. 查询数据库是否存在该联系人的会话
|
||||
const existingSession = await MessageManager.getSessionByContactId(
|
||||
currentUser.id,
|
||||
contact.id,
|
||||
contact.type,
|
||||
);
|
||||
|
||||
const currentTime = dayjs().format(); // 当前时间
|
||||
|
||||
if (!existingSession) {
|
||||
// === 场景1:会话不存在,创建新会话并插入数据库 ===
|
||||
|
||||
const newSession: ChatSession = {
|
||||
serverId: `${contact.type}_${contact.id}`,
|
||||
userId: currentUser.id,
|
||||
id: contact.id,
|
||||
type: contact.type,
|
||||
wechatAccountId: contact.wechatAccountId,
|
||||
nickname: contact.nickname,
|
||||
conRemark: contact.conRemark || "",
|
||||
avatar: contact.avatar,
|
||||
content: "",
|
||||
lastUpdateTime: currentTime, // 使用当前时间
|
||||
config: {
|
||||
unreadCount: 0,
|
||||
top: contact.config?.top === true ? 1 : 0, // boolean → number
|
||||
},
|
||||
sortKey: "",
|
||||
wechatId: contact.wechatId,
|
||||
};
|
||||
|
||||
// 插入数据库(等待完成)
|
||||
await MessageManager.createSession(currentUser.id, newSession);
|
||||
console.log(`创建新会话: ${contact.nickname || contact.wechatId}`);
|
||||
} else {
|
||||
// === 场景2:会话已存在,更新 lastUpdateTime ===
|
||||
|
||||
await MessageManager.updateSessionTime(
|
||||
currentUser.id,
|
||||
contact.id,
|
||||
contact.type,
|
||||
currentTime, // 更新为当前时间
|
||||
);
|
||||
console.log(
|
||||
`更新会话时间: ${contact.nickname || contact.wechatId} -> ${currentTime}`,
|
||||
);
|
||||
}
|
||||
|
||||
// 3. 数据库操作完成后,触发 UI 更新
|
||||
setCurrentContact(contact);
|
||||
} catch (error) {
|
||||
console.error("处理联系人点击失败:", error);
|
||||
}
|
||||
};
|
||||
// 渲染联系人项
|
||||
const renderContactItem = (contact: Contact) => {
|
||||
// 判断是否为群组
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Input, Skeleton } from "antd";
|
||||
import { SearchOutlined } from "@ant-design/icons";
|
||||
import WechatFriends from "./WechatFriends";
|
||||
@@ -12,12 +12,23 @@ interface SidebarMenuProps {
|
||||
}
|
||||
|
||||
const SidebarMenu: React.FC<SidebarMenuProps> = ({ loading = false }) => {
|
||||
const { searchKeyword, setSearchKeyword, clearSearchKeyword } =
|
||||
useContactStore();
|
||||
const {
|
||||
searchKeyword,
|
||||
setSearchKeyword,
|
||||
clearSearchKeyword,
|
||||
currentContact,
|
||||
} = useContactStore();
|
||||
const currentCustomer = useCustomerStore(state => state.currentCustomer);
|
||||
|
||||
const [activeTab, setActiveTab] = useState("chats");
|
||||
|
||||
// 监听 currentContact 变化,自动切换到聊天tab
|
||||
useEffect(() => {
|
||||
if (currentContact !== null) {
|
||||
setActiveTab("chats");
|
||||
}
|
||||
}, [currentContact]);
|
||||
|
||||
const handleSearch = (value: string) => {
|
||||
setSearchKeyword(value);
|
||||
};
|
||||
|
||||
@@ -49,7 +49,7 @@ export interface ChatSession {
|
||||
lastUpdateTime: string; // 最后更新时间
|
||||
config: {
|
||||
unreadCount: number; // 未读数量
|
||||
top: boolean; // 是否置顶
|
||||
top: number; // 是否置顶(1=置顶,0=非置顶)
|
||||
};
|
||||
sortKey: string; // 预计算排序键
|
||||
|
||||
|
||||
@@ -538,7 +538,7 @@ export class MessageManager {
|
||||
userId: number,
|
||||
sessionId: number,
|
||||
type: "friend" | "group",
|
||||
isPinned: boolean,
|
||||
isPinned: number,
|
||||
): Promise<void> {
|
||||
try {
|
||||
const serverId = `${type}_${sessionId}`;
|
||||
@@ -566,6 +566,43 @@ export class MessageManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新会话时间(用于联系人点击时更新)
|
||||
* @param userId 用户ID
|
||||
* @param sessionId 会话ID
|
||||
* @param type 会话类型
|
||||
* @param newTime 新的时间
|
||||
*/
|
||||
static async updateSessionTime(
|
||||
userId: number,
|
||||
sessionId: number,
|
||||
type: "friend" | "group",
|
||||
newTime: string,
|
||||
): Promise<void> {
|
||||
try {
|
||||
const serverId = `${type}_${sessionId}`;
|
||||
const session = (await chatSessionService.findByPrimaryKey(
|
||||
serverId,
|
||||
)) as ChatSession;
|
||||
|
||||
if (session) {
|
||||
const updatedSession = {
|
||||
...session,
|
||||
lastUpdateTime: newTime,
|
||||
};
|
||||
|
||||
// 重新生成 sortKey(因为时间变了,排序会改变)
|
||||
updatedSession.sortKey = this.generateSortKey(updatedSession);
|
||||
|
||||
await chatSessionService.update(serverId, updatedSession);
|
||||
console.log(`会话时间已更新: ${serverId} -> ${newTime}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("更新会话时间失败:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新会话备注
|
||||
* @param userId 用户ID
|
||||
@@ -690,4 +727,49 @@ export class MessageManager {
|
||||
console.error("清空用户会话失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据联系人ID获取会话
|
||||
* @param userId 用户ID
|
||||
* @param contactId 联系人ID
|
||||
* @param type 类型(friend/group)
|
||||
*/
|
||||
static async getSessionByContactId(
|
||||
userId: number,
|
||||
contactId: number,
|
||||
type: "friend" | "group",
|
||||
): Promise<ChatSession | null> {
|
||||
try {
|
||||
const serverId = `${type}_${contactId}`;
|
||||
const session = await chatSessionService.findByPrimaryKey(serverId);
|
||||
return session as ChatSession | null;
|
||||
} catch (error) {
|
||||
console.error("根据联系人ID获取会话失败:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新会话
|
||||
* @param userId 用户ID
|
||||
* @param session 会话数据
|
||||
*/
|
||||
static async createSession(
|
||||
userId: number,
|
||||
session: ChatSession,
|
||||
): Promise<void> {
|
||||
try {
|
||||
// 生成 sortKey
|
||||
const sessionWithSortKey = {
|
||||
...session,
|
||||
sortKey: this.generateSortKey(session),
|
||||
};
|
||||
|
||||
await chatSessionService.create(sessionWithSortKey);
|
||||
console.log(`创建新会话: ${session.nickname || session.wechatId}`);
|
||||
} catch (error) {
|
||||
console.error("创建会话失败:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user