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

416 lines
20 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" :style="'padding-bottom: ' + windowBottom + 'px;'">
<u-navbar @leftClick="leftClick" :bgColor="scrollTop > 20 ? '#fff' : 'transparent'" :leftIconColor="scrollTop > 20 ? '#303133' : '#fff'">
<view slot='center' class="navbar_title">{{scrollTop > 20 ? '门票详情' : ''}}</view>
</u-navbar>
<view class="banner" v-if="detail">
<swiper :autoplay="true" :interval="5000" circular :duration="1000">
<swiper-item v-for="(i, index) in detail.image43 ? detail.image43.split(',') : []" :key="index">
<image :src="$utils.setImgUrl(i)" mode=""></image>
</swiper-item>
</swiper>
<view style="width: 100%; height: 100%; position: absolute; left: 0; top: 0; z-index: 2;" v-if="detail.image43 && detail.image43.split(',').length == 1"></view>
<button open-type="share" class="icon">
<u-icon size="44rpx" color="#fff" name="share-square"></u-icon>
</button>
</view>
<view class="waper_box" v-if="detail">
<view class="info">
<view class="title">{{detail.name}}</view>
<view class="number">
<view>库存{{detail.inventory}}</view>
<view>已售{{ detail.sales }}</view>
</view>
<view class="tel">
<view>电话{{configData && configData.phone}}</view>
<view @click="callTel">
<image src="https://common/callTel.png" mode=""></image>
</view>
</view>
<view class="list">
</view>
</view>
<view class="content">
<view class="list_waper">
<view class="title">购买须知</view>
<view class="notic">
<view>{{detail.refundRule == '5' ? detail.refundRuleName.substr(0, 3) : detail.refundRuleName}}</view>
<view v-if="detail.refundRule == '0'">{{detail.refundRemark || ''}}</view>
<view v-if="detail.refundRule == '3'">门票有效期内可退</view>
<view v-if="detail.refundRule == '4'">订单生成后{{detail.refundDay}}天内可退</view>
<view v-if="detail.refundRule == '5'">未激活可退</view>
</view>
<view class="fee" v-if="detail.refundRule > 0">
<view>退款手续费</view>
<view>
<text v-if="detail.isFee == 0">无需手续费</text>
<text v-if="detail.isFee == 1 && detail.feeType == '1'">退款需扣除手续费{{(detail.deductionFees) + (detail.deductionFeesUnit == '1' ? '%' : '')}}</text>
<text v-if="detail.isFee == 1 && detail.feeType == '2'" v-for="(i, index) in detail.refundRuleList" :key="index">游玩前{{i.day}}天内退票需扣除手续费{{i.deductionFees}}{{i.deductionFeesUnit == '1' ? '%' : ''}}</text>
</view>
</view>
</view>
<view class="list_waper">
<view class="title">使用说明</view>
<view class="list">
<view>
<text>有效期</text>
<text v-if="detail.ticketValidityPeriod == '1'">游玩日期当天有效</text>
<text v-if="detail.ticketValidityPeriod == '2'">购买后{{detail.buyPeriodDay}}天有效</text>
<text v-if="detail.ticketValidityPeriod == '3'">{{detail.validityStartTime}}{{detail.validityEndTime}}有效</text>
<text v-if="detail.ticketValidityPeriod == '4'">激活后{{detail.buyPeriodDay}}天有效</text>
</view>
<view v-if="detail.applicablePeriod && detail.classify == '4' && getDayMsg(detail.applicablePeriod)">
<text>适用时间段</text>
<text>{{getDayMsg(detail.applicablePeriod)}}不可用</text>
</view>
<view v-if="detail.applicablePeriod && detail.classify != '4'">
<text>适用时间段</text>
<text>{{getWeekMsg(detail.applicablePeriod)}}</text>
</view>
<view v-if="detail.admissionTime">
<text>入园时间</text>
<text>{{detail.admissionTime.split(',').join('-')}}</text>
</view>
<view>
<text>入园地址</text>
<text>{{detail.admissionAddress || ''}}</text>
</view>
<view v-if="detail.isUnavailableHoliday == '1'">
<text>不可用节日</text>
<text>{{detail.unavailableHolidayStr}}</text>
</view>
<view v-if="detail.isUnavailableTime == '1'">
<text>不可用时间</text>
<text>{{detail.unavailableTimeStr}}</text>
</view>
</view>
</view>
<view class="list_waper">
<view class="title">费用说明</view>
<view class="list" v-if="detail.classify == 1 || detail.classify == 4">
<view>
<text>费用包含</text>
<text>{{detail.name}}-1</text>
</view>
</view>
<view class="list" v-if="detail.classify == 2">
<view>
<text>费用包含</text>
<text v-for="(i, index) in detail.childList">{{i.childTicketName}}-1张</text>
</view>
</view>
</view>
<view class="list_waper" v-if="detail.classify == 4">
<view class="title">年卡权益</view>
<view class="years_waper">
<view class="years_list" v-for="(i, index) in detail.childList">
<view>{{i.childTicketName}}</view>
<view>{{i.isUnlimited == '1' ? '不限次数' : ('限' + i.canVerificationNum + '次,每月最多' + i.monthVerificationNum + '次,每日最多' + i.dayVerificationNum + '次')}}</view>
</view>
</view>
</view>
<view class="list_waper">
<view class="title">其他说明</view>
<view class="list">
<view>
<text>限购说明</text>
<text v-if="detail.isOrderQuantity">每单最多购买{{detail.orderQuantity}}</text>
<text v-else>不限购</text>
</view>
<view v-if="detail.isOrder == '1'">
<text>预约说明</text>
<text>需提前{{detail.beforeDay}}天预约</text>
</view>
<view v-if="detail.authenticationType">
<text>是否实名</text>
<text>{{detail.authenticationTypeLabel}}</text>
</view>
<view v-if="detail.bookingNotice">
<text>预定须知</text>
<text>{{detail.bookingNotice}}</text>
</view>
</view>
</view>
</view>
</view>
<!-- :style="'padding-bottom: ' + windowBottom + 'px;'" -->
<view class="bottom">
<view class="bottom_waper" v-if="detail">
<view class="left">
<view :class="detail.salesRice > 0 ? '' : 'free'">{{detail.salesRice > 0 ? detail.salesRice.toFixed('2') : '免费'}}</view>
<view>{{detail.salesRice > 0 ? '起' : ''}}</view>
<view :class="detail.salesRice > 0 ? '' : 'free'" v-if="detail.price && detail.price > 0">{{detail.price}}</view>
</view>
<view class="right" @click="submitOrder">立即购买</view>
</view>
</view>
</view>
</template>
<script>
export default {
data () {
return {
windowBottom: 0,
scrollTop: 0,
detail: null,
configData: null
}
},
onShareAppMessage (e) {
return {
title: '巴松措风景区',
path: '/pages/login/index'
}
},
async onLoad (options) {
let windowInfo = uni.getSystemInfoSync();
this.windowBottom = this.$safeAreaBottom;
this.configData = uni.getStorageSync('configData');
let info = await this.$http.ticketDetail(options.id);
let unavailableTimeStr = [];
info.data.unavailableTimeList.forEach((item) => {
unavailableTimeStr.push(item.beginTime + '至' + item.endTime)
})
let unavailableHolidayStr = [];
info.data.unavailableHolidayList.forEach((item) => {
unavailableHolidayStr.push(item.holidayName)
})
info.data.unavailableTimeStr = unavailableTimeStr.join('');
info.data.unavailableHolidayStr = unavailableHolidayStr.join('');
this.detail = info.data;
},
methods: {
leftClick () {
let pages = getCurrentPages();
let prevPage = pages[pages.length - 2];
if (prevPage) {
uni.navigateBack({ delta: 1 })
prevPage.onLoad(prevPage.options);
} else uni.reLaunch({ url: '/pages/tabbar/home' })
},
callTel () {
uni.makePhoneCall({ phoneNumber: this.configData.phone }).catch((e) => {});
},
async submitOrder () {
if (this.detail.mpOnlyShow) {
uni.showToast({ title: '小程序暂不支持购买此年卡', icon: 'none', mask: true })
return false;
}
if (this.detail.inventory <= 0) {
uni.showToast({ title: '当前门票已售罄', icon: 'none', mask: true })
return false;
}
let user = await this.$http.getUserInfo();
if (user.data.isBlack == 1) {
uni.showToast({ title: '您是黑名单用户,禁止购票', icon: 'none', mask: true })
return false;
}
if (!user.data.name || !user.data.mobile || !user.data.idCard) {
uni.showToast({ title: '请完善个人信息后操作', icon: 'none', mask: true })
setTimeout(() => {
uni.navigateTo({ url: '/pages/my/myProfile' })
}, 1500)
return false;
}
if (this.detail.ticketStatus == 0) {
uni.navigateTo({ url: '/pages/my/buyTicket?id=' + this.detail.id })
} else uni.showToast({ mask: true, title: '该门票已失效', icon: 'none' });
},
getWeekMsg (str) {
let time = str.split(',')
let weekLabel = '';
if (this.isContinuous(time)) {// 数组连续
weekLabel = this.getWeek(Number(time[0])) + '至' + this.getWeek(Number(time[time.length - 1]));
} else {
let arr = [];
time.forEach((item) => {
arr.push(this.getWeek(Number(item)))
})
weekLabel = arr.join(',');
}
return weekLabel;
},
isContinuous (nums) {
nums.sort((a, b) => a - b);
for (let i = 1; i < nums.length; i++) {
if (nums[i] !== nums[i - 1] + 1) {
return false;
}
}
return true;
},
getDayMsg (str) {
let time = str.split(',');
let dayLabel = '';
let arr = [];
time.forEach((item) => {
if (item > 0) arr.push(this.getDay(Number(item)))
})
dayLabel = arr.join(',');
return dayLabel;
},
getDay (key) {
let str = '';
switch (key) {
case 1:
str = '周末';
break;
case 2:
str = '元旦';
break;
case 3:
str = '春节';
break;
case 4:
str = '清明';
break;
case 5:
str = '劳动';
break;
case 6:
str = '端午';
break;
case 7:
str = '中秋';
break;
case 8:
str = '国庆';
break;
}
return str;
},
getWeek (key) {
let str = '';
switch (key) {
case 1:
str = '周一';
break;
case 2:
str = '周二';
break;
case 3:
str = '周三';
break;
case 4:
str = '周四';
break;
case 5:
str = '周五';
break;
case 6:
str = '周六';
break;
case 7:
str = '周日';
break;
}
return str;
}
},
onPageScroll (e) {
this.scrollTop = e.scrollTop;
}
}
</script>
<style lang="scss">
.banner{
width: 100%; height: 562rpx; position: relative;
swiper{ width: 100%; height: 100%; }
.icon{
width: 80rpx; height: 80rpx; background: rgba(0, 0, 0, 0.5); border-radius: 50%; display: flex; justify-content: center; align-items: center; border: none; padding: 0; position: absolute; bottom: 128rpx; right: 32rpx; z-index: 3;
&::after{ border: none; }
}
}
.waper_box{
width: 100%; margin-top: -80rpx; position: relative; z-index: 3; padding-bottom: 174rpx;
.info{
width: 100%; background: #fff; border-radius: 32rpx 32rpx 0 0; box-sizing: border-box; padding: 32rpx 32rpx 28rpx;
.title{ color: #333; line-height: 50rpx; font-size: 36rpx; font-weight: 500; }
.number{ margin-top: 20rpx; display: flex; justify-content: space-between; align-items: center; height: 40rpx; color: #999; font-size: 28rpx; }
.tel{
width: 100%; display: flex; justify-content: space-between; align-items: center; margin-top: 32rpx;
view{
&:nth-child(1){ color: #333; font-size: 28rpx; font-weight: 500; }
&:nth-child(2){ width: 50rpx; height: 50rpx; }
}
}
}
.content{
width: 100%; background: #fff; margin-top: 20rpx; box-sizing: border-box; padding: 32rpx 32rpx 0;
.list_waper{
width: 100%; border-bottom: 2rpx solid rgba(0, 0, 0, 0.05); margin-bottom: 32rpx; padding-bottom: 32rpx;
&:last-child{ border-bottom: 0; margin-bottom: 0; }
.title{ line-height: 46rpx; color: #333; font-size: 32rpx; font-weight: 500; }
.notic{
width: 100%; box-sizing: border-box; padding-left: 160rpx; position: relative; margin-top: 24rpx;
view{
&:nth-child(1){ height: 40rpx; background: rgba(3, 174, 128, 0.1); border-radius: 2rpx; color: #03AE80; line-height: 40rpx; width: 140rpx; text-align: center; position: absolute; left: 0; top: 0; font-size: 20rpx; }
&:nth-child(2){ line-height: 40rpx; color: #666; font-size: 28rpx; min-height: 40rpx; }
}
}
.fee{
width: 100%; box-sizing: border-box; padding-left: 160rpx; position: relative; margin-top: 28rpx;
view{
&:nth-child(1){ height: 40rpx; background: rgba(255, 88, 51, 0.1); border-radius: 2rpx; color: #FF5833; line-height: 40rpx; width: 140rpx; text-align: center; position: absolute; left: 0; top: 0; font-size: 20rpx; }
&:nth-child(2){
line-height: 40rpx; color: #666; font-size: 28rpx; min-height: 40rpx;
text{ display: block; }
}
}
}
.list{
margin-top: 24rpx;
view{
width: 100%; margin-bottom: 20rpx; padding-left: 160rpx; box-sizing: border-box; position: relative;
&:last-child{ margin-bottom: 0; }
text{
line-height: 40rpx; color: #666; font-size: 28rpx; min-height: 40rpx; display: block; margin-bottom: 20rpx;
&:nth-child(1){ line-height: 40rpx; color: #333; font-size: 28rpx; position: absolute; left: 0; top: 0; }
&:last-child{ margin-bottom: 0; }
}
}
}
.years_waper{
margin-top: 24rpx;
.years_list{
width: 100%; font-size: 0; margin-bottom: 20rpx; box-sizing: border-box; padding-left: 240rpx; position: relative; min-height: 40rpx;
&:last-child{ margin-bottom: 0; }
view{
line-height: 40rpx; font-size: 28rpx;
&:nth-child(1){ color: #333; position: absolute; left: 0; top: 0; width: 220rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
&:nth-child(2){ color: #666; width: 100%; }
}
}
}
}
}
}
.bottom{
width: 100%; position: fixed; left: 0; bottom: 0; background: #fff; z-index: 10;
.bottom_waper{
width: 100%; height: 120rpx; box-sizing: border-box; padding: 0 32rpx; display: flex; justify-content: space-between; align-items: center;
.left{
display: flex; align-items: flex-end;
view{
&:nth-child(1){
color: #FF5833; font-size: 64rpx; font-weight: bold; line-height: 78rpx; padding-left: 36rpx; position: relative;
&::after{ content: "¥"; line-height: 50rpx; color: #FF5833; font-size: 36rpx; font-weight: 500; position: absolute; left: 0; bottom: 4rpx; }
&.free{
font-size: 32rpx;
&::after{ content: ""; font-size: 0; }
}
}
&:nth-child(2){ color: #C8C8C8; font-size: 28rpx; margin-left: 8rpx; line-height: 50rpx; }
&:nth-child(3){
margin-left: 20rpx; line-height: 50rpx; color: #C8C8C8; font-size: 28rpx; text-decoration: line-through;
&.free{ line-height: 66rpx; }
}
}
}
.right{ width: 228rpx; height: 80rpx; border-radius: 100rpx; background: linear-gradient( 141deg, #54C76E 0%, #03AE80 100%); text-align: center; line-height: 80rpx; color: #fff; font-size: 30rpx; font-weight: 500; }
}
}
</style>