diff --git a/pages/Chat/Chat.css b/pages/Chat/Chat.css index ea8f4e7..ee07b11 100644 --- a/pages/Chat/Chat.css +++ b/pages/Chat/Chat.css @@ -507,6 +507,10 @@ font-size: 48rpx; } +.chat-btn-group .head-btn:nth-child(4) { + /* 刷新按钮 */ +} + .log-out { /* background: #ffd4d4; */ } diff --git a/pages/Chat/Chat.vue b/pages/Chat/Chat.vue index 0206869..8d0b219 100644 --- a/pages/Chat/Chat.vue +++ b/pages/Chat/Chat.vue @@ -99,10 +99,13 @@ - - - - + + + + + + + @@ -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 uploadPhoto = () => { console.log('点击了拍照上传'); @@ -1368,7 +1436,10 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener. if (!oldVal && newVal) { console.log('AI开始回复(跨设备同步),锁定输入框'); isThinking.value = true - // 非本设备发起时,也需要添加流式气泡 + // 跨设备场景:先加载最新消息(含 PC 发的用户消息),再追加流式气泡 + if (!isSelfSent.value) { + await takeConversationMessages() + } if (!streamingMessageId.value) { streamingMessageId.value = 'streaming-' + Date.now() 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 回复(流式输出核心) watch(() => socketStore.messageString, (newContent) => { if (!streamingMessageId.value || !socketStore.isThinking) return diff --git a/stores/socket.js b/stores/socket.js index d51bf4a..941bfe0 100644 --- a/stores/socket.js +++ b/stores/socket.js @@ -30,6 +30,7 @@ export const useSocketStore = defineStore('socket', () => { const maxLogCount = ref(20) const authFailReason = ref('') + const pcOffline = ref(false) // ==================== 计算属性 ==================== const isConnected = computed(() => connectionStatus.value === 'connected') @@ -66,6 +67,7 @@ export const useSocketStore = defineStore('socket', () => { ...config.value, ...options } + pcOffline.value = false // 每次连接时重置 PC 离线标记 addLog('info', `准备连接WebSocket。Token:${config.value.token || '未设置'}。ConversationId: ${config.value.conversationId || '未设置'}` ) @@ -182,6 +184,7 @@ export const useSocketStore = defineStore('socket', () => { break case 'pc_offline': + pcOffline.value = true addLog('warn', 'PC 端已离线') break @@ -287,6 +290,7 @@ export const useSocketStore = defineStore('socket', () => { logs, config, authFailReason, + pcOffline, // 计算属性 isConnected,