feat: 完成Nacos配置优化和WebSocket集成
主要更新: 1. 统一所有微服务端口配置(19000-19008) 2. 为所有服务创建本地/测试/生产三套环境配置 3. 配置Nacos认证密码(本地:Peanut2817*#, 测试/生产:EmotionMuseum2025) 4. 优化网关路由配置,支持负载均衡和WebSocket 5. 新增emotion-websocket模块,支持实时聊天 6. 前端集成WebSocket,替代HTTP轮询 7. 添加配置验证和管理工具脚本 技术特性: - 完整的环境隔离和服务发现 - WebSocket实时通信支持 - 负载均衡路由配置 - 跨域和安全配置 - 自动重连和心跳检测
This commit is contained in:
@@ -1,197 +0,0 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import { chatApi } from '@/api/chat'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
export const useChatStore = defineStore('chat', () => {
|
||||
const conversations = ref([])
|
||||
const currentConversation = ref(null)
|
||||
const messages = ref([])
|
||||
const loading = ref(false)
|
||||
const typing = ref(false)
|
||||
|
||||
// 计算属性
|
||||
const hasConversations = computed(() => conversations.value.length > 0)
|
||||
const currentConversationId = computed(() => currentConversation.value?.conversationId)
|
||||
|
||||
// 获取会话列表
|
||||
const fetchConversations = async (userId) => {
|
||||
try {
|
||||
const response = await chatApi.getConversations(userId)
|
||||
if (response.success) {
|
||||
conversations.value = response.data || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取会话列表失败:', error)
|
||||
message.error('获取会话列表失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新会话
|
||||
const createConversation = async (params) => {
|
||||
try {
|
||||
loading.value = true
|
||||
console.log('创建会话请求参数:', params)
|
||||
|
||||
const response = await chatApi.createConversation(params)
|
||||
console.log('创建会话响应:', response)
|
||||
|
||||
if (response.success) {
|
||||
const newConversation = response.data
|
||||
// 确保会话对象有必要的属性
|
||||
const conversation = {
|
||||
conversationId: newConversation.conversationId,
|
||||
userId: newConversation.userId,
|
||||
title: newConversation.title || '新对话',
|
||||
type: newConversation.type || 'emotion_chat',
|
||||
status: newConversation.status || 'active',
|
||||
createTime: newConversation.createTime || new Date().toISOString(),
|
||||
updateTime: newConversation.updateTime || new Date().toISOString(),
|
||||
messageCount: 0
|
||||
}
|
||||
|
||||
conversations.value.unshift(conversation)
|
||||
currentConversation.value = conversation
|
||||
messages.value = []
|
||||
return conversation
|
||||
}
|
||||
throw new Error(response.message || '创建会话失败')
|
||||
} catch (error) {
|
||||
console.error('创建会话失败:', error)
|
||||
message.error(error.message || '创建会话失败')
|
||||
throw error
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
const sendMessage = async (content, needEmotionAnalysis = true) => {
|
||||
if (!currentConversation.value) {
|
||||
message.error('请先创建会话')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
typing.value = true
|
||||
|
||||
// 添加用户消息到界面
|
||||
const userMessage = {
|
||||
id: `user_${Date.now()}`,
|
||||
content,
|
||||
sender: 'user',
|
||||
timestamp: new Date(),
|
||||
type: 'text'
|
||||
}
|
||||
messages.value.push(userMessage)
|
||||
console.log('添加用户消息:', userMessage)
|
||||
|
||||
// 发送到后端
|
||||
const requestData = {
|
||||
userId: currentConversation.value.userId,
|
||||
conversationId: currentConversation.value.conversationId,
|
||||
message: content,
|
||||
needEmotionAnalysis,
|
||||
type: 'text'
|
||||
}
|
||||
console.log('发送消息请求:', requestData)
|
||||
|
||||
const response = await chatApi.sendMessage(requestData)
|
||||
console.log('发送消息响应:', response)
|
||||
|
||||
if (response.success) {
|
||||
// 添加AI回复到界面
|
||||
const aiMessage = {
|
||||
id: response.data.messageId || `ai_${Date.now()}`,
|
||||
content: response.data.content,
|
||||
sender: 'assistant',
|
||||
timestamp: response.data.timestamp ? new Date(response.data.timestamp) : new Date(),
|
||||
type: response.data.type || 'text',
|
||||
emotionAnalysis: response.data.emotionAnalysis
|
||||
}
|
||||
messages.value.push(aiMessage)
|
||||
console.log('添加AI消息:', aiMessage)
|
||||
|
||||
// 更新会话的最后更新时间和消息数量
|
||||
if (currentConversation.value) {
|
||||
currentConversation.value.updateTime = new Date().toISOString()
|
||||
currentConversation.value.messageCount = (currentConversation.value.messageCount || 0) + 2
|
||||
}
|
||||
|
||||
return aiMessage
|
||||
}
|
||||
throw new Error(response.message || '发送消息失败')
|
||||
} catch (error) {
|
||||
console.error('发送消息失败:', error)
|
||||
message.error(error.message || '发送消息失败')
|
||||
|
||||
// 移除失败的用户消息
|
||||
messages.value = messages.value.filter(msg => msg.id !== `user_${Date.now()}`)
|
||||
throw error
|
||||
} finally {
|
||||
typing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取会话消息
|
||||
const fetchMessages = async (conversationId) => {
|
||||
try {
|
||||
loading.value = true
|
||||
const response = await chatApi.getMessages(conversationId)
|
||||
if (response.success) {
|
||||
messages.value = response.data || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取消息失败:', error)
|
||||
message.error('获取消息失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 切换会话
|
||||
const switchConversation = async (conversation) => {
|
||||
currentConversation.value = conversation
|
||||
await fetchMessages(conversation.conversationId)
|
||||
}
|
||||
|
||||
// 清空当前会话
|
||||
const clearCurrentConversation = () => {
|
||||
currentConversation.value = null
|
||||
messages.value = []
|
||||
}
|
||||
|
||||
// 删除会话
|
||||
const deleteConversation = async (conversationId) => {
|
||||
try {
|
||||
await chatApi.deleteConversation(conversationId)
|
||||
conversations.value = conversations.value.filter(c => c.conversationId !== conversationId)
|
||||
|
||||
if (currentConversation.value?.conversationId === conversationId) {
|
||||
clearCurrentConversation()
|
||||
}
|
||||
|
||||
message.success('删除成功')
|
||||
} catch (error) {
|
||||
console.error('删除会话失败:', error)
|
||||
message.error('删除会话失败')
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
conversations,
|
||||
currentConversation,
|
||||
messages,
|
||||
loading,
|
||||
typing,
|
||||
hasConversations,
|
||||
currentConversationId,
|
||||
fetchConversations,
|
||||
createConversation,
|
||||
sendMessage,
|
||||
fetchMessages,
|
||||
switchConversation,
|
||||
clearCurrentConversation,
|
||||
deleteConversation
|
||||
}
|
||||
})
|
||||
@@ -1,270 +0,0 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import { guestChatApi } from '@/api/chat'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
export const useGuestChatStore = defineStore('guestChat', () => {
|
||||
const conversations = ref([])
|
||||
const currentConversation = ref(null)
|
||||
const messages = ref([])
|
||||
const loading = ref(false)
|
||||
const typing = ref(false)
|
||||
const guestUserInfo = ref(null)
|
||||
|
||||
// 计算属性
|
||||
const hasConversations = computed(() => conversations.value.length > 0)
|
||||
const currentConversationId = computed(() => currentConversation.value?.conversationId)
|
||||
|
||||
// 获取或创建访客用户信息
|
||||
const getOrCreateGuestUser = async () => {
|
||||
try {
|
||||
const response = await guestChatApi.getGuestUserInfo()
|
||||
if (response.code === 200) {
|
||||
guestUserInfo.value = response.data
|
||||
return response.data
|
||||
}
|
||||
throw new Error(response.message || '获取访客用户信息失败')
|
||||
} catch (error) {
|
||||
console.error('获取访客用户信息失败:', error)
|
||||
// 不显示错误消息,因为这是自动调用的
|
||||
// message.error('获取访客用户信息失败')
|
||||
|
||||
// 创建一个默认的访客用户信息
|
||||
const defaultGuestUser = {
|
||||
id: `guest_${Date.now()}`,
|
||||
name: '访客用户',
|
||||
isGuest: true,
|
||||
createTime: new Date().toISOString()
|
||||
}
|
||||
guestUserInfo.value = defaultGuestUser
|
||||
return defaultGuestUser
|
||||
}
|
||||
}
|
||||
|
||||
// 获取访客会话列表
|
||||
const fetchConversations = async () => {
|
||||
try {
|
||||
const response = await guestChatApi.getGuestConversations()
|
||||
if (response.code === 200) {
|
||||
conversations.value = response.data || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取会话列表失败:', error)
|
||||
// 不显示错误消息,因为这是自动调用的
|
||||
// message.error('获取会话列表失败')
|
||||
conversations.value = []
|
||||
}
|
||||
}
|
||||
|
||||
// 发送访客聊天消息
|
||||
const sendMessage = async (content, title = null) => {
|
||||
try {
|
||||
typing.value = true
|
||||
|
||||
// 添加用户消息到界面
|
||||
const userMessage = {
|
||||
id: `user_${Date.now()}`,
|
||||
content,
|
||||
sender: 'user',
|
||||
timestamp: new Date(),
|
||||
type: 'text'
|
||||
}
|
||||
messages.value.push(userMessage)
|
||||
console.log('添加用户消息:', userMessage)
|
||||
|
||||
// 发送到后端
|
||||
const requestData = {
|
||||
message: content,
|
||||
title: title || (currentConversation.value ? null : `对话 ${new Date().toLocaleString()}`),
|
||||
messageType: 'text'
|
||||
}
|
||||
console.log('发送访客聊天请求:', requestData)
|
||||
|
||||
const response = await guestChatApi.guestChat(requestData)
|
||||
console.log('访客聊天响应:', response)
|
||||
|
||||
if (response.code === 200) {
|
||||
const data = response.data
|
||||
|
||||
// 如果是新会话,更新当前会话信息
|
||||
if (data.isNewConversation || !currentConversation.value) {
|
||||
const newConversation = {
|
||||
conversationId: data.conversationId,
|
||||
userId: data.guestUserId,
|
||||
title: data.conversationTitle || title || `对话 ${new Date().toLocaleString()}`,
|
||||
type: 'guest_chat',
|
||||
status: data.conversationStatus || 'active',
|
||||
createTime: data.timestamp || new Date().toISOString(),
|
||||
updateTime: data.timestamp || new Date().toISOString(),
|
||||
messageCount: 2
|
||||
}
|
||||
|
||||
currentConversation.value = newConversation
|
||||
|
||||
// 添加到会话列表(如果不存在)
|
||||
const existingIndex = conversations.value.findIndex(c => c.conversationId === newConversation.conversationId)
|
||||
if (existingIndex === -1) {
|
||||
conversations.value.unshift(newConversation)
|
||||
}
|
||||
}
|
||||
|
||||
// 更新用户消息ID
|
||||
if (data.userMessageId) {
|
||||
userMessage.id = data.userMessageId
|
||||
}
|
||||
|
||||
// 处理AI回复 - 支持多条消息
|
||||
if (data.multipleMessages && data.messageCount > 1) {
|
||||
// 多条消息的情况 - 从数据库获取最新消息
|
||||
console.log('检测到多条消息,从数据库获取最新消息')
|
||||
if (currentConversation.value) {
|
||||
await fetchMessages(currentConversation.value.conversationId)
|
||||
}
|
||||
} else {
|
||||
// 单条消息的情况 - 直接添加到界面
|
||||
const aiMessage = {
|
||||
id: data.aiMessageId || `ai_${Date.now()}`,
|
||||
content: data.aiReply,
|
||||
sender: 'assistant',
|
||||
timestamp: data.timestamp ? new Date(data.timestamp) : new Date(),
|
||||
type: 'text',
|
||||
emotionAnalysis: data.emotionAnalysis
|
||||
}
|
||||
messages.value.push(aiMessage)
|
||||
console.log('添加AI消息:', aiMessage)
|
||||
}
|
||||
|
||||
// 更新会话的最后更新时间和消息数量
|
||||
if (currentConversation.value) {
|
||||
currentConversation.value.updateTime = new Date().toISOString()
|
||||
currentConversation.value.messageCount = (currentConversation.value.messageCount || 0) + 2
|
||||
}
|
||||
|
||||
return aiMessage
|
||||
}
|
||||
throw new Error(response.message || '发送消息失败')
|
||||
} catch (error) {
|
||||
console.error('发送消息失败:', error)
|
||||
message.error(error.message || '发送消息失败')
|
||||
|
||||
// 移除失败的用户消息
|
||||
messages.value = messages.value.filter(msg => msg.id !== `user_${Date.now()}`)
|
||||
throw error
|
||||
} finally {
|
||||
typing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取会话消息
|
||||
const fetchMessages = async (conversationId) => {
|
||||
try {
|
||||
loading.value = true
|
||||
const response = await guestChatApi.getGuestConversationMessages(conversationId)
|
||||
if (response.code === 200) {
|
||||
const rawMessages = response.data || []
|
||||
// 转换消息格式以适配前端显示
|
||||
messages.value = rawMessages.map(msg => ({
|
||||
id: msg.messageId || msg.id,
|
||||
content: msg.content,
|
||||
sender: msg.sender === 'user' ? 'user' : 'assistant',
|
||||
timestamp: new Date(msg.timestamp),
|
||||
type: msg.type || 'text',
|
||||
emotionAnalysis: msg.emotionAnalysis ? {
|
||||
emotionType: msg.emotionType,
|
||||
emotionScore: msg.emotionScore,
|
||||
emotionConfidence: msg.emotionConfidence
|
||||
} : null
|
||||
}))
|
||||
console.log('获取到消息:', messages.value.length, '条')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取消息失败:', error)
|
||||
message.error('获取消息失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 切换会话
|
||||
const switchConversation = async (conversation) => {
|
||||
currentConversation.value = conversation
|
||||
await fetchMessages(conversation.conversationId)
|
||||
}
|
||||
|
||||
// 清空当前会话
|
||||
const clearCurrentConversation = () => {
|
||||
currentConversation.value = null
|
||||
messages.value = []
|
||||
}
|
||||
|
||||
// 结束会话
|
||||
const endConversation = async (conversationId) => {
|
||||
try {
|
||||
await guestChatApi.endGuestConversation(conversationId)
|
||||
|
||||
// 更新会话状态
|
||||
const conversation = conversations.value.find(c => c.conversationId === conversationId)
|
||||
if (conversation) {
|
||||
conversation.status = 'ended'
|
||||
}
|
||||
|
||||
if (currentConversation.value?.conversationId === conversationId) {
|
||||
clearCurrentConversation()
|
||||
}
|
||||
|
||||
message.success('会话已结束')
|
||||
} catch (error) {
|
||||
console.error('结束会话失败:', error)
|
||||
message.error('结束会话失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新会话(访客模式下通过发送第一条消息自动创建)
|
||||
const createNewConversation = () => {
|
||||
clearCurrentConversation()
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
// 初始化访客聊天
|
||||
const initGuestChat = async () => {
|
||||
try {
|
||||
await getOrCreateGuestUser()
|
||||
await fetchConversations()
|
||||
console.log('访客聊天初始化成功')
|
||||
} catch (error) {
|
||||
console.error('初始化访客聊天失败:', error)
|
||||
// 确保有基本的状态
|
||||
if (!guestUserInfo.value) {
|
||||
guestUserInfo.value = {
|
||||
id: `guest_${Date.now()}`,
|
||||
name: '访客用户',
|
||||
isGuest: true,
|
||||
createTime: new Date().toISOString()
|
||||
}
|
||||
}
|
||||
if (!conversations.value) {
|
||||
conversations.value = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
conversations,
|
||||
currentConversation,
|
||||
messages,
|
||||
loading,
|
||||
typing,
|
||||
guestUserInfo,
|
||||
hasConversations,
|
||||
currentConversationId,
|
||||
getOrCreateGuestUser,
|
||||
fetchConversations,
|
||||
sendMessage,
|
||||
fetchMessages,
|
||||
switchConversation,
|
||||
clearCurrentConversation,
|
||||
endConversation,
|
||||
createNewConversation,
|
||||
initGuestChat
|
||||
}
|
||||
})
|
||||
@@ -1,103 +0,0 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export const useUserStore = defineStore('user', () => {
|
||||
const userInfo = ref({
|
||||
id: '',
|
||||
name: '',
|
||||
avatar: ''
|
||||
})
|
||||
|
||||
const isLoggedIn = ref(false)
|
||||
|
||||
// 初始化用户信息
|
||||
const initUser = () => {
|
||||
try {
|
||||
// 从localStorage获取用户信息
|
||||
const savedUser = localStorage.getItem('emotion_museum_user')
|
||||
if (savedUser) {
|
||||
try {
|
||||
const user = JSON.parse(savedUser)
|
||||
userInfo.value = user
|
||||
// 只有非访客用户才算真正登录
|
||||
isLoggedIn.value = !user.isGuest
|
||||
console.log('用户信息已加载:', user.name || '访客用户')
|
||||
} catch (parseError) {
|
||||
console.warn('解析用户信息失败,使用访客模式:', parseError)
|
||||
// 清除无效数据
|
||||
localStorage.removeItem('emotion_museum_user')
|
||||
setGuestMode()
|
||||
}
|
||||
} else {
|
||||
// 访客模式 - 不设置用户信息,保持未登录状态
|
||||
setGuestMode()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('初始化用户信息失败:', error)
|
||||
setGuestMode()
|
||||
}
|
||||
}
|
||||
|
||||
// 设置访客模式
|
||||
const setGuestMode = () => {
|
||||
userInfo.value = {
|
||||
id: `guest_${Date.now()}`,
|
||||
name: '访客用户',
|
||||
avatar: '',
|
||||
isGuest: true
|
||||
}
|
||||
isLoggedIn.value = false
|
||||
console.log('已切换到访客模式')
|
||||
}
|
||||
|
||||
// 设置用户信息
|
||||
const setUser = (user) => {
|
||||
userInfo.value = {
|
||||
...user,
|
||||
isGuest: false
|
||||
}
|
||||
isLoggedIn.value = true
|
||||
localStorage.setItem('emotion_museum_user', JSON.stringify(userInfo.value))
|
||||
}
|
||||
|
||||
// 清除用户信息
|
||||
const clearUser = () => {
|
||||
userInfo.value = {
|
||||
id: '',
|
||||
name: '',
|
||||
avatar: ''
|
||||
}
|
||||
isLoggedIn.value = false
|
||||
localStorage.removeItem('emotion_museum_user')
|
||||
localStorage.removeItem('token')
|
||||
localStorage.removeItem('refreshToken')
|
||||
}
|
||||
|
||||
// 登出
|
||||
const logout = async () => {
|
||||
try {
|
||||
// 如果是登录用户,调用后端登出接口
|
||||
if (isLoggedIn.value && userInfo.value.id) {
|
||||
const { userApi } = await import('@/api/user')
|
||||
await userApi.logout(userInfo.value.id)
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('登出接口调用失败:', error)
|
||||
} finally {
|
||||
// 清除本地状态
|
||||
clearUser()
|
||||
// 切换到访客模式
|
||||
setGuestMode()
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
userInfo,
|
||||
isLoggedIn,
|
||||
initUser,
|
||||
setUser,
|
||||
clearUser,
|
||||
setGuestMode,
|
||||
logout
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user