app socketTask
<template> <view class="content"> <view class="cul-wrapper"> <block v-for="(item,index) in msgs" :key="index"> <view class="cul-date">{{item.showtime}}</view> <view :id="'msg-'+index" :class="index == msgs.length -1 ? 'active' : ''"> <view :class="item.userId == uId ?'msg-me':'msg-service'"> <view v-if='item.userId != uId' class="" style="width: 72rpx;height: 72rpx; margin-right: 34rpx;border-radius: 50%;"> <image style="width: 100%;height: 100%;border-radius: 50%;" :src="zjimg" mode=""></image> </view> <view class="msg-text" v-if="item.type == 1"> <view class="msg-text-content" @click="linkToSubscribe(item.line)"> <!-- 三角形 --> <view :class="item.userId == uId ? 'triangler' : 'trianglel'"> </view> <!-- <text selectable="true" :class="item.line != 1 ? 'colors' : ''">{{item.chatContent}}</text> --> <template v-if="item.line"> <!-- 预约约课 --> <text selectable="true" class="colors" v-if="zxhsetline(item.line.toString(),'subscribe')">{{item.chatContent}}</text> <!-- 月报信息 --> <text selectable="true" class="colors" v-else-if="zxhsetline(item.line.toString(),'report')">{{item.chatContent}}</text> <!-- 积分充值 --> <text selectable="true" class="colors" v-else-if="zxhsetline(item.line.toString(),'exchange')">{{item.chatContent}}</text> <!-- 缴费信息 --> <text selectable="true" class="colors" v-else-if="zxhsetline(item.line.toString(),'payment')">{{item.chatContent}}</text> <!-- 其他连接加文字 --> <template v-else> <text selectable="true">{{item.chatContent}}</text> <br> <text selectable="true" v-if="item.line !== 1" class="colors">{{item.line}}</text> </template> </template> <template v-else> <text selectable="true">{{item.chatContent}}</text> </template> </view> </view> <view class="msg-img" v-if="item.type == 2"> <image class="img" :src="imgurl+item.chatContent" style="width:100%;height:100%;display: inherit;" :mode="'aspectFill'" @click="clickImg(index,imgurl+item.chatContent)"></image> </view> <view v-if='item.userId == uId' class="" style="width: 72rpx;height: 72rpx; margin-left: 34rpx;border-radius: 50%;"> <image style="width: 100%;height: 100%;border-radius: 50%;" :src="myimg" mode=""></image> </view> </view> </view> </block> </view> <!-- 占位符 ,防止键盘弹出遮挡消息--> <view class="divver" id="msg-00"> </view> <view class="operation"> <input type="text" cursor-spacing="0" @focus="onFocus" @blur="onBlur" v-model="msgInfor" /> <image src="@/static/images/Upload_pictures.png" style="width: 48rpx;height: 48rpx;" @click="upload()" :style="{'margin':msgInfor ? '0 30rpx' : '0 40rpx'}"></image> <image v-show="!msgInfor" src="@/static/images/send.png" style="width: 48rpx;height: 48rpx;"></image> <button v-show="msgInfor" class="btn" type="default" @click="sendMsg">发送</button> </view> <proup :subParams='subParams' ref="subRef"></proup> </view> </template> <script> import { HTTP_IMG_URL, WSS_SERVER_URL } from '@/config.js'; import getTimes from '@/utils/getTime.js'; import util from '@/utils/util.js' import proup from '@/component/proup.vue'; import { getChatRecord, getChatUser, getRemindList, getRemindRead, queryOrder, read, unreadMsgCount } from '@/api/class.js' export default { components: { proup }, data() { return { msgInfor: '', msgs: [], //消息列表 socket: "", // websocket 连接地址 path: WSS_SERVER_URL + `chat/chat?${uni.getStorageSync('token')}`, // "ws://192.168.0.200:8005/qrCodePage/ID=1/refreshTime=5", token: uni.getStorageSync('token'), // 传过来的参数 option2: [], //内部变量 // 助教id aId: '', // 用户id uId: '', // 该条消息创建的时间,用于查询消息记录 cTime: null, // 获取每次最后一条记录的时间,用于查询下一页记录 lastTime: '', chatList: [], imgurl: HTTP_IMG_URL, isShow: false, // 自己头像 myimg: '', // 助教头像 zjimg: '', subParams: {}, subRef: null, timer:'' } }, computed: { }, onShow(options) { // 设置未读消息数量 this.getMessage() this.jumpScroll('#msg-00') //进入这个页面的时候创建websocket连接 this.connectSocket(); }, onHide() { console.log('隐藏') uni.closeSocket(); clearInterval(this.timer); }, onUnload() { console.log('卸载了') uni.closeSocket(); clearInterval(this.timer); }, onLoad(options) { this.option2 = options; //用来关闭 可显示用 if (this.option2) { this.chatList = []; this.uId = this.option2.uid ? this.option2.uid : uni.getStorageSync('userInfo').userId this.initData(this.option2) // 设置未读消息数量 this.getMessage() } }, // 下拉刷新记录 onPullDownRefresh() { this.getChatList(this.lastTime) }, methods: { zxhsetline(url,name){ if(url.indexOf(name) !== -1){ return true }else{ return false } }, //连接websocket connectSocket() { let that = this; this.socketTask = uni.connectSocket({ url: that.path, success(res) { console.log("websocket连接成功"); that.isSuccess = true; clearInterval(this.timer); that.timer = setInterval(() => { that.sendSocketMessage("ping") }, 1500) }, fail(err) { console.log("报错", err); } }, ); this.socketTask.onMessage(function(res) { if (res.data != '发送消息给前端' && res.data != 'ping') { let serverData = res.data ? JSON.parse(res.data) : res.data; //这是字符串,如果要对象记得转换一下 uni.setStorageSync('serverData', serverData) // 接收最新消息 that.msgs = [] that.getChatList(serverData.data) } }); this.socketTask.onError(function(res) { console.log('WebSocket连接打开失败,请检查!'); console.log(res); this.isSuccess = false that.connectSocket() //进入重新连接 that.reconnect(); }) // // 监听连接关闭 - this.socketTask.onClose((e) => { console.log('WebSocket连接关闭!'); }) }, //进入重新连接 reconnect() { console.log('进入断线重连'); this.socketTask.close(); this.socketTask = null; this.connectSocket(); }, //发送消息 sendSocketMessage(msg) { return new Promise((reslove, reject) => { this.socketTask.send({ data: msg, success(res) { reslove(res); }, fail(res) { reject(res); } }); }) }, // ios获取未读总数 getMessage() { unreadMsgCount().then( res => { console.log('========》', res); if (res.code == 200) { // #ifdef APP-PLUS plus.runtime.setBadgeNumber(res.data) //角标设置 // #endif } }) }, //滚动到指定位置 jumpScroll(val) { // console.log(val); setTimeout(function() { uni.pageScrollTo({ duration: 1, selector: val }); }, 100); }, //向后端发送消息 sendMsg() { let that = this if (this.msgInfor == '') { uni.showToast({ title: "不能发送空消息", duration: 2000, icon: 'none', }) return } // 发送消息 var newItem = { chatContent: that.msgInfor, userId: that.uId, createDate: this.formatDate(new Date()), line: 1, type: 1 } let msg = '{"uid":"' + this.aId + '","isKF":"1","msg":"' + that.msgInfor + '","type":"1"}'; uni.sendSocketMessage({ data: msg, success(data) { // console.log('发送成功' + data); that.msgInfor = '' that.chatList.push(newItem); that.msgs = getTimes.checkShowRule(that.chatList, 'createDate'); that.jumpScroll('#msg-' + (that.msgs.length - 1).toString()) }, fail(err) { this.connectSocket(); console.log(err) } }); }, // 获取聊天对象 getUserData() { getChatUser(this.aId).then(res => { if (res.code == 200) { if (res.data.avatar) { this.zjimg = this.imgurl + res.data.avatar; } else { this.zjimg = require('@/static/images/logo.png') } uni.setNavigationBarTitle({ title: res.data ? res.data.name : '' }) } }) }, //获取聊天记录 getChatList(time) { let data = { userId: this.uId, postUserId: Number(this.aId), createDate: time, } getChatRecord(data).then(res => { const that = this if (res.code == 200) { // console.log("获取数据", res.data) // 取最后一条记录的时间 if (res.data.length > 0) { that.lastTime = res.data[res.data.length - 1].createDate } // 判断是否有聊天记录 if (that.msgs.length == 0) { for (let i = res.data.length - 1; i >= 0; i--) { let content = that.httpString(res.data[i].chatContent) if (content) { res.data[i].line = content res.data[i].chatContent = res.data[i].chatContent.replace(content, "") } else { res.data[i].line = 1 } that.chatList.push(res.data[i]) } that.msgs = getTimes.checkShowRule(that.chatList, 'createDate'); that.jumpScroll('#msg-' + (that.msgs.length - 1).toString()) // console.log(that.msgs); } else { this.msgs = [] for (let i = res.data.length - 1; i >= 0; i--) { let content = this.httpString(res.data[i].chatContent) if (content) { res.data[i].line = content res.data[i].chatContent = res.data[i].chatContent.replace(content, "") } else { res.data[i].line = 1 } // 去除重复记录 const index = this.chatList.findIndex(v => v.chatId == res.data[i].chatId) if (index != -1) { res.data.splice(index, 1) } } // 添加到旧记录 res.data.forEach(m => { this.chatList.unshift(m) }) this.msgs = getTimes.checkShowRule(this.chatList, 'createDate'); that.jumpScroll('#msg-' + (res.data.length - 1).toString()) uni.stopPullDownRefresh() } } else { uni.showToast({ title: res.msg, duration: 2000, icon: 'none', }); } }) }, // 数据初始化 initData(options) { // console.log('options',options) this.chatType = options.type; this.activeTitle = options.headline ? options.headline : null; this.cTime = options.cTime ? options.cTime : '' this.aId = options.aid let sex = uni.getStorageSync('userInfo').sex; let avatar = uni.getStorageSync('userInfo').avatar; this.myimg = avatar != '' ? HTTP_IMG_URL + avatar : (sex == 0 ? require( '@/static/images/default_boy.png') : require('@/static/images/default_girl.png')); setTimeout(() => { this.getUserData() // 自动发送消息 // if (this.activeTitle) { // this.autoSendMsg(this.activeTitle) // } }, 100) // 获取聊天记录 this.getChatList(this.cTime); }, // 键盘获取焦点 onFocus(e) { // console.log(e); this.isShow = true if (this.isShow) { // 更新消息位置 this.jumpScroll('#msg-00') } }, onClick(e) { // console.log(e); this.onFocus(e) }, // 键盘失去焦点 onBlur() { this.isShow = false // console.log(this.msgs); // 更新消息位置 this.jumpScroll('#msg-' + (this.msgs.length - 1).toString()) }, // 图片发送 upload() { let that = this; uni.chooseImage({ count: 1, //默认9 sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有 sourceType: ['album'], //从相册选择 success: function(res) { let tempFilePaths = res.tempFilePaths; let token = uni.getStorageSync('token'); uni.uploadFile({ url: HTTP_IMG_URL + '/upload', header: { 'Authorization': token }, filePath: tempFilePaths[0], name: 'file', success: (uploadFileRes) => { // console.log(uploadFileRes) that.chatImg = HTTP_IMG_URL + JSON.parse(uploadFileRes.data).data .url; let imgurl = JSON.parse(uploadFileRes.data).data.url // console.log(that.chatImg) var newItem = { chatContent: imgurl, userId: that.uId, createDate: that.formatDate(new Date()), type: 2, line: imgurl } that.chatList.push(newItem); // console.log('发送后的', that.chatList) that.msgs = getTimes.checkShowRule(that.chatList, 'createDate'); let msg = '{"uid":"' + that.aId + '","isKF":"1","msg":"' + imgurl + '","type":"2"}'; uni.sendSocketMessage({ data: msg, success(data) { console.log('发送成功' + data); that.jumpScroll('#msg-' + (that.msgs.length - 1) .toString()) } }); that.chatImg = null; } }) } }) }, // 图片预览 clickImg(index, url) { const that = this // console.log(that.msgs); uni.previewImage({ urls: [url], // success: function (res) { // that.isPreview = true // } }) }, //页面跳转 linkToSubscribe(url) { // console.log('url',url); if (url == 1) { console.log("没有链接") } else { if (url.indexOf("subscribe") !== -1) { // console.log("预约约课") let courseId = util.getParam(url, 'courseId') let teacharId = util.getParam(url, 'teacharId') // this.subParams = { // courseId: util.getParam(url, 'courseId'), // teacharId: util.getParam(url, 'teacharId'), // aid: this.aId // } // this.$refs.subRef.opens() // 预约约课 uni.navigateTo({ url: `/pages/class/subscribe/index?courseId=${courseId}&teacharId=${teacharId}&aid=${this.aId}` }) } else if (url.indexOf("exchange") !== -1) { // 积分充值 uni.navigateTo({ url: `/pages/my/integral/exchange` }) } else if (url.indexOf("report") !== -1) { const arr = url.split('syt-h5') // 月报信息 uni.navigateTo({ url: arr[1] }) } else if (url.indexOf("payment") !== -1) { // 缴费信息 let orderId = util.getParam(url, 'orderId') let appointmentIds = util.getParam(url, 'appointmentIds') let payWay = util.getParam(url, 'payWay') //判断订单是否有效 queryOrder(appointmentIds).then((res) => { if (res.data > 0) { uni.navigateTo({ url: `/pages/my/myOrder/index` }) } else { uni.navigateTo({ url: `/pages/class/chat/order/classOrder?orderId=${orderId}&appointmentIds=${appointmentIds}&payWay=${payWay}` }) } }) } } }, //截取链接字符串 httpString(str) { var reg = /(https?|http):\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/g; if (str.match(reg)) { return str.match(reg)[0]; } return false; }, // 时间格式化函数 formatDate(now) { var year = now.getFullYear(); var month = now.getMonth() + 1; var date = now.getDate(); var hour = now.getHours(); var minute = now.getMinutes(); var second = now.getSeconds(); return year + "-" + (month = month < 10 ? ("0" + month) : month) + "-" + (date = date < 10 ? ("0" + date) : date) + " " + (hour = hour < 10 ? ("0" + hour) : hour) + ":" + (minute = minute < 10 ? ("0" + minute) : minute) + ":" + (second = second < 10 ? ("0" + second) : second); }, }, } </script> <style lang="scss" scoped> </style> <style> .content { display: flex; flex-direction: column; align-items: center; flex: 1; margin-bottom: 120rpx; } .cul-wrapper { padding: 0 35rpx; box-sizing: border-box; } .divver { /* height: 100rpx; */ padding: 50rpx 0; width: 100%; /* background-color: aqua; */ } .cul-date { padding-top: 20rpx; color: #999999; font-size: 24rpx; text-align: center; } .msg-me, .msg-service { display: flex; align-items: flex-start; width: 680rpx; margin: 30rpx 0; box-sizing: border-box; overflow: hidden; } .msg-me { justify-content: flex-end; } .msg-service { justify-content: flex-start; } .msg-text { width: 560rpx; word-break: break-all; white-space: normal; } .msg-img { width: 260rpx; height: 260rpx; } .msg-me>.msg-text { display: flex; justify-content: flex-end; } .msg-text-content { line-height: 44rpx; display: inline-block; box-sizing: border-box; padding: 14rpx 25rpx; font-size: 28rpx; position: relative; } .trianglel { position: absolute; width: 0px; height: 0px; border: 10px solid transparent; border-bottom-color: #f8f8f8; transform: rotate(270deg); left: -40rpx; } .triangler { position: absolute; width: 0px; height: 0px; border: 10px solid transparent; border-bottom-color: #f0f8ff; right: -40rpx; transform: rotate(90deg); } .colors { color: blue !important; text-decoration: underline; } .active { padding-bottom: 120rpx; } .msg-me>.msg-text>.msg-text-content { background-color: aliceblue; font-size: 30rpx; /* border-top-right-radius: 44rpx; border-bottom-left-radius: 44rpx; border-top-left-radius: 44rpx; */ border-radius: 15rpx; color: #333333; } .msg-service>.msg-text>.msg-text-content { background-color: #F8F8F8; font-size: 30rpx; /* border-bottom-left-radius: 44rpx; border-bottom-right-radius: 44rpx; border-top-right-radius: 44rpx; */ border-radius: 15rpx; color: #333333; } .operation { display: flex; position: fixed; left: 0; bottom: 0; align-items: center; background: #F8F8F8; padding: 10px 35rpx; /* padd0ing-bottom: 20px !important; */ border-top: 1rpx solid rgba(184, 184, 184, 0.1); width: 100vw; } .operation input { width: 480rpx; height: 70rpx; background: #FFFFFF; border-radius: 8rpx; } .btn { width: 116rpx; height: 58rpx; line-height: 58rpx; border-radius: 8rpx; background-color: #FE564B !important; font-size: 28rpx; color: #fff !important; margin: 0; } </style>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下