فهرست منبع

0810-1531-h01

Zory 1 ماه پیش
والد
کامیت
10a3f129f4

+ 3 - 1
components/bottom-operation/emoji.vue

@@ -186,6 +186,7 @@ export default {
 		padding: 0 20rpx;
 		width: 100%;
 		height: 100rpx;
+		background-color: #fff;
 		.emoji-title-item {
 			width: 80rpx;
 			height: 80rpx;
@@ -199,7 +200,7 @@ export default {
 			}
 		}
 		.emoji_title_item {
-			background-color: #fff;
+			background-color: #f6f6f6;
 		}
 	}
 }
@@ -277,6 +278,7 @@ export default {
 			border-radius: 10rpx;
 			margin-right: 10rpx;
 			background-color: #05c160;
+			color: #fff;
 		}
 	}
 }

+ 3 - 0
components/item/m-text.vue

@@ -56,6 +56,9 @@ export default {
 	data() {
 		return {};
 	},
+	created() {
+		console.log('asdasdasdsdfdf')
+	},
 	computed: {
 		//渲染文本消息,如果包含表情,替换为图片
 		//todo:本不需要该方法,可以在标签里完成,但小程序有兼容性问题,被迫这样实现

+ 1 - 0
components/item/quoteType/m-text.vue

@@ -14,6 +14,7 @@ import { EmojiDecoder, emojiMap } from '@/utils/EmojiDecoder.js';
 const emojiUrl = 'https://imgcache.qq.com/open/qcloud/tim/assets/emoji/';
 const decoder = new EmojiDecoder(emojiUrl, emojiMap);
 export default {
+	name: 'mSubText',
 	props: {
 		isMy: {
 			type: [Boolean, Number],

+ 59 - 0
components/msg/m-text.vue

@@ -0,0 +1,59 @@
+<template>
+	<view>
+		<view class="quote-names">
+			<text v-html="renderTextMessage(value.content)"></text>
+		</view>
+	</view>
+</template>
+
+<script>
+import { EmojiDecoder, emojiMap } from '@/utils/EmojiDecoder.js';
+const emojiUrl = 'https://imgcache.qq.com/open/qcloud/tim/assets/emoji/';
+const decoder = new EmojiDecoder(emojiUrl, emojiMap);
+export default {
+	name: 'mText',
+	props: {
+		value: {
+			type: Object,
+			default: {}
+		}
+	},
+	data() {
+		return {};
+	},
+	// computed: {
+	// 	//渲染文本消息,如果包含表情,替换为图片
+	// 	//todo:本不需要该方法,可以在标签里完成,但小程序有兼容性问题,被迫这样实现
+	// 	renderTextMessage() {
+	// 		let text = this.value.content;
+	// 		text = text.replace(/\n/g, '');
+	// 		if (!text) return '<span>' + '[未知内容]' + '</span>';
+	// 		return '<span>' + decoder.decode(text) + '</span>';
+	// 	}
+	// },
+	methods: {
+		renderTextMessage(text) {
+			console.log('text',text)
+			// let text = this.value.content;
+			text = text.replace(/\n/g, '');
+			if (!text) return '<span>' + '[未知内容]' + '</span>';
+			return '<span>' + decoder.decode(text) + '</span>';
+		}
+	}
+};
+</script>
+
+<style scoped lang="scss">
+.quote-box {
+	box-sizing: border-box;
+	padding: 12rpx 16rpx;
+	border-radius: 10rpx;
+	margin-top: 6rpx;
+	background-color: #e1e1e1;
+	color: #6b6b6b;
+}
+.quote-name {
+}
+.quote-content {
+}
+</style>

+ 18 - 0
pages.json

@@ -148,6 +148,24 @@
 				"navigationBarBackgroundColor": "#ffffff",
 				"navigationBarTextStyle": "black"
 			}
+		},
+		{
+			"path": "pages/service/msg",
+			"style": {
+				"navigationBarTitleText": ""
+			}
+		},
+		{
+			"path": "components/msg/m-text",
+			"style": {
+				"navigationBarTitleText": ""
+			}
+		},
+		{
+			"path": "components/msg/m-text",
+			"style": {
+				"navigationBarTitleText": ""
+			}
 		}
 	],
 	"tabBar": {

+ 33 - 27
pages/goods/detail.vue

@@ -119,13 +119,16 @@
 				</view>
 			</view>
 			
-			<view class="service-popup popup-white" v-if="otherImg.length > 0">
-				<view class="rule-content">
-					<view class="content-data" v-html="goodsData.content"></view>
-					
-					<view class="rule-img" v-for="(item,indx) in otherImg" :key="indx">
-						<image :src="item" mode="widthFix"></image>
-					</view>
+			<view class="service-popup popup-white">
+				<view class="rule-content">
+					<template v-if="goodsData.content">
+						<view class="content-data" v-html="goodsData.content"></view>
+					</template>
+					<template v-if="otherImg.length > 0">
+						<view class="rule-img" v-for="(item,indx) in otherImg" :key="indx">
+							<image :src="item" mode="widthFix"></image>
+						</view>
+					</template>
 				</view>
 			</view>
 			
@@ -294,7 +297,8 @@ export default {
 			mobileData:null,
 			loginCode:null,
 			optionData:null,
-			otherImg:[]
+			otherImg:[],
+			scene:""
 		}
 	},
 	created() {
@@ -305,18 +309,14 @@ export default {
 	},
 	onLoad(options) {
 		app = this;
-		app.storeData = uni.getStorageSync("contact");
+		const data = uni.getLaunchOptionsSync();
+		app.scene = data.scene
+		// app.storeData = uni.getStorageSync("contact");
 		app.userToken = uni.getStorageSync("user_token");
 		app.goodsId = options.goods?options.goods:0;
 		app.spm = options.spm?options.spm:'0';
 		app.optionData = options
 		app.getGoods();
-		uni.login({
-			force:true,
-			success(resp){
-				app.loginCode = resp.code;
-			}
-		})
 	},
 	methods: {
 		popState(type){
@@ -352,14 +352,20 @@ export default {
 			})
 		},
 		toLogin(e){
-			var detail = e.detail;
-			detail.login = app.loginCode;
-			Api.mobileAuth(detail).then((res)=>{
-				if (!res.data.mobile) {
-					return app.$dialog.showSuccess(res.msg);
+			uni.login({
+				force:true,
+				success(resp){
+					app.loginCode = resp.code;
+					var detail = e.detail;
+					detail.login = resp.code;
+					Api.mobileAuth(detail).then((res)=>{
+						if (!res.data.mobile) {
+							return app.$dialog.showSuccess(res.msg);
+						}
+						app.mobileData = res.data;
+						app.popState(1)
+					})
 				}
-				app.mobileData = res.data;
-				app.popState(1)
 			})
 		},
 		callMobile(mobile){
@@ -550,8 +556,7 @@ export default {
 					app.storeData = res.data.poi;
 					uni.setStorageSync("contact",res.data.poi);
 				}
-				console.log("res",res)
-				uni.setStorageSync("poiId",res.data.poi_id);
+				uni.setStorageSync("poiId",res.data.poi.poi_id);
 				app.goodsData = res.data;
 				app.bannerData = res.data.image_list
 				app.specs = res.data.specs;
@@ -567,7 +572,8 @@ export default {
 						number:1,
 						product_id:skuSpecs.product_id,
 						sku_id:skuSpecs.sku_id,
-						goods_id:skuSpecs.goods_id
+						goods_id:skuSpecs.goods_id,
+						scene:app.scene
 					}
 				} else {
 					var buyGoods = {
@@ -578,12 +584,12 @@ export default {
 						number:1,
 						product_id:res.data.product_id,
 						sku_id:res.data.product_id,
-						goods_id:res.data.goods_id
+						goods_id:res.data.goods_id,
+						scene:app.scene
 					}
 				}
 				app.buyGoods = buyGoods
 				setTimeout(function(){
-					console.log("执行动态计算图片高度")
 					app.setSwiperHeight(); // 动态设置 swiper 的高度
 				},800)
 				// app.$nextTick(() => {

+ 8 - 1
pages/index/index.vue

@@ -110,7 +110,14 @@ export default {
 	},
 	onLoad(options) {
 		app = this;
-		app.storeId = options.store?options.store:'7644106137976965139';
+		const tokenPoi = uni.getStorageSync("contact");
+		if (options.store != null) {
+		    app.storeId = options.store;
+		} else if (tokenPoi && tokenPoi.poi_id != null) {
+		    app.storeId = tokenPoi.poi_id;
+		} else {
+		    app.storeId = "7644106137976965139";
+		}
 		app.optionData = options;
 		app.getData()
 	},

+ 3 - 1
pages/order/detail.vue

@@ -25,6 +25,7 @@
 				<view class="status-name" v-if="orderData.status == 3">已退款</view>
 				<view class="status-name" v-if="orderData.status == 4">退款中</view>
 				<view class="status-name" v-if="orderData.status == 5">已关闭</view>
+				<view class="status-name" v-if="orderData.status == 6">部分退款</view>
 				
 				<view class="status-desc" v-if="orderData.status == 0">超过30分钟未支付,订单将自动取消</view>
 				<view class="status-desc-qrcode" v-if="orderData.status == 1">
@@ -43,6 +44,7 @@
 				<view class="status-desc" v-if="orderData.status == 3">{{ $dialog.formatMoney(orderData.pay_money,true) }} 已原路退回</view>
 				<view class="status-desc" v-if="orderData.status == 4">已申请退款,钱款预计1-3个自然日到账</view>
 				<view class="status-desc" v-if="orderData.status == 5">订单已取消或已关闭</view>
+				<view class="status-desc" v-if="orderData.status == 6">已退款{{orderData.refund_num}}份</view>
 				
 			</view>
 			<view class="order-goods">
@@ -144,7 +146,7 @@
 						<!-- <view class="btn" @click="payOrder">继续支付</view> -->
 					</view>
 				</view>
-				<view class="footer-op" v-if="orderData.status == 1">
+				<view class="footer-op" v-if="orderData.status == 1 || orderData.status == 6">
 					<view class="footer-right">
 						<!-- <navigator hover-class="none" :url="'/pages/order/refund?order='+orderData.order_sn" class="btn">申请退款</navigator> -->
 						<pay-button-sdk

+ 4 - 3
pages/order/order.vue

@@ -25,6 +25,7 @@
 							<view class="order-status" v-if="item.status == 3">已退款</view>
 							<view class="order-status" v-if="item.status == 4">退款中</view>
 							<view class="order-status" v-if="item.status == 5">已关闭</view>
+							<view class="order-status" v-if="item.status == 6">部分退款</view>
 							<view class="order-time">{{ item.order_sn }}</view>
 						</view>
 						<view class="order-goods" @click="toDetail(item.out_order_no)">
@@ -47,7 +48,7 @@
 								
 								<view class="btn blue" v-if="item.status == 1" @click="toDetail(item.out_order_no)">立即预约</view>
 								<view class="btn danger" v-if="item.status == 1" @click="toDetail(item.out_order_no)">申请退款</view>
-								
+								<view class="btn danger" v-if="item.status == 6" @click="toDetail(item.out_order_no)">申请退款</view>
 								<view class="btn danger" v-if="item.status == 2" @click="toGoods(item)">再来一单</view>
 							</view>
 						</view>
@@ -169,11 +170,11 @@ export default {
 			if (!token) {
 				return false;
 			}
-			var poiId = uni.getStorageSync("poiId");
+			const tokenPoi = uni.getStorageSync("contact");
 			formData.page = pageNo;
 			formData.size = pageSize;
 			formData.status = app.orderState;
-			formData.poi = poiId;
+			formData.poi = tokenPoi.poi_id;
 			app.listState = true;
 			Api.list(formData).then((res)=>{
 				app.listState = false;

+ 19 - 12
pages/service/chat/chat.vue

@@ -325,15 +325,16 @@ export default {
 			})
 		},
 		imgLoad(data){},
-		onItem(data,index){
+		onItem(data,index){
+			console.log("msg",data)
 			switch(data.type) {
 				case "address":
 					var order = data.payload.address;
 					order.msgId = data.messageId;
 					this.addressData = order;
+					this.showAddress(1)
 					Api.city().then((res)=>{
 						this.cityData = res.data;
-						this.showAddress(1)
 					})
 				break;
 				case "order":
@@ -393,8 +394,9 @@ export default {
 				this.$refs.orderpopup.close()
 				return ;
 			}
-			this.orderLoading = true;
-			Api.order({"size":this.size,"page":this.orderPage,"status":2}).then((res)=>{
+			this.orderLoading = true;
+			const tokenPoi = uni.getStorageSync("contact");
+			Api.order({"size":this.size,"page":this.orderPage,"status":2,"poi":tokenPoi.poi_id}).then((res)=>{
 				this.orderLoading = false;
 				if (res.code == 0) {
 					return this.$dialog.showSuccess(res.msg)
@@ -408,7 +410,9 @@ export default {
 		getMoreMsg(){
 			this.history.allLoaded = true;
 			var formData = this.optionsData;
+			const tokenPoi = uni.getStorageSync("contact");
 			formData.page = this.page;
+			formData.poi = tokenPoi.poi_id;
 			Api.msg(formData).then((res)=>{
 				if(res.code == 0) {
 					return this.$dialog.showSuccess(res.msg)
@@ -499,21 +503,21 @@ export default {
 				}
 				if (res.data.code == 3) { // 无客服在线
 					this.noService = true;
-					this.emptyService()
+					this.emptyService(res.data.noService)
 				}
 				this.initPush()
 			})
 		},
-		emptyService(){
+		emptyService(data){
 			const message = {
 				groupId: this.storeData.poi_id,
 				senderData: {
-					avatar:"https://washmy.oss-cn-guangzhou.aliyuncs.com/storage/20260511/23627b2cb8f73a8a90b95c31d726e6ecad0cbb9a.png"
+					avatar:data.logo
 				},
 				senderId: this.serviceId,
 				messageId: Date.now(),
 				payload: {
-					text:"亲!当前无客服在线,请咨询商家电话客服哦!"
+					text:data.msg
 				},
 				timestamp: Date.now(),
 				type: "text",
@@ -521,7 +525,10 @@ export default {
 				status: 'success',
 				isHide: 0
 			};
-			this.pushList(message);
+			const that = this;
+			setTimeout(function(){
+				that.pushList(message);
+			},150);
 		},
 		formatMsg(item){
 			var payload = {};
@@ -799,9 +806,9 @@ export default {
 			this.initMessageItem(message);
 			this.history.messages.unshift(message);
 			// 是否触发文字动效果
-			if (message.type === 'text' || message.type === 'text_quote') {
-				this.onSetText(message.payload.text);
-			}
+			// if (message.type === 'text' || message.type === 'text_quote') {
+			// 	this.onSetText(message.payload.text);
+			// }
 			// 缓存照片地址,
 			if (message.type === 'image' || message.type === 'image_transmit') {
 				imageList.push(message.payload.url);

+ 503 - 0
pages/service/msg.vue

@@ -0,0 +1,503 @@
+<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">
+						<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="" 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>
+								</view>
+								<view class="" v-else-if="item.msgType == 'address'">
+									1
+								</view>
+								<view class="" v-else-if="item.msgType == 'order'">
+									2
+								</view>
+								<view class="" v-else-if="item.msgType == 'image'">
+									3
+								</view>
+								<view class="" v-else-if="item.msgType == 'pay'">
+									4
+								</view>
+								<view v-else>
+									<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>
+			</scroll-view>
+			<view class="tool">
+				<view class="tool-option">
+					<view class="input-text">
+						<textarea class="input" placeholder="输入点什么呢..." auto-height="true" confirm-type="send" type="text"
+							:maxlength="-1" :adjust-position="false" v-model="text" confirm-hold
+							:show-confirm-bar="false" @confirm="sendingText" @keyboardheightchange="keyboardheightchange" />
+					</view>
+					<view class="check-img">
+						<view class="check-icon" @click="tapEmoji"><image src="@/static/image/face.svg" mode="aspectFill"></image></view>
+						<view class="check-icon" @click="tapMore"><image src="@/static/image/more.svg" mode="aspectFill"></image></view>
+					</view>
+				</view>
+			</view>
+			
+			<template v-if="keyboardHeight>0">
+				<view class="keyboardheight" :style="{ height: keyboardHeight + 'px' }"></view>
+			</template>
+			<view>
+				<emoji v-model="isEmoji" @onEmoji="onEmoji" @deleteFn="deleteFn" @sendingText="sendingText" @sendingEmojiPack="sendingEmojiPack"></emoji>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+var {Push} = require("@/static/js/push.js")
+import * as Api from "@/static/api/msg.js";
+import form from "@/static/js/form.js";
+let cursor = 0; //输入框光标
+var app;
+import emoji from '@/components/bottom-operation/emoji.vue';
+import { mapState } from 'vuex';
+import {
+	show,
+	formatDate,
+	throttle,
+	openimg,
+	getLocation,
+	to as tofn
+} from '@/utils/index.js';
+import { EmojiDecoder, emojiMap } from '@/utils/EmojiDecoder.js';
+const emojiUrl = 'https://imgcache.qq.com/open/qcloud/tim/assets/emoji/';
+const decoder = new EmojiDecoder(emojiUrl, emojiMap);
+export default {
+	components: {
+		emoji
+	},
+	data() {
+		return {
+			text: '',
+			list: [],
+			allLoaded:false,
+			msgPage:2,
+			top: 0,
+			isEmoji:false,
+			isMore:false,
+			keyboardHeight:0,
+			pushObj:null,
+            wsAuth:"https://tran.jsshuita.cn/plugin/webman/push/auth",
+            wsUrl: 'wss://tran.jsshuita.cn/ws',
+			_friendAvatar:"",
+			_selfAvatar:"",
+			isKeyboard:false,
+			screenWidth:0
+		};
+	},
+	computed: mapState({
+		//显示时间
+		renderMessageDate() {
+			return (message, index) => {
+				if (message.timestamp - this.list[index + 1]?.timestamp > 3 * 60 * 1000) {
+					return formatDate(message.timestamp, 'timestamp');
+				}
+				return '';
+			};
+		},
+	}),
+	onLoad(options) {
+		app = this;
+		app.optionsData = options;
+		uni.setNavigationBarTitle({
+			title:"加载中..."
+		});
+		const systemInfo = uni.getSystemInfoSync();
+		app.screenWidth = systemInfo.screenWidth;
+		app.getService(options)
+	},
+	beforeDestroy() {
+		cursor = 0;
+		this.pushObj.disconnect()
+	},
+	methods: {
+		scroll(){},
+		// 滚动到底部
+		scrolltolower() {
+			// if (this.history.allLoaded) return;
+			// console.log('触底')
+			// this.getMoreMsg()
+			// this.loadHistoryMessage();
+		},
+		// 滚动到顶部
+		scrolltoupper() {
+			if (this.allLoaded) return;
+			console.log('滚动到顶部')
+			this.getMoreMsg()
+		},
+		getMoreMsg(){
+			this.allLoaded = true;
+			var formData = this.optionsData;
+			const tokenPoi = uni.getStorageSync("contact");
+			formData.page = this.msgPage;
+			formData.poi = tokenPoi.poi_id;
+			Api.msg(formData).then((res)=>{
+				if(res.code == 0) {
+					return this.$dialog.showSuccess(res.msg)
+				}
+				if (res.data.rows.length > 0) {
+					this.msgPage ++;
+					this.allLoaded = false;
+					var msgData = res.data.rows;
+					var pushData = [];
+					if (msgData.length > 0) {
+						msgData.forEach(item => pushData.push(app.formatMsg(item)))
+					}
+					// console.log("pushData",pushData)
+					// app.list = [...app.list,...pushData]
+					app.list.unshift(...pushData)
+					// this.scrollToBottom()
+				} else {
+					this.allLoaded = true;
+				}
+			})
+		},
+		quickQs(data){
+			if (!data.answer) return ;
+			app.list.push({
+				content: data.answer,
+				userType: 'self',
+				avatar: app._selfAvatar,
+				msgType:"text",
+				list:[]
+			})
+			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>';
+		},
+		getService(options){
+			Api.checkIn(options).then((res)=>{
+				uni.setNavigationBarTitle({
+					title:"与"+res.data.store.name+"对话中"
+				})
+				app._selfAvatar = res.data.avatar.self;
+				app._friendAvatar = res.data.avatar.friend;
+				var msgData = res.data.msg.rows;
+				var pushData = [];
+				if (msgData.length > 0) {
+					msgData.forEach(item => pushData.push(app.formatMsg(item)))
+				}
+				var quickData = res.data.quick;
+				pushData.push({
+					content: quickData.star_msg,
+					userType: 'friend',
+					avatar: res.data.avatar.friend,
+					msgType:"quick",
+					list:quickData.quick
+				})
+				console.log("pushData",pushData)
+				app.list = [...app.list,...pushData]
+				this.scrollToBottom()
+			})
+		},
+		formatMsg(item){
+			var payload = "";
+			if (item.type == 'text') {
+				payload = item.content
+			}
+			if (item.type == 'order') {
+				var order = JSON.parse(item.content)
+				payload = order
+			}
+			if (item.type == 'pay') {
+				var order = JSON.parse(item.content)
+				payload = order
+			}
+			if (item.type == 'address') {
+				var order = JSON.parse(item.content)
+				payload = order
+			}
+			if (item.type == 'image') {
+				payload = item.content
+			}
+			const message = {
+				content: payload,
+				userType: item.userType,
+				avatar: item.avatar,
+				msgType:item.type,
+				list:[],
+				timestamp: item.time,
+			};
+			return message;
+		},
+		tapMore(){
+			
+		},
+		keyboardheightchange(e){
+			// app.$dialog.showSuccess('asdasdasd')
+			const height = e.detail.height;
+			if (height > 0) {
+				this.isEmoji = false;
+				this.isMore = false;
+				this.isKeyboard = true;
+			} else {
+				this.isKeyboard = false;
+			}
+			this.keyboardHeight = height;
+			setTimeout(()=>{
+				this.scrollToBottom()
+			}, 150)
+		},
+		touchmove(){
+			this.isFocus = false;
+			this.isFocisEmojius = false;
+			this.isEmoji = false;
+			this.isMore = false;
+			this.isKeyboard = false;
+			this.keyboardHeight = 0
+		},
+		onEmoji(key) {
+			const text = `${this.text.slice(0, cursor)}${key}${this.text.slice(cursor)}`;
+			this.text = text;
+		},
+		sendingEmojiPack(){},
+		// 删除表情
+		deleteFn() {
+			const str = this.text.charAt(this.text.length - 1);
+			if (str === ']') {
+				let metaChars = /\[.*?(\u4e00*\u597d*)\]/g;
+				let xstr = '';
+				this.text.replace(metaChars, (match) => {
+					xstr = match;
+				});
+				var text = this.text;
+		
+				function del(str) {
+					return text.slice(0, text.length - str.length);
+				}
+				this.text = del(xstr);
+			} else {
+				this.text = this.text.substring(0, this.text.length - 1);
+			}
+		},
+		tapEmoji() {
+			this.isEmoji = !this.isEmoji;
+			if (this.isEmoji) {
+				this.isKeyboard = true;
+			}
+			this.isMore = false;
+			setTimeout(()=>{
+				this.scrollToBottom()
+			}, 150)
+		},
+		sendingText() {
+			if (!this.text) return ;
+			this.list.push({
+				content: this.text,
+				userType: 'self',
+				avatar: this._selfAvatar
+			})
+			this.text = ''
+			this.scrollToBottom()
+			// 模拟对方回复
+			// setTimeout(()=>{
+			// 	this.list.push({
+			// 		content: '周末什么安排',
+			// 		userType: 'friend',
+			// 		avatar: this._friendAvatar
+			// 	})
+			// 	this.scrollToBottom()
+			// }, 1500)
+		},
+		chooseImage() {
+			uni.chooseImage({
+				// sourceType: 'album',
+				success: (res) => {
+					this.list.push({
+						content: res.tempFilePaths[0],
+						userType: 'self',
+						messageType: 'image',
+						avatar: this._selfAvatar
+					})
+					this.scrollToBottom()
+					// 模拟对方回复
+					setTimeout(()=>{
+						this.list.push({
+							content: '你好呀,朋友~',
+							userType: 'friend',
+							avatar: this._friendAvatar
+						})
+						this.scrollToBottom()
+					}, 1500)
+				}
+			})
+		},
+		scrollToBottom() {
+			if (this.isEmoji) {
+				var px = 600 * (app.screenWidth / 750)
+				this.top = (this.list.length + px) * 1000
+			} else {
+				this.top = (this.list.length + parseInt(this.keyboardHeight)) * 1000
+			}
+		}
+	}
+}
+</script>
+
+<style lang="scss" scoped>
+.pages {
+    position: fixed;
+    z-index: 1;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    right: 0;
+    background-color: #ededed;
+}
+.safe-box{width: 100%;height: env(safe-area-inset-bottom);}
+.scroll-view {
+	/* #ifdef H5 */
+	height: calc(100vh - 44px);
+	/* #endif */
+	/* #ifndef H5 */
+	height: 0;
+	/* #endif */
+	background: #eee;
+	box-sizing: border-box;
+}
+.message {
+	display: flex;
+	align-items: flex-start;
+	margin-bottom: 30rpx;
+	.quickList{
+		margin-top: 10upx;
+		.list-items {
+			color: blue;
+			font-size: 28upx;
+			line-height: 48upx;
+		}
+	}
+	.avatar {
+		width: 80rpx;
+		height: 80rpx;
+		border-radius: 10rpx;
+		margin-right: 30rpx;
+	}
+	.content {
+		min-height: 80rpx;
+		max-width: 60vw;
+		box-sizing: border-box;
+		font-size: 28rpx;
+		line-height: 1.3;
+		padding: 20rpx;
+		border-radius: 10rpx;
+		background: #fff;
+		image {
+			width: 200rpx;
+		}
+	}
+	&.self {
+		justify-content: flex-end;
+		.avatar {
+			margin: 0 0 0 30rpx;
+		}
+		.content {
+			position: relative;
+			&::after {
+				position: absolute;
+				content: '';
+				width: 0;
+				height: 0;
+				border: 16rpx solid transparent;
+				border-left: 16rpx solid #fff;
+				right: -28rpx;
+				top: 24rpx;
+			}
+		}
+	}
+	&.friend {
+		.content {
+			position: relative;
+			&::after {
+				position: absolute;
+				content: '';
+				width: 0;
+				height: 0;
+				border: 16rpx solid transparent;
+				border-right: 16rpx solid #fff;
+				left: -28rpx;
+				top: 24rpx;
+			}
+		}
+	}
+}
+
+.tool {
+	// min-height: 120rpx;
+	// position: fixed;
+	// right: 0;
+	// left: 0;
+	// bottom: 0;
+	background: #fff;
+	padding: 20rpx 0 20rpx 0;
+	padding-bottom: calc(20rpx + constant(safe-area-inset-bottom)/2) !important;
+	padding-bottom: calc(20rpx + env(safe-area-inset-bottom)/2) !important;
+	.tool-option{
+		display: flex;
+		align-items: flex-start;
+		box-sizing: border-box;
+		padding: 0 20rpx;
+	}
+	.input-text{
+		flex: 1;width: 100%;
+		box-sizing: border-box;
+		padding: 10rpx 14rpx;
+		min-height: 84rpx;
+		max-height: 300rpx;
+		overflow: auto;
+		border-radius: 10rpx;
+		background-color: #eee;
+		.input{
+			margin: 10rpx 0;
+			width: 100%;
+			font-size: 28upx;
+			height: 100%;
+			background-color: #eee;
+			min-height: 48rpx;
+			max-height: 300rpx;
+		}
+	}
+	.check-img{
+		display: flex;align-items: center;justify-content: center;
+		.check-icon{width: 84rpx;height: 84rpx;display: flex;align-items: center;justify-content: center;}
+		image{width: 75%;height: 75%;}
+	}
+	
+	.thumb {
+		width: 64rpx;
+	}
+}
+.time {
+	width: 100%;
+	color: #a3a3a3;
+	line-height: 100rpx;
+	text-align: center;
+	font-size: 24rpx;
+}
+</style>

+ 99 - 0
pages/service/service copy.vue

@@ -0,0 +1,99 @@
+<template>
+	<view class="content">
+		<view class="order-body">
+			<view class="empty-body" v-if="loginState">
+				<view class="img">
+					<image src="/static/image/empty.png" mode="widthFix"></image>
+					<view class="tip">请先登录</view>
+				</view>
+				<view class="re-btn" @click="reback">去登陆</view>
+			</view>
+			<block class="" v-else>
+				<z-paging ref="paging" show-refresher-update-time v-model="dataList" @query="queryList" :fixed="false">
+					<view class="kefu-item" @click="$dialog.jumpUri('/pages/service/chat/chat?poi='+item.poi_id+'&source=list',1)" v-for="(item,index) in dataList" :key="index">
+						<view class="logo"><image :src="item.avatar" mode="widthFix"></image></view>
+						<view class="kefu-store">
+							<view class="name">{{item.poi_name}} <text v-if="item.last.num > 0">{{item.last.num}}</text></view>
+							<view class="desc" v-if="item.last.type=='text'">{{item.last.content}}</view>
+							<view class="desc" v-if="item.last.type=='order'">[订单消息]</view>
+							<view class="desc" v-if="item.last.type=='image'">[图片消息]</view>
+							<view class="desc" v-if="item.last.type=='video'">[视频消息]</view>
+							<view class="desc" v-if="item.last.type=='pay'">[支付消息]</view>
+							<view class="desc" v-if="item.last.type=='address'">[地址消息]</view>
+						</view>
+						<view class="time">
+							{{item.last.create_at}}
+						</view>
+					</view>
+				</z-paging>
+			</block>
+			
+		</view>
+	</view>
+</template>
+
+<script>
+var app;
+import * as Api from "@/static/api/service.js";
+export default {
+	data() {
+		return {
+			listState:false,
+			dataList:[],
+			loginState:true
+		}
+	},
+	onShow() {
+		var token = uni.getStorageSync("user_token")
+		if (token) {
+			this.loginState = false;
+		}
+		this.queryList(1,10)
+	},
+	onLoad() {
+		app = this;
+	},
+	methods: {
+		queryList(pageNo, pageSize){
+			var formData = {};
+			var token = uni.getStorageSync("user_token")
+			if (!token) {
+				return false;
+			}
+			const tokenPoi = uni.getStorageSync("contact");
+			console.log("tokenPoi",tokenPoi)
+			formData.page = pageNo;
+			formData.size = pageSize;
+			formData.poi = tokenPoi.poi_id;
+			app.listState = true;
+			Api.list(formData).then((res)=>{
+				app.listState = false;
+				uni.hideLoading();
+				if (res.code !== 1) {
+					this.$refs.paging.complete(false);
+					return app.$dialog.showSuccess(res.msg);
+				}
+				app.$refs.paging.complete(res.data.rows);
+			})
+		}
+	}
+}
+</script>
+
+<style>
+.order-body{height: calc(100vh - 20upx);margin-top: 20upx;}
+.kefu-item{display: flex;align-items: center;background-color: #fff;padding: 20upx;border-bottom: 2upx solid #f8f8f8;}
+.kefu-item .logo{height: 100upx;overflow: hidden;}
+.kefu-item .logo image{width: 100upx;}
+.kefu-item .kefu-store{margin-left: 20upx;}
+.kefu-item .kefu-store .name{font-size: 28upx;color: #333;display: flex;align-items: center;}
+.kefu-item .kefu-store .name text{background-color: #f00;color: #fff;width: 30upx;height: 30upx;display: flex;align-items: center;justify-content: center;border-radius: 30upx;font-size: 20upx;margin-left: 20upx;}
+.kefu-item .kefu-store .desc{font-size: 24upx;color: #666;margin-top: 10upx;}
+.kefu-item .time{margin-left: auto;margin-right: 0;font-size: 24upx;color: #666;}
+
+.empty-body{display: flex;align-items: center;justify-content: center;flex-direction: column;height: calc(100vh - 100upx);}
+.empty-body .img{text-align: center;font-size: 28upx;color: #666;}
+.empty-body .img image{height: 160upx;width: 160upx;}
+.empty-body .img .tip{margin-top: 20upx;}
+.empty-body .re-btn{width: 180upx;height: 80upx;line-height: 80upx;text-align: center;font-size: 28upx;color: #fff;background-color: #007aff;border-radius: 10upx;margin-top: 60upx;}
+</style>

+ 96 - 30
pages/service/service.vue

@@ -9,23 +9,28 @@
 				<view class="re-btn" @click="reback">去登陆</view>
 			</view>
 			<block class="" v-else>
-				<z-paging ref="paging" show-refresher-update-time v-model="dataList" @query="queryList" :fixed="false">
-					<view class="kefu-item" @click="$dialog.jumpUri('/pages/service/chat/chat?poi='+item.poi_id+'&source=list',1)" v-for="(item,index) in dataList" :key="index">
-						<view class="logo"><image :src="item.avatar" mode="widthFix"></image></view>
-						<view class="kefu-store">
-							<view class="name">{{item.poi_name}} <text v-if="item.last.num > 0">{{item.last.num}}</text></view>
-							<view class="desc" v-if="item.last.type=='text'">{{item.last.content}}</view>
-							<view class="desc" v-if="item.last.type=='order'">[订单消息]</view>
-							<view class="desc" v-if="item.last.type=='image'">[图片消息]</view>
-							<view class="desc" v-if="item.last.type=='video'">[视频消息]</view>
-							<view class="desc" v-if="item.last.type=='pay'">[支付消息]</view>
-							<view class="desc" v-if="item.last.type=='address'">[地址消息]</view>
+				<view class="page">
+					<view class="list-item" v-for="(item,index) in dataList" :key="index" @click="$dialog.jumpUri('/pages/service/msg?poi='+item.poi_id+'&source=list',1)">
+						<view class="avatar">
+							<text class="round" v-if="item.last.num > 0"></text>
+							<image :src="item.avatar" mode="widthFix"></image>
 						</view>
-						<view class="time">
-							{{item.last.create_at}}
+						<view class="content">
+							<view class="title">
+								<text class="name">{{ item.poi_name }}</text>
+								<text class="time">{{ item.last.create_at }}</text>
+							</view>
+							<view class="txt">
+								<view class="desc" v-if="item.last.type=='text'">{{item.last.content}}</view>
+								<view class="desc" v-if="item.last.type=='order'">[订单消息]</view>
+								<view class="desc" v-if="item.last.type=='image'">[图片消息]</view>
+								<view class="desc" v-if="item.last.type=='video'">[视频消息]</view>
+								<view class="desc" v-if="item.last.type=='pay'">[支付消息]</view>
+								<view class="desc" v-if="item.last.type=='address'">[地址消息]</view>
+							</view>
 						</view>
 					</view>
-				</z-paging>
+				</view>
 			</block>
 			
 		</view>
@@ -53,44 +58,105 @@ export default {
 	onLoad() {
 		app = this;
 	},
-	methods: {
+	methods: {
+		reback(){
+			uni.navigateTo({
+				url:"/pages/auth/login"
+			})
+		},
 		queryList(pageNo, pageSize){
 			var formData = {};
 			var token = uni.getStorageSync("user_token")
 			if (!token) {
 				return false;
-			}
+			}
+			const tokenPoi = uni.getStorageSync("contact");
+			console.log("tokenPoi",tokenPoi)
 			formData.page = pageNo;
 			formData.size = pageSize;
+			formData.poi = tokenPoi.poi_id;
 			app.listState = true;
 			Api.list(formData).then((res)=>{
 				app.listState = false;
 				uni.hideLoading();
 				if (res.code !== 1) {
-					this.$refs.paging.complete(false);
 					return app.$dialog.showSuccess(res.msg);
 				}
-				app.$refs.paging.complete(res.data.rows);
+				app.dataList = app.dataList.concat(res.data.rows);
 			})
 		}
 	}
 }
 </script>
 
-<style>
-.order-body{height: calc(100vh - 20upx);margin-top: 20upx;}
-.kefu-item{display: flex;align-items: center;background-color: #fff;padding: 20upx;border-bottom: 2upx solid #f8f8f8;}
-.kefu-item .logo{height: 100upx;overflow: hidden;}
-.kefu-item .logo image{width: 100upx;}
-.kefu-item .kefu-store{margin-left: 20upx;}
-.kefu-item .kefu-store .name{font-size: 28upx;color: #333;display: flex;align-items: center;}
-.kefu-item .kefu-store .name text{background-color: #f00;color: #fff;width: 30upx;height: 30upx;display: flex;align-items: center;justify-content: center;border-radius: 30upx;font-size: 20upx;margin-left: 20upx;}
-.kefu-item .kefu-store .desc{font-size: 24upx;color: #666;margin-top: 10upx;}
-.kefu-item .time{margin-left: auto;margin-right: 0;font-size: 24upx;color: #666;}
-
-.empty-body{display: flex;align-items: center;justify-content: center;flex-direction: column;height: calc(100vh - 100upx);}
+<style lang="scss" scoped>
+.empty-body{display: flex;align-items: center;justify-content: center;flex-direction: column;height: 100vh;}
 .empty-body .img{text-align: center;font-size: 28upx;color: #666;}
 .empty-body .img image{height: 160upx;width: 160upx;}
 .empty-body .img .tip{margin-top: 20upx;}
 .empty-body .re-btn{width: 180upx;height: 80upx;line-height: 80upx;text-align: center;font-size: 28upx;color: #fff;background-color: #007aff;border-radius: 10upx;margin-top: 60upx;}
+.page {
+	padding: 0 32rpx;
+	color: #333;
+}
+.list-item {
+	display: flex;
+	padding: 30rpx 0;
+	border-bottom: 2upx solid #ccced3;
+
+	.avatar {
+		width: 90rpx;
+		height: 90rpx;
+		border-radius: 10rpx;
+		margin-right: 20rpx;
+		position: relative;
+
+		.round {
+			position: absolute;
+			width: 14rpx;
+			height: 14rpx;
+			border-radius: 50%;
+			background: #ef5656;
+			top: -4rpx;
+			right: -4rpx;
+			z-index: 1;
+		}
+
+		image {
+			width: 100%;
+			height: 100%;
+			border-radius: 10rpx;
+		}
+	}
+
+	.content {
+		flex: 1;
+
+		.title {
+			display: flex;
+			justify-content: space-between;
+
+			.name {
+				font-weight: bold;
+			}
+
+			.time {
+				color: #999;
+				font-size: 24rpx;
+			}
+		}
+
+		.txt {
+			margin-top: 10rpx;
+			overflow: hidden;
+			text-overflow: ellipsis;
+			display: -webkit-box;
+			-webkit-line-clamp: 1;
+			-webkit-box-orient: vertical;
+			text-align: left;
+			color: #999;
+			font-size: 26rpx;
+		}
+	}
+}
 </style>

+ 25 - 0
static/api/msg.js

@@ -0,0 +1,25 @@
+import request from '@/static/js/request.js'
+
+const apiUri = {
+	checkIn: '/msg/checkIn', // 进线
+	list: '/service/list',
+	save: '/user/save',
+	send: '/service/send',
+	msg: '/msg/msg',
+	upload: '/service/send/img',
+	pricePay: '/order/pricePay',
+	order: '/order/chat',
+	city: '/home/city',
+	address: '/service/send/address',
+}
+export function checkIn(param) {
+	return request.request(apiUri.checkIn,'POST', param,false,true,true)
+}
+
+export function msg(param) {
+	return request.request(apiUri.msg,'GET', param,false,true,true)
+}
+
+export function upload(path,param) {
+	return request.uploadFile(apiUri.upload,path,param)
+}

+ 69 - 0
uni.scss

@@ -74,3 +74,72 @@ $uni-color-subtitle: #555555; // 二级标题颜色
 $uni-font-size-subtitle:26px;
 $uni-color-paragraph: #3F536E; // 文章段落颜色
 $uni-font-size-paragraph:15px;
+
+.flex_r {
+	display: flex;
+	flex-direction: row;
+}
+
+.flex_c {
+	display: flex;
+	flex-direction: column;
+}
+.flex1 {
+	flex: 1;
+}
+.fj_b {
+	justify-content: space-between;
+}
+
+.fj_a {
+	justify-content: space-around;
+}
+
+.fj_c {
+	justify-content: center;
+}
+
+.fa_c {
+	align-items: center;
+}
+
+.flex_c_c {
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	justify-content: center;
+}
+
+.icon_ {
+	display: flex;
+	flex-direction: row;
+	align-items: center;
+	justify-content: center;
+}
+
+.z_index2 {
+	position: relative;
+	z-index: 2;
+}
+
+.img {
+	width: 100%;
+	height: 100%;
+}
+
+.rotate_45 {
+	transform: rotate(45deg);
+}
+
+.rotate_90 {
+	transform: rotate(90deg);
+}
+
+.rotate_180 {
+	transform: rotate(180deg);
+}
+
+.text-indent {
+	text-indent: 2em;
+	text-align: justify;
+}