Files
phone-app------test1-/stores/socket.js
2026-06-02 10:42:33 +08:00

353 lines
8.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}
})