gateway tomcat去除
This commit is contained in:
@@ -31,7 +31,7 @@
|
||||
>
|
||||
<!-- 头像 -->
|
||||
<div class="room-avatar">
|
||||
{{ room.guestName.substring(0, 1) }}
|
||||
{{ room.guestName?.substring(0, 1) || '?' }}
|
||||
</div>
|
||||
|
||||
<!-- 信息 -->
|
||||
@@ -114,67 +114,50 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { ElButton, ElInput, ElDialog } from 'element-plus'
|
||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
|
||||
import { ElButton, ElInput, ElDialog, ElMessage } from 'element-plus'
|
||||
import { Search, FileText, MessageSquare } from 'lucide-vue-next'
|
||||
import ChatRoom from 'shared/components/chatRoom/ChatRoom.vue'
|
||||
import WorkcaseDetail from '@/views/public/workcase/WorkcaseDetail/WorkcaseDetail.vue'
|
||||
import { workcaseChatAPI } from 'shared/api/workcase'
|
||||
import { fileAPI } from 'shared/api/file'
|
||||
import { FILE_DOWNLOAD_URL } from '@/config'
|
||||
import type { ChatRoomVO, ChatRoomMessageVO, TbChatRoomMessageDTO } from 'shared/types'
|
||||
import SockJS from 'sockjs-client'
|
||||
import { Client } from '@stomp/stompjs'
|
||||
|
||||
interface ChatRoomVO {
|
||||
roomId: string
|
||||
workcaseId: string
|
||||
roomName: string
|
||||
guestName: string
|
||||
lastMessage: string | null
|
||||
lastMessageTime: string | null
|
||||
unreadCount: number
|
||||
// WebSocket配置 (通过网关代理访问workcase服务)
|
||||
// 原生WebSocket URL (ws://或wss://)
|
||||
const getWsUrl = () => {
|
||||
const token = localStorage.getItem('token') || ''
|
||||
// 直接连接网关,跳过Nginx调试
|
||||
return `ws://localhost:8180/urban-lifeline/workcase/ws/chat?token=${encodeURIComponent(token)}`
|
||||
}
|
||||
|
||||
interface ChatMessageVO {
|
||||
messageId: string
|
||||
senderId: string
|
||||
senderName: string
|
||||
senderAvatar: string
|
||||
content: string
|
||||
files: string[]
|
||||
sendTime: string
|
||||
}
|
||||
// STOMP客户端
|
||||
let stompClient: any = null
|
||||
let roomSubscription: any = null
|
||||
let listSubscription: any = null
|
||||
|
||||
// 当前用户ID
|
||||
const userId = ref('CURRENT_USER_ID')
|
||||
// 当前用户ID(从登录状态获取)
|
||||
const userId = ref(localStorage.getItem('userId') || '')
|
||||
|
||||
// 搜索文本
|
||||
const searchText = ref('')
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(false)
|
||||
const messageLoading = ref(false)
|
||||
|
||||
// 聊天室列表
|
||||
const chatRooms = ref<ChatRoomVO[]>([
|
||||
{
|
||||
roomId: 'ROOM001',
|
||||
workcaseId: 'WC001',
|
||||
roomName: '工单#WC001 - 电源故障',
|
||||
guestName: '张三',
|
||||
lastMessage: '好的,谢谢您的帮助',
|
||||
lastMessageTime: new Date().toISOString(),
|
||||
unreadCount: 3
|
||||
},
|
||||
{
|
||||
roomId: 'ROOM002',
|
||||
workcaseId: 'WC002',
|
||||
roomName: '工单#WC002 - 设备维修',
|
||||
guestName: '李四',
|
||||
lastMessage: '请问什么时候能来处理?',
|
||||
lastMessageTime: new Date(Date.now() - 3600000).toISOString(),
|
||||
unreadCount: 0
|
||||
}
|
||||
])
|
||||
const chatRooms = ref<ChatRoomVO[]>([])
|
||||
|
||||
// 当前选中的聊天室ID
|
||||
const currentRoomId = ref<string | null>(null)
|
||||
|
||||
// 当前聊天室
|
||||
const currentRoom = computed(() =>
|
||||
chatRooms.value.find(r => r.roomId === currentRoomId.value)
|
||||
chatRooms.value.find((r: ChatRoomVO) => r.roomId === currentRoomId.value)
|
||||
)
|
||||
|
||||
// 当前工单ID
|
||||
@@ -184,15 +167,15 @@ const currentWorkcaseId = computed(() => currentRoom.value?.workcaseId || '')
|
||||
const filteredRooms = computed(() => {
|
||||
if (!searchText.value) return chatRooms.value
|
||||
const keyword = searchText.value.toLowerCase()
|
||||
return chatRooms.value.filter(room =>
|
||||
room.roomName.toLowerCase().includes(keyword) ||
|
||||
room.guestName.toLowerCase().includes(keyword) ||
|
||||
room.workcaseId.toLowerCase().includes(keyword)
|
||||
return chatRooms.value.filter((room: ChatRoomVO) =>
|
||||
room.roomName?.toLowerCase().includes(keyword) ||
|
||||
room.guestName?.toLowerCase().includes(keyword) ||
|
||||
room.workcaseId?.toLowerCase().includes(keyword)
|
||||
)
|
||||
})
|
||||
|
||||
// 消息列表
|
||||
const messages = ref<ChatMessageVO[]>([])
|
||||
const messages = ref<ChatRoomMessageVO[]>([])
|
||||
|
||||
// 工单详情对话框
|
||||
const showWorkcaseDetail = ref(false)
|
||||
@@ -201,66 +184,93 @@ const showWorkcaseDetail = ref(false)
|
||||
const currentMeetingUrl = ref('')
|
||||
const showMeetingIframe = ref(false)
|
||||
|
||||
// 获取聊天室列表
|
||||
const fetchChatRooms = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await workcaseChatAPI.getChatRoomPage({
|
||||
filter: { status: 'active' },
|
||||
pageParam: { page: 1, pageSize: 100, total: 0 }
|
||||
})
|
||||
if (result.success && result.pageDomain) {
|
||||
chatRooms.value = result.pageDomain.dataList || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取聊天室列表失败:', error)
|
||||
ElMessage.error('获取聊天室列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 选择聊天室
|
||||
const selectRoom = (roomId: string) => {
|
||||
currentRoomId.value = roomId
|
||||
// TODO: 加载该聊天室的消息
|
||||
loadMessages(roomId)
|
||||
}
|
||||
|
||||
// 加载消息
|
||||
const loadMessages = async (roomId: string) => {
|
||||
// TODO: 调用API加载消息
|
||||
messages.value = [
|
||||
{
|
||||
messageId: 'MSG001',
|
||||
senderId: 'OTHER_USER',
|
||||
senderName: '张三',
|
||||
senderAvatar: 'avatar.jpg',
|
||||
content: '你好,我的设备出现故障了',
|
||||
files: [],
|
||||
sendTime: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
messageId: 'MSG002',
|
||||
senderId: userId.value,
|
||||
senderName: '客服',
|
||||
senderAvatar: 'avatar.jpg',
|
||||
content: '您好,请问是什么故障?',
|
||||
files: [],
|
||||
sendTime: new Date().toISOString()
|
||||
messageLoading.value = true
|
||||
try {
|
||||
const result = await workcaseChatAPI.getChatMessagePage({
|
||||
filter: { roomId },
|
||||
pageParam: { page: 1, pageSize: 100, total: 0 }
|
||||
})
|
||||
if (result.success && result.pageDomain) {
|
||||
messages.value = result.pageDomain.dataList || []
|
||||
}
|
||||
]
|
||||
scrollToBottom()
|
||||
scrollToBottom()
|
||||
} catch (error) {
|
||||
console.error('加载消息失败:', error)
|
||||
ElMessage.error('加载消息失败')
|
||||
} finally {
|
||||
messageLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 处理发送消息(从ChatRoom组件触发)
|
||||
const handleSendMessage = async (content: string, files: File[]) => {
|
||||
if (!currentRoomId.value) return
|
||||
|
||||
// TODO: 上传文件获取fileIds
|
||||
const fileIds: string[] = []
|
||||
|
||||
const newMessage: ChatMessageVO = {
|
||||
messageId: 'MSG' + Date.now(),
|
||||
senderId: userId.value,
|
||||
senderName: '客服',
|
||||
senderAvatar: 'avatar.jpg',
|
||||
content,
|
||||
files: fileIds,
|
||||
sendTime: new Date().toISOString()
|
||||
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,
|
||||
senderId: userId.value,
|
||||
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('发送消息失败')
|
||||
}
|
||||
|
||||
messages.value.push(newMessage)
|
||||
|
||||
// TODO: 通过WebSocket发送到服务器
|
||||
console.log('发送消息:', { content, files })
|
||||
}
|
||||
|
||||
// 下载文件
|
||||
const downloadFile = (fileId: string) => {
|
||||
// TODO: 下载文件
|
||||
console.log('下载文件:', fileId)
|
||||
window.open(`${FILE_DOWNLOAD_URL}/${fileId}`, '_blank')
|
||||
}
|
||||
|
||||
// 发起会议
|
||||
@@ -268,14 +278,9 @@ const startMeeting = async () => {
|
||||
if (!currentRoomId.value) return
|
||||
|
||||
// TODO: 调用后端API创建Jitsi会议
|
||||
// const meeting = await createMeeting(currentRoomId.value)
|
||||
|
||||
// 模拟会议URL
|
||||
const meetingId = 'meeting-' + Date.now()
|
||||
const meetingId = 'meeting-' + currentRoomId.value + '-' + Date.now()
|
||||
currentMeetingUrl.value = `https://meet.jit.si/${meetingId}`
|
||||
showMeetingIframe.value = true
|
||||
|
||||
console.log('发起会议:', currentMeetingUrl.value)
|
||||
}
|
||||
|
||||
// 滚动到底部
|
||||
@@ -284,7 +289,7 @@ const scrollToBottom = () => {
|
||||
}
|
||||
|
||||
// 格式化时间(用于聊天室列表)
|
||||
const formatTime = (time: string | null) => {
|
||||
const formatTime = (time: string | null | undefined) => {
|
||||
if (!time) return ''
|
||||
const date = new Date(time)
|
||||
const now = new Date()
|
||||
@@ -296,6 +301,122 @@ const formatTime = (time: string | null) => {
|
||||
|
||||
return date.toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit' })
|
||||
}
|
||||
|
||||
// ==================== WebSocket连接管理 ====================
|
||||
|
||||
// 初始化WebSocket连接(使用原生WebSocket,不降级)
|
||||
const initWebSocket = () => {
|
||||
const token = localStorage.getItem('token') || ''
|
||||
const wsUrl = getWsUrl()
|
||||
|
||||
console.log('WebSocket连接URL:', wsUrl)
|
||||
|
||||
// 创建STOMP客户端,使用原生WebSocket
|
||||
stompClient = new Client({
|
||||
brokerURL: wsUrl, // 使用原生WebSocket URL
|
||||
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()
|
||||
}
|
||||
|
||||
// 订阅聊天室列表更新 (用于更新列表中的lastMessage)
|
||||
const subscribeToListUpdate = () => {
|
||||
if (!stompClient || !stompClient.connected) return
|
||||
|
||||
listSubscription = stompClient.subscribe('/topic/chat/list-update', (message: any) => {
|
||||
const chatMessage = JSON.parse(message.body)
|
||||
// 更新对应聊天室的lastMessage和lastMessageTime
|
||||
const roomIndex = chatRooms.value.findIndex((r: ChatRoomVO) => r.roomId === chatMessage.roomId)
|
||||
if (roomIndex !== -1) {
|
||||
chatRooms.value[roomIndex] = {
|
||||
...chatRooms.value[roomIndex],
|
||||
lastMessage: chatMessage.content,
|
||||
lastMessageTime: chatMessage.sendTime
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 订阅指定聊天室消息 (用于实时接收消息)
|
||||
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
|
||||
// 避免重复添加自己发送的消息
|
||||
if (chatMessage.senderId !== userId.value) {
|
||||
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()
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import url("./ChatRoomView.scss");
|
||||
|
||||
Reference in New Issue
Block a user