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/group/group-info.vue |  154 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 154 insertions(+), 0 deletions(-)

diff --git a/src/views/im/home/components/group/group-info.vue b/src/views/im/home/components/group/group-info.vue
new file mode 100644
index 0000000..9254cc1
--- /dev/null
+++ b/src/views/im/home/components/group/group-info.vue
@@ -0,0 +1,154 @@
+<script lang="ts" setup>
+import type { Friend, GroupLite, GroupMember } from '../../types'
+import type { GroupMemberLite } from './group-member.vue'
+
+import { computed, ref, watch } from 'vue'
+
+import { CommonStatusEnum } from '#/packages/constants/src'
+
+import { Button } from 'ant-design-vue'
+
+import { getCurrentUserId } from '#/views/im/utils/auth'
+
+import { getMemberDisplayName, isGroupQuit } from '../../../utils/user'
+import { useFriendStore } from '../../store/friendStore'
+import { useGroupStore } from '../../store/groupStore'
+import GroupAvatar from './group-avatar.vue'
+import GroupMemberGrid from './group-member-grid.vue'
+
+defineOptions({ name: 'ImGroupInfo' })
+
+const props = defineProps<{
+  group: GroupLite
+}>()
+
+const emit = defineEmits<{
+  /** stranger 鐐广�屽姞鍏ョ兢鑱娿�嶏紱鐖剁骇璐熻矗寮圭敵璇风悊鐢� + 璋� applyJoinGroup */
+  apply: [group: GroupLite]
+  /** member 鐐广�岃繘鍏ョ兢鑱娿�嶏紱鐖剁骇璐熻矗鍒囦細璇� + 鍏虫诞灞� */
+  chat: [group: GroupLite]
+}>()
+
+const groupStore = useGroupStore()
+const friendStore = useFriendStore()
+
+const members = ref<GroupMemberLite[]>([])
+
+/**
+ * 鏄惁宸插姞缇わ細鍩轰簬"鑷繁纭疄鍦ㄦ垚鍛樺垪琛ㄩ噷"鍒ゆ柇
+ * - 缂撳瓨鏈懡涓細鐩存帴 false锛堥檶鐢熺兢锛�
+ * - 鍛戒腑涓� members 宸叉媺锛氱簿鍑嗘煡 self.userId 鍦ㄤ笉鍦�
+ * - 鍛戒腑浣� members 鏈媺锛歠etchGroupList 鎺ュ彛璇箟鍗炽�屾垜鍔犲叆鐨勭兢銆嶏紝鍛戒腑瑙嗕负 member锛堟媺鎴愬憳鍚庝細鑷姩鏀舵暃锛�
+ */
+const isMember = computed(() => {
+  if (!props.group?.id) {
+    return false
+  }
+  const cached = groupStore.getGroup(props.group.id)
+  if (!cached) {
+    return false
+  }
+  // 鍘嗗彶閫�缇ょ兢锛氱洿鎺ュ垽 false锛岄伩鍏嶆垚鍛樻湭鍔犺浇鏃惰鏄剧ず銆岃繘鍏ョ兢鑱娿��
+  if (isGroupQuit(cached)) {
+    return false
+  }
+  if (cached.membersLoaded && cached.members) {
+    const myId = getCurrentUserId()
+    return cached.members.some((m) => m.userId === myId && m.status === CommonStatusEnum.ENABLE)
+  }
+  return true
+})
+/** 鍘嗗彶閫�缇ょ兢锛氬彧璇伙紝鍔ㄤ綔鍖轰袱涓寜閽兘涓嶆覆鏌擄紙鏃笉銆岃繘鍏ョ兢鑱娿�嶄篃涓嶃�屽姞鍏ョ兢鑱娿�嶏級 */
+const isQuitGroup = computed(() => {
+  const id = props.group?.id
+  return id != null && isGroupQuit(groupStore.getGroup(id))
+})
+/** 鏄惁鏈姞缇わ細鏈� id銆侀潪鎴愬憳銆佷笖闈炲巻鍙查��缇ょ兢锛涘彧鏈夌湡路闄岀敓浜烘墠缁欍�屽姞鍏ョ兢鑱娿�� */
+const isStranger = computed(() => !!props.group?.id && !isMember.value && !isQuitGroup.value)
+
+/** 鎴愬憳鏁版枃妗堬細member 浼樺厛鐢ㄦ湰鍦版媺鍒扮殑鍒楄〃闀垮害锛宻tranger 鐢� props.group.memberCount 鍗$墖蹇収 */
+const memberCountText = computed(() => {
+  const count = isMember.value
+    ? props.group.memberCount || members.value.length
+    : props.group.memberCount
+  return count ? `${count} 浣嶆垚鍛榒 : ''
+})
+
+/** member 鍒囩兢 / 棣栨寕锛氭媺鎴愬憳锛涚珵鎬佺敤 group.id 姣斿涓㈠純闄堟棫鍝嶅簲閬垮厤涓婁竴鏉$兢鎴愬憳閿欎綅 */
+watch(
+  () => [props.group?.id, isMember.value] as const,
+  async ([id, member]) => {
+    members.value = []
+    if (!id || !member) {
+      return
+    }
+    const list = await groupStore.fetchGroupMemberList(id, true)
+    if (props.group?.id !== id) {
+      return
+    }
+    members.value = list.map((m) => convertGroupMemberLite(m, friendStore.getFriend(m.userId)))
+  },
+  { immediate: true }
+)
+
+/** 缇ゆ垚鍛� 鈫� 鍒楄〃椤� */
+function convertGroupMemberLite(member: GroupMember, friend: Friend | undefined): GroupMemberLite {
+  return {
+    userId: member.userId,
+    showName: getMemberDisplayName(member, friend),
+    nickname: member.nickname,
+    avatar: member.avatar,
+    status: member.status,
+    role: member.role
+  }
+}
+</script>
+
+<template>
+  <!--
+    缇や俊鎭唴瀹圭粍浠讹紙涓� UserInfo 瀵逛綅锛�
+    - 澶村儚 + 缇ゅ悕 + 鎴愬憳鏁� + 鎴愬憳瀹牸 + 鍔ㄤ綔鍖猴紝绾睍绀� + 鎶涗簨浠讹紝涓氬姟鐢辩埗绾ф壙鎺�
+    - relation 璧� groupStore 缂撳瓨鎺ㄥ锛氬懡涓� = member锛堝凡鍔犵兢锛夛紝鍚﹀垯 = stranger锛堟湭鍔犵兢锛夛紝鏃� id = readonly
+    - 鎴愬憳瀹牸浠� member 鏃舵媺鍙栵紙闄岀敓缇ゆ媺涓嶅埌锛屾墍鏈変俊鎭蛋 props.group 鍗$墖蹇収锛�
+  -->
+  <div class="flex justify-center">
+    <div class="w-full max-w-[320px] flex flex-col gap-3 items-center">
+      <GroupAvatar
+        :group-id="group.id"
+        :url="group.showImage || group.showImageThumb"
+        :name="group.showGroupName || group.name"
+        :size="72"
+        :previewable="isMember"
+      />
+      <div
+        class="w-full text-lg font-semibold leading-snug text-[var(--ant-color-text)] truncate text-center"
+      >
+        {{ group.showGroupName || group.name }}
+      </div>
+      <div v-if="memberCountText" class="text-13px text-[var(--ant-color-text-secondary)]">
+        {{ memberCountText }}
+      </div>
+
+      <!-- 鎴愬憳瀹牸锛氫粎 member 娓叉煋锛堥檶鐢熺兢鎷変笉鍒版垚鍛橈級 -->
+      <div
+        v-if="isMember && members.length > 0"
+        class="flex flex-wrap gap-2 justify-center w-full pt-2"
+      >
+        <GroupMemberGrid
+          v-for="member in members"
+          :key="member.userId"
+          :member="member"
+          :group-name="group.name"
+        />
+      </div>
+
+      <!-- 鍔ㄤ綔鍖猴細member 杩涘叆缇よ亰 / stranger 鍔犲叆缇よ亰 / readonly 涓嶆覆鏌� -->
+      <div v-if="isMember" class="mt-4">
+        <Button type="primary" @click="emit('chat', group)">杩涘叆缇よ亰</Button>
+      </div>
+      <div v-else-if="isStranger" class="mt-4">
+        <Button type="primary" @click="emit('apply', group)">鍔犲叆缇よ亰</Button>
+      </div>
+    </div>
+  </div>
+</template>

--
Gitblit v1.9.3