|
|
|
|
|
<template>
|
|
|
|
|
|
<view class="page">
|
|
|
|
|
|
<!-- 页面头部 -->
|
|
|
|
|
|
<view class="page-header" :style="{ paddingTop: geStatusBarHeight() + 8 + 'px' }">
|
|
|
|
|
|
<view class="text-center">消息</view>
|
|
|
|
|
|
<uni-icons type="staff-filled" size="30" color="#ffffff" @click="gotoContacts"></uni-icons>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="wrapcon">
|
|
|
|
|
|
<!-- 暂无消息 -->
|
|
|
|
|
|
<view v-if="chats.length === 0 && loadStatus === 'nomore'" class="nodata">暂无消息~</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 列表 -->
|
|
|
|
|
|
<view class="listcell">
|
|
|
|
|
|
<u-swipe-action
|
|
|
|
|
|
ref="swipeRef"
|
|
|
|
|
|
:options="options"
|
|
|
|
|
|
v-for="(chat, index) in chats"
|
|
|
|
|
|
:key="chat.id || index"
|
|
|
|
|
|
style="min-width: 600rpx;"
|
|
|
|
|
|
@click="actionClick(chat, index)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="lcon" @click="gotoChat(chat, index)" @longpress="handleLongPress(index)">
|
|
|
|
|
|
<view class="limg">
|
|
|
|
|
|
<image class="img" :src="chat.headImage || '/static/image/girl.png'" mode="aspectFill"></image>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="lright">
|
|
|
|
|
|
<view class="lrow">
|
|
|
|
|
|
<view class="pname">{{ chat.showName || '未知' }}</view>
|
|
|
|
|
|
<view class="ptime">{{ changeTime(chat.lastSendTime) }}</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="lrow">
|
|
|
|
|
|
<view class="pnr">
|
|
|
|
|
|
{{ chat.lastContent || '' }}
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="lnum" v-if="chat.unreadCount > 0">
|
|
|
|
|
|
{{ chat.unreadCount }}
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</u-swipe-action>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 加载状态 -->
|
|
|
|
|
|
<u-loadmore v-if="chats.length === 0 && loadStatus === 'loading'" :status="loadStatus" :marginTop="20"></u-loadmore>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 提示信息弹窗 -->
|
|
|
|
|
|
<uni-popup ref="message" type="message">
|
|
|
|
|
|
<uni-popup-message :type="msgType" :message="messageText" :duration="2000"></uni-popup-message>
|
|
|
|
|
|
</uni-popup>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import { mapState, mapActions, mapGetters } from 'vuex'
|
|
|
|
|
|
import dateTime from '@/common/dateTime.js'
|
|
|
|
|
|
import {myCache} from "../../utils/utils";
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
loadStatus: 'loadmore',
|
|
|
|
|
|
options: [
|
|
|
|
|
|
{
|
|
|
|
|
|
text: '删除',
|
|
|
|
|
|
style: {
|
|
|
|
|
|
backgroundColor: '#ed2a28'
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
messageText: '',
|
|
|
|
|
|
msgType: 'error'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
computed: {
|
|
|
|
|
|
...mapState('chatStore', ['chats']),
|
|
|
|
|
|
...mapGetters('chatStore', ['isLoading']),
|
|
|
|
|
|
// 未读消息总数(用于角标)
|
|
|
|
|
|
unreadCount() {
|
|
|
|
|
|
let count = 0
|
|
|
|
|
|
this.chats.forEach(chat => {
|
|
|
|
|
|
|
|
|
|
|
|
if (!chat.delete) {
|
|
|
|
|
|
count += chat.unreadCount
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
return count
|
|
|
|
|
|
},
|
|
|
|
|
|
// 是否正在加载(用于显示loading状态)
|
|
|
|
|
|
loading() {
|
|
|
|
|
|
return this.isLoading()
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
watch: {
|
|
|
|
|
|
unreadCount(newVal) {
|
|
|
|
|
|
this.setBadge(newVal)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
onShow() {
|
|
|
|
|
|
console.log("this.chats列表.......",this.chats)
|
|
|
|
|
|
this.loadStatus = 'nomore'
|
|
|
|
|
|
this.setBadge(this.unreadCount)
|
|
|
|
|
|
},
|
|
|
|
|
|
onPullDownRefresh() {
|
|
|
|
|
|
// 下拉刷新仅刷新角标,数据由全局WebSocket维护
|
|
|
|
|
|
this.setBadge(this.unreadCount)
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
uni.stopPullDownRefresh()
|
|
|
|
|
|
}, 500)
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
...mapActions('chatStore', ['removeChat', 'moveTop','loadFriend']),
|
|
|
|
|
|
|
|
|
|
|
|
// 设置底部角标
|
|
|
|
|
|
setBadge(count) {
|
|
|
|
|
|
if (count > 0) {
|
|
|
|
|
|
uni.setTabBarBadge({
|
|
|
|
|
|
index: 3, // 根据实际tabBar索引调整
|
|
|
|
|
|
text: count + ''
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
uni.removeTabBarBadge({
|
|
|
|
|
|
index: 3
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 长按打开滑动菜单
|
|
|
|
|
|
handleLongPress(index) {
|
|
|
|
|
|
this.$refs.swipeRef[index].open()
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 滑动菜单点击(删除)
|
|
|
|
|
|
actionClick(chat, index) {
|
|
|
|
|
|
const that = this
|
|
|
|
|
|
uni.showModal({
|
|
|
|
|
|
title: '提示',
|
|
|
|
|
|
content: '确定要删除此聊天记录吗?',
|
|
|
|
|
|
success: res => {
|
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
|
that.$refs.swipeRef[index].close()
|
|
|
|
|
|
that.removeChat(index) // 调用 Vuex action
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 跳转到聊天页面
|
|
|
|
|
|
gotoChat(chat, index) {
|
|
|
|
|
|
// 清除该会话的未读(由chat页面处理)
|
|
|
|
|
|
// 构造跳转参数(与原有逻辑兼容)
|
|
|
|
|
|
let info = {}
|
|
|
|
|
|
if (chat.type === 'PRIVATE') {
|
|
|
|
|
|
info = {
|
|
|
|
|
|
chatId: chat.id || `privatechat-${chat.targetId}`,
|
|
|
|
|
|
chatName: chat.showName,
|
|
|
|
|
|
chatAvatar: chat.headImage,
|
|
|
|
|
|
friendId: chat.targetId,
|
|
|
|
|
|
minId: chat.hotMinIdx || 0,
|
|
|
|
|
|
sort: 'privatechat',
|
|
|
|
|
|
from: 'message'
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (chat.type === 'GROUP') {
|
|
|
|
|
|
info = {
|
|
|
|
|
|
chatId: chat.id || `groupchat-${chat.targetId}`,
|
|
|
|
|
|
groupId: chat.targetId,
|
|
|
|
|
|
chatName: chat.showName,
|
|
|
|
|
|
chatAvatar: chat.headImage,
|
|
|
|
|
|
minId: chat.hotMinIdx || 0,
|
|
|
|
|
|
sort: 'groupchat',
|
|
|
|
|
|
from: 'message'
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
const data = encodeURIComponent(JSON.stringify(info))
|
|
|
|
|
|
uni.navigateTo({ url: `/pages/chatbox/chat-box?chatIdx=${index}` });
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 跳转到通讯录
|
|
|
|
|
|
gotoContacts() {
|
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
|
url: '/pages/message/contact'
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 时间格式化
|
|
|
|
|
|
changeTime(time) {
|
|
|
|
|
|
return dateTime.dateTime(time)
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 获取状态栏高度
|
|
|
|
|
|
geStatusBarHeight() {
|
|
|
|
|
|
return uni.getSystemInfoSync().statusBarHeight
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.page {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
background-image: url('@/static/image/bg.jpg');
|
|
|
|
|
|
background-attachment: fixed;
|
|
|
|
|
|
background-size: cover;
|
|
|
|
|
|
background-position: center center;
|
|
|
|
|
|
min-height: calc(100vh - var(--window-top) - var(--window-bottom));
|
|
|
|
|
|
}
|
|
|
|
|
|
.page-header {
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
z-index: 999;
|
|
|
|
|
|
padding: 40rpx 30rpx 30rpx 30rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
font-size: 36rpx;
|
|
|
|
|
|
background-color: #00a89b;
|
|
|
|
|
|
.text-center {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
.edit {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 50%;
|
|
|
|
|
|
transform: translateY(-50%);
|
|
|
|
|
|
right: 30rpx;
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.wrapcon {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
margin: 180rpx 0 0 0;
|
|
|
|
|
|
min-height: calc(100vh - 180rpx);
|
|
|
|
|
|
/* #ifdef H5 */
|
|
|
|
|
|
margin: calc(110rpx + var(--window-top)) 0 0 0;
|
|
|
|
|
|
min-height: calc(100vh - var(--window-top) - var(--window-bottom) - 180rpx);
|
|
|
|
|
|
/* #endif */
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.listcell {
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
min-width: 750rpx;
|
|
|
|
|
|
.lcon {
|
|
|
|
|
|
border-bottom: 1rpx solid #eee;
|
|
|
|
|
|
padding-top: 20rpx;
|
|
|
|
|
|
padding-bottom: 20rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
min-width: 750rpx;
|
|
|
|
|
|
.limg {
|
|
|
|
|
|
width: 100rpx;
|
|
|
|
|
|
height: 100rpx;
|
|
|
|
|
|
margin-right: 20rpx;
|
|
|
|
|
|
margin-left: 20rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
.img {
|
|
|
|
|
|
width: 100rpx;
|
|
|
|
|
|
height: 100rpx;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.lright {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
.lrow {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
margin-right: 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
.pname {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
line-height: 50rpx;
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #000000;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ptime {
|
|
|
|
|
|
line-height: 50rpx;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
color: #595959;
|
|
|
|
|
|
}
|
|
|
|
|
|
.pnr {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
color: #595959;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
line-height: 40rpx;
|
|
|
|
|
|
max-height: 40rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
.lnum {
|
|
|
|
|
|
background-color: #de0000;
|
|
|
|
|
|
padding: 0 10rpx;
|
|
|
|
|
|
min-width: 32rpx;
|
|
|
|
|
|
height: 32rpx;
|
|
|
|
|
|
line-height: 32rpx;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
border-radius: 28rpx;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.nodata {
|
|
|
|
|
|
background-image: url('../../static/image/nomsg.png');
|
|
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
|
|
background-position: center center;
|
|
|
|
|
|
background-size: 100%;
|
|
|
|
|
|
height: 376rpx;
|
|
|
|
|
|
width: 256rpx;
|
|
|
|
|
|
color: #00a89b;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
padding-bottom: 40rpx;
|
|
|
|
|
|
margin: 100rpx auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|