From 47fac373b78cb7860a282d4d18df507c111e427f Mon Sep 17 00:00:00 2001 From: liqi Date: Thu, 4 Dec 2025 09:46:29 +0800 Subject: [PATCH] =?UTF-8?q?=E9=83=A8=E5=88=86=E8=81=94=E7=B3=BB=E4=BA=BA?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E5=92=8C=E4=BC=9A=E8=AF=9D=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stores/contact.ts | 13 +++++-- src/utils/storage.ts | 47 +++++++++++++++++++++++++ src/views/chat/ChatView.vue | 22 ++++++++++-- src/views/contact/ContactDetail.vue | 6 ++-- src/views/contact/ContactDetailCard.vue | 18 +++------- src/views/contact/FriendNotifyView.vue | 23 +++++++++--- 6 files changed, 104 insertions(+), 25 deletions(-) diff --git a/src/stores/contact.ts b/src/stores/contact.ts index cd21930..901ec06 100644 --- a/src/stores/contact.ts +++ b/src/stores/contact.ts @@ -1,5 +1,6 @@ import { defineStore } from 'pinia' -import { ref } from 'vue' +import { ref, watch } from 'vue' +import { storage } from '@/utils/storage' import type { FriendRequest, ContactGroup, Contact } from '@/types/api' export type LeftPanelMode = 'default' | 'friend-manager' | 'friend-notify' | 'group-notify' @@ -7,9 +8,9 @@ export type LeftPanelMode = 'default' | 'friend-manager' | 'friend-notify' | 'gr export const useContactStore = defineStore('contact', () => { const friendRequests = ref([]) const groups = ref([]) - const leftPanelMode = ref('default') + const leftPanelMode = ref(storage.getContactLeftPanelMode() as LeftPanelMode) const selectedContact = ref(null) - const contactListTab = ref<'friends' | 'groups'>('friends') + const contactListTab = ref<'friends' | 'groups'>(storage.getContactListTab()) /** * 设置好友申请列表 @@ -74,6 +75,7 @@ export const useContactStore = defineStore('contact', () => { */ function setLeftPanelMode(mode: LeftPanelMode) { leftPanelMode.value = mode + storage.setContactLeftPanelMode(mode) // 切换到管理/通知模式时,清除选中联系人 if (mode !== 'default') { selectedContact.value = null @@ -91,6 +93,11 @@ export const useContactStore = defineStore('contact', () => { } } + // 监听 contactListTab 变化并保存 + watch(contactListTab, (newTab) => { + storage.setContactListTab(newTab) + }) + return { friendRequests, groups, diff --git a/src/utils/storage.ts b/src/utils/storage.ts index 3cbefca..96cf42e 100644 --- a/src/utils/storage.ts +++ b/src/utils/storage.ts @@ -6,6 +6,10 @@ const TOKEN_KEY = 'token' const USER_ID_KEY = 'user_id' const USER_INFO_KEY = 'user_info' const REMEMBER_KEY = 'remember' +const CURRENT_TAB_KEY = 'current_tab' +const CONTACT_LEFT_PANEL_MODE_KEY = 'contact_left_panel_mode' +const CONTACT_LIST_TAB_KEY = 'contact_list_tab' +const SELECTED_CONVERSATION_KEY = 'selected_conversation' export const storage = { // Token @@ -57,12 +61,55 @@ export const storage = { return localStorage.getItem(REMEMBER_KEY) === 'true' }, + // Current Tab (chat/contact) + setCurrentTab(tab: 'chat' | 'contact') { + localStorage.setItem(CURRENT_TAB_KEY, tab) + }, + + getCurrentTab(): 'chat' | 'contact' { + const tab = localStorage.getItem(CURRENT_TAB_KEY) + return (tab === 'chat' || tab === 'contact') ? tab : 'chat' + }, + + // Contact Left Panel Mode + setContactLeftPanelMode(mode: string) { + localStorage.setItem(CONTACT_LEFT_PANEL_MODE_KEY, mode) + }, + + getContactLeftPanelMode(): string { + return localStorage.getItem(CONTACT_LEFT_PANEL_MODE_KEY) || 'default' + }, + + // Contact List Tab + setContactListTab(tab: 'friends' | 'groups') { + localStorage.setItem(CONTACT_LIST_TAB_KEY, tab) + }, + + getContactListTab(): 'friends' | 'groups' { + const tab = localStorage.getItem(CONTACT_LIST_TAB_KEY) + return (tab === 'friends' || tab === 'groups') ? tab : 'friends' + }, + + // Selected Conversation + setSelectedConversation(targetId: string | null) { + if (targetId) { + localStorage.setItem(SELECTED_CONVERSATION_KEY, targetId) + } else { + localStorage.removeItem(SELECTED_CONVERSATION_KEY) + } + }, + + getSelectedConversation(): string | null { + return localStorage.getItem(SELECTED_CONVERSATION_KEY) + }, + // Clear all clear() { this.removeToken() this.removeUserId() this.removeUserInfo() this.setRemember(false) + // 不清除 UI 状态,让用户刷新后保持界面状态 }, } diff --git a/src/views/chat/ChatView.vue b/src/views/chat/ChatView.vue index 7d0b3db..794feb5 100644 --- a/src/views/chat/ChatView.vue +++ b/src/views/chat/ChatView.vue @@ -264,6 +264,7 @@ import * as messageApi from '@/api/modules/message' import * as contactApi from '@/api/modules/contact' import * as attachmentApi from '@/api/modules/attachment' import { formatTime } from '@/utils/format' +import { storage } from '@/utils/storage' import type { Contact, ChatMessage } from '@/types/api' import type { Conversation } from '@/types/conversation' import { useWebRTC } from '@/composables/useWebRTC' @@ -296,8 +297,8 @@ function handleIncomingCall(senderUserId: string) { } const webrtc = useWebRTC(authStore.user?.id || '', handleIncomingCall) -// State -const currentTab = ref<'chat' | 'contact'>('chat') +// State - 从本地存储恢复 +const currentTab = ref<'chat' | 'contact'>(storage.getCurrentTab()) const searchQuery = ref('') const inputText = ref('') const chatVisible = ref(false) @@ -364,6 +365,8 @@ function scrollToBottom(smooth = true) { } async function selectChat(contact: Contact) { + // 保存选中的会话 + storage.setSelectedConversation(contact.user_id || contact.id) chatStore.setCurrentTarget(contact) chatVisible.value = true unreadCount.value = 0 // 切换聊天时重置 @@ -496,6 +499,11 @@ async function handleRecordStop(blob: Blob, duration: number) { isRecording.valu function handleRecordCancel() { isRecording.value = false } async function loadContacts() { try { const contacts = await contactApi.getContacts(); chatStore.setContacts(contacts) } catch (e) { console.error(e) } } +// 监听 currentTab 变化并保存 +watch(currentTab, (newTab) => { + storage.setCurrentTab(newTab) +}) + onMounted(async () => { if (!authStore.isAuthenticated) { const isValid = await authStore.checkAuth() @@ -509,6 +517,16 @@ onMounted(async () => { } await loadContacts() await conversationStore.loadConversations() + + // 恢复选中的会话 + const savedTargetId = storage.getSelectedConversation() + if (savedTargetId) { + const contact = chatStore.contacts.find(c => c.user_id === savedTargetId || c.id === savedTargetId) + if (contact) { + await selectChat(contact) + } + } + window.addEventListener('resize', () => isMobile.value = window.innerWidth < 768) }) onUnmounted(() => { diff --git a/src/views/contact/ContactDetail.vue b/src/views/contact/ContactDetail.vue index 7b35144..e68e6ff 100644 --- a/src/views/contact/ContactDetail.vue +++ b/src/views/contact/ContactDetail.vue @@ -274,14 +274,16 @@ function handleSendMessage() { function handleAudioCall() { if (contact.value) { - const receiverUserId = contact.value.user_id || contact.value.id + const receiverUserId = contact.value.user_id || contact.value.id || contact.value.contact_user_id + // 直接发起通话,不跳转到会话模块 webrtc.startCall('audio', receiverUserId) } } function handleVideoCall() { if (contact.value) { - const receiverUserId = contact.value.user_id || contact.value.id + const receiverUserId = contact.value.user_id || contact.value.id || contact.value.contact_user_id + // 直接发起通话,不跳转到会话模块 webrtc.startCall('video', receiverUserId) } } diff --git a/src/views/contact/ContactDetailCard.vue b/src/views/contact/ContactDetailCard.vue index fc555d9..92cf88f 100644 --- a/src/views/contact/ContactDetailCard.vue +++ b/src/views/contact/ContactDetailCard.vue @@ -288,26 +288,16 @@ function handleSendMessage() { function handleAudioCall() { if (contact.value) { const receiverUserId = contact.value.user_id || contact.value.id - chatStore.setCurrentTarget(contact.value) - // 切换到 Chat Tab 后再发起通话 - emit('switchToChat') - // 延迟一下确保 Tab 切换完成 - setTimeout(() => { - webrtc.startCall('audio', receiverUserId) - }, 100) + // 直接发起通话,不跳转到会话模块 + webrtc.startCall('audio', receiverUserId) } } function handleVideoCall() { if (contact.value) { const receiverUserId = contact.value.user_id || contact.value.id - chatStore.setCurrentTarget(contact.value) - // 切换到 Chat Tab 后再发起通话 - emit('switchToChat') - // 延迟一下确保 Tab 切换完成 - setTimeout(() => { - webrtc.startCall('video', receiverUserId) - }, 100) + // 直接发起通话,不跳转到会话模块 + webrtc.startCall('video', receiverUserId) } } diff --git a/src/views/contact/FriendNotifyView.vue b/src/views/contact/FriendNotifyView.vue index bfd7b60..84fe790 100644 --- a/src/views/contact/FriendNotifyView.vue +++ b/src/views/contact/FriendNotifyView.vue @@ -14,9 +14,15 @@
-
+
{{ request.from_user?.name }}
- {{ request.message || '请求添加你为好友' }} + + 对方拒绝了你的好友申请 + + + {{ request.message || '请求添加你为好友' }} +
{{ formatTime(new Date(request.created_at).getTime()) }}
-
+
+
+ + 已拒绝 +