From a42ad4ebb3082ecc180bd5da3aa9b6811c578f5e Mon Sep 17 00:00:00 2001 From: jing <1683105490@qq.com> Date: Wed, 23 Sep 2026 16:25:39 +0800 Subject: [PATCH] =?UTF-8?q?chore=EF=BC=9A=E6=96=B0=E5=A2=9EAI=E6=99=BA?= =?UTF-8?q?=E8=83=BD=E9=97=AE=E9=A2=98=E6=98=AF=E5=90=A6=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E5=9B=9E=E7=AD=94/=E5=8D=95=E7=8B=AC=E5=9B=9E=E7=AD=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages_tool/ai-chat/ai-chat-message.vue | 55 ++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/pages_tool/ai-chat/ai-chat-message.vue b/pages_tool/ai-chat/ai-chat-message.vue index 491f0a4..7f6d66b 100644 --- a/pages_tool/ai-chat/ai-chat-message.vue +++ b/pages_tool/ai-chat/ai-chat-message.vue @@ -703,6 +703,10 @@ export default { streamInterval: null, streamContent: '', isStreaming: false, + // PR-CHAT-PARALLEL-CONFIRM (2026-09-23): AI 正在回答时又发新问题, 用户选"单独处理" + // → 该消息排队, 等本轮流式回答结束后自动发送 + // (避免后端把"上一轮未完成的请求"和"新问题"并行/合并处理, 导致答非所问串题) + pendingSendAfterStream: false, // 本地用户头像(优先使用缓存,无缓存则用默认图) localUserAvatar: '', showAvatarSelector: false, // 头像选择弹窗控制 @@ -1376,6 +1380,37 @@ async loadChatHistoryIfExist() { } }, + // PR-CHAT-PARALLEL-CONFIRM (2026-09-23): AI 还在回答上一个问题时又发新消息的"是否合并"确认 + // 背景: AI 是"并行处理"的智能体, 上一轮未完成的任务 + 新问题一起丢给它时, + // 它会自作主张把两件事并行处理(思考流里会出现 "do these in parallel"), + // 结果就是答非所问/串题(例如问"王维怎么玩"却回答上一个公司的信息)。 + // 策略: 发出去之前先问用户 —— 合并处理(立即发, 与当前回答并行) / 单独处理(排队, 本轮结束后自动发) + _confirmParallelMerge() { + return new Promise((resolve) => { + uni.showModal({ + title: 'AI 正在回答上一个问题', + content: '是否把这条新消息与当前回答合并处理?\n· 合并处理:立即发送,AI 会并行处理两个问题\n· 单独处理:等当前回答结束后自动发送', + confirmText: '合并处理', + cancelText: '单独处理', + success: (res) => resolve(!!res.confirm), + fail: () => resolve(false) + }) + }) + }, + + // PR-CHAT-PARALLEL-CONFIRM (2026-09-23): 本轮回答结束后, 自动发送排队中的消息 + // 多个结束路径(正常结束/报错/降级)都会调, 用标记位保证只触发一次 + _flushQueuedSend() { + if (!this.pendingSendAfterStream) return + this.pendingSendAfterStream = false + // 排队期间用户可能把输入框清空了/删掉了附件 → 没有可发内容就放弃, 不弹空消息 + const hasText = this.inputText && this.inputText.trim() !== '' + const hasAttach = (this.pendingImages && this.pendingImages.length) || (this.pendingFiles && this.pendingFiles.length) + if (!hasText && !hasAttach) return + uni.showToast({ title: '正在发送排队中的消息', icon: 'none' }) + this.$nextTick(() => { this.sendMessage() }) + }, + // 发送消息 // PR-FRONTEND-MEDIA-UPLOAD-FIX (2026-09-16): pendingImages 数组版 // 原 pendingImage 单数, 改支持 1-9 张图一起发 @@ -1401,6 +1436,18 @@ async loadChatHistoryIfExist() { if (!hasContent && !hasEmoji && !allPending.length) return + // PR-CHAT-PARALLEL-CONFIRM (2026-09-23): AI 还在回答时又发新消息 → 先问用户是否合并处理 + // 合并: 立即发出(与当前回答并行, 可能出现串题) 单独: 排队, 本轮流式回答结束后自动发送 + if (this.isStreaming) { + const mergeNow = await this._confirmParallelMerge() + if (!mergeNow) { + // 输入框内容与待发附件原样保留, 等本轮回答结束由 _flushQueuedSend 自动发出 + this.pendingSendAfterStream = true + uni.showToast({ title: '已排队,本轮回答结束后自动发送', icon: 'none' }) + return + } + } + // PR-FIX (2026-09-20): 手动发送消息后清掉欢迎气泡上的快捷问题 chips // 原来只有点击 chip 才摘除, 用户手动打字发消息后 chips 一直挂着, // 与"引导一次性"的语义不符 @@ -1720,12 +1767,16 @@ async sendStreamMessage(userMessage, attachments = []) { } this.$nextTick(() => this.scrollToBottom()) this.$emit('ai-response', msg) + // PR-CHAT-PARALLEL-CONFIRM: 本轮结束 → 若有排队消息, 自动发出 + this._flushQueuedSend() break } case 'error': msg.isStreaming = false this.isStreaming = false msg.content = (msg.content || '') + '\n[错误] ' + (data.message || '未知错误') + // PR-CHAT-PARALLEL-CONFIRM: 报错也算本轮结束, 排队消息照常发出 + this._flushQueuedSend() break case 'attachments': if (!msg.attachments) this.$set(msg, 'attachments', []) @@ -1748,6 +1799,8 @@ async sendStreamMessage(userMessage, attachments = []) { this.isStreaming = false this.$nextTick(() => this.scrollToBottom()) this.$emit('ai-response', msg) + // PR-CHAT-PARALLEL-CONFIRM: 本轮结束 → 若有排队消息, 自动发出 + this._flushQueuedSend() } try { @@ -1777,6 +1830,8 @@ async sendStreamMessage(userMessage, attachments = []) { } this.messages.push(errorMsg) this.$emit('ai-response', errorMsg) + // PR-CHAT-PARALLEL-CONFIRM: 请求失败也算本轮结束, 排队消息照常发出 + this._flushQueuedSend() } },