You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
337 lines
9.4 KiB
337 lines
9.4 KiB
|
1 month ago
|
<template>
|
||
|
|
<div class="message-main">
|
||
|
|
<MessageList
|
||
|
|
ref="messageList"
|
||
|
|
@select-contact="handleSelectContact"
|
||
|
|
/>
|
||
|
|
<div class="message-right">
|
||
|
|
<MessageDisplay
|
||
|
|
ref="messageDisplay"
|
||
|
|
@clear-unread="handleClearUnread"
|
||
|
|
@send-files="handleSendFiles"
|
||
|
|
@group-setting="handleGroupSetting"
|
||
|
|
/>
|
||
|
|
|
||
|
|
<MessageEditor
|
||
|
|
ref="messageEditor"
|
||
|
|
@send-message="handleSendMessage"
|
||
|
|
@update-message-status="handleUpdateMessageStatus"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- 群设置弹窗 -->
|
||
|
|
<GroupSetting
|
||
|
|
:visible.sync="groupSettingVisible"
|
||
|
|
:chat="currentChat"
|
||
|
|
@quit-group="handleQuitGroup"
|
||
|
|
@dismiss-group="handleDismissGroup"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
import { mapGetters, mapActions } from 'vuex'
|
||
|
|
import MessageList from './components/MessageList.vue'
|
||
|
|
import MessageDisplay from './components/MessageDisplay.vue'
|
||
|
|
import GroupSetting from './components/GroupSetting.vue'
|
||
|
|
import MessageEditor from './components/MessageEditor.vue'
|
||
|
|
// import { getMultiChatInfo } from '@/api/multichat'
|
||
|
|
import { MessageType, ContactsScene, MqttTopics } from '@/utils/constants'
|
||
|
|
|
||
|
|
export default {
|
||
|
|
name: 'MessageMain',
|
||
|
|
|
||
|
|
components: {
|
||
|
|
MessageList,
|
||
|
|
MessageDisplay,
|
||
|
|
GroupSetting,
|
||
|
|
MessageEditor
|
||
|
|
},
|
||
|
|
|
||
|
|
data() {
|
||
|
|
return {
|
||
|
|
groupSettingVisible: false
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
computed: {
|
||
|
|
...mapGetters(['mqttMessages', 'currentChat', 'userInfo', 'mqttConnected'])
|
||
|
|
},
|
||
|
|
|
||
|
|
watch: {
|
||
|
|
mqttMessages: {
|
||
|
|
deep: true,
|
||
|
|
handler(newMessages, oldMessages) {
|
||
|
|
const oldLen = oldMessages ? oldMessages.length : 0
|
||
|
|
const newLen = newMessages ? newMessages.length : 0
|
||
|
|
if (newLen > oldLen) {
|
||
|
|
for (let i = oldLen; i < newLen; i++) {
|
||
|
|
this.handleMqttMessage(newMessages[i])
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
mounted() {
|
||
|
|
this.initMqttSubscriptions()
|
||
|
|
},
|
||
|
|
|
||
|
|
beforeDestroy() {
|
||
|
|
// 清理
|
||
|
|
},
|
||
|
|
|
||
|
|
methods: {
|
||
|
|
...mapActions('mqtt', ['subscribe', 'unsubscribe']),
|
||
|
|
|
||
|
|
async initMqttSubscriptions() {
|
||
|
|
// 订阅个人消息主题
|
||
|
|
if (this.userInfo?.id) {
|
||
|
|
await this.subscribe(MqttTopics.PRIVATE_CHAT + this.userInfo.id)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
handleMqttMessage(msg) {
|
||
|
|
const type = msg.type || msg.message_type
|
||
|
|
switch (type) {
|
||
|
|
case MessageType.READ:
|
||
|
|
this.handleReadMessage(msg)
|
||
|
|
break
|
||
|
|
case MessageType.TEXT:
|
||
|
|
case MessageType.IMAGE:
|
||
|
|
case MessageType.VIDEO:
|
||
|
|
case MessageType.AUDIO:
|
||
|
|
case MessageType.FILE:
|
||
|
|
case MessageType.REPORT_SHARE:
|
||
|
|
case MessageType.KNOWLEDGE_SHARE:
|
||
|
|
case MessageType.CONSULTATION_MESSAGE_INVITE:
|
||
|
|
this.handleBaseMessage(msg)
|
||
|
|
break
|
||
|
|
case MessageType.MULTI_CHAT_INVITE:
|
||
|
|
this.handleMultiChatInvite(msg)
|
||
|
|
break
|
||
|
|
case MessageType.MULTI_CHAT_JOIN:
|
||
|
|
this.handleMultiChatJoin(msg)
|
||
|
|
break
|
||
|
|
case MessageType.MULTI_CHAT_EDIT:
|
||
|
|
this.handleMultiChatEdit(msg)
|
||
|
|
break
|
||
|
|
case MessageType.MULTI_CHAT_QUIT:
|
||
|
|
this.handleMultiChatQuit(msg)
|
||
|
|
break
|
||
|
|
case MessageType.MULTI_CHAT_DISMISS:
|
||
|
|
this.handleMultiChatDismiss(msg)
|
||
|
|
break
|
||
|
|
case MessageType.NOTIFY_CONTENT:
|
||
|
|
this.handleNotifyContent(msg)
|
||
|
|
break
|
||
|
|
default:
|
||
|
|
console.log('未处理的MQTT消息类型:', type, msg)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
handleReadMessage(msg) {
|
||
|
|
// 更新消息已读状态
|
||
|
|
if (this.$refs.messageDisplay) {
|
||
|
|
this.$refs.messageDisplay.updateMessageStatus(msg.message_id, { read: true, read_status: 1 })
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
handleBaseMessage(msg) {
|
||
|
|
const isSelf = msg.source_id === this.userInfo?.id
|
||
|
|
const scene = msg.scene || (msg.multi_chat_id ? ContactsScene.GROUP : ContactsScene.PRIVATE)
|
||
|
|
const targetId = msg.target_id || msg.source_id
|
||
|
|
const contactId = isSelf ? targetId : msg.source_id
|
||
|
|
|
||
|
|
// 如果当前正在查看该会话,展示消息
|
||
|
|
if (this.currentChat &&
|
||
|
|
this.currentChat.id === (scene === ContactsScene.GROUP ? msg.multi_chat_id : contactId) &&
|
||
|
|
this.currentChat.scene === scene) {
|
||
|
|
if (this.$refs.messageDisplay) {
|
||
|
|
this.$refs.messageDisplay.addChatMessage(msg)
|
||
|
|
}
|
||
|
|
// 标记已读
|
||
|
|
if (!isSelf) {
|
||
|
|
this.handleClearUnread(this.currentChat.id, this.currentChat.scene)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 更新联系人列表最后消息
|
||
|
|
if (this.$refs.messageList) {
|
||
|
|
this.$refs.messageList.updateContactLastMessage(
|
||
|
|
scene === ContactsScene.GROUP ? msg.multi_chat_id : contactId,
|
||
|
|
scene,
|
||
|
|
msg,
|
||
|
|
msg.timestamp || new Date().toISOString()
|
||
|
|
)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
async handleMultiChatInvite(msg) {
|
||
|
|
const payload = msg.payload || {}
|
||
|
|
const multiChatId = payload.multi_chat_id || msg.multi_chat_id
|
||
|
|
if (!multiChatId) return
|
||
|
|
// 订阅群主题
|
||
|
|
await this.subscribe(MqttTopics.MULTI_CHAT + multiChatId)
|
||
|
|
// 获取群详情
|
||
|
|
try {
|
||
|
|
const res = await getMultiChatInfo({ multi_chat_id: multiChatId })
|
||
|
|
const group = res.data
|
||
|
|
if (group && this.$refs.messageList) {
|
||
|
|
this.$refs.messageList.loadContacts()
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
console.error('获取群详情失败', e)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
async handleMultiChatJoin(msg) {
|
||
|
|
const multiChatId = msg.multi_chat_id || msg.payload?.multi_chat_id
|
||
|
|
if (!multiChatId) return
|
||
|
|
try {
|
||
|
|
await getMultiChatInfo({ multi_chat_id: multiChatId })
|
||
|
|
if (this.$refs.messageList) {
|
||
|
|
this.$refs.messageList.loadContacts()
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
console.error('获取群详情失败', e)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
async handleMultiChatEdit(msg) {
|
||
|
|
const multiChatId = msg.multi_chat_id || msg.payload?.multi_chat_id
|
||
|
|
if (!multiChatId) return
|
||
|
|
try {
|
||
|
|
await getMultiChatInfo({ multi_chat_id: multiChatId })
|
||
|
|
if (this.$refs.messageList) {
|
||
|
|
this.$refs.messageList.loadContacts()
|
||
|
|
}
|
||
|
|
// 如果当前正在该群聊,刷新标题
|
||
|
|
if (this.currentChat && this.currentChat.id === multiChatId && this.currentChat.scene === ContactsScene.GROUP) {
|
||
|
|
this.$refs.messageList.loadContacts()
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
console.error('获取群详情失败', e)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
handleMultiChatQuit(msg) {
|
||
|
|
const payload = msg.payload || {}
|
||
|
|
const multiChatId = payload.multi_chat_id || msg.multi_chat_id
|
||
|
|
const quitUserId = payload.user_id || msg.source_id
|
||
|
|
if (!multiChatId) return
|
||
|
|
if (quitUserId === this.userInfo?.id) {
|
||
|
|
// 自己退出,取消订阅并删除列表项
|
||
|
|
this.unsubscribe(MqttTopics.MULTI_CHAT + multiChatId)
|
||
|
|
if (this.$refs.messageList) {
|
||
|
|
this.$refs.messageList.removeContact(multiChatId, ContactsScene.GROUP)
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
// 他人退出,更新列表
|
||
|
|
if (this.$refs.messageList) {
|
||
|
|
this.$refs.messageList.loadContacts()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
handleMultiChatDismiss(msg) {
|
||
|
|
const multiChatId = msg.multi_chat_id || msg.payload?.multi_chat_id
|
||
|
|
if (!multiChatId) return
|
||
|
|
this.unsubscribe(MqttTopics.MULTI_CHAT + multiChatId)
|
||
|
|
if (this.$refs.messageList) {
|
||
|
|
this.$refs.messageList.removeContact(multiChatId, ContactsScene.GROUP)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
handleNotifyContent(msg) {
|
||
|
|
// 系统通知处理
|
||
|
|
this.$notify({
|
||
|
|
title: '系统通知',
|
||
|
|
message: msg.payload?.content || msg.content || '新通知',
|
||
|
|
type: 'info',
|
||
|
|
duration: 5000
|
||
|
|
})
|
||
|
|
},
|
||
|
|
|
||
|
|
handleSelectContact(contact) {
|
||
|
|
// 如果是群聊,订阅MQTT主题
|
||
|
|
if (contact.scene === ContactsScene.GROUP) {
|
||
|
|
this.subscribe(MqttTopics.MULTI_CHAT + contact.id)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
handleClearUnread(contactId, scene) {
|
||
|
|
if (this.$refs.messageList) {
|
||
|
|
this.$refs.messageList.clearUnread(contactId, scene)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
handleSendMessage(message) {
|
||
|
|
if (this.$refs.messageDisplay) {
|
||
|
|
this.$refs.messageDisplay.addChatMessage(message)
|
||
|
|
}
|
||
|
|
// 更新联系人列表
|
||
|
|
if (this.$refs.messageList) {
|
||
|
|
this.$refs.messageList.updateContactLastMessage(
|
||
|
|
message.target_id,
|
||
|
|
message.scene,
|
||
|
|
message,
|
||
|
|
new Date().toISOString()
|
||
|
|
)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
handleUpdateMessageStatus(messageId, updates) {
|
||
|
|
if (this.$refs.messageDisplay) {
|
||
|
|
this.$refs.messageDisplay.updateMessageStatus(messageId, updates)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
handleSendFiles(files) {
|
||
|
|
if (this.$refs.messageEditor) {
|
||
|
|
files.forEach(file => {
|
||
|
|
const type = file.type.startsWith('image/') ? 'image'
|
||
|
|
: file.type.startsWith('video/') ? 'video'
|
||
|
|
: file.type.startsWith('audio/') ? 'audio'
|
||
|
|
: 'file'
|
||
|
|
this.$refs.messageEditor.sendFileMessage(file, type)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
handleGroupSetting(chat) {
|
||
|
|
this.groupSettingVisible = true
|
||
|
|
},
|
||
|
|
|
||
|
|
handleQuitGroup(chat) {
|
||
|
|
// 退出群组逻辑
|
||
|
|
if (this.$refs.messageList) {
|
||
|
|
this.$refs.messageList.removeContact(chat.id, chat.scene)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
handleDismissGroup(chat) {
|
||
|
|
// 解散群组逻辑
|
||
|
|
if (this.$refs.messageList) {
|
||
|
|
this.$refs.messageList.removeContact(chat.id, chat.scene)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style lang="scss" scoped>
|
||
|
|
.message-main {
|
||
|
|
display: flex;
|
||
|
|
height: 100%;
|
||
|
|
background: #fff;
|
||
|
|
|
||
|
|
.message-right {
|
||
|
|
flex: 1;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
min-width: 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</style>
|