Zory 4 недель назад
Родитель
Сommit
6ff46bcbaa

+ 6 - 0
奥莱优品/api/model/home.js

@@ -18,5 +18,11 @@ export default {
 		get: async function(data={}) {
 			return await request.request(this.url,"GET",data,false,true,true)
 		}
+	},
+	city: {
+		url: `/home/city`,
+		get: async function(data={}) {
+			return await request.request(this.url,"GET",data,false,true,true)
+		}
 	}
 }

+ 6 - 0
奥莱优品/api/model/order.js

@@ -7,6 +7,12 @@ export default {
 			return await request.request(this.url,"GET",data,false,true,true)
 		}
 	},
+	chat: {
+		url: `/order/chat`,
+		get: async function(data={}) {
+			return await request.request(this.url,"GET",data,false,true,true)
+		}
+	},
 	detail: {
 		url: `/order/detail`,
 		get: async function(data={}) {

+ 137 - 0
奥莱优品/components/chat/order.vue

@@ -0,0 +1,137 @@
+<template>
+	<view>
+		<uni-popup ref="orderPop" type="bottom" border-radius="10px 10px 0 0" background-color="#f1f1f1" :mask-click="false">
+			<view class="order-popup">
+				<view class="order-title">
+					<view class="name">我的订单</view>
+					<view class="close" @click="closeOrder()"><image src="/static/image/close.png"></image></view>
+				</view>
+				<view class="order-body-con" v-if="orderList.length > 0">
+				<scroll-view class="order-body" scroll-y scroll-with-animation @scrolltoupper="scrolltoupper" @scrolltolower="scrolltolower" upper-threshold="80">
+					<view class="m-order-s" v-for="(items,index) in orderList" :key="index">
+						<view class="order-img"><image :src="items.img" mode="widthFix"></image></view>
+						<view class="order-info">
+							<view class="title">{{items.product.product_name}}</view>
+							<view class="desc">{{items.out_order_no}}</view>
+							<view class="price">{{ $dialog.formatMoney(items.price,true) }}</view>
+						</view>
+						<view class="status-btn-group">
+							<view class="status info" v-if="items.status=='0'">未支付</view>
+							<view class="status primary" v-if="items.status=='1'">待使用</view>
+							<view class="status success" v-if="items.status=='2'">已完成</view>
+							<view class="status danger" v-if="items.status=='3'">已退款</view>
+							<view class="status warn" v-if="items.status=='4'">退款中</view>
+							<view class="status info" v-if="items.status=='5'">已关闭</view>
+							<view class="status danger" @click="sendOrder(items)">发送</view>
+						</view>
+					</view>
+					<view class="view-more" v-if="orderData.loading">
+						<uni-load-more status="loading"></uni-load-more>
+					</view>
+				</scroll-view>
+				</view>
+				<view class="order-body" v-else>
+					<view class="empty-body">暂无数据...</view>
+				</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+export default {
+	data () {
+		return {
+			orderList:[],
+			orderData:{
+				page:1,
+				size:10,
+				loading:false,
+				isDone:false
+			}
+		}
+	},
+	methods: {
+		open() {
+			this.$nextTick(()=>{
+				this.$refs.orderPop.open()
+			})
+			return this;
+		},
+		closeOrder(){
+			this.$nextTick(()=>{
+				this.$refs.orderPop.close()
+			})
+		},
+		setData(data) {
+			this.orderData.page = 1;
+			this.orderData.loading = false;
+			this.orderData.isDone = false;
+			this.getOrder();
+		},
+		sendOrder(data){
+			this.$refs.orderPop.close()
+			this.$emit("send",data)
+		},
+		scrolltoupper(){},
+		scrolltolower(e){
+			if (this.orderData.isDone || this.orderList.length == 0) return ;
+			this.getOrder()
+		},
+		async getOrder(){
+			this.orderData.loading = true;
+			var formData = {};
+			const tokenPoi = uni.getStorageSync("contact");
+			formData.poi = tokenPoi.poi_id;
+			formData.page = this.orderData.page;
+			formData.size = this.orderData.size;
+			// formData.status = 1;
+			var resp = await this.$api.order.chat.get(formData)
+			this.orderData.loading = false;
+			if (resp.code == 0) {
+				return this.$dialog.showSuccess(resp.msg)
+			}
+			if (resp.data.rows.length > 0) {
+				this.orderData.page ++;
+				this.orderList = [...this.orderList,...resp.data.rows];
+			} else {
+				this.orderData.isDone = true;
+			}
+		}
+	}
+}
+</script>
+
+<style>
+.order-popup .order-title{display: flex;align-items: center;justify-content: space-between;font-size: 32upx;padding: 20upx;font-weight: bold;}
+.order-popup .input-value-border{border: 0;}
+.order-popup .order-title.bb1{border-bottom: 2upx solid #efefef;}
+.order-popup .order-title image{width: 40upx;height: 40upx;}
+.order-popup .order-body{
+	height: 50vh;overflow: auto;background-color: #fff;border-radius: 20rpx;
+}
+.order-popup.address .order-body{height: 60vh;overflow: auto;padding: 20upx;}
+.order-body-con{margin: 20rpx;}
+
+.view-more{text-align: center;font-size: 24upx;color: #666;padding: 20upx;}
+.order-popup .u-input {height: 60upx;}
+.order-popup .submit-btn{
+	border-top: 2upx solid #efefef;
+	border-radius: 0;
+}
+.m-order-s{border-bottom:2rpx solid #f1f1f1;border-radius: 10upx;display: flex;font-size: 28upx;position: relative;padding: 20upx;}
+.m-order-s .order-img {display: flex;align-items: center;justify-content: center;}
+.m-order-s .order-img image{width: 150upx;height: 150upx;}
+.m-order-s .order-info {padding: 15upx;flex:1;overflow: hidden;}
+.m-order-s .order-info .title{font-size: 28upx;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}
+.m-order-s .order-info .desc{font-size: 24upx;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;color: #999;}
+.m-order-s .order-info .price{font-size: 28upx;color: #f00;}
+.m-order-s .status-btn-group{position: absolute;right: 10rpx;bottom: 10rpx;display: flex;align-items: center;gap: 15upx;}
+.m-order-s .status{border-radius: 10upx 0 10upx 0;background-color: #909399;font-size: 24upx;color: #fff;padding: 10upx;}
+.m-order-s .status.info{background-color: #909399;}
+.m-order-s .status.primary{background-color: #409eff;}
+.m-order-s .status.success{background-color: #67c23a;}
+.m-order-s .status.danger{background-color: #f56c6c;}
+.m-order-s .status.warn{background-color: #e6a23c;}
+.empty-body{display: flex;align-items: center;justify-content: center;height: 100%;}
+</style>

+ 8 - 0
奥莱优品/pages.json

@@ -82,6 +82,14 @@
 			"style": {
 				"navigationBarTitleText": ""
 			}
+		},
+		{
+			"path": "pages/order/done",
+			"style": {
+				"navigationBarTitleText": "完善会员信息",
+				"navigationBarBackgroundColor": "#ffffff",
+				"navigationBarTextStyle": "black"
+			}
 		}
 	],
 	"globalStyle": {

+ 424 - 0
奥莱优品/pages/order/done.vue

@@ -0,0 +1,424 @@
+<template>
+	<view class="content">
+		<template v-if="loading">
+			<view class="skeleton">
+				<view class="skeleton-line max animate" style="height: 200upx;"></view>
+				<view class="skeleton-line animate"></view>
+				<view class="skeleton-line min animate"></view>
+				<view class="skeleton-line min animate"></view>
+				<view class="skeleton-line max animate" style="height: 200upx;"></view>
+				<view class="skeleton-line max animate" style="height: 200upx;"></view>
+			</view>
+		</template>
+		<template v-else>
+			<scroll-view class="goods-body" scroll-y scroll-with-animation>
+				<view class="order-body" v-if="orderData">
+					<view class="item-goods">
+						<view class="item-goods-body">
+							<view class="image">
+								<image :src="orderData.img"></image>
+							</view>
+							<view class="info">
+								<view class="title">
+									<view class="name">{{ orderData.product.product_name }}</view>
+									<view class="num">x{{ orderData.number }}</view>
+								</view>
+								<view class="tags">
+									{{orderData.sku_name?orderData.sku_name:'默认'}}
+									<view class="price">{{ $dialog.formatMoney(orderData.price,true) }}</view>
+								</view>
+								<view class="price-right">实付 <text>{{ $dialog.formatMoney(orderData.pay_money,true) }}</text></view>
+							</view>
+						</view>
+					</view>
+					<view class="order-info">
+						<view class="title-h">完善信息</view>
+						<view class="form-feedbak">
+							<view class="title"><text>*</text>姓名</view>
+							<view class="form-textarea">
+								<input :value="addressForm.nickname" data-field="nickname"  placeholder="请输入" class="u-input" />
+							</view>
+						</view>
+						<view class="form-feedbak">
+							<view class="title"><text>*</text>手机号码</view>
+							<view class="form-textarea">
+								<input :value="addressForm.mobile" data-field="mobile" placeholder="请输入" class="u-input" />
+							</view>
+						</view>
+						<view class="form-feedbak">
+							<view class="title"><text>*</text>所属地区</view>
+							<view class="form-textarea" @click="showAddress">
+								{{addressData.name}}
+							</view>
+						</view>
+						<view class="form-feedbak">
+							<view class="title"><text>*</text>详细地址</view>
+							<view class="form-textarea">
+								<input :value="addressForm.address" data-field="address"  placeholder="请输入" class="u-textarea" />
+							</view>
+						</view>
+					</view>
+				</view>
+				<view class="line-height"></view>
+			</scroll-view>
+			<view class="footer">
+				<view class="footer-op">
+					<view class="footer-left"></view>
+					<view class="footer-right">
+						<view class="btn">再次购买</view>
+					</view>
+				</view>
+				<view class="footer-safe"></view>
+			</view>
+		</template>
+
+		<uni-popup ref="addressPop" type="bottom" border-radius="10px 10px 0 0" background-color="#ffffff" :mask-click="false">
+			<view class="address-pop">
+				<view class="address-check">
+					<view class="check-name" @click="addTop(1,fristData.index)">{{fristData.name}}</view>
+					<view class="check-name" @click="addTop(2,fristData.index)">{{secondData.name}}</view>
+					<view class="check-name" @click="addTop(3,secondData.index)">{{threeData.name}}</view>
+				</view>
+				<view class="address-scroll">
+					<template v-if="fristData.list.length > 0">
+						<view :class="fristData.index==indx?'item-name active':'item-name'" v-for="(item,indx) in fristData.list" :key="indx" @click="addClick(indx,1)">
+							{{ item.text }}
+							<view class="icon"><image src="/static/image/gou.svg"></image></view>
+						</view>
+					</template>
+					<template v-if="secondData.list.length > 0">
+						<view :class="secondData.index==indx?'item-name active':'item-name'" v-for="(item,indx) in secondData.list" :key="indx" @click="addClick(indx,2)">
+							{{ item.text }}
+							<view class="icon"><image src="/static/image/gou.svg"></image></view>
+						</view>
+					</template>
+					<template v-if="threeData.list.length > 0">
+						<view :class="threeData.index==indx?'item-name active':'item-name'" v-for="(item,indx) in threeData.list" :key="indx" @click="addClick(indx,3)">
+							{{ item.text }}
+							<view class="icon"><image src="/static/image/gou.svg"></image></view>
+						</view>
+					</template>
+				</view>
+				<view class="address-footer">
+					<view class="footer-btn" @click="closeOrder">取消</view>
+					<view class="footer-btn full">确定</view>
+				</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+var app;
+export default {
+	data() {
+		return {
+			optionData:null,
+			orderData:null,
+			loading:false,
+			cityData:[],
+			addressForm:{},
+			addressData:{
+				index:0,
+				name:"请选择"
+			},
+			fristData:{
+				index:null,
+				name:"",
+				list:[]
+			},
+			secondData:{
+				index:null,
+				name:"",
+				list:[]
+			},
+			threeData:{
+				index:null,
+				name:"",
+				list:[]
+			},
+		}
+	},
+	onLoad(options) {
+		app = this;
+		app.optionData = options;
+		this.getOrder();
+	},
+	methods: {
+		addClick(indx,type) {
+			if (type == 1) {
+				app.fristData.index = indx;
+				app.fristData.list = [];
+				app.secondData.list = app.cityData[indx].children;
+				app.fristData.name = app.cityData[indx].text;
+			}
+			if (type == 2) {
+				app.secondData.index = indx;
+				app.secondData.name = app.secondData.list[indx].text;
+				app.threeData.list = app.secondData.list[indx].children;
+				app.secondData.list = [];
+			}
+			if (type == 3) {
+				app.threeData.index = indx;
+				app.threeData.name = app.threeData.list[indx].text;
+			}
+		},
+		addTop(type,index){
+			if (type == 1) {
+				app.fristData.list = app.cityData;
+				app.secondData.list = [];
+				app.secondData.index = null;
+				app.secondData.name = null;
+				app.threeData.list = [];
+				app.threeData.index = null;
+				app.threeData.name = null;
+			}
+			if (type == 2) {
+				app.secondData.list = app.cityData[index].children;
+				app.threeData.list = [];
+				app.threeData.index = null;
+				app.threeData.name = null;
+			}
+		},
+		showAddress(){
+			this.$refs.addressPop.open();
+		},
+		closeOrder(){
+			this.$refs.addressPop.close();
+		},
+		addressChange(data){
+			if (data.detail) {
+				this.addressForm.city = JSON.stringify(data.detail.value);
+			}
+		},
+		async getOrder(){
+			app.loading = true;
+			var res = await app.$api.order.detail.get({"order":app.optionData.order});
+			app.loading = false;
+			if (res.code && res.code == 0) {
+				app.$dialog.showSuccess(res.msg);
+				uni.navigateBack()
+				return ;
+			}
+			app.orderData = res.data;
+			app.getCity()
+		},
+		async getCity(){
+			var resp = await app.$api.home.city.get();
+			if (resp.code !== 1) return ;
+			app.cityData = resp.data;
+			app.fristData.index = 0;
+			app.fristData.name = resp.data[0].text;
+			app.fristData.list = resp.data
+		}
+	}
+}
+</script>
+
+<style lang="scss" scoped>
+.address-pop{
+	.address-check{
+		display: flex;
+		align-items: center;
+		justify-content: space-around;
+		color: $main-text-color;
+		background-color: #f1f1f1;
+		.check-name{
+			flex: 1;
+			text-align: center;
+			padding: 30rpx 0;
+		}
+	}
+	.address-scroll{
+		height: 50vh;
+		overflow: auto;
+		padding: 20rpx;
+		.item-name{
+			padding: 20rpx;
+			border-bottom: 2rpx solid #f1f1f1;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			.icon{
+				display: none;
+				image {
+					width: 40rpx;
+					height: 40rpx;
+				}
+			}
+			&.active{
+				color: $main-color;
+				.icon{
+					display: block;
+				}
+			}
+		}
+	}
+	.address-footer{
+		display: flex;
+		align-items: center;
+		justify-content: space-around;
+		gap: 20rpx;
+		padding: 20rpx;
+		.footer-btn{
+			background-color: #fff;
+			border: 2rpx solid $main-text-color;
+			border-radius: 10rpx;
+			color: $main-text-color;
+			height: 80rpx;
+			line-height: 80rpx;
+			text-align: center;
+			flex: 1;
+			&.full{
+				border: 2rpx solid $main-color;
+				background-color: $main-color;
+				color: #fff;
+			}
+		}
+	}
+}
+.content{
+    position: fixed;
+    z-index: 1;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    right: 0;
+    background-color: #f1f1f1;
+	display: flex;
+	flex-direction: column;
+	.line-height{
+		height: 40rpx;
+		width: 100%;
+	}
+}
+
+.form-feedbak{
+	background-color: #fff;
+	border-radius: 20upx;
+}
+.form-feedbak .title{
+	line-height: 80upx;
+	font-size: 28upx;
+}
+.form-feedbak .title text{
+	color: #f00;
+	margin-right: 10upx;
+}
+.form-feedbak .form-textarea{
+	background-color: #f8f8f8;
+	padding: 20upx;
+}
+.order-body {
+	width: 95%;
+	margin: 20rpx auto;
+	.order-info{
+		border-radius: 20rpx;
+		background-color: #fff;padding: 20upx;margin-top: 20upx;
+		.title-h{font-size: 32upx;color: #333;font-weight: bold;margin-bottom: 20rpx;}
+
+	}
+	.item-goods{
+		background-color: #fff;
+		margin-top: 20rpx;
+		border-radius: 20rpx;
+		padding: 20rpx;
+		.item-goods-body{
+			display: flex;
+			align-items: center;
+			gap: 20rpx;
+		}
+		.stock{
+			text-align: right;
+		}
+		.image {
+			height: 140rpx;
+			overflow: hidden;display: flex;align-items: center;min-width: 140rpx;
+			position: relative;
+			image {
+				width: 140rpx;
+				border-radius: 10upx;
+				height: 100%;
+			}
+		}
+		.info{
+			flex: 1 1 0%;
+			overflow: hidden;
+			.title{
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				.name {
+					overflow: hidden;
+					text-overflow: ellipsis;
+					font-size: 32rpx;
+					display: -webkit-box;
+					-webkit-line-clamp: 2;
+					 -webkit-box-orient: vertical;
+					color: #333;
+					font-weight: 900;
+				}
+			}
+			.price-right{
+				text-align: right;
+				color: $main-color;
+				margin-top: 20rpx;
+				font-size: 28rpx;
+				text {
+					font-size: 30rpx;
+					font-weight: 800;
+				}
+			}
+			.tags {
+				color: #94a3b8;
+				font-size: 24rpx;
+				margin: 10rpx 0;
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				.price {
+					font-size: 28rpx;
+					color: $main-text-color;
+					font-weight: 600;
+				}
+			}
+		}
+	}
+}
+.goods-body{
+	height: 0;
+	flex: 1;
+}
+.footer{
+	background-color: #fff;
+	padding: 20upx 20upx 0 20upx;border-top: 2upx solid #f8f8f8;
+	.footer-safe {
+		height: env(safe-area-inset-bottom);width: 100%;
+	}
+	.footer-op{
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		.footer-right{
+			display: flex;
+			align-items: center;
+			gap: 20rpx;
+			.btn{
+				font-size: 28rpx;
+				height: 80upx;
+				border-radius: 10upx;
+				line-height: 80upx;
+				text-align: center;
+				min-width: 200rpx;
+				color: #333;
+				border: 2rpx solid #ccc;
+				&.full{
+					background-color: $main-color;
+					color: #fff;
+					border: 2rpx solid $main-color;
+				}
+			}
+		}
+	}
+}
+</style>

+ 41 - 4
奥莱优品/pages/service/chat.vue

@@ -17,7 +17,7 @@
 									<view v-if="item.msgType == 'text'" @click="clickText(item.content)">
 										<view v-html="renderTextMessage(item.content)"></view>
 									</view>
-									<view class="m-address" v-if="item.msgType == 'address'">
+									<view class="m-address" v-if="item.msgType == 'address'" @click="toAddress(item.content)">
 										<view class="image"><image :src="item.content.img" mode="widthFix"></image></view>
 										<view class="infos">
 											<view class="title">{{item.content.name}}</view>
@@ -75,6 +75,7 @@
 			<emoji v-model="isEmoji" @onEmoji="onEmoji" @deleteFn="deleteFn" @sendingText="sendingText" @sendingEmojiPack="sendingEmojiPack"></emoji>
 			<more v-model="isMore" @onMore="sendingMore"></more>
 		</view>
+		<orderDialog ref="orderDialog" @send="sendOrder"></orderDialog>
 	</view>
 </template>
 
@@ -96,13 +97,14 @@ var {Push} = require("@/static/js/push.js")
 
 import emoji from '@/components/chat/emoji';
 import more from '@/components/chat/more';
+import orderDialog from '@/components/chat/order';
 import { EmojiDecoder, emojiMap } from '@/utils/js/EmojiDecoder.js';
 const emojiUrl = 'https://imgcache.qq.com/open/qcloud/tim/assets/emoji/';
 const decoder = new EmojiDecoder(emojiUrl, emojiMap);
 
 export default {
 	components: {
-		emoji,more
+		emoji,more,orderDialog
 	},
 	data() {
 		return {
@@ -169,6 +171,11 @@ export default {
 		previewImg(data){
 			return openimg(1,[data])
 		},
+		toAddress(data){
+			uni.navigateTo({
+				url:"/pages/order/done?order="+data.order
+			})
+		},
 		clickText(text){
 			const regex = /(1[3-9]\d{9})|(\d{3,4}-\d{7,8})|(\d{7,12})/g;
 			const matches = text.match(regex);
@@ -261,6 +268,34 @@ export default {
 		scrolltoupper(){
 			if (this.msgData.allLoaded) return;
 			this.getMessage()
+		},
+		async sendOrder(items){
+			if (app.chatData.serviceId == 0) {
+				app.sendMessage(app.quickData.unline_msg,"text",'friend');
+				app.scrollToBottom()
+				return ;
+			}
+			var orderData = {};
+			orderData.img = items.img;
+			orderData.name = items.product.product_name;
+			orderData.goods_id = items.life_goods_id;
+			orderData.order = items.out_order_no;
+			orderData.price = (parseInt(items.pay_money) / 100).toFixed(2);
+			orderData.status = items.status;
+
+			var formData = {};
+			const tokenPoi = uni.getStorageSync("contact");
+			formData.groupId = tokenPoi.poi_id;
+			formData.type = "order";
+			formData.content = JSON.stringify(orderData);
+			formData.chatId = app.chatData.serviceId;
+			var resp = await app.$api.chat.sendText.post(formData);
+			app.msgData.isSend = false;
+			if (resp.code == 0) {
+				return show(resp.msg);
+			}
+			app.sendMessage(orderData,"order");
+			app.scrollToBottom()
 		},
 		scrolltolower() {},
 		keyboardheightchange(e){
@@ -334,7 +369,10 @@ export default {
 					show("暂未开通");
 					break;
 				case 'order':
-					show("暂未开通");
+					var formData = {};
+					const tokenPoi = uni.getStorageSync("contact");
+					formData.groupId = tokenPoi.poi_id;
+					this.$refs.orderDialog.open().setData(formData);
 					// this.showOrder(1);
 					break;
 			}
@@ -384,7 +422,6 @@ export default {
 		},
 		async sendingText(){
 			if (app.text === '') return ;
-			console.log("app.chatData.serviceId",app.chatData.serviceId)
 			if (app.chatData.serviceId == 0) {
 				app.text = ''
 				app.sendMessage(app.quickData.unline_msg,"text",'friend');

+ 1 - 0
奥莱优品/static/image/gou.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1787250733463" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12578" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M507.408072 50.511211c-252.556054 0-459.192825 206.636771-459.192825 459.192825s206.636771 459.192825 459.192825 459.192825 459.192825-206.636771 459.192825-459.192825-206.636771-459.192825-459.192825-459.192825m220.412556 353.578475L461.488789 670.421525c-9.183857 9.183857-18.367713 9.183857-27.551569 9.183856-9.183857 0-18.367713-4.591928-27.55157-9.183856l-114.798206-114.798207c-13.775785-13.775785-13.775785-41.327354 0-55.103139 13.775785-13.775785 41.327354-13.775785 55.103139 0l87.246637 87.246637 238.780269-238.780269c13.775785-13.775785 41.327354-13.775785 55.103139 0 13.775785 13.775785 13.775785 36.735426 0 55.103139" fill="#ff5a25" p-id="12579"></path></svg>