7 天以前 91c82965b2d987452ca276e3a03b48c8dcda2ae9
src/views/im/home/pages/contact/friend-request-list.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,138 @@
<script lang="ts" setup>
import type { FriendRequest } from '../../types'
import { computed, ref } 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 { Badge } from 'ant-design-vue'
import { getCurrentUserId } from '#/views/im/utils/auth'
import { UserAvatar } from '../../components/user'
import { useFriendStore } from '../../store/friendStore'
defineOptions({ name: 'ImContactFriendRequestList' })
const props = defineProps<{
  activeId?: number
  requests: FriendRequest[]
}>()
const emit = defineEmits<{
  select: [request: FriendRequest]
}>()
const friendStore = useFriendStore()
const expanded = ref(true)
/** å½“前登录用户编号;用 computed åŒ…一层,切账号后随 wsCache é‡å–,避免顶层求值在 keep-alive å®žä¾‹é‡ŒæŒæœ‰æ—§ id */
const currentUserId = computed(() => getCurrentUserId())
/** åˆ—表项展示对端:fromUserId == æˆ‘ â†’ å¯¹ç«¯ = toUser;否则对端 = fromUser */
function getPeer(request: FriendRequest) {
  const sentByMe = request.fromUserId === currentUserId.value
  return {
    id: sentByMe ? request.toUserId : request.fromUserId,
    nickname: sentByMe
      ? request.toNickname || String(request.toUserId)
      : request.fromNickname || String(request.fromUserId),
    avatar: sentByMe ? request.toAvatar : request.fromAvatar
  }
}
/** åˆ—表项预先附 peer å­—段,模板里直接 {{ peer.xxx }} ä¸€æ¬¡æˆåž‹ï¼Œçœ 3 æ¬¡ helper è°ƒç”¨ */
const enrichedRequests = computed(() =>
  props.requests.map((request) => ({ request, peer: getPeer(request) }))
)
const loadingMore = ref(false) // ç‚¹å‡»ã€ŒåŠ è½½æ›´å¤šã€æ‹‰ä¸‹ä¸€é¡µï¼›store å†…部按 maxId æ¸¸æ ‡åˆ†é¡µ + pending åŽ»é‡
async function handleLoadMore() {
  if (loadingMore.value) {
    return
  }
  loadingMore.value = true
  try {
    await friendStore.loadMoreFriendRequestList()
  } finally {
    loadingMore.value = false
  }
}
</script>
<template>
  <!--
    é€šè®¯å½• - æ–°çš„æœ‹å‹åˆ†ç»„
    - è‡ªæ²»ï¼šæŠ˜å çŠ¶æ€ç”±ç»„ä»¶å†… ref ç®¡ç†ï¼Œé»˜è®¤å±•å¼€
    - åˆ—表项展示:头像 + æ˜µç§° + ç”³è¯·ç†ç”± + çŠ¶æ€æ ‡ç­¾ï¼ˆç­‰å¾…éªŒè¯ / å·²æ·»åŠ  / å·²æ‹’绝)
    - é€‰ä¸­æ€ç”±çˆ¶çº§ activeId é€ä¼ ï¼›ç‚¹å‡»è§¦å‘ select äº‹ä»¶
  -->
  <div>
    <!-- æŠ˜å åˆ†ç»„头 -->
    <div
      class="flex gap-2 items-center px-3.5 py-2.5 text-15px text-[var(--ant-color-text)] cursor-pointer select-none hover:bg-[var(--ant-color-fill-secondary)]"
      @click="expanded = !expanded"
    >
      <Icon :icon="expanded ? 'ep:caret-bottom' : 'ep:caret-right'" :size="14" />
      <span class="flex-1">新的朋友</span>
      <!-- çº¢ç‚¹ï¼šæœªå¤„理且别人加我的(统一走 store getter,避免本地 computed è·Ÿ store åŒå£å¾„) -->
      <Badge
        v-if="friendStore.getUnhandledRequestCount > 0"
        :count="friendStore.getUnhandledRequestCount"
        :max="99"
        class="mr-2"
      />
      <span class="text-sm text-[var(--ant-color-text-secondary)]">{{ requests.length }}</span>
    </div>
    <div v-show="expanded">
      <div
        v-for="{ request, peer } in enrichedRequests"
        :key="request.id"
        class="flex gap-3 items-start px-3.5 py-2.5 cursor-pointer transition-colors hover:bg-[var(--ant-color-fill-secondary)]"
        :class="{
          'bg-[var(--ant-color-fill)]': activeId === request.id
        }"
        @click="emit('select', request)"
      >
        <UserAvatar
          :id="peer.id"
          :url="peer.avatar"
          :name="peer.nickname"
          :size="36"
          :clickable="false"
        />
        <div class="flex-1 min-w-0 overflow-hidden">
          <div class="flex justify-between gap-2 items-center">
            <span class="flex-1 text-sm font-medium truncate text-[var(--ant-color-text)]">
              {{ peer.nickname }}
            </span>
            <span class="flex-shrink-0 text-12px text-[var(--ant-color-text-secondary)]">
              {{ getDictLabel(DICT_TYPE.IM_FRIEND_REQUEST_HANDLE_RESULT, request.handleResult) }}
            </span>
          </div>
          <div
            v-if="request.applyContent"
            class="mt-0.5 text-xs truncate text-[var(--ant-color-text-secondary)]"
          >
            {{ request.applyContent }}
          </div>
        </div>
      </div>
      <div
        v-if="requests.length === 0"
        class="py-3 text-12px text-center text-[var(--ant-color-text-disabled)]"
      >
        æš‚无新的朋友
      </div>
      <!-- åŠ è½½æ›´å¤šï¼šæŒ‰æœ¬åœ°æœ€æ—§ requestId æ¸¸æ ‡åˆ†é¡µæ‹‰ä¸‹ä¸€æ‰¹ï¼›hasMore=false ä¸å±•示 -->
      <div
        v-else-if="friendStore.hasMoreFriendRequests"
        class="py-2 text-12px text-center cursor-pointer text-[var(--ant-color-text-secondary)] hover:bg-[var(--ant-color-fill-secondary)]"
        @click="handleLoadMore"
      >
        {{ loadingMore ? '加载中…' : '加载更多' }}
      </div>
    </div>
  </div>
</template>