import { defineStore } from 'pinia' import { ref, watch } from 'vue' import type { ChatMessage, ChatSession } from '@/types' import webSocketService, { type WebSocketMessage, type ConnectionStatus } from '@/services/websocket' import { useUserStore } from './user' import { chatApi } from '@/services/chat' export const useChatStore = defineStore('chat', () => { const userStore = useUserStore() // 聊天状态 const currentSession = ref(null) const messages = ref([]) const sessions = ref([]) const isTyping = ref(false) const isConnected = ref(false) const connectionStatus = ref('DISCONNECTED') const wsConnected = ref(false) // 方法 const addMessage = (message: Omit) => { const newMessage: ChatMessage = { ...message, id: Date.now().toString(), timestamp: new Date().toISOString(), status: message.type === 'user' ? 'sending' : 'sent' } messages.value.push(newMessage) return newMessage } // 更新消息状态 const updateMessageStatus = (messageId: string, status: ChatMessage['status'], error?: string) => { const message = messages.value.find(m => m.id === messageId) if (message) { message.status = status if (error) { message.error = error } } } // 发送消息:WebSocket推送+数据库保存 const sendMessage = async (content: string) => { if (!wsConnected.value) { console.error('WebSocket未连接,无法发送消息') addMessage({ content: '连接已断开,请刷新页面重试。', type: 'ai', sessionId: currentSession.value?.id }) return } // 添加用户消息 const userMessage = addMessage({ content, type: 'user', sessionId: currentSession.value?.id }) try { // WebSocket推送 webSocketService.sendChatMessage(content, currentSession.value?.id) // 更新消息状态为已发送 updateMessageStatus(userMessage.id, 'sent') // 数据库保存 if (currentSession.value?.id && userStore.user?.id) { await chatApi.createMessage({ conversationId: currentSession.value.id, userId: userStore.user.id, content, contentType: 'TEXT', senderType: 'USER', senderId: userStore.user.id }) // 更新消息状态为已送达 updateMessageStatus(userMessage.id, 'delivered') } } catch (error) { console.error('消息发送或保存失败:', error) // 更新消息状态为失败 updateMessageStatus(userMessage.id, 'failed', '发送失败') addMessage({ content: '抱歉,消息发送失败,请稍后重试。', type: 'ai', sessionId: currentSession.value?.id }) } return userMessage } // 创建会话:同步后端 const createSession = async (title?: string) => { let newSession: ChatSession if (userStore.user?.id) { newSession = await chatApi.createSession(userStore.user.id, title || `对话${sessions.value.length + 1}`) } else { newSession = { id: Date.now().toString(), title: title || `对话${sessions.value.length + 1}`, createTime: new Date().toISOString(), updateTime: new Date().toISOString(), messageCount: 0 } } sessions.value.unshift(newSession) currentSession.value = newSession messages.value = [] // 如果WebSocket已连接,设置新的会话ID if (wsConnected.value) { webSocketService.setConversationId(newSession.id) } return newSession } // 切换会话:加载消息 const switchSession = async (sessionId: string) => { const session = sessions.value.find(s => s.id === sessionId) if (session) { currentSession.value = session await loadSessionMessages(sessionId) // 如果WebSocket已连接,更新会话ID if (wsConnected.value) { webSocketService.setConversationId(sessionId) } } } // 加载会话消息:从后端获取 const loadSessionMessages = async (sessionId: string) => { try { const msgs = await chatApi.getAllSessionMessages(sessionId) messages.value = msgs } catch (error) { console.error('Failed to load session messages:', error) messages.value = [] } } // 删除会话:同步后端 const deleteSession = async (sessionId: string) => { try { await chatApi.deleteSession(sessionId) const index = sessions.value.findIndex(s => s.id === sessionId) if (index > -1) { sessions.value.splice(index, 1) if (currentSession.value?.id === sessionId) { currentSession.value = sessions.value[0] || null if (currentSession.value) { await loadSessionMessages(currentSession.value.id) } else { messages.value = [] } } } } catch (error) { console.error('删除会话失败:', error) } } const clearMessages = () => { messages.value = [] } const searchMessages = (keyword: string) => { return messages.value.filter(message => message.content.toLowerCase().includes(keyword.toLowerCase()) ) } // 分割AI回复为多条消息 const splitAiReply = (content: string): string[] => { // 先按 \n\n 分割,再按 \n 分割 const segments = content.split(/\n\n|\n/).filter(segment => segment.trim().length > 0) return segments } // 添加AI回复消息(支持分段显示) const addAiReplyMessages = (content: string, delay: number = 1000) => { const segments = splitAiReply(content) segments.forEach((segment, index) => { setTimeout(() => { const aiMessage = addMessage({ content: segment.trim(), type: 'ai', sessionId: currentSession.value?.id }) // 强制触发响应式更新 console.log('AI消息已添加,当前消息总数:', messages.value.length) console.log('最新AI消息:', aiMessage) // 最后一条消息后停止输入状态 if (index === segments.length - 1) { isTyping.value = false } }, index * delay) }) } // WebSocket消息处理 const handleWebSocketMessage = (wsMessage: WebSocketMessage) => { console.log('收到WebSocket消息:', wsMessage.type, wsMessage.senderType) switch (wsMessage.type) { case 'TEXT': if (wsMessage.senderType === 'AI') { // AI回复消息 - 支持分段显示 addAiReplyMessages(wsMessage.content) } break case 'AI_THINKING': // AI正在思考 isTyping.value = true break case 'CONNECTION': // 连接状态消息 console.log('WebSocket连接状态:', wsMessage.content) break case 'ERROR': // 错误消息 addMessage({ content: wsMessage.content, type: 'ai', sessionId: currentSession.value?.id }) isTyping.value = false break case 'SYSTEM': // 系统消息 addMessage({ content: wsMessage.content, type: 'ai', sessionId: currentSession.value?.id }) break default: console.log('未处理的消息类型:', wsMessage.type) } } // WebSocket连接管理 const connectWebSocket = async () => { try { // 优先使用userInfo中的用户ID,如果没有则使用user中的ID const userId = userStore.userInfo?.id || userStore.user?.id || undefined await webSocketService.connect(userId, { onMessage: handleWebSocketMessage, onConnect: () => { console.log('WebSocket连接成功') wsConnected.value = true isConnected.value = true // 设置会话ID if (currentSession.value?.id) { webSocketService.setConversationId(currentSession.value.id) } }, onDisconnect: () => { console.log('WebSocket连接断开') wsConnected.value = false isConnected.value = false isTyping.value = false }, onError: (error) => { console.error('WebSocket错误:', error) wsConnected.value = false isConnected.value = false isTyping.value = false // 显示用户友好的错误信息 if (error.userMessage) { addMessage({ content: error.userMessage, type: 'ai', sessionId: currentSession.value?.id }) } }, onStatusChange: (status) => { connectionStatus.value = status isConnected.value = status === 'CONNECTED' } }) } catch (error) { console.error('WebSocket连接失败:', error) wsConnected.value = false isConnected.value = false } } const disconnectWebSocket = () => { webSocketService.disconnect() wsConnected.value = false isConnected.value = false isTyping.value = false } // 初始化 const initChat = async () => { // 如果没有会话,创建一个默认会话 if (sessions.value.length === 0) { await createSession('与开开的对话') } // 连接WebSocket await connectWebSocket() } // 监听会话变化,更新WebSocket会话ID watch(currentSession, (newSession) => { if (newSession?.id && wsConnected.value) { webSocketService.setConversationId(newSession.id) } }) return { // 状态 currentSession, messages, sessions, isTyping, isConnected, connectionStatus, wsConnected, // 方法 addMessage, sendMessage, createSession, switchSession, loadSessionMessages, deleteSession, clearMessages, searchMessages, initChat, connectWebSocket, disconnectWebSocket, handleWebSocketMessage } })