import { useMemo } from 'react'; import { useLoadMoreInfinite, createKey } from '@/utils/loadMoreInfinite'; import { getMessageHistories } from '@/service/chat'; import { useTextChat } from '@/store/textChatStore'; import { formatMessageItem } from '@/utils/messageUtils'; import { TMessage, TRobotMessage, TAnyMessage } from '@/types/bot'; /** * 聊天消息管理 Hook * 负责处理消息历史记录获取、消息分组和格式化 */ export const useChatMessages = (agentId: string, isVisitor?: string): { historyList: TAnyMessage[]; messageList: TAnyMessage[]; parsedList: TAnyMessage[]; groupedMessages: { dt: string; list: TAnyMessage[] }[]; messagesLength: number; loadMore: () => void; pageIndex: number; mutate: (data: any, params: any) => void; } => { const messageList = useTextChat((state) => state.list); // 获取历史聊天记录的 fetcher 函数 const fetcher = async ([_url, { nextId, pageSize }]) => { const _nextId = nextId ? decodeURIComponent(nextId) : nextId; const res = await getMessageHistories({ agentId, startId: _nextId, pageSize, }); return res.data; }; // 使用无限滚动加载历史消息 const { list, loadMore, pageIndex, mutate } = useLoadMoreInfinite< TMessage[] | TRobotMessage[] >(createKey(`messeagehistories${isVisitor}${agentId}`), fetcher, { revalidateOnMount: false }); // 解析消息体 content,并展平数组 const parsedList = list .flat() .filter((item) => !!item.content.length) .map(formatMessageItem); // 按 sessionId 分组消息,并记录每组的最早时间 // 最后返回数组,以按组显示聊天记录时间 隔开每一组聊天记录 const groupedMessages = useMemo(() => { const allMessages = [...[...parsedList].reverse(), ...messageList]; const resultMap = allMessages.reduce((acc, item) => { const { sessionId, msgTime } = item; if (!sessionId || !msgTime) { return acc; } let _msgTime = msgTime.replace(/\-/g, "/"); if (!acc[sessionId]) { acc[sessionId] = { dt: _msgTime, // 初始化当前组的最早时间 list: [item], // 初始化当前组的记录列表 }; } else { // 更新最早时间(如果当前记录的 msgTime 更早) if (new Date(_msgTime) < new Date(acc[sessionId].dt)) { acc[sessionId].dt = msgTime; } // 将记录添加到当前组 acc[sessionId].list.push(item); } return acc; }, {} as Record); // 转换为最终数组格式 return Object.values(resultMap); }, [parsedList, messageList]); // 消息总长度(用于触发滚动等副作用) const messagesLength = useMemo(() => groupedMessages.length, [groupedMessages.length]); return { // 原始数据(保持原始结构供其他用途) historyList: parsedList, // 已经展平的消息列表 messageList, parsedList, // 处理后的数据 groupedMessages, messagesLength, // 操作方法 loadMore, pageIndex, mutate, }; };