Files
zhwl-miniapp/pages/scenic/ticktOrderConfirm.vue
2025-06-26 12:38:35 +08:00

698 lines
26 KiB
Vue
Raw 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" :style="'padding-bottom: ' + windowBottom + 'px;'">
<u-navbar :autoBack="true" :bgColor="scrollTop > 20 ? 'white' : 'transparent'"
:leftIconColor="scrollTop > 20 ? '#303133' : '#fff'">
<view slot='center' class="navbar_title" :style="{color: scrollTop > 20 ? '#303133' : '#fff'}">确认订单</view>
</u-navbar>
<view class="banner"></view>
<view class="waper_box" v-if="pageData">
<view class="header-box">
<view class="header-title">{{pageData.ticketName}}</view>
<view class="text-box">
<view class="label">观影日期</view>
<view class="text-content">{{pageData.hallTime}}</view>
</view>
<view class="text-box">
<view class="label">已选座位</view>
<view class="text-content">
<view v-for="item in pageData.chooseTicket" :key="item.id">
{{pageData.hallName || ''}} {{pageData.itemName || ''}} {{item.zoneName || ''}} {{item.rowNum}}{{item.seatNum}}
</view>
</view>
</view>
<view class="text-box">
<view class="label">包含门票</view>
<view class="text-content">{{getTicketName()}}</view>
</view>
</view>
<view class="info-box">
<view class="info-tit">游客信息</view>
<view class="info-sub-tit">需填{{pageData.authenticationType == 2 ? 1 : pageData.authenticationType == 3 ? pageData.chooseTicket.length : 1}}请按座位的顺序填写</view>
<view class="box" v-if="touristList.length > 0">
<view class="border-box" :class="[item.active ? 'active' : '']" v-for="(item, index) in touristList"
:key="item.id" @click="selectTourist(index)">
<view class="border-box-tit">{{item.name}}</view>
<image src="https://common/date_active.png" mode="scaleToFill" />
</view>
<view class="border-more" @click="addTourist">
<view class="left">
新增游客
</view>
<view class="right">
<u-icon name="arrow-right" color="rgba(0,0,0,0.45)" size="32rpx"></u-icon>
</view>
</view>
</view>
<view class="add_menu" v-else @click="addTourist">
<u-icon name="plus" color="#03AE80" size="28rpx"></u-icon>
<view class="text">点击新增游客</view>
</view>
<view class="info-list" v-for="(item, index) in touristList" :key="index" v-if="item.active">
<view class="info-list-left">
<view>{{item.name}}</view>
<view>手机号 {{item.mobile}}</view>
<view>身份证号 {{item.idCard}}</view>
</view>
<view class="info-list-right" @click="editTourist(item)">编辑</view>
</view>
</view>
</view>
<view class="bottom-box" v-if="pageData">
<view class="bottom-left">
<view>总金额</view>
<view></view>
<view>{{pageData.totalPrice && pageData.totalPrice.toFixed(2)}}</view>
</view>
<view class="bottom-right" @click="confirmFun">确认支付</view>
</view>
<!-- 添加修改游客 -->
<view class="tourist_waper" v-if="showTourist">
<view class="tourist_box" :style="'padding-bottom: ' + keyboardHeight + 'px;'">
<view class="popup-tourist">
<view class="title">
{{popupTitle}}
<view class="close" @click="closeTourist">
<u-icon name="close" color="#000" size="30rpx"></u-icon>
</view>
</view>
<view class="form">
<view class="name-box">
<view class="list">
<view class="label">姓名</view>
<input type="text" :adjust-position="false" @keyboardheightchange="handleKeyboardChange"
v-model="touristForm.name" placeholder="请输入联系人姓名" />
</view>
</view>
<view class="num-box">
<view class="list">
<view class="label">联系电话</view>
<input type="number" :adjust-position="false"
@keyboardheightchange="handleKeyboardChange" v-model="touristForm.mobile"
placeholder="请输入联系号码" @blur="keyboardHeight = 0;" />
</view>
<view class="list">
<view class="label">身份证号码</view>
<input type="idcard" :adjust-position="false"
@keyboardheightchange="handleKeyboardChange" v-model="touristForm.idCard"
placeholder="请输入证件号码" @blur="keyboardHeight = 0;" />
</view>
</view>
</view>
<view class="btn" @click="saveTourist">保存</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
windowBottom: 0,
scrollTop: 0,
safeAreaBottom: 0,
touristList: [],
showTourist: false,
keyboardHeight: 0,
popupTitle: '',
activeTourist: [],
touristForm: {
name: '',
mobile: '',
idCard: '',
},
pageData: null
}
},
async onLoad(options) {
this.windowBottom = this.$safeAreaBottom + uni.upx2px(152);
this.safeAreaBottom = this.$safeAreaBottom;
this.pageData = JSON.parse(decodeURIComponent(options.pageData));
this.getTouristList('init')
},
methods: {
async getTouristList(type) {
let info = await this.$http.touristList();
if (type == 'init') {
let data = info.rows.find((item) => {
return item.status == '1'
})
if (data) this.activeTourist = [data.id];
}
for (var i = 0; i < info.rows.length; i++) {
info.rows[i].active = false;
if (this.activeTourist.indexOf(info.rows[i].id) > -1) info.rows[i].active = true;
}
this.touristList = info.rows;
},
selectTourist(index) {
console.log(this.pageData.authenticationType)
// authenticationType 1不实名2需提供一位身份证信息3所有出行人需要提供身份信息
if (this.pageData.authenticationType == '1' || this.pageData.authenticationType == '2') {
for (var i = 0; i < this.touristList.length; i ++) {
this.$set(this.touristList[i], 'active', false);
}
this.$set(this.touristList[index], 'active', true);
} else {
const info = this.touristList[index];
let num = this.touristList.filter((item) => {
return item.active
}).length;
if (!this.touristList[index].active) {
if (num >= this.pageData.chooseTicket.length) {
uni.showToast({
mask: true,
title: '游客人数不得大于购票数量',
icon: 'none'
});
return false;
}
}
this.touristList[index].active = !this.touristList[index].active;
}
},
handleKeyboardChange(e) {
this.$nextTick(() => {
this.keyboardHeight = e.detail.height
})
},
closeTourist() {
this.showTourist = false;
},
async saveTourist() {
if (!this.touristForm.name) {
uni.showToast({
mask: true,
title: '请输入姓名',
icon: 'none'
})
return false;
}
if (!this.$utils.checkStr(this.touristForm.idCard, 'card')) {
uni.showToast({
mask: true,
title: '请输入正确的证件号',
icon: 'none'
})
return false;
}
if (!this.$utils.checkStr(this.touristForm.mobile, 'mobile')) {
uni.showToast({
mask: true,
title: '请输入正确的手机号',
icon: 'none'
})
return false;
}
let info = null;
if (this.touristForm.id) {
info = await this.$http.updateTourist(this.touristForm);
} else {
info = await this.$http.addTourist(this.touristForm);
}
if (info.code == 200) {
uni.showToast({
mask: true,
title: '操作成功',
icon: 'success'
});
this.closeTourist();
this.getTouristList('get');
}
},
addTourist() {
let arr = [];
for (var i = 0; i < this.touristList.length; i++) {
if (this.touristList[i].active) arr.push(this.touristList[i].id);
}
this.activeTourist = arr;
this.touristForm.name = ''
this.touristForm.mobile = ''
this.touristForm.idCard = ''
this.popupTitle = '新增游客'
this.showTourist = true;
},
editTourist(info) {
this.touristForm.name = info.name
this.touristForm.mobile = info.mobile
this.touristForm.idCard = info.idCard
this.touristForm.id = info.id
this.popupTitle = '编辑游客'
this.showTourist = true;
let arr = [];
for (var i = 0; i < this.touristList.length; i++) {
if (this.touristList[i].active) arr.push(this.touristList[i].id);
}
this.activeTourist = arr;
},
async confirmFun() {
const arr = this.touristList.filter((item) => {
return item.active;
});
if (this.pageData.authenticationType == 3) {
if (arr.length != this.pageData.chooseTicket.length) {
uni.showToast({ mask: true, title: '购票数量和游客信息人数不匹配', icon: 'none' })
return false;
}
} else {
if (!arr.length) {
uni.showToast({ mask: true, title: '请选择游客信息', icon: 'none'
})
return false;
}
}
let userList = []
let ids = []
// authenticationType 1不实名2需提供一位身份证信息3所有出行人需要提供身份信息
if (this.pageData.authenticationType == '1' || this.pageData.authenticationType == '2') {
this.pageData.chooseTicket.forEach((item, index) => {
ids.push(item.id)
userList.push({
name: arr[0].name,
idCard: arr[0].idCard,
userId: arr[0].userId,
id: arr[0].id,
rowNum: item.rowNum,
seatNum: item.seatNum,
priceId: item.priceId,
price: item.sumPrice,
zoneId: item.zoneId,
zoneName: item.zoneName,
})
})
} else {
this.pageData.chooseTicket.forEach((item, index) => {
ids.push(item.id)
userList.push({
name: arr[index].name,
idCard: arr[index].idCard,
userId: arr[index].userId,
id: arr[index].id,
rowNum: item.rowNum,
seatNum: item.seatNum,
priceId: item.priceId,
price: item.sumPrice,
zoneId: item.zoneId,
zoneName: item.zoneName,
})
})
}
let data = {
"buyQuantity": this.pageData.chooseTicket.length,
"totalPrice": this.pageData.totalPrice,
"cinemaOrderItemList": [{
"buyQuantity": this.pageData.chooseTicket.length,
"ticketId": this.pageData.ticketId,
"qrcodeRule": this.pageData.qrcodeRule,
"totalPrice": this.pageData.totalPrice,
"movieId": this.pageData.movieId,
"movieName": this.pageData.movieName,
"itemId": this.pageData.itemId,
"userList": userList,
"saleTime": this.pageData.saleTime + ' 00:00:00'
}],
"ids": ids
}
let info = await this.$http.buyOtherTicket(data)
uni.showLoading({ mask: true });
if(info.code == 200) {
if (data.totalPrice > 0) {
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.showToast({ mask: true, title: '支付成功', icon: 'success' })
uni.redirectTo({
url: '/pages/my/unpaid?id=' + info.data.id
})
},
fail: (err) => {
uni.showToast({ mask: true, title: '支付取消', icon: 'none' })
uni.redirectTo({
url: '/pages/my/unpaid?id=' + info.data.id
})
}
});
} else {
uni.showToast({ mask: true, title: '购买成功', icon: 'success' })
setTimeout(() => {
uni.redirectTo({
url: '/pages/my/unpaid?id=' + info.data.id
})
}, 1500)
}
} else {
uni.hideLoading();
}
},
getTicketName() {
let str = `${this.pageData.movieName}${this.pageData.chooseTicket.length}`
this.pageData.ticketChildren && this.pageData.ticketChildren.forEach(item => {
str += `${item.childTicketName}${this.pageData.chooseTicket.length}`
})
return str
}
},
onPageScroll(e) {
this.scrollTop = e.scrollTop;
}
}
</script>
<style lang="scss">
page {
background: #FBFBFB;
}
</style>
<style lang="scss" scoped>
.navbar_title {
color: white;
}
.banner {
width: 100%;
height: 394rpx;
background: #03AE80;
}
.waper_box {
width: 100%;
margin-top: -187rpx;
padding: 0 32rpx;
box-sizing: border-box;
.header-box {
width: 100%;
background: #FFFFFF;
border-radius: 10rpx;
box-sizing: border-box;
padding: 32rpx 24rpx 15rpx;
margin-bottom: 20rpx;
.header-title {
padding-bottom: 24rpx;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
font-weight: 600;
font-size: 40rpx;
color: #333333;
height: 56rpx;
line-height: 47rpx;
margin-bottom: 24rpx;
}
.text-box {
display: flex;
align-items: flex-start;
margin-top: 20rpx;
.label {
width: 112rpx;
min-width: 112rpx;
margin-right: 48rpx;
height: 39rpx;
font-size: 28rpx;
color: rgba(0, 0, 0, 0.65);
}
.text-content {
font-size: 28rpx;
color: rgba(0, 0, 0, 0.85);
min-height: 40rpx;
flex: 1;
view {
// height: 40rpx;
line-height: 40rpx;
}
&>view:not(:first-child) {
margin-top: 12rpx;
}
}
}
}
.info-box {
background: #FFFFFF;
border-radius: 10rpx;
box-sizing: border-box;
padding: 32rpx 24rpx;
.info-tit {
height: 45rpx;
font-weight: 500;
font-size: 32rpx;
color: rgba(0, 0, 0, 0.85);
line-height: 38rpx;
margin-bottom: 8rpx;
}
.info-sub-tit {
height: 34rpx;
font-size: 24rpx;
color: rgba(0, 0, 0, 0.45);
line-height: 28rpx;
}
.box {
display: flex;
align-items: center;
flex-wrap: wrap;
margin-bottom: 24rpx;
.border-box {
width: 166rpx;
height: 106rpx;
border-radius: 10rpx 10rpx 10rpx 10rpx;
border: 1rpx solid rgba(0, 0, 0, 0.1);
margin-right: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
margin-top: 20rpx;
box-sizing: border-box;
.border-box-tit {
font-size: 28rpx;
color: rgba(0, 0, 0, 0.85);
line-height: 33rpx;
}
image {
width: 40rpx;
height: 40rpx;
position: absolute;
right: 0;
bottom: 0;
z-index: -1;
}
}
.time-border-box {
width: 215rpx;
height: 104rpx;
border-radius: 10rpx 10rpx 10rpx 10rpx;
border: 1rpx solid rgba(0, 0, 0, 0.1);
margin-right: 20rpx;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
position: relative;
overflow: hidden;
margin-top: 20rpx;
box-sizing: border-box;
padding: 16rpx 12rpx;
.time-border-box-tit {
height: 34rpx;
font-size: 24rpx;
color: rgba(0, 0, 0, 0.65);
line-height: 28rpx;
}
.time-border-box-sub-tit {
height: 34rpx;
font-size: 24rpx;
color: rgba(0, 0, 0, 0.45);
line-height: 28rpx;
margin-top: 4px;
}
image {
width: 40rpx;
height: 40rpx;
position: absolute;
right: 0;
bottom: 0;
z-index: -1;
}
}
.time-border-box:nth-child(3n) {
margin-right: 0;
}
.active {
border: 1rpx solid #03AE80;
image {
z-index: 1;
}
}
.border-more {
width: 80rpx;
display: flex;
align-items: center;
justify-content: center;
.left {
width: 48rpx;
font-size: 24rpx;
color: rgba(0, 0, 0, 0.45);
line-height: 28rpx;
}
}
}
.add_menu {
width: 100%;
margin-top: 32rpx;
height: 90rpx;
display: flex;
justify-content: center;
align-items: center;
background: rgba(#03AE80, 0.1);
border-radius: 10rpx;
margin-bottom: 24rpx;
.text {
margin-left: 8rpx;
color: #03AE80;
font-size: 28rpx;
font-weight: 500;
}
}
.info-list {
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
padding: 12rpx 0px 24rpx 0rpx;
border-top: 1rpx solid rgba(0, 0, 0, 0.1);
.info-list-left {
&>view {
margin-top: 12rpx;
height: 39rpx;
font-size: 28rpx;
color: rgba(0, 0, 0, 0.85);
line-height: 33rpx;
}
}
.info-list-right {
height: 39rpx;
font-size: 28rpx;
color: #03AE80;
line-height: 33rpx;
}
}
}
}
.bottom-box {
width: 100%;
height: 120rpx;
position: fixed;
left: 0;
bottom: 0;
background: #fff;
z-index: 10;
box-sizing: border-box;
padding: 0 32rpx;
display: flex;
justify-content: space-between;
align-items: center;
.bottom-left {
display: flex;
align-items: flex-end;
view {
&:nth-child(1) {
font-size: 24rpx;
color: #999999;
line-height: 1;
margin-bottom: 4rpx;
}
&:nth-child(2) {
font-weight: 500;
font-size: 36rpx;
color: #FF5833;
line-height: 1;
margin-bottom: 1rpx;
}
&:nth-child(3) {
font-family: DIN, DIN;
font-weight: bold;
font-size: 64rpx;
color: #FF5833;
line-height: 1;
}
}
}
.bottom-right {
width: 228rpx;
height: 80rpx;
border-radius: 40rpx;
background: #03AE80;
text-align: center;
line-height: 80rpx;
color: #fff;
font-size: 30rpx;
font-weight: 500;
}
}
.tourist_waper {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.4);
position: fixed;
left: 0;
bottom: 0;
z-index: 100;
display: flex;
align-items: flex-end;
.tourist_box {
width: 100%;
.popup-tourist {
width: 100%;
}
}
}
</style>