UI优化
This commit is contained in:
@@ -91,7 +91,7 @@ function switchTab(name: string) {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
z-index: 1;
|
||||
background: var(--bg-content, #fff);
|
||||
border-top: 1rpx solid var(--divider-color, #eee);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
@@ -1,3 +1,150 @@
|
||||
<script setup lang="ts">
|
||||
import type { Conversation } from '@/types/conversation'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useMessage, useToast } from 'wot-design-uni'
|
||||
import * as conversationApi from '@/api/modules/conversation'
|
||||
import AppAvatar from '@/components/common/AppAvatar.vue'
|
||||
import AppTabBar from '@/components/common/AppTabBar.vue'
|
||||
import { useTheme } from '@/composables/useTheme'
|
||||
import { useAuthStore, useConversationStore } from '@/stores'
|
||||
import { formatMessageTime } from '@/utils/format'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const conversationStore = useConversationStore()
|
||||
const { isDark } = useTheme()
|
||||
|
||||
// --- 保持原有逻辑代码不变 ---
|
||||
const toast = useToast()
|
||||
const messageBox = useMessage()
|
||||
const searchKeyword = ref('')
|
||||
const showPlusMenu = ref(false)
|
||||
const showDrawer = ref(false)
|
||||
const refreshing = ref(false)
|
||||
const showConvActions = ref(false)
|
||||
const selectedConv = ref<Conversation | null>(null)
|
||||
|
||||
const user = computed(() => authStore.user)
|
||||
const conversations = computed(() => conversationStore.conversations)
|
||||
const loading = computed(() => conversationStore.loading)
|
||||
|
||||
const themeText = computed(() => {
|
||||
const mode = uni.getStorageSync('nl_im_theme_mode') || 'system'
|
||||
const texts: Record<string, string> = { system: '跟随系统', light: '浅色模式', dark: '深色模式' }
|
||||
return texts[mode] || '跟随系统'
|
||||
})
|
||||
|
||||
const plusMenuActions = [
|
||||
{ name: '创建群聊', value: 'createGroup' },
|
||||
{ name: '添加好友', value: 'addFriend' },
|
||||
{ name: '扫一扫', value: 'scan' },
|
||||
]
|
||||
|
||||
const convActionItems = computed(() => {
|
||||
if (!selectedConv.value)
|
||||
return []
|
||||
const conv = selectedConv.value
|
||||
const isGroup = conv.is_group || conv.type === 2
|
||||
const items: any[] = [
|
||||
{ name: conv.is_top ? '取消置顶' : '置顶会话', value: 'toggleTop' },
|
||||
{ name: conv.is_muted ? '开启提醒' : '消息免打扰', value: 'toggleMute' },
|
||||
]
|
||||
if (!isGroup)
|
||||
items.push({ name: conv.is_special_care ? '取消特别关心' : '特别关心', value: 'toggleSpecial' })
|
||||
if (conv.unread_count && conv.unread_count > 0)
|
||||
items.push({ name: '标记已读', value: 'markRead' })
|
||||
items.push({ name: '删除会话', value: 'delete', color: '#fa5151' })
|
||||
return items
|
||||
})
|
||||
|
||||
onMounted(() => loadData())
|
||||
onShow(() => loadData())
|
||||
|
||||
async function loadData() {
|
||||
if (!authStore.isAuthenticated) {
|
||||
uni.reLaunch({ url: '/pages/login/index' })
|
||||
return
|
||||
}
|
||||
await conversationStore.loadConversations()
|
||||
}
|
||||
|
||||
async function onRefresh() {
|
||||
refreshing.value = true
|
||||
await conversationStore.loadConversations()
|
||||
refreshing.value = false
|
||||
}
|
||||
|
||||
function goSearch() { uni.navigateTo({ url: '/pages/search/index' }) }
|
||||
function goChat(item: Conversation) {
|
||||
conversationStore.clearUnread(item.target_id)
|
||||
uni.navigateTo({ url: `/pages/chat/index?roomId=${item.room_id || ''}&targetId=${item.target_id}&name=${encodeURIComponent(item.name || '')}&avatar=${encodeURIComponent(item.avatar || '')}` })
|
||||
}
|
||||
function handleLongPress(item: Conversation) { selectedConv.value = item; showConvActions.value = true }
|
||||
async function onConvActionSelect(action: { value: string }) {
|
||||
if (!selectedConv.value)
|
||||
return
|
||||
const conv = selectedConv.value
|
||||
showConvActions.value = false
|
||||
try {
|
||||
if (action.value === 'toggleTop') {
|
||||
await conversationApi.updateConversation({ target_id: conv.target_id, is_top: !conv.is_top })
|
||||
conv.is_top = !conv.is_top
|
||||
conversationStore.sortConversations()
|
||||
}
|
||||
else if (action.value === 'toggleMute') {
|
||||
await conversationApi.updateConversation({ target_id: conv.target_id, is_muted: !conv.is_muted })
|
||||
conv.is_muted = !conv.is_muted
|
||||
}
|
||||
else if (action.value === 'toggleSpecial') {
|
||||
await conversationApi.updateConversation({ target_id: conv.target_id, is_special_care: !conv.is_special_care })
|
||||
conv.is_special_care = !conv.is_special_care
|
||||
}
|
||||
else if (action.value === 'markRead') {
|
||||
await conversationStore.clearUnread(conv.target_id)
|
||||
}
|
||||
else if (action.value === 'delete') {
|
||||
await deleteConversation(conv)
|
||||
}
|
||||
}
|
||||
catch (e) { toast.error('操作失败') }
|
||||
}
|
||||
|
||||
// 提取删除逻辑
|
||||
async function deleteConversation(item: Conversation) {
|
||||
try {
|
||||
await messageBox.confirm({ title: '提示', msg: '确定删除该会话吗?' })
|
||||
await conversationApi.deleteConversation(item.target_id)
|
||||
const index = conversationStore.conversations.findIndex(c => c.id === item.id)
|
||||
if (index > -1)
|
||||
conversationStore.conversations.splice(index, 1)
|
||||
toast.success('已删除')
|
||||
}
|
||||
catch (e: any) {
|
||||
if (e !== 'cancel')
|
||||
toast.error('删除失败')
|
||||
}
|
||||
}
|
||||
|
||||
function onPlusMenuSelect(item: { value: string }) {
|
||||
showPlusMenu.value = false
|
||||
if (item.value === 'createGroup')
|
||||
uni.navigateTo({ url: '/pages/group/create' })
|
||||
else if (item.value === 'addFriend')
|
||||
uni.navigateTo({ url: '/pages/contact/add' })
|
||||
else if (item.value === 'scan')
|
||||
uni.scanCode({ success: () => toast.show('扫码成功'), fail: () => toast.error('扫码失败') })
|
||||
}
|
||||
function openDrawer() { showDrawer.value = true }
|
||||
function goProfile() { showDrawer.value = false; uni.navigateTo({ url: '/pages/profile/index' }) }
|
||||
function goSettings() { showDrawer.value = false; uni.navigateTo({ url: '/pages/settings/index' }) }
|
||||
function goTheme() { showDrawer.value = false; uni.navigateTo({ url: '/pages/settings/theme' }) }
|
||||
async function logout() {
|
||||
try { await messageBox.confirm({ title: '提示', msg: '确定退出?' }); showDrawer.value = false; authStore.logout() }
|
||||
catch {}
|
||||
}
|
||||
// --- 保持逻辑代码结束 ---
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!--
|
||||
WotUI 最佳实践:
|
||||
@@ -6,10 +153,9 @@
|
||||
-->
|
||||
<wd-config-provider :theme="isDark ? 'dark' : 'light'">
|
||||
<view class="page-container" :class="{ dark: isDark }">
|
||||
|
||||
<!-- 沉浸式导航栏 -->
|
||||
<view class="custom-navbar">
|
||||
<view class="navbar-bg"></view> <!-- 独立背景层用于做高斯模糊 -->
|
||||
<view class="navbar-bg" /> <!-- 独立背景层用于做高斯模糊 -->
|
||||
<view class="navbar-content">
|
||||
<view class="navbar-left" @click="openDrawer">
|
||||
<app-avatar
|
||||
@@ -21,8 +167,10 @@
|
||||
/>
|
||||
</view>
|
||||
<view class="navbar-title">
|
||||
<text class="title-text">{{ user?.name || '消息' }}</text>
|
||||
<view class="online-status" v-if="!loading"></view>
|
||||
<text class="title-text">
|
||||
{{ user?.name || '消息' }}
|
||||
</text>
|
||||
<view v-if="!loading" class="online-status" />
|
||||
</view>
|
||||
<view class="navbar-right">
|
||||
<view class="icon-btn" @click="showPlusMenu = true">
|
||||
@@ -36,7 +184,9 @@
|
||||
<view class="search-wrapper">
|
||||
<view class="search-inner" @click="goSearch">
|
||||
<wd-icon name="search" size="32rpx" color="var(--text-tertiary)" />
|
||||
<text class="search-placeholder">搜索</text>
|
||||
<text class="search-placeholder">
|
||||
搜索
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -98,11 +248,15 @@
|
||||
{{ item.name || '未知' }}
|
||||
</text>
|
||||
</view>
|
||||
<text class="time">{{ formatMessageTime(item.last_time) }}</text>
|
||||
<text class="time">
|
||||
{{ formatMessageTime(item.last_time) }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="row-bottom">
|
||||
<text class="msg-preview text-ellipsis">{{ item.last_message || '暂无消息' }}</text>
|
||||
<text class="msg-preview text-ellipsis">
|
||||
{{ item.last_message || '暂无消息' }}
|
||||
</text>
|
||||
<wd-icon v-if="item.is_muted" name="volume-mute" size="28rpx" class="mute-icon" />
|
||||
</view>
|
||||
</view>
|
||||
@@ -123,7 +277,7 @@
|
||||
</template>
|
||||
|
||||
<!-- 底部垫片 -->
|
||||
<view class="safe-area-spacer"></view>
|
||||
<view class="safe-area-spacer" />
|
||||
</scroll-view>
|
||||
|
||||
<!-- 弹窗组件保持原有逻辑 -->
|
||||
@@ -136,8 +290,8 @@
|
||||
<wd-action-sheet
|
||||
v-model="showConvActions"
|
||||
:actions="convActionItems"
|
||||
@select="onConvActionSelect"
|
||||
cancel-text="取消"
|
||||
@select="onConvActionSelect"
|
||||
/>
|
||||
|
||||
<!-- 侧边抽屉 -->
|
||||
@@ -147,11 +301,15 @@
|
||||
custom-style="width: 75%; height: 100%; background: var(--bg-surface);"
|
||||
>
|
||||
<view class="drawer-container">
|
||||
<view class="drawer-header-bg"></view>
|
||||
<view class="drawer-header-bg" />
|
||||
<view class="drawer-info">
|
||||
<app-avatar :src="user?.avatar" :name="user?.name" :size="140" round custom-style="border: 4rpx solid var(--bg-surface);" />
|
||||
<text class="drawer-username">{{ user?.name || '请登录' }}</text>
|
||||
<text class="drawer-bio">{{ user?.desc || '编辑个签,展示你的独特个性' }}</text>
|
||||
<text class="drawer-username">
|
||||
{{ user?.name || '请登录' }}
|
||||
</text>
|
||||
<text class="drawer-bio">
|
||||
{{ user?.desc || '编辑个签,展示你的独特个性' }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="drawer-menu-list">
|
||||
@@ -163,7 +321,9 @@
|
||||
</view>
|
||||
|
||||
<view class="drawer-footer-btn">
|
||||
<wd-button type="info" plain block @click="logout">退出登录</wd-button>
|
||||
<wd-button type="info" plain block @click="logout">
|
||||
退出登录
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</wd-popup>
|
||||
@@ -175,135 +335,6 @@
|
||||
</wd-config-provider>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { useAuthStore, useConversationStore } from '@/stores'
|
||||
import { useTheme } from '@/composables/useTheme'
|
||||
import { formatMessageTime } from '@/utils/format'
|
||||
import { useToast, useMessage } from 'wot-design-uni'
|
||||
import * as conversationApi from '@/api/modules/conversation'
|
||||
import AppAvatar from '@/components/common/AppAvatar.vue'
|
||||
import AppTabBar from '@/components/common/AppTabBar.vue'
|
||||
import type { Conversation } from '@/types/conversation'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const conversationStore = useConversationStore()
|
||||
const { isDark } = useTheme()
|
||||
|
||||
// --- 保持原有逻辑代码不变 ---
|
||||
const toast = useToast()
|
||||
const messageBox = useMessage()
|
||||
const searchKeyword = ref('')
|
||||
const showPlusMenu = ref(false)
|
||||
const showDrawer = ref(false)
|
||||
const refreshing = ref(false)
|
||||
const showConvActions = ref(false)
|
||||
const selectedConv = ref<Conversation | null>(null)
|
||||
|
||||
const user = computed(() => authStore.user)
|
||||
const conversations = computed(() => conversationStore.conversations)
|
||||
const loading = computed(() => conversationStore.loading)
|
||||
|
||||
const themeText = computed(() => {
|
||||
const mode = uni.getStorageSync('nl_im_theme_mode') || 'system'
|
||||
const texts: Record<string, string> = { system: '跟随系统', light: '浅色模式', dark: '深色模式' }
|
||||
return texts[mode] || '跟随系统'
|
||||
})
|
||||
|
||||
const plusMenuActions = [
|
||||
{ name: '创建群聊', value: 'createGroup' },
|
||||
{ name: '添加好友', value: 'addFriend' },
|
||||
{ name: '扫一扫', value: 'scan' }
|
||||
]
|
||||
|
||||
const convActionItems = computed(() => {
|
||||
if (!selectedConv.value) return []
|
||||
const conv = selectedConv.value
|
||||
const isGroup = conv.is_group || conv.type === 2
|
||||
const items: any[] = [
|
||||
{ name: conv.is_top ? '取消置顶' : '置顶会话', value: 'toggleTop' },
|
||||
{ name: conv.is_muted ? '开启提醒' : '消息免打扰', value: 'toggleMute' }
|
||||
]
|
||||
if (!isGroup) items.push({ name: conv.is_special_care ? '取消特别关心' : '特别关心', value: 'toggleSpecial' })
|
||||
if (conv.unread_count && conv.unread_count > 0) items.push({ name: '标记已读', value: 'markRead' })
|
||||
items.push({ name: '删除会话', value: 'delete', color: '#fa5151' })
|
||||
return items
|
||||
})
|
||||
|
||||
onMounted(() => loadData())
|
||||
onShow(() => loadData())
|
||||
|
||||
async function loadData() {
|
||||
if (!authStore.isAuthenticated) {
|
||||
uni.reLaunch({ url: '/pages/login/index' })
|
||||
return
|
||||
}
|
||||
await conversationStore.loadConversations()
|
||||
}
|
||||
|
||||
async function onRefresh() {
|
||||
refreshing.value = true
|
||||
await conversationStore.loadConversations()
|
||||
refreshing.value = false
|
||||
}
|
||||
|
||||
function goSearch() { uni.navigateTo({ url: '/pages/search/index' }) }
|
||||
function goChat(item: Conversation) {
|
||||
conversationStore.clearUnread(item.target_id)
|
||||
uni.navigateTo({ url: `/pages/chat/index?roomId=${item.room_id || ''}&targetId=${item.target_id}&name=${encodeURIComponent(item.name || '')}&avatar=${encodeURIComponent(item.avatar || '')}` })
|
||||
}
|
||||
function handleLongPress(item: Conversation) { selectedConv.value = item; showConvActions.value = true }
|
||||
async function onConvActionSelect(action: { value: string }) {
|
||||
if (!selectedConv.value) return
|
||||
const conv = selectedConv.value
|
||||
showConvActions.value = false
|
||||
try {
|
||||
if (action.value === 'toggleTop') {
|
||||
await conversationApi.updateConversation({ target_id: conv.target_id, is_top: !conv.is_top })
|
||||
conv.is_top = !conv.is_top
|
||||
conversationStore.sortConversations()
|
||||
} else if (action.value === 'toggleMute') {
|
||||
await conversationApi.updateConversation({ target_id: conv.target_id, is_muted: !conv.is_muted })
|
||||
conv.is_muted = !conv.is_muted
|
||||
} else if (action.value === 'toggleSpecial') {
|
||||
await conversationApi.updateConversation({ target_id: conv.target_id, is_special_care: !conv.is_special_care })
|
||||
conv.is_special_care = !conv.is_special_care
|
||||
} else if (action.value === 'markRead') {
|
||||
await conversationStore.clearUnread(conv.target_id)
|
||||
} else if (action.value === 'delete') {
|
||||
await deleteConversation(conv)
|
||||
}
|
||||
} catch(e) { toast.error('操作失败') }
|
||||
}
|
||||
|
||||
// 提取删除逻辑
|
||||
async function deleteConversation(item: Conversation) {
|
||||
try {
|
||||
await messageBox.confirm({ title: '提示', msg: '确定删除该会话吗?' })
|
||||
await conversationApi.deleteConversation(item.target_id)
|
||||
const index = conversationStore.conversations.findIndex(c => c.id === item.id)
|
||||
if (index > -1) conversationStore.conversations.splice(index, 1)
|
||||
toast.success('已删除')
|
||||
} catch (e: any) { if(e !== 'cancel') toast.error('删除失败') }
|
||||
}
|
||||
|
||||
function onPlusMenuSelect(item: { value: string }) {
|
||||
showPlusMenu.value = false
|
||||
if(item.value === 'createGroup') uni.navigateTo({ url: '/pages/group/create' })
|
||||
else if(item.value === 'addFriend') uni.navigateTo({ url: '/pages/contact/add' })
|
||||
else if(item.value === 'scan') uni.scanCode({ success: () => toast.show('扫码成功'), fail: () => toast.error('扫码失败') })
|
||||
}
|
||||
function openDrawer() { showDrawer.value = true }
|
||||
function goProfile() { showDrawer.value = false; uni.navigateTo({ url: '/pages/profile/index' }) }
|
||||
function goSettings() { showDrawer.value = false; uni.navigateTo({ url: '/pages/settings/index' }) }
|
||||
function goTheme() { showDrawer.value = false; uni.navigateTo({ url: '/pages/settings/theme' }) }
|
||||
async function logout() {
|
||||
try { await messageBox.confirm({ title: '提示', msg: '确定退出?' }); showDrawer.value = false; authStore.logout() } catch {}
|
||||
}
|
||||
// --- 保持逻辑代码结束 ---
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* ----- 语义化 CSS 变量定义 ----- */
|
||||
.page-container {
|
||||
@@ -345,7 +376,7 @@ async function logout() {
|
||||
.custom-navbar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
z-index: 0;
|
||||
padding-top: var(--status-bar-height);
|
||||
|
||||
.navbar-bg {
|
||||
@@ -402,7 +433,7 @@ async function logout() {
|
||||
padding: 16rpx 32rpx;
|
||||
position: sticky;
|
||||
top: calc(44px + var(--status-bar-height));
|
||||
z-index: 99;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.search-inner {
|
||||
@@ -543,6 +574,7 @@ async function logout() {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
z-index: 50000;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -559,7 +591,7 @@ async function logout() {
|
||||
|
||||
.drawer-info {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
z-index: 1000;
|
||||
padding: 100rpx 40rpx 60rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
Reference in New Issue
Block a user