From 0b2c40437bee95ecca2168fb154e675bb9f0d404 Mon Sep 17 00:00:00 2001
From: hsy <1029150275@qq.com>
Date: 星期二, 18 八月 2026 10:33:20 +0800
Subject: [PATCH] refactor: 根据角色标识获取报工人

---
 src/views/im/home/pages/contact/index.vue |  309 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 309 insertions(+), 0 deletions(-)

diff --git a/src/views/im/home/pages/contact/index.vue b/src/views/im/home/pages/contact/index.vue
new file mode 100644
index 0000000..a711125
--- /dev/null
+++ b/src/views/im/home/pages/contact/index.vue
@@ -0,0 +1,309 @@
+<script lang="ts" setup>
+import type { FriendLite, FriendRequest, Group, GroupLite, User } from '../../types'
+
+import { computed, onMounted, ref, watch } from 'vue'
+import { useRouter } from 'vue-router'
+
+import { confirm } from '#/packages/effects/common-ui/src'
+import { IconifyIcon as Icon } from '#/packages/icons/src'
+
+import { Input, message } from 'ant-design-vue'
+
+import { ImConversationType } from '../../../utils/constants'
+import { StorageKeys } from '../../../utils/db'
+import { getFriendDisplayName, getGroupDisplayName, isGroupQuit } from '../../../utils/user'
+import { ResizableAside } from '../../components'
+import { UserInfo } from '../../components/user'
+import { useConversationStore } from '../../store/conversationStore'
+import { useFriendStore } from '../../store/friendStore'
+import { useGroupStore } from '../../store/groupStore'
+import FriendList from './friend-list.vue'
+import FriendRequestDetail from './friend-request-detail.vue'
+import FriendRequestList from './friend-request-list.vue'
+import GroupDetail from './group-detail.vue'
+import GroupList from './group-list.vue'
+
+defineOptions({ name: 'ImContactPage' })
+
+const router = useRouter()
+const conversationStore = useConversationStore()
+const friendStore = useFriendStore()
+const groupStore = useGroupStore()
+
+/** 鐢� type 鍒ゅ埆閫変腑鏄ソ鍙� / 缇よ亰 / 濂藉弸鐢宠 */
+type Selection =
+  | { friend: FriendLite; type: 'friend'; }
+  | { group: GroupLite; type: 'group'; }
+  | { request: FriendRequest; type: 'request'; }
+
+const selection = ref<null | Selection>(null)
+const keyword = ref('')
+
+/** 閫変腑鐢宠璇︽儏锛氳鎯呯敤 store 閲岀殑鏈�鏂板壇鏈紙鍚屾剰 / 鎷掔粷鍚庣姸鎬佷細鍙橈級 */
+const currentRequest = computed<FriendRequest>(() => {
+  const req = selection.value?.type === 'request' ? selection.value.request : null
+  if (!req) {
+    return {} as FriendRequest
+  }
+  return friendStore.getFriendRequest(req.id) || req
+})
+
+/** 鎴戠浉鍏崇殑鐢宠鍒楄〃锛堢敤 friendStore 閲岀殑瀹炴椂鍓湰锛屼究浜庨�氱煡鍒拌揪鍚庤嚜鍔ㄥ埛鏂帮級 */
+const friendRequests = computed<FriendRequest[]>(() => friendStore.friendRequests)
+
+/** 濂藉弸鍒楄〃鐨勫睍绀哄揩鐓э細闄勫甫鍚庣绠楀ソ鐨勬嫾闊筹紝缁� FriendList 鍋氬瓧姣嶅垎妗� / 鎷奸煶鎼滅储 */
+const friends = computed<FriendLite[]>(() => friendStore.getActiveFriendLiteList)
+
+const groups = computed<GroupLite[]>(() =>
+  // 閫氳褰曞彧灞曠ず褰撳墠浠嶅湪缇ょ殑锛涘凡閫�缇ゅ巻鍙茬兢鍙暀鍦� store 閲屼緵娑堟伅灞曠ず缇ゅ悕 / 澶村儚锛屼笉杩涢�氳褰�
+  groupStore.groups
+    .filter((group: Group) => !isGroupQuit(group))
+    .map((group: Group) => ({
+      id: group.id,
+      name: group.name,
+      showGroupName: getGroupDisplayName(group), // 浼樺厛鐢ㄧ兢澶囨敞 groupRemark锛屾病璁剧疆鏃跺洖钀藉埌鍘熺兢鍚嶏紱閬垮厤鐐�"杩涘叆缇よ亰"鏃舵妸宸插悓姝ョ殑澶囨敞浼氳瘽鍚嶅埛鍥炲師鍚�
+      showImage: group.avatar,
+      showImageThumb: group.avatar,
+      memberCount: group.memberCount
+    }))
+)
+
+/**
+ * store 鍒楄〃鍙樺寲鏃跺悓姝� selection 鎸佺殑瀵硅薄鍓湰锛氬绔帹閫� / 璺ㄧ鍔ㄤ綔鏀� store 鍚庯紝鍙充晶璇︽儏鑳借窡涓婏細
+ * - 鍛戒腑鍒欐浛鎹负鏈�鏂板紩鐢紝璧勬枡 / 澶囨敞 / 鐢宠鐘舵�佸彉鏇寸珛鍒诲弽鏄�
+ * - 鎵句笉鍒帮紙鍒犻櫎 / 鎷掔粷 / 宸查�氳繃绛夎璁板綍娑堝け锛夊垯缃� null 鏀惰捣璇︽儏
+ */
+watch(
+  friends,
+  (list) => {
+    const selected = selection.value
+    if (selected?.type !== 'friend') {
+      return
+    }
+    const fresh = list.find((friend) => friend.id === selected.friend.id)
+    if (!fresh) {
+      selection.value = null
+    } else if (fresh !== selected.friend) {
+      selection.value = { type: 'friend', friend: fresh }
+    }
+  },
+  { deep: true }
+)
+watch(
+  groups,
+  (list) => {
+    const selected = selection.value
+    if (selected?.type !== 'group') {
+      return
+    }
+    const fresh = list.find((group) => group.id === selected.group.id)
+    if (!fresh) {
+      selection.value = null
+    } else if (fresh !== selected.group) {
+      selection.value = { type: 'group', group: fresh }
+    }
+  },
+  { deep: true }
+)
+watch(
+  friendRequests,
+  (list) => {
+    const selected = selection.value
+    if (selected?.type !== 'request') {
+      return
+    }
+    const fresh = list.find((request) => request.id === selected.request.id)
+    if (!fresh) {
+      selection.value = null
+    } else if (fresh !== selected.request) {
+      selection.value = { type: 'request', request: fresh }
+    }
+  },
+  { deep: true }
+)
+
+const friendUser = computed<null | User>(() => {
+  if (selection.value?.type !== 'friend') {
+    return null
+  }
+  const friend = selection.value.friend
+  return {
+    id: friend.id,
+    nickname: friend.nickname,
+    avatar: friend.avatar
+  }
+})
+
+onMounted(async () => {
+  await Promise.all([
+    friendStore.fetchFriendList(),
+    friendStore.fetchFriendRequestList(),
+    groupStore.fetchGroupList()
+  ])
+})
+
+/** 閫変腑濂藉弸 鈫� 鍒囧埌濂藉弸璇︽儏 */
+function handleSelectFriend(friend: FriendLite) {
+  selection.value = { type: 'friend', friend }
+}
+
+/** 閫変腑缇よ亰 鈫� 鍒囧埌缇よ鎯� */
+function handleSelectGroup(group: GroupLite) {
+  selection.value = { type: 'group', group }
+}
+
+/** 閫変腑濂藉弸鐢宠 鈫� 鍒囧埌銆屾柊鐨勬湅鍙嬨�嶈鎯� */
+function handleSelectRequest(request: FriendRequest) {
+  selection.value = { type: 'request', request }
+}
+
+/** 鐢宠璇︽儏閲岀偣銆屽彂娑堟伅銆嶏細鐩存帴杩涗笌瀵圭鐨勭鑱婁細璇� */
+function handleChatPeer(peerUserId: number) {
+  const friend = friendStore.getFriend(peerUserId)
+  const conversationName = friend ? getFriendDisplayName(friend) : String(peerUserId)
+  conversationStore.openConversation(
+    peerUserId,
+    ImConversationType.PRIVATE,
+    conversationName,
+    friend?.avatar || '',
+    { silent: !!friend?.silent }
+  )
+  router.push({ name: 'ImHomeConversation' })
+}
+
+/** 杩涘叆涓庤濂藉弸鐨勭鑱婁細璇� */
+function handleChatFriend(friend: FriendLite) {
+  // 浠� friendStore 鍚屾澶囨敞 + 鍏嶆墦鎵帮紝閬垮厤鏂板缓浼氳瘽鐢ㄨ繃鏈熸暟鎹�
+  const entry = friendStore.getFriend(friend.id)
+  const conversationName = entry ? getFriendDisplayName(entry) : friend.nickname
+  conversationStore.openConversation(
+    friend.id,
+    ImConversationType.PRIVATE,
+    conversationName,
+    friend.avatar || '',
+    { silent: !!entry?.silent }
+  )
+  router.push({ name: 'ImHomeConversation' })
+}
+
+/** 杩涘叆璇ョ兢鐨勭兢鑱婁細璇� */
+function handleChatGroup(group: GroupLite) {
+  const entry = groupStore.getGroup(group.id)
+  conversationStore.openConversation(
+    group.id,
+    ImConversationType.GROUP,
+    group.showGroupName || group.name || '',
+    group.showImage || group.showImageThumb || '',
+    { silent: !!entry?.silent }
+  )
+  router.push({ name: 'ImHomeConversation' })
+}
+
+/** 鍒犻櫎濂藉弸锛氫簩娆$‘璁� 鈫� store 钀藉簱 鈫� 娓呯┖褰撳墠閫変腑 */
+async function handleDeleteFriend(friend: FriendLite) {
+  try {
+    await confirm(`纭畾鍒犻櫎濂藉弸銆�${friend.nickname}銆嶅悧锛焋, '鍒犻櫎鑱旂郴浜�')
+    // friendStore.deleteFriend 鍐呴儴宸茬粡绾ц仈娓呯悊瀵瑰簲绉佽亰浼氳瘽
+    await friendStore.deleteFriend(friend.id)
+    if (selection.value?.type === 'friend' && selection.value.friend.id === friend.id) {
+      selection.value = null
+    }
+    message.success('宸插垹闄ゅソ鍙�')
+  } catch {}
+}
+
+/** 澶囨敞宸蹭繚瀛橈細UserInfo 鍐呴儴宸茬粡璧板畬 friendStore 钀藉簱 + 鎻愮ず锛屾湰渚у彧璐熻矗鍚屾 selection 鎸佺殑鏃� FriendLite 鍓湰 */
+function onRemarkSaved(displayName: string) {
+  if (selection.value?.type === 'friend') {
+    selection.value.friend.displayName = displayName
+  }
+}
+</script>
+
+<template>
+  <!--
+    閫氳褰� Tab 鏁撮〉锛堝弬鑰冨井淇� PC 閫氳褰曪級
+    - 宸︼細鎼滅储 + GroupList / FriendList 涓や釜鎶樺彔鍒嗙粍锛堝ソ鍙嬫寜瀛楁瘝鍒嗘《锛�
+    - 鍙筹細閫変腑椤圭殑璇︽儏锛屽ソ鍙嬭蛋鍏变韩 <UserInfo>锛坮elation=friend锛夛紝缇よ亰璧� GroupDetail
+    - 鏈〉浠呭仛锛氶�変腑鍒嗗彂 + 鏁版嵁婧愯浆鎹� + 璺ㄧ粍浠朵簨浠惰惤 store
+  -->
+  <div class="flex flex-1 h-full min-w-0 bg-[var(--ant-color-bg-container)]">
+    <ResizableAside :default-width="260" :storage-key="StorageKeys.localStorage.asideWidth">
+      <!-- 椤堕儴锛氫粎鎼滅储妗嗭紱h-14 涓庢秷鎭� Tab 椤堕儴瀵归綈锛岄伩鍏嶅垏鎹㈡椂鎼滅储妗嗕笂涓嬫姈鍔� -->
+      <div
+        class="flex flex-shrink-0 items-center h-14 px-4 border-b border-b-solid border-[var(--im-border-color-lighter)]"
+      >
+        <Input v-model:value="keyword" placeholder="鎼滅储" allow-clear class="flex-1">
+          <template #prefix>
+            <Icon icon="ant-design:search-outlined" />
+          </template>
+        </Input>
+      </div>
+
+      <!-- 鍒楄〃涓讳綋锛氭媶 FriendRequestList / GroupList / FriendList 涓変釜瀛愮粍浠讹紝鍚勮嚜绠$悊鎶樺彔 + 杩囨护锛涙湰椤靛彧閫忎紶閫変腑鎬� -->
+      <!-- overflow-y-auto锛氳仈绯讳汉澶氭椂鏈垪琛ㄥ彲婊氬姩锛堢埗 ResizableAside 涓嶆彁渚涙粴鍔級锛屽榻� Vue3 鐨� el-scrollbar -->
+      <div class="flex-1 overflow-y-auto">
+        <FriendRequestList
+          :requests="friendRequests"
+          :active-id="selection?.type === 'request' ? selection.request.id : undefined"
+          @select="handleSelectRequest"
+        />
+        <GroupList
+          :groups="groups"
+          :keyword="keyword"
+          :active-id="selection?.type === 'group' ? selection.group.id : undefined"
+          @select="handleSelectGroup"
+        />
+        <FriendList
+          :friends="friends"
+          :keyword="keyword"
+          :active-id="selection?.type === 'friend' ? selection.friend.id : undefined"
+          @select="handleSelectFriend"
+          @chat="handleChatFriend"
+          @delete="handleDeleteFriend"
+        />
+      </div>
+    </ResizableAside>
+
+    <!-- 鍙充晶璇︽儏鍖� -->
+    <div class="flex-1 min-w-0">
+      <!-- 绌烘�侊細鍗犱綅鍥炬爣 + 鎻愮ず鏂囨 -->
+      <div
+        v-if="!selection"
+        class="flex flex-col items-center justify-center h-full gap-3 text-[var(--ant-color-text-secondary)]"
+      >
+        <Icon
+          icon="ant-design:contacts-outlined"
+          :size="64"
+          class="text-[var(--ant-color-text-placeholder)]"
+        />
+        <span class="text-sm">鍦ㄥ乏渚ч�夋嫨濂藉弸鎴栫兢鑱婃煡鐪嬭鎯�</span>
+      </div>
+      <!-- 濂藉弸璇︽儏 -->
+      <div v-else-if="selection.type === 'friend'" class="flex justify-center pt-12 px-6">
+        <div class="w-full max-w-[320px]">
+          <UserInfo
+            :user="friendUser"
+            :display-name="selection.friend.displayName || ''"
+            relation="friend"
+            @chat="handleChatFriend(selection.friend)"
+            @deleted="selection = null"
+            @saved="onRemarkSaved"
+          />
+        </div>
+      </div>
+      <!-- 缇よ鎯� -->
+      <GroupDetail
+        v-else-if="selection.type === 'group'"
+        :group="selection.group"
+        @chat="handleChatGroup"
+      />
+      <!-- 鏂扮殑鏈嬪弸 - 鐢宠璇︽儏 -->
+      <FriendRequestDetail
+        v-else-if="selection.type === 'request'"
+        :request="currentRequest"
+        @chat="handleChatPeer"
+      />
+    </div>
+  </div>
+</template>

--
Gitblit v1.9.3