fix: prevent duplicate history animation
This commit is contained in:
parent
4262922694
commit
8de3b5d24a
@ -130,6 +130,8 @@ const appOptions = {
|
|||||||
toolStacks: new Map(),
|
toolStacks: new Map(),
|
||||||
// 当前任务是否仍在进行中(用于保持输入区的“停止”状态)
|
// 当前任务是否仍在进行中(用于保持输入区的“停止”状态)
|
||||||
taskInProgress: false,
|
taskInProgress: false,
|
||||||
|
// 记录上一次成功加载历史的对话ID,防止初始化阶段重复加载导致动画播放两次
|
||||||
|
lastHistoryLoadedConversationId: null,
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// 对话管理相关状态
|
// 对话管理相关状态
|
||||||
@ -1132,6 +1134,9 @@ const appOptions = {
|
|||||||
this.ensureScrollListener();
|
this.ensureScrollListener();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 重置已加载对话标记,便于后续重新加载新对话历史
|
||||||
|
this.lastHistoryLoadedConversationId = null;
|
||||||
|
|
||||||
this.logMessageState('resetAllStates:after-cleanup', { reason });
|
this.logMessageState('resetAllStates:after-cleanup', { reason });
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1182,6 +1187,8 @@ const appOptions = {
|
|||||||
if (statusConversationId) {
|
if (statusConversationId) {
|
||||||
if (!this.currentConversationId) {
|
if (!this.currentConversationId) {
|
||||||
this.skipConversationHistoryReload = true;
|
this.skipConversationHistoryReload = true;
|
||||||
|
// 首次从状态恢复对话时,避免 socket 的 conversation_loaded 再次触发历史加载
|
||||||
|
this.skipConversationLoadedEvent = true;
|
||||||
this.currentConversationId = statusConversationId;
|
this.currentConversationId = statusConversationId;
|
||||||
|
|
||||||
// 如果有当前对话,尝试获取标题和历史
|
// 如果有当前对话,尝试获取标题和历史
|
||||||
@ -1192,7 +1199,13 @@ const appOptions = {
|
|||||||
this.currentConversationTitle = convData.data.title;
|
this.currentConversationTitle = convData.data.title;
|
||||||
}
|
}
|
||||||
// 初始化时调用一次,因为 skipConversationHistoryReload 会阻止 watch 触发
|
// 初始化时调用一次,因为 skipConversationHistoryReload 会阻止 watch 触发
|
||||||
|
if (
|
||||||
|
this.lastHistoryLoadedConversationId !== this.currentConversationId ||
|
||||||
|
!Array.isArray(this.messages) ||
|
||||||
|
this.messages.length === 0
|
||||||
|
) {
|
||||||
await this.fetchAndDisplayHistory();
|
await this.fetchAndDisplayHistory();
|
||||||
|
}
|
||||||
// 获取当前对话的Token统计
|
// 获取当前对话的Token统计
|
||||||
this.fetchConversationTokenStatistics();
|
this.fetchConversationTokenStatistics();
|
||||||
this.updateCurrentContextTokens();
|
this.updateCurrentContextTokens();
|
||||||
@ -1417,7 +1430,8 @@ const appOptions = {
|
|||||||
// ==========================================
|
// ==========================================
|
||||||
// 关键功能:获取并显示历史对话内容
|
// 关键功能:获取并显示历史对话内容
|
||||||
// ==========================================
|
// ==========================================
|
||||||
async fetchAndDisplayHistory() {
|
async fetchAndDisplayHistory(options = {}) {
|
||||||
|
const { force = false } = options as { force?: boolean };
|
||||||
const targetConversationId = this.currentConversationId;
|
const targetConversationId = this.currentConversationId;
|
||||||
if (!targetConversationId || targetConversationId.startsWith('temp_')) {
|
if (!targetConversationId || targetConversationId.startsWith('temp_')) {
|
||||||
debugLog('没有当前对话ID,跳过历史加载');
|
debugLog('没有当前对话ID,跳过历史加载');
|
||||||
@ -1431,6 +1445,20 @@ const appOptions = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 已经有完整历史且非强制刷新时,避免重复加载导致动画播放两次
|
||||||
|
const alreadyHydrated =
|
||||||
|
!force &&
|
||||||
|
this.lastHistoryLoadedConversationId === targetConversationId &&
|
||||||
|
Array.isArray(this.messages) &&
|
||||||
|
this.messages.length > 0;
|
||||||
|
if (alreadyHydrated) {
|
||||||
|
debugLog('历史已加载,跳过重复请求');
|
||||||
|
this.logMessageState('fetchAndDisplayHistory:skip-duplicate', {
|
||||||
|
conversationId: targetConversationId
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const loadSeq = ++this.historyLoadSeq;
|
const loadSeq = ++this.historyLoadSeq;
|
||||||
this.historyLoading = true;
|
this.historyLoading = true;
|
||||||
this.historyLoadingFor = targetConversationId;
|
this.historyLoadingFor = targetConversationId;
|
||||||
@ -1743,6 +1771,7 @@ const appOptions = {
|
|||||||
|
|
||||||
debugLog(`历史消息渲染完成,共 ${this.messages.length} 条消息`);
|
debugLog(`历史消息渲染完成,共 ${this.messages.length} 条消息`);
|
||||||
this.logMessageState('renderHistoryMessages:after-render');
|
this.logMessageState('renderHistoryMessages:after-render');
|
||||||
|
this.lastHistoryLoadedConversationId = this.currentConversationId || null;
|
||||||
|
|
||||||
// 强制更新视图
|
// 强制更新视图
|
||||||
this.$forceUpdate();
|
this.$forceUpdate();
|
||||||
|
|||||||
@ -522,16 +522,30 @@ export async function initializeLegacySocket(ctx: any) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const scheduleHistoryReload = (delay = 0) => {
|
const scheduleHistoryReload = (delay = 0, options: { force?: boolean } = {}) => {
|
||||||
|
const { force = false } = options;
|
||||||
if (!ctx || typeof ctx.fetchAndDisplayHistory !== 'function') {
|
if (!ctx || typeof ctx.fetchAndDisplayHistory !== 'function') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!ctx.currentConversationId || ctx.currentConversationId.startsWith('temp_')) {
|
setTimeout(() => {
|
||||||
|
const targetConversationId = ctx.currentConversationId;
|
||||||
|
if (!targetConversationId || targetConversationId.startsWith('temp_')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
|
||||||
try {
|
try {
|
||||||
ctx.fetchAndDisplayHistory();
|
if (!force) {
|
||||||
|
const loadingSame =
|
||||||
|
!!ctx.historyLoading && ctx.historyLoadingFor === targetConversationId;
|
||||||
|
const historyReady =
|
||||||
|
ctx.lastHistoryLoadedConversationId === targetConversationId &&
|
||||||
|
Array.isArray(ctx.messages) &&
|
||||||
|
ctx.messages.length > 0;
|
||||||
|
if (loadingSame || historyReady) {
|
||||||
|
socketLog('跳过重复历史加载(scheduleHistoryReload)');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.fetchAndDisplayHistory({ force });
|
||||||
if (typeof ctx.fetchConversationTokenStatistics === 'function') {
|
if (typeof ctx.fetchConversationTokenStatistics === 'function') {
|
||||||
ctx.fetchConversationTokenStatistics();
|
ctx.fetchConversationTokenStatistics();
|
||||||
}
|
}
|
||||||
@ -565,13 +579,31 @@ export async function initializeLegacySocket(ctx: any) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let hasConnectedOnce = false;
|
||||||
|
|
||||||
// 连接事件
|
// 连接事件
|
||||||
ctx.socket.on('connect', () => {
|
ctx.socket.on('connect', () => {
|
||||||
|
const isReconnect = hasConnectedOnce;
|
||||||
|
const historyLoadingSame =
|
||||||
|
!!ctx.historyLoading && ctx.historyLoadingFor === ctx.currentConversationId;
|
||||||
|
const historyReady =
|
||||||
|
ctx.lastHistoryLoadedConversationId === ctx.currentConversationId &&
|
||||||
|
Array.isArray(ctx.messages) &&
|
||||||
|
ctx.messages.length > 0;
|
||||||
|
|
||||||
ctx.isConnected = true;
|
ctx.isConnected = true;
|
||||||
socketLog('WebSocket已连接');
|
socketLog('WebSocket已连接');
|
||||||
// 连接时重置所有状态并刷新当前对话
|
|
||||||
ctx.resetAllStates('socket:connect');
|
// 首次连接且历史已在加载/已就绪时,避免重复清空与重复动画
|
||||||
scheduleHistoryReload(200);
|
if (!isReconnect && (historyLoadingSame || historyReady)) {
|
||||||
|
socketLog('初次连接已存在历史,跳过重复重置与加载');
|
||||||
|
hasConnectedOnce = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasConnectedOnce = true;
|
||||||
|
ctx.resetAllStates(isReconnect ? 'socket:reconnect' : 'socket:connect');
|
||||||
|
scheduleHistoryReload(200, { force: isReconnect });
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.socket.on('disconnect', () => {
|
ctx.socket.on('disconnect', () => {
|
||||||
@ -731,15 +763,30 @@ export async function initializeLegacySocket(ctx: any) {
|
|||||||
socketLog('跳过重复的 conversation_loaded 处理');
|
socketLog('跳过重复的 conversation_loaded 处理');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const targetConversationId = (data && data.conversation_id) || ctx.currentConversationId;
|
||||||
|
const historyLoadingSame =
|
||||||
|
!!targetConversationId &&
|
||||||
|
!!ctx.historyLoading &&
|
||||||
|
ctx.historyLoadingFor === targetConversationId;
|
||||||
|
const historyReady =
|
||||||
|
!!targetConversationId &&
|
||||||
|
ctx.lastHistoryLoadedConversationId === targetConversationId &&
|
||||||
|
Array.isArray(ctx.messages) &&
|
||||||
|
ctx.messages.length > 0;
|
||||||
|
const forceReload = !!(data && data.force_reload);
|
||||||
|
|
||||||
|
if (!forceReload && (historyLoadingSame || historyReady)) {
|
||||||
|
socketLog('conversation_loaded: 历史已加载/加载中,跳过重复刷新');
|
||||||
|
} else {
|
||||||
if (data.clear_ui) {
|
if (data.clear_ui) {
|
||||||
// 清理当前UI状态,准备显示历史内容
|
// 清理当前UI状态,准备显示历史内容
|
||||||
ctx.resetAllStates('socket:conversation_loaded');
|
ctx.resetAllStates('socket:conversation_loaded');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 延迟获取并显示历史对话内容
|
// 延迟获取并显示历史对话内容
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
ctx.fetchAndDisplayHistory();
|
ctx.fetchAndDisplayHistory({ force: forceReload });
|
||||||
}, 300);
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
// 延迟获取Token统计(累计+当前上下文)
|
// 延迟获取Token统计(累计+当前上下文)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user