@@ -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;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
Reference in New Issue
Block a user