|
|
|
|
<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
|
|
|
|
|
ref="groupSettingRef"
|
|
|
|
|
:chat="currentChat"
|
|
|
|
|
@quit-group="handleQuitGroup"
|
|
|
|
|
@dismiss-group="handleDismissGroup"
|
|
|
|
|
@refresh-list="handleRefreshList"
|
|
|
|
|
/>
|
|
|
|
|
</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, editMultiChatName } from '@/api/multichat'
|
|
|
|
|
import { MessageType, ContactsScene, MqttTopics } from "@/utils/constants";
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
name: "MessageMain",
|
|
|
|
|
|
|
|
|
|
components: {
|
|
|
|
|
MessageList,
|
|
|
|
|
MessageDisplay,
|
|
|
|
|
GroupSetting,
|
|
|
|
|
MessageEditor,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
this.handleUrlParams();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
beforeDestroy() {
|
|
|
|
|
// 清理
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
methods: {
|
|
|
|
|
...mapActions("mqtt", ["subscribe", "unsubscribe"]),
|
|
|
|
|
...mapActions("message", ["setCurrentChat"]),
|
|
|
|
|
|
|
|
|
|
// 处理URL参数,实现从通讯录发消息联动
|
|
|
|
|
handleUrlParams() {
|
|
|
|
|
const { contactId, contactName, scene } = this.$route.query;
|
|
|
|
|
if (contactId && scene) {
|
|
|
|
|
const chat = {
|
|
|
|
|
id: contactId,
|
|
|
|
|
name: contactName || "未知联系人",
|
|
|
|
|
scene: parseInt(scene),
|
|
|
|
|
avatar: "",
|
|
|
|
|
unread_count: 0,
|
|
|
|
|
last_message: "",
|
|
|
|
|
last_message_time: new Date().toISOString(),
|
|
|
|
|
};
|
|
|
|
|
// 设置当前聊天
|
|
|
|
|
this.setCurrentChat(chat);
|
|
|
|
|
// 如果是群聊,订阅MQTT主题
|
|
|
|
|
if (parseInt(scene) === ContactsScene.GROUP) {
|
|
|
|
|
this.subscribe(MqttTopics.MULTI_CHAT + contactId);
|
|
|
|
|
}
|
|
|
|
|
// 清除URL参数
|
|
|
|
|
this.$router.replace({ query: {} });
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 群设置修改后刷新列表
|
|
|
|
|
handleRefreshList() {
|
|
|
|
|
if (this.$refs.messageList) {
|
|
|
|
|
this.$refs.messageList.refreshList({ keepCurrent: true });
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
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() {
|
|
|
|
|
this.$refs.groupSettingRef.loadGroupInfo();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
handleQuitGroup(chat) {
|
|
|
|
|
// 退出群组逻辑
|
|
|
|
|
if (this.$refs.messageList) {
|
|
|
|
|
// 刷新列表并打开第一个
|
|
|
|
|
this.$refs.messageList.refreshList({ selectFirst: true });
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
handleDismissGroup(chat) {
|
|
|
|
|
// 解散群组逻辑
|
|
|
|
|
if (this.$refs.messageList) {
|
|
|
|
|
// 刷新列表并打开第一个
|
|
|
|
|
this.$refs.messageList.refreshList({ selectFirst: true });
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
</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>
|