Files
urbanLifeline/urbanLifelineWeb/packages/workcase/src/views/public/ChatRoom/ChatRoomView.vue

652 lines
23 KiB
Vue
Raw Normal View History

2025-12-20 18:52:33 +08:00
<template>
<div class="chat-room-container">
2025-12-23 19:15:00 +08:00
<!-- 折叠状态的侧边栏 -->
<div v-if="!isSidebarOpen" class="sidebar-collapsed">
<button class="sidebar-toggle-btn" @click="toggleSidebar" title="展开聊天室列表">
<MessageCircle :size="20" />
</button>
<div class="sidebar-icons">
<button
v-for="room in filteredRooms.slice(0, 8)"
:key="room.roomId"
2025-12-24 16:32:06 +08:00
@click="selectRoom(room)"
2025-12-23 19:15:00 +08:00
class="sidebar-icon-btn"
:class="{ active: currentRoomId === room.roomId }"
:title="room.roomName"
>
{{ room.guestName?.substring(0, 1) || '?' }}
</button>
2025-12-20 18:52:33 +08:00
</div>
2025-12-23 19:15:00 +08:00
<button class="expand-btn" @click="toggleSidebar" title="展开聊天室列表">
<ChevronRight :size="18" />
</button>
</div>
2025-12-20 18:52:33 +08:00
2025-12-23 19:15:00 +08:00
<!-- 展开时的关闭按钮 -->
<button v-if="isSidebarOpen" class="sidebar-close-btn" @click="toggleSidebar">
<ChevronLeft :size="18" />
</button>
2025-12-20 18:52:33 +08:00
2025-12-23 19:15:00 +08:00
<!-- 聊天室列表侧边栏 -->
<aside class="room-list-sidebar" :class="{ open: isSidebarOpen }">
<div class="sidebar-inner">
<!-- 头部 -->
<div class="sidebar-header">
<span class="title">聊天室</span>
2025-12-20 18:52:33 +08:00
</div>
2025-12-23 19:15:00 +08:00
<!-- 搜索框 -->
<div class="search-box">
<ElInput
v-model="searchText"
placeholder="搜索工单号、来客姓名、电话..."
:prefix-icon="Search"
clearable
/>
</div>
<!-- chatRoom列表 -->
<div class="room-list-container">
<div v-if="filteredRooms.length === 0" class="empty-tip">
暂无聊天室
2025-12-20 18:52:33 +08:00
</div>
2025-12-23 19:15:00 +08:00
<div
v-for="room in filteredRooms"
:key="room.roomId"
class="room-item"
:class="{ active: currentRoomId === room.roomId }"
2025-12-24 16:32:06 +08:00
@click="selectRoom(room)"
2025-12-23 19:15:00 +08:00
>
<!-- 头像 -->
<div class="room-avatar">
{{ room.guestName?.substring(0, 1) || '?' }}
</div>
2025-12-20 18:52:33 +08:00
2025-12-23 19:15:00 +08:00
<!-- 信息 -->
<div class="room-info">
<div class="room-header">
<div class="room-name">{{ room.roomName }}</div>
<div class="room-time">{{ formatTime(room.lastMessageTime) }}</div>
</div>
2025-12-24 15:02:23 +08:00
<div class="last-message-row">
<div class="last-message">{{ room.lastMessage || '暂无消息' }}</div>
<!-- 未读红点 -->
<div v-if="(room.unreadCount ?? 0) > 0" class="unread-badge">
{{ (room.unreadCount ?? 0) > 99 ? '99+' : room.unreadCount }}
</div>
</div>
2025-12-20 18:52:33 +08:00
</div>
</div>
</div>
</div>
</aside>
<!-- 主聊天区域 -->
2025-12-23 19:15:00 +08:00
<main class="chat-main" :class="{ 'sidebar-open': isSidebarOpen }">
2025-12-20 18:52:33 +08:00
<template v-if="currentRoomId">
2025-12-24 16:32:06 +08:00
<div class="chat-room-wrapper">
<!-- 自动填充加载遮罩 -->
<div v-if="autoFilling" class="auto-fill-mask">
<div class="loading-spinner"></div>
<div class="loading-text">正在加载历史消息...</div>
</div>
<ChatRoom
ref="chatRoomRef"
:messages="messages"
:current-user-id="loginDomain.user.userId"
:room-name="currentRoom?.roomName"
:meeting-url="currentMeetingUrl"
:show-meeting="showMeetingIframe"
:file-download-url="FILE_DOWNLOAD_URL"
:has-more="hasMore"
:loading-more="loadingMore"
@send-message="handleSendMessage"
@start-meeting="startMeeting"
@download-file="downloadFile"
@load-more="loadMoreMessages"
>
2025-12-20 18:52:33 +08:00
<template #header>
<div class="chat-room-header">
<div class="header-left">
<div class="room-avatar-small">
{{ currentRoom?.guestName?.substring(0, 1) }}
</div>
<div class="room-title-group">
<div class="room-name-text">{{ currentRoom?.roomName }}</div>
<div class="room-subtitle">
工单 #{{ currentRoom?.workcaseId }} · {{ currentRoom?.guestName }}
</div>
</div>
</div>
</div>
</template>
<template #action-area>
<ElButton type="primary" @click="showWorkcaseDetail = true">
<FileText :size="16" />
查看工单
</ElButton>
</template>
</ChatRoom>
2025-12-24 16:32:06 +08:00
</div>
2025-12-20 18:52:33 +08:00
</template>
<!-- 空状态 -->
<div v-else class="empty-state">
<div class="empty-content">
<div class="empty-icon">
<MessageSquare :size="40" />
</div>
<h3 class="empty-title">选择一个聊天室开始对话</h3>
<p class="empty-desc">从左侧列表中选择一个聊天室查看消息</p>
</div>
</div>
</main>
<!-- 工单详情对话框 -->
<ElDialog
v-model="showWorkcaseDetail"
title="工单详情"
width="800px"
class="workcase-dialog"
>
<WorkcaseDetail :workcase-id="currentWorkcaseId" />
</ElDialog>
</div>
</template>
<script setup lang="ts">
2025-12-23 19:15:00 +08:00
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
2025-12-22 17:03:37 +08:00
import { ElButton, ElInput, ElDialog, ElMessage } from 'element-plus'
2025-12-23 19:15:00 +08:00
import { Search, FileText, MessageSquare, MessageCircle, ChevronLeft, ChevronRight } from 'lucide-vue-next'
2025-12-23 16:16:47 +08:00
import { ChatRoom } from '@/components/chatRoom'
2025-12-20 18:52:33 +08:00
import WorkcaseDetail from '@/views/public/workcase/WorkcaseDetail/WorkcaseDetail.vue'
2025-12-23 16:16:47 +08:00
import { workcaseChatAPI } from '@/api/workcase'
2025-12-22 17:03:37 +08:00
import { fileAPI } from 'shared/api/file'
2025-12-20 18:52:33 +08:00
import { FILE_DOWNLOAD_URL } from '@/config'
2025-12-24 15:02:23 +08:00
import type { ChatRoomVO, ChatRoomMessageVO, TbChatRoomMessageDTO, TbChatRoomMemberDTO } from '@/types/workcase'
2025-12-22 17:03:37 +08:00
import SockJS from 'sockjs-client'
import { Client } from '@stomp/stompjs'
2025-12-20 18:52:33 +08:00
2025-12-22 17:08:49 +08:00
// WebSocket配置 (通过Nginx代理访问网关再到workcase服务)
// SockJS URL (http://)
2025-12-22 17:03:37 +08:00
const getWsUrl = () => {
const token = localStorage.getItem('token') || ''
2025-12-22 17:08:49 +08:00
const protocol = window.location.protocol
const host = window.location.host
return `${protocol}//${host}/api/urban-lifeline/workcase/ws/chat-sockjs?token=${encodeURIComponent(token)}`
2025-12-20 18:52:33 +08:00
}
2025-12-22 17:03:37 +08:00
// STOMP客户端
let stompClient: any = null
let roomSubscription: any = null
let listSubscription: any = null
2025-12-20 18:52:33 +08:00
2025-12-22 17:03:37 +08:00
// 当前用户ID从登录状态获取
2025-12-24 15:02:23 +08:00
const loginDomain = JSON.parse(localStorage.getItem('loginDomain')!)
2025-12-20 18:52:33 +08:00
2025-12-23 19:15:00 +08:00
// 侧边栏展开状态
const isSidebarOpen = ref(false)
// 切换侧边栏
const toggleSidebar = () => {
isSidebarOpen.value = !isSidebarOpen.value
}
2025-12-20 18:52:33 +08:00
// 搜索文本
const searchText = ref('')
2025-12-23 16:56:22 +08:00
const userType = true //web端固定这个
2025-12-22 17:03:37 +08:00
// 加载状态
const loading = ref(false)
const messageLoading = ref(false)
2025-12-23 19:15:00 +08:00
const loadingMore = ref(false)
2025-12-24 16:32:06 +08:00
// 自动填充加载状态
const autoFilling = ref(false)
2025-12-23 19:15:00 +08:00
// 分页状态
const PAGE_SIZE = 5
const currentPage = ref(1)
const hasMore = ref(true)
2025-12-22 17:03:37 +08:00
2025-12-20 18:52:33 +08:00
// 聊天室列表
2025-12-22 17:03:37 +08:00
const chatRooms = ref<ChatRoomVO[]>([])
2025-12-20 18:52:33 +08:00
// 当前选中的聊天室ID
const currentRoomId = ref<string | null>(null)
// 当前聊天室
const currentRoom = computed(() =>
2025-12-22 17:03:37 +08:00
chatRooms.value.find((r: ChatRoomVO) => r.roomId === currentRoomId.value)
2025-12-20 18:52:33 +08:00
)
// 当前工单ID
const currentWorkcaseId = computed(() => currentRoom.value?.workcaseId || '')
// 过滤后的聊天室列表
const filteredRooms = computed(() => {
if (!searchText.value) return chatRooms.value
const keyword = searchText.value.toLowerCase()
2025-12-22 17:03:37 +08:00
return chatRooms.value.filter((room: ChatRoomVO) =>
room.roomName?.toLowerCase().includes(keyword) ||
room.guestName?.toLowerCase().includes(keyword) ||
room.workcaseId?.toLowerCase().includes(keyword)
2025-12-20 18:52:33 +08:00
)
})
// 消息列表
2025-12-22 17:03:37 +08:00
const messages = ref<ChatRoomMessageVO[]>([])
2025-12-20 18:52:33 +08:00
// 工单详情对话框
const showWorkcaseDetail = ref(false)
// Jitsi Meet会议相关
const currentMeetingUrl = ref('')
const showMeetingIframe = ref(false)
2025-12-23 19:15:00 +08:00
// ChatRoom组件引用
const chatRoomRef = ref<InstanceType<typeof ChatRoom> | null>(null)
2025-12-22 17:03:37 +08:00
// 获取聊天室列表
const fetchChatRooms = async () => {
loading.value = true
try {
const result = await workcaseChatAPI.getChatRoomPage({
2025-12-24 16:32:06 +08:00
filter: {
status: 'active'
},
2025-12-22 17:03:37 +08:00
pageParam: { page: 1, pageSize: 100, total: 0 }
2025-12-24 16:32:06 +08:00
})
2025-12-22 17:03:37 +08:00
if (result.success && result.pageDomain) {
chatRooms.value = result.pageDomain.dataList || []
}
2025-12-23 19:15:00 +08:00
2025-12-22 17:03:37 +08:00
} catch (error) {
console.error('获取聊天室列表失败:', error)
ElMessage.error('获取聊天室列表失败')
} finally {
loading.value = false
}
}
2025-12-20 18:52:33 +08:00
// 选择聊天室
2025-12-24 16:32:06 +08:00
const selectRoom = async (room: ChatRoomVO) => {
currentRoomId.value = room.roomId!
2025-12-24 15:02:23 +08:00
// 自动加入聊天室成员表(如果不存在)
try {
const memberData: TbChatRoomMemberDTO = {
2025-12-24 16:32:06 +08:00
roomId: room.roomId,
2025-12-24 15:02:23 +08:00
userId: loginDomain.user.userId,
userName: loginDomain.userInfo.username,
userType: 'staff'
}
await workcaseChatAPI.addChatRoomMember(memberData)
2025-12-24 16:32:06 +08:00
room.unreadCount = 0
2025-12-24 15:02:23 +08:00
} catch (error) {
// 已存在成员或其他错误,忽略
console.debug('加入聊天室:', error)
}
2025-12-24 16:32:06 +08:00
loadMessages(room.roomId!)
2025-12-20 18:52:33 +08:00
}
2025-12-23 19:15:00 +08:00
// 加载消息初始加载page1后端降序返回
2025-12-20 18:52:33 +08:00
const loadMessages = async (roomId: string) => {
2025-12-22 17:03:37 +08:00
messageLoading.value = true
2025-12-23 19:15:00 +08:00
currentPage.value = 1
hasMore.value = true
2025-12-22 17:03:37 +08:00
try {
const result = await workcaseChatAPI.getChatMessagePage({
filter: { roomId },
2025-12-23 19:15:00 +08:00
pageParam: { page: 1, pageSize: PAGE_SIZE }
2025-12-22 17:03:37 +08:00
})
if (result.success && result.pageDomain) {
2025-12-23 19:15:00 +08:00
const pageInfo = result.pageDomain.pageParam
const actualTotalPages = pageInfo?.totalPages || 1
hasMore.value = actualTotalPages > currentPage.value
// 后端降序返回,需要反转后显示(早的在上,新的在下)
const dataList = result.pageDomain.dataList || []
messages.value = [...dataList].reverse()
2025-12-24 16:32:06 +08:00
// 首次加载后自动填充消息直到出现滚动条
await autoFillMessages(roomId)
2025-12-20 18:52:33 +08:00
}
2025-12-23 19:15:00 +08:00
// 加载完成后滚动到底部
2025-12-22 17:03:37 +08:00
scrollToBottom()
} catch (error) {
console.error('加载消息失败:', error)
ElMessage.error('加载消息失败')
} finally {
messageLoading.value = false
}
2025-12-20 18:52:33 +08:00
}
2025-12-24 16:32:06 +08:00
// 自动填充消息直到出现滚动条
const autoFillMessages = async (roomId: string) => {
autoFilling.value = true
console.log('[autoFill] 开始检查消息高度, hasMore:', hasMore.value, 'messages:', messages.value.length)
// 等待DOM渲染
await nextTick()
await new Promise(resolve => setTimeout(resolve, 300))
let attempts = 0
const maxAttempts = 20
while (hasMore.value && attempts < maxAttempts) {
attempts++
const container = chatRoomRef.value?.$el?.querySelector?.('.messages-container')
const messagesList = chatRoomRef.value?.$el?.querySelector?.('.messages-list')
if (!container || !messagesList) {
console.warn('[autoFill] 找不到容器或消息列表')
break
}
// 容器高度(可视区域)
const containerHeight = container.clientHeight
// 消息列表实际高度(内容)
const listHeight = messagesList.offsetHeight
const fillPercent = containerHeight > 0 ? Math.round(listHeight / containerHeight * 100) : 0
console.log(`[autoFill] 第${attempts}次检查 - 容器高度: ${containerHeight}px, 列表高度: ${listHeight}px, 填充率: ${fillPercent}%, 消息数: ${messages.value.length}`)
// 判断是否已经溢出(列表高度 >= 容器高度)
if (containerHeight > 0 && listHeight >= containerHeight) {
console.log(`[autoFill] ✓ 列表已溢出(${fillPercent}%),可以滚动!停止加载`)
break
}
// 内容不足,继续加载下一页
console.log('[autoFill] → 内容不足,继续加载历史消息...')
const nextPage = currentPage.value + 1
const result = await workcaseChatAPI.getChatMessagePage({
filter: { roomId },
pageParam: { page: nextPage, pageSize: PAGE_SIZE }
})
if (result.success && result.pageDomain) {
const pageInfo = result.pageDomain.pageParam
const actualTotalPages = pageInfo?.totalPages || 1
const dataList = result.pageDomain.dataList || []
if (dataList.length > 0) {
currentPage.value = nextPage
hasMore.value = actualTotalPages > currentPage.value
// 反转后插入到列表前面
const reversedList = [...dataList].reverse()
messages.value.unshift(...reversedList)
console.log(`[autoFill] ✓ 加载第${nextPage}页完成, 新增${dataList.length}条, 总消息数: ${messages.value.length}`)
await nextTick()
await new Promise(resolve => setTimeout(resolve, 200))
} else {
hasMore.value = false
break
}
} else {
break
}
}
if (attempts >= maxAttempts) {
console.warn('[autoFill] ⚠ 达到最大尝试次数')
}
console.log(`[autoFill] 自动填充结束 - 共尝试${attempts}次, 最终消息数: ${messages.value.length}, hasMore: ${hasMore.value}`)
autoFilling.value = false
}
2025-12-23 19:15:00 +08:00
// 加载更多历史消息(滚动到顶部触发)
const loadMoreMessages = async () => {
if (!currentRoomId.value || loadingMore.value || !hasMore.value) return
const nextPage = currentPage.value + 1
loadingMore.value = true
try {
const result = await workcaseChatAPI.getChatMessagePage({
filter: { roomId: currentRoomId.value },
pageParam: { page: nextPage, pageSize: PAGE_SIZE }
})
if (result.success && result.pageDomain) {
const pageInfo = result.pageDomain.pageParam
const actualTotalPages = pageInfo?.totalPages || 1
const dataList = result.pageDomain.dataList || []
if (dataList.length > 0) {
currentPage.value = nextPage
hasMore.value = actualTotalPages > currentPage.value
// 后端降序返回,反转后插入到列表前面
const reversedList = [...dataList].reverse()
messages.value.unshift(...reversedList)
} else {
hasMore.value = false
}
}
} catch (error) {
console.error('加载更多消息失败:', error)
} finally {
loadingMore.value = false
}
}
2025-12-20 18:52:33 +08:00
// 处理发送消息从ChatRoom组件触发
const handleSendMessage = async (content: string, files: File[]) => {
if (!currentRoomId.value) return
2025-12-22 17:03:37 +08:00
try {
// 上传文件获取fileIds
let fileIds: string[] = []
if (files.length > 0) {
const uploadResult = await fileAPI.batchUpload(files, 'chatroom')
if (uploadResult.success && uploadResult.dataList) {
fileIds = uploadResult.dataList.map((f: any) => f.fileId)
}
}
// 构造消息
const messageData: TbChatRoomMessageDTO = {
roomId: currentRoomId.value,
2025-12-24 15:02:23 +08:00
senderId: loginDomain.user.userId,
senderName: loginDomain.userInfo.username,
2025-12-22 17:03:37 +08:00
senderType: 'agent',
content,
files: fileIds,
messageType: 'text'
}
// 发送消息
const result = await workcaseChatAPI.sendMessage(messageData)
if (result.success && result.data) {
// 添加到消息列表
messages.value.push(result.data as ChatRoomMessageVO)
scrollToBottom()
} else {
ElMessage.error(result.message || '发送失败')
}
} catch (error) {
console.error('发送消息失败:', error)
ElMessage.error('发送消息失败')
2025-12-20 18:52:33 +08:00
}
}
// 下载文件
const downloadFile = (fileId: string) => {
2025-12-22 17:03:37 +08:00
window.open(`${FILE_DOWNLOAD_URL}/${fileId}`, '_blank')
2025-12-20 18:52:33 +08:00
}
// 发起会议
const startMeeting = async () => {
if (!currentRoomId.value) return
// TODO: 调用后端API创建Jitsi会议
2025-12-22 17:03:37 +08:00
const meetingId = 'meeting-' + currentRoomId.value + '-' + Date.now()
2025-12-20 18:52:33 +08:00
currentMeetingUrl.value = `https://meet.jit.si/${meetingId}`
showMeetingIframe.value = true
}
2025-12-23 19:15:00 +08:00
// 滚动聊天消息到底部
2025-12-20 18:52:33 +08:00
const scrollToBottom = () => {
2025-12-23 19:15:00 +08:00
nextTick(() => {
chatRoomRef.value?.scrollToBottom()
})
2025-12-20 18:52:33 +08:00
}
// 格式化时间(用于聊天室列表)
2025-12-22 17:03:37 +08:00
const formatTime = (time: string | null | undefined) => {
2025-12-20 18:52:33 +08:00
if (!time) return ''
const date = new Date(time)
const now = new Date()
const diff = now.getTime() - date.getTime()
if (diff < 60000) return '刚刚'
if (diff < 3600000) return Math.floor(diff / 60000) + '分钟前'
if (diff < 86400000) return Math.floor(diff / 3600000) + '小时前'
return date.toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit' })
}
2025-12-22 17:03:37 +08:00
// ==================== WebSocket连接管理 ====================
2025-12-22 17:08:49 +08:00
// 初始化WebSocket连接支持SockJS降级
2025-12-22 17:03:37 +08:00
const initWebSocket = () => {
const token = localStorage.getItem('token') || ''
const wsUrl = getWsUrl()
console.log('WebSocket连接URL:', wsUrl)
2025-12-22 17:08:49 +08:00
// 创建STOMP客户端使用SockJS支持降级
2025-12-22 17:03:37 +08:00
stompClient = new Client({
2025-12-22 17:08:49 +08:00
webSocketFactory: () => new SockJS(wsUrl),
2025-12-22 17:03:37 +08:00
connectHeaders: {
Authorization: `Bearer ${token}`
},
reconnectDelay: 5000,
heartbeatIncoming: 4000,
heartbeatOutgoing: 4000,
debug: (str: string) => {
console.log('[STOMP]', str)
},
onConnect: () => {
console.log('WebSocket已连接')
// 订阅聊天室列表更新
subscribeToListUpdate()
// 如果当前有选中的聊天室,订阅该聊天室消息
if (currentRoomId.value) {
subscribeToRoom(currentRoomId.value)
}
},
onDisconnect: () => {
console.log('WebSocket已断开')
},
onStompError: (frame: any) => {
console.error('STOMP错误:', frame)
},
onWebSocketError: (event: any) => {
console.error('WebSocket错误:', event)
}
})
stompClient.activate()
}
2025-12-24 15:02:23 +08:00
// 订阅聊天室列表更新 (用于更新列表中的lastMessage和未读数)
2025-12-22 17:03:37 +08:00
const subscribeToListUpdate = () => {
if (!stompClient || !stompClient.connected) return
2025-12-24 15:02:23 +08:00
listSubscription = stompClient.subscribe('/topic/chat/list-update', async (message: any) => {
2025-12-22 17:03:37 +08:00
const chatMessage = JSON.parse(message.body)
// 更新对应聊天室的lastMessage和lastMessageTime
const roomIndex = chatRooms.value.findIndex((r: ChatRoomVO) => r.roomId === chatMessage.roomId)
if (roomIndex !== -1) {
2025-12-24 15:02:23 +08:00
// 查询当前用户在该聊天室的未读数
let unreadCount = 0
try {
const unreadResult = await workcaseChatAPI.getUnreadCount(
chatMessage.roomId,
loginDomain.user.userId
)
if (unreadResult.success && unreadResult.data !== undefined) {
unreadCount = unreadResult.data
}
} catch (error) {
console.error('查询未读数失败:', error)
}
2025-12-22 17:03:37 +08:00
chatRooms.value[roomIndex] = {
...chatRooms.value[roomIndex],
lastMessage: chatMessage.content,
2025-12-24 15:02:23 +08:00
lastMessageTime: chatMessage.sendTime,
unreadCount: unreadCount
2025-12-22 17:03:37 +08:00
}
2025-12-24 15:02:23 +08:00
// 将更新的聊天室移到列表顶部
const updatedRoom = chatRooms.value[roomIndex]
chatRooms.value.splice(roomIndex, 1)
chatRooms.value.unshift(updatedRoom)
2025-12-22 17:03:37 +08:00
}
})
}
// 订阅指定聊天室消息 (用于实时接收消息)
const subscribeToRoom = (roomId: string) => {
if (!stompClient || !stompClient.connected) return
// 先取消之前的订阅
if (roomSubscription) {
roomSubscription.unsubscribe()
roomSubscription = null
}
roomSubscription = stompClient.subscribe(`/topic/chat/${roomId}`, (message: any) => {
const chatMessage = JSON.parse(message.body) as ChatRoomMessageVO
// 避免重复添加自己发送的消息
2025-12-24 15:02:23 +08:00
if (chatMessage.senderId !== loginDomain.user.userId) {
2025-12-22 17:03:37 +08:00
messages.value.push(chatMessage)
scrollToBottom()
}
})
}
// 断开WebSocket连接
const disconnectWebSocket = () => {
if (roomSubscription) {
roomSubscription.unsubscribe()
roomSubscription = null
}
if (listSubscription) {
listSubscription.unsubscribe()
listSubscription = null
}
if (stompClient) {
stompClient.deactivate()
stompClient = null
}
}
// 监听currentRoomId变化切换聊天室时重新订阅
watch(currentRoomId, (newRoomId) => {
if (newRoomId && stompClient?.connected) {
subscribeToRoom(newRoomId)
}
})
// 初始化
onMounted(() => {
fetchChatRooms()
initWebSocket()
})
// 组件卸载时断开连接
onUnmounted(() => {
disconnectWebSocket()
})
2025-12-20 18:52:33 +08:00
</script>
<style scoped lang="scss">
@import url("./ChatRoomView.scss");
</style>