Zory 1 miesiąc temu
rodzic
commit
ddec2a96e0
2 zmienionych plików z 118 dodań i 49 usunięć
  1. 2 1
      pages/order/detail.vue
  2. 116 48
      pages/service/msg.vue

+ 2 - 1
pages/order/detail.vue

@@ -319,7 +319,8 @@ export default {
 			const { orderId } = event.detail; 
 			const goodsDetail = [
 				{
-				  itemOrderId:app.orderData.item_order_id //商品单,可在预下单回调itemOrderlist里获取,或通过查询券状态接口获取
+					refundRelatedItemType: 2,
+					itemOrderId:app.orderData.item_order_id //商品单,可在预下单回调itemOrderlist里获取,或通过查询券状态接口获取
 				}
 			];
 			const extra = { orderId , goodsDetail};

+ 116 - 48
pages/service/msg.vue

@@ -1,43 +1,56 @@
 <template>
 	<view class="page">
 		<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">
 							{{ renderMessageDate(item, index) }}
 						</view>
 						<view class="message" :class="[item.userType]">
 							<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="quickCon">{{item.content}}</view>
 									<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 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 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 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 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 v-else>
+								<view v-if="item.msgType == 'text'">
 									<view v-html="renderTextMessage(item.content)"></view>
 								</view>
 							</view>
 							<image :src="item.avatar" v-if="item.userType === 'self'" class="avatar" mode="widthFix"></image>
 						</view>
-					</block>
+					</view>
+					</template>
 				</view>
 			</scroll-view>
 			<view class="tool">
@@ -93,7 +106,7 @@ export default {
 			list: [],
 			allLoaded:false,
 			msgPage:2,
-			top: 0,
+			top: 0, // 绑定给 scroll-view 的滚动位置
 			isEmoji:false,
 			isMore:false,
 			keyboardHeight:0,
@@ -103,14 +116,17 @@ export default {
 			_friendAvatar:"",
 			_selfAvatar:"",
 			isKeyboard:false,
-			screenWidth:0
+			screenWidth:0,
+			currentTop: 0,
+			anchorOffset: 0, // 锚点相对于容器的偏移
+			scrollIntoViewId:""
 		};
 	},
 	computed: mapState({
 		//显示时间
 		renderMessageDate() {
 			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 '';
@@ -132,18 +148,32 @@ export default {
 		this.pushObj.disconnect()
 	},
 	methods: {
-		scroll(){},
+		anchorScroll(id) {
+			// 直接赋值已声明变量,无需$set
+			this.scrollIntoViewId = 'msg-' + id
+		},
+		scroll(e){
+			if (!this.allLoaded) {
+				this.currentTop = e.detail.scrollTop
+			};
+		},
 		// 滚动到底部
 		scrolltolower() {
 			// if (this.history.allLoaded) return;
 			// console.log('触底')
 			// this.getMoreMsg()
 			// this.loadHistoryMessage();
+		},
+		previewImg(url){
+			uni.previewImage({
+				urls:[url],
+				success() {},
+				fail() {}
+			})
 		},
 		// 滚动到顶部
 		scrolltoupper() {
-			if (this.allLoaded) return;
-			console.log('滚动到顶部')
+			if (this.allLoaded) return;
 			this.getMoreMsg()
 		},
 		getMoreMsg(){
@@ -152,13 +182,14 @@ export default {
 			const tokenPoi = uni.getStorageSync("contact");
 			formData.page = this.msgPage;
 			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) {
 					return this.$dialog.showSuccess(res.msg)
 				}
 				if (res.data.rows.length > 0) {
 					this.msgPage ++;
-					this.allLoaded = false;
+					// this.allLoaded = false;
 					var msgData = res.data.rows;
 					var pushData = [];
 					if (msgData.length > 0) {
@@ -167,26 +198,48 @@ export default {
 					// console.log("pushData",pushData)
 					// app.list = [...app.list,...pushData]
 					app.list.unshift(...pushData)
-					// this.scrollToBottom()
+					this.$nextTick(() => {
+						this.anchorScroll(anchorMsgId)
+					})
+					setTimeout(() => this.allLoaded = false, 60)
 				} else {
 					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){
+			setTimeout(()=>{
+				console.log('quickQs',data)
+			},200)
 			if (!data.answer) return ;
 			app.list.push({
 				content: data.answer,
 				userType: 'self',
 				avatar: app._selfAvatar,
 				msgType:"text",
-				list:[]
+				list:[],
+				messageId: Date.now(),
+				timestamp: Date.now(),
 			})
 			app.scrollToBottom()
 		},
 		renderTextMessage(text) {
 			if (!text) return "";
-			console.log("text",text)
 			text = text.replace(/\n/g, '');
 			if (!text) return '<span>' + '[未知内容]' + '</span>';
 			return '<span>' + decoder.decode(text) + '</span>';
@@ -211,8 +264,11 @@ export default {
 					msgType:"quick",
 					list:quickData.quick
 				})
-				console.log("pushData",pushData)
+				// app.list.unshift(...pushData)
 				app.list = [...app.list,...pushData]
+				this.$nextTick(() => {
+					this.anchorScroll(this.list.at(-1).messageId)
+				})
 				this.scrollToBottom()
 			})
 		},
@@ -242,9 +298,11 @@ export default {
 				avatar: item.avatar,
 				msgType:item.type,
 				list:[],
+				messageId: item.msgId,
 				timestamp: item.time,
 			};
-			return message;
+			console.log("message",message)
+			return message
 		},
 		tapMore(){
 			
@@ -307,23 +365,22 @@ export default {
 			}, 150)
 		},
 		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.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() {
 			uni.chooseImage({
@@ -355,6 +412,9 @@ export default {
 			} else {
 				this.top = (this.list.length + parseInt(this.keyboardHeight)) * 1000
 			}
+		},
+		pushList(message){
+			app.list.push(message);
 		}
 	}
 }
@@ -370,6 +430,14 @@ export default {
     right: 0;
     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);}
 .scroll-view {
 	/* #ifdef H5 */
@@ -401,7 +469,7 @@ export default {
 	}
 	.content {
 		min-height: 80rpx;
-		max-width: 60vw;
+		max-width: 80vw;
 		box-sizing: border-box;
 		font-size: 28rpx;
 		line-height: 1.3;
@@ -409,7 +477,7 @@ export default {
 		border-radius: 10rpx;
 		background: #fff;
 		image {
-			width: 200rpx;
+			// width: 200rpx;
 		}
 	}
 	&.self {