From 31ea151bb296283f6b0672680d21eec7918c8827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=9D=E5=B0=98?= <237809796@qq.com> Date: Wed, 17 Jun 2026 02:04:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96:=20=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E8=A7=86=E8=A7=89=E5=8C=BA=E5=88=86(UX-01)+?= =?UTF-8?q?=E6=97=A7=E5=8D=A1=E8=87=AA=E5=8A=A8=E6=94=B6=E8=B5=B7=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA(UX-03)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AiChat.vue | 20 ++++++++- src/components/ToolCard.vue | 78 +++++++++++++++++++++++++++++++-- src/components/ToolCardList.vue | 30 +++++++++++-- src/i18n/en/ai.ts | 3 +- src/i18n/en/aiTool.ts | 3 ++ src/i18n/zh-CN/ai.ts | 3 +- src/i18n/zh-CN/aiTool.ts | 3 ++ 7 files changed, 129 insertions(+), 11 deletions(-) diff --git a/src/components/AiChat.vue b/src/components/AiChat.vue index ba4d2ab..91030f2 100644 --- a/src/components/AiChat.vue +++ b/src/components/AiChat.vue @@ -1743,6 +1743,10 @@ function isNearBottom(): boolean { // 回到底部按钮:内容溢出且不在底部时显示 const showBackToBottom = ref(false) +// UX-260616-03: 跟随阅读位置自动收起 —— 用户滚近底部(在读最新内容)时, +// 收起不再活跃的旧卡(视为已读)。用 wasNearBottom 边沿检测避免每个 scroll tick 都触发: +// 仅在"远离底部 → 滚近底部"的转换瞬间收起一次,已在底部继续滚动不重复触发。 +let wasNearBottom = true function refreshBackToBottom() { const el = messagesContainer.value if (!el) { showBackToBottom.value = false; return } @@ -1751,6 +1755,12 @@ function refreshBackToBottom() { } function onMessagesScroll() { refreshBackToBottom() + // UX-260616-03: 滚近底部 → 收起已读旧卡(边沿触发,防抖) + const near = isNearBottom() + if (near && !wasNearBottom) { + collapseAllToolLists(buildActiveToolIds(store.state.messages)) + } + wasNearBottom = near } function scrollToBottom(smooth = false) { @@ -1789,7 +1799,15 @@ watch(mdReady, (ready) => { }) watch(() => store.state.streaming, (s) => { if (rafId !== null) { cancelAnimationFrame(rafId); rafId = null } - if (!s) { + if (s) { + // UX-260616-03: 新一轮生成开始 → 收起上一轮已完成的旧工具卡,聚焦当前生成内容。 + // 仅当前视图正在生成时触发(generatingConvId 对齐 activeConversationId), + // 切走后台生成/恢复会话(streaming 初值已 true 的 onMounted 路径)不误触。 + // buildActiveToolIds/collapseAllToolLists 是 function 声明,提升可用。 + if (store.state.generatingConvId === store.state.activeConversationId) { + collapseAllToolLists(buildActiveToolIds(store.state.messages)) + } + } else { // UX-2025-01: 流式→完成切换,模板从 v-for 分块切到 v-html 整段,DOM 重建 saveSelection() streamingBlocks.value = [] diff --git a/src/components/ToolCard.vue b/src/components/ToolCard.vue index f05df9c..0b152ef 100644 --- a/src/components/ToolCard.vue +++ b/src/components/ToolCard.vue @@ -1,7 +1,10 @@