| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { FriendRequest, User } from '../../types' |
| | | |
| | | import { computed, ref } from 'vue' |
| | | |
| | | import { prompt } from '#/packages/effects/common-ui/src' |
| | | import { DICT_TYPE } from '#/packages/constants/src' |
| | | import { getDictLabel } from '#/packages/effects/hooks/src' |
| | | |
| | | import { Button, Input, message } from 'ant-design-vue' |
| | | |
| | | import { getCurrentUserId } from '#/views/im/utils/auth' |
| | | |
| | | import { ImFriendRequestHandleResult } from '../../../utils/constants' |
| | | import { UserAvatar } from '../../components/user' |
| | | import { UserInfo } from '../../components/user' |
| | | import { useFriendStore } from '../../store/friendStore' |
| | | |
| | | defineOptions({ name: 'ImContactFriendRequestDetail' }) |
| | | |
| | | const props = defineProps<{ |
| | | request: FriendRequest |
| | | }>() |
| | | |
| | | const emit = defineEmits<{ |
| | | chat: [peerUserId: number] |
| | | }>() |
| | | |
| | | const friendStore = useFriendStore() |
| | | |
| | | /** å½åç»å½ç¨æ·ç¼å·ï¼ç¨ computed å
ä¸å±ï¼åè´¦å·åé wsCache éåï¼é¿å
顶屿±å¼å¨ keep-alive å®ä¾éæææ§ id */ |
| | | const currentUserId = computed(() => getCurrentUserId()) |
| | | |
| | | /** æ¯ä¸æ¯æåèµ·çï¼fromUserId === currentUserIdï¼ */ |
| | | const iSentIt = computed(() => props.request.fromUserId === currentUserId.value) |
| | | |
| | | /** æ¯å¦ãå·²æç»ãæï¼æ¨¡æ¿éå¤å¤ç¨å°ï¼computed 䏿¬¡çå¾å°å¤åæä¸¾æ¯å¯¹ */ |
| | | const refused = computed( |
| | | () => props.request.handleResult === ImFriendRequestHandleResult.REFUSED |
| | | ) |
| | | |
| | | /** æ¯å¦ãå·²éè¿ãæï¼è½¬èµ° UserInfo 好å详æ
å
¥å£ */ |
| | | const agreed = computed( |
| | | () => props.request.handleResult === ImFriendRequestHandleResult.AGREED |
| | | ) |
| | | |
| | | /** 对端çç¨æ·ç¼å· / æµç§° / 头å */ |
| | | const peerUserId = computed(() => |
| | | iSentIt.value ? props.request.toUserId : props.request.fromUserId |
| | | ) |
| | | const peerNickname = computed(() => |
| | | iSentIt.value |
| | | ? props.request.toNickname || String(props.request.toUserId) |
| | | : props.request.fromNickname || String(props.request.fromUserId) |
| | | ) |
| | | const peerAvatar = computed(() => |
| | | iSentIt.value ? props.request.toAvatar : props.request.fromAvatar |
| | | ) |
| | | |
| | | /** éç» UserInfo çæå°ç¨æ·ä¿¡æ¯ï¼UserInfo å
é¨ä¼æ id è° getSimpleUser è¡¥é½æ§å« / é¨é¨ */ |
| | | const peerUser = computed<User>(() => ({ |
| | | id: peerUserId.value, |
| | | nickname: peerNickname.value, |
| | | avatar: peerAvatar.value |
| | | })) |
| | | |
| | | // åèªç loading ç¨äºæé® spinner æ¾ç¤ºï¼processing æ¯è·¨æé®äºæ¥éï¼é¿å
åæ / æç»å¹¶åæäº¤åä¸ç³è¯· |
| | | const agreeing = ref(false) |
| | | const refusing = ref(false) |
| | | const processing = ref(false) |
| | | |
| | | /** åæç³è¯·ï¼äºæ¥é + ç¶æäºæ¬¡æ ¡éªï¼é¿å
å¹¶å / æå¡ç«¯å·²å¤çå忬¡æäº¤ */ |
| | | async function handleAgree() { |
| | | if (processing.value) { |
| | | return |
| | | } |
| | | if (props.request.handleResult !== ImFriendRequestHandleResult.UNHANDLED) { |
| | | return |
| | | } |
| | | processing.value = true |
| | | agreeing.value = true |
| | | try { |
| | | await friendStore.agreeFriendRequest(props.request.id) |
| | | message.success('å·²åæå¥½åç³è¯·') |
| | | } finally { |
| | | agreeing.value = false |
| | | processing.value = false |
| | | } |
| | | } |
| | | |
| | | /** æç»ç³è¯·ï¼å¼¹ prompt æ¶éå¯éæç»çç±ï¼ç¹åæ¶å䏿¢ï¼ï¼éåè° store è½åº + æç¤º */ |
| | | async function handleRefuse() { |
| | | if (processing.value) { |
| | | return |
| | | } |
| | | if (props.request.handleResult !== ImFriendRequestHandleResult.UNHANDLED) { |
| | | return |
| | | } |
| | | // 1. å¼¹ prompt æ¶éæç»çç±ï¼æå¤ 255 åï¼ï¼ç¨æ·ç¹ãåæ¶ãä¼ rejectï¼ä¸æ¢åç»æµç¨ |
| | | let handleContent: string | undefined |
| | | try { |
| | | const result = await prompt<string>({ |
| | | beforeClose(scope) { |
| | | if (!scope.isConfirm) { |
| | | return |
| | | } |
| | | if ((scope.value || '').length > 255) { |
| | | message.error('æå¤ 255 个å符') |
| | | return false |
| | | } |
| | | }, |
| | | cancelText: 'åæ¶', |
| | | component: Input.TextArea, |
| | | componentProps: { |
| | | allowClear: true, |
| | | maxlength: 255, |
| | | placeholder: 'ä¸å¡«åä¸åç¥å¯¹æ¹åå ', |
| | | rows: 3 |
| | | }, |
| | | content: '', |
| | | defaultValue: '', |
| | | confirmText: 'æç»', |
| | | modelPropName: 'value', |
| | | title: 'æç»å¥½åç³è¯·' |
| | | }) |
| | | handleContent = result || undefined |
| | | } catch { |
| | | return |
| | | } |
| | | // 2. prompt æé´ç¶æå¯è½è¢«è·¨ç«¯æ¹æ AGREED / REFUSEDï¼åæ ¡éªä¸æ¬¡é¿å
éå¤æäº¤ |
| | | if (processing.value) { |
| | | return |
| | | } |
| | | if (props.request.handleResult !== ImFriendRequestHandleResult.UNHANDLED) { |
| | | return |
| | | } |
| | | processing.value = true |
| | | refusing.value = true |
| | | try { |
| | | await friendStore.refuseFriendRequest(props.request.id, handleContent) |
| | | message.success('å·²æç»å¥½åç³è¯·') |
| | | } finally { |
| | | refusing.value = false |
| | | processing.value = false |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <!-- |
| | | æ°çæå详æ
颿¿ |
| | | - å·²éè¿ â ç´æ¥èµ° UserInfo 好å详æ
ï¼è·é讯å½éç¹å¼å¥½åçä½éªå®å
¨ä¸è´ |
| | | - æªå¤ç / å·²æç» â ç³è¯·æé¢æ¿ï¼å¤´å + ç³è¯·/æç»å¯¹è¯æ°æ³¡ + æ¥æº + æä½æé® |
| | | --> |
| | | <div v-if="agreed" class="flex justify-center pt-12 px-6"> |
| | | <div class="w-full max-w-[320px]"> |
| | | <UserInfo |
| | | :user="peerUser" |
| | | :display-name="friendStore.getFriend(peerUserId)?.displayName || ''" |
| | | relation="friend" |
| | | @chat="emit('chat', peerUserId)" |
| | | /> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-else class="flex flex-col items-center px-6 pt-12"> |
| | | <UserAvatar |
| | | :id="peerUserId" |
| | | :url="peerAvatar" |
| | | :name="peerNickname" |
| | | :size="64" |
| | | :clickable="false" |
| | | /> |
| | | <div class="mt-3 text-base font-semibold text-[var(--ant-color-text)]"> |
| | | {{ peerNickname }} |
| | | </div> |
| | | |
| | | <!-- ç³è¯·çç±åï¼ä»¿å¾®ä¿¡ç°åºæ°æ³¡ï¼æç³è¯·æ¹èº«ä»½åç¼ï¼é¿ææ¬ break-words æè¡ --> |
| | | <div |
| | | v-if="request.applyContent" |
| | | class="w-full max-w-[420px] mt-6 px-3.5 py-3 rounded-md bg-[var(--ant-color-fill-secondary)] text-13px text-[var(--ant-color-text)] break-words" |
| | | > |
| | | <span class="text-[var(--ant-color-text-secondary)]"> |
| | | {{ iSentIt ? 'æ' : peerNickname }}: |
| | | </span> |
| | | <span class="ml-1">{{ request.applyContent }}</span> |
| | | </div> |
| | | <!-- æ¥æºè¡ï¼label å·¦ãvalue å³ï¼å¯¹é½å¾®ä¿¡ãæ¥æºãè¡ --> |
| | | <div |
| | | v-if="request.addSource" |
| | | class="w-full max-w-[420px] mt-3 flex items-center text-13px text-[var(--ant-color-text-secondary)]" |
| | | > |
| | | <span class="w-16 flex-shrink-0 whitespace-nowrap">æ¥æº</span> |
| | | <span class="text-[var(--ant-color-text)]"> |
| | | {{ getDictLabel(DICT_TYPE.IM_FRIEND_ADD_SOURCE, request.addSource) }} |
| | | </span> |
| | | </div> |
| | | <!-- æç»çç±ï¼label å·¦ãvalue å³ï¼é¿ææ¬ break-words èªå¨æè¡ --> |
| | | <div |
| | | v-if="refused && request.handleContent" |
| | | class="w-full max-w-[420px] mt-3 flex items-start text-13px text-[var(--ant-color-text-secondary)]" |
| | | > |
| | | <span class="w-16 flex-shrink-0 whitespace-nowrap">æç»çç±</span> |
| | | <span class="flex-1 min-w-0 break-words text-[var(--ant-color-text)]"> |
| | | {{ request.handleContent }} |
| | | </span> |
| | | </div> |
| | | |
| | | <!-- æä½æé® --> |
| | | <div class="w-full max-w-[420px] mt-8 flex justify-center"> |
| | | <!-- æåèµ· + çå¾
ä¸ï¼ç¦ç¨ãçå¾
对æ¹éªè¯ã --> |
| | | <Button |
| | | v-if="iSentIt && request.handleResult === ImFriendRequestHandleResult.UNHANDLED" |
| | | disabled |
| | | > |
| | | çå¾
对æ¹éªè¯ |
| | | </Button> |
| | | <!-- å«äººå æ + çå¾
ä¸ï¼åæ / æç» --> |
| | | <template v-if="!iSentIt && request.handleResult === ImFriendRequestHandleResult.UNHANDLED"> |
| | | <Button @click="handleRefuse" :loading="refusing" :disabled="processing">æç»</Button> |
| | | <Button type="primary" @click="handleAgree" :loading="agreeing" :disabled="processing"> |
| | | åæ |
| | | </Button> |
| | | </template> |
| | | <!-- å·²æç»ï¼å ä½ç¦ç¨æé® --> |
| | | <Button v-if="refused" disabled>å·²æç»</Button> |
| | | </div> |
| | | </div> |
| | | </template> |