From 8814f963f5f4a53c1366db6c0029010aff315d21 Mon Sep 17 00:00:00 2001 From: JOJO <1498581755@qq.com> Date: Tue, 28 Apr 2026 17:56:52 +0800 Subject: [PATCH] =?UTF-8?q?fix(ux):=20=E7=94=A8=E6=88=B7=E5=8F=91=E9=80=81?= =?UTF-8?q?=E5=90=8E=E5=8D=B3=E6=97=B6=E6=98=BE=E7=A4=BA=20assistant=20?= =?UTF-8?q?=E5=A4=B4=E9=83=A8=E5=92=8C=E7=AD=89=E5=BE=85=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/app/methods/message.ts | 35 ++++++++++++++++++++++----- static/src/app/methods/taskPolling.ts | 23 +++++++++++++++--- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/static/src/app/methods/message.ts b/static/src/app/methods/message.ts index ba2412f..9bfa621 100644 --- a/static/src/app/methods/message.ts +++ b/static/src/app/methods/message.ts @@ -255,6 +255,16 @@ export const messageMethods = { // 标记任务进行中,直到任务完成或用户手动停止 this.taskInProgress = true; this.chatAddUserMessage(message, images, videos); + // 关键体验修复:用户发送后立刻显示 assistant 头部 + 工作中计时 + 等待提示, + // 不等待 createTask / 轮询首事件返回。 + this.chatStartAssistantMessage(); + this.stopRequested = false; + if (typeof this.monitorShowPendingReply === 'function') { + this.monitorShowPendingReply(); + } + if (this.autoScrollEnabled) { + this.scrollToBottom(); + } // 使用 REST API 创建任务(轮询模式) try { @@ -278,13 +288,17 @@ export const messageMethods = { message: error.message || '创建任务失败,请重试', type: 'error' }); + this.streamingMessage = false; this.taskInProgress = false; + if (typeof this.cleanupTrailingEmptyAssistantPlaceholder === 'function') { + this.cleanupTrailingEmptyAssistantPlaceholder('create_task_failed'); + } + if (typeof this.forceUnlockMonitor === 'function') { + this.forceUnlockMonitor('create_task_failed'); + } return; } - if (typeof this.monitorShowPendingReply === 'function') { - this.monitorShowPendingReply(); - } this.inputClearMessage(); this.inputClearSelectedImages(); this.inputClearSelectedVideos(); @@ -555,6 +569,11 @@ export const messageMethods = { } this.taskInProgress = true; this.chatAddUserMessage(message, []); + this.chatStartAssistantMessage(); + this.stopRequested = false; + if (typeof this.monitorShowPendingReply === 'function') { + this.monitorShowPendingReply(); + } try { const { useTaskStore } = await import('../../stores/task'); const taskStore = useTaskStore(); @@ -569,12 +588,16 @@ export const messageMethods = { message: error?.message || '创建任务失败,请重试', type: 'error' }); + this.streamingMessage = false; this.taskInProgress = false; + if (typeof this.cleanupTrailingEmptyAssistantPlaceholder === 'function') { + this.cleanupTrailingEmptyAssistantPlaceholder('auto_create_task_failed'); + } + if (typeof this.forceUnlockMonitor === 'function') { + this.forceUnlockMonitor('auto_create_task_failed'); + } return false; } - if (typeof this.monitorShowPendingReply === 'function') { - this.monitorShowPendingReply(); - } if (this.autoScrollEnabled) { this.scrollToBottom(); } diff --git a/static/src/app/methods/taskPolling.ts b/static/src/app/methods/taskPolling.ts index 700026a..3fa3f45 100644 --- a/static/src/app/methods/taskPolling.ts +++ b/static/src/app/methods/taskPolling.ts @@ -83,6 +83,24 @@ function isEmptyAssistantPlaceholderMessage(message: any): boolean { return actions.length === 0 && !!message.awaitingFirstContent; } +function getOptimisticUserEchoTarget(messages: any[]): any | null { + if (!Array.isArray(messages) || messages.length === 0) { + return null; + } + const lastIndex = messages.length - 1; + const last = messages[lastIndex]; + if (last?.role === 'user') { + return last; + } + if (isEmptyAssistantPlaceholderMessage(last) && lastIndex > 0) { + const prev = messages[lastIndex - 1]; + if (prev?.role === 'user') { + return prev; + } + } + return null; +} + /** * 任务轮询事件处理器 * 将从 REST API 轮询获取的事件转换为前端状态更新 @@ -1284,10 +1302,7 @@ export const taskPollingMethods = { : Array.isArray(data?.mediaRefs) ? data.mediaRefs : []; - const last = - Array.isArray(this.messages) && this.messages.length > 0 - ? this.messages[this.messages.length - 1] - : null; + const last = getOptimisticUserEchoTarget(this.messages || []); const isLikelyOptimisticEcho = !!( last && last.role === 'user' &&