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.

506 lines
13 KiB

3 weeks ago
<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="$u.throttle(gotoContacts(), 2000)"></uni-icons>
</view>
<view class="wrapcon">
<!-- 列表 -->
<view v-if="grouplist.length==0 && loadStatus=='nomore'" class="nodata">~</view>
<view class="listcell">
<view class="lcon" v-for="(info, index) in grouplist" :key="index" @click="gotoGroup(info)">
<view class="limg">
<image class="img" :src="info.img" mode="aspectFill"></image>
</view>
<view class="lright">
<view class="lrow">
<view class="pname">{{info.name}}</view>
<view class="ptime"> {{ changeTime(info.datetime)}}</view>
</view>
<view class="lrow">
<view class="pnr">
{{info.content}}
</view>
<!-- <view class="lnum">
{{ getgroupsnums(info.minId)}}
</view> -->
<view class="lnum" v-if="info.sl>0">
{{ info.sl}}
</view>
</view>
</view>
</view>
</view>
<u-loadmore v-if="grouplist.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 { myCache } from '../../utils/utils.js';
import dateTime from '@/common/dateTime.js';
export default {
data() {
return {
openId:"",
phone:"",
userid:"",
messageText:'', //错误提示框
msgType :'error',
loadStatus:'loadmore',
imgurl:uni.$http.baseUrl,
grouplist:[
// {
// id:1,
// sl:25,
// name:"商城客服-伽伽",
// img:"../../static/image/girl.png",
// content:"测试信息1",
// datetime:"2025-07-10 12:18",
// type:1, // 客服
// },
// {
// id:2,
// sl:8,
// name:"教练A",
// img:"../../static/image/girl.png",
// content:"测试信息2",
// datetime:"2025-07-05 12:18",
// type:2, // 老师
// },
],
socketTask: null,
isConnected: false, // WebSocket连接状态
socketmsg:[],//接收信息
heartbeatInterval: null, // 心跳包20秒连接一次
heartbeatTimeout: 20000, // 心跳间隔时间例如每20秒发送一次
}
},
onLoad(options) {
// socket接收信息初始化
// this.socketinit();
},
onShow(){
this.openId = myCache('openId');
var user = myCache('user');
this.userid = user.userid? user.userid:'';
this.phone = user.userphone;
// 从缓存聊天群里获取聊天群列表 chatlist
this.loadData();
// socket接收实时消息
this.socketinit();
},
onPullDownRefresh() {
console.log('onPullDownRefresh');
setTimeout(()=>{
uni.stopPullDownRefresh()
},500);
},
onBackPress(options) {
if (options.from === 'backbutton') {
// 来自顶部菜单的返回按钮
// 在这里处理你的逻辑
console.log('返回按钮被点击');
this.closeWebSocket();
uni.onSocketClose(function (res) {
console.log('WebSocket 已关闭!');
});
return false;
}
},
beforeDestroy() {
console.log('界面关闭socketbeforeDestroy');
// 在组件销毁前,确保关闭 WebSocket 连接
this.closeWebSocket();
},
beforeRouteLeave(to, from, next) {
console.log('界面关闭socketbeforeRouteLeave');
next();
},
methods: {
// ws接收消息
socketinit(){
var that = this;
if (!that.isConnected) {
console.log("wss://www.sanduolantoyoga.com/yoga-imserver/")
this.socketTask=uni.connectSocket({
url: "wss://www.sanduolantoyoga.com/yoga-imserver/",
header: {
// 'content-type': 'application/json',
Authorization: uni.getStorageSync("token"),
},
success: (res) => {
console.log(res, 'socket连接成功success');
},
fail: (res) => {
console.log(res, 'socket连接失败')
},
complete: (res) => {
console.log(res,'socket连接成功complete');
}
});
uni.onSocketOpen(resopen => {
console.log('WebSocket连接已打开');
that.isConnected = true;
uni.sendSocketMessage({
data: JSON.stringify({
"cmd": 0,//心跳
"data": {
"accessToken":uni.getStorageSync("token"),
},
}), // 发送心跳包数据 // 发送的消息内容
success(re) {
console.log(re);
console.log('消息发送成功!')
},
fail(err) {
console.log(err);
console.log('消息发送失败!')
}
});
// 发送心跳包
// this.startHeartbeat();
// 测试发送 消息
// this.sendWebSocketMessage();
});
uni.onSocketMessage(res => {
console.log('收到WebSocket服务器消息', res);
if(res.data){
var cmd=res.cmd;
let data=JSON.parse(res.data);
console.log(data);
// if(data){
// // 加入聊天记录
// // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
// if(data.type=='0'){
// data.content=decodeURIComponent(data.content);
// }
// let mdata = {
// "fromname": that.friendName,
// "fromuser": that.friendcode,
// "headimg": that.friendheadimg,
// "toname": that.info.chatName, // 接收人
// "touser": that.info.friendId, // 接收人姓名
// "content": data.content,
// "time": data.type==3?5:0,
// "ifaudio":data.type==3? true:false,
// "fromtime": data.sendTime,
// "type": data.type==0?'txt':(data.type==1?'image':data.type==3?'audio':(data.type==4?'video':'')),
// "id": data.id,
// "recvId": data.recvId,
// "sendId": data.sendId,
// };
// if(data.type==0||data.type==1||data.type==3||data.type==4){
// that.socketmsg.push(data);
// that.$forceUpdate();
// }
// else{
// // 10, "撤回" 11, "已读 " 12, "消息已读回执 " 30,"加载中标记"
// }
// }
}
});
uni.onSocketClose(res => {
console.log('WebSocket连接已关闭');
that.isConnected = false;
clearInterval(that.heartbeatInterval); // 停止心跳包发送
});
uni.onSocketError(err => {
console.error('WebSocket连接打开失败请检查', err);
clearInterval(that.heartbeatInterval); // 停止心跳包发送
});
}
},
startHeartbeat() {
console.log("startHeartbeat")
this.heartbeatInterval = setInterval(() => {
if (this.socketTask) {
this.socketTask.send({
data: JSON.stringify({
'cmd': 1,//心跳
'data': {
'accessToken':uni.getStorageSync("token")
},
}) // 发送心跳包数据
});
}
}, this.heartbeatTimeout);
},
sendWebSocketMessage(){
uni.sendSocketMessage({
data: '这是一条测试消息', // 发送的消息内容
success(re) {
console.log(re);
console.log('消息发送成功!')
},
fail(err) {
console.log(err);
console.log('消息发送失败!')
}
});
},
// 关闭WebSocket连接
closeWebSocket() {
uni.closeSocket();
this.isConnected = false;
clearInterval(this.heartbeatInterval); // 停止心跳包发送
},
gotoContacts(){
uni.navigateTo({
url: `/pages/message/contact`
});
},
changeTime(date) {
return dateTime.dateTime(date);
},
gotoGroup(info){
// 去聊天室
if(info.type==1){
// 客服
var data=encodeURIComponent(JSON.stringify(info));
uni.navigateTo({
url: `/pages/chat/groupchat?data=${data}`
});
}
else if(info.type==2){
// 老师
var data=encodeURIComponent(JSON.stringify(info));
uni.navigateTo({
url: `/pages/chat/chat?data=${data}`
});
}
},
loadData(){
// 信息列表加载
this.loadStatus="loading";
setTimeout(() => {
this.getgroupsmembers();
}, 300);
},
// 获取群聊列表
async getgroupsmembers(){
// 获取聊天群列表
this.grouplist=[];
var chatlist=myCache("chatlist")?myCache("chatlist"):[];
chatlist.forEach(cell=>{
if(cell.fromuser==this.userid){
this.grouplist.push(cell);
}
});
this.grouplist.forEach((cell,i)=>{
if(cell.minId){
// 通过某个会话中已读消息的最大id 获取离线消息
this.getgroupsnums(i,cell.minId)
}
});
this.loadStatus="nomore";
this.$forceUpdate();
},
// 获取群聊中离线信息
async getgroupsnums(i,id){
const {data: res} = await uni.$http.get("/api/message/private/pullOfflineMessage",{"minId":id});
if(res.data&&res.data.length>0){
// 获取消息后对消息进行缓存处理
var data=res.data;
// 获取离线消息数量返回
this.grouplist[i]["sl"]=res.data.length;
this.$forceUpdate();
}
},
// 获取状态栏高度
geStatusBarHeight(){
return uni.getSystemInfoSync()['statusBarHeight'];
},
// 获取导航栏高度
getNavBarHeight(){
return 45+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 - 100rpx);
/* #ifdef H5 */
margin: calc( 110rpx + var(--window-top)) 0 0 0;
min-height: calc(100vh - var(--window-top) - var(--window-bottom) - 100rpx);
/* #endif */
overflow-y: auto;
}
.listcell{
background: #fff;
margin: 0;
.lcon{
border-bottom: 1rpx solid #eee;
padding-top: 20rpx;
padding-bottom: 20rpx;
opacity: 1;
display: flex;
flex-direction: row;
align-items: center;
.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;
}
}
.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-family: PingFang SC, PingFang SC;
font-weight: 600;
color: #000000;
}
.ptime{
line-height: 50rpx;
font-size: 24rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 500;
color: #595959;
}
.pnr{
display: flex;
flex: 1;
font-size: 24rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
color: #595959;
}
.lnum{
background-color: #de0000;
padding: 0 10rpx;
min-width: 32rpx;
height: 32rpx;
line-height: 32rpx;
color: #fff;
font-size: 24rpx;
border-radius: 28rpx;
}
}
}
.tips{
margin-top: 20rpx;
margin-bottom: 20rpx;
width: 100%;
line-height: 44rpx;
font-size: 26rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
color: #595959;
text-align: center;
}
.submitcon{
margin-top: 200rpx;
display: flex;
align-items: center;
justify-content: center;
}
.bbtn{
margin: 20rpx 30rpx 54rpx;
font-size: 32rpx;
font-family: PingFang SC-Medium, PingFang SC;
font-weight: 500;
color: #FCFCFD;
width: 560rpx;
height: 96rpx;
line-height: 96rpx;
background: #367FFA;
box-shadow: 0rpx 12rpx 64rpx 2rpx rgba(67,110,255,0.4);
border-radius: 254rpx 254rpx 254rpx 254rpx;
opacity: 1;
&::after{
border:none;
}
}
.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>