From 5367b3b4d92588c4e76728e6bd4ad6aae0cbb967 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 23 七月 2026 13:05:25 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_pro2.0' into dev_pro2.0
---
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