1 消息列表
<!-- 底部消息列表 -->
<template>
<view class="chatList">
<view v-if="chatList.length>0">
<u-swipe-action :show="item.show" :index="index" v-for="(item, index) in chatList" :key="item.ChatId"
@click="click(index)" :options="options" @content-click="toChat(item.ChatId)">
<view class="item u-border-bottom">
<view class="left">
<view class="photo">
<image :src="item.HeadIcon?$t.img(item.HeadIcon):image"></u-image>
<u-badge type="error" :offset="[0,0]" :count="item.UnRead"></u-badge>
</view>
<!-- 此层wrap在此为必写的,否则可能会出现标题定位错误 -->
<view class="center">
<!-- <view class="title-wrap">
<text class="title u-line-2">{{ item.userName }}</text>
</view> -->
<view class="title">
{{ item.UserName }}
</view>
<view class="note u-line-1">
{{ item.note||'' }}
</view>
</view>
</view>
<view class="right">
{{changeTime(item.LastChatDate)}}
</view>
</view>
</u-swipe-action>
</view>
<view v-else class="nomore">
<u-image width="620" height="400" mode="scaleToFill" :src="noData" />
<u-loadmore status="nomore" />
</view>
</view>
</template>
<script>
import dateTime from '@/commons/dateTime.js';
export default {
data() {
return {
chatList: [],
options: [{
text: '删除',
style: {
backgroundColor: '#dd524d'
}
}],
disabled: false,
btnWidth: 180,
show: false,
noData: this.$t.imgPath('noData.png'),
image: this.$t.imgPath('man.png'),
}
},
methods: {
getList() {
this.$api.chat.GetChatList({
ChatType: 1
}).then(res => {
this.chatList = res.response
this.chatList.forEach(item => {
item.show = false
})
})
},
changeTime(date) {
return dateTime.dateTime(date);
},
toChat(chatId) {
this.$u.route({
url: '/chatPage/chat',
params: {
chatId
}
})
},
click(index) {
this.$api.chat.DeleteChat({
chatId: this.chatList[index].ChatId
}).then(res => {
const {
success,
response
} = res
if (success) {
this.$u.toast(`已结束对话`);
this.getList()
}
})
},
},
onShow() {
this.getList()
}
}
</script>
<style lang="scss" scoped>
.chatList {
.item {
display: flex;
padding: 20rpx;
justify-content: space-between;
.left {
display: flex;
justify-content: start;
.photo {
margin-right: 10rpx;
position: relative;
image {
width: 100rpx;
flex: 0 0 10rpx;
height: 100rpx;
margin-right: 20rpx;
border-radius: 50rpx;
}
}
.center {
width: 400rpx;
overflow: hidden;
.title {
font-size: 30rpx;
font-weight: 500;
color: #333333;
margin-top: 0;
margin-bottom: 20rpx;
}
.note {
font-size: 24rpx;
color: darkgrey;
}
}
}
.right {
font-size: 24rpx;
color: darkgrey;
}
}
.nomore {
padding-top: 300rpx;
::v-deep .u-image {
margin: 0 auto 30rpx;
}
}
}
</style>
2.聊天页面
<template>
<view class="chat">
<scroll-view :style="{height: `${windowHeight-inputHeight}rpx`}" id="scrollview" scroll-y="true"
:scroll-top="scrollTop" class="scroll-view">
<!-- 聊天主体 -->
<view id="msglistview" class="chat-body">
<!-- 聊天记录 -->
<view v-for="(item,index) in msgList" :key="index">
<!-- 自己发的消息 -->
<view class="chat-time" v-if="item.CreateDate != ''">{{changeTime(item.CreateDate)}}</view>
<view class="item self" v-if="item.MessageType == 2">
<!-- 文字内容 -->
<view class="content right">
{{item.Message}}
</view>
</view>
<!-- 机器人发的消息 -->
<view class="item Ai" v-if="item.MessageType == 1">
<!-- 文字内容 -->
<view class="content left">
{{item.Message}}
</view>
</view>
</view>
</view>
</scroll-view>
<!-- 底部消息发送栏 -->
<!-- 用来占位,防止聊天消息被发送框遮挡 -->
<view class="chat-bottom" :style="{height: `${inputHeight}rpx`}">
<view class="send-msg" :style="{bottom:`${keyboardHeight}rpx`}">
<view class="uni-textarea">
<textarea v-model="chatMsg" maxlength="300" confirm-type="send" @confirm="handleSend"
:show-confirm-bar="false" :adjust-position="false" @linechange="sendHeight" @focus="focus"
@blur="blur" auto-height :hold-keyboard="true"></textarea>
</view>
<button @click="handleSend" class="send-btn">发送</button>
</view>
</view>
</view>
</template>
<script>
import dateTime from '@/commons/dateTime.js';
export default {
data() {
return {
//键盘高度
keyboardHeight: 0,
//底部消息发送高度
bottomHeight: 0,
//滚动距离
scrollTop: 0,
userId: '',
//发送的消息
chatMsg: "",
msgList: [],
autoRefreshId: 1, // 判断自动刷新 1 刷新,0 停止
theTime: '',
unshiftmsg: [],
oldTime: new Date(),
}
},
updated() {
//页面更新时调用聊天消息定位到最底部
this.scrollToBottom();
},
computed: {
windowHeight() {
return this.rpxTopx(uni.getSystemInfoSync().windowHeight)
},
// 键盘弹起来的高度+发送框高度
inputHeight() {
return this.bottomHeight + this.keyboardHeight
}
},
onLoad(data) {
console.log(data);
this.chatId = data.chatId
this.getChatInfo()
uni.onKeyboardHeightChange(res => {
//这里正常来讲代码直接写
//this.keyboardHeight=this.rpxTopx(res.height)就行了
//但是之前界面ui设计聊天框的高度有点高,为了不让键盘和聊天输入框之间距离差太大所以我改动了一下。
this.keyboardHeight = this.rpxTopx(res.height - 30)
if (this.keyboardHeight < 0) this.keyboardHeight = 0;
})
},
onUnload() {
uni.offKeyboardHeightChange()
this.autoRefreshId = 0; // 同时改变autoRefreshId 数值
clearInterval(this.theTime) // 清除指定的定时
clearInterval() // 清除所有
},
onHide() {
this.autoRefreshId = 0; // 同时改变autoRefreshId 数值
clearInterval(this.theTime) // 清除指定的定时
clearInterval() // 清除所有
},
onShow() {
let that = this
if (that.autoRefreshId == 1) {
that.theTime = setInterval(() => {
this.getChatInfo()
}, 5000);
} else {
clearInterval(that.theTime)
}
},
methods: {
getChatInfo() {
this.$api.chat.ChatInfo({
ChatId: this.chatId
}).then(res => {
const {
success,
response
} = res
if (success) {
this.msgList = response.reverse()
// // 数组倒叙 主要是应对后端传过来的数据
// for (var i = 0; i < this.msgList.length; i++) {
// //时间间隔处理
// if (i < this.msgList.length - 1) { //这里表示头部时间还是显示一下
// let t = dateTime.spaceTime(this.oldTime, this.msgList[i].createDate);
// if (t) {
// this.oldTime = t;
// }
// this.msgList[i].createDate = t;
// }
// this.unshiftmsg.unshift(this.msgList[i]);
// }
}
})
},
focus() {
this.scrollToBottom()
},
blur() {
this.scrollToBottom()
},
// px转换成rpx
rpxTopx(px) {
let deviceWidth = wx.getSystemInfoSync().windowWidth
let rpx = (750 / deviceWidth) * Number(px)
return Math.floor(rpx)
},
// 监视聊天发送栏高度
sendHeight() {
setTimeout(() => {
let query = uni.createSelectorQuery();
query.select('.send-msg').boundingClientRect()
query.exec(res => {
this.bottomHeight = this.rpxTopx(res[0].height)
})
}, 10)
},
// 滚动至聊天底部
scrollToBottom(e) {
setTimeout(() => {
let query = uni.createSelectorQuery().in(this);
query.select('#scrollview').boundingClientRect();
query.select('#msglistview').boundingClientRect();
query.exec((res) => {
if (res[1].height > res[0].height) {
this.scrollTop = this.rpxTopx(res[1].height - res[0].height)
}
})
}, 15)
},
// 发送消息
handleSend() {
//如果消息不为空
if (!this.$u.test.isEmpty(this.chatMsg)) {
this.$api.chat.AnswerChat({
chatId: this.chatId,
message: this.chatMsg,
}).then(res => {
if (res.success) {
this.getChatInfo()
this.chatMsg = '';
this.scrollToBottom()
} else {
this.$u.toast('发送失败')
}
})
} else {
this.$u.toast('不能发送空白消息')
}
},
changeTime(date) {
return dateTime.dateTime1(date);
},
}
}
</script>
<style lang="scss" scoped>
view,
button,
text,
input,
textarea {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* 聊天消息 */
.chat {
.scroll-view {
::-webkit-scrollbar {
display: none;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
color: transparent;
}
// background-color: orange;
background-color: #F6F6F6;
.chat-body {
display: flex;
flex-direction: column;
padding-top: 23rpx;
// background-color:skyblue;
.chat-time {
font-size: 24rpx;
color: rgba(39, 40, 50, 0.3);
line-height: 34rpx;
padding: 10rpx 0rpx;
text-align: center;
}
.self {
justify-content: flex-end;
}
.item {
display: flex;
padding: 23rpx 30rpx;
// background-color: greenyellow;
.right {
background-color: #EF7F25;
color: #FFFFFF;
border-radius: 30rpx 30rpx 5rpx 30rpx;
}
.left {
background-color: rgba(239, 127, 37, 0.1);
border: 3rpx solid #EF7F25;
color: #9e9e9e;
border-radius: 30rpx 30rpx 30rpx 5rpx;
}
// // 聊天消息的三角形
// .right::after {
// position: absolute;
// display: inline-block;
// content: '';
// width: 0;
// height: 0;
// left: 100%;
// top: 10px;
// border: 12rpx solid transparent;
// border-left: 12rpx solid #EF7F25;
// }
// .left::after {
// position: absolute;
// display: inline-block;
// content: '';
// width: 0;
// height: 0;
// top: 10px;
// right: 100%;
// border: 12rpx solid transparent;
// border-right: 12rpx solid #FFFFFF;
// }
.content {
position: relative;
max-width: 486rpx;
word-wrap: break-word;
padding: 24rpx 24rpx;
margin: 0 24rpx;
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 500;
line-height: 42rpx;
}
}
}
}
/* 底部聊天发送栏 */
.chat-bottom {
width: 100%;
height: 177rpx;
background: #F4F5F7;
transition: all 0.1s ease;
.send-msg {
display: flex;
align-items: flex-end;
padding: 16rpx 30rpx;
width: 100%;
min-height: 177rpx;
position: fixed;
bottom: 0;
background: #EDEDED;
transition: all 0.1s ease;
}
.uni-textarea {
padding-bottom: 70rpx;
textarea {
width: 537rpx;
min-height: 75rpx;
max-height: 500rpx;
background: #FFFFFF;
border-radius: 8rpx;
font-size: 32rpx;
font-family: PingFang SC;
color: #333333;
line-height: 43rpx;
padding: 5rpx 8rpx;
}
}
.send-btn {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 70rpx;
margin-left: 25rpx;
width: 128rpx;
height: 75rpx;
background: #EF7F25;
border-radius: 30rpx;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 500;
color: #FFFFFF;
line-height: 28rpx;
}
}
}
</style>