first commit
This commit is contained in:
255
stores/friend-socket.js
Normal file
255
stores/friend-socket.js
Normal file
@@ -0,0 +1,255 @@
|
||||
import {
|
||||
defineStore
|
||||
} from "pinia";
|
||||
import {
|
||||
computed,
|
||||
ref
|
||||
} from "vue";
|
||||
|
||||
import {
|
||||
friendSocketManager
|
||||
} from '@/utils/friend-socket.js'
|
||||
import {
|
||||
getToken,
|
||||
getUserId
|
||||
} from "../utils/user-info";
|
||||
|
||||
export const useFriendSocketStore = defineStore('friendSocket', () => {
|
||||
// ==================== 状态定义 ====================
|
||||
const connectionStatus = ref('disconnected') //connecting | connected | disconnected | error
|
||||
const messages = ref([])
|
||||
const messageString = ref('')
|
||||
const config = ref({
|
||||
token: '',
|
||||
UserId: ''
|
||||
})
|
||||
const taskCallId = ref('')
|
||||
const command = ref(null)
|
||||
const groupId = ref(null)
|
||||
// 收到消息
|
||||
const MessageReceived = ref(false)
|
||||
|
||||
|
||||
// 日志数组和最大值
|
||||
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',
|
||||
`准备连接FriendsWebSocket。Token:${config.value.token || '未设置'}。UserId: ${config.value.UserId || '未设置'}`
|
||||
)
|
||||
if (!config.value.token || !config.value.UserId) {
|
||||
addLog('error', 'Token和UserId都不能为空')
|
||||
return
|
||||
}
|
||||
connectionStatus.value = 'connecting'
|
||||
|
||||
friendSocketManager.connect({
|
||||
token: config.value.token,
|
||||
UserId: config.value.UserId,
|
||||
onMessage: handleMessage,
|
||||
onError: handleError,
|
||||
onOpen: handleOpen,
|
||||
onClose: handleClose,
|
||||
onReconnect: handleReconnecting
|
||||
})
|
||||
|
||||
setConnectionTimeout()
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
friendSocketManager.close()
|
||||
connectionStatus.value = 'disconnected'
|
||||
addLog('warn', '已主动断开连接')
|
||||
}
|
||||
|
||||
async function send(message) {
|
||||
if (!isConnected.value) {
|
||||
addLog('error', '发送失败: 连接未建立')
|
||||
throw new Error('连接未建立')
|
||||
}
|
||||
try {
|
||||
await friendSocketManager.send(message)
|
||||
addLog('send', typeof message === 'string' ? message : JSON.stringify(message))
|
||||
return true
|
||||
} catch (error) {
|
||||
addLog('error', `发送失败: ${error.message || error}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// =====================连接成功发送验证标识,指令为7===============
|
||||
async function sendAuthData() {
|
||||
const userId = getUserId()
|
||||
const authData = {
|
||||
"version": "1.1",
|
||||
"body": {
|
||||
"command": 7,
|
||||
"sender": userId,
|
||||
"avatar": "",
|
||||
"sessionId": "",
|
||||
"message": "",
|
||||
"callBackMessage": false,
|
||||
}
|
||||
}
|
||||
try {
|
||||
await friendSocketManager.send(authData)
|
||||
addLog('send', typeof authData === 'string' ? authData : JSON.stringify(authData))
|
||||
return true
|
||||
} catch (error) {
|
||||
addLog('error', `发送验证失败: ${error.message || error}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 事件回调 ====================
|
||||
function handleOpen() {
|
||||
connectionStatus.value = 'connected'
|
||||
addLog('success', '连接成功!')
|
||||
sendAuthData()
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
if (connectionStatus.value !== 'disconnected') {
|
||||
// disconnect()
|
||||
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 msgBody = messageData.body || messageData;
|
||||
|
||||
// command 和 groupId和响应式变量重名冲突,直接解构时重命名
|
||||
const {
|
||||
callBackMessage,
|
||||
groupName,
|
||||
command: msgCommand,
|
||||
groupId: msgGroupId
|
||||
} = msgBody || {}
|
||||
|
||||
switch (msgCommand) {
|
||||
case 3:
|
||||
command.value = msgCommand
|
||||
groupId.value = msgGroupId
|
||||
break
|
||||
|
||||
case 7:
|
||||
command.value = msgCommand
|
||||
break
|
||||
|
||||
case 1:
|
||||
console.log("有好友消息");
|
||||
MessageReceived.value = true
|
||||
break
|
||||
|
||||
case 9:
|
||||
console.log("群消息发送成功/有新群消息");
|
||||
MessageReceived.value = true
|
||||
break
|
||||
|
||||
default:
|
||||
addLog('info', `未知事件类型`)
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 状态查询 ====================
|
||||
function getStatusText() {
|
||||
const statusMap = {
|
||||
connecting: '连接中',
|
||||
connected: '已连接',
|
||||
disconnected: '未连接',
|
||||
error: '连接错误'
|
||||
}
|
||||
return statusMap[connectionStatus.value] || '未知状态'
|
||||
}
|
||||
|
||||
function getReadyState() {
|
||||
return friendSocketManager.getReadyState()
|
||||
}
|
||||
|
||||
// ==================== 导出 ====================
|
||||
return {
|
||||
// 状态
|
||||
connectionStatus,
|
||||
//属性变量
|
||||
messageString,
|
||||
logs,
|
||||
config,
|
||||
command,
|
||||
groupId,
|
||||
MessageReceived,
|
||||
|
||||
// 计算属性
|
||||
isConnected,
|
||||
isConnecting,
|
||||
isDisconnected,
|
||||
isError,
|
||||
lastMessage,
|
||||
|
||||
// 方法
|
||||
connect,
|
||||
disconnect,
|
||||
send,
|
||||
addLog,
|
||||
clearLogs,
|
||||
getStatusText
|
||||
}
|
||||
})
|
||||
353
stores/socket.js
Normal file
353
stores/socket.js
Normal file
@@ -0,0 +1,353 @@
|
||||
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
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user