fix: 修复页面加载时出现两次动画的问题

问题原因:
- Socket 事件(conversation_changed, status_update 等)在初始化期间与 bootstrapRoute 并发执行
- loadConversationsList 在初始化期间自动加载第一个对话
- 导致 currentConversationId 被多次设置,触发多次历史加载和动画

解决方案:
- 在 Socket 事件处理中添加 initialRouteResolved 检查
- 初始化完成前,Socket 事件不修改 currentConversationId
- loadConversationsList 在初始化完成前不自动加载对话
- 确保所有数据(历史、文件树、思考模式等)在同一时间加载完成

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
JOJO 2026-03-09 16:59:56 +08:00
parent cd68812743
commit a4d3160b0a
3 changed files with 53 additions and 35 deletions

View File

@ -125,11 +125,15 @@ export const conversationMethods = {
debugLog(`已加载 ${this.conversations.length} 个对话`); debugLog(`已加载 ${this.conversations.length} 个对话`);
if (this.conversationsOffset === 0 && !this.currentConversationId && this.conversations.length > 0) { if (this.conversationsOffset === 0 && !this.currentConversationId && this.conversations.length > 0) {
// 只有在初始化完成后,才自动加载第一个对话
// 避免与 bootstrapRoute 冲突
if (this.initialRouteResolved) {
const latestConversation = this.conversations[0]; const latestConversation = this.conversations[0];
if (latestConversation && latestConversation.id) { if (latestConversation && latestConversation.id) {
await this.loadConversation(latestConversation.id); await this.loadConversation(latestConversation.id);
} }
} }
}
} else { } else {
console.error('加载对话列表失败:', data.error); console.error('加载对话列表失败:', data.error);
} }

View File

@ -953,7 +953,7 @@ export const uiMethods = {
}, },
async bootstrapRoute() { async bootstrapRoute() {
// 在路由解析期间抑制标题动画,避免预置“新对话”闪烁 // 在路由解析期间抑制标题动画,避免预置"新对话"闪烁
this.suppressTitleTyping = true; this.suppressTitleTyping = true;
this.titleReady = false; this.titleReady = false;
this.currentConversationTitle = ''; this.currentConversationTitle = '';

View File

@ -703,7 +703,8 @@ export async function initializeLegacySocket(ctx: any) {
ctx.socket.on('todo_updated', (data) => { ctx.socket.on('todo_updated', (data) => {
socketLog('收到todo更新事件:', data); socketLog('收到todo更新事件:', data);
if (data && data.conversation_id) { // 初始化期间不修改 currentConversationId避免与 bootstrapRoute 冲突
if (ctx.initialRouteResolved && data && data.conversation_id) {
ctx.currentConversationId = data.conversation_id; ctx.currentConversationId = data.conversation_id;
} }
ctx.fileSetTodoList((data && data.todo_list) || null); ctx.fileSetTodoList((data && data.todo_list) || null);
@ -740,6 +741,9 @@ export async function initializeLegacySocket(ctx: any) {
ctx.socket.on('conversation_changed', (data) => { ctx.socket.on('conversation_changed', (data) => {
socketLog('对话已切换:', data); socketLog('对话已切换:', data);
console.log('[conv-trace] socket:conversation_changed', data); console.log('[conv-trace] socket:conversation_changed', data);
// 初始化期间不修改 currentConversationId避免与 bootstrapRoute 冲突
if (ctx.initialRouteResolved) {
ctx.currentConversationId = data.conversation_id; ctx.currentConversationId = data.conversation_id;
ctx.currentConversationTitle = data.title || ''; ctx.currentConversationTitle = data.title || '';
ctx.promoteConversationToTop(data.conversation_id); ctx.promoteConversationToTop(data.conversation_id);
@ -760,6 +764,7 @@ export async function initializeLegacySocket(ctx: any) {
ctx.loadConversationsList(); ctx.loadConversationsList();
ctx.fetchTodoList(); ctx.fetchTodoList();
ctx.fetchSubAgents(); ctx.fetchSubAgents();
}
}); });
ctx.socket.on('conversation_resolved', (data) => { ctx.socket.on('conversation_resolved', (data) => {
@ -768,6 +773,9 @@ export async function initializeLegacySocket(ctx: any) {
} }
const convId = data.conversation_id; const convId = data.conversation_id;
console.log('[conv-trace] socket:conversation_resolved', data); console.log('[conv-trace] socket:conversation_resolved', data);
// 初始化期间不修改 currentConversationId避免与 bootstrapRoute 冲突
if (ctx.initialRouteResolved) {
ctx.currentConversationId = convId; ctx.currentConversationId = convId;
if (data.title) { if (data.title) {
ctx.currentConversationTitle = data.title; ctx.currentConversationTitle = data.title;
@ -780,6 +788,7 @@ export async function initializeLegacySocket(ctx: any) {
} else if (currentPath !== pathFragment) { } else if (currentPath !== pathFragment) {
history.replaceState({ conversationId: convId }, '', `/${pathFragment}`); history.replaceState({ conversationId: convId }, '', `/${pathFragment}`);
} }
}
}); });
// 监听对话加载事件 // 监听对话加载事件
@ -836,9 +845,14 @@ export async function initializeLegacySocket(ctx: any) {
// 监听状态更新事件 // 监听状态更新事件
ctx.socket.on('status_update', (status) => { ctx.socket.on('status_update', (status) => {
ctx.applyStatusSnapshot(status); ctx.applyStatusSnapshot(status);
// 只有在初始化完成后,才允许 status_update 修改 currentConversationId
// 避免与 bootstrapRoute 冲突
if (status.conversation && status.conversation.current_id) { if (status.conversation && status.conversation.current_id) {
if (ctx.initialRouteResolved && !ctx.currentConversationId) {
// 初始化完成且当前没有对话ID才设置
ctx.currentConversationId = status.conversation.current_id; ctx.currentConversationId = status.conversation.current_id;
} }
}
if (typeof status.run_mode === 'string') { if (typeof status.run_mode === 'string') {
ctx.runMode = status.run_mode; ctx.runMode = status.run_mode;
} else if (typeof status.thinking_mode !== 'undefined') { } else if (typeof status.thinking_mode !== 'undefined') {