From 83376a2a6a60e872be84ee2f50bdd5c635304c2a Mon Sep 17 00:00:00 2001 From: bob <312777916@qq.com> Date: Tue, 13 May 2025 15:01:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6=E6=B6=88=E6=81=AF=E8=BD=AC?= =?UTF-8?q?=E5=8F=91=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/message.js | 4 + src/const/msgConst.js | 2 +- src/views/message/MessageLayout.vue | 110 +++++++++--------- .../message/components/DialogForMsgList.vue | 86 ++++++++++++-- src/views/message/components/MessageItem.vue | 59 ++++++++-- 5 files changed, 185 insertions(+), 76 deletions(-) diff --git a/src/api/message.js b/src/api/message.js index 0a05bb0..842539f 100644 --- a/src/api/message.js +++ b/src/api/message.js @@ -32,6 +32,10 @@ export const msgChatQuerySessionService = (obj) => { return request.get('/chat/querySession', { params: obj }) } +export const msgChatQueryMessagesService = (obj) => { + return request.get('/chat/queryMessages', { params: obj }) +} + export const msgChatCloseSessionService = (obj) => { return request.post('/chat/closeSession', obj) } diff --git a/src/const/msgConst.js b/src/const/msgConst.js index f0b81b6..ecaf536 100644 --- a/src/const/msgConst.js +++ b/src/const/msgConst.js @@ -21,7 +21,7 @@ export const msgContentType = { EMOJI: 5, // 表情 VIDEO: 6, // 视频 DOCUMENT: 7, // 文档 - FORWARD_TOGETHER: 8 // 合并转发消息 + FORWARD_TOGETHER: 10 // 合并转发消息 } // 消息发送状态 diff --git a/src/views/message/MessageLayout.vue b/src/views/message/MessageLayout.vue index 4dcedf4..4c9f400 100644 --- a/src/views/message/MessageLayout.vue +++ b/src/views/message/MessageLayout.vue @@ -1158,22 +1158,22 @@ const onSelectOprMenu = (label) => { const inputMultiSelectRef = ref(null) const isMultiSelect = ref(false) -const multiSelectedMsgIds = ref(new Set()) +const multiSelectedMsgKeys = ref(new Set()) const handleMsgItemSelect = (msgKey, selected) => { if (!isMultiSelect.value) { isMultiSelect.value = true } if (selected) { - multiSelectedMsgIds.value.add(msgKey) + multiSelectedMsgKeys.value.add(msgKey) } else { - multiSelectedMsgIds.value.delete(msgKey) + multiSelectedMsgKeys.value.delete(msgKey) } } const handleCancleMultiSelect = () => { isMultiSelect.value = false - multiSelectedMsgIds.value.clear() + multiSelectedMsgKeys.value.clear() } const handleForwardTogether = () => { @@ -1187,14 +1187,17 @@ const handleForwardOneByOne = () => { } const handleBatchDeleteMsg = () => { + const deleteMsgIds = [...multiSelectedMsgKeys.value].map((item) => { + return messageData.getMsg(selectedSessionId.value, item).msgId + }) msgChatDeleteMsgService({ sessionId: selectedSessionId.value, - deleteMsgIds: [...multiSelectedMsgIds.value] + deleteMsgIds: [...deleteMsgIds] }) .then((res) => { if (res.data.code === 0) { - multiSelectedMsgIds.value.forEach((item) => { - messageData.removeMsgRecord(selectedSessionId.value, item) + multiSelectedMsgKeys.value.forEach((msgKey) => { + messageData.removeMsgRecord(selectedSessionId.value, msgKey) }) handleCancleMultiSelect() ElMessage.success('消息已删除') @@ -1326,10 +1329,10 @@ const handleGlobalMouseUp = (e) => { isMultiSelect.value = true } - const msgId = el.dataset.msgId + const msgKey = el.dataset.msgKey const disabled = el.dataset.disabled - if (disabled !== 'true' && !multiSelectedMsgIds.value.has(msgId)) { - multiSelectedMsgIds.value.add(msgId) + if (disabled !== 'true' && !multiSelectedMsgKeys.value.has(msgKey)) { + multiSelectedMsgKeys.value.add(msgKey) } const cancelClick = (e) => { @@ -1346,40 +1349,6 @@ const handleGlobalMouseUp = (e) => { const isShowForwardMsgDialog = ref(false) const showForwardMsgDialogTitle = ref('') -// 待转发的消息 -const forwardMsgs = computed(() => { - let msgs = [] - multiSelectedMsgIds.value.forEach((item) => { - const msg = messageData.getMsg(selectedSessionId.value, item) - let nickName = '' - if (msg.msgType === MsgType.CHAT) { - if (myAccount.value === msg.fromId) { - nickName = userData.user.nickName - } else { - nickName = messageData.sessionList[msg.sessionId].objectInfo.nickName - } - } else if (msg.msgType === MsgType.GROUP_CHAT) { - const groupId = messageData.sessionList[msg.sessionId].remoteId - const members = groupData.groupMembersList[groupId] - nickName = members[msg.fromId].nickName - } - msgs.push({ - ...msg, - nickName - }) - }) - - if (showForwardMsgDialogTitle.value === '合并转发') { - return [ - { - type: msgContentType.FORWARD_TOGETHER, - value: msgs - } - ] - } else { - return msgs - } -}) const sessionListSortedKey = computed(() => { return sessionListSorted.value @@ -1389,11 +1358,11 @@ const sessionListSortedKey = computed(() => { .map((item) => item.sessionId) }) -const showForwardMsgDialog = (msgId) => { - multiSelectedMsgIds.value.clear() - multiSelectedMsgIds.value.add(msgId) +const showForwardMsgDialog = (msgKey) => { + multiSelectedMsgKeys.value.clear() + multiSelectedMsgKeys.value.add(msgKey) isShowForwardMsgDialog.value = true - showForwardMsgDialogTitle.value = '转发消息' + showForwardMsgDialogTitle.value = '逐条转发' } const handleConfirmForwardMsg = async (sessions) => { @@ -1412,14 +1381,43 @@ const handleConfirmForwardMsg = async (sessions) => { messageData.addSession(res.data.data.session) } - for (const forwardMsg of forwardMsgs.value) { - const content = - showForwardMsgDialogTitle.value !== '合并转发' - ? forwardMsg.content - : JSON.stringify(forwardMsg) + if (showForwardMsgDialogTitle.value === '逐条转发') { + for (const msgKey of multiSelectedMsgKeys.value) { + const msg = messageData.getMsg(selectedSessionId.value, msgKey) + await handleSendForwardMsg({ + session: item, + content: msg.content + }) + } + } else if (showForwardMsgDialogTitle.value === '合并转发') { + const msgs = [...multiSelectedMsgKeys.value].map((item) => { + const msg = messageData.getMsg(selectedSessionId.value, item) + let nickName = '' + if (selectedSession.value.sessionType === MsgType.CHAT) { + if (myAccount.value === msg.fromId) { + nickName = userData.user.nickName + } else { + nickName = selectedSession.value.objectInfo.nickName + } + } else if (selectedSession.value.sessionType === MsgType.GROUP_CHAT) { + const groupId = selectedSession.value.remoteId + const members = groupData.groupMembersList[groupId] + nickName = members[msg.fromId].nickName + } + return { + nickName, + msgId: msg.msgId + } + }) await handleSendForwardMsg({ session: item, - content: content + content: JSON.stringify({ + type: msgContentType.FORWARD_TOGETHER, + value: { + sessionId: selectedSessionId.value, + data: [...msgs] + } + }) }) } } @@ -1675,7 +1673,7 @@ const onShowRecorder = () => { :isLoadMoreLoading="selectedSessionCache[selectedSessionId]?.isLoadMoreLoading" :inputEditorRef="inputEditorRef" :isMultiSelect="isMultiSelect" - :isSelected="multiSelectedMsgIds.has(item)" + :isSelected="multiSelectedMsgKeys.has(item)" @loadMore="onLoadMore" @showUserCard="onShowUserCard" @showGroupCard="onShowGroupCard" @@ -1728,7 +1726,7 @@ const onShowRecorder = () => { -import { onMounted, computed, watch, createApp, h } from 'vue' +import { ref, onMounted, computed, watch, createApp, h } from 'vue' import { ElDialog, ElLoading } from 'element-plus' import { useUserStore, @@ -24,6 +24,7 @@ import MsgBoxDocument from '@/views/message/components/MsgBoxDocument.vue' import DialogForMsgList from '@/views/message/components/DialogForMsgList.vue' import { emojis } from '@/js/utils/emojis' import { MsgType } from '@/proto/msg' +import { msgChatQueryMessagesService } from '@/api/message' const props = defineProps(['isShow', 'title', 'sessionId', 'msgs', 'tier']) const emit = defineEmits(['update:isShow', 'showUserCard', 'close']) @@ -36,8 +37,16 @@ const audioData = useAudioStore() const videoData = useVideoStore() const documentData = useDocumentStore() +const msgsFromServer = ref({}) + onMounted(async () => { - await messageData.preloadResource(props.msgs) + const loadingInstance = ElLoading.service(el_loading_options) + try { + await messageData.preloadResource(props.msgs) + await loadForwardTogetherMsgs() + } finally { + loadingInstance.close() + } }) /** @@ -50,6 +59,65 @@ watch( } ) +const loadForwardTogetherMsgs = async () => { + for (const msg of props.msgs) { + const content = msg.content + const contentJson = jsonParseSafe(content) + if (!contentJson) { + return + } + + const type = contentJson['type'] + const value = contentJson['value'] + if (!type || !value) { + return + } else { + if (type === msgContentType.FORWARD_TOGETHER) { + let res + try { + const msgIds = value.data + .map((item) => { + return item.msgId + }) + .join(',') + res = await msgChatQueryMessagesService({ + sessionId: value.sessionId, + msgIds + }) + } catch (error) { + console.error(error) + return + } + + const msgs = res.data.data + if (!res.data.data || res.data.data.length == 0) { + return + } + + // value.data(取里面的nickName) 和 msgs合一 + const newMsgs = {} + msgs.forEach((item) => { + newMsgs[item.msgId] = item + }) + value.data.forEach((item) => { + if (item.msgId in newMsgs) { + newMsgs[item.msgId] = { + ...newMsgs[item.msgId], + ...item + } + } + }) + + msgsFromServer.value[msg.msgId] = Object.values(newMsgs).sort((a, b) => { + const timeA = new Date(a.sendTime || a.msgTime).getTime() + const timeB = new Date(b.sendTime || b.msgTime).getTime() + return timeA - timeB + }) + } + } + } +} + const myAccount = computed(() => { return userData.user.account }) @@ -91,7 +159,7 @@ const renderContent = ({ msg }) => { case msgContentType.DOCUMENT: return renderDocument(value) case msgContentType.FORWARD_TOGETHER: - return renderForwardTogether(value) + return renderForwardTogether(msgId) default: return {content} } @@ -232,13 +300,13 @@ const renderDocument = (content) => { } } -const renderForwardTogether = (msgs) => { +const renderForwardTogether = (msgId) => { const title = '聊天记录' - const msgsSorted = msgs.sort((a, b) => { - const timeA = new Date(a.sendTime || a.msgTime).getTime() - const timeB = new Date(b.sendTime || b.msgTime).getTime() - return timeA - timeB - }) + const msgsSorted = msgsFromServer.value[msgId] + + if (!msgsSorted) { + return
+ } return (
{ - rendering() +onMounted(async () => { + await rendering() }) let app = null -const rendering = () => { +const rendering = async () => { const msgContent = document.querySelector(`#div-content-${msg.value.msgId}`) if (msgContent) { if (app) { app.unmount() } - const vnode = renderComponent(msg.value.content) + const vnode = await renderComponent(msg.value.content) app = createApp({ render: () => vnode }) @@ -84,7 +88,7 @@ const rendering = () => { * 动态渲染消息内容 * @param content 消息内容 */ -const renderComponent = (content) => { +const renderComponent = async (content) => { const contentJson = jsonParseSafe(content) if (!contentJson) { return renderMix(content) @@ -114,7 +118,7 @@ const renderComponent = (content) => { case msgContentType.DOCUMENT: return renderDocument(value) case msgContentType.FORWARD_TOGETHER: - return renderForwardTogether(value) + return await renderForwardTogether(value) default: return h('span', content) } @@ -263,11 +267,46 @@ const showMsgContentInForwardTogether = (content) => { } } -const renderForwardTogether = (msgs) => { +const renderForwardTogether = async (content) => { + let res + try { + const msgIds = content.data + .map((item) => { + return item.msgId + }) + .join(',') + res = await msgChatQueryMessagesService({ + sessionId: content.sessionId, + msgIds + }) + } catch (error) { + console.error(error) + return h('span', content) + } + + const msgs = res.data.data + if (!res.data.data || res.data.data.length == 0) { + return h('span', content) + } + + // 把content.data(取里面的nickName) 和 msgs合一 + const newMsgs = {} + msgs.forEach((item) => { + newMsgs[item.msgId] = item + }) + content.data.forEach((item) => { + if (item.msgId in newMsgs) { + newMsgs[item.msgId] = { + ...newMsgs[item.msgId], + ...item + } + } + }) + const title = (msgs[0].msgType === MsgType.GROUP_CHAT ? '群聊' : nickNameFromMsg.value) + '的聊天记录' - const msgsSorted = msgs.sort((a, b) => { + const msgsSorted = Object.values(newMsgs).sort((a, b) => { const timeA = new Date(a.sendTime || a.msgTime).getTime() const timeB = new Date(b.sendTime || b.msgTime).getTime() return timeA - timeB @@ -1046,7 +1085,7 @@ const handleItemClick = () => {