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

698 lines
26 KiB
Vue

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