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/components/rtc/rtc-call-incoming.vue |  112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 112 insertions(+), 0 deletions(-)

diff --git a/src/views/im/home/components/rtc/rtc-call-incoming.vue b/src/views/im/home/components/rtc/rtc-call-incoming.vue
new file mode 100644
index 0000000..a010fa0
--- /dev/null
+++ b/src/views/im/home/components/rtc/rtc-call-incoming.vue
@@ -0,0 +1,112 @@
+<script lang="ts" setup>
+import type { ImRtcCallNotification } from '../../store/rtcStore'
+
+import { computed } from 'vue'
+
+import { DICT_TYPE } from '#/packages/constants/src'
+import { getDictLabel } from '#/packages/effects/hooks/src'
+import { IconifyIcon as Icon } from '#/packages/icons/src'
+
+import { useGroupCallMembers } from '../../composables/useGroupCallMembers'
+import { UserAvatar } from '../user'
+
+const props = defineProps<{
+  accepting?: boolean
+  isGroup?: boolean
+  payload: ImRtcCallNotification | null
+  rejecting?: boolean
+}>()
+
+defineEmits<{ accept: []; reject: [] }>()
+
+/** 鏉ョ數鎻愮ず鏂囨锛涘尯鍒嗚闊� / 瑙嗛 */
+const tipText = computed(() => {
+  if (!props.payload) return ''
+  return `閭�璇蜂綘${getDictLabel(DICT_TYPE.IM_RTC_CALL_MEDIA_TYPE, props.payload.mediaType)}閫氳瘽`
+})
+
+/** 鎺ュ惉鎸夐挳绂佺敤鎬� */
+const acceptDisabled = computed(() => !!props.accepting || !!props.rejecting)
+
+/** 鎷掔粷鎸夐挳绂佺敤鎬� */
+const rejectDisabled = computed(() => !!props.rejecting || !!props.accepting)
+
+// 缇ら�氳瘽鎴愬憳锛涚紦瀛樹负绌烘椂鐢� INVITE 杞借嵎閲岀殑涓诲彨鍏滃簳锛岄伩鍏嶇┖鐧�
+const callMembers = useGroupCallMembers(
+  computed(() => (props.isGroup ? props.payload?.groupId : undefined)),
+  computed(() => props.payload?.inviterUserId)
+)
+</script>
+
+<template>
+  <!--
+    琚彨绔潵鐢靛皬鏉★紱鍙傝�冨井淇★紝鍙充笂瑙掑浐瀹氭偓娴紱
+    缇よ亰锛氬乏澶村儚 + 涓紙閭�璇蜂汉 + 鏂囨涓�琛� / 閫氳瘽鎴愬憳琛岋級+ 鍙充笅瑙掓嫆缁� / 鎺ュ惉锛�
+    绉佽亰锛氬乏澶村儚 + 涓紙閭�璇蜂汉 + 鏂囨涓よ锛�+ 鍙充笅瑙掓嫆缁� / 鎺ュ惉
+  -->
+  <div
+    class="fixed top-5 right-5 rounded-2xl overflow-hidden shadow-[0_12px_36px_rgba(0,0,0,0.4)] z-[9999] flex gap-3 items-end p-3 text-white bg-[#2a2a2c]"
+    :class="isGroup ? 'w-[360px]' : 'w-[340px]'"
+  >
+    <!-- 宸︼細閭�璇疯�呭ご鍍� -->
+    <UserAvatar
+      :url="payload?.inviterAvatar"
+      :name="payload?.inviterNickname"
+      :size="48"
+      radius="8px"
+      :clickable="false"
+      class="self-start"
+    />
+
+    <!-- 涓細缇よ亰鍗曡锛堥個璇蜂汉 + 鏂囨锛�+ 閫氳瘽鎴愬憳锛涚鑱婁袱琛岋紙鍚� / 鏂囨锛� -->
+    <div class="flex flex-col flex-1 gap-1 self-start min-w-0">
+      <!-- 鍚� + 鏂囨锛氱兢鍗曡鍐呰仈锛岀鑱婁笂涓嬩袱琛� -->
+      <div v-if="isGroup" class="text-sm truncate">
+        <span class="font-medium">{{ payload?.inviterNickname || '瀵规柟' }}</span>
+        <span class="ml-1 text-white/60">{{ tipText }}</span>
+      </div>
+      <template v-else>
+        <div class="text-sm font-medium truncate">{{ payload?.inviterNickname || '瀵规柟' }}</div>
+        <div class="text-13px text-white/60 truncate">{{ tipText }}</div>
+      </template>
+
+      <!-- 缇ら�氳瘽鎴愬憳琛岋紱绉佽亰鏃狅紱鎺ュ叆涓殑浜哄崐閫忔槑灞曠ず -->
+      <template v-if="isGroup && callMembers.length > 0">
+        <div class="mt-1 text-xs text-white/45">閫氳瘽鎴愬憳</div>
+        <div class="flex flex-wrap gap-1">
+          <UserAvatar
+            v-for="member in callMembers"
+            :key="member.userId"
+            :url="member.avatar"
+            :name="member.nickname"
+            :size="22"
+            radius="4px"
+            :clickable="false"
+            :class="{ 'opacity-50': member.pending }"
+            :title="member.pending ? `${member.nickname}锛堟帴鍏ヤ腑锛塦 : member.nickname"
+          />
+        </div>
+      </template>
+    </div>
+
+    <!-- 鍙充笅瑙掞細鎷掔粷 / 鎺ュ惉 -->
+    <div class="flex flex-shrink-0 gap-2 items-center">
+      <button
+        class="flex flex-shrink-0 justify-center items-center w-10 h-10 text-white rounded-full transition-opacity bg-[#f04a4a] hover:opacity-90"
+        :class="{ 'opacity-60 cursor-not-allowed': rejectDisabled }"
+        :disabled="rejectDisabled"
+        @click="$emit('reject')"
+      >
+        <Icon icon="ant-design:phone-outlined" :size="18" class="rotate-[135deg]" />
+      </button>
+      <button
+        class="flex flex-shrink-0 justify-center items-center w-10 h-10 text-white rounded-full transition-opacity bg-[#2ec27e] hover:opacity-90"
+        :class="{ 'opacity-60 cursor-not-allowed': acceptDisabled }"
+        :disabled="acceptDisabled"
+        @click="$emit('accept')"
+      >
+        <Icon icon="ant-design:phone-outlined" :size="18" />
+      </button>
+    </div>
+  </div>
+</template>

--
Gitblit v1.9.3