322 lines
11 KiB
Vue
322 lines
11 KiB
Vue
|
<template>
|
|||
|
<view class="waper">
|
|||
|
<u-navbar :autoBack="true" :placeholder="true" bgColor="#FFFFFF">
|
|||
|
<view slot='center' style="font-size: 36rpx; font-weight: bold;">
|
|||
|
提交订单
|
|||
|
</view>
|
|||
|
</u-navbar>
|
|||
|
<view class="content">
|
|||
|
<view class="order">
|
|||
|
<view class="residue">
|
|||
|
<view class="label">支付剩余时间</view>
|
|||
|
<view class="time">{{secondsToTime(timeNum)}}</view>
|
|||
|
</view>
|
|||
|
<view class="price">
|
|||
|
<text class="unit">¥</text>{{detail.totalAmount}}
|
|||
|
</view>
|
|||
|
<view class="specs">
|
|||
|
<view class="tags_box">
|
|||
|
<view class="tag" v-if="detail.roomClassifyName">{{detail.roomClassifyName}}</view>
|
|||
|
<view class="tag" v-if="detail.roomQuantity">{{detail.roomQuantity}}间</view>
|
|||
|
<view class="tag" v-if="detail.inDateTime">{{detail.inDateTime}}入住</view>
|
|||
|
</view>
|
|||
|
<view class="detailed" @click="showPopupDetailed = true">
|
|||
|
<text>订单明细</text>
|
|||
|
<u-icon name="arrow-right" color="#03AE80" size="28rpx"></u-icon>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view class="pay">
|
|||
|
<view class="item" v-for="(item, index) in payList" :key="index" v-if="getiPass(item)" @click="changePay(item.dictValue)">
|
|||
|
<image :src="'../../static/image/mine/pay' + (item.paymentScene == 'WECHAT_MINI_PROGRAM' ? '2' : item.dictValue) + '.png'" mode=""></image>
|
|||
|
<view class="title">{{item.paymentScene == 'WECHAT_MINI_PROGRAM' ? '微信' : item.dictLabel}}
|
|||
|
<text class="balance" v-if="item.dictValue == 7">(可用¥{{cardInfo.balance}})</text>
|
|||
|
</view>
|
|||
|
<view class="noChange" v-if="payType != item.dictValue"></view>
|
|||
|
<view class="isChange" v-if="payType == item.dictValue">
|
|||
|
<u-icon name="checkmark" color="#fff" size="28rpx"></u-icon>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view class="footer" :style="'padding-bottom: ' + windowBottom + 'px;'">
|
|||
|
<view class="btn" @click="confirmPay">确认支付</view>
|
|||
|
</view>
|
|||
|
<u-popup :show="showPopupDetailed" :round="10" mode="bottom">
|
|||
|
<view class="detailed_con">
|
|||
|
<view class="head">
|
|||
|
<view class="title">明细</view>
|
|||
|
<view class="close" @click="showPopupDetailed = false">
|
|||
|
<u-icon name="close" color="#000000" size="36rpx" />
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view class="add">
|
|||
|
<view class="label">订单合计</view>
|
|||
|
<view class="all">共<text>¥{{detail.totalAmount}}</text></view>
|
|||
|
</view>
|
|||
|
<view class="row">
|
|||
|
<view class="col">
|
|||
|
<view class="key">房费 </view>
|
|||
|
<view class="value">¥{{detail.totalAmount}}</view>
|
|||
|
</view>
|
|||
|
<view class="col" v-for="(item, index) in detail.roomChargeDetails" :key="index">
|
|||
|
<view class="key">{{item.stayDate}}</view>
|
|||
|
<view class="value">{{item.roomQuantity}}x ¥{{item.roomPrice}}</view>
|
|||
|
</view>
|
|||
|
<view class="col" v-if="detail.stayType !== 'HOURLY'">
|
|||
|
<view class="key">{{detail.outDateTime}}</view>
|
|||
|
<view class="value"></view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view class="footer" :style="'padding-bottom: ' + windowBottom + 'px;'">
|
|||
|
<view class="btn" @click="confirmPay">确认支付</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</u-popup>
|
|||
|
</view>
|
|||
|
</template>
|
|||
|
|
|||
|
<script>
|
|||
|
export default {
|
|||
|
data () {
|
|||
|
return {
|
|||
|
windowBottom: 0,
|
|||
|
id: '',
|
|||
|
hotelId: '',
|
|||
|
detail: {},
|
|||
|
timeNum: 0,
|
|||
|
timer: null,
|
|||
|
payList: [],
|
|||
|
payType: null,
|
|||
|
cardInfo: null,
|
|||
|
showPopupDetailed: false,
|
|||
|
configData: null,
|
|||
|
source: ''
|
|||
|
}
|
|||
|
},
|
|||
|
onLoad (options) {
|
|||
|
this.id = options.id;
|
|||
|
this.hotelId = options.hotelId;
|
|||
|
this.source = options.source;
|
|||
|
this.getDetail();
|
|||
|
this.windowBottom = this.$safeAreaBottom || uni.upx2px(13);
|
|||
|
},
|
|||
|
onUnload () {
|
|||
|
clearInterval(this.timer);
|
|||
|
this.timer = null;
|
|||
|
},
|
|||
|
methods: {
|
|||
|
async getDetail() {
|
|||
|
let res=await this.$http.hotelOrderDetail(this.id);
|
|||
|
res.data.inDateTime = this.$moment(res.data.inDateTime).format("MM月DD日");
|
|||
|
res.data.outDateTime = this.$moment(res.data.outDateTime).format("YYYY-MM-DD");
|
|||
|
this.detail=res.data;
|
|||
|
|
|||
|
this.configData = uni.getStorageSync('configData');
|
|||
|
let creaetdTime = parseInt(new Date(res.data.createTime).getTime() / 1000);
|
|||
|
let nowtime = parseInt(new Date().getTime() / 1000);
|
|||
|
if ((creaetdTime + this.configData.expirationTime * 60) >= nowtime) {
|
|||
|
this.timeNum = (creaetdTime + this.configData.expirationTime * 60) - nowtime;
|
|||
|
this.setIntervalFn()
|
|||
|
}
|
|||
|
|
|||
|
this.payList = this.configData.payConfig;
|
|||
|
if (this.payList.length) {
|
|||
|
this.payType = this.payList[0].dictValue;
|
|||
|
}
|
|||
|
let cardInfo = await this.$http.getPrepaidCard();
|
|||
|
this.cardInfo = cardInfo.data;
|
|||
|
},
|
|||
|
secondsToTime(seconds) {
|
|||
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|||
|
const remainingSeconds = seconds % 60;
|
|||
|
return (minutes >= 10 ? minutes : '0' + minutes) + ":" + (remainingSeconds >= 10 ? remainingSeconds : '0' + remainingSeconds);
|
|||
|
},
|
|||
|
setIntervalFn () {
|
|||
|
clearInterval(this.timer);
|
|||
|
this.timer = setInterval(() => {
|
|||
|
if (this.timeNum <= 0) {
|
|||
|
clearInterval(this.timer)
|
|||
|
uni.redirectTo({ url: `/pages/hotelOrder/detail?id=` + this.detail.id });
|
|||
|
}
|
|||
|
this.timeNum --;
|
|||
|
}, 1000)
|
|||
|
},
|
|||
|
changePay(e) {
|
|||
|
this.payType = e;
|
|||
|
},
|
|||
|
getiPass(e) {
|
|||
|
if (e.dictValue != 7) {
|
|||
|
return true;
|
|||
|
} else {
|
|||
|
if (this.cardInfo) {
|
|||
|
return true;
|
|||
|
} else {
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
async confirmPay() {
|
|||
|
uni.showLoading({ mask: true });
|
|||
|
let parmas = {};
|
|||
|
parmas.id = this.detail.id;
|
|||
|
parmas.paymentMethod = this.payType;
|
|||
|
if (this.detail.totalAmount <= 0) {
|
|||
|
parmas.paymentMethod = '4';
|
|||
|
}
|
|||
|
parmas.paymentScene = null;
|
|||
|
let f = this.payList.find(m => m.dictValue == parmas.paymentMethod);
|
|||
|
if (f) parmas.paymentScene = f.paymentScene;
|
|||
|
parmas.authCode = this.cardInfo ? this.cardInfo.accountNo : '';
|
|||
|
let info = await this.$http.hotelPayment(parmas);
|
|||
|
|
|||
|
if (parmas.paymentMethod == '7') {
|
|||
|
uni.hideLoading();
|
|||
|
if (info.data.errorMessage) {
|
|||
|
uni.showToast({ mask: true, title: info.data.errorMessage, icon: 'none' })
|
|||
|
setTimeout(() => {
|
|||
|
this.goPage();
|
|||
|
}, 1500)
|
|||
|
} else {
|
|||
|
uni.showToast({ mask: true, title: '支付成功', icon: 'success' })
|
|||
|
setTimeout(() => {
|
|||
|
uni.redirectTo({ url: `/pages/hotel/paySuccess?id=${this.id}&hotelId=${this.hotelId}&source=${this.source}` })
|
|||
|
}, 1500)
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (info.data.payUrl) {
|
|||
|
uni.hideLoading();
|
|||
|
let str = info.data.payUrl;
|
|||
|
let newStr = str.replace("?", "&");
|
|||
|
uni.showToast({ mask: true, title: '小程序不支持此支付方式', icon: 'none' })
|
|||
|
} else if (info.data.tradeSession) {
|
|||
|
const prepayId = JSON.parse(info.data.tradeSession);
|
|||
|
uni.requestPayment({
|
|||
|
provider: 'wxpay',
|
|||
|
timeStamp: prepayId.timeStamp,
|
|||
|
nonceStr: prepayId.nonceStr,
|
|||
|
package: prepayId.packageValue,
|
|||
|
signType: prepayId.signType,
|
|||
|
paySign: prepayId.paySign,
|
|||
|
success: (res) => {
|
|||
|
uni.hideLoading();
|
|||
|
uni.showToast({ mask: true, title: '支付成功', icon: 'success' })
|
|||
|
setTimeout(() => {
|
|||
|
uni.redirectTo({ url: `/pages/hotel/paySuccess?id=${this.id}&hotelId=${this.hotelId}&source=${this.source}` })
|
|||
|
}, 1500)
|
|||
|
},
|
|||
|
fail: (err) => {
|
|||
|
uni.hideLoading();
|
|||
|
uni.showToast({ mask: true, title: '支付取消', icon: 'none' })
|
|||
|
setTimeout(() => {
|
|||
|
this.goPage();
|
|||
|
}, 1500)
|
|||
|
}
|
|||
|
});
|
|||
|
} else {
|
|||
|
uni.showToast({ mask: true, title: '支付失败', icon: 'none' });
|
|||
|
}
|
|||
|
},
|
|||
|
goPage() {
|
|||
|
if (this.source == 'order') {
|
|||
|
uni.navigateBack();
|
|||
|
} else {
|
|||
|
uni.redirectTo({ url: `/pages/hotelOrder/detail?id=${this.id}` });
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
<style lang="scss">
|
|||
|
.waper { min-height: 100vh; background-color: #F6F6F6; }
|
|||
|
.content{
|
|||
|
width: 100%; box-sizing: border-box; padding: 24rpx;
|
|||
|
.order {
|
|||
|
background: #FFFFFF; border-radius: 10rpx; padding: 32rpx 24rpx; box-sizing: border-box;
|
|||
|
.residue {
|
|||
|
display: flex; align-items: center;
|
|||
|
.label { font-size: 28rpx; color: rgba(0,0,0,0.45); margin-right: 10rpx; }
|
|||
|
.time { font-weight: 500; font-size: 32rpx; color: rgba(0,0,0,0.85); }
|
|||
|
}
|
|||
|
.price {
|
|||
|
margin: 12rpx 0 0 3rpx; font-weight: bold; font-size: 56rpx; color: #E54042;
|
|||
|
.unit { font-weight: 400; font-size: 28rpx; }
|
|||
|
}
|
|||
|
.specs {
|
|||
|
display: flex; align-items: center; justify-content: space-between; margin-top: 12rpx;
|
|||
|
.tags_box {
|
|||
|
display: flex; align-items: center; flex-wrap: wrap; flex: 1;
|
|||
|
.tag {
|
|||
|
padding: 0 18rpx; position: relative; font-size: 28rpx; color: rgba(0,0,0,0.45);
|
|||
|
&::after{ content: ""; width: 1rpx; height: 23rpx; background: #ECEAEA; position: absolute; right: 0; top: 50%; transform: translateY(-50%); }
|
|||
|
&:first-child { padding-left: 0; }
|
|||
|
&:last-child {
|
|||
|
padding-right: 0;
|
|||
|
&::after {display: none;}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
.detailed {
|
|||
|
display: flex; align-items: center; width: 140rpx;
|
|||
|
text { font-size: 24rpx; color: #03AE80; margin-right: 4rpx; }
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
.pay {
|
|||
|
background: #FFFFFF; border-radius: 10rpx; margin-top: 32rpx; padding: 0 24rpx; box-sizing: border-box;
|
|||
|
.item {
|
|||
|
height: 112rpx; border-bottom: 1rpx solid #E8E8E8; display: flex; align-items: center;
|
|||
|
&:last-child { border-bottom: none; }
|
|||
|
image { width: 48rpx; height: 48rpx; margin-right: 16rpx; }
|
|||
|
.title {
|
|||
|
flex: 1; font-size: 30rpx; color: rgba(0,0,0,0.85);
|
|||
|
.balance { font-size: 28rpx; color: rgba(0,0,0,0.45); }
|
|||
|
}
|
|||
|
.noChange { width: 42rpx; height: 42rpx; border-radius: 50%; border: 1rpx solid rgba(0,0,0,0.2); }
|
|||
|
.isChange {
|
|||
|
width: 42rpx; height: 42rpx; border-radius: 50%; background-color: #03AE80; position: relative;
|
|||
|
::v-deep .u-icon {
|
|||
|
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
.footer {
|
|||
|
width: 100%; background: #FFFFFF; padding-top: 13rpx; box-sizing: border-box; position: fixed; left: 0; bottom: 0; display: flex; align-items: center; justify-content: center;
|
|||
|
.btn { width: 654rpx; height: 90rpx; background: #03AE80; border-radius: 49rpx; line-height: 90rpx; text-align: center; font-weight: 500; font-size: 32rpx; color: #FFFFFF; }
|
|||
|
}
|
|||
|
.detailed_con {
|
|||
|
padding: 32rpx 0 150rpx; position: relative;
|
|||
|
.head {
|
|||
|
position: relative; text-align: center; margin: 0 32rpx 30rpx;
|
|||
|
.title { font-weight: 500; font-size: 34rpx; color: rgba(0,0,0,0.85); }
|
|||
|
.close { position: absolute; right: 0; top: 50%; transform: translateY(-50%); }
|
|||
|
}
|
|||
|
.add {
|
|||
|
padding: 54rpx 0 24rpx; margin: 0 32rpx; display: flex; align-items: center; justify-content: space-between; border-bottom: 1rpx solid #ECEAEA;
|
|||
|
.label { font-size: 32rpx; color: rgba(0,0,0,0.85); }
|
|||
|
.all {
|
|||
|
font-size: 28rpx; color: rgba(0,0,0,0.85);
|
|||
|
text { font-weight: bold; font-size: 28rpx; color: #E54042; }
|
|||
|
}
|
|||
|
}
|
|||
|
.row {
|
|||
|
padding: 0 32rpx;
|
|||
|
.col {
|
|||
|
display: flex; align-items: center; justify-content: space-between; margin-bottom: 8rpx;
|
|||
|
&:first-child {
|
|||
|
margin: 24rpx 0 13rpx;
|
|||
|
.key, .value { font-weight: 500; font-size: 28rpx; color: rgba(0,0,0,0.85); }
|
|||
|
}
|
|||
|
.key, .value { font-size: 28rpx; color: rgba(0,0,0,0.65); }
|
|||
|
}
|
|||
|
}
|
|||
|
.footer {
|
|||
|
width: 100%; background: #FFFFFF; padding-top: 13rpx; box-sizing: border-box; position: fixed; left: 0; bottom: 0; display: flex; align-items: center; justify-content: center;
|
|||
|
.btn { width: 654rpx; height: 90rpx; background: #03AE80; border-radius: 49rpx; line-height: 90rpx; text-align: center; font-weight: 500; font-size: 32rpx; color: #FFFFFF; }
|
|||
|
}
|
|||
|
}
|
|||
|
</style>
|