From 58d5c52a455ebbd1c3ab8850dc574470777a5bd7 Mon Sep 17 00:00:00 2001 From: liqi Date: Wed, 10 Dec 2025 13:23:17 +0800 Subject: [PATCH] =?UTF-8?q?UI=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 21 +- src/pages/chat/index.vue | 2042 ++++++++++---------------------- src/pages/contact/add.vue | 473 +++++--- src/pages/contact/detail.vue | 576 +++++---- src/pages/contact/groups.vue | 219 ++-- src/pages/contact/index.vue | 439 ++----- src/pages/contact/requests.vue | 255 ++-- src/pages/index/index.vue | 743 +++++------- src/pages/moment/index.vue | 716 +++++------ src/pages/profile/edit.vue | 153 ++- src/pages/profile/index.vue | 209 ++-- src/pages/search/index.vue | 133 ++- src/pages/settings/index.vue | 145 ++- src/pages/settings/theme.vue | 196 ++- src/styles/variables.scss | 46 +- 15 files changed, 2641 insertions(+), 3725 deletions(-) diff --git a/src/App.vue b/src/App.vue index 97d11f5..202ea71 100644 --- a/src/App.vue +++ b/src/App.vue @@ -13,7 +13,7 @@ const conversationStore = useConversationStore() function handleGlobalMessage(message: ChatMessage) { // 忽略信令消息 if (message.message_type === 6) return - + // 更新会话列表 const isSelf = message.sender_user_id === authStore.user?.id conversationStore.handleMessageUpdate(message, isSelf, false) @@ -23,7 +23,7 @@ function handleGlobalMessage(message: ChatMessage) { async function initWebSocket() { const userId = authStore.user?.id if (!userId) return - + try { await wsManager.connect(userId) // 注册全局消息处理器 @@ -44,7 +44,7 @@ onShow(async () => { console.log('App Show') // 检查登录状态 const isAuth = await authStore.checkAuth() - + // 如果已登录,初始化 WebSocket if (isAuth && authStore.user?.id) { initWebSocket() @@ -56,6 +56,11 @@ onShow(async () => { @import '@/styles/variables.scss'; @import '@/styles/common.scss'; +/* 移除全局硬编码 padding,交由各页面 nav-bar 处理 */ +#app { + /* padding-top: calc(var(--status-bar-height) + 40rpx); REMOVED */ +} + /* 全局样式 */ page { background-color: var(--bg-page); @@ -64,11 +69,11 @@ page { font-size: 28rpx; line-height: 1.5; - // wot-design-uni 主题色覆盖 - --wot-color-theme: #07c160; - --wot-color-success: #07c160; - --wot-color-danger: #fa5151; - --wot-color-warning: #ffc300; + // wot-design-uni 主题色覆盖 (使用 CSS 变量) + --wot-color-theme: var(--color-primary); + --wot-color-success: var(--color-success); + --wot-color-danger: var(--color-danger); + --wot-color-warning: var(--color-warning); } /* 暗色模式下的 wot-design-uni 组件适配 */ diff --git a/src/pages/chat/index.vue b/src/pages/chat/index.vue index 481338d..8ee2098 100644 --- a/src/pages/chat/index.vue +++ b/src/pages/chat/index.vue @@ -1,284 +1,260 @@ diff --git a/src/pages/contact/add.vue b/src/pages/contact/add.vue index aec4605..8c30719 100644 --- a/src/pages/contact/add.vue +++ b/src/pages/contact/add.vue @@ -1,223 +1,344 @@ diff --git a/src/pages/contact/detail.vue b/src/pages/contact/detail.vue index 5200a0e..daa01f1 100644 --- a/src/pages/contact/detail.vue +++ b/src/pages/contact/detail.vue @@ -1,73 +1,100 @@ diff --git a/src/pages/contact/groups.vue b/src/pages/contact/groups.vue index 37d2a8f..3837617 100644 --- a/src/pages/contact/groups.vue +++ b/src/pages/contact/groups.vue @@ -1,135 +1,138 @@ diff --git a/src/pages/contact/index.vue b/src/pages/contact/index.vue index a357ca2..2968fbf 100644 --- a/src/pages/contact/index.vue +++ b/src/pages/contact/index.vue @@ -2,31 +2,27 @@ - + - 通讯录 - - - - + + + - - {{ tab.label }} - - + - + + + + - - - + 新朋友 - - - - - - - 群通知 - - + + 群通知 - + - - - + - + - + - + - + - {{ l }} + {{ l }} - + - - 新建分组 @@ -200,10 +200,7 @@ - - - 重命名分组 @@ -213,9 +210,7 @@ - - 修改备注 @@ -245,84 +240,18 @@ import AppAvatar from '@/components/common/AppAvatar.vue' import AppTabBar from '@/components/common/AppTabBar.vue' import type { Contact, ContactGroup } from '@/types/api' -// 类型定义补全 -interface GroupChat { - room_id: string; room_type: string; room_name: string; room_avatar: string; category: 'joined' | 'created' | 'managed'; -} - -const contactStore = useContactStore() -const chatStore = useChatStore() -const { isDark } = useTheme() -const toast = useToast() -const messageBox = useMessage() - -// 保持全部原有逻辑变量和方法不变 -const tabs = [{ key: 'groups', label: '分组' }, { key: 'friends', label: '好友' }, { key: 'chats', label: '群聊' }] -const activeTab = ref('groups') -const searchKeyword = ref('') -const refreshing = ref(false) -const loading = ref(false) -const collapsedIds = ref<(number | string)[]>([]) -const contactGroups = ref([]) -const groupChats = ref([]) -const showContactActions = ref(false) -const selectedContact = ref(null) -const showMoveGroupModal = ref(false) -const showRemarkModal = ref(false) -const remarkName = ref('') -const savingRemark = ref(false) -const showGroupActions = ref(false) -const selectedGroup = ref(null) -const showCreateGroupModal = ref(false) -const showRenameGroupModal = ref(false) -const newGroupName = ref('') -const renameGroupName = ref('') -const creating = ref(false) -const renaming = ref(false) - -const contacts = computed(() => chatStore.contacts) -const friendRequestCount = computed(() => contactStore.friendRequests.filter(r => r.status === 'pending').length) -const ungroupedContacts = computed(() => contacts.value.filter(c => !c.group_id || c.group_id === 0)) -function getGroupContacts(groupId: number): Contact[] { return contacts.value.filter(c => c.group_id === groupId) } -const letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '#'] -const alphabetGroupedContacts = computed(() => { - const groups: Record = {} - contacts.value.forEach(contact => { - const name = contact.remark_name || contact.user?.name || '' - const firstChar = name.charAt(0).toUpperCase() - const letter = /[A-Z]/.test(firstChar) ? firstChar : '#' - if (!groups[letter]) groups[letter] = [] - groups[letter].push(contact) - }) - return Object.keys(groups).sort((a, b) => (a === '#' ? 1 : b === '#' ? -1 : a.localeCompare(b))).map(letter => ({ letter, contacts: groups[letter] })) -}) -const createdGroups = computed(() => groupChats.value.filter(g => g.category === 'created')) -const managedGroups = computed(() => groupChats.value.filter(g => g.category === 'managed')) -const joinedGroups = computed(() => groupChats.value.filter(g => g.category === 'joined')) - -const contactActionItems = [{ name: '修改备注', value: 'remark' }, { name: '移动到分组', value: 'move' }, { name: '删除好友', value: 'delete', color: '#fa5151' }] -const groupActionItems = [{ name: '重命名', value: 'rename' }, { name: '删除分组', value: 'delete', color: '#fa5151' }] -const moveGroupActions = computed(() => { - const actions: any[] = [{ name: '未分组', value: 0 }] - contactGroups.value.forEach(g => { if (selectedContact.value?.group_id !== g.id) actions.push({ name: g.group_name, value: g.id }) }) - return actions -}) - -onMounted(() => loadData()) -onShow(() => loadFriendRequests()) - -async function loadData() { - loading.value = true - try { - const [contactList, groups, chats] = await Promise.all([contactApi.getContacts(), contactApi.getGroups(), roomApi.getUserGroups()]) - chatStore.setContacts(contactList) - contactGroups.value = groups - groupChats.value = chats || [] - } catch (error) { console.error(error) } finally { loading.value = false } -} +// --- 逻辑完全不变 --- +interface GroupChat { room_id: string; room_type: string; room_name: string; room_avatar: string; category: 'joined' | 'created' | 'managed'; } +const contactStore = useContactStore(); const chatStore = useChatStore(); const { isDark } = useTheme(); const toast = useToast(); const messageBox = useMessage(); +const tabs = [{ key: 'groups', label: '分组' }, { key: 'friends', label: '好友' }, { key: 'chats', label: '群聊' }]; const activeTab = ref('groups'); const searchKeyword = ref(''); const refreshing = ref(false); const loading = ref(false); const collapsedIds = ref<(number | string)[]>([]); const contactGroups = ref([]); const groupChats = ref([]); const showContactActions = ref(false); const selectedContact = ref(null); const showMoveGroupModal = ref(false); const showRemarkModal = ref(false); const remarkName = ref(''); const savingRemark = ref(false); const showGroupActions = ref(false); const selectedGroup = ref(null); const showCreateGroupModal = ref(false); const showRenameGroupModal = ref(false); const newGroupName = ref(''); const renameGroupName = ref(''); const creating = ref(false); const renaming = ref(false); +const contacts = computed(() => chatStore.contacts); const friendRequestCount = computed(() => contactStore.friendRequests.filter(r => r.status === 'pending').length); const ungroupedContacts = computed(() => contacts.value.filter(c => !c.group_id || c.group_id === 0)); function getGroupContacts(groupId: number): Contact[] { return contacts.value.filter(c => c.group_id === groupId) } +const letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '#']; const alphabetGroupedContacts = computed(() => { const groups: Record = {}; contacts.value.forEach(contact => { const name = contact.remark_name || contact.user?.name || ''; const firstChar = name.charAt(0).toUpperCase(); const letter = /[A-Z]/.test(firstChar) ? firstChar : '#'; if (!groups[letter]) groups[letter] = []; groups[letter].push(contact) }); return Object.keys(groups).sort((a, b) => (a === '#' ? 1 : b === '#' ? -1 : a.localeCompare(b))).map(letter => ({ letter, contacts: groups[letter] })) }); +const createdGroups = computed(() => groupChats.value.filter(g => g.category === 'created')); const managedGroups = computed(() => groupChats.value.filter(g => g.category === 'managed')); const joinedGroups = computed(() => groupChats.value.filter(g => g.category === 'joined')); +const contactActionItems = [{ name: '修改备注', value: 'remark' }, { name: '移动到分组', value: 'move' }, { name: '删除好友', value: 'delete', color: '#fa5151' }]; const groupActionItems = [{ name: '重命名', value: 'rename' }, { name: '删除分组', value: 'delete', color: '#fa5151' }]; const moveGroupActions = computed(() => { const actions: any[] = [{ name: '未分组', value: 0 }]; contactGroups.value.forEach(g => { if (selectedContact.value?.group_id !== g.id) actions.push({ name: g.group_name, value: g.id }) }); return actions }); +onMounted(() => loadData()); onShow(() => loadFriendRequests()); +async function loadData() { loading.value = true; try { const [contactList, groups, chats] = await Promise.all([contactApi.getContacts(), contactApi.getGroups(), roomApi.getUserGroups()]); chatStore.setContacts(contactList); contactGroups.value = groups; groupChats.value = chats || [] } catch (error) { console.error(error) } finally { loading.value = false } } async function loadFriendRequests() { try { const requests = await contactApi.getFriendRequests(); contactStore.setFriendRequests(requests) } catch {} } async function onRefresh() { refreshing.value = true; await loadData(); await loadFriendRequests(); refreshing.value = false } - function toggleCollapse(id: number | string) { const idx = collapsedIds.value.indexOf(id); idx === -1 ? collapsedIds.value.push(id) : collapsedIds.value.splice(idx, 1) } function goSearch() { uni.navigateTo({ url: '/pages/search/index' }) } function goAddFriend() { uni.navigateTo({ url: '/pages/contact/add' }) } @@ -330,14 +259,12 @@ function goFriendRequests() { uni.navigateTo({ url: '/pages/contact/requests' }) function goGroupNotify() { uni.navigateTo({ url: '/pages/group/notify' }) } function goContactDetail(contact: Contact) { uni.navigateTo({ url: `/pages/contact/detail?id=${contact.id}` }) } function goGroupChat(group: GroupChat) { uni.navigateTo({ url: `/pages/chat/index?roomId=${group.room_id}&name=${encodeURIComponent(group.room_name || '群聊')}` }) } -function scrollToLetter(letter: string) { /* Scroll logic */ console.log(letter) } - +function scrollToLetter(letter: string) { console.log(letter) } function handleContactLongPress(c: Contact) { selectedContact.value = c; remarkName.value = c.remark_name || ''; showContactActions.value = true } function onContactActionSelect(a: { value: string }) { showContactActions.value = false; if(a.value === 'remark') showRemarkModal.value = true; else if(a.value === 'move') showMoveGroupModal.value = true; else if(a.value === 'delete') handleDeleteContact() } async function handleSaveRemark() { if(!selectedContact.value) return; savingRemark.value=true; try { await contactApi.updateContact(selectedContact.value.id.toString(), {remark_name: remarkName.value}); const idx = chatStore.contacts.findIndex(c => c.id === selectedContact.value?.id); if(idx>-1) chatStore.contacts[idx].remark_name = remarkName.value; showRemarkModal.value=false; toast.success('备注已修改') } catch(e){toast.error('失败')} finally {savingRemark.value=false} } async function onMoveGroupSelect(a: { value: number }) { if(!selectedContact.value) return; showMoveGroupModal.value=false; try { await contactApi.updateContact(selectedContact.value.id.toString(), {group_id: a.value}); const idx = chatStore.contacts.findIndex(c => c.id === selectedContact.value?.id); if(idx>-1) chatStore.contacts[idx].group_id = a.value; toast.success('已移动') } catch { toast.error('失败') } } async function handleDeleteContact() { try { await messageBox.confirm({title:'提示', msg:'确定删除?'}); await contactApi.deleteContact(selectedContact.value!.id.toString()); const idx = chatStore.contacts.findIndex(c=>c.id===selectedContact.value!.id); if(idx>-1) chatStore.contacts.splice(idx,1); toast.success('已删除') } catch {} } - function handleGroupLongPress(g: ContactGroup) { selectedGroup.value=g; renameGroupName.value=g.group_name; showGroupActions.value=true } function onGroupActionSelect(a: { value: string }) { showGroupActions.value=false; if(a.value==='rename') showRenameGroupModal.value=true; else if(a.value==='delete') handleDeleteGroup() } async function handleCreateGroup() { if(!newGroupName.value.trim()) return; creating.value=true; try { const ng = await contactApi.createGroup({group_name: newGroupName.value.trim()}); contactGroups.value.push(ng); showCreateGroupModal.value=false; newGroupName.value=''; toast.success('成功') } catch { toast.error('失败') } finally { creating.value=false } } @@ -346,7 +273,6 @@ async function handleDeleteGroup() { try { await messageBox.confirm({title:'提 diff --git a/src/pages/contact/requests.vue b/src/pages/contact/requests.vue index 1b76cc0..4ee3ba9 100644 --- a/src/pages/contact/requests.vue +++ b/src/pages/contact/requests.vue @@ -1,177 +1,146 @@ diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue index 47c01f4..2ca176e 100644 --- a/src/pages/index/index.vue +++ b/src/pages/index/index.vue @@ -1,20 +1,190 @@ + + - - diff --git a/src/pages/moment/index.vue b/src/pages/moment/index.vue index 009c72b..39dc88c 100644 --- a/src/pages/moment/index.vue +++ b/src/pages/moment/index.vue @@ -1,169 +1,162 @@ diff --git a/src/pages/profile/edit.vue b/src/pages/profile/edit.vue index c9cc21d..b0aa1dd 100644 --- a/src/pages/profile/edit.vue +++ b/src/pages/profile/edit.vue @@ -1,109 +1,94 @@