You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
4.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="tab-page">
<view v-if="loading" class="chat-loading">
<loading :size="50" :mask="false">
<view>消息接收中...</view>
</loading>
</view>
<view v-if="initializing" class="chat-loading">
<loading :size="50" :mask="false">
<view>正在初始化...</view>
</loading>
</view>
<view class="nav-bar" v-if="showSearch">
<view class="nav-search">
<uni-search-bar focus="true" radius="100" v-model="searchText" cancelButton="none"
placeholder="搜索"></uni-search-bar>
</view>
</view>
<view class="chat-tip" v-if="!loading && chats.length == 0">
温馨提示:您现在还没有任何聊天消息,快跟您的好友发起聊天吧~
</view>
<scroll-view class="scroll-bar" v-else scroll-with-animation="true" scroll-y="true">
<view v-for="(chat, index) in chats" :key="index">
<long-press-menu v-if="isShowChat(chat)" :items="menu.items" @select="onSelectMenu($event, index)">
<chat-item :chat="chat" :index="index" :active="menu.chatIdx == index"></chat-item>
</long-press-menu>
</view>
</scroll-view>
</view>
</template>
<script>
import { mapState, mapGetters, mapActions } from 'vuex'
export default {
data() {
return {
showSearch: false,
searchText: "",
menu: {
show: false,
style: "",
chatIdx: -1,
isTouchMove: false,
items: [
{
key: 'DELETE',
name: '删除该聊天',
icon: 'trash',
color: '#e64e4e'
},
{
key: 'TOP',
name: '置顶该聊天',
icon: 'arrow-up'
}
]
}
}
},
computed: {
// 映射 Vuex state 和 getters
...mapState('chatStore', ['chats']),
...mapGetters('chatStore', ['isLoading']),
// 未读消息总数
unreadCount() {
let count = 0
this.chats.forEach(chat => {
if (!chat.delete) {
count += chat.unreadCount
}
})
return count
},
// 是否正在加载消息(调用 getter 返回的函数)
loading() {
return this.isLoading()
},
// 是否正在初始化(来自全局变量)
initializing() {
return !getApp().$vm.isInit
},
// 搜索过滤(用于模板,但未直接使用,可保留)
showChats() {
return this.chats.filter(chat =>
!chat.delete && chat.showName && chat.showName.includes(this.searchText)
)
}
},
methods: {
// 映射 Vuex actions
...mapActions('chatStore', ['removeChat', 'moveTop']),
onSelectMenu(item, chatIdx) {
switch (item.key) {
case 'DELETE':
this.removeChat(chatIdx)
break
case 'TOP':
this.moveTop(chatIdx)
break
default:
break
}
this.menu.show = false
},
// 不再需要单独定义 removeChat 和 moveToTop已通过 mapActions 映射
isShowChat(chat) {
if (chat.delete) return false
return !this.searchText || chat.showName.includes(this.searchText)
},
onSearch() {
this.showSearch = !this.showSearch
this.searchText = ""
},
refreshUnreadBadge() {
if (this.unreadCount > 0) {
uni.setTabBarBadge({
index: 0,
text: this.unreadCount + ""
})
} else {
uni.removeTabBarBadge({
index: 0,
complete: () => {}
})
}
}
},
watch: {
unreadCount(newCount) {
this.refreshUnreadBadge()
}
},
onShow() {
this.refreshUnreadBadge()
}
}
</script>
<style lang="scss">
.tab-page {
position: relative;
display: flex;
flex-direction: column;
.chat-tip {
position: absolute;
top: 400rpx;
padding: 50rpx;
line-height: 50rpx;
text-align: center;
color: $im-text-color-lighter;
}
.chat-loading {
display: block;
width: 100%;
height: 120rpx;
background: white;
color: $im-text-color-lighter;
.loading-box {
position: relative;
}
}
.scroll-bar {
flex: 1;
height: 100%;
}
}
</style>