From c4fb90b755e0b6fc1402aa595d28b179ec27910b Mon Sep 17 00:00:00 2001 From: hy <2503800130@qq.com> Date: Mon, 3 Aug 2026 17:29:25 +0800 Subject: [PATCH] =?UTF-8?q?Revert=20"=E5=B0=81=E7=AA=97"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 9965f2772deebc4ba271a6bd332ad6385d0761b1. --- pages/Chat/Chat.vue | 99 ++++++++++++++++++--------------------------- stores/socket.js | 95 +------------------------------------------ 2 files changed, 40 insertions(+), 154 deletions(-) diff --git a/pages/Chat/Chat.vue b/pages/Chat/Chat.vue index 58fd89e..06fdf82 100644 --- a/pages/Chat/Chat.vue +++ b/pages/Chat/Chat.vue @@ -825,61 +825,11 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener. const isThinking = ref(false) const isSelfSent = ref(false) // 是否当前设备发起的 AI 对话(用于区分弹窗/仅锁输入) - const programInputLocked = ref(false) const isUploading = ref(false) const isLoadingMessages = ref(false) // 消息加载中状态(仅会话变化时显示) const uploadedFiles = ref([]) const streamingMessageId = ref(null) // 流式消息的临时 ID,用于实时更新 AI 回复 - const ensureStreamingBubble = () => { - if (streamingMessageId.value) return - streamingMessageId.value = 'streaming-' + Date.now() - allmessages.value = [...allmessages.value, { - role: 'assistant', - content: '', - _streaming: true, - _id: streamingMessageId.value - }] - } - - const removeStreamingBubble = () => { - if (!streamingMessageId.value) return - allmessages.value = allmessages.value.filter(m => m._id !== streamingMessageId.value) - streamingMessageId.value = null - } - - const beginAiTurn = (selfSent = false) => { - programInputLocked.value = false - isThinking.value = true - socketStore.messageString = '' - socketStore.isThinking = true - isSelfSent.value = selfSent - ensureStreamingBubble() - } - - const cleanupAiTurn = async (options = {}) => { - programInputLocked.value = false - isThinking.value = false - isSelfSent.value = false - removeStreamingBubble() - if (options.refresh !== false) { - await takeConversationMessages() - } - } - - const finishAiTurn = async (options = {}) => { - await cleanupAiTurn(options) - socketStore.isThinking = false - } - - const keepProgramInputLocked = () => { - programInputLocked.value = true - isThinking.value = true - socketStore.isThinking = true - isSelfSent.value = false - ensureStreamingBubble() - } - // 消息详情弹窗 const showMessageModal = ref(false) const detailLinks = ref([]) @@ -1086,9 +1036,6 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener. const sendMessage = async () => { - if (isUploading.value) return - if (ChatType.value === 0 && isThinking.value) return - const message = textMessage.value.trim() if (!message && previewFileArray.value.length === 0) return @@ -1249,18 +1196,27 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener. "conversation_id": currentSessionId.value, "content": messageContent } - beginAiTurn(true) - await socketStore.send(data) + socketStore.send(data) + isThinking.value = true + isSelfSent.value = true // // 立即添加用户消息到列表(使用完整的 messageContent,包含文件信息) // allmessages.value = [...allmessages.value, { // role: 'user', // content: messageContent // }] + // 添加流式消息气泡(加载中状态) + streamingMessageId.value = 'streaming-' + Date.now() + allmessages.value = [...allmessages.value, { + role: 'assistant', + content: '', + _streaming: true, + _id: streamingMessageId.value + }] textMessage.value = '' uploadedFiles.value = [] scrollToBottom() } catch (error) { - await finishAiTurn({ refresh: false }) + isThinking.value = false uni.showToast({ title: `用户发送消息失败${error}`, icon: 'error' @@ -1280,7 +1236,16 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener. } catch (err) { console.error('中断指令发送失败:', err) } - await finishAiTurn({ refresh: false }) + // 移除流式消息占位 + if (streamingMessageId.value) { + allmessages.value = allmessages.value.filter(m => m._id !== streamingMessageId.value) + streamingMessageId.value = null + } + // 立即关闭弹窗,清除超时 + // clearTimeout(aiResponseTimer) + isThinking.value = false + socketStore.isThinking = false + isSelfSent.value = false textMessage.value = '' uploadedFiles.value = [] // takeConversationMessages 由后端中断确认驱动(见 handleBusinessMessage) @@ -1299,14 +1264,28 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener. console.log('AI开始回复(跨设备同步),锁定输入框'); isThinking.value = true // 非本设备发起时,也需要添加流式气泡 - ensureStreamingBubble() + if (!streamingMessageId.value) { + streamingMessageId.value = 'streaming-' + Date.now() + allmessages.value = [...allmessages.value, { + role: 'assistant', + content: '', + _streaming: true, + _id: streamingMessageId.value + }] + } return } // true → false:AI 回复结束或中断,解锁输入框并刷新消息列表 if (oldVal && !newVal) { console.log('AI回复结束(正常/中断),解锁并刷新消息列表'); // 移除流式消息气泡,从服务器加载完整消息 - cleanupAiTurn() + if (streamingMessageId.value) { + allmessages.value = allmessages.value.filter(m => m._id !== streamingMessageId.value) + streamingMessageId.value = null + } + takeConversationMessages() + isThinking.value = false + isSelfSent.value = false textMessage.value = '' uploadedFiles.value = [] } @@ -2037,4 +2016,4 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener. color: #fff; font-weight: 500; } - + \ No newline at end of file diff --git a/stores/socket.js b/stores/socket.js index ac1c49f..d51bf4a 100644 --- a/stores/socket.js +++ b/stores/socket.js @@ -161,21 +161,6 @@ export const useSocketStore = defineStore('socket', () => { // 调试日志:明确输出 type 和 data console.log(`[handleMessage] type = ${type}, data = ${JSON.stringify(data)}`); - const eventConversationId = - conversation_id || - data?.conversation_id || - data?.page?.conversation?.conversation_id || - data?.page?.conversation?.id || - '' - if ( - eventConversationId && - config.value.conversationId && - String(eventConversationId) !== String(config.value.conversationId) - ) { - addLog('info', `忽略非当前会话消息: ${eventConversationId}`) - return - } - switch (type) { case 'auth_ok': addLog('success', '连接成功') @@ -191,42 +176,6 @@ export const useSocketStore = defineStore('socket', () => { addLog('warn', 'AI成功收到用户发送的消息') break - case 'forbid_input': - addLog('warn', '收到封框指令') - isThinking.value = true - break - - case 'relieve_input': - addLog('warn', '收到解框指令') - isThinking.value = false - break - - case 'turn_status': { - const status = String(messageData.status || data?.status || '').toLowerCase() - if (status === 'locked') { - addLog('warn', '后端确认程序封框') - isThinking.value = true - } else if (status === 'finished' || status === 'cancelled' || status === 'unlocked' || status === 'relieved') { - addLog('warn', `后端确认当前轮结束/解框: ${status}`) - isThinking.value = false - } - break - } - - case 'prompt': - if ((messageData.info || data?.info) === '结束等待') { - addLog('warn', '收到结束等待信号') - isThinking.value = false - } - break - - case 'refresh': - if (messageData.page?.waiting === false || data?.page?.waiting === false) { - addLog('warn', 'refresh 确认 waiting=false,释放输入框') - isThinking.value = false - } - break - case 'render': addLog('warn', 'AI正在回复信息') handleBusinessMessage(data) @@ -234,8 +183,6 @@ export const useSocketStore = defineStore('socket', () => { case 'pc_offline': addLog('warn', 'PC 端已离线') - isThinking.value = false - authFailReason.value = 'pc offline' break default: @@ -282,46 +229,6 @@ export const useSocketStore = defineStore('socket', () => { // 处理 data 为对象的情况 if (!data || typeof data !== 'object') return - const msgType = String(data.type || '').trim() - if (msgType === 'forbid_input') { - console.log("收到后端封框指令"); - isThinking.value = true - return - } - if (msgType === 'relieve_input') { - console.log("收到后端解框指令"); - isThinking.value = false - return - } - - if (data.cmd === 'turn_status') { - const status = String(data.status || '').toLowerCase() - if (status === 'locked') { - console.log("后端确认程序封框"); - isThinking.value = true - return - } - if (status === 'finished' || status === 'cancelled' || status === 'unlocked' || status === 'relieved') { - console.log("后端确认当前轮结束/解框:", status); - isThinking.value = false - return - } - } - - if (data.cmd === 'prompt' && data.info === '结束等待') { - console.log("收到结束等待信号"); - isThinking.value = false - return - } - - // refresh 也会在流式输出和工具中间消息落盘时出现,不能直接当成最终完成。 - // 只有后端明确 page.waiting=false 时,才作为漏发结束信号的兜底释放。 - if (data.cmd === 'refresh' && data.page?.waiting === false) { - console.log("refresh 确认 waiting=false,释放输入框"); - isThinking.value = false - return - } - // 中断确认:后端返回 cmd=event_callback 表示中断成功 if (data.cmd === 'event_callback' && data.info === '中断成功') { console.log("后端确认中断成功"); @@ -396,4 +303,4 @@ export const useSocketStore = defineStore('socket', () => { clearLogs, getStatusText } -}) +}) \ No newline at end of file