import { defineStore } from "pinia"; import { computed, ref } from "vue"; import { socketManager } from '@/utils/socket.js' import { getToken } from "../utils/user-info"; export const useSocketStore = defineStore('socket', () => { // ==================== 状态定义 ==================== const connectionStatus = ref('disconnected') //connecting | connected | disconnected | error const messages = ref([]) const messageString = ref('') const isThinking = ref(false) const config = ref({ token: '', conversationId: '' }) const taskCallId = ref('') // 日志数组和最大值 const logs = ref([]) const maxLogCount = ref(20) // ==================== 计算属性 ==================== const isConnected = computed(() => connectionStatus.value === 'connected') const isConnecting = computed(() => connectionStatus.value === 'connecting') const isDisconnected = computed(() => connectionStatus.value === 'disconnected') const isError = computed(() => connectionStatus.value === 'error') const lastMessage = computed(() => messages.value[messages.value.length - 1]) // 日志方法 function addLog(type, connect) { const now = new Date() const time = `${now.getHours().toString().padStart(2,'0')}:${now.getMinutes().toString().padStart(2,'0')}:${now.getSeconds().toString().padStart(2,'0')}` logs.value.push({ type, connect, time }) if (logs.value.length > maxLogCount.value) { logs.value = logs.value.slice(-maxLogCount.value) } console.log(`[${type.toUpperCase()}] ${connect}`); } function clearLogs() { logs.value = [] } // ==================== 连接相关方法 ==================== function connect(options = {}) { messages.value = [] messageString.value = '' config.value = { ...config.value, ...options } addLog('info', `准备连接WebSocket。Token:${config.value.token || '未设置'}。ConversationId: ${config.value.conversationId || '未设置'}` ) if (!config.value.token || !config.value.conversationId) { addLog('error', 'Token和ConversationId都不能为空') return } connectionStatus.value = 'connecting' socketManager.connect({ token: config.value.token, conversationId: config.value.conversationId, onMessage: handleMessage, onError: handleError, onOpen: handleOpen, onClose: handleClose, onReconnect: handleReconnecting }) setConnectionTimeout() } function disconnect() { socketManager.close() connectionStatus.value = 'disconnected' addLog('warn', '已主动断开连接') } async function send(message) { console.log("检查到要发生消息为:",message); if (!isConnected.value) { addLog('error', '发送失败: 连接未建立') throw new Error('连接未建立') } try { await socketManager.send(message) addLog('send', typeof message === 'string' ? message : JSON.stringify(message)) return true } catch (error) { addLog('error', `发送失败: ${error.message || error}`) throw error } } // ==================== 事件回调 ==================== function handleOpen() { connectionStatus.value = 'connected' addLog('success', '连接成功!发送auth') console.log('连接成功!发送auth'); sendAuth() } function handleClose() { if (connectionStatus.value !== 'disconnected') { connectionStatus.value = 'disconnected' addLog('warn', '连接已断开') } } function handleError(error) { addLog('error', `Socket错误: ${JSON.stringify(error)}`) connectionStatus.value = 'error' } function handleReconnecting(attempts) { connectionStatus.value = 'connecting' addLog('warn', `重连中... (${attempts}/5)`) } function setConnectionTimeout() { const timer = setTimeout(() => { if (connectionStatus.value === 'connecting') { connectionStatus.value = 'error' addLog('error', '连接超时(10s)') } }, 10000) // 返回 timer 以便必要时清除,但目前用不到 return timer } // function handleMessage(messageData) { // addLog('receive', `收到: ${JSON.stringify(messageData)}`) // const { // ws_event, // queue, // data // } = messageData || {} // if (data?.task_call_id) { // taskCallId.value = data.task_call_id // uni.setStorageSync('taskCallId', data.task_call_id) // } // switch (ws_event) { // case 'connect': // addLog('success', '连接成功') // handleBindConversation(messageData) // break // case 'disconnect': // addLog('warn', '收到服务端断开指令') // disconnect() // break // case 'message': // handleBusinessMessage(messageData) // break // default: // addLog('info', `未知事件类型: ${ws_event}`) // } // } function handleMessage(messageData) { addLog('receive', `收到: ${JSON.stringify(messageData)}`) const { type, conversation_id, message_id, data } = messageData || {} // 调试日志:明确输出 type 和 data console.log('[handleMessage] type =', type, ', data =', JSON.stringify(data)); switch (type) { case 'auth_ok': addLog('success', '连接成功') break case 'chat_ack': addLog('warn', 'AI成功收到用户发送的消息') break case 'render': addLog('warn', 'AI正在回复信息') handleBusinessMessage(data) break default: addLog('info', `未知事件类型: ${type}`) } } // ==================== 消息处理 ==================== function sendAuth() { config.value.token socketManager.send({ "type": "auth", "access_token": config.value.token }) } function handleBindConversation(messageData) { // 管理绑定对话,// 发送"task_call_id","token""conversation_id" const { ws_event, queue, data } = messageData || {} if (data?.task_call_id) { socketManager.send({ "ws_event": "message", "data": { "task_call_id": taskCallId.value, "token": config.value.token, "conversation_id": config.value.conversationId, }, }) } } // function handleBusinessMessage(messageData) { // const { // ws_event, // queue, // data // } = messageData // const messageContent = data?.content || data?.chunk || '' // // 调用工具 // if (data?.cmd === 'list_tools' || data?.cmd === 'catalog') { // socketManager.send({ // "ws_event": "message", // "data": { // "task_call_id": taskCallId.value, // "result": { // "tools": [] // } // }, // }) // addLog('info', `调用工具: ${data?.module}`) // return // } // // 消息事件:渲染队列的业务消息 // if (ws_event === 'message' && queue === 'render') { // messageString.value += messageContent // // 有任务ID时,自动回复消息确认包 // if (data.task_call_id) { // socketManager.send({ // "ws_event": "message", // "data": { // "task_call_id": taskCallId.value // } // }).catch(err => console.error('发送确认失败:', err)) // } // } // } function handleBusinessMessage(data) { // 处理 data 为字符串 "exit" 的情况 if (data === "exit") { console.log("ai结束思考"); isThinking.value = false return } // 处理 data 为对象的情况 if (!data || typeof data !== 'object') return const { role, chunk, message_role, meaasge_uuid, message_type, task_call_id } = data // ai 开始回复:首次收到 chunk 或 message_role 为 assistant 时 if (!isThinking.value && (chunk || message_role === 'assistant')) { console.log("ai开始思考"); messageString.value = '' isThinking.value = true } if (chunk) { // 拼接 ai 回复的内容 messageString.value += chunk } } // ==================== 状态查询 ==================== function getStatusText() { const statusMap = { connecting: '连接中', connected: '已连接', disconnected: '未连接', error: '连接错误' } return statusMap[connectionStatus.value] || '未知状态' } function getReadyState() { return socketManager.getReadyState() } // ==================== 导出 ==================== return { // 状态 connectionStatus, messageString, isThinking, logs, config, // 计算属性 isConnected, isConnecting, isDisconnected, isError, lastMessage, // 方法 connect, disconnect, send, addLog, clearLogs, getStatusText } })