Mike преди 4 години
родител
ревизия
7089604ccc

+ 3 - 2
manifest.json

xqd
@@ -11,9 +11,10 @@
     "app-plus" : {},
     "quickapp" : {},
     "mp-weixin" : {
-        "appid" : "wxa6d3f8efdc58ff7e",
+        "appid" : "wx7881c559997a5d6d",
         "setting" : {
-            "urlCheck" : false
+            "urlCheck" : false,
+            "postcss" : false
         },
         "usingComponents" : true,
         "permission" : {

+ 101 - 0
pages.json

xqd
@@ -434,6 +434,107 @@
           }
         }
       ]
+    },
+    {
+      "root": "pages/order",
+      "pages": [
+        {
+          "path": "index/index",
+          "style": {
+            "navigationBarTitleText": "我的订单"
+          }
+        },
+        {
+          "path": "order-detail/order-detail",
+          "style": {
+            "navigationBarTitleText": "订单详情"
+          }
+        },
+        {
+          "path": "express-detail/express-detail",
+          "style": {
+            "navigationBarTitleText": "物流详情"
+          }
+        },
+        {
+          "path": "refund/refund",
+          "style": {
+            "navigationBarTitleText": "订单售后"
+          }
+        },
+        {
+          "path": "refund/index",
+          "style": {
+            "navigationBarTitleText": "售后列表"
+          }
+        },
+        {
+          "path": "refund-detail/refund-detail",
+          "style": {
+            "navigationBarTitleText": "订单售后"
+          }
+        },
+        {
+          "path": "clerk/clerk",
+          "style": {
+            "navigationBarTitleText": "订单核销"
+          }
+        },
+        {
+          "path": "appraise/appraise",
+          "style": {
+            "navigationBarTitleText": "订单评价"
+          }
+        },
+        {
+          "path": "appraise-finish/index",
+          "style": {
+            "navigationBarTitleText": "评价完成"
+          }
+        },
+        {
+          "path": "express-list/express-list",
+          "style": {
+            "navigationBarTitleText": "物流列表"
+          }
+        }
+      ]
+    },
+    {
+      "root": "plugins/book",
+      "pages": [
+        {
+          "path": "index/index",
+          "style": {
+            "navigationBarTitleText": "预约首页"
+          }
+        },
+        {
+          "path": "goods/goods",
+          "style": {
+            "navigationBarTitleText": "商品详情"
+          }
+        },
+        {
+          "path": "orderDetails/orderDetails",
+          "style": {
+            "navigationBarTitleText": "订单详情"
+          }
+        },
+        {
+          "path": "order/order",
+          "style": {
+            "navigationBarTitleText": "订单列表"
+          }
+        },
+        {
+          "path": "reservationList/reservationList",
+          "style": {
+            "navigationBarTitleText": "我的预约"
+          }
+        }
+      ]
     }
+   
   ]
 }

+ 32 - 0
plugins/book/components/app-button.vue

xqd
@@ -0,0 +1,32 @@
+<template>
+	<view class="app-button">
+		<app-form-id>
+			<button class="button">预约</button>
+		</app-form-id>
+	</view>
+</template>
+
+<script>
+    export default {
+        name: "app-button"
+    }
+</script>
+
+<style scoped lang="scss">
+	.app-button {
+		display: inline-block;
+		height: #{48rpx};
+		.button {
+			width: 100%;
+			display: inline-block;
+			border: #{1rpx} solid #ff4544;
+			height: #{48rpx};
+			font-size: #{28rpx};
+			color: #ff4544;
+			padding: 0 #{28rpx};
+			line-height: #{48rpx};
+			border-radius: #{24rpx};
+			background-color: #fff5f5;
+		}
+	}
+</style>

+ 47 - 0
plugins/book/components/app-head-nav-list.vue

xqd
@@ -0,0 +1,47 @@
+<template>
+	<scroll-view scroll-x class="app-head-nav-list">
+		<text class="app-item" v-for="(item, index) in catList"
+		      :key="index"
+		      :class="{'app-active-item': cat_id == item.id}"
+		      @click="active(item.id)"
+		>{{item.name}}</text>
+	</scroll-view>
+</template>
+
+<script>
+    export default {
+        name: "app-head-nav-list",
+	    
+        props: [`catList`, `cat_id`],
+	    
+        methods: {
+            active(id) {
+                this.$emit('click', id);
+            }
+        }
+    }
+</script>
+
+<style scoped lang="scss">
+	.app-head-nav-list {
+		width: #{750rpx};
+		height: #{88rpx};
+		white-space: nowrap;
+		background-color: #ffecec;
+		.app-item {
+			display: inline-block;
+			height: #{56rpx};
+			line-height: #{56rpx};
+			font-size: #{28rpx};
+			text-align: center;
+			color: #666666;
+			margin: #{16rpx} #{23rpx};
+			border-radius: #{30rpx};
+			padding: 0 #{24rpx};
+		}
+		.app-active-item {
+			background: linear-gradient(140deg, #ffa360, #ff5c5c);
+			color: #ffffff;
+		}
+	}
+</style>

+ 84 - 0
plugins/book/components/app-head-navigation.vue

xqd
@@ -0,0 +1,84 @@
+<template>
+	<view class="app-head-navigation dir-left-nowrap">
+		<view class="app-item"
+		      v-for="(item, index) in list"
+		      :key="index"
+		      :class="{'app-active-item': activeIndex === item.id}"
+		      @click="active(item.id)"
+		>{{item.name}}</view>
+	</view>
+</template>
+
+<script>
+    export default {
+        name: 'app-head-navigation',
+        props: {
+            list: {
+                type: Array,
+                default() {
+                    return [
+                        {
+                            name: '全部',
+                            id: 0,
+                        },
+                        {
+                            name: '待支付',
+                            id: 1
+                        },
+                        {
+                            name: '待使用',
+                            id: 2,
+                        },
+                        {
+                            name: '待评价',
+                            id: 4,
+                        }
+                        ,
+                        {
+                            name: '售后',
+                            id: 9,
+                        }
+                    ];
+                }
+            }
+        },
+        data() {
+            return {
+                activeIndex: 0
+            }
+        },
+        methods: {
+            active(index) {
+                this.activeIndex = index;
+                this.$emit('click', index);
+            }
+        }
+    }
+</script>
+
+<style scoped lang="scss">
+	.app-head-navigation {
+		width: #{750rpx};
+		height: #{80rpx};
+		background-color: white;
+		white-space: nowrap;
+		border-bottom: #{1rpx} solid #e2e2e2;
+		
+		.app-item {
+			display: inline-block;
+			height: #{80rpx};
+			line-height: #{80rpx};
+			width: #{150rpx};
+			border-bottom-width: #{4rpx};
+			border-bottom-style: solid;
+			border-bottom-color: transparent;
+			color: #666666;
+			font-size: #{32rpx};
+			text-align: center;
+		}
+		.app-active-item {
+			border-bottom-color: #ff5a5a;
+			color: #ff5a5a;
+		}
+	}
+</style>

+ 158 - 0
plugins/book/components/app-product-list.vue

xqd
@@ -0,0 +1,158 @@
+<template>
+	<view class="goods-list dir-top-nowrap">
+		<view v-if="goodsList.length > 0"  class="row dir-left-nowrap main-between box-grow-1" v-for="(item, key) in goodsList" :key="key" >
+			<view class="item box-grow-0" v-for="(good, index) in item"  :key="index" @click="route_go(good)">
+				<view class="image-name dir-top-nowrap main-left">
+					<view class="out-dialog" v-if="good.goods_stock == 0 && appSetting.is_show_stock == '1'">
+						<image :src="appSetting.is_use_stock == '1' ? appImg.plugins_out : appSetting.sell_out_pic"></image>
+					</view>
+					<image :lazy-load="true"  class="cover_pic" :src="good.cover_pic"></image>
+					<view class="name t-omit">{{good.name}}</view>
+				</view>
+				<view class="content dir-top-nowrap main-right">
+					<view class="price-bottom" v-if="good.is_level == 1">
+						<app-member-price :price="good.level_price"></app-member-price>
+					</view>
+					<view v-if="good.discount > 0">
+						<app-sup-vip :is_vip_card_user="good.is_vip_card_user" :discount="good.discount"></app-sup-vip>
+					</view>
+					<view class="price-btn dir-left-nowrap main-between cross-center">
+						<view class="price">{{good.price_str}}</view>
+						<view v-if="good.goods_stock != 0" class="btn">预约</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+    import {mapState, mapGetters} from 'vuex';
+    import appButton from '../components/app-button.vue';
+    import appMemberPrice from "../../../components/page-component/app-member-mark/app-member-price.vue";
+    import appSupVip from "../../../components/page-component/app-sup-vip/app-sup-vip.vue";
+
+    export default {
+        name: "app-product-list",
+	    
+        components: {
+            'app-button': appButton,
+			'app-member-price': appMemberPrice,
+            'app-sup-vip': appSupVip,
+        },
+	    
+        computed: {
+            ...mapState({
+                appImg: state => state.mallConfig.__wxapp_img.mall,
+                appSetting: state => state.mallConfig.mall.setting,
+            }),
+			...mapGetters('mallConfig', {
+				getVideo: 'getVideo'
+			}),
+        },
+
+        props: [`goodsList`],
+	    
+	    methods: {
+            route_go(data) {
+            	console.log(data);
+				// #ifndef MP-BAIDU
+				if (data.video_url && this.getVideo == 1) {
+					uni.navigateTo({
+						url: `/pages/goods/video?goods_id=${data.goods_id}&sign=booking`
+					});
+				} else {
+					uni.navigateTo({
+						url: `/plugins/book/goods/goods?goods_id=${data.goods_id}`,
+					});
+				}
+				// #endif
+
+				// #ifdef MP-BAIDU
+				uni.navigateTo({
+					url: `/plugins/book/goods/goods?goods_id=${data.goods_id}`,
+				});
+				// #endif
+
+            }
+	    },
+    }
+</script>
+
+<style scoped lang="scss">
+	
+	.goods-list {
+		width: calc(100% - #{32upx});
+		background-color: #f7f7f7;
+		margin: #{0 16upx};
+	}
+	.row {
+		margin-bottom: #{16upx};
+	}
+	.item {
+		width: #{350upx};
+		border-radius: #{15upx};
+		background-color: #ffffff;
+	}
+	
+	.image-name {
+		height: #{396upx};
+		margin-bottom: #{10upx};
+		position: relative;
+		.out-dialog {
+			width: #{350upx};
+			height: #{350upx};
+			position: absolute;
+			top: 0;
+			left: 0;
+			background-color: rgba(0,0,0,.5);
+			image {
+				width: #{350upx};
+				height: #{350upx};
+			}
+		}
+	}
+	
+	.content {
+		margin: #{0 20upx};
+		width: #{310upx};
+		height: calc(100% - #{405upx});
+	}
+	.cover_pic {
+		width: #{350upx};
+		height: #{350upx};
+		margin-bottom: #{20upx};
+		border-top-right-radius: #{15upx};
+		border-top-left-radius: #{15upx};
+	}
+	.name {
+		width: #{310upx};
+		margin: #{0 20upx};
+		font-size: #{28upx};
+		line-height: 1;
+		color: #353535;
+	}
+	.btn {
+		width: #{110upx};
+		height: #{45upx};
+		border-radius: #{22.5upx};
+		border: #{1upx} solid #ff4544;
+		font-size: #{26upx};
+		color: #ff4544;
+		line-height: 1;
+		padding: #{9upx 0};
+		text-align: center;
+		background-color: #fff5f5;
+	}
+	.price-bottom {
+		margin-bottom: #{10upx};
+	}
+	.price {
+		font-size: #{25upx};
+		color: #ff4544;
+	}
+	.price-btn {
+		margin-top: #{10upx};
+		margin-bottom: #{16upx};
+	}
+</style>

+ 184 - 0
plugins/book/components/app-reservation-form.vue

xqd
@@ -0,0 +1,184 @@
+<template>
+	<view class="app-reservation-form dir-left-wrap">
+		<view>
+			<app-jump-button form open_type="navigate" :url="`/plugins/book/orderDetails/orderDetails?id=${item.id}`">
+				<image class="app-image" :src="item.detail[0].goods_info.pic_url"></image>
+				<text class="app-status-text" v-if="item.cancel_status == 2">退款中</text>
+				<text class="app-status-text" v-else-if="item.cancel_status == 1 && item.is_pay == 0">已取消</text>
+				<text class="app-status-text" v-else-if="item.cancel_status == 1">已退款</text>
+				<text class="app-status-text" v-else-if="item.is_pay == 0">待付款</text>
+				<text class="app-status-text" v-else-if="item.is_confirm == 0">待使用</text>
+				<text class="app-status-text" v-else-if="item.is_confirm == 1">已使用</text>
+				<view class="app-title-price">
+					<view class="app-title">
+						{{item.detail[0].goods_info.name}}
+					</view>
+					<view class="app-price dir-left-wrap main-right cross-center">
+						<view class="app-attr">
+							<text v-for="(attr, i) in item.detail[0].goods_info.attr_list" :key="i">{{attr.attr_group_name}}: {{attr.attr_name}}</text>
+						</view>
+						<text class="app-old-price">{{item.total_goods_original_price}}</text>
+						<text  class="app-new-price">{{item.total_pay_price}}</text>
+					</view>
+				</view>
+			</app-jump-button>
+		</view>
+		<view class="app-buttons dir-left-nowrap main-right" v-if="item.cancel_status == 0 && item.is_sale == 0">
+			<view class="app-button" v-if="item.cancel_status != 2 && item.is_pay == 1 && item.is_confirm == 0" @click="refund('refund')">
+				<app-form-id>
+					<view class="button app-button-white">申请退款</view>
+				</app-form-id>
+			</view>
+			<view class="app-button" v-if="item.cancel_status != 2 && item.is_pay == 1 && item.is_confirm == 0" @click="refund('use')">
+				<app-form-id>
+					<view class="button app-button-red">立即使用</view>
+				</app-form-id>
+			</view>
+			<view class="app-button" v-if="item.is_sale == 0 && item.is_confirm == 1" @click="evaluation">
+				<app-form-id>
+					<view class="button app-button-red">去评价</view>
+				</app-form-id>
+			</view>
+			<view class="app-button" v-if="item.is_pay == 0" @click="refund('cancel')">
+				<app-form-id>
+					<view class="button app-button-white">申请取消</view>
+				</app-form-id>
+			</view>
+			<view class="app-button" v-if="item.is_pay == 0" @click="refund('pay')">
+				<app-form-id>
+					<view class="button app-button-red">去支付</view>
+				</app-form-id>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+    export default {
+        name: 'app-reservation-form',
+        props: {
+            item: {
+                type: Object,
+                default() {
+                    return {}
+                }
+            }
+        },
+        methods: {
+            refund(data) {
+                this.$emit('click', data, this.item);
+            },
+            evaluation() {
+                this.$jump({
+                    open_type: 'navigate',
+                    url: `pages/order/appraise/appraise?id=${this.item.id}`
+                })
+            }
+        }
+    }
+</script>
+
+<style scoped lang="scss">
+	.app-reservation-form {
+		width: 100%;
+		margin-top: #{20rpx};
+		position: relative;
+		background-color:white;
+		.app-image {
+			width: #{208rpx};
+			height: #{160rpx};
+			border-radius: #{8rpx};
+			margin: #{24rpx} #{24rpx} #{24rpx} #{24rpx};
+		}
+		.app-status-text {
+			display: inline-block;
+			width: #{100rpx};
+			height: #{48rpx};
+			line-height: #{48rpx};
+			font-size: #{26rpx};
+			color: #FFFFFF;
+			background-color: #ff4544;
+			border-top-left-radius: #{8rpx};
+			text-align: center;
+			position: absolute;
+			top: #{24rpx};
+			left: #{24rpx};
+		}
+		.app-title-price {
+			width: #{470rpx};
+			height: #{24+160+24rpx};
+			margin-right: #{24rpx};
+			.app-title {
+				margin-top: #{32rpx};
+				height: #{64rpx};
+				width: #{470rpx};
+				font-size: #{28rpx};
+				line-height: #{32rpx};
+				color: #353535;
+				word-break: break-all;
+				text-overflow: ellipsis;
+				display: -webkit-box;
+				-webkit-box-orient: vertical;
+				-webkit-line-clamp: 2;
+				overflow: hidden;
+			}
+			.app-attr {
+				width: #{470rpx};
+				margin-top: #{6rpx};
+				font-size: 12px;
+				color: #c9c9c9;
+			}
+			.app-price>text {
+				margin-top: #{32rpx};
+				margin-bottom: #{32rpx};
+			}
+			.app-price>text:before {
+				content: '¥';
+			}
+			.app-old-price {
+				text-decoration:line-through;
+				font-size: #{26rpx};
+				color: #999999;
+				margin-right: #{24rpx};
+			}
+			.app-new-price {
+				font-size: #{32rpx};
+				color: #ff4544;
+			}
+		}
+		.app-buttons {
+			height: #{100rpx};
+			width: 100%;
+			border-top: #{1rpx} solid #e2e2e2;
+			padding-right: #{8rpx};
+			.app-button {
+				width: #{180rpx};
+				height: #{60rpx};
+				margin-right: #{16rpx};
+				padding-top: #{20rpx};
+				.button {
+					width: 100%;
+					height: #{60rpx};
+					line-height: #{60rpx};
+					border-radius: #{30rpx};
+					padding: 0;
+					font-size: #{32rpx};
+					border-width: #{1rpx};
+					border-style: solid;
+					text-align: center;
+					border-color: transparent;
+				}
+				.app-button-white {
+					background-color: white;
+					border-color: #cdcdcd;
+					color: #666666;
+				}
+				.app-button-red {
+					background-color: #fff5f5;
+					color: #ff4544;
+					border-color: #ff4544;
+				}
+			}
+		}
+	}
+</style>

+ 139 - 0
plugins/book/components/app-store.vue

xqd
@@ -0,0 +1,139 @@
+<template>
+	<view class="app-store">
+		<view class="app-text" :style="{'app-text-border': borderStyle}" v-if="title">门店信息</view>
+		<view class="app-list" :class="{'app-list-border': storeNum > 1}">
+			<app-jump-button form arrangement="a" open_type="navigate" :url="`/pages/store/detail?id=${store_id}`">
+				<text class="app-store-name" >
+					{{name}}
+				</text>
+				<text class="app-address">地址: {{address}}</text>
+				<text class="app-time">营业时间: {{business_hours}}</text>
+			</app-jump-button>
+		</view>
+		<view class="app-more" v-if="storeNum > 1">
+			<app-jump-button open_type="navigate" :url="`/pages/store/store?book_id=${goods_id}`" arrangement="left" form>
+				查看全部{{storeNum}}家分店
+				<icon class="app-icon" v-if="icon"></icon>
+			</app-jump-button>
+		</view>
+	</view>
+</template>
+
+<script>
+    export default {
+        name: "app-store",
+        props: {
+            borderStyle: {
+                type: Boolean,
+                default: function() {
+                    return true;
+                }
+            },
+            icon: {
+                type: Boolean,
+                default() {
+                    return true;
+                }
+            },
+            storeNum: {
+                type: Number,
+                default() {
+                    return 0;
+                }
+            },
+            business_hours: {
+                type: String,
+                default() {
+                    return '';
+                }
+            },
+            address: {
+                type: String,
+                default() {
+                    return '';
+                }
+            },
+            name: {
+                type: String,
+                default() {
+                    return '';
+                }
+            },
+            store_id: {
+                type: String,
+                default() {
+                    return '';
+                }
+            },
+            title: {
+                type: Boolean,
+                default() {
+                    return true;
+                }
+            },
+            goods_id: {
+                type: String,
+                default() {
+                    return '';
+                }
+            },
+        }
+    }
+</script>
+
+<style scoped lang="scss">
+	.app-store {
+		width: 100%;
+		background-color: white;
+		padding-left: #{24rpx};
+		margin-bottom: #{20rpx};
+		.app-text {
+			height: #{72rpx};
+			width: calc(100% - #{24rpx});
+			font-size: #{26rpx};
+			color: #999999;
+			line-height: #{72rpx};
+			border-bottom: #{1rpx} solid #e2e2e2;
+		}
+		.app-text-border {
+			border-bottom: #{1rpx} solid #e2e2e2;
+		}
+		.app-more {
+			height: #{80rpx};
+			line-height: #{80rpx};
+			font-size: #{28rpx};
+			color: #00a0e9;
+			position: relative;
+		}
+		.app-icon {
+			position: absolute;
+			top: #{30rpx};
+			right: #{24rpx};
+			width: #{10rpx};
+			height: #{22rpx};
+			background-size: 100% 100%;
+			background-repeat: no-repeat;
+			background-image: url("../../../static/image/icon/arrow-right.png");
+		}
+		.app-list-border {
+			border-bottom: #{1rpx} solid #e2e2e2;
+		}
+		.app-list {
+			padding-bottom: #{32rpx};
+			.app-store-name {
+				font-size: #{28rpx};
+				margin-top: #{32rpx};
+				margin-bottom: #{20rpx};
+				color: #353535;
+			}
+			.app-address {
+				font-size: #{28rpx};
+				color: #999999;
+			}
+			.app-time {
+				font-size: #{28rpx};
+				color: #999999;
+			}
+		}
+	}
+</style>

+ 105 - 0
plugins/book/components/app-write-off-code.vue

xqd
@@ -0,0 +1,105 @@
+<template>
+	<view class="app-write-off-code" v-if="hidden">
+		<view class="app-content">
+			<view class="app-icon" @click="hiddenHandler"></view>
+			<view class="app-text">核销码</view>
+			<image :src="file_path" class="app-image"></image>
+		</view>
+	</view>
+</template>
+
+<script>
+    export default {
+        name: 'app-write-off-code',
+        props: {
+            hidden: {
+                type: Boolean,
+                default() {
+                    return false;
+                }
+            },
+            itemId: {
+                type: String,
+                default() {
+                    return '-1';
+                }
+            }
+        },
+        data() {
+            return {
+                file_path: '',
+            }
+        },
+        watch: {
+            hidden: {
+                handler: function(v) {
+                    if (v === true) {
+                        this.$request({
+                            url: this.$api.book.clerk_code,
+                            data: {
+                                id: this.itemId,
+                            }
+                        }).then(response => {
+                            if (response.code === 0) {
+                                this.file_path = response.data.file_path;
+                            }
+                        })
+                    }
+                }
+            }
+        },
+        methods: {
+            hiddenHandler() {
+                this.$emit('hiden', false);
+                this.file_path = '';
+            }
+        }
+    }
+</script>
+
+<style scoped lang="scss">
+	.app-write-off-code {
+		background-color: rgba(0,0,0, 0.6);
+		width: 100%;
+		height: 100%;
+		top: 0;
+		left:0;
+		position: fixed;
+		border-radius: 0;
+		z-index: 1500;
+		.app-content {
+			background-color: white;
+			width: #{600rpx};
+			height: #{600rpx};
+			border-radius: #{8rpx};
+			position: absolute;
+			top: 50%;
+			left: 50%;
+			transform: translate(-50%, -50%);
+			.app-icon {
+				width: #{30rpx};
+				height: #{30rpx};
+				position: absolute;
+				top: #{32rpx};
+				right: #{32rpx};
+				background-repeat: no-repeat;
+				background-size: 100% 100%;
+				background-image: url("../../../static/image/icon/close.png");
+			}
+			.app-text {
+				font-size: #{33rpx};
+				color: #353535;
+				margin-top: #{56rpx};
+				text-align: center;
+			}
+			.app-image {
+				width: #{360rpx};
+				height: #{360rpx};
+				margin-top: #{64rpx};
+				position: absolute;
+				left: 50%;
+				transform: translateX(-50%);
+			}
+		}
+	}
+</style>

+ 338 - 0
plugins/book/goods/goods.vue

xqd
@@ -0,0 +1,338 @@
+<template>
+	<app-layout>
+		<view class="app-details" v-if="loading">
+			
+			<view>
+				<app-quick-navigation></app-quick-navigation>
+			</view>
+			
+			<view class="app-banner">
+				<app-goods-banner
+						:picList="item.pic_url"
+	                    :isCart="isCart"
+						:share="item.share"
+						:goods_id="item.id"
+						:video-url="item.video_url"
+						sign="booking"
+				></app-goods-banner>
+			</view>
+
+			 <!-- 详情标题 -->
+			<view class="goods-name">
+				<app-name :name="item.name"></app-name>
+			</view>
+
+
+			<view class="app-price">
+				<app-goods-price
+				 		:is_vip_card_user="is_vip_card_user"
+				 		:discount='discount'
+						:goods="item"
+						:shareUrl="url"
+				></app-goods-price>
+			</view>
+			
+	        <view class="vip-card">
+	            <app-vip-card background="#fff" top="0" v-if="is_vip"></app-vip-card>
+	        </view>
+			
+			<view class="merchant-guarantee" v-if="item.services.length > 0">
+				<app-goods-service :list="item.services" :border="false"></app-goods-service>
+			</view>
+			
+			<view class="app-attr">
+				<app-attr :goods="item"
+				          :attrGroupList="item.attr_group"
+				          @attrtap="attrtap"
+				          :cartShow="cartShow"
+				          ref="attr"
+				          :selectAttr="selectAttr"
+				          buyText="立即预约"
+				          :previewUrl="previewUrl"
+				          :submitUrl="submitUrl"
+						  plugin="booking"
+				          :show="show"
+				>
+					<app-goods-attr
+							slot="button"
+							:attr-groups="item.attr_group"
+					        :selectAttr="selectAttr"
+							:attr="item.attr"
+					></app-goods-attr>
+				</app-attr>
+			</view>
+			
+			<view v-if="item.store.length > 0">
+				<app-store :store_id="item.store[0].id"
+				           :address="item.store[0].address"
+				           :name="item.store[0].name"
+				           :business_hours="item.store[0].business_hours"
+				           :storeNum="item.store.length"
+						   :goods_id="item.id"
+				></app-store>
+			</view>
+			
+			<view class="goods-detail">
+				<app-goods-detail :goods="item"></app-goods-detail>
+			</view>
+			
+			<view class="app-recommend">
+				<app-related-suggestion-product sign="booking" :list="list" ></app-related-suggestion-product>
+			</view>
+			
+			<view>
+				<app-empty-bottom backgroundColor="#f7f7f7" :height="Number(110)"></app-empty-bottom>
+			</view>
+			
+			<view class="app-buttons">
+				<app-iphone-x>
+					<view slot="empty-area">
+						<view class="app-reservation-button dir-left-nowrap" >
+							
+							<view class="app-back-home">
+								<app-jump-button form arrangement="column" open_type="redirect" url="/pages/index/index">
+									<image class="app-image" src="../../../static/image/icon/index.png"></image>
+									<text class="app-home">首页</text>
+								</app-jump-button>
+							</view>
+							<view class="app-jump" v-if="item.goods_num == 0" style="background-color: #CDCDCD;color: #fff;">已售罄</view>
+							<view class="app-jump" v-else>
+								<app-form-id @click="reservationNow">
+									立即预约
+								</app-form-id>
+							</view>
+						</view>
+					</view>
+				</app-iphone-x>
+			</view>
+		</view>
+	</app-layout>
+</template>
+
+<script>
+    import { mapState } from 'vuex';
+    import appGoodsBanner from '../../../components/page-component/goods/app-goods-banner.vue';
+	import appGoodsPrice from '../../../components/page-component/goods/app-goods-price.vue';
+	import appGoodsAttr from '../../../components/page-component/goods/app-goods-attr.vue';
+	import appAttr from '../../../components/page-component/app-attr/app-attr.vue';
+	import appStore from '../components/app-store.vue';
+	import appRelatedSuggestionProduct from '../../../components/page-component/app-related-suggestion-product/app-related-suggestion-product.vue';
+	import appGoodsDetail from '../../../components/page-component/goods/app-goods-detail.vue';
+    import appQuickNavigation from "../../../components/page-component/app-quick-navigation/app-quick-navigation.vue";
+    import appIphonexBottom from '../../../components/page-component/app-iphonex-bottom/app-iphonex-bottom.vue';
+    import appIphoneX from '../../../components/basic-component/app-iphone-x/app-iphone-x.vue';
+    import appGoodsService from '../../../components/page-component/goods/app-goods-service.vue';
+    import AppVipCard from '../../../components/page-component/app-vip-card/app-vip-card';
+	import appName from '../../../components/page-component/app-goods-detail/app-name.vue';
+    import appEmptyBottom from '../../../components/basic-component/app-empty-bottom/app-empty-bottom.vue';
+
+    export default {
+        name: 'details',
+	    components: {
+            'app-goods-banner': appGoodsBanner,
+		    'app-goods-price': appGoodsPrice,
+		    'app-goods-attr': appGoodsAttr,
+		    'app-attr': appAttr,
+		    'app-store': appStore,
+		    'app-related-suggestion-product': appRelatedSuggestionProduct,
+		    'app-goods-detail': appGoodsDetail,
+            'app-quick-navigation': appQuickNavigation,
+            'app-iphone-bottom': appIphonexBottom,
+		    'app-iphone-x': appIphoneX,
+            'app-goods-service': appGoodsService,
+			'app-name': appName,
+            'app-vip-card': AppVipCard,
+            'app-empty-bottom': appEmptyBottom,
+        },
+	    data() {
+            return {
+                item: null,
+                selectAttr: {},
+                activeIndex: 0,
+                list: [],
+                submitUrl: this.$api.book.order_submit,
+                previewUrl: this.$api.book.order_preview,
+                url: '',
+                cartShow: false,
+                isCart: false,
+                is_vip: false,
+                is_vip_card_user: 0,
+                discount: null,
+                show: 0,
+                loading: false,
+            }
+	    },
+	    onShareAppMessage() {
+	        return this.$shareAppMessage({
+	            path: '/plugins/book/goods/goods',
+	            title: this.item.app_share_title ? this.item.app_share_title : this.item.name,
+                imageUrl: this.item.app_share_pic ? this.item.app_share_pic : '',
+                params: {
+                    goods_id: this.item.id,
+                }
+	        });
+	    },
+        onLoad(options) {
+            let _this = this;
+
+			uni.getLocation({
+                type:'wgs84',
+                success:function(res){
+                    let goods_id = options.goods_id;
+                    _this.$request({
+                        url: _this.$api.book.detail,
+                        data: {
+                            goods_id: goods_id,
+                            latitude: res.latitude,
+                            longitude: res.longitude,
+                        },
+                    }).then(response => {
+                        if (response.code === 0) {
+                            _this.loading = true;
+                            _this.item = response.data.list;
+                            _this.item.id = _this.item.goods_id;
+                            _this.url = `${_this.$api.book.poster}&goods_id=${_this.item.goods_id}`;
+                           _this.requestFun(goods_id);
+	                        if(_this.item.vip_card_appoint.discount > 0) {
+	                            _this.is_vip = true;
+	                            _this.discount = _this.item.vip_card_appoint.discount
+	                        }
+	                        _this.is_vip_card_user = _this.item.vip_card_appoint.is_vip_card_user
+                        }
+                    })
+                },
+                fail:function(e){
+                	console.log(e);
+                    uni.showModal({
+	                    title: '提示',
+	                    content: '请开启位置权限',
+                        success: function() {
+	                        uni.navigateBack();
+                        }
+                    });
+                },
+                complete:function(res){
+                }
+            });
+        },
+	    methods: {
+            attrtap(data)  {
+                if (data !== null) {
+                    this.selectAttr = data;
+                } else {
+                    this.selectAttr = {};
+                }
+            },
+		    requestFun(goods_id) {
+               this.$request({
+                    url: this.$api.goods.new_recommend,
+                    data: {
+                        goods_id: goods_id,
+                        page: this.page,
+                    }
+                }).then(response => {
+                    if (response.code === 0) {
+                        if (response.data.list.length > 0) {
+                            this.list = [...this.list, ...response.data.list];
+                        } else {
+                            this.over = true;
+                        }
+                    }
+                })
+		    },
+            reservationNow() {
+                this.show = Math.random();
+            }
+	    },
+	    computed: {
+            ...mapState({
+                mall: state => state.mallConfig.mall,
+            }),
+            ...mapState('gConfig',{
+                iphone: (data) => {
+                    return data.iphone;
+                },
+                iphoneHeight: (state) =>{
+                    return  state.iphoneHeight;
+                },
+            })
+	    }
+    }
+</script>
+
+<style scoped lang="scss">
+
+    .vip-card {
+        padding: 0 #{20rpx};
+        background-color: #fff;
+    }
+	.merchant-guarantee {
+        margin-top: #{20rpx};
+	}
+	.app-details {
+		background-color: #f7f7f7;
+		width: #{750rpx};
+		padding-bottom: #{100rpx};
+		.app-banner {
+			width: 100%;
+		}
+		
+		.app-attr {
+			width: 100%;
+			margin-bottom: #{20rpx};
+			margin-top: #{20rpx};
+		}
+		.app-rich-evaluation {
+			background-color: white;
+			width: #{750rpx};
+			.app-nav {
+				width: #{750rpx};
+				height: #{100rpx};
+				border-bottom: #{1rpx} solid #e2e2e2;
+				>view {
+					text-align: center;
+				}
+				text {
+					text-align: center;
+					height: #{100rpx};
+					line-height: #{100rpx};
+					border-bottom-width: #{1rpx};
+					border-bottom-style: solid;
+					border-bottom-color: transparent;
+					display: inline-block;
+				}
+				.app-active-color {
+					border-bottom-color: #ff4544;
+					color: #ff4544;
+				}
+			}
+		}
+		.app-reservation-button {
+			width: #{750rpx};
+			height: #{100rpx};
+			background-color:white;
+			border-top: #{1rpx} solid #e9e9e9;
+			.app-back-home {
+				width: #{110rpx};
+				height: #{100rpx};
+				.app-image {
+					width: #{40rpx};
+					height: #{40rpx};
+				}
+				.app-home {
+					font-size: #{18rpx};
+					color: #888888;
+				}
+			}
+			.app-jump {
+				width: #{640rpx};
+				height: #{110rpx};
+				line-height: #{100rpx};
+				background-color: #ff4544;
+				color: #ffffff;
+				font-size: #{32rpx};
+				text-align: center;
+			}
+		}
+	}
+</style>

+ 147 - 0
plugins/book/index/index.vue

xqd
@@ -0,0 +1,147 @@
+<template>
+	<app-layout>
+		<view class="book-index">
+			<view class="page-width quick-navigation">
+				<app-quick-navigation></app-quick-navigation>
+			</view>
+			
+			<view class="page-width head-nav-list">
+				<app-head-nav-list
+					v-bind:catList="catList"
+					@click="changeStatus"
+					v-bind:cat_id="cat_id"
+				></app-head-nav-list>
+			</view>
+			
+			<view class="page-width product-list" v-if="goods_list.length > 0">
+				<app-product-list v-bind:goodsList="goods_list"></app-product-list>
+			</view>
+			
+			<view class="page-width no-goods" v-else>
+				<app-no-goods background="#f7f7f7"></app-no-goods>
+			</view>
+		</view>
+	</app-layout>
+</template>
+
+<script>
+	import appHeadNavList from '../components/app-head-nav-list.vue';
+	import appProductList from '../components/app-product-list.vue';
+    import appQuickNavigation from "../../../components/page-component/app-quick-navigation/app-quick-navigation.vue";
+	import appNoGoods from '../../../components/page-component/app-no-goods/app-no-goods.vue';
+	
+    export default {
+        name: "index",
+	   
+	    data() {
+            return {
+                catList: [
+	                {
+	                    name: '全部',
+		                id: 0
+	                }
+                ],
+                cat_id: 0,
+                page: 1,
+                goods_list: [],
+                page_count: 1,
+            }
+	    },
+	    onLoad(option) {
+            uni.showLoading({
+	            title: '加载中',
+            });
+            if (option.cat_id) {
+                this.cat_id = option.cat_id;
+            } else {
+                this.cat_id = this.catList[0].id;
+            }
+            this.request();
+            this.$request({
+	            url: this.$api.book.cats
+            }).then(response => {
+                uni.hideLoading();
+                if (response.code === 0) {
+                    this.catList = [...this.catList, ...response.data.cat];
+	                // this.request();
+                }
+            });
+            
+        },
+	    methods: {
+            
+            changeStatus(status) {
+	            this.page = 1;
+	            this.cat_id = status;
+	            this.goods_list = [];
+                this.request();
+            },
+		    
+		    async request() {
+                uni.showLoading({
+                    title: '加载中',
+                });
+                const res = await this.$request({
+                    url: this.$api.book.list,
+                    data: {
+                        page: this.page,
+                        cat_id: this.cat_id,
+                    }
+                });
+                uni.hideLoading();
+                if (res.code === 0) {
+                    this.dataProcessing(res.data);
+                }
+		    },
+
+            dataProcessing(data) {
+                for (let i = 0; i < data.list.length; i+=2) {
+                    if (i+1 !== data.list.length) {
+                        this.goods_list.push([data.list[i], data.list[i+1]]);
+                    } else {
+                        this.goods_list.push([data.list[i]]);
+                    }
+                }
+                this.page_count = data.pagination.page_count;
+            }
+	    },
+	    onReachBottom() {
+            if (this.page < this.page_count) {
+                this.page++;
+                this.request();
+            }
+        },
+	    
+        onShareAppMessage() {
+            return this.$shareAppMessage({
+                path: '/plugins/book/index/index',
+                title: this.$children[0].navigationBarTitle,
+            });
+        },
+	    
+        components: {
+            'app-head-nav-list': appHeadNavList,
+            'app-product-list': appProductList,
+            'app-quick-navigation': appQuickNavigation,
+	        'app-no-goods': appNoGoods,
+        },
+    }
+</script>
+
+<style scoped lang="scss">
+	
+	.head-nav-list {
+		position: fixed;
+		top: 0;
+		left: 0;
+		z-index: 1500;
+	}
+	
+	.product-list {
+		margin-top: #{100rpx};
+	}
+	
+	.no-goods {
+		margin-top: #{150rpx};
+	}
+</style>

+ 212 - 0
plugins/book/order/order.scss

xqd
@@ -0,0 +1,212 @@
+.order {
+  width: #{750rpx};
+  position: absolute;
+  top: 0;
+  left: 0;
+  height: 100%;
+  background-color: #f7f7f7;
+  .header {
+    height: #{88rpx};
+    width: 100%;
+    position: fixed;
+    top: 0;
+    left: 0;
+    z-index: 1000;
+    background-color: white;
+    border-bottom: #{1rpx} solid #e2e2e2;
+    .header-item {
+      line-height: #{88rpx};
+      text-align: center;
+      text {
+        display: inline-block;
+        height: #{87rpx};
+        line-height: #{86rpx};
+        font-size: #{32rpx};
+        color: #666666;
+        border-bottom-width: #{2rpx};
+        border-bottom-style: solid;
+        border-bottom-color:transparent;
+      }
+      .active-item {
+        color: #ff5c5c;
+        border-bottom-color: #ff5c5c;
+      }
+    }
+  }
+  .product-list {
+    margin-top: #{80rpx};
+    padding-top: #{20rpx};
+    .product {
+      width: 100%;
+      background-color: white;
+      margin-bottom: #{20rpx};
+      .top {
+        padding: #{24rpx};
+        height: #{248rpx};
+        .image-content {
+          width: #{200rpx};
+          height: #{200rpx};
+          position: relative;
+          >image {
+            width: #{200rpx};
+            height: #{200rpx};
+            border-radius: #{8rpx};
+          }
+          .tip-angle {
+            position: absolute;
+            top: 0;
+            left: 0;
+            background-color: #ff6868;
+            color: white;
+            font-size: #{26rpx};
+            border-top-left-radius: #{8rpx};
+            line-height: #{48rpx};
+            height: #{48rpx};
+            width: #{100rpx};
+            text-align: center;
+          }
+        }
+        .text-content {
+          width: #{750-24-200-24-24rpx};
+          height: #{200rpx};
+          .text-top {
+            margin-top: #{8rpx};
+            .name {
+              font-size: #{28rpx};
+              color: #353535;
+              word-break: break-all;
+              text-overflow: ellipsis;
+              display: -webkit-box;
+              -webkit-box-orient: vertical;
+              -webkit-line-clamp: 2;
+              overflow: hidden;
+            }
+            .attr {
+              font-size: #{24rpx};
+              color: #999999;
+              margin-top: #{20rpx};
+            }
+          }
+          .text-bottom {
+            margin-bottom: #{8rpx};
+            .original-price {
+              text-decoration:line-through;
+              font-size: #{26rpx};
+              color: #999999;
+              margin-right: #{24rpx};
+            }
+            .current-price {
+              font-size: #{32rpx};
+              color: #ff4544;
+            }
+          }
+        }
+      }
+      .bottom {
+        padding: 0 #{24rpx};
+        height: #{100rpx};
+        border-top: #{1rpx} solid #e2e2e2;
+        .but {
+          height: #{60rpx};
+          border-radius: #{30rpx};
+          border-style: solid;
+          border-width: #{1rpx};
+          font-size: #{32rpx};
+          line-height: #{60rpx};
+          text-align: center;
+          padding: 0 #{32rpx};
+        }
+        .no {
+          color: #666666;
+          border-color: #cdcdcd;
+          background-color: white;
+          margin-right: #{16rpx};
+        }
+        .ok {
+          background-color: #fff5f5;
+          color: #ff4544;
+          border-color: #ff4544;
+        }
+      }
+
+    }
+  }
+  .model {
+    position: fixed;
+    top: 0;
+    left: 0;
+    z-index: 1000;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0,0,0,.3);
+    .model-content {
+      width: #{620rpx};
+      border-radius: #{15rpx};
+      background-color: white;
+      text-align: center;
+      padding-top: #{20rpx};
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      .model-header {
+        font-size: #{32rpx};
+        color: #353535;
+
+        margin: #{64rpx 0};
+      }
+      .model-title-top {
+        font-size: #{32rpx};
+        text-align: center;
+        margin: #{20rpx 0 0rpx 0} ;
+        color: #353535;
+      }
+      .model-bottom {
+        border-top: #{1rpx} solid #e2e2e2;
+        .model-but {
+          width: #{309rpx};
+          height: #{88rpx};
+          line-height: #{88rpx};
+        }
+        .model-line {
+          width: #{2rpx};
+          height: #{32rpx};
+          background-color: #e2e2e2;
+        }
+      }
+    }
+    .model-use {
+      background-color: white;
+      width: #{600rpx};
+      box-sizing: border-box;
+      border-radius: #{8rpx};
+      margin: #{20rpx} 0;
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      z-index: 1700;
+      .image {
+        width: #{30rpx};
+        height: #{30rpx};
+        position: absolute;
+        right: #{32rpx};
+        top: #{32rpx};
+        background-size: 100% 100%;
+        background-repeat: no-repeat;
+        background-image: url("../../../static/image/icon/close.png");
+      }
+      .model-title {
+        font-size: #{32rpx};
+        margin-top: #{56rpx};
+        margin-bottom: #{64rpx};
+        text-align: center;
+      }
+      .model-image {
+        width: #{360rpx};
+        height: #{360rpx};
+        margin: #{0 120rpx 86rpx 120rpx};
+      }
+    }
+  }
+}

+ 346 - 0
plugins/book/order/order.vue

xqd
@@ -0,0 +1,346 @@
+<template>
+	<app-layout>
+		<view class="order">
+			<view class="header dir-left-nowrap">
+				<view class="header-item box-grow-1" @click="setActiveHeader(0)">
+					<app-form-id>
+						<text :class="{'active-item': status === 0}">
+							全部
+						</text>
+					</app-form-id>
+				</view>
+				<view class="header-item box-grow-1" @click="setActiveHeader(1)">
+					<app-form-id>
+						<text :class="{'active-item': status === 1}">
+							待支付
+						</text>
+					</app-form-id>
+				</view>
+				<view class="header-item box-grow-1" @click="setActiveHeader(2)">
+					<app-form-id>
+						<text :class="{'active-item': status === 2}">
+							待使用
+						</text>
+					</app-form-id>
+				</view>
+				<view class="header-item box-grow-1" @click="setActiveHeader(4)">
+					<app-form-id>
+						<text :class="{'active-item': status === 4}">
+							待评价
+						</text>
+					</app-form-id>
+				</view>
+			</view>
+			<view class="product-list" v-if="list.length > 0">
+				<view class="product" v-for="(item, index) in list" :key="index">
+					<view class="top dir-left-nowrap main-between" @click.stop="jump(item)">
+						<view class="image-content">
+							<image :src="item.detail[0].goods_info.pic_url"></image>
+							<view class="tip-angle" v-if="item.cancel_status == 2">
+								退款中
+							</view>
+							<view class="tip-angle" v-else-if="item.cancel_status == 1 && item.is_pay == 0">
+								已取消
+							</view>
+							<view class="tip-angle" v-else-if="item.cancel_status == 1">
+								已退款
+							</view>
+							<view class='tip-angle' v-else-if="item.is_comment == 1">
+								已评价
+							</view>
+							<view class="tip-angle" v-else-if="item.is_pay == 0">
+								待付款
+							</view>
+							<view class="tip-angle" v-else-if="item.is_confirm == 0">
+								待使用
+							</view>
+							<view class="tip-angle" v-else-if="item.is_confirm == 1">
+								已使用
+							</view>
+						</view>
+						<view class="text-content dir-top-nowrap main-between">
+							<view class="text-top">
+								<view class="name">
+									{{item.detail[0].goods_info.name}}
+								</view>
+								<view class="attr dir-left-nowrap">
+									<view :key="n" v-for="(attr, n) in item.detail[0].goods_info.attr_list">
+										{{attr.attr_group_name}}: {{attr.attr_name}}
+									</view>
+								</view>
+							</view>
+							<view class="text-bottom dir-left-nowrap main-right cross-center">
+								<view class="original-price">¥{{item.detail[0].total_original_price}}</view>
+								<view class="current-price">¥{{item.detail[0].total_price}}</view>
+							</view>
+						</view>
+					</view>
+					<view class="bottom dir-left-nowrap main-right cross-center"
+					      v-if="item.cancel_status === '0' && item.is_sale === '0' && item.sale_status === '0' && item.is_comment == 0"
+					>
+						<view class="but no" @click.stop="operationOrder(1, item)" v-if="item.cancel_status != 2 && item.is_pay == 1 && item.is_confirm == 0">
+							<app-form-id>
+								申请退款
+							</app-form-id>
+						</view>
+						<view class="but ok" @click.stop="operationOrder(2, item)" v-if="item.cancel_status != 2 && item.is_pay == 1 && item.is_confirm == 0">
+							<app-form-id>
+								立即使用
+							</app-form-id>
+						</view>
+						<view class="but ok" v-if="item.sale_status == 0 && item.is_sale == 0 && item.is_confirm == 1 && item.is_comment == 0">
+							<app-jump-button form :url="`/pages/order/appraise/appraise?id=${item.id}`">
+								去评价
+							</app-jump-button>
+						</view>
+						<view class="but no" @click.stop="operationOrder(3, item)" v-if="item.is_pay == 0">
+							<app-form-id>
+								申请取消
+							</app-form-id>
+						</view>
+						<view class="but ok"  v-if="item.is_pay == 0" @click.stop="operationOrder(4, item)">
+							<app-form-id>
+								去支付
+							</app-form-id>
+						</view>
+					</view>
+				</view>
+			</view>
+			<view class="model" v-if="model" @click.stop="model = false">
+				<view class="model-content" v-if="modelType !== 2">
+					<view class="model-title-top">提示</view>
+					<view class="model-header" v-if="modelType === 1">是否申请退款</view>
+					<view class="model-header" v-else-if="modelType === 3">是否申请取消订单</view>
+					<view class="model-header" v-else-if="modelType === 4">申请支付</view>
+					<view class="model-bottom dir-left-nowrap cross-center" v-if="modelType !== 2">
+						<view class="model-but" @click.stop="cancle">
+							<app-form-id>
+								取消
+							</app-form-id>
+						</view>
+						<view class="model-line"></view>
+						<view class="model-but" @click.stop="determine">
+							<app-form-id>
+								确定
+							</app-form-id>
+						</view>
+					</view>
+				</view>
+				<view class="model-use" v-if="modelType === 2">
+					<view class="image" @click.stop="model = false"></view>
+					<view class="model-title">核销码</view>
+					<image class="model-image" :src="writeOffChart" mode="aspectFill"></image>
+				</view>
+			</view>
+		</view>
+	</app-layout>
+</template>
+
+<script>
+    export default {
+        name: "order",
+	    data() {
+            return {
+                status: 0,
+	            list: [],
+	            page: 1,
+                over: false,
+                model: false,
+	            modelType: 0,
+	            setItem: {},
+                writeOffChart: '',
+            }
+	    },
+	    onLoad() {
+            this.request({
+                status: this.status,
+                page: this.page,
+            }).then(res => {
+                if (res) {
+                    this.list = res.list;
+                }
+            });
+	    },
+	    onReachBottom() {
+	        if (!this.over) {
+	            this.page+=1;
+	            this.pagingRequest({
+		            status: this.status,
+		            page: this.page,
+	            });
+	        }
+	    },
+	    methods: {
+            setActiveHeader(data) {
+                this.page = 1;
+                this.status = data;
+                this.over = false;
+                this.list = [];
+                this.request({
+	                status: this.status,
+	                page: this.page,
+                }).then(res => {
+                    if (res) {
+						this.list = res.list;
+                    }
+                })
+            },
+		    async request({status, page}) {
+                const res = await this.$request({
+	                url: this.$api.book.order_list,
+	                data: {
+                        status,
+                        page,
+	                }
+                });
+                if (res.code === 0) {
+                    return res.data;
+                } else {
+                    return false;
+                }
+		    },
+            operationOrder(number, data) {
+                this.model = true;
+                this.setItem = data;
+                switch (number) {
+	                case 1:
+                        this.modelType = 1;
+	                    break;
+	                case 2:
+                        uni.showLoading({
+                            mask: true,
+                            title: '加载中',
+                        });
+                        this.modelType = 2;
+                        this.$request({
+	                        url: this.$api.book.clerk_code,
+	                        data: {
+	                            id: data.id,
+	                        }
+                        }).then(res => {
+                            uni.hideLoading();
+                            if (res.code === 0) {
+                                this.writeOffChart = res.data.file_path;
+                            } else if (res.code === 1) {
+                                this.model = false;
+                                uni.showModal({
+	                                title: '提示',
+	                                content: res.msg,
+                                });
+                            }
+                        });
+	                    break;
+	                case 3:
+                        this.modelType = 3;
+	                    break;
+	                case 4:
+                        this.modelType = 4;
+	                    break;
+                }
+            },
+            pagingRequest({status, page}) {
+                this.request({
+	                status,
+	                page,
+                }).then(response => {
+                    if (response) {
+                        if (response.list.length > 0) {
+                            this.list = [...this.list, ...response.list];
+                        } else {
+                            this.over = true;
+                        }
+                    }
+                })
+            },
+            cancle() {
+                this.modelType = 0;
+                this.model = false;
+            },
+            determine() {
+                uni.showLoading({
+                    mask: true,
+                    title: '加载中',
+                });
+                switch (this.modelType) {
+                    case 1:
+                        this.$request({
+	                        url: this.$api.order.cancel,
+	                        data: {
+	                            id: this.setItem.id,
+	                        }
+                        }).then(res => {
+                            if (res.code === 0) {
+                                uni.hideLoading();
+                                this.model = false;
+                                for (let i = 0; i < this.list.length; i++) {
+                                    if (this.setItem.id === this.list[i].id) {
+                                        this.list[i].cancel_status = '2';
+                                        if (this.status === 2) {
+                                            this.$delete(this.list, i);
+                                        }
+                                    }
+                                }
+                            }
+                        });
+                        break;
+                    case 3:
+                        this.$request({
+                            url: this.$api.order.cancel,
+                            data: {
+                                id: this.setItem.id,
+                            }
+                        }).then(res => {
+                            if (res.code === 0) {
+                                uni.hideLoading();
+                                this.model = false;
+                                for (let i = 0; i < this.list.length; i++) {
+                                    if (this.setItem.id === this.list[i].id) {
+                                        this.list[i].cancel_status = '1';
+                                        this.list[i].is_pay = '0';
+                                        if (this.status === 1) {
+                                            this.$delete(this.list, i);
+                                        }
+                                    }
+                                }
+                            }
+                        });
+                        break;
+                    case 4:
+                        this.$request({
+	                        url: this.$api.order.list_pay_data,
+	                        data: {
+	                            id: this.setItem.id,
+	                        }
+                        }).then(res => {
+                            if (res.code === 0) {
+                                uni.hideLoading();
+                                this.model = false;
+                                this.$payment.pay(res.data.id).then(() => {
+                                    for (let i = 0; i < this.list.length; i++) {
+                                        if (this.setItem.id === this.list[i].id) {
+                                            this.list[i].is_pay = '1';
+                                            if (this.status === 1) {
+                                                this.$delete(this.list, i);
+                                            }
+                                        }
+                                    }
+                                }).catch(() => {
+                                })
+                            }
+                        });
+                        break;
+                }
+            },
+            jump(data) {
+                this.$jump({
+                    open_type: 'navigate',
+	                url: `/plugins/book/orderDetails/orderDetails?id=${data.id}`
+                });
+            }
+	    }
+    }
+</script>
+
+<style scoped lang="scss">
+	@import './order.scss';
+</style>

+ 304 - 0
plugins/book/orderDetails/orderDetails.vue

xqd
@@ -0,0 +1,304 @@
+<template>
+	<app-layout>
+		<view class="app-order-details">
+			<app-write-off-code :hidden="hidden" :itemId="item.id" @hiden="hidden = false"></app-write-off-code>
+			<view v-if="refundBoolean">
+				<app-prompt-box @click="close" text="是否确认申请退款该订单"></app-prompt-box>
+			</view>
+			<view v-if="payBoolean">
+				<app-prompt-box @click="goPay" text="是否确认支付该订单"></app-prompt-box>
+			</view>
+			<view v-if="cancelBoolean"></view>
+			<view class="app-image-title dir-left-nowrap">
+				<image class="app-image" :src="item.store.cover_url"></image>
+				<view class="app-content dir-top-nowrap">
+					<text class="app-content-title">{{item.store.name}}</text>
+					<view class="app-prices dir-left-nowrap main-right cross-center">
+						<text class="app-old-price">{{item.total_goods_original_price}}</text>
+						<text class="app-new-price">{{item.total_pay_price}}</text>
+					</view>
+				</view>
+			</view>
+			<text class="app-title">门店信息</text>
+			<view class="app-store">
+				<app-store :address="item.store.address" :business_hours="item.store.business_hours" :storeNum="item.store_list.length" :goods_id="item.id" :store_id="item.store.id"  :name="item.store.name" :sotreNum="item.store.length" :title="title" :borderStyle="borderStyle" :icon="icon"></app-store>
+			</view>
+			<text class="app-title">订单信息</text>
+			<view class="app-order-information dir-top-nowrap main-left">
+				<text>姓名: {{item.name}}</text>
+				<text>手机号: {{item.mobile}}</text>
+				<text>订单号: {{item.order_no}}</text>
+				<text>下单时间: {{item.created_at}}</text>
+			</view>
+			<text class="app-title" v-if="item.order_form.length > 0">其他信息</text>
+			<view class="app-other" v-if="item.order_form.length > 0">
+				<block v-for="(it, index) in item.order_form" :key="index">
+					<template v-if="it.key === 'img_upload'">
+						<view class="app-in dir-top-nowrap">
+							<text class="app-top">{{it.label}}</text>
+							<image class="app-image" :src="it.value"></image>
+						</view>
+					</template>
+					<template v-else>
+						<view class="app-in dir-top-nowrap"  v-if="it.value" :class="{'app-border': item.order_form.length-1 !== index}" >
+							<text class="app-top" >{{it.label}}</text>
+							<text class="app-bottom" >{{it.value}}</text>
+						</view>
+					</template>
+				</block>
+			</view>
+			<view class="empty" v-if="item.cancel_status == 0  && item.is_sale == 0"></view>
+			<view class="app-buttons dir-left-nowrap main-right cross-center" v-if="item.cancel_status == 0  && item.is_sale == 0">
+				<view class="app-button" v-if="item.is_pay == 0">
+					<app-form-id >
+						<button class="app-button app-red" @click="payBoolean = true">去支付</button>
+					</app-form-id>
+				</view>
+				<view class="app-button" v-if="item.is_pay == 0">
+					<app-form-id >
+						<button class="app-button app-white">申请取消</button>
+					</app-form-id>
+				</view>
+				<view class="app-button" v-if="item.is_confirm == 1" @click="evaluation">
+					<app-form-id>
+						<button class="app-button  app-red" >去评价</button>
+					</app-form-id>
+				</view>
+				<view class="app-button" v-if="item.cancel_status != 2 && item.is_pay == 1 && item.is_confirm == 0">
+					<app-form-id>
+						<view class="app-button app-red" @click="useImmediately">立即使用</view>
+					</app-form-id>
+				</view>
+				<view class="app-button" v-if="item.cancel_status != 2 && item.is_pay == 1 && item.is_confirm == 0">
+					<app-form-id >
+						<view class="app-button app-white" @click="refundBoolean = true">申请退款</view>
+					</app-form-id>
+				</view>
+			</view>
+		</view>
+	</app-layout>
+</template>
+
+<script>
+    import appStore from '../components/app-store.vue';
+    import appPromptBox from '../../../components/basic-component/app-prompt-box/app-prompt-box.vue';
+    import appWriteOffCode from '../components/app-write-off-code.vue';
+    
+	let borderStyle = false;
+	let icon = false;
+	let title = false;
+    export default {
+        name: 'orderDetails',
+	    components: {
+            'app-store': appStore,
+		    'app-prompt-box': appPromptBox,
+            'app-write-off-code': appWriteOffCode,
+	    },
+	    data() {
+            return {
+                item: null,
+                file_path: '',
+	            hidden: false,
+                refundBoolean: false,
+	            payBoolean: false,
+                cancelBoolean: false,
+            }
+	    },
+        onLoad(options) {
+            this.request(options);
+        },
+	    methods: {
+            request(options) {
+                this.$request({
+                    url: this.$api.book.order_detail,
+                    data: {
+                        id: options.id,
+                    }
+                }).then(response => {
+                    this.item = response.data.detail;
+                })
+            },
+            useImmediately() {
+                this.hidden = true;
+            },
+            close(boolean) {
+                if (boolean) {
+                    this.$request({
+	                    url: this.$api.order.cancel,
+	                    data: {
+	                        id: this.item.id
+	                    }
+                    }).then(response => {
+                        if (response.code === 0) {
+                            this.refundBoolean = false;
+                            this.request({
+	                            id: this.item.id
+                            });
+                        }
+                    });
+                } else {
+                    this.refundBoolean = false;
+                }
+            },
+            goPay(boolean) {
+                this.payBoolean = false;
+                if (boolean) {
+                   this.$request({
+	                   url: this.$api.order.list_pay_data,
+	                   data: {
+	                       id: this.item.id
+	                   }
+                   }).then(response => {
+                       if (response.code === 0) {
+                           this.$payment.pay(response.data.id).then(msg => {
+                               // 支付成功
+	                           this.item.is_pay = 1;
+                           }).catch(msg => {
+                               // 支付失败
+                           });
+                       } else {
+                       
+                       }
+                   })
+                } else {
+                    this.payBoolean = false;
+                }
+            },
+            evaluation() {
+				uni.navigateTo({
+					url: `/pages/order/appraise/appraise?id=${this.item.id}`
+				});
+            }
+	    }
+    }
+</script>
+
+<style scoped lang="scss">
+	.app-order-details {
+		background-color: #f7f7f7;
+		width: #{750rpx};
+		padding: #{20rpx} #{24rpx};
+		
+		.app-title {
+			display: inline-block;
+			margin-top: #{32rpx};
+			margin-bottom: #{24rpx};
+			color: #999999;
+			font-size: #{26rpx};
+		}
+		>view {
+			width: #{750-48rpx};
+			border-radius: #{16rpx};
+			background-color: white;
+		}
+		.app-image-title {
+			padding: #{24rpx};
+			.app-image {
+				width: #{208rpx};
+				height: #{160rpx};
+			}
+			.app-content {
+				width: #{750-48-48-24-208rpx};
+				margin-left: #{24rpx};
+				height: #{160rpx};
+				.app-content-title {
+					display: inline-block;
+					margin-top: #{10rpx};
+					font-size: #{28rpx};
+					color: #353535;
+					word-break: break-all;
+					text-overflow: ellipsis;
+					display: -webkit-box;
+					-webkit-box-orient: vertical;
+					-webkit-line-clamp: 2;
+					overflow: hidden;
+					height: #{64rpx};
+					width: 100%;
+				}
+				.app-prices {
+					padding-top: #{50rpx};
+					>text:before {
+						content: '¥';
+					}
+					.app-old-price {
+						color: #a4a4a4;
+						font-size: #{24rpx};
+						text-decoration:line-through;
+					}
+					.app-new-price {
+						margin-left: #{24rpx};
+						font-size: #{32rpx};
+						color: #ff4544;
+					}
+				}
+			}
+		}
+		.app-order-information {
+			padding: #{28rpx} #{24rpx} #{12rpx} #{24rpx};
+			>text {
+				font-size: #{28rpx};
+				color: #353535;
+				margin-bottom: #{16rpx};
+			}
+		}
+		.app-other {
+			padding: 0 #{24rpx};
+			.app-in {
+				padding: #{28rpx} 0;
+				font-size: #{28rpx};
+				.app-top {
+					margin-bottom: #{24rpx};
+					color: #999999;
+				}
+				.app-bottom {
+					color: #353535;
+				}
+			}
+			.app-border {
+				border-bottom: #{1rpx} solid #e2e2e2;
+			}
+			.app-image {
+				width: #{150rpx};
+				height: #{150rpx};
+				border-radius: #{8rpx};
+			}
+		}
+		.app-buttons {
+			height: #{102rpx};
+			width: #{750rpx};
+			background-color: white;
+			border-top: #{1rpx} solid #e2e2e2;
+			position: fixed;
+			left: 0;
+			bottom: 0;
+			>view {
+				margin-right: #{15rpx};
+			}
+			.app-button {
+				height: #{60rpx};
+				line-height: #{60rpx};
+				font-size: #{28rpx};
+				border-radius: #{25rpx};
+				display: inline-block;
+			}
+			.app-red {
+				border: #{1rpx} solid #ff4544;
+				background-color: #fff5f5;
+				color: #ff4544;
+				padding: 0 #{30rpx};
+			}
+			.app-white {
+				background-color: white;
+				border: #{1rpx} solid #d4d4d4;
+				color: #565656;
+				padding: 0 #{30rpx};
+			}
+		}
+	}
+
+	.empty {
+		height: #{102rpx};
+		width: #{750rpx};
+		background-color: #f7f7f7 !important;
+	}
+</style>

+ 178 - 0
plugins/book/reservationList/reservationList.vue

xqd
@@ -0,0 +1,178 @@
+<template>
+	<app-layout>
+		<view class="app-reservationList">
+			<app-prompt-box v-if="hidden" :text="text" @click="confirmNegative"></app-prompt-box>
+			<app-write-off-code  :hidden="hiddenCode" :itemId="itemId" @hiden="hiddenCode = false"></app-write-off-code>
+			<view class="app-nav">
+				<app-head-navigation @click="classification"></app-head-navigation>
+			</view>
+			<view class="app-reservation">
+				<app-reservation-form @click="funHandler" v-for="(item, index) in list" :key="index" :item="item"></app-reservation-form>
+			</view>
+		</view>
+	</app-layout>
+</template>
+
+<script>
+    import appHeadNavigation from '../components/app-head-navigation.vue';
+    import appReservationForm from '../components/app-reservation-form.vue';
+	import appPromptBox from '../../../components/basic-component/app-prompt-box/app-prompt-box.vue';
+	import appWriteOffCode from '../components/app-write-off-code.vue';
+	
+    export default {
+        name: 'reservationList',
+	    components: {
+            'app-head-navigation': appHeadNavigation,
+		    'app-reservation-form': appReservationForm,
+		    'app-prompt-box': appPromptBox,
+		    'app-write-off-code': appWriteOffCode,
+	    },
+	    data() {
+            return {
+                list: [],
+	            page: 1,
+                over: false,
+	            status: 0,
+	            hidden: false,
+	            text: '',
+                confirm: false,
+	            back: '',
+	            item: null,
+                file_path: '',
+                hiddenCode: false,
+                itemId: '-1'
+            }
+	    },
+        onLoad(options) {
+            this.request(this.page, this.status);
+        },
+	    methods: {
+            classification(status) {
+                this.list = [];
+                this.status = status;
+                this.over = false;
+                this.page = 1;
+                this.request(this.page, status);
+            },
+		    request(page, status) {
+                this.$request({
+                    url: this.$api.book.order_list,
+                    data: {
+                        page: page,
+                        status: status,
+                    }
+                }).then(response => {
+                    if (response.code === 0) {
+                        if (response.data.list.length === 0) {
+                            this.over = true;
+                        } else {
+                            this.list = [...this.list, ...response.data.list];
+                        }
+                    }
+                }).catch(() => {
+                })
+		    },
+            confirmNegative(data) {
+                if (data) {
+                    this[this.back]();
+                } else {
+                    this.hidden = false;
+                }
+            },
+            funHandler(data, item) {
+                this.back = data;
+                this.item = item;
+                if (data === 'refund') {
+                    this.text = '是否申请退款';
+                    this.hidden = true;
+                } else if (data === 'cancel') {
+                    this.text = '是否申请取消订单';
+                    this.hidden = true;
+                } else if (data === 'use') {
+                    this[this.back]();
+                } else if (data === 'pay') {
+                    this.hidden = true;
+                    this.text = '申请支付';
+                }
+            },
+            refund() {
+                this.$request({
+                    url: this.$api.order.cancel,
+                    data: {
+                        id: this.item.id
+                    }
+                }).then(response => {
+                    if (response.code === 0) {
+	                    for (let i = 0; i < this.list.length; i++) {
+	                        if (this.list[i].id === this.item.id) {
+                                this.$delete(this.list, i);
+	                        }
+	                    }
+                        this.hidden = false;
+                    }
+                });
+            },
+            cancel() {
+                this.$request({
+	                url: this.$api.order.cancel,
+	                data: {
+	                    id: this.item.id,
+	                }
+                }).then(response => {
+                    if (response.code === 0) {
+                        for (let i = 0; i < this.list.length; i++) {
+                            if (this.list[i].id === this.item.id) {
+	                            this.$delete(this.list, i);
+                            }
+                        }
+                        this.hidden = false;
+                    }
+                })
+            },
+            use() {
+                this.itemId = this.item.id;
+                this.hiddenCode = true;
+            },
+            pay() {
+                this.hidden = false;
+                this.$request({
+                    url: this.$api.order.list_pay_data,
+                    data: {
+                        id: this.item.id
+                    }
+                }).then(response => {
+                    if (response.code === 0) {
+                        this.$payment.pay(response.data.id).then(() => {
+                            for (let i = 0; i < this.list.length; i++) {
+                                if (this.list[i].id === this.item.id) {
+                                    this.$delete(this.list, i);
+                                }
+                            }
+                        }).catch(() => {
+                        });
+                    }
+                })
+            }
+	    },
+        onReachBottom() {
+            if (!this.over) {
+                this.page+=1;
+                this.request(this.page, this.status);
+            }
+        }
+    }
+</script>
+
+<style scoped lang="scss">
+	.app-reservationList {
+		.app-nav {
+			position: fixed;
+			top: 0;
+			z-index: 1500;
+		}
+		.app-reservation {
+			margin-top:#{80rpx};
+			background-color: #f7f7f7;
+		}
+	}
+</style>