两端同步流式输出,刷新状态,强制退出。
This commit is contained in:
@@ -507,6 +507,10 @@
|
|||||||
font-size: 48rpx;
|
font-size: 48rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-btn-group .head-btn:nth-child(4) {
|
||||||
|
/* 刷新按钮 */
|
||||||
|
}
|
||||||
|
|
||||||
.log-out {
|
.log-out {
|
||||||
/* background: #ffd4d4; */
|
/* background: #ffd4d4; */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,9 @@
|
|||||||
<view class="head-btn" @click="goCloudDatabase">
|
<view class="head-btn" @click="goCloudDatabase">
|
||||||
<view class="iconfont icon-cloud"></view>
|
<view class="iconfont icon-cloud"></view>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="head-btn" @click="handleRefresh">
|
||||||
|
<uni-icons type="refreshempty" size="24" color="#52c41a"></uni-icons>
|
||||||
|
</view>
|
||||||
<view class="head-btn log-out" @click="logOut">
|
<view class="head-btn log-out" @click="logOut">
|
||||||
<view class="iconfont icon-tuichu"></view>
|
<view class="iconfont icon-tuichu"></view>
|
||||||
</view>
|
</view>
|
||||||
@@ -839,6 +842,71 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener.
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 刷新当前会话消息
|
||||||
|
const handleRefresh = async () => {
|
||||||
|
// 1. 重置输入框状态
|
||||||
|
isThinking.value = false
|
||||||
|
isSelfSent.value = false
|
||||||
|
socketStore.isThinking = false
|
||||||
|
textMessage.value = ''
|
||||||
|
uploadedFiles.value = []
|
||||||
|
previewFileArray.value = []
|
||||||
|
// 移除流式消息占位
|
||||||
|
if (streamingMessageId.value) {
|
||||||
|
allmessages.value = allmessages.value.filter(m => m._id !== streamingMessageId.value)
|
||||||
|
streamingMessageId.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const titleMap = { 0: 'AI消息', 1: '好友消息', 2: '群聊消息' }
|
||||||
|
const title = titleMap[ChatType.value] || '消息'
|
||||||
|
uni.showLoading({ title: `刷新${title}中...`, mask: true })
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 2. 检查当前 token 是否还有效
|
||||||
|
const token = getToken()
|
||||||
|
if (!token) {
|
||||||
|
uni.hideLoading()
|
||||||
|
uni.showToast({ title: '登录已失效,请重新登录', icon: 'none', duration: 1500 })
|
||||||
|
setTimeout(() => uni.reLaunch({ url: '/pages/Login/Login' }), 1500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await getUserInfo(token)
|
||||||
|
|
||||||
|
// 3. 确保 AI 对话模式下 socket 连接正常(PC 离线由 watcher 实时监控)
|
||||||
|
if (ChatType.value === 0 && !socketStore.isConnected) {
|
||||||
|
await handleConnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 刷新消息
|
||||||
|
switch (ChatType.value) {
|
||||||
|
case 0:
|
||||||
|
await takeConversationMessages()
|
||||||
|
break
|
||||||
|
case 1:
|
||||||
|
await takeFriendMessages()
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
await takeGroupMessages()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
await takeConversationMessages()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
uni.hideLoading()
|
||||||
|
uni.showToast({ title: '已刷新', icon: 'success', duration: 1200 })
|
||||||
|
} catch (e) {
|
||||||
|
uni.hideLoading()
|
||||||
|
// 区分 token 失效和其他错误
|
||||||
|
const errMsg = typeof e === 'string' ? e : (e?.message || '')
|
||||||
|
if (errMsg.includes('token') || errMsg.includes('Token') || errMsg.includes('登录') || errMsg.includes('过期')) {
|
||||||
|
uni.showToast({ title: '登录已失效,请重新登录', icon: 'none', duration: 1500 })
|
||||||
|
setTimeout(() => uni.reLaunch({ url: '/pages/Login/Login' }), 1500)
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: '刷新失败', icon: 'error', duration: 1500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const previewFileArray = ref([])
|
const previewFileArray = ref([])
|
||||||
const uploadPhoto = () => {
|
const uploadPhoto = () => {
|
||||||
console.log('点击了拍照上传');
|
console.log('点击了拍照上传');
|
||||||
@@ -1368,7 +1436,10 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener.
|
|||||||
if (!oldVal && newVal) {
|
if (!oldVal && newVal) {
|
||||||
console.log('AI开始回复(跨设备同步),锁定输入框');
|
console.log('AI开始回复(跨设备同步),锁定输入框');
|
||||||
isThinking.value = true
|
isThinking.value = true
|
||||||
// 非本设备发起时,也需要添加流式气泡
|
// 跨设备场景:先加载最新消息(含 PC 发的用户消息),再追加流式气泡
|
||||||
|
if (!isSelfSent.value) {
|
||||||
|
await takeConversationMessages()
|
||||||
|
}
|
||||||
if (!streamingMessageId.value) {
|
if (!streamingMessageId.value) {
|
||||||
streamingMessageId.value = 'streaming-' + Date.now()
|
streamingMessageId.value = 'streaming-' + Date.now()
|
||||||
allmessages.value = [...allmessages.value, {
|
allmessages.value = [...allmessages.value, {
|
||||||
@@ -1416,6 +1487,25 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener.
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 监听 pc_offline,PC 端下线时立即强制跳转登录页
|
||||||
|
watch(() => socketStore.pcOffline, (offline) => {
|
||||||
|
if (offline) {
|
||||||
|
isThinking.value = false
|
||||||
|
socketStore.isThinking = false
|
||||||
|
socketStore.pcOffline = false
|
||||||
|
uni.showToast({
|
||||||
|
title: 'PC端不在线,请先登录',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 1500
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/Login/Login'
|
||||||
|
})
|
||||||
|
}, 1500)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 监听流式消息内容,实时更新 AI 回复(流式输出核心)
|
// 监听流式消息内容,实时更新 AI 回复(流式输出核心)
|
||||||
watch(() => socketStore.messageString, (newContent) => {
|
watch(() => socketStore.messageString, (newContent) => {
|
||||||
if (!streamingMessageId.value || !socketStore.isThinking) return
|
if (!streamingMessageId.value || !socketStore.isThinking) return
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export const useSocketStore = defineStore('socket', () => {
|
|||||||
const maxLogCount = ref(20)
|
const maxLogCount = ref(20)
|
||||||
|
|
||||||
const authFailReason = ref('')
|
const authFailReason = ref('')
|
||||||
|
const pcOffline = ref(false)
|
||||||
|
|
||||||
// ==================== 计算属性 ====================
|
// ==================== 计算属性 ====================
|
||||||
const isConnected = computed(() => connectionStatus.value === 'connected')
|
const isConnected = computed(() => connectionStatus.value === 'connected')
|
||||||
@@ -66,6 +67,7 @@ export const useSocketStore = defineStore('socket', () => {
|
|||||||
...config.value,
|
...config.value,
|
||||||
...options
|
...options
|
||||||
}
|
}
|
||||||
|
pcOffline.value = false // 每次连接时重置 PC 离线标记
|
||||||
addLog('info',
|
addLog('info',
|
||||||
`准备连接WebSocket。Token:${config.value.token || '未设置'}。ConversationId: ${config.value.conversationId || '未设置'}`
|
`准备连接WebSocket。Token:${config.value.token || '未设置'}。ConversationId: ${config.value.conversationId || '未设置'}`
|
||||||
)
|
)
|
||||||
@@ -182,6 +184,7 @@ export const useSocketStore = defineStore('socket', () => {
|
|||||||
break
|
break
|
||||||
|
|
||||||
case 'pc_offline':
|
case 'pc_offline':
|
||||||
|
pcOffline.value = true
|
||||||
addLog('warn', 'PC 端已离线')
|
addLog('warn', 'PC 端已离线')
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -287,6 +290,7 @@ export const useSocketStore = defineStore('socket', () => {
|
|||||||
logs,
|
logs,
|
||||||
config,
|
config,
|
||||||
authFailReason,
|
authFailReason,
|
||||||
|
pcOffline,
|
||||||
|
|
||||||
// 计算属性
|
// 计算属性
|
||||||
isConnected,
|
isConnected,
|
||||||
|
|||||||
Reference in New Issue
Block a user