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

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="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>