zhwl-miniapp/pages/hotel/submitOrder.vue
2025-06-26 12:38:35 +08:00

322 lines
11 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>