From 27cd042df9aca0383a49f3514bc21958dd890912 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 29 六月 2026 15:42:23 +0800
Subject: [PATCH] 银川 1.联调产品维护页面 2.添加IM即时通讯模块

---
 src/views/im/home/pages/conversation/components/message/forward/message-merge-detail-dialog.vue |  129 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 129 insertions(+), 0 deletions(-)

diff --git a/src/views/im/home/pages/conversation/components/message/forward/message-merge-detail-dialog.vue b/src/views/im/home/pages/conversation/components/message/forward/message-merge-detail-dialog.vue
new file mode 100644
index 0000000..6a58e06
--- /dev/null
+++ b/src/views/im/home/pages/conversation/components/message/forward/message-merge-detail-dialog.vue
@@ -0,0 +1,129 @@
+<script lang="ts" setup>
+import { computed, ref } from 'vue'
+
+import { IconifyIcon as Icon } from '#/packages/icons/src'
+
+import { Modal } from 'ant-design-vue'
+
+import { UserAvatar } from '#/views/im/home/components/user'
+import { useVoicePlayer } from '#/views/im/home/composables/useVoicePlayer'
+import { type MergeMessage, parseMessage } from '#/views/im/utils/message'
+import { formatMergeItemTime } from '#/views/im/utils/time'
+
+import { MessageBubble } from '..'
+
+defineOptions({ name: 'ImMessageMergeDetailDialog' })
+
+const voicePlayer = useVoicePlayer()
+const visible = ref(false)
+
+const stack = ref<MergeMessage[]>([]) // 宓屽灞傜骇鏍堬紝瀛� parsed payload 閬垮厤鍒囧眰閲� parse
+
+defineExpose({
+  /** 鎵撳紑璇︽儏寮圭獥锛屼紶鍏ラ《灞傚悎骞舵秷鎭� content */
+  open(content: string) {
+    const payload = parseMessage<MergeMessage>(content)
+    stack.value = payload ? [payload] : []
+    visible.value = true
+  }
+})
+
+/** 褰撳墠灞� payload */
+const currentPayload = computed<MergeMessage | null>(
+  () => stack.value[stack.value.length - 1] ?? null
+)
+
+/** 宓屽鍚堝苟姘旀场鐐瑰嚮锛氳В鏋� content 鍚庡帇鏍堣繘鍏ヤ笅涓�灞� */
+function handleNestedOpen(content: string) {
+  const payload = parseMessage<MergeMessage>(content)
+  if (payload) {
+    stack.value.push(payload)
+  }
+}
+
+/** 椤堕儴杩斿洖绠ご鐐瑰嚮锛氬脊鍑烘爤椤跺洖鍒颁笂涓�灞� */
+function handleBack() {
+  if (stack.value.length > 1) {
+    stack.value.pop()
+  }
+}
+
+/** 寮圭獥鍏抽棴锛氭竻鏍� + 鍋滆闊筹紝涓嬫鎵撳紑浠庨《灞傞噸鏂板紑濮� */
+function handleClose() {
+  stack.value = []
+  voicePlayer.stop()
+}
+
+</script>
+
+<template>
+  <Modal
+    v-model:open="visible"
+    width="560px"
+    :footer="null"
+    :mask-closable="false"
+    class="im-merge-detail-dialog"
+    :closable="true"
+    @close="handleClose"
+  >
+    <template #header>
+      <div class="flex items-center gap-2">
+        <Icon
+          v-if="stack.length > 1"
+          icon="ant-design:left-outlined"
+          class="cursor-pointer text-[var(--ant-color-text-secondary)] hover:text-[var(--ant-color-text)]"
+          @click="handleBack"
+        />
+        <span class="text-base font-medium truncate">{{ currentPayload?.title || '鑱婂ぉ璁板綍' }}</span>
+      </div>
+    </template>
+
+    <div v-if="currentPayload" class="flex flex-col h-[480px]">
+      <div
+        class="px-4 py-2 text-12px text-[var(--ant-color-text-secondary)] border-b border-b-solid border-[var(--ant-color-border-secondary)]"
+      >
+        浠ヤ笅鏄� {{ currentPayload.messages.length }} 鏉℃秷鎭�
+      </div>
+      <!-- overflow-y-auto锛氬悎骞舵秷鎭鏃跺湪瀹氶珮寮圭獥鍐呭彲婊氬姩锛屽榻� Vue3 鐨� el-scrollbar -->
+      <div class="flex-1 overflow-y-auto">
+        <div
+          v-for="(item, idx) in currentPayload.messages"
+          :key="idx"
+          class="flex gap-3 items-start px-4 py-3 border-b border-b-solid border-[var(--ant-color-border-secondary)]"
+        >
+          <UserAvatar
+            :url="item.senderAvatar"
+            :name="item.senderNickname"
+            :size="36"
+            :clickable="false"
+          />
+          <div class="flex-1 min-w-0">
+            <div class="flex gap-2 items-baseline">
+              <span class="text-13px font-medium text-[var(--ant-color-text)] truncate">
+                {{ item.senderNickname }}
+              </span>
+              <span class="text-12px text-[var(--ant-color-text-secondary)] flex-shrink-0">
+                {{ formatMergeItemTime(item.sendTime) }}
+              </span>
+            </div>
+            <!-- 澶嶇敤涓昏亰澶╂皵娉℃覆鏌擄紱MERGE 宓屽鐐瑰嚮 push 褰撳墠灞� -->
+            <div class="mt-1.5">
+              <MessageBubble
+                :type="item.type"
+                :content="item.content"
+                @open-merge="handleNestedOpen($event)"
+              />
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </Modal>
+</template>
+
+<style scoped>
+/* :deep 绌块�� el-dialog 鍐呴儴 body锛屽幓鎺夐粯璁ゅ唴杈硅窛锛岃婊氬姩鍖鸿创杈� */
+.im-merge-detail-dialog :deep(.el-dialog__body) {
+  padding: 0;
+}
+</style>

--
Gitblit v1.9.3