From 3f9bb220975292c033db35f8caea7e9e1b9500d8 Mon Sep 17 00:00:00 2001 From: oudecheng <13802883547@139.com> Date: Mon, 8 Jun 2026 14:43:47 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20favicon.svg=20?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=B9=B6=E5=9C=A8=20index.html=20=E4=B8=AD?= =?UTF-8?q?=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/index.html | 1 + web/public/favicon.svg | 3 ++ web/src/components/Chat/MessageList.tsx | 38 ++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 web/public/favicon.svg diff --git a/web/index.html b/web/index.html index 78b3465..c596841 100644 --- a/web/index.html +++ b/web/index.html @@ -4,6 +4,7 @@ PicoBot +
diff --git a/web/public/favicon.svg b/web/public/favicon.svg new file mode 100644 index 0000000..db7bc7a --- /dev/null +++ b/web/public/favicon.svg @@ -0,0 +1,3 @@ + + + diff --git a/web/src/components/Chat/MessageList.tsx b/web/src/components/Chat/MessageList.tsx index 3f5ddb4..fcef3f3 100644 --- a/web/src/components/Chat/MessageList.tsx +++ b/web/src/components/Chat/MessageList.tsx @@ -15,6 +15,8 @@ export function MessageList({ messages, onNavigateToSubAgent }: MessageListProps const prevShowBottomRef = useRef(false) const prevShowTopRef = useRef(false) const lastMessageCountRef = useRef(0) + const prevMessageCountRef = useRef(0) + const stickyLockUntilRef = useRef(0) const isProgrammaticScrollRef = useRef(false) const scrollTimerRef = useRef(0) @@ -28,6 +30,12 @@ export function MessageList({ messages, onNavigateToSubAgent }: MessageListProps const el = containerRef.current if (!el) return + // sticky lock 期间:防止中间 DOM 状态的 scroll 事件打断历史加载 + if (Date.now() < stickyLockUntilRef.current) { + isStickyRef.current = true + return + } + const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight const nearBottom = distanceFromBottom < 120 @@ -81,13 +89,31 @@ export function MessageList({ messages, onNavigateToSubAgent }: MessageListProps // ---- auto-scroll effect ---- useEffect(() => { - if (messages.length === 0) return + // 消息清空 → 重置所有追踪状态(话题/会话切换) + if (messages.length === 0) { + prevMessageCountRef.current = 0 + lastMessageCountRef.current = 0 + isStickyRef.current = true + return + } const lastMessage = messages[messages.length - 1] + const isFreshLoad = prevMessageCountRef.current === 0 && messages.length > 0 // 用户自己发的消息 → 始终滚到底部 if (lastMessage.role === 'user') { scrollToBottom('instant') + prevMessageCountRef.current = messages.length + return + } + + // 新加载(话题切换后首次收到消息)→ 强制滚到底部 + if (isFreshLoad) { + isStickyRef.current = true + lastMessageCountRef.current = 0 + stickyLockUntilRef.current = Date.now() + 1500 + scrollToBottom('instant') + prevMessageCountRef.current = messages.length return } @@ -102,6 +128,7 @@ export function MessageList({ messages, onNavigateToSubAgent }: MessageListProps } lastMessageCountRef.current = messages.length + prevMessageCountRef.current = messages.length }, [messages, scrollToBottom]) // ---- ResizeObserver: 窗口大小变化时保持底部对齐 ---- @@ -119,6 +146,15 @@ export function MessageList({ messages, onNavigateToSubAgent }: MessageListProps return () => observer.disconnect() }, []) + // ---- 组件挂载时滚动到底部 ---- + + useEffect(() => { + if (messages.length > 0) { + scrollToBottom('instant') + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + // ---- 清理定时器 ---- useEffect(() => {