From 91c82965b2d987452ca276e3a03b48c8dcda2ae9 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 19 八月 2026 11:47:26 +0800
Subject: [PATCH] config(env): 更新生产环境配置和公司名称
---
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