From 7f5c4fd704d4fc7e9eca679bb527822e8b374fc7 Mon Sep 17 00:00:00 2001
From: zouyanyan <254651820@qq.com>
Date: Mon, 8 Jun 2026 14:34:57 +0800
Subject: [PATCH] upbug
---
components/chat/submit.vue | 14 +-
manifest.json | 4 +-
pages/chat/chat.vue | 433 +++++++++++++++---------
pages/chat/groupchat.vue | 335 +++++++++++-------
pages/index/index.vue | 7 +
pages/message/group.vue | 675 ++++++++++++++++++++++---------------
pages/user/user.vue | 5 -
static/icon/voice.png | Bin 1717 -> 1733 bytes
static/icon/voice0.png | Bin 0 -> 1717 bytes
9 files changed, 911 insertions(+), 562 deletions(-)
create mode 100644 static/icon/voice0.png
diff --git a/components/chat/submit.vue b/components/chat/submit.vue
index b39b386..5905484 100644
--- a/components/chat/submit.vue
+++ b/components/chat/submit.vue
@@ -152,7 +152,7 @@
// }, 0)
// }
- if (this.msg.length > 1) {
+ if (this.msg.length > 0) {
// 0为表情和文字
this.send(this.msg, 'txt');
this.ifmore=true;
@@ -161,7 +161,7 @@
},
inputs(e) {
var chatm = e.detail.value;
- if (chatm.length > 1) {
+ if (chatm.length > 0) {
this.ifmore=false;
}
else{
@@ -431,12 +431,12 @@
display: flex;
align-items: flex-end;
box-sizing: border-box;
- padding: 14rpx 20rpx;
+ padding: 14rpx;
image {
- width: 56rpx;
- height: 56rpx;
- margin: 0 10rpx;
+ width: 60rpx;
+ height: 60rpx;
+ margin: 0 8rpx;
flex: auto;
}
.btnt {
@@ -464,7 +464,7 @@
.record {
line-height: 44rpx;
text-align: center;
- font-size: 20rpx;
+ font-size: 24rpx;
color: rgba(39, 40, 50, 0.6);
}
}
diff --git a/manifest.json b/manifest.json
index b40d8d2..c1782a1 100644
--- a/manifest.json
+++ b/manifest.json
@@ -2,8 +2,8 @@
"name" : "瑜伽汇",
"appid" : "__UNI__B6E0086",
"description" : "瑜伽汇",
- "versionName" : "1.0.12",
- "versionCode" : 1012,
+ "versionName" : "1.0.16",
+ "versionCode" : 1016,
"transformPx" : false,
"app-plus" : {
"flexible" : true,
diff --git a/pages/chat/chat.vue b/pages/chat/chat.vue
index ddc3615..fd9de54 100644
--- a/pages/chat/chat.vue
+++ b/pages/chat/chat.vue
@@ -90,18 +90,26 @@
{{item.fromname}}
+ 已读
+ 未读
{{item.content}}
+ 已读
+ 未读
+ 已读
+ 未读
+ 已读
+ 未读
{{item.time}}″
@@ -112,6 +120,8 @@
+ 已读
+ 未读
订单咨询
@@ -276,15 +286,13 @@
this.sendinfo=null;
this.$forceUpdate();
}
-
- // 先获取聊天记录缓存
- this.getchatstore();
}
},
onShow() {
+ // 先获取聊天记录缓存
+ this.getchatstore();
// 跳转到最后一条数据 与前面的:id进行对照
setTimeout(() => {
- console.log("onShow")
this.screendo(this.unshiftmsg.length - 1);
}, 100);
@@ -292,26 +300,24 @@
if(this.heartbeatInterval){
clearInterval(this.heartbeatInterval); // 停止心跳包发送
}
- // socket接收实时消息
- this.socketinit();
},
onBackPress(options) {
if (options.from === 'backbutton') {
// 来自顶部菜单的返回按钮
// 在这里处理你的逻辑
console.log('返回按钮被点击');
- this.closeWebSocket();
- uni.onSocketClose(function (res) {
- console.log('WebSocket 已关闭!');
- });
+ // this.closeWebSocket();
+ // uni.onSocketClose(function (res) {
+ // console.log('WebSocket 已关闭!');
+ // });
return false;
}
},
beforeDestroy() {
console.log('界面关闭socket,beforeDestroy');
// 在组件销毁前,确保关闭 WebSocket 连接
- this.closeWebSocket();
- clearInterval(this.heartbeatInterval); // 停止心跳包发送
+ // this.closeWebSocket();
+ // clearInterval(this.heartbeatInterval); // 停止心跳包发送
},
methods: {
gotoDetail(item){
@@ -385,11 +391,12 @@
},
// 获取聊天记录
getchatstore(){
+ console.log("getchatstore");
var that=this;
try{
+ this.unshiftmsg=[];
// 先获取会话缓存
- var data= myCache(this.info.chatId)?myCache(this.info.chatId):[];
- console.log("data",data)
+ var data= myCache(this.info.chatId)?myCache(this.info.chatId):[];
data.forEach((cell,i)=>{
cell["ifaudio"]=false;
//时间间隔处理
@@ -409,8 +416,7 @@
cell.content=decodeURIComponent(cell.content);
}
this.unshiftmsg.push(cell);
- });
-
+ });
if(this.unshiftmsg.length<=0)
{
if(this.info.from=="yh"){
@@ -452,31 +458,42 @@
}
];
this.$forceUpdate();
- }
-
- // 如果是第一次接收消息没有缓存,且有minId则拉取离线消息
- if(this.info.minId){
- this.readUp(1);
- }
+ }
}
else{
// 跳转到最后一条数据 与前面的:id进行对照
setTimeout(() => {
that.screendo(that.unshiftmsg.length-1);
}, 100);
- // 已经有缓存,则拉取离线消息
- this.info.minId=this.unshiftmsg[this.unshiftmsg.length-1].id;
- this.$forceUpdate();
- // 请求服务器加载加载拉取离线聊天记录
- if(this.info.minId&&this.info.minId>0){
- this.readUp(1);
- }
}
-
}
catch(err){
console.log(err);
}
+
+ // socket接收实时消息
+ this.socketinit();
+
+ },
+ // 是否是列表中已经存在了minId
+ ifpull(){
+ var ret=true;
+ this.unshiftmsg.forEach((cell)=>{
+ if(cell.id&&this.info.minId&&parseInt(cell.id)>=parseInt(this.info.minId)){
+ ret=false;
+ }
+ });
+ return ret;
+ },
+ // 消息是否存在列表中
+ ifadd(id){
+ var ret=true;
+ this.unshiftmsg.forEach((cell)=>{
+ if(cell.id==id){
+ ret=false;
+ }
+ });
+ return ret;
},
// 定时心跳包
startHeartbeat() {
@@ -497,54 +514,59 @@
// ws接收消息
socketinit(){
var that = this;
- if (!this.isConnected) {
- 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连接失败')
+ 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');
+ // 获取当前聊天中的minId 拉取离线信息
+ that.getReadedId();
+ },
+ fail: (res) => {
+ console.log(res, 'socket连接失败')
+ },
+ complete: (res) => {
+ console.log(res,'socket连接成功complete');
+ }
+ });
+ uni.onSocketOpen(res => {
+ 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('消息发送成功!')
},
- complete: (res) => {
- console.log(res,'socket连接成功complete');
+ fail(err) {
+ console.log(err);
+ console.log('消息发送失败!')
}
});
- uni.onSocketOpen(res => {
- 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();
- });
- uni.onSocketMessage(res => {
- console.log('收到WebSocket服务器消息:');
- if(res.data){
- let data=JSON.parse(res.data);
- console.log(data);
- if(data.data){
- data=data.data;
- if(data){
+
+ // 发送心跳包
+ this.startHeartbeat();
+
+ });
+ uni.onSocketMessage(res => {
+ console.log('收到WebSocket服务器消息:');
+ if(res.data){
+ let data=JSON.parse(res.data);
+ console.log(data);
+ if(data.data){
+ data=data.data;
+ if(data){
+ if(this.ifadd(data.id)){
// 是发送者发送来的消息
if(data.recvId&&data.recvId.toString()==that.userid.toString()&&data.sendId.toString()==this.info.friendId.toString()){
// 加入聊天记录
@@ -596,19 +618,24 @@
}
}
}
+ // 10, "撤回" 11, "已读 " 12, "消息已读回执 " 30,"加载中标记"
+ if(data.type==12){
+ // 已读操作
+ this.updateRead(data);
+ }
}
}
- });
- uni.onSocketClose(res => {
- console.log('WebSocket连接已关闭!');
- that.isConnected = false;
- clearInterval(that.heartbeatInterval); // 停止心跳包发送
- });
- uni.onSocketError(err => {
- console.error('WebSocket连接打开失败,请检查:', err);
- clearInterval(that.heartbeatInterval); // 停止心跳包发送
- });
- }
+ }
+ });
+ uni.onSocketClose(res => {
+ console.log('WebSocket连接已关闭!');
+ that.isConnected = false;
+ clearInterval(that.heartbeatInterval); // 停止心跳包发送
+ });
+ uni.onSocketError(err => {
+ console.error('WebSocket连接打开失败,请检查:', err);
+ clearInterval(that.heartbeatInterval); // 停止心跳包发送
+ });
},
// 关闭WebSocket连接
closeWebSocket() {
@@ -621,14 +648,37 @@
async setMsglist(data){
data.send=data.type==6?await this.getProduct(data.content):(data.type==5?await this.getOrder(data.content):null);
data.type=data.type==0?'txt':(data.type==1?'image':data.type==3?'audio':(data.type==4?'video':(data.type==5?'order':(data.type==6?'product':'')))),
- console.log("setMsglist",data)
+ // console.log("setMsglist",data)
this.unshiftmsg.push(data);
this.$forceUpdate();
setTimeout(() => {
this.screendo(this.unshiftmsg.length-1);
}, 100);
// 缓存聊天
- myCache(this.info.chatId,this.unshiftmsg);
+ myCache(this.info.chatId,this.unshiftmsg);
+ // 保存最大拉取Id
+ this.savaMaxId({id:this.info.chatId,minId:this.info.minId});
+ },
+ savaMaxId(info){
+ // 保存最大拉取Id
+ var data= myCache("privateMsgMaxId")?myCache("privateMsgMaxId"):[];
+ console.log("data",data)
+ var ifhas=0;
+ data.forEach((cell,i)=>{
+ if(cell.id==info.id){
+ ifhas=1;
+ data[i].minId==info.minId;
+ }
+ });
+ if(ifhas){
+ // 如果存在信息修改
+ myCache("privateMsgMaxId",data);
+ }
+ else{
+ // 如果不存在信息添加
+ data.push(info);
+ myCache("privateMsgMaxId",data);
+ }
},
async getProduct(id){
console.log("getProduct",id)
@@ -679,89 +729,97 @@
async readed() {
const {data: res} = await uni.$http.put('/api/message/private/readed?friendId='+this.info.friendId);
},
- // 已读推送
- async readUp(ii) {
- const {data: res} = await uni.$http.put('/api/message/private/readed?friendId='+this.info.friendId);
- this.getList(ii);
+ // 获取当前聊天中最大minId
+ async getReadedId() {
+ const {data: res} = await uni.$http.get('/api/message/private/maxReadedId',{friendId:this.info.friendId});
+ if(res.data){
+ this.info.minId=res.data;
+ this.$forceUpdate();
+ // 保存最大拉取Id
+ this.savaMaxId({id:this.info.chatId,minId:this.info.minId});
+ this.getList();
+ }
},
- // 加载对话
- async getList(ii) {
- var that=this;
- const {data: res} = await uni.$http.get('/api/message/private/pullOfflineMessage',{minId: this.info.minId});
- this.triggered = false;
- if(res.data&&res.data.length>0){
- const gotonum=res.data.length;
- var type=0;
- res.data.forEach((cell,i)=>{
- type=cell.type;
- cell["ifaudio"]=false;
- //时间间隔处理
- if (i < this.unshiftmsg.length - 1) {
- //这里表示头部时间还是显示一下
- let t = dateTime.spaceTime(this.oldTime, cell.fromtime);
- if (t) {
- this.oldTime = t;
+ // 拉取离线消息
+ async getList() {
+ // 判断当前 minId 是不是列表中已经存在了,是不再拉取,不是继续拉取
+ // if(this.ifpull()){
+ var that=this;
+ const {data: res} = await uni.$http.get('/api/message/private/pullOfflineMessage',{minId: this.info.minId});
+ this.triggered = false;
+ if(res.data&&res.data.length>0){
+ var type=0;
+ res.data.forEach((cell,i)=>{
+ type=cell.type;
+ cell["ifaudio"]=false;
+ //时间间隔处理
+ if (i < this.unshiftmsg.length - 1) {
+ //这里表示头部时间还是显示一下
+ let t = dateTime.spaceTime(this.oldTime, cell.fromtime);
+ if (t) {
+ this.oldTime = t;
+ }
+ cell.fromtime = t;
}
- cell.fromtime = t;
- }
- // 获取图片,为下面的预览做准备
- if (cell.type == 1) {
- this.imgMsg.unshift(cell.content)
- }
- else if(cell.type==0){
- cell.content=decodeURIComponent(cell.content);
- }
- // // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 5 订单 6 商品 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
- let mdata = {
- "fromname": this.userName,
- "fromuser": this.userid,
- "headimg": cell.headImage?cell.headImage:'/static/image/kfr.png',
- "toname": this.info.chatName, // 接收人
- "touser": this.info.friendId, // 接收人姓名
- "content": cell.content,
- "time": cell.type==3?5:0,
- "ifaudio":cell.type==3? true:false,
- "fromtime": cell.sendTime,
- "type": data.type==0?'txt':(data.type==1?'image':data.type==3?'audio':(data.type==4?'video':(data.type==5?'order':(data.type==6?'product':'')))),
- "id": cell.id,
- "recvId": cell.recvId,
- "sendId": cell.sendId,
- };
- this.unshiftmsg.unshift(mdata);
- });
- if(ii==2){
- // 跳转到加载数据的第一条 与前面的:id进行对照
- setTimeout(() => {
- that.screendo(gotonum -1);
- }, 100);
- }
- else{
+ // 获取图片,为下面的预览做准备
+ if (cell.type == 1) {
+ this.imgMsg.unshift(cell.content)
+ }
+ else if(cell.type==0){
+ cell.content=decodeURIComponent(cell.content);
+ }
+ // // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 5 订单 6 商品 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
+ let mdata = {
+ "fromname": this.userName,
+ "fromuser": this.userid,
+ "headimg": cell.headImage?cell.headImage:'/static/image/kfr.png',
+ "toname": this.info.chatName, // 接收人
+ "touser": this.info.friendId, // 接收人姓名
+ "content": cell.content,
+ "time": cell.type==3?5:0,
+ "ifaudio":cell.type==3? true:false,
+ "fromtime": cell.sendTime,
+ "type": data.type==0?'txt':(data.type==1?'image':data.type==3?'audio':(data.type==4?'video':(data.type==5?'order':(data.type==6?'product':'')))),
+ "id": cell.id,
+ "recvId": cell.recvId,
+ "sendId": cell.sendId,
+ };
+ this.unshiftmsg.unshift(mdata);
+ });
+
// 跳转到最后一条数据 与前面的:id进行对照
setTimeout(() => {
that.screendo(that.unshiftmsg.length-1);
}, 100);
+
+ // 缓存聊天
+ myCache(this.info.chatId,this.unshiftmsg);
+ this.info.minId=this.unshiftmsg[this.unshiftmsg.length-1].id;
+ // 保存最大拉取Id
+ // this.savaMaxId({id:this.info.chatId,minId:this.info.minId});
+ this.$forceUpdate();
+
+ // 离线加载后更新聊天列表记录
+ var chatlastinfo={
+ id: this.info.chatId,
+ content:this.unshiftmsg[this.unshiftmsg.length-1].content,
+ type: type,
+ minId: this.unshiftmsg[this.unshiftmsg.length-1].id,
+ datetime: this.unshiftmsg[this.unshiftmsg.length-1].sendTime,
+ name: this.info.chatName,
+ userid: this.userid,
+ fromuser: this.info.friendId,
+ img: this.info.chatAvatar,
+ sort:"privatechat"
+ };
+ this.updateChatList(chatlastinfo);
+
+ // 已读操作
+ this.readed();
+
}
- // 缓存聊天
- myCache(this.info.chatId,this.unshiftmsg);
- this.info.minId=this.unshiftmsg[this.unshiftmsg.length-1].id;
- this.$forceUpdate();
-
- // 离线加载后更新聊天列表记录
- var chatlastinfo={
- id: this.info.chatId,
- content:this.unshiftmsg[this.unshiftmsg.length-1].content,
- type: type,
- minId: this.unshiftmsg[this.unshiftmsg.length-1].id,
- datetime: this.unshiftmsg[this.unshiftmsg.length-1].sendTime,
- name: this.info.chatName,
- userid: this.userid,
- fromuser: this.info.friendId,
- img: this.info.chatAvatar,
- sort:"privatechat"
- };
- this.updateChatList(chatlastinfo);
-
- }
+ // }
+
},
screendo(scrindex){
this.scrollToView = '';
@@ -785,7 +843,7 @@
// 自定义下拉刷新被触发
onRefresh(event){
// 加载聊天记录
- this.readUp(2);
+ this.getList();
},
// 自定义下拉刷新被复位
onRestore() {
@@ -1103,6 +1161,10 @@
this.$forceUpdate();
// 缓存聊天
myCache(this.info.chatId,this.unshiftmsg);
+ this.info.minId=this.unshiftmsg[this.unshiftmsg.length-1].id;
+ this.$forceUpdate();
+ // 保存最大拉取Id
+ // this.savaMaxId({id:this.info.chatId,minId:this.info.minId});
// 更新聊天列表记录
var chatlastinfo={
id:this.info.chatId,
@@ -1162,6 +1224,19 @@
myCache("chatlist-"+this.userid,chatlist);
}
},
+ // 更新是否已读
+ updateRead(item){
+ console.log("updateRead")
+ this.unshiftmsg.forEach((cell,index)=>{
+ // console.log(cell,item.recvId)
+ if(cell.fromuser==item.recvId){
+ this.unshiftmsg[index].ifread=true;
+ this.$forceUpdate();
+ }
+ });
+ // 缓存聊天
+ myCache(this.info.chatId,this.unshiftmsg);
+ },
//输入框高度
heights(e) {
this.inputh = e;
@@ -1246,19 +1321,23 @@
}
.message {
flex: none;
- max-width: 480rpx;
+ max-width: 540rpx;
+ display: flex;
+ flex-direction: row;
}
.messagevideo {
- max-width: 480rpx;
+ max-width: 540rpx;
height: 300rpx;
+ display: flex;
+ flex-direction: row;
}
.msg-text {
font-size: 32rpx;
color: rgba(39, 40, 50, 1);
line-height: 44rpx;
padding: 18rpx 24rpx;
+ word-break: break-all;
}
-
.msg-img {
max-width: 400rpx;
border-radius: 20rpx;
@@ -1337,6 +1416,7 @@
margin-left: 16rpx;
background-color: #fff;
border-radius: 0rpx 20rpx 20rpx 20rpx;
+ word-break: break-all;
}
.ms-img {
@@ -1497,6 +1577,22 @@
.msg-right {
flex-direction: row-reverse;
+ .read{
+ font-size: 24rpx;
+ color: #888;
+ margin-right: 10rpx;
+ display: flex;
+ justify-content: flex-end;
+ align-items: flex-end;
+ }
+ .noread{
+ font-size: 24rpx;
+ color: #00a89b;
+ margin-right: 10rpx;
+ display: flex;
+ justify-content: flex-end;
+ align-items: flex-end;
+ }
.feed-imgy{
display: flex;
flex-direction: column;
@@ -1523,6 +1619,7 @@
font-size: 32rpx;
color: #FFFFFF;
line-height: 48rpx;
+ word-break: break-all;
border-radius: 20rpx 0rpx 20rpx 20rpx;
}
diff --git a/pages/chat/groupchat.vue b/pages/chat/groupchat.vue
index 53aeb45..d1f6572 100644
--- a/pages/chat/groupchat.vue
+++ b/pages/chat/groupchat.vue
@@ -90,19 +90,29 @@
{{item.fromname}}
+ 已读
+ {{item.readedCount?(2-item.readedCount):2}}未读
{{item.content}}
+ 已读
+ {{item.readedCount?(2-item.readedCount):2}}未读
+ 已读
+ {{item.readedCount?(2-item.readedCount):2}}未读
+ 已读
+ {{item.readedCount?(2-item.readedCount):2}}未读
+ 已读
+ {{item.readedCount?(2-item.readedCount):2}}未读
{{item.time}}″
@@ -112,6 +122,8 @@
+ 已读
+ {{item.readedCount?(2-item.readedCount):2}}未读
订单咨询
@@ -349,15 +361,15 @@
this.sendinfo=null;
this.$forceUpdate();
}
-
- // 先获取聊天记录缓存
- this.getchatstore();
-
- // 获取客服 和 教练 头像和名称
- this.getrwinfo();
}
},
onShow() {
+ // 先获取聊天记录缓存
+ this.getchatstore();
+
+ // 获取客服 和 教练 头像和名称
+ this.getrwinfo();
+
// 跳转到最后一条数据 与前面的:id进行对照
setTimeout(() => {
console.log("onShow")
@@ -368,18 +380,16 @@
if(this.heartbeatInterval){
clearInterval(this.heartbeatInterval); // 停止心跳包发送
}
- // socket接收实时消息
- this.socketinit();
},
onBackPress(options) {
if (options.from === 'backbutton') {
// 来自顶部菜单的返回按钮
// 在这里处理你的逻辑
console.log('返回按钮被点击');
- this.closeWebSocket();
- uni.onSocketClose(function (res) {
- console.log('WebSocket 已关闭!');
- });
+ // this.closeWebSocket();
+ // uni.onSocketClose(function (res) {
+ // console.log('WebSocket 已关闭!');
+ // });
return false;
}
},
@@ -393,8 +403,8 @@
beforeDestroy() {
console.log('界面关闭socket,beforeDestroy');
// 在组件销毁前,确保关闭 WebSocket 连接
- this.closeWebSocket();
- clearInterval(this.heartbeatInterval); // 停止心跳包发送
+ // this.closeWebSocket();
+ // clearInterval(this.heartbeatInterval); // 停止心跳包发送
},
methods: {
// 获取客服和教练信息
@@ -499,9 +509,9 @@
getchatstore(){
var that=this;
try{
+ this.unshiftmsg=[];
// 先获取会话缓存
var data= myCache(this.info.chatId)?myCache(this.info.chatId):[];
- console.log("data",data)
data.forEach((cell,i)=>{
cell["ifaudio"]=false;
//时间间隔处理
@@ -565,30 +575,39 @@
];
this.$forceUpdate();
}
-
- // 如果是第一次接收消息没有缓存,且有minId则拉取离线消息
- if(this.info.minId){
- this.readUp(1);
- }
}
else{
// 跳转到最后一条数据 与前面的:id进行对照
setTimeout(() => {
that.screendo(that.unshiftmsg.length-1);
}, 100);
- // 已经有缓存,则拉取离线消息
- this.info.minId=this.unshiftmsg[this.unshiftmsg.length-1].id;
- this.$forceUpdate();
- // 请求服务器加载加载拉取离线聊天记录
- if(this.info.minId&&this.info.minId>0){
- this.readUp(1);
- }
}
-
}
catch(err){
console.log(err);
}
+
+ // socket接收实时消息
+ this.socketinit();
+ },
+ // 是否是列表中已经存在了minId
+ ifpull(){
+ var ret=true;
+ this.unshiftmsg.forEach((cell)=>{
+ if(cell.id&&this.info.minId&&parseInt(cell.id)>=parseInt(this.info.minId)){
+ ret=false;
+ }
+ });
+ return ret;
+ },
+ ifadd(id){
+ var ret=true;
+ this.unshiftmsg.forEach((cell)=>{
+ if(cell.id==id){
+ ret=false;
+ }
+ });
+ return ret;
},
// 定时心跳包
startHeartbeat() {
@@ -626,6 +645,8 @@
},
success: (res) => {
console.log(res, 'socket连接成功success');
+ // 获取当前聊天中的minId 拉取离线信息
+ that.getReadedId();
},
fail: (res) => {
console.log(res, 'socket连接失败')
@@ -666,18 +687,29 @@
// 群聊
if(data.data){
data=data.data;
+
// 是此群聊发送来的消息
if(data.groupId==this.info.groupId){
- // 加入聊天记录
- // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 5 订单 6 商品 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
- if(data.type==0||data.type==1||data.type==2||data.type==3||data.type==4||data.type==5||data.type==6){
- this.getMsgSender(data)
+ if(this.ifadd(data.id)){
+ // 加入聊天记录
+ // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 5 订单 6 商品 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
+ if(data.type==0||data.type==1||data.type==2||data.type==3||data.type==4||data.type==5||data.type==6){
+ this.getMsgSender(data);
+ // 已读操作
+ this.readed();
+ }
+ else{
+ // 10, "撤回" 11, "已读 " 12, "消息已读回执 " 30,"加载中标记"
+ }
}
- else{
- // 10, "撤回" 11, "已读 " 12, "消息已读回执 " 30,"加载中标记"
+ // 10, "撤回" 11, "已读 " 12, "消息已读回执 " 30,"加载中标记"
+ if(data.type==12){
+ // 已读操作
+ this.updateRead(data);
}
}
}
+
}
}
});
@@ -742,6 +774,8 @@
// 缓存聊天
myCache(this.info.chatId,this.unshiftmsg);
+ // 保存最大拉取Id
+ this.savaMaxId({id:this.info.chatId,minId:data.id});
// 接收到socket后更新聊天列表记录
var chatlastinfo={
@@ -764,6 +798,27 @@
// 已读操作
this.readed();
},
+ savaMaxId(info){
+ // 保存最大拉取Id
+ var data= myCache("groupMsgMaxId")?myCache("groupMsgMaxId"):[];
+ console.log("data",data)
+ var ifhas=0;
+ data.forEach((cell,i)=>{
+ if(cell.id==info.id){
+ ifhas=1;
+ data[i].minId==info.minId;
+ }
+ });
+ if(ifhas){
+ // 如果存在信息修改
+ myCache("groupMsgMaxId",data);
+ }
+ else{
+ // 如果不存在信息添加
+ data.push(info);
+ myCache("groupMsgMaxId",data);
+ }
+ },
async getProduct(id){
console.log("getProduct",id)
var rets=null;
@@ -812,93 +867,102 @@
async readed() {
const {data: res} = await uni.$http.put('/api/message/group/readed?groupId='+this.info.groupId);
},
- // 已读推送
- async readUp(ii) {
- const {data: res} = await uni.$http.put('/api/message/group/readed?groupId='+this.info.groupId);
- this.getList(ii);
+ // 获取当前聊天中最大minId
+ async getReadedId() {
+ const {data: res} = await uni.$http.get('/api/message/group/maxReadedId',{groupId:this.info.groupId});
+ if(res.data){
+ this.info.minId=res.data;
+ this.$forceUpdate();
+ this.getList();
+ }
},
// 加载对话
- async getList(ii) {
- var that=this;
- const {data: res} = await uni.$http.get('/api/message/group/pullOfflineMessage',{minId: this.info.minId});
- this.triggered = false;
- if(res.data&&res.data.length>0){
- const gotonum=res.data.length;
- var type=0;
- res.data.forEach((cell,i)=>{
- type=cell.type;
- cell["ifaudio"]=false;
- //时间间隔处理
- if (i < this.unshiftmsg.length - 1) {
- //这里表示头部时间还是显示一下
- let t = dateTime.spaceTime(this.oldTime, cell.fromtime);
- if (t) {
- this.oldTime = t;
+ async getList() {
+ // if(this.ifpull()){
+ var that=this;
+ const {data: res} = await uni.$http.get('/api/message/group/pullOfflineMessage',{minId: this.info.minId});
+ this.triggered = false;
+ if(res.data&&res.data.length>0){
+ const gotonum=res.data.length;
+ var type=0;
+ res.data.forEach((cell,i)=>{
+ if(this.ifadd(cell.id)){
+ type=cell.type;
+ cell["ifaudio"]=false;
+ //时间间隔处理
+ if (i < this.unshiftmsg.length - 1) {
+ //这里表示头部时间还是显示一下
+ let t = dateTime.spaceTime(this.oldTime, cell.fromtime);
+ if (t) {
+ this.oldTime = t;
+ }
+ cell.fromtime = t;
+ }
+ // 获取图片,为下面的预览做准备
+ if (cell.type == 1) {
+ this.imgMsg.unshift(cell.content)
+ }
+ else if(cell.type==0){
+ cell.content=decodeURIComponent(cell.content);
+ }
+ // // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 5 订单 6 商品 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
+ let mdata = {
+ "fromname": this.userName,
+ "fromuser": this.userid,
+ "headimg": cell.headImage?cell.headImage:'/static/image/kfr.png',
+ "toname": cell.sendNickName, // 接收人
+ "touser": cell.sendId, // 接收人姓名
+ "content": cell.content,
+ "readedCount": cell.readedCount,
+ "time": cell.type==3?5:0,
+ "ifaudio":cell.type==3? true:false,
+ "fromtime": cell.sendTime,
+ "type": data.type==0?'txt':(data.type==1?'image':data.type==3?'audio':(data.type==4?'video':(data.type==5?'order':(data.type==6?'product':'')))),
+ "id": cell.id,
+ "sendId": cell.sendId,
+ "atUserIds": data.atUserIds,
+ };
+ this.unshiftmsg.unshift(mdata);
}
- cell.fromtime = t;
- }
- // 获取图片,为下面的预览做准备
- if (cell.type == 1) {
- this.imgMsg.unshift(cell.content)
- }
- else if(cell.type==0){
- cell.content=decodeURIComponent(cell.content);
- }
- // // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 5 订单 6 商品 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
- let mdata = {
- "fromname": this.userName,
- "fromuser": this.userid,
- "headimg": cell.headImage?cell.headImage:'/static/image/kfr.png',
- "toname": cell.sendNickName, // 接收人
- "touser": cell.sendId, // 接收人姓名
- "content": cell.content,
- "readedCount": cell.readedCount,
- "time": cell.type==3?5:0,
- "ifaudio":cell.type==3? true:false,
- "fromtime": cell.sendTime,
- "type": data.type==0?'txt':(data.type==1?'image':data.type==3?'audio':(data.type==4?'video':(data.type==5?'order':(data.type==6?'product':'')))),
- "id": cell.id,
- "sendId": cell.sendId,
- "atUserIds": data.atUserIds,
- };
- this.unshiftmsg.unshift(mdata);
- });
- if(ii==2){
- // 跳转到加载数据的第一条 与前面的:id进行对照
- setTimeout(() => {
- that.screendo(gotonum -1);
- }, 100);
- }
- else{
+ });
+ // // 跳转到加载数据的第一条 与前面的:id进行对照
+ // setTimeout(() => {
+ // that.screendo(gotonum -1);
+ // }, 100);
// 跳转到最后一条数据 与前面的:id进行对照
setTimeout(() => {
that.screendo(that.unshiftmsg.length-1);
}, 100);
+ // 缓存聊天
+ myCache(this.info.chatId,this.unshiftmsg);
+ this.info.minId=this.unshiftmsg[this.unshiftmsg.length-1].id;
+ this.$forceUpdate();
+ // 保存最大拉取Id
+ this.savaMaxId({id:this.info.chatId,minId:this.info.minId});
+
+ // 离线加载后更新聊天列表记录
+ var chatlastinfo={
+ id: this.info.chatId,
+ groupId:this.info.groupId,
+ content:this.unshiftmsg[this.unshiftmsg.length-1].content,
+ type: type,
+ minId: this.unshiftmsg[this.unshiftmsg.length-1].id,
+ datetime: this.unshiftmsg[this.unshiftmsg.length-1].sendTime,
+ name: this.info.chatName,
+ userid: this.userid,
+ friendId: this.info.friendId, // 客服userid
+ teacherId: this.info.teacherId? this.info.teacherId:this.info.instructor, // 教练userid
+ fromuser: this.unshiftmsg[this.unshiftmsg.length-1].touser,
+ img: this.unshiftmsg[this.unshiftmsg.length-1].headimg,
+ sort:"groupchat"
+ };
+ this.updateChatList(chatlastinfo);
+
+ // 已读操作
+ this.readed();
}
- // 缓存聊天
- myCache(this.info.chatId,this.unshiftmsg);
- this.info.minId=this.unshiftmsg[this.unshiftmsg.length-1].id;
- this.$forceUpdate();
-
- // 离线加载后更新聊天列表记录
- var chatlastinfo={
- id: this.info.chatId,
- groupId:this.info.groupId,
- content:this.unshiftmsg[this.unshiftmsg.length-1].content,
- type: type,
- minId: this.unshiftmsg[this.unshiftmsg.length-1].id,
- datetime: this.unshiftmsg[this.unshiftmsg.length-1].sendTime,
- name: this.info.chatName,
- userid: this.userid,
- friendId: this.info.friendId, // 客服userid
- teacherId: this.info.teacherId? this.info.teacherId:this.info.instructor, // 教练userid
- fromuser: this.unshiftmsg[this.unshiftmsg.length-1].touser,
- img: this.unshiftmsg[this.unshiftmsg.length-1].headimg,
- sort:"groupchat"
- };
- this.updateChatList(chatlastinfo);
-
- }
+ // }
+
},
screendo(scrindex){
this.scrollToView = '';
@@ -922,7 +986,7 @@
// 自定义下拉刷新被触发
onRefresh(event){
// 加载聊天记录
- this.readUp(2);
+ this.getList();
},
// 自定义下拉刷新被复位
onRestore() {
@@ -1240,6 +1304,9 @@
this.$forceUpdate();
// 缓存聊天
myCache(this.info.chatId,this.unshiftmsg);
+ // 保存最大拉取Id
+ this.savaMaxId({id:this.info.chatId,minId:rrdata.id});
+
// 更新聊天列表记录
var chatlastinfo={
id:this.info.chatId,
@@ -1302,6 +1369,21 @@
myCache("chatlist-"+this.userid,chatlist);
}
},
+ // 更新是否已读
+ updateRead(item){
+ console.log(this.info)
+ this.unshiftmsg.forEach((cell,index)=>{
+ if(cell.id==item.id){
+ this.unshiftmsg[index].readedCount=item.readedCount;
+ if(item.readedCount>=2){
+ this.unshiftmsg[index].ifread=true;
+ }
+ this.$forceUpdate();
+ }
+ });
+ // 缓存聊天
+ myCache(this.info.chatId,this.unshiftmsg);
+ },
//输入框高度
heights(e) {
this.inputh = e;
@@ -1386,11 +1468,15 @@
}
.message {
flex: none;
- max-width: 480rpx;
+ max-width: 540rpx;
+ display: flex;
+ flex-direction: row;
}
.messagevideo {
- max-width: 480rpx;
+ max-width: 540rpx;
height: 300rpx;
+ display: flex;
+ flex-direction: row;
}
.msg-text {
font-size: 32rpx;
@@ -1637,6 +1723,23 @@
.msg-right {
flex-direction: row-reverse;
+ .read{
+ font-size: 24rpx;
+ color: #888;
+ margin-right: 10rpx;
+ display: flex;
+ justify-content: flex-end;
+ align-items: flex-end;
+ }
+ .noread{
+ font-size: 24rpx;
+ color: #00a89b;
+ margin-right: 10rpx;
+ display: flex;
+ justify-content: flex-end;
+ align-items: flex-end;
+ }
+
.feed-imgy{
display: flex;
flex-direction: column;
diff --git a/pages/index/index.vue b/pages/index/index.vue
index eabbe16..8e50656 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -781,6 +781,13 @@
.thname{
font-size: 30rpx;
color:#000;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ /* 假设你的行高是20px,并且你想要两行显示 */
+ line-height: 40rpx; /* 每行的行高 */
+ max-height: 80rpx;
}
.thtext{
margin-top: 10rpx;
diff --git a/pages/message/group.vue b/pages/message/group.vue
index cdb5141..cf20d90 100644
--- a/pages/message/group.vue
+++ b/pages/message/group.vue
@@ -12,27 +12,28 @@
暂无消息~
-
-
-
-
+
+
+
+
+
+
+
+ {{info.name}}
+ {{ changeTime(info.datetime)}}
-
-
- {{info.name}}
- {{ changeTime(info.datetime)}}
+
+
+ {{ info.type==0?info.content:(info.type==1?"图片":(info.type==2?"文件":(info.type==3?"语音":(info.type==4?"视频":
+ (info.type==5?"订单咨询":(info.type==6?"商品咨询":info.content))))))}}
-
-
- {{ info.type==0?info.content:(info.type==1?"图片":(info.type==2?"文件":(info.type==3?"语音":(info.type==4?"视频":
- (info.type==5?"订单咨询":(info.type==6?"商品咨询":info.content))))))}}
-
-
- {{ info.sl}}
-
+
+ {{ info.sl}}
-
+
+
@@ -71,7 +72,7 @@
backgroundColor: '#ed2a28'
}
}
- ], //u-swipe-action样式
+ ], // u-swipe-action样式
imgurl:uni.$http.baseUrl,
grouplist:[],
socketTask: null,
@@ -82,8 +83,6 @@
}
},
onLoad(options) {
- // socket接收信息初始化
- // this.socketinit();
},
onShow(){
this.openId = myCache('openId');
@@ -110,18 +109,18 @@
// 来自顶部菜单的返回按钮
// 在这里处理你的逻辑
console.log('返回按钮被点击');
- this.closeWebSocket();
- uni.onSocketClose(function (res) {
- console.log('WebSocket 已关闭!');
- });
+ // this.closeWebSocket();
+ // uni.onSocketClose(function (res) {
+ // console.log('WebSocket 已关闭!');
+ // });
return false;
}
},
beforeDestroy() {
console.log('界面关闭socket,beforeDestroy');
// 在组件销毁前,确保关闭 WebSocket 连接
- this.closeWebSocket();
- clearInterval(this.heartbeatInterval); // 停止心跳包发送
+ // this.closeWebSocket();
+ // clearInterval(this.heartbeatInterval); // 停止心跳包发送
},
beforeRouteLeave(to, from, next) {
console.log('界面关闭socket,beforeRouteLeave');
@@ -130,22 +129,7 @@
methods: {
handleLongPress(info,index) {
console.log(index);
- this.$refs.swipeRef[index].open()
- // var that=this;
- // uni.showModal({
- // title: '提示',
- // content: "确定要删除此聊天记录吗?",
- // cancelText: '取消',
- // confirmText: '确定',
- // success: ress => {
- // if (ress.confirm) {
- // // myCache(info.id,"");
- // // that.grouplist.splice(index, 1);
- // // that.$forceUpdate();
- // // myCache("chatlist-"+this.userid,that.grouplist);
- // }
- // }
- // });
+ this.$refs.swipeRef[index].open();
},
// 删除
actionClick(info,index) {
@@ -158,6 +142,7 @@
confirmText: '确定',
success: ress => {
if (ress.confirm) {
+ that.$refs.swipeRef[index].close();
myCache(info.id,"");
that.grouplist.splice(index, 1);
that.$forceUpdate();
@@ -185,182 +170,222 @@
// ws接收消息
socketinit(){
var that = this;
- // if (!that.isConnected) {
-
- that.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连接失败')
+ that.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;
+ that.$forceUpdate();
+ uni.sendSocketMessage({
+ data: JSON.stringify({
+ "cmd": 0,//心跳
+ "data": {
+ "accessToken":uni.getStorageSync("token"),
+ },
+ }), // 发送心跳包数据 // 发送的消息内容
+ success(re) {
+ console.log(re);
+ console.log('消息发送成功!')
},
- complete: (res) => {
- console.log(res,'socket连接成功complete');
+ fail(err) {
+ console.log(err);
+ console.log('消息发送失败!')
}
});
- uni.onSocketOpen(resopen => {
- console.log('WebSocket连接已打开!');
- that.isConnected = true;
- that.$forceUpdate()
- 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.grouplist.forEach((cell,i)=>{
+ if(cell.minId){
+ // 通过某个会话中已读消息的最大id 获取离线消息
+ this.pullMessage(i,cell);
+ }
+ });
+
+ // 已经删除的有最大id的继续拉取是否有消息
+ var data= myCache("privateMsgMaxId")?myCache("privateMsgMaxId"):[{id:0,minId:0}];
+ data.forEach((cell)=>{
+ console.log("privateMsgMaxId")
+ var ifcz=false;
+ this.grouplist.forEach((item)=>{
+ if(cell.id==item.id){
+ // 已经存在列表了,不用拉取离线信息
+ ifcz=true;
}
});
-
- // 发送心跳包
- this.startHeartbeat();
+ if(!ifcz){
+ // 拉取离线信息
+ this.getList(cell);
+ }
});
- uni.onSocketMessage(res => {
- console.log('收到WebSocket服务器消息:');
- if(res.data){
- var rs=JSON.parse(res.data);
- console.log(rs);
- if(rs.cmd==3){
- // 私聊
- if(rs.data){
- var data=rs.data;
- if(data.recvId&&(data.recvId).toString()==(that.userid).toString()){
- // 是这个用户的接收的私聊信息
- // 加入聊天记录
- // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
- if(data.type==0){
- data.content=decodeURIComponent(data.content);
- }
- if(data.type==0||data.type==1||data.type==2||data.type==3||data.type==4||data.type==5||data.type==6){
- var ifexist=0,idx=null;
- that.grouplist.forEach((cell,index)=>{
- if(cell.fromuser==data.sendId&&cell.userid==data.recvId&&cell.sort=="privatechat"){
- ifexist=1;
- idx=index;
- that.grouplist[index].sl=(that.grouplist[index].sl?that.grouplist[index].sl+1:1);
- that.grouplist[index].content=data.content;
- that.grouplist[index].datetime=data.sendTime;
- that.grouplist[index].type=data.type;
- that.$forceUpdate();
- }
- });
-
- if(ifexist==0){
- // 未保存缓存
- // 接收到socket后更新聊天列表记录
- var chatlastinfo={
- id: "privatechat-" + data.recvId +"-" + data.sendId,
- content: data.content,
- minId: data.id,
- sl:1,
- datetime: data.sendTime,
- type: data.type,
- name: "",
- userid: data.recvId,
- fromuser: data.sendId,
- img: "",
- sort:"privatechat"
- };
- that.updateChatList(chatlastinfo,ifexist);
- }
- else{
- that.updateChatList(that.grouplist[idx],ifexist);
+ var data= myCache("groupMsgMaxId")?myCache("groupMsgMaxId"):[{id:0,minId:0}];
+ data.forEach((cell)=>{
+ var ifcz=false;
+ this.grouplist.forEach((item)=>{
+ if(cell.id==item.id){
+ // 已经存在列表了,不用拉取离线信息
+ ifcz=true;
+ }
+ });
+ if(!ifcz){
+ // 拉取离线信息
+ this.getGroupList(cell);
+ }
+ });
+
+ });
+
+ uni.onSocketMessage(res => {
+ console.log('收到WebSocket服务器消息:');
+ if(res.data){
+ var rs=JSON.parse(res.data);
+ console.log(rs);
+ if(rs.cmd==3){
+ // 私聊
+ if(rs.data){
+ var data=rs.data;
+ if(data.recvId&&(data.recvId).toString()==(that.userid).toString()){
+ // 是这个用户的接收的私聊信息
+ // 加入聊天记录
+ // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
+ if(data.type==0){
+ data.content=decodeURIComponent(data.content);
+ }
+ if(data.type==0||data.type==1||data.type==2||data.type==3||data.type==4||data.type==5||data.type==6){
+ var ifexist=0,chatinfo=null;
+ that.grouplist.forEach((cell,index)=>{
+ if(cell.fromuser==data.sendId&&cell.userid==data.recvId&&cell.sort=="privatechat"){
+ ifexist=1;
+ that.grouplist[index].sl=(that.grouplist[index].sl?that.grouplist[index].sl+1:1);
+ that.grouplist[index].content=data.content;
+ that.grouplist[index].datetime=data.sendTime;
+ that.grouplist[index].type=data.type;
+ that.$forceUpdate();
+ chatinfo= JSON.parse(JSON.stringify(that.grouplist[index])) ;
+ console.log(chatinfo)
}
+ });
+ if(ifexist==0){
+ // 未保存缓存
+ // 接收到socket后更新聊天列表记录
+ var chatlastinfo={
+ id: "privatechat-" + data.recvId +"-" + data.sendId,
+ content: data.content,
+ minId: data.id,
+ sl:1,
+ datetime: data.sendTime,
+ type: data.type,
+ name: "",
+ userid: data.recvId,
+ fromuser: data.sendId,
+ img: "",
+ sort:"privatechat"
+ };
+ that.updateChatList(chatlastinfo);
}
else{
- // 10, "撤回" 11, "已读 " 12, "消息已读回执 " 30,"加载中标记"
+ that.updateChatList(chatinfo);
}
}
+ else{
+ // 10, "撤回" 11, "已读 " 12, "消息已读回执 " 30,"加载中标记"
+
+ }
}
}
- else if(rs.cmd==4){
- // 群聊
- if(rs.data){
- var data=rs.data;
- if(data.atUserIds&&data.atUserIds.includes(that.userid)){
- // 是这个用户的接收的群聊信息
- // 加入聊天记录
- // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
- if(data.type==0){
- data.content=decodeURIComponent(data.content);
- }
- if(data.type==0||data.type==1||data.type==2||data.type==3||data.type==4||data.type==5||data.type==6){
- var ifexist=0,idx=null;
- that.grouplist.forEach((cell,index)=>{
- if(cell.groupId==data.groupId&&cell.sort=="groupchat"){
- ifexist=1;
- idx=index;
- that.grouplist[index].sl=(that.grouplist[index].sl?that.grouplist[index].sl+1:1);
- that.grouplist[index].content=data.content;
- that.grouplist[index].datetime=data.sendTime;
- that.grouplist[index].fromuser=data.sendId;
- that.grouplist[index].type=data.type;
- that.$forceUpdate();
- }
- });
-
- if(ifexist==0){
- // 未保存缓存
- // 接收到socket后更新聊天列表记录
- var chatlastinfo={
- id: "groupchat-" + data.groupId,
- groupId:data.groupId,
- content: data.content,
- minId: data.id,
- sl:1,
- datetime: data.sendTime,
- type: data.type,
- name: "",
- userid: this.userid,
- fromuser: data.sendId,
- img: "",
- sendId: data.sendId,
- sendNickName: data.sendNickName,
- sort:"groupchat"
- };
- that.getGroupInfo(chatlastinfo,ifexist);
- }
- else{
- that.getGroupInfo(that.grouplist[idx],ifexist);
+ }
+ else if(rs.cmd==4){
+ // 群聊
+ if(rs.data){
+ var data=rs.data;
+ if(data.atUserIds&&data.atUserIds.includes(that.userid)){
+ // 是这个用户的接收的群聊信息
+ // 加入聊天记录
+ // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
+ if(data.type==0){
+ data.content=decodeURIComponent(data.content);
+ }
+ if(data.type==0||data.type==1||data.type==2||data.type==3||data.type==4||data.type==5||data.type==6){
+ var ifexist=0,idx=null;
+ that.grouplist.forEach((cell,index)=>{
+ if(cell.groupId==data.groupId&&cell.sort=="groupchat"){
+ ifexist=1;
+ idx=index;
+ that.grouplist[index].sl=(that.grouplist[index].sl?that.grouplist[index].sl+1:1);
+ that.grouplist[index].content=data.content;
+ that.grouplist[index].datetime=data.sendTime;
+ that.grouplist[index].fromuser=data.sendId;
+ that.grouplist[index].type=data.type;
+ that.$forceUpdate();
}
+ });
+
+ if(ifexist==0){
+ // 未保存缓存
+ // 接收到socket后更新聊天列表记录
+ var chatlastinfo={
+ id: "groupchat-" + data.groupId,
+ groupId:data.groupId,
+ content: data.content,
+ minId: data.id,
+ sl:1,
+ datetime: data.sendTime,
+ type: data.type,
+ name: "",
+ userid: this.userid,
+ fromuser: data.sendId,
+ img: "",
+ sendId: data.sendId,
+ sendNickName: data.sendNickName,
+ sort:"groupchat"
+ };
+ that.getGroupInfo(chatlastinfo);
}
else{
- // 10, "撤回" 11, "已读 " 12, "消息已读回执 " 30,"加载中标记"
+ that.getGroupInfo(that.grouplist[idx]);
}
}
+ else{
+ // 10, "撤回" 11, "已读 " 12, "消息已读回执 " 30,"加载中标记"
+
+ }
}
}
}
- });
-
- uni.onSocketClose(res => {
- console.log('WebSocket连接已关闭!',res);
- that.isConnected = false;
- that.$forceUpdate();
- clearInterval(that.heartbeatInterval); // 停止心跳包发送
- });
-
- uni.onSocketError(err => {
- console.error('WebSocket连接打开失败,请检查:', err);
- that.isConnected = false;
- that.$forceUpdate();
- clearInterval(that.heartbeatInterval); // 停止心跳包发送
- });
- // }
+ }
+ });
+
+ uni.onSocketClose(res => {
+ console.log('WebSocket连接已关闭!',res);
+ that.isConnected = false;
+ that.$forceUpdate();
+ clearInterval(that.heartbeatInterval); // 停止心跳包发送
+ });
+
+ uni.onSocketError(err => {
+ console.error('WebSocket连接打开失败,请检查:', err);
+ that.isConnected = false;
+ that.$forceUpdate();
+ clearInterval(that.heartbeatInterval); // 停止心跳包发送
+ });
},
// 关闭WebSocket连接
closeWebSocket() {
@@ -368,6 +393,16 @@
this.isConnected = false;
this.$forceUpdate()
},
+ // 消息是否存在列表中
+ ifadd(id){
+ var ret=0;
+ this.grouplist.forEach((cell,ii)=>{
+ if(cell.id==id){
+ ret=ii+1;
+ }
+ });
+ return ret;
+ },
gotoContacts(){
uni.navigateTo({
url: `/pages/message/contact`
@@ -440,21 +475,10 @@
// 获取群聊列表
async getgroupsmembers(){
// 获取聊天群列表
- this.grouplist=[];
- var chatlist=myCache("chatlist-"+this.userid)?myCache("chatlist-"+this.userid):[];
- chatlist.forEach(cell=>{
- if(cell.userid==this.userid){
- this.grouplist.push(cell);
- }
- });
- this.grouplist.forEach((cell,i)=>{
- if(cell.minId){
- // 通过某个会话中已读消息的最大id 获取离线消息
- this.readUp(i,cell);
- }
- });
+ this.grouplist=myCache("chatlist-"+this.userid)?myCache("chatlist-"+this.userid):[];
this.loadStatus="nomore";
this.$forceUpdate();
+ // 按照时间排序
var that=this;
setTimeout(() => {
that.reorder();
@@ -469,68 +493,148 @@
this.grouplist.sort((a, b) => b.datetime - a.datetime);
this.$forceUpdate();
},
- // 已读推送
- async readUp(i,item) {
+ // 拉取离线信息
+ async pullMessage(i,item) {
if(item.sort=="groupchat"){
- const {data: res} = await uni.$http.put('/api/message/group/readed?groupId='+item.groupId);
this.getgroupsnums(i,item);
}
else{
- const {data: res} = await uni.$http.put('/api/message/private/readed?friendId='+item.fromuser);
this.getgroupsnums(i,item);
}
},
+ // 拉取离线消息
+ async getGroupList(item) {
+ // 判断当前 minId 是不是列表中已经存在了,是不再拉取,不是继续拉取
+ var that=this;
+ const {data: res} = await uni.$http.get('/api/message/group/pullOfflineMessage',{minId: item.minId});
+ if(res.data&&res.data.length>0){
+ res.data.forEach((cell,index)=>{
+ // 获取消息后对消息进行缓存处理
+ var chatlastinfo={
+ id: "groupchat-" + cell.groupId,
+ groupId:cell.groupId,
+ content: cell.content,
+ minId: cell.id,
+ sl: index+1,
+ datetime: cell.sendTime,
+ type: cell.type,
+ name: "",
+ userid: this.userid,
+ fromuser: cell.sendId,
+ img: "",
+ sendId: cell.sendId,
+ sendNickName: cell.sendNickName,
+ sort:"groupchat"
+ };
+ this.getGroupInfo(chatlastinfo,index);
+ });
+ }
+ },
+ // 拉取离线消息
+ async getList(item) {
+ // 判断当前 minId 是不是列表中已经存在了,是不再拉取,不是继续拉取
+ var that=this;
+ const {data: res} = await uni.$http.get('/api/message/private/pullOfflineMessage',{minId: item.minId});
+ if(res.data&&res.data.length>0){
+ res.data.forEach((cell,index)=>{
+ // 获取消息后对消息进行缓存处理
+ var chatlastinfo={
+ id: "privatechat-" + cell.recvId +"-" + cell.sendId,
+ content: cell.content,
+ minId: cell.id,
+ sl:index+1,
+ datetime: cell.sendTime,
+ type: cell.type,
+ name: "",
+ userid: cell.recvId,
+ fromuser: cell.sendId,
+ img: "",
+ sort:"privatechat"
+ };
+ this.updateChatList(chatlastinfo,index);
+ });
+ }
+ },
+ ifprivateMsgMaxId(item){
+ var ret=true;
+ // 判断当前 minId 是不是列表中已经存在了,是不再拉取,不是继续拉取
+ var data= myCache("privateMsgMaxId")?myCache("privateMsgMaxId"):[];
+ data.forEach((cell)=>{
+ if(cell.id==item.id&&parseInt(item.minId)>=parseInt(cell.minId)){
+ ret=false;
+ }
+ });
+ return ret;
+ },
+ ifgroupMsgMaxId(item){
+ console.log("ifgroupMsgMaxId")
+ var ret=true;
+ // 判断当前 minId 是不是列表中已经存在了,是不再拉取,不是继续拉取
+ var data= myCache("groupMsgMaxId")?myCache("groupMsgMaxId"):[];
+ data.forEach((cell)=>{
+ if(cell.id==item.id&&parseInt(item.minId)>=parseInt(cell.minId)){
+ ret=false;
+ }
+ });
+ return ret;
+ },
// 获取群聊中离线信息
async getgroupsnums(i,item){
if(item.sort=="groupchat"){
- // 群聊
- const {data: res} = await uni.$http.get("/api/message/group/pullOfflineMessage",{minId:item.minId});
- if(res.data&&res.data.length>0){
- // 获取消息后对消息进行缓存处理
- var data=res.data;
- // 获取离线消息数量返回
- this.grouplist[i]["sl"]=res.data.length;
- var last=res.data[res.data.length-1];
- if(last.type==0){
- last.content=decodeURIComponent(last.content);
- }
- if(last.type==0||last.type==1||last.type==2||last.type==3||last.type==4||data.type==5||data.type==6){
- this.grouplist[i].content=last.content;
- this.grouplist[i].type=last.type;
- this.grouplist[i].datetime=last.datetime;
- this.$forceUpdate();
- // 重新排序
- this.reorder();
- myCache("chatlist-"+this.userid,this.grouplist);
+ // 判断当前 minId 是不是列表中已经存在了,是不再拉取,不是继续拉取
+ // if(this.ifgroupMsgMaxId(item)){
+ // 群聊
+ const {data: res} = await uni.$http.get("/api/message/group/pullOfflineMessage",{minId:item.minId});
+ if(res.data&&res.data.length>0){
+ // 获取消息后对消息进行缓存处理
+ var data=res.data;
+ // 获取离线消息数量返回
+ this.grouplist[i]["sl"]=res.data.length;
+ var last=res.data[res.data.length-1];
+ if(last.type==0){
+ last.content=decodeURIComponent(last.content);
+ }
+ if(last.type==0||last.type==1||last.type==2||last.type==3||last.type==4||data.type==5||data.type==6){
+ this.grouplist[i].content=last.content;
+ this.grouplist[i].type=last.type;
+ this.grouplist[i].datetime=last.datetime;
+ this.$forceUpdate();
+ // 重新排序
+ this.reorder();
+ myCache("chatlist-"+this.userid,this.grouplist);
+ }
}
- }
+ // }
}
else{
- // 私聊
- const {data: res} = await uni.$http.get("/api/message/private/pullOfflineMessage",{minId:item.minId});
- if(res.data&&res.data.length>0){
- // 获取消息后对消息进行缓存处理
- var data=res.data;
- // 获取离线消息数量返回
- this.grouplist[i]["sl"]=res.data.length;
- var last=res.data[res.data.length-1];
- if(last.type==0){
- last.content=decodeURIComponent(last.content);
- }
- if(last.type==0||last.type==1||last.type==2||last.type==3||last.type==4||data.type==5||data.type==6){
- this.grouplist[i].content=last.content;
- this.grouplist[i].type=last.type;
- this.grouplist[i].datetime=last.datetime;
- this.$forceUpdate();
- // 重新排序
- this.reorder();
- myCache("chatlist-"+this.userid,this.grouplist);
+ // 判断当前 minId 是不是列表中已经存在了,是不再拉取,不是继续拉取
+ // if(this.ifprivateMsgMaxId(item)){
+ // 私聊
+ const {data: res} = await uni.$http.get("/api/message/private/pullOfflineMessage",{minId:item.minId});
+ if(res.data&&res.data.length>0){
+ // 获取消息后对消息进行缓存处理
+ var data=res.data;
+ // 获取离线消息数量返回
+ this.grouplist[i]["sl"]=res.data.length;
+ var last=res.data[res.data.length-1];
+ if(last.type==0){
+ last.content=decodeURIComponent(last.content);
+ }
+ if(last.type==0||last.type==1||last.type==2||last.type==3||last.type==4||data.type==5||data.type==6){
+ this.grouplist[i].content=last.content;
+ this.grouplist[i].type=last.type;
+ this.grouplist[i].datetime=last.datetime;
+ this.$forceUpdate();
+ // 重新排序
+ this.reorder();
+ myCache("chatlist-"+this.userid,this.grouplist);
+ }
}
- }
+ // }
}
},
// 获取群信息
- async getGroupInfo(info,ifexist) {
+ async getGroupInfo(info) {
const {data: res} = await uni.$http.get('/api/group/find/'+info.groupId);
if(res.data){
var data = res.data;
@@ -545,26 +649,34 @@
info.instructor=data.instructor;
info.productId=data.productId;
info.productName=data.productName;
- this.updateChatGroupList(info,ifexist);
+ this.updateChatGroupList(info);
}
},
- async updateChatGroupList(info,ifexist){
+ async updateChatGroupList(info){
var name=info.name,img=info.img||require("@/static/image/girl.png");
const {data: res} = await uni.$http.get("/api/friend/find/"+info.sendId);
if(res.data){
var data=res.data;
name=data.nickName?data.nickName:"匿名";
img=data.headImage?data.headImage:require("@/static/image/girl.png");
- if(ifexist==0){
+ var idx=this.ifadd(info.id);
+ if(!idx){
this.grouplist.push(info);
this.$forceUpdate();
}
+ else{
+ this.grouplist[idx-1].content=info.content;
+ this.grouplist[idx-1].datetime=info.datetime;
+ this.grouplist[idx-1].fromuser=info.fromuser;
+ this.grouplist[idx-1].type=info.type;
+ this.$forceUpdate();
+ }
// 重新排序 保存缓存
this.reorder();
myCache("chatlist-"+this.userid,this.grouplist);
// 聊天框消息缓存
var msgchat=myCache(info.id);
- if(ifexist==0||!msgchat){
+ if(!msgchat){
// 第一条聊天记录保存缓存
let firstmsg = [{
"fromname": name, // 发送人
@@ -610,15 +722,23 @@
else{
name="匿名";
img="../../static/image/girl.png";
- if(ifexist==0){
+ var idx=this.ifadd(info.id);
+ if(!idx){
this.grouplist.push(info);
this.$forceUpdate();
}
+ else{
+ this.grouplist[idx-1].content=info.content;
+ this.grouplist[idx-1].datetime=info.datetime;
+ this.grouplist[idx-1].fromuser=info.fromuser;
+ this.grouplist[idx-1].type=info.type;
+ this.$forceUpdate();
+ }
// 重新排序
this.reorder();
myCache("chatlist-"+this.userid,this.grouplist);
var msgchat=myCache(info.id);
- if(ifexist==0||!msgchat){
+ if(!msgchat){
// 第一条聊天记录保存缓存
let firstmsg = [{
"fromname": name, // 发送人
@@ -661,22 +781,31 @@
}
}
},
- async updateChatList(info,ifexist){
+ async updateChatList(info){
const {data: res} = await uni.$http.get("/api/friend/find/"+info.fromuser);
if(res.data){
var data=res.data;
info.name=data.nickName?data.nickName:"匿名";
info.img=data.headImage?data.headImage:require("@/static/image/girl.png");
- if(ifexist==0){
+ var idx=this.ifadd(info.id);
+ if(!idx){
this.grouplist.push(info);
this.$forceUpdate();
}
+ else{
+ // this.grouplist[idx-1].sl=(this.grouplist[idx-1].sl?this.grouplist[idx-1].sl+1:1);
+ this.grouplist[idx-1].content=info.content;
+ this.grouplist[idx-1].datetime=info.datetime;
+ this.grouplist[idx-1].fromuser=info.fromuser;
+ this.grouplist[idx-1].type=info.type;
+ this.$forceUpdate();
+ }
// 重新排序 保存缓存
this.reorder();
myCache("chatlist-"+this.userid,this.grouplist);
// 聊天框消息缓存
var msgchat=myCache(info.id);
- if(ifexist==0||!msgchat){
+ if(!msgchat){
// 第一条聊天记录保存缓存
let firstmsg = [{
"fromname": info.name, // 发送人
@@ -723,15 +852,26 @@
else{
info.name="匿名";
info.img="../../static/image/girl.png";
- if(ifexist==0){
+ var idx=this.ifadd(info.id);
+ if(!idx){
this.grouplist.push(info);
this.$forceUpdate();
}
+ else{
+ // this.grouplist[idx-1].sl=(this.grouplist[idx-1].sl?this.grouplist[idx-1].sl+1:1);
+ this.grouplist[idx-1].content=info.content;
+ this.grouplist[idx-1].datetime=info.datetime;
+ this.grouplist[idx-1].fromuser=info.fromuser;
+ this.grouplist[idx-1].type=info.type;
+ this.$forceUpdate();
+ }
// 重新排序
this.reorder();
myCache("chatlist-"+this.userid,this.grouplist);
+
var msgchat=myCache(info.id);
- if(ifexist==0||!msgchat){
+ console.log(info.id,msgchat);
+ if(!msgchat){
// 第一条聊天记录保存缓存
let firstmsg = [{
"fromname": info.name, // 发送人
@@ -880,6 +1020,7 @@
background: #fff;
margin: 0;
width: 100%;
+ min-width: 600rpx;
.lcon{
border-bottom: 1rpx solid #eee;
padding-top: 20rpx;
@@ -939,6 +1080,12 @@
font-family: PingFang SC, PingFang SC;
font-weight: 400;
color: #595959;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ /* 假设你的行高是20px,并且你想要两行显示 */
+ line-height: 40rpx; /* 每行的行高 */
+ max-height: 40rpx;
}
.lnum{
background-color: #de0000;
diff --git a/pages/user/user.vue b/pages/user/user.vue
index 0f531b9..f6fda12 100644
--- a/pages/user/user.vue
+++ b/pages/user/user.vue
@@ -360,11 +360,6 @@
uni.stopPullDownRefresh()
},500);
},
- // onTabItemTap(){
- // console.log('界面关闭socket,onTabItemTap');
- // // 在组件销毁前,确保关闭 WebSocket 连接
- // uni.closeSocket();
- // },
methods: {
ifview(value){
// 描述:角色ID;顾问:103 ;教练:104 ;店长:105 ;普通用户:107;
diff --git a/static/icon/voice.png b/static/icon/voice.png
index b703979978bc0da4e5af80a02d5db16b2938c56a..b865874f0bf97851669744b89f5fe024918640f4 100644
GIT binary patch
delta 1704
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
LNkvXXu0mjfbbTLS
literal 0
HcmV?d00001