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:
2025-07-17 18:10:45 +08:00
parent 9a3a8267b5
commit c77352877d
391 changed files with 46585 additions and 4294 deletions
-197
View File
@@ -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
}
})
-270
View File
@@ -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
}
})
-103
View File
@@ -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
}
})