chore:新增AI智能问题是否合并回答/单独回答
This commit is contained in:
@@ -703,6 +703,10 @@ export default {
|
|||||||
streamInterval: null,
|
streamInterval: null,
|
||||||
streamContent: '',
|
streamContent: '',
|
||||||
isStreaming: false,
|
isStreaming: false,
|
||||||
|
// PR-CHAT-PARALLEL-CONFIRM (2026-09-23): AI 正在回答时又发新问题, 用户选"单独处理"
|
||||||
|
// → 该消息排队, 等本轮流式回答结束后自动发送
|
||||||
|
// (避免后端把"上一轮未完成的请求"和"新问题"并行/合并处理, 导致答非所问串题)
|
||||||
|
pendingSendAfterStream: false,
|
||||||
// 本地用户头像(优先使用缓存,无缓存则用默认图)
|
// 本地用户头像(优先使用缓存,无缓存则用默认图)
|
||||||
localUserAvatar: '',
|
localUserAvatar: '',
|
||||||
showAvatarSelector: false, // 头像选择弹窗控制
|
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 数组版
|
// PR-FRONTEND-MEDIA-UPLOAD-FIX (2026-09-16): pendingImages 数组版
|
||||||
// 原 pendingImage 单数, 改支持 1-9 张图一起发
|
// 原 pendingImage 单数, 改支持 1-9 张图一起发
|
||||||
@@ -1401,6 +1436,18 @@ async loadChatHistoryIfExist() {
|
|||||||
|
|
||||||
if (!hasContent && !hasEmoji && !allPending.length) return
|
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
|
// PR-FIX (2026-09-20): 手动发送消息后清掉欢迎气泡上的快捷问题 chips
|
||||||
// 原来只有点击 chip 才摘除, 用户手动打字发消息后 chips 一直挂着,
|
// 原来只有点击 chip 才摘除, 用户手动打字发消息后 chips 一直挂着,
|
||||||
// 与"引导一次性"的语义不符
|
// 与"引导一次性"的语义不符
|
||||||
@@ -1720,12 +1767,16 @@ async sendStreamMessage(userMessage, attachments = []) {
|
|||||||
}
|
}
|
||||||
this.$nextTick(() => this.scrollToBottom())
|
this.$nextTick(() => this.scrollToBottom())
|
||||||
this.$emit('ai-response', msg)
|
this.$emit('ai-response', msg)
|
||||||
|
// PR-CHAT-PARALLEL-CONFIRM: 本轮结束 → 若有排队消息, 自动发出
|
||||||
|
this._flushQueuedSend()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'error':
|
case 'error':
|
||||||
msg.isStreaming = false
|
msg.isStreaming = false
|
||||||
this.isStreaming = false
|
this.isStreaming = false
|
||||||
msg.content = (msg.content || '') + '\n[错误] ' + (data.message || '未知错误')
|
msg.content = (msg.content || '') + '\n[错误] ' + (data.message || '未知错误')
|
||||||
|
// PR-CHAT-PARALLEL-CONFIRM: 报错也算本轮结束, 排队消息照常发出
|
||||||
|
this._flushQueuedSend()
|
||||||
break
|
break
|
||||||
case 'attachments':
|
case 'attachments':
|
||||||
if (!msg.attachments) this.$set(msg, 'attachments', [])
|
if (!msg.attachments) this.$set(msg, 'attachments', [])
|
||||||
@@ -1748,6 +1799,8 @@ async sendStreamMessage(userMessage, attachments = []) {
|
|||||||
this.isStreaming = false
|
this.isStreaming = false
|
||||||
this.$nextTick(() => this.scrollToBottom())
|
this.$nextTick(() => this.scrollToBottom())
|
||||||
this.$emit('ai-response', msg)
|
this.$emit('ai-response', msg)
|
||||||
|
// PR-CHAT-PARALLEL-CONFIRM: 本轮结束 → 若有排队消息, 自动发出
|
||||||
|
this._flushQueuedSend()
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1777,6 +1830,8 @@ async sendStreamMessage(userMessage, attachments = []) {
|
|||||||
}
|
}
|
||||||
this.messages.push(errorMsg)
|
this.messages.push(errorMsg)
|
||||||
this.$emit('ai-response', errorMsg)
|
this.$emit('ai-response', errorMsg)
|
||||||
|
// PR-CHAT-PARALLEL-CONFIRM: 请求失败也算本轮结束, 排队消息照常发出
|
||||||
|
this._flushQueuedSend()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user