298 lines
7.3 KiB
TypeScript
298 lines
7.3 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import { ref, computed } from 'vue'
|
|
import { io, type Socket } from 'socket.io-client'
|
|
|
|
export interface ChatMessage {
|
|
id: string
|
|
role: 'user' | 'assistant' | 'system'
|
|
content: string
|
|
timestamp: Date
|
|
metadata?: {
|
|
knowledge_used?: string[]
|
|
confidence_score?: number
|
|
work_order_id?: string
|
|
}
|
|
}
|
|
|
|
export interface ChatSession {
|
|
id: string
|
|
userId: string
|
|
workOrderId?: string
|
|
messages: ChatMessage[]
|
|
status: 'active' | 'ended'
|
|
createdAt: Date
|
|
}
|
|
|
|
export const useChatStore = defineStore('chat', () => {
|
|
// 状态
|
|
const socket = ref<Socket | null>(null)
|
|
const isConnected = ref(false)
|
|
const currentSession = ref<ChatSession | null>(null)
|
|
const messages = ref<ChatMessage[]>([])
|
|
const isTyping = ref(false)
|
|
const userId = ref('user_001')
|
|
const workOrderId = ref<string>('')
|
|
|
|
// 计算属性
|
|
const hasActiveSession = computed(() =>
|
|
currentSession.value && currentSession.value.status === 'active'
|
|
)
|
|
|
|
const messageCount = computed(() => messages.value.length)
|
|
|
|
// 动作
|
|
const connectWebSocket = () => {
|
|
return new Promise<void>((resolve, reject) => {
|
|
try {
|
|
socket.value = io('ws://localhost:8765', {
|
|
transports: ['websocket']
|
|
})
|
|
|
|
socket.value.on('connect', () => {
|
|
isConnected.value = true
|
|
resolve()
|
|
})
|
|
|
|
socket.value.on('disconnect', () => {
|
|
isConnected.value = false
|
|
})
|
|
|
|
socket.value.on('error', (error) => {
|
|
console.error('WebSocket error:', error)
|
|
reject(error)
|
|
})
|
|
|
|
socket.value.on('message_response', (data) => {
|
|
handleMessageResponse(data)
|
|
})
|
|
|
|
socket.value.on('typing_start', () => {
|
|
isTyping.value = true
|
|
})
|
|
|
|
socket.value.on('typing_end', () => {
|
|
isTyping.value = false
|
|
})
|
|
|
|
} catch (error) {
|
|
reject(error)
|
|
}
|
|
})
|
|
}
|
|
|
|
const disconnectWebSocket = () => {
|
|
if (socket.value) {
|
|
socket.value.disconnect()
|
|
socket.value = null
|
|
isConnected.value = false
|
|
}
|
|
}
|
|
|
|
const startChat = async () => {
|
|
try {
|
|
if (!socket.value) {
|
|
await connectWebSocket()
|
|
}
|
|
|
|
const response = await sendSocketMessage({
|
|
type: 'create_session',
|
|
user_id: userId.value,
|
|
work_order_id: workOrderId.value ? parseInt(workOrderId.value) : null
|
|
})
|
|
|
|
if (response.type === 'session_created') {
|
|
currentSession.value = {
|
|
id: response.session_id,
|
|
userId: userId.value,
|
|
workOrderId: workOrderId.value,
|
|
messages: [],
|
|
status: 'active',
|
|
createdAt: new Date()
|
|
}
|
|
|
|
addMessage('system', '对话已开始,请描述您的问题。')
|
|
return true
|
|
}
|
|
|
|
return false
|
|
} catch (error) {
|
|
console.error('启动对话失败:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
const endChat = async () => {
|
|
try {
|
|
if (currentSession.value) {
|
|
await sendSocketMessage({
|
|
type: 'end_session',
|
|
session_id: currentSession.value.id
|
|
})
|
|
|
|
currentSession.value.status = 'ended'
|
|
addMessage('system', '对话已结束。')
|
|
}
|
|
} catch (error) {
|
|
console.error('结束对话失败:', error)
|
|
}
|
|
}
|
|
|
|
const sendMessage = async (content: string) => {
|
|
if (!currentSession.value || !content.trim()) {
|
|
return
|
|
}
|
|
|
|
// 添加用户消息
|
|
addMessage('user', content)
|
|
|
|
try {
|
|
const response = await sendSocketMessage({
|
|
type: 'send_message',
|
|
session_id: currentSession.value.id,
|
|
message: content
|
|
})
|
|
|
|
if (response.type === 'message_response' && response.result.success) {
|
|
const result = response.result
|
|
|
|
// 添加助手回复
|
|
addMessage('assistant', result.content, {
|
|
knowledge_used: result.knowledge_used,
|
|
confidence_score: result.confidence_score,
|
|
work_order_id: result.work_order_id
|
|
})
|
|
|
|
// 更新工单ID
|
|
if (result.work_order_id) {
|
|
workOrderId.value = result.work_order_id.toString()
|
|
}
|
|
} else {
|
|
addMessage('assistant', '抱歉,我暂时无法处理您的问题。请稍后再试。')
|
|
}
|
|
} catch (error) {
|
|
console.error('发送消息失败:', error)
|
|
addMessage('assistant', '发送消息失败,请检查网络连接。')
|
|
}
|
|
}
|
|
|
|
const createWorkOrder = async (data: {
|
|
title: string
|
|
description: string
|
|
category: string
|
|
priority: string
|
|
}) => {
|
|
if (!currentSession.value) {
|
|
throw new Error('没有活跃的会话')
|
|
}
|
|
|
|
try {
|
|
const response = await sendSocketMessage({
|
|
type: 'create_work_order',
|
|
session_id: currentSession.value.id,
|
|
...data
|
|
})
|
|
|
|
if (response.type === 'work_order_created' && response.result.success) {
|
|
workOrderId.value = response.result.work_order_id.toString()
|
|
addMessage('system', `工单创建成功!工单号: ${response.result.order_id}`)
|
|
return response.result
|
|
} else {
|
|
throw new Error(response.result.error || '创建工单失败')
|
|
}
|
|
} catch (error) {
|
|
console.error('创建工单失败:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
const sendSocketMessage = (message: any): Promise<any> => {
|
|
return new Promise((resolve, reject) => {
|
|
if (!socket.value) {
|
|
reject(new Error('WebSocket未连接'))
|
|
return
|
|
}
|
|
|
|
const messageId = 'msg_' + Date.now()
|
|
message.messageId = messageId
|
|
|
|
const timeout = setTimeout(() => {
|
|
reject(new Error('请求超时'))
|
|
}, 10000)
|
|
|
|
const handleResponse = (data: any) => {
|
|
if (data.messageId === messageId) {
|
|
clearTimeout(timeout)
|
|
socket.value?.off('message_response', handleResponse)
|
|
resolve(data)
|
|
}
|
|
}
|
|
|
|
socket.value.on('message_response', handleResponse)
|
|
socket.value.emit('message', message)
|
|
})
|
|
}
|
|
|
|
const addMessage = (role: 'user' | 'assistant' | 'system', content: string, metadata?: any) => {
|
|
const message: ChatMessage = {
|
|
id: 'msg_' + Date.now() + '_' + Math.random(),
|
|
role,
|
|
content,
|
|
timestamp: new Date(),
|
|
metadata
|
|
}
|
|
|
|
messages.value.push(message)
|
|
|
|
if (currentSession.value) {
|
|
currentSession.value.messages.push(message)
|
|
}
|
|
}
|
|
|
|
const clearMessages = () => {
|
|
messages.value = []
|
|
if (currentSession.value) {
|
|
currentSession.value.messages = []
|
|
}
|
|
}
|
|
|
|
const setUserId = (id: string) => {
|
|
userId.value = id
|
|
}
|
|
|
|
const setWorkOrderId = (id: string) => {
|
|
workOrderId.value = id
|
|
}
|
|
|
|
const handleMessageResponse = (data: any) => {
|
|
// 处理WebSocket消息响应
|
|
console.log('收到消息响应:', data)
|
|
}
|
|
|
|
return {
|
|
// 状态
|
|
socket,
|
|
isConnected,
|
|
currentSession,
|
|
messages,
|
|
isTyping,
|
|
userId,
|
|
workOrderId,
|
|
|
|
// 计算属性
|
|
hasActiveSession,
|
|
messageCount,
|
|
|
|
// 动作
|
|
connectWebSocket,
|
|
disconnectWebSocket,
|
|
startChat,
|
|
endChat,
|
|
sendMessage,
|
|
createWorkOrder,
|
|
addMessage,
|
|
clearMessages,
|
|
setUserId,
|
|
setWorkOrderId
|
|
}
|
|
})
|