fix: 修复页面刷新时思考块自动展开的问题

- 在历史加载时给思考块设置 collapsed: true 默认折叠
- 在任务恢复时跳过思考块的展开/折叠动画
- 延迟清除 _rebuildingFromScratch 标记,确保所有历史事件处理完毕
- 删除过早清除重建标记的逻辑,避免后续思考块被展开

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
JOJO 2026-03-09 16:31:00 +08:00
parent d71525a3c6
commit cd68812743
2 changed files with 114 additions and 107 deletions

View File

@ -194,6 +194,7 @@ export const historyMethods = {
type: 'thinking', type: 'thinking',
content: reasoningText, content: reasoningText,
streaming: false, streaming: false,
collapsed: true,
timestamp: Date.now(), timestamp: Date.now(),
blockId blockId
}); });

View File

@ -104,12 +104,8 @@ export const taskPollingMethods = {
debugLog(`[TaskPolling] 未知事件类型: ${eventType}`); debugLog(`[TaskPolling] 未知事件类型: ${eventType}`);
} }
// 如果正在从头重建,检查是否已经处理到当前事件 // 注意:不要在这里清除 _rebuildingFromScratch 标记
// 当处理到工具相关事件时,说明思考已经结束,可以清除重建标记 // 该标记应该在恢复完所有历史事件后才清除
if (this._rebuildingFromScratch && (eventType === 'tool_preparing' || eventType === 'tool_start')) {
debugLog('[TaskPolling] 检测到工具事件,清除重建标记');
this._rebuildingFromScratch = false;
}
}, },
handleAiMessageStart(data: any, eventIdx: number) { handleAiMessageStart(data: any, eventIdx: number) {
@ -160,42 +156,48 @@ export const taskPollingMethods = {
this.monitorShowThinking(); this.monitorShowThinking();
// 获取当前 actions 数量,用于调试 // 获取当前 actions 数量,用于调试(已禁用)
const lastMessage = this.messages[this.messages.length - 1]; // const lastMessage = this.messages[this.messages.length - 1];
const beforeCount = lastMessage?.actions?.length || 0; // const beforeCount = lastMessage?.actions?.length || 0;
console.log('[TaskPolling] 添加思考块前actions 数量:', beforeCount); // console.log('[TaskPolling] 添加思考块前actions 数量:', beforeCount);
console.log('[TaskPolling] 当前 currentMessageIndex:', this.currentMessageIndex); // console.log('[TaskPolling] 当前 currentMessageIndex:', this.currentMessageIndex);
console.log('[TaskPolling] messages 总数:', this.messages.length); // console.log('[TaskPolling] messages 总数:', this.messages.length);
console.log('[TaskPolling] 最后一条消息 role:', lastMessage?.role); // console.log('[TaskPolling] 最后一条消息 role:', lastMessage?.role);
const result = this.chatStartThinkingAction(); const result = this.chatStartThinkingAction();
console.log('[TaskPolling] chatStartThinkingAction 返回:', result); // console.log('[TaskPolling] chatStartThinkingAction 返回:', result);
if (result && result.blockId) { if (result && result.blockId) {
const blockId = result.blockId; const blockId = result.blockId;
// 检查新添加的 action // 检查新添加的 action(已禁用)
const afterCount = lastMessage?.actions?.length || 0; // const afterCount = lastMessage?.actions?.length || 0;
console.log('[TaskPolling] 添加思考块后actions 数量:', afterCount); // console.log('[TaskPolling] 添加思考块后actions 数量:', afterCount);
// 检查 currentMessageIndex 指向的消息 // 检查 currentMessageIndex 指向的消息(已禁用)
const currentMsg = this.messages[this.currentMessageIndex]; // const currentMsg = this.messages[this.currentMessageIndex];
if (currentMsg) { // if (currentMsg) {
console.log('[TaskPolling] currentMessageIndex 指向的消息 actions 数量:', currentMsg.actions?.length || 0); // console.log('[TaskPolling] currentMessageIndex 指向的消息 actions 数量:', currentMsg.actions?.length || 0);
// }
// if (afterCount > beforeCount) {
// const newAction = lastMessage.actions[afterCount - 1];
// console.log('[TaskPolling] 新添加的思考块:', {
// type: newAction.type,
// blockId: newAction.blockId,
// hasId: !!newAction.id,
// timestamp: newAction.timestamp
// });
// }
const lastMessage = this.messages[this.messages.length - 1];
// 只在非历史恢复时展开思考块
if (!this._rebuildingFromScratch) {
this.chatExpandBlock(blockId);
} }
if (afterCount > beforeCount) {
const newAction = lastMessage.actions[afterCount - 1];
console.log('[TaskPolling] 新添加的思考块:', {
type: newAction.type,
blockId: newAction.blockId,
hasId: !!newAction.id,
timestamp: newAction.timestamp
});
}
this.chatExpandBlock(blockId);
this.scrollToBottom(); this.scrollToBottom();
this.chatSetThinkingLock(blockId, true); this.chatSetThinkingLock(blockId, true);
@ -235,11 +237,17 @@ export const taskPollingMethods = {
// 解锁思考块 // 解锁思考块
this.chatSetThinkingLock(blockId, false); this.chatSetThinkingLock(blockId, false);
// 延迟折叠思考块(给用户一点时间看到思考完成) // 只在非历史恢复时延迟折叠思考块
setTimeout(() => { if (!this._rebuildingFromScratch) {
// 延迟折叠思考块(给用户一点时间看到思考完成)
setTimeout(() => {
this.chatCollapseBlock(blockId);
this.$forceUpdate();
}, 1000);
} else {
// 历史恢复时立即折叠,不需要动画
this.chatCollapseBlock(blockId); this.chatCollapseBlock(blockId);
this.$forceUpdate(); }
}, 1000);
this.$nextTick(() => this.scrollThinkingToBottom(blockId)); this.$nextTick(() => this.scrollThinkingToBottom(blockId));
} }
@ -641,12 +649,12 @@ export const taskPollingMethods = {
const lastMessage = this.messages[this.messages.length - 1]; const lastMessage = this.messages[this.messages.length - 1];
const isAssistantMessage = lastMessage && lastMessage.role === 'assistant'; const isAssistantMessage = lastMessage && lastMessage.role === 'assistant';
console.log('[TaskPolling] 最后一条消息:', { // console.log('[TaskPolling] 最后一条消息:', {
exists: !!lastMessage, // exists: !!lastMessage,
role: lastMessage?.role, // role: lastMessage?.role,
actionsCount: lastMessage?.actions?.length || 0, // actionsCount: lastMessage?.actions?.length || 0,
isAssistant: isAssistantMessage // isAssistant: isAssistantMessage
}); // });
// 检查是否需要从头重建 // 检查是否需要从头重建
// 1. 最后一条不是 assistant 消息 // 1. 最后一条不是 assistant 消息
@ -661,13 +669,13 @@ export const taskPollingMethods = {
historyIncomplete; historyIncomplete;
if (needsRebuild) { if (needsRebuild) {
if (historyIncomplete) { // if (historyIncomplete) {
console.log('[TaskPolling] 历史不完整,从头重建:', { // console.log('[TaskPolling] 历史不完整,从头重建:', {
historyActionsCount, // historyActionsCount,
eventCount, // eventCount,
diff: eventCount - historyActionsCount // diff: eventCount - historyActionsCount
}); // });
} // }
debugLog('[TaskPolling] 需要从头重建 assistant 响应'); debugLog('[TaskPolling] 需要从头重建 assistant 响应');
// 清空所有消息,准备从头重建 // 清空所有消息,准备从头重建
@ -687,6 +695,7 @@ export const taskPollingMethods = {
// 标记正在从头重建,用于后续处理 // 标记正在从头重建,用于后续处理
this._rebuildingFromScratch = true; this._rebuildingFromScratch = true;
this._rebuildingEventCount = allEvents.length; // 记录当前事件总数
(window as any).__taskEventHandler = (event: any) => { (window as any).__taskEventHandler = (event: any) => {
this.handleTaskEvent(event); this.handleTaskEvent(event);
@ -695,6 +704,14 @@ export const taskPollingMethods = {
taskStore.startPolling((event: any) => { taskStore.startPolling((event: any) => {
this.handleTaskEvent(event); this.handleTaskEvent(event);
}); });
// 延迟清除重建标记,确保所有历史事件都处理完毕
setTimeout(() => {
debugLog('[TaskPolling] 历史事件处理完毕,清除重建标记');
this._rebuildingFromScratch = false;
this._rebuildingEventCount = 0;
}, 2000);
return; return;
} }
@ -718,95 +735,84 @@ export const taskPollingMethods = {
} }
} }
console.log('[TaskPolling] 分析结果:', { // console.log('[TaskPolling] 分析结果:', {
inThinking, // inThinking,
inText, // inText,
totalEvents: allEvents.length, // totalEvents: allEvents.length,
lastEventType: allEvents[allEvents.length - 1]?.type, // lastEventType: allEvents[allEvents.length - 1]?.type,
lastEventIdx: allEvents[allEvents.length - 1]?.idx // lastEventIdx: allEvents[allEvents.length - 1]?.idx
}); // });
// 恢复思考块状态 // 恢复思考块状态
if (lastMessage.actions) { if (lastMessage.actions) {
console.log('[TaskPolling] 历史中的 actions 详情:', lastMessage.actions.map((a, idx) => ({ // console.log('[TaskPolling] 历史中的 actions 详情:', lastMessage.actions.map((a, idx) => ({
index: idx, // index: idx,
type: a.type, // type: a.type,
id: a.id, // id: a.id,
hasContent: !!a.content, // hasContent: !!a.content,
contentLength: a.content?.length || 0, // contentLength: a.content?.length || 0,
toolName: a.tool?.name, // toolName: a.tool?.name,
hasBlockId: !!a.blockId, // hasBlockId: !!a.blockId,
blockId: a.blockId, // blockId: a.blockId,
collapsed: a.collapsed, // collapsed: a.collapsed,
streaming: a.streaming // streaming: a.streaming
}))); // })));
const thinkingActions = lastMessage.actions.filter(a => a.type === 'thinking'); const thinkingActions = lastMessage.actions.filter(a => a.type === 'thinking');
console.log('[TaskPolling] 思考块数量:', thinkingActions.length); // console.log('[TaskPolling] 思考块数量:', thinkingActions.length);
if (inThinking && thinkingActions.length > 0) { if (inThinking && thinkingActions.length > 0) {
// 正在思考中,检查最后一个思考块是否正在流式输出 // 正在思考中,检查最后一个思考块是否正在流式输出
const lastThinking = thinkingActions[thinkingActions.length - 1]; const lastThinking = thinkingActions[thinkingActions.length - 1];
// 只有当思考块正在流式输出时才展开 // 只有当思考块正在流式输出时才设置锁定状态(但不展开
if (lastThinking.streaming && lastThinking.blockId) { if (lastThinking.streaming && lastThinking.blockId) {
console.log('[TaskPolling] 找到正在流式输出的思考块,展开:', lastThinking.blockId); // console.log('[TaskPolling] 找到正在流式输出的思考块,设置锁定状态:', lastThinking.blockId);
lastThinking.collapsed = false;
this.$nextTick(() => { this.$nextTick(() => {
this.chatExpandBlock(lastThinking.blockId);
this.chatSetThinkingLock(lastThinking.blockId, true); this.chatSetThinkingLock(lastThinking.blockId, true);
}); });
} else {
console.log('[TaskPolling] 没有找到正在流式输出的思考块,不展开');
// 折叠所有思考块
for (const thinking of thinkingActions) {
if (thinking.blockId) {
thinking.collapsed = true;
}
}
}
} else {
// 不在思考中,折叠所有思考块
console.log('[TaskPolling] 不在思考中,折叠所有思考块');
for (const thinking of thinkingActions) {
if (thinking.blockId) {
thinking.collapsed = true;
}
} }
} }
// 检查思考块状态(在设置之后) // 确保所有思考块都是折叠状态
thinkingActions.forEach((thinking, idx) => { for (const thinking of thinkingActions) {
console.log(`[TaskPolling] 思考块 ${idx} (设置后):`, { if (thinking.blockId) {
hasBlockId: !!thinking.blockId, thinking.collapsed = true;
blockId: thinking.blockId, }
collapsed: thinking.collapsed, }
contentLength: thinking.content?.length || 0
}); // 检查思考块状态(在设置之后)(已禁用)
}); // thinkingActions.forEach((thinking, idx) => {
// console.log(`[TaskPolling] 思考块 ${idx} (设置后):`, {
// hasBlockId: !!thinking.blockId,
// blockId: thinking.blockId,
// collapsed: thinking.collapsed,
// contentLength: thinking.content?.length || 0
// });
// });
// 恢复文本块状态 // 恢复文本块状态
const textActions = lastMessage.actions.filter(a => a.type === 'text'); const textActions = lastMessage.actions.filter(a => a.type === 'text');
console.log('[TaskPolling] 文本块数量:', textActions.length); // console.log('[TaskPolling] 文本块数量:', textActions.length);
if (inText && textActions.length > 0) { if (inText && textActions.length > 0) {
const lastText = textActions[textActions.length - 1]; const lastText = textActions[textActions.length - 1];
console.log('[TaskPolling] 标记文本块为流式状态'); // console.log('[TaskPolling] 标记文本块为流式状态');
lastText.streaming = true; lastText.streaming = true;
} }
// 注册历史中的工具块到 toolActionIndex // 注册历史中的工具块到 toolActionIndex
// 这样后续的 update_action 事件可以找到对应的块进行状态更新 // 这样后续的 update_action 事件可以找到对应的块进行状态更新
const toolActions = lastMessage.actions.filter(a => a.type === 'tool'); const toolActions = lastMessage.actions.filter(a => a.type === 'tool');
console.log('[TaskPolling] 工具块数量:', toolActions.length); // console.log('[TaskPolling] 工具块数量:', toolActions.length);
for (const toolAction of toolActions) { for (const toolAction of toolActions) {
if (toolAction.tool && toolAction.tool.id) { if (toolAction.tool && toolAction.tool.id) {
console.log('[TaskPolling] 注册工具块:', { // console.log('[TaskPolling] 注册工具块:', {
id: toolAction.tool.id, // id: toolAction.tool.id,
name: toolAction.tool.name, // name: toolAction.tool.name,
status: toolAction.tool.status // status: toolAction.tool.status
}); // });
// 注册到 toolActionIndex // 注册到 toolActionIndex
this.toolRegisterAction(toolAction, toolAction.tool.id); this.toolRegisterAction(toolAction, toolAction.tool.id);
// 如果有 executionId也注册 // 如果有 executionId也注册
@ -830,7 +836,7 @@ export const taskPollingMethods = {
const lastMessageIndex = this.messages.length - 1; const lastMessageIndex = this.messages.length - 1;
if (lastMessage && lastMessage.role === 'assistant') { if (lastMessage && lastMessage.role === 'assistant') {
this.currentMessageIndex = lastMessageIndex; this.currentMessageIndex = lastMessageIndex;
console.log('[TaskPolling] 设置 currentMessageIndex 为:', lastMessageIndex); // console.log('[TaskPolling] 设置 currentMessageIndex 为:', lastMessageIndex);
} }
// 强制更新界面 // 强制更新界面