blob: 860505eb79d706ffee8d2f59787ca29a79441ff7 [file] [log] [blame]
208159515458d95702025-06-09 14:46:58 +08001<template>
2 <div class="chat-room">
20815951548db5f2a2025-06-09 23:58:33 +08003 <Navbar />
208159515458d95702025-06-09 14:46:58 +08004 <h2>聊天室</h2>
5 <div class="chat-messages" ref="messagesRef">
6 <div v-for="(msg, idx) in messages" :key="idx" class="chat-message">
7 <span class="chat-user">{{ msg.username || '匿名' }}:</span>
8 <span class="chat-content">{{ msg.content }}</span>
9 <span class="chat-time" v-if="msg.timestamp">({{ formatTime(msg.timestamp) }})</span>
10 </div>
11 </div>
12 <div class="chat-input">
13 <el-input v-model="input" placeholder="输入消息..." @keyup.enter="sendMessage" />
14 <el-button type="primary" @click="sendMessage">发送</el-button>
15 </div>
16 </div>
17</template>
18
19<script setup>
20import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
21import { useStore } from 'vuex'
22import axios from 'axios'
20815951548db5f2a2025-06-09 23:58:33 +080023import Navbar from "@/components/Navbar.vue";
208159515458d95702025-06-09 14:46:58 +080024
25const store = useStore()
26const wsUrl = 'ws://localhost:8081/api/ws/chat'
27const ws = ref(null)
28const messages = ref([])
29const input = ref('')
30const messagesRef = ref(null)
31
32function getToken() {
33 return localStorage.getItem('token')
34}
35
36function setCookie(name, value, days = 7) {
37 const expires = new Date()
38 expires.setTime(expires.getTime() + (days * 24 * 60 * 60 * 1000))
39 document.cookie = `${name}=${value};expires=${expires.toUTCString()};path=/`
40}
41
42// 获取聊天历史记录
43async function loadChatHistory() {
44 try {
45 const token = getToken()
46 if (!token) return
47
48 console.log('🔄 获取聊天历史记录...')
49 const response = await axios.get('http://localhost:8081/api/chat/history', {
50 params: { roomId: 1 },
51 headers: { 'sapling-token': token }
52 })
53
54 if (response.data && Array.isArray(response.data)) {
55 messages.value = response.data
56 console.log('📚 获取到', response.data.length, '条历史消息')
57
58 // 滚动到底部
59 nextTick(() => {
60 if (messagesRef.value) {
61 messagesRef.value.scrollTop = messagesRef.value.scrollHeight
62 }
63 })
64 }
65 } catch (error) {
66 console.error('❌ 获取聊天历史失败:', error)
67 }
68}
69
70function connect() {
71 const token = getToken()
72 if (!token) {
73 console.error('无法连接WebSocket:未找到token')
74 return
75 }
76
77 // 设置cookie,这样WebSocket握手时后端可以从cookie获取token
78 setCookie('sapling-token', token)
79
80 console.log('尝试连接WebSocket:', wsUrl)
81 console.log('已设置cookie: sapling-token =', token)
82
83 ws.value = new WebSocket(wsUrl)
84
85 ws.value.onopen = async () => {
86 console.log('✅ WebSocket连接成功')
87 // 连接成功后立即获取聊天历史
88 await loadChatHistory()
89 }
90
91 ws.value.onmessage = (event) => {
92 console.log('📥 收到消息:', event.data)
93 try {
94 const msg = JSON.parse(event.data)
95 console.log('📥 解析后的消息:', msg)
96 messages.value.push(msg)
97 nextTick(() => {
98 if (messagesRef.value) {
99 messagesRef.value.scrollTop = messagesRef.value.scrollHeight
100 }
101 })
102 } catch (e) {
103 console.error('❌ 消息解析失败:', e, event.data)
104 }
105 }
106
107 ws.value.onerror = (err) => {
108 console.error('❌ WebSocket错误:', err)
109 }
110
111 ws.value.onclose = (event) => {
112 console.log('❌ WebSocket已断开, 代码:', event.code, '原因:', event.reason)
113 setTimeout(() => {
114 console.log('🔄 尝试重连...')
115 connect()
116 }, 2000)
117 }
118}
119
120function sendMessage() {
121 if (!input.value.trim()) return
122
123 if (!ws.value || ws.value.readyState !== WebSocket.OPEN) {
124 console.error('❌ WebSocket未连接')
125 return
126 }
127
128 const message = {
129 roomId: 1, // 默认房间ID为1
130 content: input.value.trim()
131 }
132
133 console.log('📤 发送消息:', message)
134 ws.value.send(JSON.stringify(message))
135 input.value = ''
136}
137
138function formatTime(timestamp) {
139 return new Date(timestamp).toLocaleTimeString()
140}
141
142onMounted(() => {
143 console.log('🚀 聊天室组件已挂载')
144 connect()
145})
146
147onBeforeUnmount(() => {
148 console.log('🔌 组件卸载,关闭WebSocket连接')
149 if (ws.value) {
150 ws.value.close()
151 }
152})
153</script>
154
155<style scoped>
156.chat-room {
157 max-width: 600px;
158 margin: 40px auto;
159 border: 1px solid #eee;
160 border-radius: 8px;
161 padding: 24px;
162 background: #fff;
163}
164.chat-messages {
165 height: 320px;
166 overflow-y: auto;
167 border: 1px solid #f0f0f0;
168 border-radius: 4px;
169 padding: 12px;
170 margin-bottom: 16px;
171 background: #fafbfc;
172}
173.chat-message {
174 margin-bottom: 8px;
175}
176.chat-user {
177 font-weight: bold;
178 color: #409eff;
179}
180.chat-time {
181 color: #999;
182 font-size: 12px;
183 margin-left: 8px;
184}
185.chat-input {
186 display: flex;
187 gap: 8px;
188}
189</style>