From f11bd0d8d9c1190340a445a67df9e43cdbde0a3e Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期四, 27 八月 2026 11:21:26 +0800
Subject: [PATCH] feat(mes): 基础参数与工序绑定前端 + 报工填写参数字段
---
src/views/im/home/pages/contact/friend-request-detail.vue | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 229 insertions(+), 0 deletions(-)
diff --git a/src/views/im/home/pages/contact/friend-request-detail.vue b/src/views/im/home/pages/contact/friend-request-detail.vue
new file mode 100644
index 0000000..235af5c
--- /dev/null
+++ b/src/views/im/home/pages/contact/friend-request-detail.vue
@@ -0,0 +1,229 @@
+<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 鏄剧ず锛沺rocessing 鏄法鎸夐挳浜掓枼閿侊紝閬垮厤鍚屾剰 / 鎷掔粷骞跺彂鎻愪氦鍚屼竴鐢宠
+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 宸︺�乿alue 鍙筹紝瀵归綈寰俊銆屾潵婧愩�嶈 -->
+ <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>
+ <!-- 鎷掔粷鐞嗙敱锛歭abel 宸︺�乿alue 鍙筹紱闀挎枃鏈� 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>
--
Gitblit v1.9.3