forked from 77media/video-flow
chatbox--修复重复消息
This commit is contained in:
parent
55b5e6e570
commit
65c21e1c40
@ -30,6 +30,21 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me
|
|||||||
const timeoutIdRef = useRef<NodeJS.Timeout | null>(null);
|
const timeoutIdRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
const isViewingHistoryRef = useRef(false);
|
const isViewingHistoryRef = useRef(false);
|
||||||
const prevTotalCountRef = useRef(totalCount);
|
const prevTotalCountRef = useRef(totalCount);
|
||||||
|
const isPollingRef = useRef(false);
|
||||||
|
|
||||||
|
// 合并和去重消息
|
||||||
|
const mergeMessages = useCallback((oldMessages: ChatMessage[], newMessages: ChatMessage[]) => {
|
||||||
|
const messageMap = new Map<string, ChatMessage>();
|
||||||
|
|
||||||
|
// 使用 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 引用
|
// 更新 config 引用
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -46,7 +61,7 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me
|
|||||||
}, [totalCount, onMessagesUpdate]);
|
}, [totalCount, onMessagesUpdate]);
|
||||||
|
|
||||||
// 获取最新消息
|
// 获取最新消息
|
||||||
const fetchLatestMessages = useCallback(async (showLoading: boolean = false) => {
|
const updateMessages = useCallback(async (showLoading: boolean = false) => {
|
||||||
try {
|
try {
|
||||||
if (showLoading) {
|
if (showLoading) {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
@ -79,7 +94,9 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me
|
|||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
const response = await fetchMessages(configRef.current, offset, PAGE_SIZE);
|
const response = await fetchMessages(configRef.current, offset, PAGE_SIZE);
|
||||||
setDisplayMessages(prev => [...response.messages, ...prev]);
|
|
||||||
|
// 合并并去重消息
|
||||||
|
setDisplayMessages(prev => mergeMessages(prev, response.messages));
|
||||||
setHasMore(response.hasMore);
|
setHasMore(response.hasMore);
|
||||||
setOffset(prev => prev + PAGE_SIZE);
|
setOffset(prev => prev + PAGE_SIZE);
|
||||||
setTotalCount(response.totalCount);
|
setTotalCount(response.totalCount);
|
||||||
@ -89,7 +106,7 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me
|
|||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
}, [offset, hasMore, isLoading]);
|
}, [offset, hasMore, isLoading, mergeMessages]);
|
||||||
|
|
||||||
// 返回最新消息
|
// 返回最新消息
|
||||||
const backToLatest = useCallback(async () => {
|
const backToLatest = useCallback(async () => {
|
||||||
@ -116,20 +133,20 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me
|
|||||||
|
|
||||||
// 无论是否在查看历史,发送消息后都切换到最新视图
|
// 无论是否在查看历史,发送消息后都切换到最新视图
|
||||||
isViewingHistoryRef.current = false;
|
isViewingHistoryRef.current = false;
|
||||||
setDisplayMessages(prev => [...prev, userMessage]);
|
setDisplayMessages(prev => mergeMessages(prev, [userMessage]));
|
||||||
|
|
||||||
// 发送到服务器
|
// 发送到服务器
|
||||||
await sendMessage(blocks, configRef.current);
|
await sendMessage(blocks, configRef.current);
|
||||||
|
|
||||||
// 立即获取最新的消息列表
|
// 立即获取最新的消息列表
|
||||||
await fetchLatestMessages(false);
|
await updateMessages(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("发送消息失败:", err);
|
console.error("发送消息失败:", err);
|
||||||
setError(err instanceof Error ? err : new Error("发送消息失败"));
|
setError(err instanceof Error ? err : new Error("发送消息失败"));
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
}, [fetchLatestMessages]);
|
}, [updateMessages, mergeMessages]);
|
||||||
|
|
||||||
// 重试消息
|
// 重试消息
|
||||||
const handleRetryMessage = useCallback(async (messageId: string) => {
|
const handleRetryMessage = useCallback(async (messageId: string) => {
|
||||||
@ -140,14 +157,14 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me
|
|||||||
// 重试时切换到最新视图
|
// 重试时切换到最新视图
|
||||||
isViewingHistoryRef.current = false;
|
isViewingHistoryRef.current = false;
|
||||||
await retryMessage(messageId, configRef.current);
|
await retryMessage(messageId, configRef.current);
|
||||||
await fetchLatestMessages(false);
|
await updateMessages(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("重试消息失败:", err);
|
console.error("重试消息失败:", err);
|
||||||
setError(err instanceof Error ? err : new Error("重试消息失败"));
|
setError(err instanceof Error ? err : new Error("重试消息失败"));
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
}, [fetchLatestMessages]);
|
}, [updateMessages]);
|
||||||
|
|
||||||
// 清空消息
|
// 清空消息
|
||||||
const handleClearMessages = useCallback(() => {
|
const handleClearMessages = useCallback(() => {
|
||||||
@ -168,8 +185,17 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me
|
|||||||
if (!systemPush) return;
|
if (!systemPush) return;
|
||||||
|
|
||||||
const poll = async () => {
|
const poll = async () => {
|
||||||
await fetchLatestMessages(false);
|
if (isPollingRef.current) return;
|
||||||
timeoutIdRef.current = setTimeout(poll, POLLING_INTERVAL);
|
|
||||||
|
try {
|
||||||
|
isPollingRef.current = true;
|
||||||
|
await updateMessages(false);
|
||||||
|
} finally {
|
||||||
|
isPollingRef.current = false;
|
||||||
|
if (systemPush) {
|
||||||
|
timeoutIdRef.current = setTimeout(poll, POLLING_INTERVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
poll();
|
poll();
|
||||||
@ -179,15 +205,15 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me
|
|||||||
clearTimeout(timeoutIdRef.current);
|
clearTimeout(timeoutIdRef.current);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [systemPush, fetchLatestMessages]);
|
}, [systemPush, updateMessages]);
|
||||||
|
|
||||||
// 初始加载
|
// 初始加载
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isInitialLoadRef.current) {
|
if (isInitialLoadRef.current) {
|
||||||
isInitialLoadRef.current = false;
|
isInitialLoadRef.current = false;
|
||||||
fetchLatestMessages(true);
|
updateMessages(true);
|
||||||
}
|
}
|
||||||
}, [fetchLatestMessages]);
|
}, [updateMessages]);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user