diff --git a/components/SmartChatBox/useMessages.ts b/components/SmartChatBox/useMessages.ts index e0068f3..cbc4760 100644 --- a/components/SmartChatBox/useMessages.ts +++ b/components/SmartChatBox/useMessages.ts @@ -30,6 +30,21 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me const timeoutIdRef = useRef(null); const isViewingHistoryRef = useRef(false); const prevTotalCountRef = useRef(totalCount); + const isPollingRef = useRef(false); + + // 合并和去重消息 + const mergeMessages = useCallback((oldMessages: ChatMessage[], newMessages: ChatMessage[]) => { + const messageMap = new Map(); + + // 使用 Map 自动去重,后面的会覆盖前面的 + [...oldMessages, ...newMessages].forEach(msg => { + messageMap.set(msg.id, msg); + }); + + // 转回数组并按 id 排序 + return Array.from(messageMap.values()) + .sort((a, b) => Number(a.id) - Number(b.id)); + }, []); // 更新 config 引用 useEffect(() => { @@ -46,7 +61,7 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me }, [totalCount, onMessagesUpdate]); // 获取最新消息 - const fetchLatestMessages = useCallback(async (showLoading: boolean = false) => { + const updateMessages = useCallback(async (showLoading: boolean = false) => { try { if (showLoading) { setIsLoading(true); @@ -79,7 +94,9 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me setIsLoading(true); const response = await fetchMessages(configRef.current, offset, PAGE_SIZE); - setDisplayMessages(prev => [...response.messages, ...prev]); + + // 合并并去重消息 + setDisplayMessages(prev => mergeMessages(prev, response.messages)); setHasMore(response.hasMore); setOffset(prev => prev + PAGE_SIZE); setTotalCount(response.totalCount); @@ -89,7 +106,7 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me } finally { setIsLoading(false); } - }, [offset, hasMore, isLoading]); + }, [offset, hasMore, isLoading, mergeMessages]); // 返回最新消息 const backToLatest = useCallback(async () => { @@ -116,20 +133,20 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me // 无论是否在查看历史,发送消息后都切换到最新视图 isViewingHistoryRef.current = false; - setDisplayMessages(prev => [...prev, userMessage]); + setDisplayMessages(prev => mergeMessages(prev, [userMessage])); // 发送到服务器 await sendMessage(blocks, configRef.current); // 立即获取最新的消息列表 - await fetchLatestMessages(false); + await updateMessages(false); } catch (err) { console.error("发送消息失败:", err); setError(err instanceof Error ? err : new Error("发送消息失败")); } finally { setIsLoading(false); } - }, [fetchLatestMessages]); + }, [updateMessages, mergeMessages]); // 重试消息 const handleRetryMessage = useCallback(async (messageId: string) => { @@ -140,14 +157,14 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me // 重试时切换到最新视图 isViewingHistoryRef.current = false; await retryMessage(messageId, configRef.current); - await fetchLatestMessages(false); + await updateMessages(false); } catch (err) { console.error("重试消息失败:", err); setError(err instanceof Error ? err : new Error("重试消息失败")); } finally { setIsLoading(false); } - }, [fetchLatestMessages]); + }, [updateMessages]); // 清空消息 const handleClearMessages = useCallback(() => { @@ -168,8 +185,17 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me if (!systemPush) return; const poll = async () => { - await fetchLatestMessages(false); - timeoutIdRef.current = setTimeout(poll, POLLING_INTERVAL); + if (isPollingRef.current) return; + + try { + isPollingRef.current = true; + await updateMessages(false); + } finally { + isPollingRef.current = false; + if (systemPush) { + timeoutIdRef.current = setTimeout(poll, POLLING_INTERVAL); + } + } }; poll(); @@ -179,15 +205,15 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me clearTimeout(timeoutIdRef.current); } }; - }, [systemPush, fetchLatestMessages]); + }, [systemPush, updateMessages]); // 初始加载 useEffect(() => { if (isInitialLoadRef.current) { isInitialLoadRef.current = false; - fetchLatestMessages(true); + updateMessages(true); } - }, [fetchLatestMessages]); + }, [updateMessages]); return [ {