From a4d3160b0ad1c4f2c4da87bd608a6eb91768fa7b Mon Sep 17 00:00:00 2001 From: JOJO <1498581755@qq.com> Date: Mon, 9 Mar 2026 16:59:56 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E6=97=B6=E5=87=BA=E7=8E=B0=E4=B8=A4=E6=AC=A1?= =?UTF-8?q?=E5=8A=A8=E7=94=BB=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题原因: - Socket 事件(conversation_changed, status_update 等)在初始化期间与 bootstrapRoute 并发执行 - loadConversationsList 在初始化期间自动加载第一个对话 - 导致 currentConversationId 被多次设置,触发多次历史加载和动画 解决方案: - 在 Socket 事件处理中添加 initialRouteResolved 检查 - 初始化完成前,Socket 事件不修改 currentConversationId - loadConversationsList 在初始化完成前不自动加载对话 - 确保所有数据(历史、文件树、思考模式等)在同一时间加载完成 Co-Authored-By: Claude Sonnet 4.5 --- static/src/app/methods/conversation.ts | 10 ++- static/src/app/methods/ui.ts | 2 +- static/src/composables/useLegacySocket.ts | 76 ++++++++++++++--------- 3 files changed, 53 insertions(+), 35 deletions(-) diff --git a/static/src/app/methods/conversation.ts b/static/src/app/methods/conversation.ts index 8cb44ac..034c617 100644 --- a/static/src/app/methods/conversation.ts +++ b/static/src/app/methods/conversation.ts @@ -125,9 +125,13 @@ export const conversationMethods = { debugLog(`已加载 ${this.conversations.length} 个对话`); if (this.conversationsOffset === 0 && !this.currentConversationId && this.conversations.length > 0) { - const latestConversation = this.conversations[0]; - if (latestConversation && latestConversation.id) { - await this.loadConversation(latestConversation.id); + // 只有在初始化完成后,才自动加载第一个对话 + // 避免与 bootstrapRoute 冲突 + if (this.initialRouteResolved) { + const latestConversation = this.conversations[0]; + if (latestConversation && latestConversation.id) { + await this.loadConversation(latestConversation.id); + } } } } else { diff --git a/static/src/app/methods/ui.ts b/static/src/app/methods/ui.ts index 5c113dc..25074cd 100644 --- a/static/src/app/methods/ui.ts +++ b/static/src/app/methods/ui.ts @@ -953,7 +953,7 @@ export const uiMethods = { }, async bootstrapRoute() { - // 在路由解析期间抑制标题动画,避免预置“新对话”闪烁 + // 在路由解析期间抑制标题动画,避免预置"新对话"闪烁 this.suppressTitleTyping = true; this.titleReady = false; this.currentConversationTitle = ''; diff --git a/static/src/composables/useLegacySocket.ts b/static/src/composables/useLegacySocket.ts index f87cb4f..d27e103 100644 --- a/static/src/composables/useLegacySocket.ts +++ b/static/src/composables/useLegacySocket.ts @@ -703,7 +703,8 @@ export async function initializeLegacySocket(ctx: any) { ctx.socket.on('todo_updated', (data) => { socketLog('收到todo更新事件:', data); - if (data && data.conversation_id) { + // 初始化期间不修改 currentConversationId,避免与 bootstrapRoute 冲突 + if (ctx.initialRouteResolved && data && data.conversation_id) { ctx.currentConversationId = data.conversation_id; } ctx.fileSetTodoList((data && data.todo_list) || null); @@ -740,26 +741,30 @@ export async function initializeLegacySocket(ctx: any) { ctx.socket.on('conversation_changed', (data) => { socketLog('对话已切换:', data); console.log('[conv-trace] socket:conversation_changed', data); - ctx.currentConversationId = data.conversation_id; - ctx.currentConversationTitle = data.title || ''; - ctx.promoteConversationToTop(data.conversation_id); - if (data.cleared) { - // 对话被清空 - ctx.logMessageState?.('socket:conversation_changed-clearing', { event: data }); - ctx.messages = []; - ctx.logMessageState?.('socket:conversation_changed-cleared', { event: data }); - ctx.currentConversationId = null; - ctx.currentConversationTitle = ''; - // 重置Token统计 - ctx.resetTokenStatistics(); - history.replaceState({}, '', '/new'); + // 初始化期间不修改 currentConversationId,避免与 bootstrapRoute 冲突 + if (ctx.initialRouteResolved) { + ctx.currentConversationId = data.conversation_id; + ctx.currentConversationTitle = data.title || ''; + ctx.promoteConversationToTop(data.conversation_id); + + if (data.cleared) { + // 对话被清空 + ctx.logMessageState?.('socket:conversation_changed-clearing', { event: data }); + ctx.messages = []; + ctx.logMessageState?.('socket:conversation_changed-cleared', { event: data }); + ctx.currentConversationId = null; + ctx.currentConversationTitle = ''; + // 重置Token统计 + ctx.resetTokenStatistics(); + history.replaceState({}, '', '/new'); + } + + // 刷新对话列表 + ctx.loadConversationsList(); + ctx.fetchTodoList(); + ctx.fetchSubAgents(); } - - // 刷新对话列表 - ctx.loadConversationsList(); - ctx.fetchTodoList(); - ctx.fetchSubAgents(); }); ctx.socket.on('conversation_resolved', (data) => { @@ -768,17 +773,21 @@ export async function initializeLegacySocket(ctx: any) { } const convId = data.conversation_id; console.log('[conv-trace] socket:conversation_resolved', data); - ctx.currentConversationId = convId; - if (data.title) { - ctx.currentConversationTitle = data.title; - } - ctx.promoteConversationToTop(convId); - const pathFragment = ctx.stripConversationPrefix(convId); - const currentPath = window.location.pathname.replace(/^\/+/, ''); - if (data.created) { - history.pushState({ conversationId: convId }, '', `/${pathFragment}`); - } else if (currentPath !== pathFragment) { - history.replaceState({ conversationId: convId }, '', `/${pathFragment}`); + + // 初始化期间不修改 currentConversationId,避免与 bootstrapRoute 冲突 + if (ctx.initialRouteResolved) { + ctx.currentConversationId = convId; + if (data.title) { + ctx.currentConversationTitle = data.title; + } + ctx.promoteConversationToTop(convId); + const pathFragment = ctx.stripConversationPrefix(convId); + const currentPath = window.location.pathname.replace(/^\/+/, ''); + if (data.created) { + history.pushState({ conversationId: convId }, '', `/${pathFragment}`); + } else if (currentPath !== pathFragment) { + history.replaceState({ conversationId: convId }, '', `/${pathFragment}`); + } } }); @@ -836,8 +845,13 @@ export async function initializeLegacySocket(ctx: any) { // 监听状态更新事件 ctx.socket.on('status_update', (status) => { ctx.applyStatusSnapshot(status); + // 只有在初始化完成后,才允许 status_update 修改 currentConversationId + // 避免与 bootstrapRoute 冲突 if (status.conversation && status.conversation.current_id) { - ctx.currentConversationId = status.conversation.current_id; + if (ctx.initialRouteResolved && !ctx.currentConversationId) { + // 初始化完成且当前没有对话ID,才设置 + ctx.currentConversationId = status.conversation.current_id; + } } if (typeof status.run_mode === 'string') { ctx.runMode = status.run_mode;