Fix: Fixed the issue where the agent's chat box could not automatically scroll to the bottom #3221 (#9219)

### What problem does this PR solve?

Fix: Fixed the issue where the agent's chat box could not automatically
scroll to the bottom #3221

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
balibabu
2025-08-05 09:26:15 +08:00
committed by GitHub
parent 9db999ccae
commit dda5a0080a
6 changed files with 44 additions and 27 deletions

View File

@ -353,7 +353,12 @@ export const useHandleMessageInputChange = () => {
export const useSelectDerivedMessages = () => { export const useSelectDerivedMessages = () => {
const [derivedMessages, setDerivedMessages] = useState<IMessage[]>([]); const [derivedMessages, setDerivedMessages] = useState<IMessage[]>([]);
const ref = useScrollToBottom(derivedMessages); const messageContainerRef = useRef<HTMLDivElement>(null);
const { scrollRef, scrollToBottom } = useScrollToBottom(
derivedMessages,
messageContainerRef,
);
const addNewestQuestion = useCallback( const addNewestQuestion = useCallback(
(message: Message, answer: string = '') => { (message: Message, answer: string = '') => {
@ -492,7 +497,8 @@ export const useSelectDerivedMessages = () => {
}, [setDerivedMessages]); }, [setDerivedMessages]);
return { return {
ref, scrollRef,
messageContainerRef,
derivedMessages, derivedMessages,
setDerivedMessages, setDerivedMessages,
addNewestQuestion, addNewestQuestion,
@ -503,6 +509,7 @@ export const useSelectDerivedMessages = () => {
addNewestOneAnswer, addNewestOneAnswer,
removeMessagesAfterCurrentMessage, removeMessagesAfterCurrentMessage,
removeAllMessages, removeAllMessages,
scrollToBottom,
}; };
}; };

View File

@ -22,7 +22,8 @@ import { useAwaitCompentData } from '../hooks/use-chat-logic';
function AgentChatBox() { function AgentChatBox() {
const { const {
value, value,
ref, scrollRef,
messageContainerRef,
sendLoading, sendLoading,
derivedMessages, derivedMessages,
handleInputChange, handleInputChange,
@ -59,7 +60,7 @@ function AgentChatBox() {
return ( return (
<> <>
<section className="flex flex-1 flex-col px-5 h-[90vh]"> <section className="flex flex-1 flex-col px-5 h-[90vh]">
<div className="flex-1 overflow-auto"> <div className="flex-1 overflow-auto" ref={messageContainerRef}>
<div> <div>
{/* <Spin spinning={sendLoading}> */} {/* <Spin spinning={sendLoading}> */}
{derivedMessages?.map((message, i) => { {derivedMessages?.map((message, i) => {
@ -106,7 +107,7 @@ function AgentChatBox() {
})} })}
{/* </Spin> */} {/* </Spin> */}
</div> </div>
<div ref={ref.scrollRef} /> <div ref={scrollRef} />
</div> </div>
<NextMessageInput <NextMessageInput
value={value} value={value}

View File

@ -198,12 +198,14 @@ export const useSendAgentMessage = (
const prologue = useGetBeginNodePrologue(); const prologue = useGetBeginNodePrologue();
const { const {
derivedMessages, derivedMessages,
ref, scrollRef,
messageContainerRef,
removeLatestMessage, removeLatestMessage,
removeMessageById, removeMessageById,
addNewestOneQuestion, addNewestOneQuestion,
addNewestOneAnswer, addNewestOneAnswer,
removeAllMessages, removeAllMessages,
scrollToBottom,
} = useSelectDerivedMessages(); } = useSelectDerivedMessages();
const { addEventList: addEventListFun } = useContext(AgentChatLogContext); const { addEventList: addEventListFun } = useContext(AgentChatLogContext);
const { const {
@ -303,7 +305,18 @@ export const useSendAgentMessage = (
}); });
} }
addNewestOneQuestion({ ...msgBody, files: fileList }); addNewestOneQuestion({ ...msgBody, files: fileList });
}, [value, done, addNewestOneQuestion, fileList, setValue, sendMessage]); setTimeout(() => {
scrollToBottom();
}, 100);
}, [
value,
done,
addNewestOneQuestion,
fileList,
setValue,
sendMessage,
scrollToBottom,
]);
useEffect(() => { useEffect(() => {
const { content, id } = findMessageFromList(answerList); const { content, id } = findMessageFromList(answerList);
@ -337,7 +350,8 @@ export const useSendAgentMessage = (
value, value,
sendLoading: !done, sendLoading: !done,
derivedMessages, derivedMessages,
ref, scrollRef,
messageContainerRef,
handlePressEnter, handlePressEnter,
handleInputChange, handleInputChange,
removeMessageById, removeMessageById,

View File

@ -1,7 +1,6 @@
import MessageItem from '@/components/message-item'; import MessageItem from '@/components/message-item';
import { MessageType } from '@/constants/chat'; import { MessageType } from '@/constants/chat';
import { Flex, Spin } from 'antd'; import { Flex, Spin } from 'antd';
import { useRef } from 'react';
import { import {
useCreateConversationBeforeUploadDocument, useCreateConversationBeforeUploadDocument,
useGetFileIcon, useGetFileIcon,
@ -19,7 +18,6 @@ import {
useFetchNextDialog, useFetchNextDialog,
useGetChatSearchParams, useGetChatSearchParams,
} from '@/hooks/chat-hooks'; } from '@/hooks/chat-hooks';
import { useScrollToBottom } from '@/hooks/logic-hooks';
import { useFetchUserInfo } from '@/hooks/user-setting-hooks'; import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
import { buildMessageUuidWithRole } from '@/utils/chat'; import { buildMessageUuidWithRole } from '@/utils/chat';
import { memo } from 'react'; import { memo } from 'react';
@ -34,10 +32,10 @@ const ChatContainer = ({ controller }: IProps) => {
const { data: conversation } = useFetchNextConversation(); const { data: conversation } = useFetchNextConversation();
const { data: currentDialog } = useFetchNextDialog(); const { data: currentDialog } = useFetchNextDialog();
const messageContainerRef = useRef<HTMLDivElement>(null);
const { const {
value, value,
ref, scrollRef,
messageContainerRef,
loading, loading,
sendLoading, sendLoading,
derivedMessages, derivedMessages,
@ -47,10 +45,6 @@ const ChatContainer = ({ controller }: IProps) => {
removeMessageById, removeMessageById,
stopOutputMessage, stopOutputMessage,
} = useSendNextMessage(controller); } = useSendNextMessage(controller);
const { scrollRef, isAtBottom, scrollToBottom } = useScrollToBottom(
derivedMessages,
messageContainerRef,
);
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } = const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
useClickDrawer(); useClickDrawer();
@ -61,11 +55,6 @@ const ChatContainer = ({ controller }: IProps) => {
const { createConversationBeforeUploadDocument } = const { createConversationBeforeUploadDocument } =
useCreateConversationBeforeUploadDocument(); useCreateConversationBeforeUploadDocument();
const handleSend = (msg) => {
// your send logic
setTimeout(scrollToBottom, 0);
};
return ( return (
<> <>
<Flex flex={1} className={styles.chatContainer} vertical> <Flex flex={1} className={styles.chatContainer} vertical>

View File

@ -291,7 +291,8 @@ export const useSetConversation = () => {
export const useSelectNextMessages = () => { export const useSelectNextMessages = () => {
const { const {
ref, scrollRef,
messageContainerRef,
setDerivedMessages, setDerivedMessages,
derivedMessages, derivedMessages,
addNewestAnswer, addNewestAnswer,
@ -335,7 +336,8 @@ export const useSelectNextMessages = () => {
}, [conversation.message, conversationId, setDerivedMessages, isNew]); }, [conversation.message, conversationId, setDerivedMessages, isNew]);
return { return {
ref, scrollRef,
messageContainerRef,
derivedMessages, derivedMessages,
loading, loading,
addNewestAnswer, addNewestAnswer,
@ -371,7 +373,8 @@ export const useSendNextMessage = (controller: AbortController) => {
api.completeConversation, api.completeConversation,
); );
const { const {
ref, scrollRef,
messageContainerRef,
derivedMessages, derivedMessages,
loading, loading,
addNewestAnswer, addNewestAnswer,
@ -499,7 +502,8 @@ export const useSendNextMessage = (controller: AbortController) => {
regenerateMessage, regenerateMessage,
sendLoading: !done, sendLoading: !done,
loading, loading,
ref, scrollRef,
messageContainerRef,
derivedMessages, derivedMessages,
removeMessageById, removeMessageById,
stopOutputMessage, stopOutputMessage,

View File

@ -50,7 +50,8 @@ const ChatContainer = () => {
handleInputChange, handleInputChange,
value, value,
sendLoading, sendLoading,
ref, scrollRef,
messageContainerRef,
derivedMessages, derivedMessages,
hasError, hasError,
stopOutputMessage, stopOutputMessage,
@ -149,6 +150,7 @@ const ChatContainer = () => {
className={cn( className={cn(
'flex flex-1 flex-col overflow-auto scrollbar-auto m-auto w-5/6', 'flex flex-1 flex-col overflow-auto scrollbar-auto m-auto w-5/6',
)} )}
ref={messageContainerRef}
> >
<div> <div>
{derivedMessages?.map((message, i) => { {derivedMessages?.map((message, i) => {
@ -203,7 +205,7 @@ const ChatContainer = () => {
); );
})} })}
</div> </div>
<div ref={ref.scrollRef} /> <div ref={scrollRef} />
</div> </div>
<div className="flex w-full justify-center mb-8"> <div className="flex w-full justify-center mb-8">
<div className="w-5/6"> <div className="w-5/6">