|
@@ -1,43 +1,56 @@
|
|
|
<template>
|
|
<template>
|
|
|
<view class="page">
|
|
<view class="page">
|
|
|
<view class="flex_c pages" @touchmove="touchmove">
|
|
<view class="flex_c pages" @touchmove="touchmove">
|
|
|
- <scroll-view class="scroll-view flex1" scroll-y scroll-with-animation :scroll-top="top" scroll-with-animation @scroll="scroll" @scrolltoupper="scrolltoupper" @scrolltolower="scrolltolower">
|
|
|
|
|
- <view style="padding: 30rpx 30rpx">
|
|
|
|
|
- <block v-for="(item,index) in list" :key="index">
|
|
|
|
|
|
|
+ <scroll-view class="scroll-view flex1" scroll-y scroll-with-animation :scroll-top="top" scroll-with-animation @scroll="scroll" @scrolltoupper="scrolltoupper" @scrolltolower="scrolltolower" upper-threshold="80" :scroll-into-view="scrollIntoViewId">
|
|
|
|
|
+ <view class="scroll-view-msg" style="padding: 30rpx 30rpx;">
|
|
|
|
|
+ <template v-for="(item, index) in list">
|
|
|
|
|
+ <view class="msgContent" :id="'msg-' + item.messageId">
|
|
|
<view class="text_26 color__ time">
|
|
<view class="text_26 color__ time">
|
|
|
{{ renderMessageDate(item, index) }}
|
|
{{ renderMessageDate(item, index) }}
|
|
|
</view>
|
|
</view>
|
|
|
<view class="message" :class="[item.userType]">
|
|
<view class="message" :class="[item.userType]">
|
|
|
<image :src="item.avatar" v-if="item.userType === 'friend'" class="avatar" mode="widthFix"></image>
|
|
<image :src="item.avatar" v-if="item.userType === 'friend'" class="avatar" mode="widthFix"></image>
|
|
|
- <view class="content" v-if="item.messageType === 'image'">
|
|
|
|
|
- <image :src="item.content" mode="widthFix"></image>
|
|
|
|
|
- </view>
|
|
|
|
|
- <view class="content" v-else>
|
|
|
|
|
|
|
+ <view class="content">
|
|
|
<view class="" v-if="item.msgType == 'quick'">
|
|
<view class="" v-if="item.msgType == 'quick'">
|
|
|
<view class="quickCon">{{item.content}}</view>
|
|
<view class="quickCon">{{item.content}}</view>
|
|
|
<view class="quickList" v-if="item.list.length > 0">
|
|
<view class="quickList" v-if="item.list.length > 0">
|
|
|
- <view class="list-items" v-for="(qItem,indx) in item.list" @click="quickQs(qItem)">{{qItem.question}}</view>
|
|
|
|
|
|
|
+ <view class="list-items" v-for="(qItem,indx) in item.list" @click="quickQs(qItem)">
|
|
|
|
|
+ {{qItem.question}}
|
|
|
|
|
+ </view>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
- <view class="m-address" v-else-if="item.msgType == 'address'">
|
|
|
|
|
- {{item.content}}
|
|
|
|
|
|
|
+ <view class="m-address" v-if="item.msgType == 'address'">
|
|
|
|
|
+ <view class="image"><image :src="item.content.img" mode="widthFix"></image></view>
|
|
|
|
|
+ <view class="infos">
|
|
|
|
|
+ <view class="title">{{item.content.name}}</view>
|
|
|
|
|
+ <view class="desc">{{item.content.order?item.content.order:'-'}}</view>
|
|
|
|
|
+ </view>
|
|
|
</view>
|
|
</view>
|
|
|
- <view class="m-order" v-else-if="item.msgType == 'order'">
|
|
|
|
|
- {{item.content}}
|
|
|
|
|
|
|
+ <view class="m-address" v-if="item.msgType == 'order'">
|
|
|
|
|
+ <view class="image"><image :src="item.content.img" mode="widthFix"></image></view>
|
|
|
|
|
+ <view class="infos">
|
|
|
|
|
+ <view class="title">{{item.content.name}}</view>
|
|
|
|
|
+ <view class="desc">{{item.content.order?item.content.order:'-'}}</view>
|
|
|
|
|
+ </view>
|
|
|
</view>
|
|
</view>
|
|
|
- <view class="m-image" v-else-if="item.msgType == 'image'">
|
|
|
|
|
- {{item.content}}
|
|
|
|
|
|
|
+ <view class="m-image" v-if="item.msgType == 'image'">
|
|
|
|
|
+ <image :src="item.content" mode="widthFix" @click="previewImg(item.content)"></image>
|
|
|
</view>
|
|
</view>
|
|
|
- <view class="m-payment" v-else-if="item.msgType == 'pay'">
|
|
|
|
|
- {{item.content}}
|
|
|
|
|
|
|
+ <view class="m-address" v-if="item.msgType == 'pay'">
|
|
|
|
|
+ <view class="image"><image :src="item.content.img" mode="widthFix"></image></view>
|
|
|
|
|
+ <view class="infos">
|
|
|
|
|
+ <view class="title">{{item.content.name}}</view>
|
|
|
|
|
+ <view class="price">¥ {{item.content.price?item.content.price:'-'}}</view>
|
|
|
|
|
+ </view>
|
|
|
</view>
|
|
</view>
|
|
|
- <view v-else>
|
|
|
|
|
|
|
+ <view v-if="item.msgType == 'text'">
|
|
|
<view v-html="renderTextMessage(item.content)"></view>
|
|
<view v-html="renderTextMessage(item.content)"></view>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
<image :src="item.avatar" v-if="item.userType === 'self'" class="avatar" mode="widthFix"></image>
|
|
<image :src="item.avatar" v-if="item.userType === 'self'" class="avatar" mode="widthFix"></image>
|
|
|
</view>
|
|
</view>
|
|
|
- </block>
|
|
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </template>
|
|
|
</view>
|
|
</view>
|
|
|
</scroll-view>
|
|
</scroll-view>
|
|
|
<view class="tool">
|
|
<view class="tool">
|
|
@@ -93,7 +106,7 @@ export default {
|
|
|
list: [],
|
|
list: [],
|
|
|
allLoaded:false,
|
|
allLoaded:false,
|
|
|
msgPage:2,
|
|
msgPage:2,
|
|
|
- top: 0,
|
|
|
|
|
|
|
+ top: 0, // 绑定给 scroll-view 的滚动位置
|
|
|
isEmoji:false,
|
|
isEmoji:false,
|
|
|
isMore:false,
|
|
isMore:false,
|
|
|
keyboardHeight:0,
|
|
keyboardHeight:0,
|
|
@@ -103,14 +116,17 @@ export default {
|
|
|
_friendAvatar:"",
|
|
_friendAvatar:"",
|
|
|
_selfAvatar:"",
|
|
_selfAvatar:"",
|
|
|
isKeyboard:false,
|
|
isKeyboard:false,
|
|
|
- screenWidth:0
|
|
|
|
|
|
|
+ screenWidth:0,
|
|
|
|
|
+ currentTop: 0,
|
|
|
|
|
+ anchorOffset: 0, // 锚点相对于容器的偏移
|
|
|
|
|
+ scrollIntoViewId:""
|
|
|
};
|
|
};
|
|
|
},
|
|
},
|
|
|
computed: mapState({
|
|
computed: mapState({
|
|
|
//显示时间
|
|
//显示时间
|
|
|
renderMessageDate() {
|
|
renderMessageDate() {
|
|
|
return (message, index) => {
|
|
return (message, index) => {
|
|
|
- if (message.timestamp - this.list[index + 1]?.timestamp > 3 * 60 * 1000) {
|
|
|
|
|
|
|
+ if (this.list[index + 1]?.timestamp - message.timestamp > 3 * 60 * 1000) {
|
|
|
return formatDate(message.timestamp, 'timestamp');
|
|
return formatDate(message.timestamp, 'timestamp');
|
|
|
}
|
|
}
|
|
|
return '';
|
|
return '';
|
|
@@ -132,18 +148,32 @@ export default {
|
|
|
this.pushObj.disconnect()
|
|
this.pushObj.disconnect()
|
|
|
},
|
|
},
|
|
|
methods: {
|
|
methods: {
|
|
|
- scroll(){},
|
|
|
|
|
|
|
+ anchorScroll(id) {
|
|
|
|
|
+ // 直接赋值已声明变量,无需$set
|
|
|
|
|
+ this.scrollIntoViewId = 'msg-' + id
|
|
|
|
|
+ },
|
|
|
|
|
+ scroll(e){
|
|
|
|
|
+ if (!this.allLoaded) {
|
|
|
|
|
+ this.currentTop = e.detail.scrollTop
|
|
|
|
|
+ };
|
|
|
|
|
+ },
|
|
|
// 滚动到底部
|
|
// 滚动到底部
|
|
|
scrolltolower() {
|
|
scrolltolower() {
|
|
|
// if (this.history.allLoaded) return;
|
|
// if (this.history.allLoaded) return;
|
|
|
// console.log('触底')
|
|
// console.log('触底')
|
|
|
// this.getMoreMsg()
|
|
// this.getMoreMsg()
|
|
|
// this.loadHistoryMessage();
|
|
// this.loadHistoryMessage();
|
|
|
|
|
+ },
|
|
|
|
|
+ previewImg(url){
|
|
|
|
|
+ uni.previewImage({
|
|
|
|
|
+ urls:[url],
|
|
|
|
|
+ success() {},
|
|
|
|
|
+ fail() {}
|
|
|
|
|
+ })
|
|
|
},
|
|
},
|
|
|
// 滚动到顶部
|
|
// 滚动到顶部
|
|
|
scrolltoupper() {
|
|
scrolltoupper() {
|
|
|
- if (this.allLoaded) return;
|
|
|
|
|
- console.log('滚动到顶部')
|
|
|
|
|
|
|
+ if (this.allLoaded) return;
|
|
|
this.getMoreMsg()
|
|
this.getMoreMsg()
|
|
|
},
|
|
},
|
|
|
getMoreMsg(){
|
|
getMoreMsg(){
|
|
@@ -152,13 +182,14 @@ export default {
|
|
|
const tokenPoi = uni.getStorageSync("contact");
|
|
const tokenPoi = uni.getStorageSync("contact");
|
|
|
formData.page = this.msgPage;
|
|
formData.page = this.msgPage;
|
|
|
formData.poi = tokenPoi.poi_id;
|
|
formData.poi = tokenPoi.poi_id;
|
|
|
- Api.msg(formData).then((res)=>{
|
|
|
|
|
|
|
+ const anchorMsgId = this.list[0].messageId
|
|
|
|
|
+ Api.msg(formData).then(async (res)=>{
|
|
|
if(res.code == 0) {
|
|
if(res.code == 0) {
|
|
|
return this.$dialog.showSuccess(res.msg)
|
|
return this.$dialog.showSuccess(res.msg)
|
|
|
}
|
|
}
|
|
|
if (res.data.rows.length > 0) {
|
|
if (res.data.rows.length > 0) {
|
|
|
this.msgPage ++;
|
|
this.msgPage ++;
|
|
|
- this.allLoaded = false;
|
|
|
|
|
|
|
+ // this.allLoaded = false;
|
|
|
var msgData = res.data.rows;
|
|
var msgData = res.data.rows;
|
|
|
var pushData = [];
|
|
var pushData = [];
|
|
|
if (msgData.length > 0) {
|
|
if (msgData.length > 0) {
|
|
@@ -167,26 +198,48 @@ export default {
|
|
|
// console.log("pushData",pushData)
|
|
// console.log("pushData",pushData)
|
|
|
// app.list = [...app.list,...pushData]
|
|
// app.list = [...app.list,...pushData]
|
|
|
app.list.unshift(...pushData)
|
|
app.list.unshift(...pushData)
|
|
|
- // this.scrollToBottom()
|
|
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ this.anchorScroll(anchorMsgId)
|
|
|
|
|
+ })
|
|
|
|
|
+ setTimeout(() => this.allLoaded = false, 60)
|
|
|
} else {
|
|
} else {
|
|
|
this.allLoaded = true;
|
|
this.allLoaded = true;
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
},
|
|
},
|
|
|
|
|
+ // 实测新增DOM高度(精准适配动态气泡高度)
|
|
|
|
|
+ calcNewAddHeight(addCount) {
|
|
|
|
|
+ return new Promise(resolve => {
|
|
|
|
|
+ uni.createSelectorQuery()
|
|
|
|
|
+ .in(this)
|
|
|
|
|
+ .selectAll('.scroll-view-msg')
|
|
|
|
|
+ .boundingClientRect(rects => {
|
|
|
|
|
+ // 前面addCount条是本次新增历史消息
|
|
|
|
|
+ const addRects = rects.slice(0, addCount)
|
|
|
|
|
+ const sum = addRects.reduce((p, c) => p + c.height, 0)
|
|
|
|
|
+ resolve(sum)
|
|
|
|
|
+ })
|
|
|
|
|
+ .exec()
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
quickQs(data){
|
|
quickQs(data){
|
|
|
|
|
+ setTimeout(()=>{
|
|
|
|
|
+ console.log('quickQs',data)
|
|
|
|
|
+ },200)
|
|
|
if (!data.answer) return ;
|
|
if (!data.answer) return ;
|
|
|
app.list.push({
|
|
app.list.push({
|
|
|
content: data.answer,
|
|
content: data.answer,
|
|
|
userType: 'self',
|
|
userType: 'self',
|
|
|
avatar: app._selfAvatar,
|
|
avatar: app._selfAvatar,
|
|
|
msgType:"text",
|
|
msgType:"text",
|
|
|
- list:[]
|
|
|
|
|
|
|
+ list:[],
|
|
|
|
|
+ messageId: Date.now(),
|
|
|
|
|
+ timestamp: Date.now(),
|
|
|
})
|
|
})
|
|
|
app.scrollToBottom()
|
|
app.scrollToBottom()
|
|
|
},
|
|
},
|
|
|
renderTextMessage(text) {
|
|
renderTextMessage(text) {
|
|
|
if (!text) return "";
|
|
if (!text) return "";
|
|
|
- console.log("text",text)
|
|
|
|
|
text = text.replace(/\n/g, '');
|
|
text = text.replace(/\n/g, '');
|
|
|
if (!text) return '<span>' + '[未知内容]' + '</span>';
|
|
if (!text) return '<span>' + '[未知内容]' + '</span>';
|
|
|
return '<span>' + decoder.decode(text) + '</span>';
|
|
return '<span>' + decoder.decode(text) + '</span>';
|
|
@@ -211,8 +264,11 @@ export default {
|
|
|
msgType:"quick",
|
|
msgType:"quick",
|
|
|
list:quickData.quick
|
|
list:quickData.quick
|
|
|
})
|
|
})
|
|
|
- console.log("pushData",pushData)
|
|
|
|
|
|
|
+ // app.list.unshift(...pushData)
|
|
|
app.list = [...app.list,...pushData]
|
|
app.list = [...app.list,...pushData]
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ this.anchorScroll(this.list.at(-1).messageId)
|
|
|
|
|
+ })
|
|
|
this.scrollToBottom()
|
|
this.scrollToBottom()
|
|
|
})
|
|
})
|
|
|
},
|
|
},
|
|
@@ -242,9 +298,11 @@ export default {
|
|
|
avatar: item.avatar,
|
|
avatar: item.avatar,
|
|
|
msgType:item.type,
|
|
msgType:item.type,
|
|
|
list:[],
|
|
list:[],
|
|
|
|
|
+ messageId: item.msgId,
|
|
|
timestamp: item.time,
|
|
timestamp: item.time,
|
|
|
};
|
|
};
|
|
|
- return message;
|
|
|
|
|
|
|
+ console.log("message",message)
|
|
|
|
|
+ return message
|
|
|
},
|
|
},
|
|
|
tapMore(){
|
|
tapMore(){
|
|
|
|
|
|
|
@@ -307,23 +365,22 @@ export default {
|
|
|
}, 150)
|
|
}, 150)
|
|
|
},
|
|
},
|
|
|
sendingText() {
|
|
sendingText() {
|
|
|
- if (!this.text) return ;
|
|
|
|
|
- this.list.push({
|
|
|
|
|
- content: this.text,
|
|
|
|
|
- userType: 'self',
|
|
|
|
|
- avatar: this._selfAvatar
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ if (!this.text) return ;
|
|
|
|
|
+ app.sendMessage(this.text,"text");
|
|
|
this.text = ''
|
|
this.text = ''
|
|
|
this.scrollToBottom()
|
|
this.scrollToBottom()
|
|
|
- // 模拟对方回复
|
|
|
|
|
- // setTimeout(()=>{
|
|
|
|
|
- // this.list.push({
|
|
|
|
|
- // content: '周末什么安排',
|
|
|
|
|
- // userType: 'friend',
|
|
|
|
|
- // avatar: this._friendAvatar
|
|
|
|
|
- // })
|
|
|
|
|
- // this.scrollToBottom()
|
|
|
|
|
- // }, 1500)
|
|
|
|
|
|
|
+ },
|
|
|
|
|
+ sendMessage(payload,type){
|
|
|
|
|
+ const message = {
|
|
|
|
|
+ content: payload,
|
|
|
|
|
+ userType: 'self',
|
|
|
|
|
+ avatar: app._selfAvatar,
|
|
|
|
|
+ msgType:type,
|
|
|
|
|
+ list:[],
|
|
|
|
|
+ messageId: Date.now(),
|
|
|
|
|
+ timestamp: Date.now(),
|
|
|
|
|
+ };
|
|
|
|
|
+ app.list.push(message);
|
|
|
},
|
|
},
|
|
|
chooseImage() {
|
|
chooseImage() {
|
|
|
uni.chooseImage({
|
|
uni.chooseImage({
|
|
@@ -355,6 +412,9 @@ export default {
|
|
|
} else {
|
|
} else {
|
|
|
this.top = (this.list.length + parseInt(this.keyboardHeight)) * 1000
|
|
this.top = (this.list.length + parseInt(this.keyboardHeight)) * 1000
|
|
|
}
|
|
}
|
|
|
|
|
+ },
|
|
|
|
|
+ pushList(message){
|
|
|
|
|
+ app.list.push(message);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -370,6 +430,14 @@ export default {
|
|
|
right: 0;
|
|
right: 0;
|
|
|
background-color: #ededed;
|
|
background-color: #ededed;
|
|
|
}
|
|
}
|
|
|
|
|
+.m-image image{width: 200rpx;}
|
|
|
|
|
+.m-address{display: flex;align-items: center;gap: 20rpx;min-width: 70vw;}
|
|
|
|
|
+.self .m-address{transform: rotate(180);}
|
|
|
|
|
+.m-address .image image{width: 120upx;}
|
|
|
|
|
+.m-address .infos{flex: 1;overflow: hidden;}
|
|
|
|
|
+.m-address .infos .title{font-size: 28upx;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}
|
|
|
|
|
+.m-address .infos .desc{font-size: 20upx;color: #999;margin-top: 20rpx;}
|
|
|
|
|
+.m-address .infos .price{font-size: 28upx;color: #f00;margin-top: 20rpx;}
|
|
|
.safe-box{width: 100%;height: env(safe-area-inset-bottom);}
|
|
.safe-box{width: 100%;height: env(safe-area-inset-bottom);}
|
|
|
.scroll-view {
|
|
.scroll-view {
|
|
|
/* #ifdef H5 */
|
|
/* #ifdef H5 */
|
|
@@ -401,7 +469,7 @@ export default {
|
|
|
}
|
|
}
|
|
|
.content {
|
|
.content {
|
|
|
min-height: 80rpx;
|
|
min-height: 80rpx;
|
|
|
- max-width: 60vw;
|
|
|
|
|
|
|
+ max-width: 80vw;
|
|
|
box-sizing: border-box;
|
|
box-sizing: border-box;
|
|
|
font-size: 28rpx;
|
|
font-size: 28rpx;
|
|
|
line-height: 1.3;
|
|
line-height: 1.3;
|
|
@@ -409,7 +477,7 @@ export default {
|
|
|
border-radius: 10rpx;
|
|
border-radius: 10rpx;
|
|
|
background: #fff;
|
|
background: #fff;
|
|
|
image {
|
|
image {
|
|
|
- width: 200rpx;
|
|
|
|
|
|
|
+ // width: 200rpx;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
&.self {
|
|
&.self {
|