<template>
<view>
<sc-nav back-color="white" :opacity="1" is-back>
<text slot="content" class="sc-page-title">{{friendName}}</text>
</sc-nav>
<scroll-view :scroll-into-view="scrollViewTo" scroll-y scroll-anchoring @scrolltoupper="scrollToTop" class="bg-white"
style="overflow-anchor: auto;" :style="{height: scrollHeight + 'px'}">
<view class="flex justify-center align-center" style="width: 100%;background-color: aliceblue;padding: 10rpx 0;" v-if="historyLoading">
正在刷新
</view>
<view class="cu-chat bg-white">
<view v-for="(item,index) in messageList" :key="index" :id="`msg-${item.id}`">
<view class="cu-item self" v-if="friendName !== item.senderName">
<view class="main">
<view class="content bg-grey shadow">
<text :class="{'content-min': item.sendContent.length < 2}">{{item.sendContent}}</text>
</view>
</view>
<view class="cu-avatar radius">
<sc-image :src="mySrc" style="width: 100%;height: 100%;"></sc-image>
</view>
<view class="date">{{timeFormat(item.receivingTime)}}</view>
</view>
<view class="cu-item" v-if="friendName === item.senderName">
<view class="cu-avatar radius">
<sc-image :src="friendSrc" style="width: 100%;height: 100%;"></sc-image>
</view>
<view class="main">
<view class="content bg-blue shadow">
<text :class="{'content-min': item.sendContent.length < 2}">{{item.sendContent}}</text>
</view>
</view>
<view class="date">{{timeFormat(item.receivingTime)}}</view>
</view>
</view>
</view>
</scroll-view>
<view class="cu-bar foot input" :style="[{bottom:InputBottom+'px'}]">
<input class="" placeholder="请输入" :class="{'input1':msg.sendContent === ''}" :adjust-position="false" :focus="false" maxlength="300" cursor-spacing="10"
v-model="msg.sendContent"></input>
<button class="cu-btn bg-green shadow animation-slide-top" v-if="msg.sendContent !== ''" @click="sendSocketMessage(msg)">发送</button>
<!-- <image v-else style="width:66rpx;height:66rpx;" src="../../static/images/icon/addPhone@2x.png" mode=""> -->
</image>
</view>
</view>
</template>
<script>
import {
baseUrl
} from '@/config.js'
import {
mapGetters
} from 'vuex'
import {
recordMessage
} from '@/api/application.js'
import WS from '@/utils/websocket.js'
export default {
data() {
return {
baseUrl: baseUrl,
InputBottom: 0,
msg: {
linkType: 'msg',
senderName: '',
senderId: '',
sendContent: '',
recipientId: '',
recipientName: '',
receivingTime: ''
},
messageList: [],
friendName: '',
friendSrc: '',
mySrc: '',
pagination: {
pageSize: 15,
pageNum: 1,
flag: true
},
ws: null,
wsUrl: '',
curDate: '',
scrollViewTo: null,
historyLoading: false,
nomore: false,
screnHeight: 0,
CustomBar: this.CustomBar
};
},
computed: {
...mapGetters(['userInfo']),
timeFormat() {
return function(time) {
if (time.substr(0, 10) === this.curDate) {
return time.substr(11)
}
return time
}
},
scrollHeight() {
return this.screnHeight - this.InputBottom - uni.upx2px(152) - this.CustomBar
}
},
onLoad(page) {
var data = JSON.parse(decodeURIComponent(page.data))
this.friendName = data.name
this.friendSrc = data.avatar
this.mySrc = this.userInfo.avatar
this.initMsg(data)
this.initDate()
this.createWebScoket()
this.restKeyboardHeught()
},
mounted() {
this.$nextTick(() => {
this.loadRecordMessage()
});
let sys = uni.getSystemInfoSync()
this.screnHeight = sys.windowHeight
},
onUnload() {
this.ws.closeSocket()
},
methods: {
restKeyboardHeught(){
uni.onKeyboardHeightChange(res=>{
this.InputBottom = res.height
// 键盘弹起,自动跳转到最新消息
if(res.height > 0 && this.messageList.length) {
this.scrollViewTo = `msg-${this.messageList[this.messageList.length - 1].id}`
}
})
},
initDate() {
this.curDate = this.$time.formatDate(Date.now())
},
// msg初始化
initMsg(data) {
if (data.appMessage !== null) { //从消息记录进入聊天详情
this.msg.recipientId = data.userId
this.msg.recipientName = data.name
if (data.appMessage.senderName === data.name) {
this.msg.senderName = data.appMessage.recipientName
this.msg.senderId = data.appMessage.recipientId
} else {
this.msg.senderName = data.appMessage.senderName
this.msg.senderId = data.appMessage.senderId
}
} else { //从人员列表进入聊天详情
this.msg.senderName = this.userInfo.studentName
this.msg.senderId = this.userInfo.userId.toString()
this.msg.recipientName = data.name
this.msg.recipientId = data.userId
}
},
initWsUrl() {
if (this.baseUrl === 'http://10.148.12.191/sc-api') { //测试
this.wsUrl = 'ws://10.148.12.196:8099/realtimeMessageWebsocket'
} else {
this.wsUrl = this.baseUrl.replace(/http/g, 'ws') + '/realtimeMessageWebsocket'
}
},
// 创建websockt
createWebScoket() {
this.initWsUrl()
this.ws && this.ws.closeSocket()
this.ws = new WS(this.wsUrl)
this.ws.getWebSocketMsg(data => {
// this.pagination.pageNum = 1
this.nomore = false
// this.messageList = []
this.loadRecordMessage(true)
})
},
scrollToTop() {
if(this.historyLoading || this.nomore) return
this.historyLoading = true
this.loadRecordMessage()
},
//获取聊天记录
loadRecordMessage(isAdd = false) {
if (!this.pagination.flag) return
if (this.nomore) return
const requestParams = {
...this.pagination,
userId: this.userInfo.userId,
personId: this.msg.recipientId,
}
if (isAdd) requestParams.pageNum = 1
// this.pagination.flag = false
recordMessage(requestParams).then(rs => {
if (rs.code === 200) {
let data = rs.rows
let selector = '',
scrollToBottom = false
if (this.pagination.pageNum > 1 && !isAdd) {
// 非第一页,则取历史消息数据的第一条信息元素
selector = `msg-${this.messageList[0].id}`
} else {
// 第一页,则取当前消息数据的最后一条信息元素
selector = data.length ? `msg-${data[data.length-1].id}` : ''
}
// 发送,接受消息已有消息比较插入
if (isAdd) {
data.forEach(item => {
let index = this.messageList.findIndex(v => v.id === item.id)
if (index === -1) {
this.messageList.push(item)
}
})
this.$nextTick(() => {
this.scrollViewTo = selector
this.pagination.flag = true
})
} else {
let time = this.pagination.pageNum === 1? 0: 300
setTimeout(() => {
this.messageList = [...data, ...this.messageList]
this.historyLoading = false
this.$nextTick(() => {
this.scrollViewTo = selector
this.pagination.flag = true
if (data.length < this.pagination.pageSize) {
// 当前消息数据条数小于请求要求条数时,则无更多消息,不再允许请求。
this.nomore = true
} else {
this.pagination.pageNum++
}
})
}, time)
}
// this.$nextTick(() => {
// this.scrollViewTo = selector
// this.pagination.flag = true
// if (data.length < this.pagination.pageSize) {
// // 当前消息数据条数小于请求要求条数时,则无更多消息,不再允许请求。
// this.nomore = true
// } else {
// this.pagination.pageNum++
// }
// })
this.pagination.flag = false
}
})
},
//发送消息
sendSocketMessage(msg) {
this.ws.webSocketSendMsg(JSON.stringify(msg), ({
success,
data
}) => {
if (success) {
// this.messageList = []
// this.pagination.pageNum = 1
this.nomore = false
this.loadRecordMessage(true)
this.msg.sendContent = ''
}
})
}
}
}
</script>
<style lang="less" scoped>
page {
// padding-bottom: 100upx;s
}
.cu-chat .cu-item.self>.main .content::after,
.cu-chat .cu-item.self>.main .content::before {
display: none;
}
.cu-chat .cu-item>.main .content::after,
.cu-chat .cu-item>.main .content::before {
display: none;
}
.cu-chat .cu-item>.main {
margin: 0 16rpx;
}
/deep/ .cu-chat .cu-item>.main .content {
border-radius: 30rpx;
word-break: break-all;
}
.cu-chat .cu-item>.cu-avatar {
border-radius: 16rpx;
}
.cu-bar.input {
height: 152rpx;
background: #F1F2F3;
}
.cu-bar.input uni-input {
width: 612rpx;
height: 84rpx;
}
/deep/ .uni-input-input {
width: 238 * 2rpx;
padding: 0 20rpx;
background: #FFFFFF;
border-radius: 20rpx;
}
.uni-input-placeholder {
width: 238 * 2rpx;
z-index: 10;
margin-left: 38rpx;
height: 38rpx;
font-size: 32rpx;
font-family: LXGWWenKai-Bold, LXGWWenKai;
font-weight: bold;
color: rgba(0, 0, 0, 0.45);
line-height: 38rpx;
}
.input1 {
/deep/ .uni-input-input {
width: 309 * 2rpx;
}
}
/deep/ .cu-bar.foot {
box-shadow: none;
}
// .cu-avatar{
// background-image: url(https://ossweb-img.qq.com/images/lol/web201310/skin/big143004.jpg);
// }
// .self{
// .cu-avatar{
// background-image: url(https://ossweb-img.qq.com/images/lol/web201310/skin/big107000.jpg);
// }
// }
// .bg-white {
// // min-height: calc(100vh - 260rpx);
// // height: auto !important;
// // padding-bottom: 20rpx;
// border-top: 2rpx solid rgba(33, 40, 51, 0.06);
// }
.bg-grey {
font-size: 32rpx;
font-family: LXGWWenKai-Bold, LXGWWenKai;
font-weight: bold;
color: #000000;
line-height: 38rpx;
background: #F5F5F5;
border-top-right-radius: 0 !important;
}
.bg-blue {
font-size: 32rpx;
font-family: LXGWWenKai-Bold, LXGWWenKai;
font-weight: bold;
color: #FFFFFF;
line-height: 38rpx;
background: #5A8EEA;
border-top-left-radius: 0 !important;
}
.date {
height: 28rpx;
font-size: 24rpx;
font-family: LXGWWenKai-Bold, LXGWWenKai;
font-weight: bold;
color: rgba(0, 0, 0, 0.25);
line-height: 28rpx;
width: calc(100% - 250upx) !important;
left: 125rpx !important;
letter-spacing: -0.17px;
}
.content-min {
min-width: 40rpx;
text-align: center !important;
}
</style>