feat: 质惠游 H5 一期 —— 门票模块全链路(微信公众号版)

从 xghmall(云闪付版湘工游)迁移民票模块,改造为微信公众号 H5:

- 技术栈沿用 uni-app + Vue2 + uView(含定制版日历组件)
- 登录/支付独立成层(common/auth.js、common/pay.js):
  一期假登录(测试手机号)+ 模拟支付,后端微信接口就绪后只换这两处
- 登录页重写:短信验证码 + 公众号网页授权(code 换用户信息)预留
- 门票列表页为入口页(进页必须登录),加订单悬浮按钮
- 支付成功页接通:查看订单/继续逛逛 + 订单状态轮询
- 详情页定位导航改用 uni.openLocation + 高德网页兜底
- 出行人页:身份证 18 位格式校验,删除死的删除按钮,修正证件类型回显笔误
- 清理云闪付 SDK、支付宝授权、死页面引用等残留

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
xuchao
2026-07-21 00:43:59 +08:00
co-authored by Claude Opus 4.8
commit 4190565eb7
192 changed files with 35664 additions and 0 deletions
+217
View File
@@ -0,0 +1,217 @@
<template>
<view class="auth_rq">
<image class="auth_rq_image" src="https://aliyunoss.hn12301.net/sd/ali_logo.png"></image>
<view class="auth_rq_view">质惠游</view>
<!-- xuchao: 开发模式提示(正式环境不显示) -->
<view class="auth_rq_tips" v-if="devMode">开发模式:输入测试手机号直接登录</view>
<view class="auth_rq_input" :style="{marginTop: devMode ? '40rpx' : '146rpx'}">
<u-input v-model="value" type="number" :border="false" :custom-style='customStyle' placeholder='请输入手机号' />
</view>
<!-- xuchao: 开发模式免验证码 -->
<view class="auth_rq_input" v-if="!devMode" style="margin-top: 50rpx;">
<u-input v-model="value1" type="number" :border="false" :custom-style='customStyle' placeholder='请输入验证码' />
<text style="margin-left: 30rpx;" :style="{color:isFlag?'#488CFE':'#666'}" @tap="getCode">{{tips}}</text>
</view>
<button class="auth_rq_button1" :style="{marginTop: devMode ? '80rpx' : '80rpx'}" @click="doLogin">立即登录</button>
<view style="margin-top: 32rpx;margin-left: 70rpx;">
<u-checkbox-group>
<u-checkbox v-model="checked" shape="circle" style="color: #929292;">我已阅读并同意<text
style="color: #488CFE;" @click="readXy()">用户服务协议</text></u-checkbox>
</u-checkbox-group>
</view>
<u-verification-code :seconds="seconds" @end="end" @start="start" ref="uCode"
@change="codeChange"></u-verification-code>
</view>
</template>
<script>
// xuchao: 登录页 —— 微信版
// 开发模式:输入测试手机号直接登录(假登录)
// 正式流程:微信网页授权(code 换用户信息)+ 短信验证码绑定手机号
import config from '@/common/config.js'
import auth from '@/common/auth.js'
export default {
data() {
return {
devMode: config.devMode,
redirect: '',
tips: '发送验证码',
seconds: 60,
checked: false,
value: '',
value1: '',
isFlag: true,
customStyle: {
background: '#f8f8f8',
}
}
},
onLoad(options) {
// xuchao: 记录登录前的页面,登录成功后回跳
if (options.redirect) {
this.redirect = decodeURIComponent(options.redirect)
}
// xuchao: 正式流程 —— 公众号网页授权重定向回来时 URL 带 code,用它换用户信息
if (options.code && !config.devMode) {
auth.loginByWechat(options.code).then(res => {
// 后端已绑定手机的用户直接登录成功
if (res && res.mobile) {
uni.setStorageSync('openId', res.openId)
uni.setStorageSync('phone', res.mobile)
this.finishLogin()
}
// 未绑定手机的用户停留在本页,走短信验证码绑定
}).catch(() => {})
}
},
methods: {
// xuchao: 登录入口
doLogin() {
if (!this.checked) {
uni.showToast({ icon: 'none', title: '请先阅读并同意用户服务协议' })
return
}
if (!/^1\d{10}$/.test(this.value)) {
uni.showToast({ icon: 'none', title: '请输入正确的手机号' })
return
}
if (config.devMode) {
// 开发模式:只允许测试手机号登录
if (config.testPhones.indexOf(this.value) === -1) {
uni.showToast({ icon: 'none', title: '开发模式仅支持测试手机号' })
return
}
auth.loginByMock(this.value)
this.finishLogin()
return
}
// 正式流程:短信验证码校验 + 绑定手机号
if (!this.value1) {
uni.showToast({ icon: 'none', title: '请输入验证码' })
return
}
auth.bindPhoneBySms(this.value, this.value1).then(() => {
this.finishLogin()
}).catch(() => {})
},
// xuchao: 登录成功后回跳
finishLogin() {
uni.showToast({ icon: 'success', title: '登录成功' })
setTimeout(() => {
if (this.redirect) {
uni.reLaunch({ url: this.redirect })
} else if (getCurrentPages().length > 1) {
uni.navigateBack()
} else {
uni.reLaunch({ url: '/pages/ticket/scenic' })
}
}, 500)
},
end() {
this.isFlag = true
},
start() {
this.isFlag = false
},
readXy() {
uni.downloadFile({
url: "https://aliyunoss.hn12301.net/sd/zfzxy.docx",
success: function(res) {
uni.openDocument({
filePath: res.tempFilePath,
showMenu: true
});
}
});
},
codeChange(text) {
this.tips = text;
},
// xuchao: 发送验证码 —— 开发模式仅走倒计时,正式流程需后端短信接口
getCode() {
if (!/^1\d{10}$/.test(this.value)) {
uni.showToast({ icon: 'none', title: '请输入正确的手机号' })
return
}
if (!this.$refs.uCode.canGetCode) {
this.$u.toast('倒计时结束后再发送');
return
}
if (config.devMode) {
this.$u.toast('验证码已发送');
this.$refs.uCode.start();
return
}
// TODO 后端就绪后替换为真实发送短信验证码接口
uni.showLoading({ title: '正在获取验证码' })
setTimeout(() => {
uni.hideLoading();
this.$u.toast('短信接口未接入');
}, 1000);
}
}
}
</script>
<style>
page {
background: #ffffff;
}
</style>
<style lang="less" scoped>
.auth_rq {
.auth_rq_input {
display: flex;
width: 610rpx;
height: 98rpx;
align-items: center;
padding-left: 40rpx;
margin-left: 70rpx;
background-color: #F8F8F8;
border-radius: 8px;
padding-right: 40rpx;
}
.auth_rq_image {
width: 164rpx;
height: 140rpx;
margin-top: 182rpx;
margin-left: 294rpx;
}
.auth_rq_view {
width: 750rpx;
text-align: center;
color: #0DD381;
font-size: 36rpx;
margin-top: 18rpx;
}
// xuchao: 开发模式提示条
.auth_rq_tips {
width: 610rpx;
margin: 40rpx 0 0 70rpx;
padding: 16rpx 24rpx;
box-sizing: border-box;
background-color: #FDF6EC;
color: #E6A23C;
font-size: 24rpx;
border-radius: 8px;
}
.auth_rq_button1 {
width: 610rpx;
margin-left: 70rpx;
margin-top: 80rpx;
height: 98rpx;
border-radius: 49rpx;
background-color: #488CFE;
color: #fff;
}
}
</style>
+509
View File
@@ -0,0 +1,509 @@
<template>
<view v-if="obj">
<view class="detail_h">
<view style="width: 654rpx;display: flex;justify-content: space-between;">
<text style="font-size: 48rpx;font-weight: bold;"
:style="{color:obj.order.orderStatus=='WAITPAY'?'#FF0000':'#000'}">{{orderStatus}}</text>
<view>
<text style="color: #000000;font-size: 20rpx;">¥</text>
<text
style="color: #000000;font-size: 48rpx;font-weight: bold;margin-right: 12rpx;">{{(obj.order.orderAmount/100).toFixed(2)}}</text>
<u-icon name="arrow-right" color="#808080" size="28"></u-icon>
</view>
</view>
<text style="color:#808080;margin-top: 24rpx;display: block;">{{orderTitle}}</text>
</view>
<view class="detail_rq">
<text style="color: #000;line-height: 88rpx;font-size: 36rpx;font-weight: bold;">商品信息</text>
<view style="width: 702rpx;display: flex;justify-content: space-between;">
<text style="color: #000;font-weight: bold;">{{obj.tickets.name}}</text>
<u-icon name="arrow-right" color="#808080" size="24"></u-icon>
</view>
<view style="display: flex;margin-top: 24rpx;">
<view style="width: 120rpx;color: #808080;">票型类型</view>
<view style="width: 566rpx;margin-left: 16rpx;color: #000;">
【{{getSkuType(obj.sku.typeId)}}】&nbsp;{{obj.sku.skuName}}</view>
</view>
<view style="display: flex;margin-top: 24rpx;">
<view style="width: 120rpx;color: #808080;">使用日期</view>
<view style="width: 566rpx;margin-left: 16rpx;color: #FF0000;">{{obj.orderGoods.bookDate}} <text
v-if="obj.orderGoods.timeSlot">({{obj.orderGoods.timeSlot}})</text></view>
</view>
<view style="display: flex;margin-top: 24rpx;">
<view style="width: 120rpx;color: #808080;">生效时间</view>
<view style="width: 566rpx;margin-left: 16rpx;color: #000;">出票后立即生效</view>
</view>
<view class="rypz" v-if="obj.touristList.length!=0">
<view style="width: 654rpx;text-align: center;display: flex;flex-direction: column;">
<text style="color: #000000;font-size: 32rpx;font-weight: bold;">入园凭证</text>
<scroll-view scroll-x="true" class="xsms-scroll">
<view style="width: 404rpx;display: inline-block;"
:style="{marginRight:index==obj.touristList.length-1?'0rpx':'24rpx'}"
v-for="(item,index) in obj.touristList" :key="index">
<view class="rq_item">凭证码</view>
<view
style="width: 404rpx;background: #F8F9FC;display: flex;flex-direction: column;align-items: center;padding-bottom: 24rpx0;border-radius: 0rpx 0rpx 24rpx 24rpx;">
<view class="rq_num">{{item.qrCode}}</view>
<view class="rq_btn" @tap='coyp(item.qrCode)'>复制</view>
<image style="width: 240rpx;height: 240rpx;margin-top: 24rpx;" :src="item.qrCodeBase64">
</image>
</view>
</view>
</scroll-view>
</view>
</view>
<view style="display: flex;margin-top: 24rpx;">
<view style="width: 120rpx;color: #808080;">入园方式</view>
<view style="width: 566rpx;margin-left: 16rpx;color: #000;">
{{obj.sku.enterChangeFlag?'凭('+getTyepStr(obj.sku.enterType)+')换票入园':'无需换票'}}
</view>
</view>
<view style="display: flex;margin-top: 24rpx;" v-if="obj.sku.enterChangeFlag">
<view style="width: 120rpx;color: #808080;">换票时间</view>
<view style="width: 566rpx;margin-left: 16rpx;color: #000;">
{{obj.sku.changeStart}}~{{obj.sku.changeEnd}}
</view>
</view>
<view style="display: flex;margin-top: 24rpx;" v-if="obj.sku.enterChangeFlag">
<view style="width: 120rpx;color: #808080;">换票地点</view>
<view style="width: 566rpx;margin-left: 16rpx;color: #000;">{{obj.sku.changePostion}}</view>
</view>
<view style="display: flex;margin-top: 24rpx;">
<view style="width: 120rpx;color: #808080;">入园时间</view>
<view style="width: 566rpx;margin-left: 16rpx;color: #000;">{{obj.sku.enterStart}}~{{obj.sku.enterEnd}}
</view>
</view>
<view style="display: flex;margin-top: 24rpx;">
<view style="width: 120rpx;color: #808080;">入园地点</view>
<view style="width: 566rpx;margin-left: 16rpx;color: #000;">{{obj.sku.enterPostion}}</view>
</view>
<view style="display: flex;margin-top: 24rpx;border-bottom: 2rpx #E1E1E1 dashed;padding-bottom: 24rpx;">
<view style="width: 120rpx;color: #808080;">门票</view>
<view style="width: 566rpx;margin-left: 16rpx;color: #000;">
¥{{(obj.orderGoods.skuPrice/100).toFixed(2)}} x {{obj.order.buyNum}}</view>
</view>
<view style="position: relative;height: 96rpx;display: flex;align-items: center;" @click="show1=true">
<text style="color: black;font-weight: bold;display: block;width: 120rpx;">取消政策</text>
<image src="https://aliyunoss.hn12301.net/sd/ticket_dg.png"
style="width: 40rpx;height: 40rpx;margin-left: 12rpx;margin-right: 12rpx;"></image>
<text
style="color: rgba(0, 0, 0, 0.8);">{{obj.sku.refundType==1?'随时退':obj.sku.refundType==2?'有条件退':obj.sku.refundType==3?'不可退款':''}}</text>
<u-icon name="arrow-right" color="#808080" size="24" style="position: absolute;right: 0rpx;"></u-icon>
</view>
</view>
<view class="detail_rq" style="border-top: none;padding-bottom: 24rpx;">
<text style="color: #000;line-height: 88rpx;font-size: 36rpx;font-weight: bold;">订单信息</text>
<view v-if="obj.sku.enterDemand=='2'">
<view style="display: flex;margin-top: 24rpx;" v-for="(item,index) in obj.touristList">
<view style="width: 120rpx;color: #808080;">出行人</view>
<view style="width: 566rpx;margin-left: 16rpx;color: #000;line-height: 48rpx;">{{item.name}} <br />
{{item.phone}}
<br />{{item.identityNo}}
</view>
</view>
</view>
<view v-if="obj.sku.enterDemand=='1'"
style="display: flex;margin-top: 24rpx;border-bottom: 2rpx #E1E1E1 dashed;padding-bottom: 24rpx;">
<view style="width: 120rpx;color: #808080;">联系人</view>
<view style="width: 566rpx;margin-left: 16rpx;color: #000;">{{obj.order.orderContactName}}</view>
</view>
<view style="display: flex;margin-top: 24rpx;border-bottom: 2rpx #E1E1E1 dashed;padding-bottom: 24rpx;">
<view style="width: 120rpx;color: #808080;">手机号</view>
<view style="width: 566rpx;margin-left: 16rpx;color: #000;">{{obj.order.orderContactMobile}}</view>
</view>
<view style="display: flex;margin-top: 24rpx;position: relative;">
<view style="width: 120rpx;color: #808080;">订单编号</view>
<view style="width: 566rpx;margin-left: 16rpx;color: #000;">{{obj.order.id}}</view>
<text style="position: absolute;right: 0rpx;color: #808080;" @tap='coyp(obj.order.id)'>复制</text>
</view>
<view style="display: flex;margin-top: 24rpx;position: relative;" v-if="obj.order.orderStatus!='WAITPAY'">
<view style="width: 120rpx;color: #808080;">支付时间</view>
<view style="width: 566rpx;margin-left: 16rpx;color: #000;" v-if="obj.payment">
{{obj.payment.createdTime||''}}
</view>
</view>
</view>
<view style="width: 750rpx;height: 120rpx;"></view>
<view class="detail_btn">
<!-- <view class="tozf">再次购买</view> -->
<view class="tozf" v-if="obj.order.orderStatus=='WAITPAY'" @tap='toPay()'>去支付</view>
<view class="toqx" v-if="obj.order.orderStatus=='WAITPAY'" @tap='cancel()'>取消订单</view>
<view class="toqx" @tap='aginPlay()'
v-if="obj.order.orderStatus=='HAVESEND'||obj.order.orderStatus=='COMPLETED'||obj.order.orderStatus=='BACKPAYED'">
重新购买</view>
<view class="toqx" v-if="obj.order.orderStatus=='HAVESEND'" @tap='refund()'>申请退款</view>
</view>
<u-popup v-model="show1" border-radius='20' mode='bottom'>
<view style="padding:48rpx;display: flex;flex-direction: column;">
<text style="color: #000;font-size: 36rpx;font-weight: bold;">取消政策</text>
<!-- <view
style="height: 88rpx;display: flex;align-items: center;position: relative;border-top: 1px dashed #E1E1E1;margin-top: 24rpx;">
<image src="https://aliyunoss.hn12301.net/sd/ticket_dg.png"
style="width: 40rpx;height: 40rpx;margin-right: 12rpx;"></image>
<text style="color: rgba(0, 0, 0, 0.8);">随时退</text>
</view>
<view style="position: relative;color: rgba(0, 0, 0, 0.5);">
该商品支持随时退,经核实未使用后,可免费取消。
</view> -->
<u-parse style="margin-top: 24rpx;" :html="obj.sku.refundPolicy"></u-parse>
<view style="width: 654rpx;height: 120rpx;"></view>
<view
style="width: 654rpx;position: fixed;height: 88rpx;line-height: 88rpx;background: #fff;bottom: 0rpx;">
<u-button shape="circle" size="default"
style="background: linear-gradient(180deg, #FF9E49 0%, #ED3B1A 100%);color: #fff;"
@click="show1=false">确定</u-button>
</view>
</view>
</u-popup>
<u-popup v-model="show" mode='bottom' border-radius='20'>
<view style="padding: 48rpx;">
<view style="width: 654rpx;text-align: center;font-size: 30rpx;font-weight: bold;">请选择游客</view>
<u-checkbox-group :wrap='true'>
<u-checkbox v-model="item.checked" v-for="(item, index) in list" :key="index"
:name="item.name">{{item.name}}</u-checkbox>
</u-checkbox-group>
<u-button shape="circle" size="default"
style="background: linear-gradient(180deg, #FF9E49 0%, #ED3B1A 100%);color: #fff;margin-top: 24rpx;"
@click="sure()">确定</u-button>
</view>
</u-popup>
</view>
</template>
<script>
// xuchao: 订单详情页 —— 待支付订单的"去支付"统一走 common/pay.js 支付层
import pay from '@/common/pay.js'
var that = ''
import {
getSkuType
} from '../../unit/utils.js'
export default {
data() {
return {
enterTypeList: [{
value: "二维码",
label: '1'
},
{
value: "实体票",
label: '2'
},
{
value: "第三方凭证码",
label: '3'
},
{
value: "身份证",
label: '4'
},
{
value: "护照",
label: '5'
},
{
value: "港澳居民来往内地通行证",
label: '6'
},
{
value: "台湾居民来往大陆通行证",
label: '7'
}
],
list: [],
show1: false,
show: false,
id: '',
obj: '',
getSkuType: '',
orderList: [{
text: '待支付',
value: 'WAITPAY',
label: '逾期未支付订单将自动关闭'
}, {
text: '出票中',
value: 'WAITSEND',
label: '正在出票中,预计30分钟内出票,超时未出票系统将为您自动退款'
}, {
text: '已出票',
value: 'HAVESEND',
label: '已出票,如有疑问请及时联系客服'
}, {
text: '已完成',
value: 'COMPLETED',
label: '订单已完成'
}, {
text: '已取消',
value: 'CANCELLED',
label: '订单已取消'
}, {
text: '退款中',
value: 'REFUNDING',
label: '已确认退款,款项将在1-7个工作日内退回您的付款渠道,请耐心等待'
}, {
text: '已退款',
value: 'BACKPAYED',
label: '退款完成,款项已退回您的付款渠道'
}]
}
},
computed: {
orderStatus() {
let str = ''
if (this.obj) {
str = this.orderList.filter(item => {
return item.value == this.obj.order.orderStatus
})[0].text
}
return str
},
orderTitle() {
let str = ''
if (this.obj) {
str = this.orderList.filter(item => {
return item.value == this.obj.order.orderStatus
})[0].label
}
return str
}
},
onLoad(e) {
that = this
this.id = e.id
this.getSkuType = getSkuType
this.getOrderDetail()
},
methods: {
cancel(e) {
uni.showModal({
title: '提示',
content: '确定要取消订单吗?',
success: function(res) {
if (res.confirm) {
that.$u.api.cancelTicketsOrder({
id: that.id,
}).then(res => {
that.getOrderDetail()
})
} else if (res.cancel) {
console.log('用户点击取消');
}
}
})
},
toPay() {
// xuchao: 支付层 —— 开发模式模拟成功,正式模式唤起微信支付
pay.pay(this, {
orderId: this.obj.order.id,
onSuccess: () => {
uni.showToast({
icon: 'success',
title: '支付成功'
})
this.getOrderDetail()
},
onFail: () => {
uni.showToast({
icon: 'none',
title: '支付未完成,可稍后再次支付'
})
}
})
},
refund() {
//
this.show = true
},
sure() {
console.log(this.list);
let arr = []
this.list.forEach(item => {
arr.push(item.id)
})
that.$u.api.refundTicketsOrderXgh({
orderId: this.id,
touristIdList: arr
}).then(res => {
if (res) {
this.show = false
uni.showToast({
icon: 'none',
title: res.data.message
})
setTimeout(() => {
this.getOrderDetail()
}, 1000)
}
})
},
aginPlay() {
uni.reLaunch({
url: 'scenicdetail?id=' + this.obj.tickets.id
})
},
coyp(e) {
uni.setClipboardData({
data: e + ''
})
},
getTyepStr(e) {
let typeStr = ''
e.split(',').forEach((item) => {
this.enterTypeList.forEach((item1) => {
if (item == item1.label) {
typeStr = typeStr + item1.value + '、'
}
})
})
return typeStr.slice(0, -1)
},
getOrderDetail() {
that.$u.api.getTicketsOrderDetail({
id: this.id,
}).then(res => {
if (res) {
this.obj = res.data
this.list = []
res.data.touristList.forEach(item => {
this.$set(item, 'checked', false)
this.list.push(item)
})
}
})
},
}
}
</script>
<style>
page {
background: #F8F9FC;
}
</style>
<style scoped lang="less">
.xsms-scroll {
overflow: hidden;
white-space: nowrap;
margin-top: 24rpx;
width: 654rpx;
}
.rypz {
width: 702rpx;
border: 1px dashed #E1E1E1;
margin-top: 24rpx;
padding: 24rpx;
.rq_item {
width: 404rpx;
height: 64rpx;
border-radius: 20rpx 20rpx 0rpx 0rpx;
background: #EEEFF3;
color: #000;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.rq_num {
width: 356rpx;
margin: 24rpx;
color: #000;
font-weight: bold;
white-space: normal;
overflow-wrap: break-word;
}
.rq_btn {
color: rgba(0, 0, 0, 0.8);
width: 72rpx;
height: 36rpx;
font-size: 20rpx;
border-radius: 36rpx;
border: 1px solid #E1E1E1;
display: flex;
align-items: center;
justify-content: center;
}
}
.tozf {
height: 64rpx;
background: linear-gradient(180deg, #FF9E49 0%, #ED3B1A 100%);
border-radius: 64rpx;
color: #fff;
font-weight: bold;
padding: 0rpx 24rpx;
display: flex;
align-items: center;
}
.toqx {
height: 64rpx;
background: rgba(0, 0, 0, 0.1);
border-radius: 64rpx;
color: #000;
font-weight: bold;
padding: 0rpx 24rpx;
display: flex;
align-items: center;
}
.detail_btn {
width: 750rpx;
height: 88rpx;
display: flex;
align-items: center;
background-color: #fff;
position: fixed;
bottom: 0rpx;
gap: 20rpx;
padding-right: 24rpx;
justify-content: flex-end;
}
.detail_h {
margin: 48rpx 24rpx 0rpx 24rpx;
background: #fff;
border-radius: 20rpx 20rpx 0rpx 0rpx;
padding: 24rpx;
width: 702rpx;
}
.detail_rq {
border-top: 1px #E1E1E1 solid;
background-color: #fff;
padding: 24rpx 24rpx 0rpx 24rpx;
}
</style>
+148
View File
@@ -0,0 +1,148 @@
<template>
<view>
<view class="item" v-for="(item,index) in lookList" :key="index" @tap='toOrderDetail(item.id)'>
<view class="item_h">
<text>订单编号:{{item.id}}</text>
<text>{{getText(item.orderStatus,1)}}</text>
</view>
<view class="item_rq">
<view style="font-weight: bold;color: #000;">{{item.skuName}}</view>
<view style="width: 606rpx;display: flex;justify-content: space-between;color: rgba(0, 0, 0, 0.8);margin-top: 24rpx;">
<text>使用日期:{{item.orderDate}}</text>
<text>¥{{(item.orderAmount/100).toFixed(2)}}</text>
</view>
</view>
</view>
<u-loadmore :status="status" />
</view>
</template>
<script>
var that=''
export default{
data(){
return{
status: 'loadmore',
obj: {
"orderPhone": "",
"orderStatus": "",
"pageSize": 10,
"pageNum": 1,
},
pageAll:2,
isLoad:true,
lookList:[],
orderList:[{
text:'待支付',
value:'WAITPAY',
label:'逾期未支付订单将自动关闭'
},{
text:'出票中',
value:'WAITSEND',
label:'正在出票中,预计30分钟内出票,超时未出票系统将为您自动退款'
},{
text:'已出票',
value:'HAVESEND',
label:'已出票,如有疑问请及时联系客服'
},{
text:'已完成',
value:'COMPLETED',
label:'订单已完成'
},{
text:'已取消',
value:'CANCELLED',
label:'订单已取消'
},{
text:'退款中',
value:'REFUNDING',
label:'已确认退款,款项将在1-7个工作日内退回您的付款渠道,请耐心等待'
},{
text:'已退款',
value:'BACKPAYED',
label:'退款完成,款项已退回您的付款渠道'
}]
}
},
onLoad(){
that=this
this.obj.orderPhone=uni.getStorageSync('phone')
},
onShow() {
this.pageAll=2
this.obj.pageNum=1
this.lookList=[]
this.queryTicketsOrderPageMethod()
},
onReachBottom() {
this.queryTicketsOrderPageMethod()
},
methods:{
getText(e,f){
if(f==1){
let str=this.orderList.filter(item=>{
return item.value==e
})[0].text
return str
}else if(f==2){
let str=this.orderList.filter(item=>{
return item.value==e
})[0].label
return str
}
},
queryTicketsOrderPageMethod() {
if (that.obj.pageNum <= that.pageAll&&this.isLoad) {
this.isLoad=false
this.$u.api.queryTicketsOrderPage(this.obj).then(res => {
this.isLoad=true
that.obj.pageNum = that.obj.pageNum * 1 + 1;
that.pageAll = Math.ceil(res.data.total / 10)
if (that.page == 2) {
that.lookList = res.data.list
} else {
that.lookList = that.lookList.concat(res.data.list)
}
if (that.obj.pageNum > that.pageAll) {
that.status = "nomore"
}
})
}
},
toOrderDetail(e){
uni.navigateTo({
url:'orderdetail?id='+e
})
}
}
}
</script>
<style>
page{
background: #F8F9FC;
padding-top: 24rpx;
}
</style>
<style lang="less" scoped>
.item{
width: 750rpx;
margin-bottom: 20rpx;
padding: 24rpx;
background: #fff;
.item_h{
width: 702rpx;
display: flex;
justify-content: space-between;
color: rgba(0, 0, 0, 0.5);
}
.item_rq{
width: 654rpx;
margin: 24rpx 24rpx 0rpx 24rpx;
background: #F8F9FC;
padding: 24rpx;
}
}
</style>
+726
View File
@@ -0,0 +1,726 @@
<template>
<view v-if="skuObj">
<!-- <view style="position: fixed;top: 0px;width: 750rpx;z-index: 1000;" :style="{height:windowHeight+'px'}">
<view style="width: inherit;" :style="{height:windowHeight-62+'px'}"></view> -->
<view class="db_rq" :style="{top:windowHeight-62+'px'}">
<view>
<text style="color: rgba(0, 0, 0, 0.5);font-size: 20rpx;">总价</text>
<view style="display: flex;align-items: flex-end;gap: 24rpx;" @tap='show1=true'>
<text style="color: #FF0000;font-size: 48rpx;font-weight: bold;">¥{{salesPriceSum}}</text>
<view style="margin-bottom: 10rpx;display: flex;align-items: center;gap: 10rpx;color: #457AF7;">
明细<u-icon name="arrow-down-fill" size='20'></u-icon></view>
</view>
</view>
<view class="bt" @tap="buy">立即购买</view>
</view>
<!-- </view> -->
<view style="padding: 24rpx;background-color: #fff;">
<view style="color: #000;font-size: 32rpx;font-weight: bold;line-height: normal;">
{{skuObj.sku.skuName}}
</view>
<text style="color: rgba(0, 0, 0, 0.5);font-size: 20rpx;">适用年龄:{{skuObj.sku.typeInfo}}</text>
<view style="margin-top: 24rpx;border-top: 1px dashed rgba(0, 0, 0, 0.1);"></view>
<view style="margin-top: 24rpx;color: rgba(0, 0, 0, 0.5);font-size: 500;position: relative;">使用日期
</view>
<view style="width: 702rpx;display: flex;gap: 8rpx;margin-top: 12rpx;">
<view v-for="(item,index) in cList" :key="index" v-if="index<3"
:class="item.isSelect?'mt_rq':item.isEnabled?'jt_rq':'ht_rq'" @click="selectDate(item)">
{{getDayName(item.enableDate)}}<br />
{{formatToMonthDay(item.enableDate)}}
<view class="jt_tag">{{item.isSelect?'√':item.isEnabled?'可订':'不可订'}}</view>
</view>
<view class="gd_rq" @tap="show=true">更多<br />
日期
<u-icon name="arrow-right" style="margin-left: 5rpx;"></u-icon>
</view>
</view>
<view style="margin-top: 24rpx;color: rgba(0, 0, 0, 0.5);font-size: 500;" v-if="!skuObj.sku.stockDateType">
适用时段</view>
<view style="width: 702rpx;display: flex;gap: 12rpx;margin-top: 12rpx;flex-wrap: wrap;"
v-if="!skuObj.sku.stockDateType">
<view :class="item.isSelect?'xz_item':'nx_item' " v-for="(item,index) in timeSlotList" :key="index"
@click="selectSlot(index)">{{item.name}}
<view class="xz_tag">余{{item.stock}}张</view>
</view>
</view>
<view style="margin-top: 24rpx;border-top: 1px dashed rgba(0, 0, 0, 0.1);"></view>
<view style="display: flex;align-items: center;margin-top: 24rpx;height: 96rpx;">
<text style="color: #000;font-size: 32rpx;font-weight: bold;">购买数量</text>
<u-number-box v-model="value" :max='getMaxStock()' :min='1' @change="valChange"
style="position: absolute;right: 24rpx;"></u-number-box>
</view>
</view>
<view style="padding: 24rpx;background-color: #fff;margin-top: 20rpx;" v-if="skuObj.sku.enterDemand=='2'">
<view style="display: flex;margin-top: 24rpx;align-items: flex-end;">
<text style="color: #000;font-size: 32rpx;font-weight: bold;">游客信息</text>
<view style="margin-left: 24rpx;color: rgba(0, 0, 0, 0.5);font-size: 20rpx;">
需要 <text style="color: #000;font-size: 24rpx;font-weight: bold;">{{value}}位</text> 出行游客信息,用于入园身份验证
</view>
</view>
<view style="margin-top: 24rpx;border-top: 1px dashed rgba(0, 0, 0, 0.1);"></view>
<view style="display: flex;gap: 24rpx;margin-top: 24rpx;">
<view class="xz_name" v-for="(item,index) in personList" :key="index">{{item.name}}</view>
<view class="nx_name" @tap='addPerson'>新增/更换 ></view>
</view>
<view v-for="(item,index) in personList" :key="index"
style="display: flex;width: 702rpx;color: #000;padding: 24rpx 0rpx;position:relative;border-bottom: 1px dashed rgba(0, 0, 0, 0.1);align-items: center;">
<u-icon name="close" style="color: rgba(0, 0, 0, 0.5);" @click="deletePerson(index)"></u-icon>
<text style="margin-left: 24rpx;">游客{{index+1}}</text>
<input style="margin-left: 104rpx;font-size: 28rpx;" v-model="item.name" :disabled="true" />
<input style="position: absolute;right: 0rpx;font-size: 28rpx;" v-model="item.identityNo"
:disabled="true" />
<!-- <text style="color: #0066F6;position: absolute;right: 0rpx;">编辑</text> -->
</view>
<view style="margin-top: 24rpx;color: rgba(0, 0, 0, 0.8);">
联系手机
<text style="color: #000;margin-left: 95rpx;">{{createInfo.mobile}}</text>
</view>
</view>
<view style="padding: 24rpx;background-color: #fff;margin-top: 20rpx;" v-else>
<view style="display: flex;margin-top: 24rpx;align-items: flex-end;">
<text style="color: #000;font-size: 32rpx;font-weight: bold;">联系人信息</text>
</view>
<view style="margin-top: 24rpx;border-top: 1px dashed rgba(0, 0, 0, 0.1);"></view>
<view style="margin-top: 24rpx;color: rgba(0, 0, 0, 0.8);display: flex;align-items: center;">
联系人
<input :adjust-position="false" type="text" v-model="createInfo.contactName"
style="color: #000;margin-left: 95rpx;" placeholder="请输入联系人姓名" />
</view>
<view style="margin-top: 24rpx;color: rgba(0, 0, 0, 0.8);">
手机号
<text style="color: #000;margin-left: 95rpx;">{{createInfo.mobile}}</text>
</view>
</view>
<u-calendar v-model="show" :mode="mode" activeBgColor='#F4612C' :calendarList='calendarList'
@change="change"></u-calendar>
<u-popup v-model="show1" border-radius='20' mode='bottom'>
<view style="padding:48rpx;display: flex;flex-direction: column;">
<text style="color: #000;font-size: 36rpx;font-weight: bold;">费用明细</text>
<text style="color: #000;font-size: 32rpx;font-weight: bold;margin-top: 18rpx;">景区/场馆</text>
<view
style="height: 88rpx;display: flex;align-items: center;position: relative;border-bottom: 1px dashed #E1E1E1;">
<text style="color: rgba(0, 0, 0, 0.5);">门票</text>
<text style="color: #000;position: absolute;right: 0rpx;">¥{{salesPrice}}
&nbsp;&nbsp;x{{value}}</text>
</view>
<view style="position: relative;margin-top: 24rpx;">
<view style="color: rgba(0, 0, 0, 0.5);font-size: 20rpx;position: absolute;right: 0rpx;">总价<text
style="color: #FF0000;">¥</text><text
style="color: #FF0000;font-size: 32rpx;">{{salesPriceSum}}</text>
</view>
</view>
<view style="width: 654rpx;height: 120rpx;"></view>
<view
style="width: 654rpx;position: fixed;height: 88rpx;line-height: 88rpx;background: #fff;bottom: 0rpx;">
<u-button shape="circle" size="default"
style="background: linear-gradient(180deg, #FF9E49 0%, #ED3B1A 100%);color: #fff;"
@click="show1=false">确定</u-button>
</view>
</view>
</u-popup>
</view>
</template>
<script>
// xuchao: 确认订单页 —— 支付统一走 common/pay.js 支付层
import pay from '@/common/pay.js'
var that = ''
export default {
data() {
return {
show1: false,
show: false,
mode: 'date',
sf: `**** **** **** *1918`,
mz: `李富贵`,
value: 1,
hday: '',
whday: '',
skuObj: '',
calendarList: [],
windowHeight: '',
mobile: '',
personList: [],
objInfo: '',
createInfo: {
"ticketsId": 0,
"skuId": 0,
"buyNum": 0,
"calendarId": 0,
"timeSlot": 0,
"touristIdList": [],
"contactMobile": "",
"contactName": "",
"price": "",
"orderSource": "Channel_XGH",
"mobile": ""
}
}
},
computed: {
salesPrice() {
let price = 0
if (this.skuObj) {
if (this.skuObj.sku.stockDateType) {
this.calendarList.forEach(item => {
if (item.isSelect) {
price = (item.salePrice / 100).toFixed(2)
}
})
} else {
this.timeSlotList.forEach(item => {
if (item.isSelect) {
price = (item.salePrice / 100).toFixed(2)
}
})
}
}
return price
},
salesPriceSum() {
let priceSum = 0
if (this.skuObj) {
if (this.skuObj.sku.stockDateType) {
this.calendarList.forEach(item => {
if (item.isSelect) {
priceSum = (item.salePrice * this.value / 100).toFixed(2)
}
})
} else {
this.timeSlotList.forEach(item => {
if (item.isSelect) {
priceSum = (item.salePrice * this.value / 100).toFixed(2)
}
})
}
}
return priceSum
},
cList() {
let arr = []
console.log(this.calendarList,12312);
if (this.calendarList.length != 0) {
this.calendarList.forEach((item, index) => {
if (item.isSelect && index < 3) {
if(this.calendarList.length==1){
arr.push(this.calendarList[0])
}else if(this.calendarList.length==2){
arr.push(this.calendarList[0])
arr.push(this.calendarList[1])
}else if(this.calendarList.length>=3){
arr.push(this.calendarList[0])
arr.push(this.calendarList[1])
arr.push(this.calendarList[2])
}
} else if (item.isSelect && index >= 3) {
arr.push(this.calendarList[0])
arr.push(this.calendarList[1])
arr.push(item)
}
})
}
console.log(arr);
return arr
},
timeSlotList() {
let arr = []
if (this.calendarList.length != 0) {
this.calendarList.forEach((item, index) => {
if (item.isSelect) {
arr = item.timeSlotList
}
})
if (arr) {
arr.forEach((item1, index1) => {
if (index1 == 0) {
this.$set(item1, 'isSelect', true)
} else {
this.$set(item1, 'isSelect', false)
}
})
}
}
return arr
}
},
onLoad() {
that = this
uni.getSystemInfo({
success: function(res) {
that.windowHeight = res.windowHeight
}
});
this.createInfo.mobile = uni.getStorageSync('phone')
this.createInfo.contactMobile = uni.getStorageSync('phone')
this.skuObj = uni.getStorageSync('scenicDetail')
this.createInfo.ticketsId = this.skuObj.tickets.id
this.createInfo.skuId = this.skuObj.sku.id
if (this.skuObj.sku.stockDateType) {
for (var i = 0; i < this.skuObj.calendarList.length; i++) {
this.skuObj.calendarList[i].enableDate = this.formatDateTime(this.skuObj.calendarList[i].enableDate)
if (this.skuObj.sku.bookType == 1) {
if (i == 0) {
this.$set(this.skuObj.calendarList[i], 'isSelect', true)
} else {
this.$set(this.skuObj.calendarList[i], 'isSelect', false)
}
} else {
if (i == 1) {
this.$set(this.skuObj.calendarList[i], 'isSelect', true)
this.skuObj.calendarList[0].isEnabled = false
} else {
this.$set(this.skuObj.calendarList[i], 'isSelect', false)
}
}
this.calendarList.push(this.skuObj.calendarList[i])
}
} else {
for (var i = 0; i < this.skuObj.timeSlotData.length; i++) {
this.$set(this.skuObj.timeSlotData[i], 'isEnabled', true)
this.$set(this.skuObj.timeSlotData[i], 'enableDate', this.formatDateTime(this.skuObj.timeSlotData[i]
.date))
if (this.skuObj.sku.bookType == 1) {
if (i == 0) {
this.$set(this.skuObj.timeSlotData[i], 'isSelect', true)
} else {
this.$set(this.skuObj.timeSlotData[i], 'isSelect', false)
}
} else {
if (i == 1) {
this.$set(this.skuObj.timeSlotData[i], 'isSelect', true)
this.skuObj.timeSlotData[0].isEnabled = false
} else {
this.$set(this.skuObj.timeSlotData[i], 'isSelect', false)
}
}
this.calendarList.push(this.skuObj.timeSlotData[i])
}
}
console.log(this.calendarList);
},
onShow() {
var pages = getCurrentPages();
var prevPage = pages[pages.length - 1];
if (prevPage.objitem != undefined) {
that.isshow = true
that.personList = JSON.parse(prevPage.objitem);
}
},
methods: {
formatDateTime(isoString) {
// const date = new Date(isoString);
// const year = date.getFullYear();
// const month = String(date.getMonth() + 1).padStart(2, '0');
// const day = String(date.getDate()).padStart(2, '0');
// const hours = String(date.getHours()).padStart(2, '0');
// const minutes = String(date.getMinutes()).padStart(2, '0');
// const seconds = String(date.getSeconds()).padStart(2, '0');
return isoString.replace(/-/g, "/");;
},
getMaxStock() {
let stock = 0
if (this.skuObj.sku.stockNumType) {
stock = 99999
} else {
if (this.skuObj.sku.stockDateType) {
this.calendarList.forEach(item => {
if (item.isSelect) {
stock = item.stock
}
})
} else {
this.timeSlotList.forEach(item => {
if (item.isSelect) {
stock = item.stock
}
})
}
}
return stock
},
deletePerson(e) {
this.personList.splice(e, 1)
},
selectDate(e) {
if (e.isEnabled) {
this.cList.forEach(item => {
if (item.enableDate == e.enableDate) {
item.isSelect = true
} else {
item.isSelect = false
}
})
}
this.value = 1
},
selectSlot(e) {
this.timeSlotList.forEach((item, index) => {
if (e == index) {
this.timeSlotList[index].isSelect = true
} else {
this.timeSlotList[index].isSelect = false
}
})
this.value = 1
},
formatToMonthDay(dateStr) {
const date = new Date(dateStr)
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return `${month}月${day}日`;
},
valChange(e) {
console.log('当前值为: ' + e.value)
},
change(e) {
this.calendarList.forEach((item, index) => {
if (new Date(item.enableDate).getTime() == new Date(e.result + ' 00:00:00').getTime()) {
item.isSelect = true
} else {
item.isSelect = false
}
})
this.value = 1
},
formatDateToMMDD(dateStr) {
const [year, month, day] = dateStr.split('-');
return `${month.padStart(2, '0')}月${day.padStart(2, '0')}日`;
},
buy() {
// uni.showModal({
// title: '提示',
// content: '预订人同一证件号1天内,最多可购买1份,当前超限制的证件号尾号为0514',
// showCancel: false
// })
if (this.skuObj.sku.enterDemand == '2') {
if (this.value > this.personList.length) {
uni.showToast({
icon: 'none',
title: '还需填写' + (this.value - this.personList.length) + '位游客信息',
duration: 2000
});
return
}
} else {
if (this.createInfo.contactName == '') {
uni.showToast({
icon: 'none',
title: '请填写联系人姓名',
duration: 2000
});
return
}
}
this.createInfo.buyNum = this.value
if (this.skuObj.sku.stockDateType) {
this.createInfo.calendarId = this.cList.filter(item => {
return item.isSelect
})[0].id
} else {
this.createInfo.timeSlot = this.timeSlotList.filter(item => {
return item.isSelect
})[0].id
}
this.createInfo.price = this.salesPriceSum
this.createInfo.touristIdList = this.personList.map(item => {
return item.id
})
console.log(this.createInfo);
this.$u.api.createTicketsOrder(this.createInfo).then(res => {
if (res.errcode == 0) {
// xuchao: 支付层 —— 开发模式模拟成功,正式模式唤起微信支付
pay.pay(this, {
orderId: res.data,
onSuccess: () => {
uni.redirectTo({
url: 'paysuccess?id=' + res.data
})
},
onFail: () => {
uni.showToast({
icon: 'none',
title: '支付未完成,可在订单中继续支付',
duration: 2000
})
setTimeout(() => {
uni.redirectTo({
url: 'orderlist'
})
}, 1500)
}
})
}
})
},
addPerson() {
uni.navigateTo({
url: 'select?value=' + this.value
})
},
getFormattedDate(offset = 0) {
const date = new Date();
date.setDate(date.getDate() + offset);
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return `${month}月${day}日`;
},
getDayName(date) {
const today = new Date();
today.setHours(0, 0, 0, 0);
const inputDate = new Date(date);
inputDate.setHours(0, 0, 0, 0);
const diffDays = Math.round((inputDate - today) / (1000 * 60 * 60 * 24));
// 处理今天/明天/后天
if (diffDays === 0) return "今天";
if (diffDays === 1) return "明天";
if (diffDays === 2) return "后天";
// 其他日期返回星期几
const weekDays = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
return weekDays[inputDate.getDay()];
}
}
}
</script>
<style>
page {
background: #F8F9FC;
}
</style>
<style scoped lang="less">
.bt {
width: 288rpx;
height: 100rpx;
background: linear-gradient(180deg, #FF9E49 0%, #ED3B1A 100%);
border-radius: 100rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 36rpx;
color: #fff;
position: absolute;
right: 24rpx;
bottom: 14rpx;
font-weight: bold;
}
.db_rq {
width: 750rpx;
background-color: #fff;
height: 62px;
position: fixed;
// bottom: 0rpx;
padding: 14rpx 24rpx;
}
.xz_name {
height: 56rpx;
padding: 0rpx 24rpx;
line-height: 56rpx;
color: #fff;
border-radius: 4rpx;
background: linear-gradient(180deg, #FF9E49 0%, #ED3B1A 100%);
}
.nx_name {
height: 56rpx;
padding: 0rpx 24rpx;
line-height: 56rpx;
color: rgba(0, 0, 0, 0.5);
border-radius: 4rpx;
background: #F8F9FC;
border: 1px solid rgba(0, 0, 0, 0.1);
}
.nx_item {
width: 226rpx;
height: 110rpx;
border-radius: 8rpx;
border: 1px solid #E1E1E1;
color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
position: relative;
.xz_tag {
height: 30rpx;
padding: 0rpx 10rpx;
display: flex;
align-items: center;
color: rgba(0, 0, 0, 0.5);
font-size: 16rpx;
background: #E1E1E1;
border-radius: 0px 8rpx 0px 8rpx;
position: absolute;
top: 0rpx;
right: 0rpx;
}
}
.xz_item {
width: 226rpx;
height: 110rpx;
border-radius: 8rpx;
border: 1px solid #F66C31;
color: #F66C31;
display: flex;
align-items: center;
justify-content: center;
position: relative;
.xz_tag {
height: 30rpx;
padding: 0rpx 10rpx;
display: flex;
align-items: center;
color: #fff;
font-size: 16rpx;
background: linear-gradient(180deg, #FF9E49 0%, #ED3B1A 100%);
border-radius: 0px 8rpx 0px 8rpx;
position: absolute;
top: 0rpx;
right: 0rpx;
}
}
.gd_rq {
width: 120rpx;
height: 170rpx;
border: 1px solid #E1E1E1;
border-radius: 8rpx;
color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
}
.ht_rq {
width: 186rpx;
height: 170rpx;
border: 1px solid #E1E1E1;
border-radius: 8rpx;
color: rgba(0, 0, 0, 0.5);
position: relative;
line-height: 24px;
padding-top: 48rpx;
padding-left: 24rpx;
background: #F8F9FC;
.jt_tag {
font-size: 16rpx;
height: 30rpx;
display: flex;
align-items: center;
padding: 0rpx 10rpx;
background: #E1E1E1;
border-radius: 0px 8rpx 0px 8rpx;
position: absolute;
top: 0rpx;
right: 0rpx;
}
}
.jt_rq {
width: 186rpx;
height: 170rpx;
border: 1px solid #E1E1E1;
border-radius: 8rpx;
color: rgba(0, 0, 0, 0.5);
position: relative;
line-height: 24px;
padding-top: 48rpx;
padding-left: 24rpx;
.jt_tag {
font-size: 16rpx;
height: 30rpx;
display: flex;
align-items: center;
padding: 0rpx 10rpx;
background: #E1E1E1;
border-radius: 0px 8rpx 0px 8rpx;
position: absolute;
top: 0rpx;
right: 0rpx;
}
}
.mt_rq {
width: 186rpx;
height: 170rpx;
border: 1px solid #F66C31;
border-radius: 8rpx;
color: #F66C31;
position: relative;
line-height: 24px;
padding-top: 48rpx;
padding-left: 24rpx;
.jt_tag {
font-size: 16rpx;
height: 30rpx;
display: flex;
align-items: center;
padding: 0rpx 10rpx;
background: linear-gradient(180deg, #FF9E49 0%, #ED3B1A 100%);
border-radius: 0px 8rpx 0px 8rpx;
position: absolute;
color: #fff;
top: 0rpx;
right: 0rpx;
}
}
</style>
+163
View File
@@ -0,0 +1,163 @@
<template>
<view v-if="obj">
<view class="od_top">
<view class="od_top_first">
<image src="http://cdn.hntgov.net/online/static/ps_ps.png"></image>支付成功
</view>
</view>
<view style="background-color: #fff;">
<view class="od_sh">
<image style="width: 32rpx;height: 28rpx;" src="http://cdn.hntgov.net/online/static/pas_ps.png">
</image>
<view class="od_sh_right">
<!-- xuchao: 支付方式改为微信支付 -->
<text style="color: #696969;">支付方式:<text style="color: #3D3D3D;">微信支付</text></text>
<text style="color: #696969;padding-top: 16rpx;">实付金额:<text
style="color: #3D3D3D;">¥{{(obj.order.orderAmount/100).toFixed(2)||0}}</text></text>
</view>
</view>
<view class="od_line"></view>
<view class="ps_item">
<!-- xuchao: 接通"查看订单"入口(旧版此按钮被注释成了死页面) -->
<view class="ps_item_item" style="color: #181617;" @tap='seeOrder()'>查看订单</view>
<view style="width: 1rpx;height: 48rpx;background-color: #E7E6E6;"></view>
<view class="ps_item_item" style="color: #ED2D38;" @tap='toMall()'>继续逛逛</view>
</view>
</view>
<u-toast ref="uToast" />
</view>
</template>
<script>
// xuchao: 支付成功页 —— 支付完成后跳入,轮询订单状态直到后端确认
var that = ''
export default {
data() {
return {
id: '',
obj: "",
// xuchao: 轮询订单状态(等待后端支付回调把订单从"待支付"更新掉)
pollTimer: null,
pollTimes: 5
}
},
onLoad(e) {
that = this
that.id = e.id
that.getOrderDetail()
},
onUnload() {
clearInterval(this.pollTimer)
},
methods: {
seeOrder() {
uni.reLaunch({
url: 'orderlist'
})
},
// xuchao: "继续逛逛"回到门票列表(旧版指向的商城页已不存在)
toMall() {
uni.reLaunch({
url: '/pages/ticket/scenic'
})
},
getOrderDetail() {
that.$u.api.getTicketsOrderDetail({
id: this.id,
}).then(res => {
if (res) {
this.obj = res.data
// 订单仍为待支付时轮询,最多 5 次(每次间隔 2 秒)
if (this.obj.order.orderStatus == 'WAITPAY' && this.pollTimes > 0) {
clearInterval(this.pollTimer)
this.pollTimer = setInterval(() => {
this.pollTimes--
if (this.pollTimes <= 0) {
clearInterval(this.pollTimer)
return
}
this.getOrderDetail()
}, 2000)
} else {
clearInterval(this.pollTimer)
}
}
})
}
}
}
</script>
<style>
page {
background-color: #f7f7f7;
}
</style>
<style scoped lang="scss">
.ps_item {
width: 690rpx;
margin-left: 30rpx;
height: 96rpx;
align-items: center;
display: flex;
.ps_item_item {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
font-size: 30rpx;
font-weight: bold;
}
}
.od_top {
width: 750rpx;
height: 210rpx;
background: linear-gradient(90deg, #FF3F3C -8%, #FFA371 107%);
padding-top: 56rpx;
padding-left: 70rpx;
display: flex;
flex-direction: column;
}
.od_top_first {
display: flex;
align-items: center;
color: #FFF;
font-size: 34rpx;
}
.od_top_first image {
width: 50rpx;
height: 50rpx;
margin-right: 20rpx;
}
.od_sh {
padding: 30rpx;
display: flex;
align-items: center;
font-size: 26rpx;
background-color: #fff;
.od_sh_right {
width: 640rpx;
margin-left: 18rpx;
display: flex;
flex-direction: column;
}
}
.od_line {
width: 690rpx;
height: 1rpx;
background-color: #E7E6E6;
margin-left: 30rpx;
}
</style>
+215
View File
@@ -0,0 +1,215 @@
<template>
<view>
<u-form :model="form" :rules="rules" ref="uForm">
<view style="background-color: #fff;padding-left: 30rpx;padding-right: 30rpx;">
<u-form-item label-width="200" :label-position="labelPosition" label="出行人姓名" prop="name">
<u-input placeholder="请输入出行人姓名" v-model="form.name" type="text"></u-input>
</u-form-item>
</view>
<view style="background-color: #fff;padding-left: 30rpx;padding-right: 30rpx;margin-top: 20rpx;">
<u-form-item label-width="200" :label-position="labelPosition" label="联系号码" prop="phone">
<u-input placeholder="请输入联系号码" v-model="form.phone" type="text"></u-input>
</u-form-item>
</view>
<view style="background-color: #fff;padding-left: 30rpx;padding-right: 30rpx;margin-top: 20rpx;">
<u-form-item label="证件类型" prop="idType" label-width="200" :label-position="labelPosition">
<u-input v-model="idTypeName" placeholder='请选择证件类型' type="select" @click="idTypeShow()" />
</u-form-item>
</view>
<view style="background-color: #fff;padding-left: 30rpx;padding-right: 30rpx;margin-top: 20rpx;">
<u-form-item label-width="200" :label-position="labelPosition" label="证件号码" prop="identityNo">
<u-input placeholder="请输入证件号码" v-model="form.identityNo" type="text"></u-input>
</u-form-item>
</view>
</u-form>
<view class="pp_hh" @click="submit()">完成</view>
<u-action-sheet :list="actionSheetList" v-model="show" @click="actionSheetCallback"></u-action-sheet>
</view>
</template>
<script>
var that = ''
export default {
data() {
return {
show: false,
action: 'https://api.xhmyjq.com/web/upload/single',
fileList: [],
header: {
'token': '',
'Content-Type': 'multipart/form-data' // 设置请求头为multipart/form-data
},
labelPosition: 'left',
actionSheetList: [{
value: 'IDCARD',
text: '身份证'
},
{
value: 'PASSPORT',
text: '护照'
},
{
value: 'HONGKONG',
text: '港澳居民来往内地通行证'
},
{
value: 'TAIWAN',
text: '台湾居民来往大陆通行证'
}
],
form: {
"mobile": "",
"name": "",
"idType": "IDCARD",
"phone": "",
"identityNo": "",
"isDefault": true
},
idTypeName: '身份证',
rules: {
name: [{
required: true,
message: '请填写真实姓名',
// 可以单个或者同时写两个触发验证方式
trigger: ['change', 'blur'],
}],
phone: [{
required: true,
message: '请填写手机号码',
// 可以单个或者同时写两个触发验证方式
trigger: ['change', 'blur'],
}],
identityNo: [{
required: true,
message: '请填写证件号码',
// 可以单个或者同时写两个触发验证方式
trigger: ['change', 'blur'],
}],
},
userId: '',
fullName: '',
identityNo: '',
id: '',
mobile: '',
code: '',
errorMessage: '',
errorMessage1: '',
isOpen: false,
}
},
watch: {
},
onReady() {
console.log(11);
this.$refs.uForm.setRules(this.rules);
},
onLoad(e) {
that = this
this.form.mobile=uni.getStorageSync('phone')
if (e.info) {
this.id = JSON.parse(e.info).id
this.form.name = JSON.parse(e.info).name
this.form.identityNo = JSON.parse(e.info).identityNo
this.form.idType=JSON.parse(e.info).idType
this.form.phone=JSON.parse(e.info).phone
this.actionSheetList.forEach(item=>{
// xuchao: 修正旧版笔误 —— 原来误拿 phone 和 value 比较,证件类型回显不对
if(item.value==this.form.idType){
this.idTypeName=item.text
}
})
}
// this.getMiniProgramMethod()
},
methods: {
actionSheetCallback(index) {
this.form.idType = this.actionSheetList[index].value
this.idTypeName = this.actionSheetList[index].text
},
getMiniProgramMethod() {
that.$u.mapApi.getMiniProgram().then(res => {
if (res) {
that.isOpen = res.isOpen
}
})
},
idTypeShow() {
this.show = !this.show
},
onSuccess(e) {
console.log(e);
if (e.code == 600) {
uni.removeStorageSync('phone')
uni.navigateTo({
url: '/pages/index/authorization'
})
} else {
this.form.facePhoto = e.data.url
}
},
submit() {
this.$refs.uForm.validate(valid => {
if (valid) {
// xuchao: 身份证类型增加 18 位格式校验,避免填错到景区门口才发现
if (this.form.idType == 'IDCARD' && !/^\d{17}[\dXx]$/.test(this.form.identityNo)) {
uni.showToast({
icon: 'none',
title: '请输入正确的18位身份证号'
})
return
}
if (that.id == '' || that.id == undefined) {
this.addTicketsMemberTouristMethod()
} else {
this.updateTicketsMemberTouristMethod()
}
} else {
console.log('验证失败');
}
});
},
updateTicketsMemberTouristMethod() {
this.$set(this.form,'id',this.id)
console.log(this.form);
that.$u.api.updateTicketsMemberTourist(this.form).then(res => {
if (res) {
uni.navigateBack()
}
})
},
addTicketsMemberTouristMethod() {
that.$u.api.addTicketsMemberTourist(this.form).then(res => {
if (res) {
uni.navigateBack()
}
})
}
}
}
</script>
<style scoped lang="less">
.pp_hh {
width: 702rpx;
height: 88rpx;
border-radius: 48rpx;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 28rpx;
background: linear-gradient(180deg, #FF9E49 0%, #ED3B1A 100%);
margin-left: 30rpx;
position: fixed;
bottom: 25rpx;
}
</style>
+390
View File
@@ -0,0 +1,390 @@
<template>
<view>
<view style="width: 750rpx;background-color: #fff;padding:15rpx 0rpx;" v-if="false">
<view style="width: 702rpx;margin-left: 24rpx;">
<u-search placeholder="搜景区名称" bg-color='#F8F9FC' search-icon-color='#7C7C7E' v-model="obj.name" @search='search()'
:show-action='false' height='72'></u-search>
</view>
</view>
<view v-if="false"
style="width: 750rpx;height: 88rpx;background: #fff;padding: 0rpx 24rpx;display: flex;align-items: center;color: #000;position: relative;">
<view @tap="selectArae" style="display: flex;gap: 10rpx;">
{{cityName}}<u-icon :style="{transform:transform}" style="transition: 500ms;" name="arrow-down-fill"
size='20'></u-icon>
</view>
<view @tap="selectType" style="display: flex;gap: 10rpx;margin-left: 72rpx;">
{{typeName}}
<u-icon :style="{transform:transform1}" style="transition: 500ms;" name="arrow-down-fill"
size='20'></u-icon>
</view>
<view style="position: absolute;right: 0rpx;">
<u-checkbox-group @change='search()'>
<u-checkbox v-model="obj.todayAvailable" :label-disabled="false" active-color="#3B94E6"><text style="color: #000;">今日可用</text></u-checkbox>
</u-checkbox-group>
</view>
</view>
<view class='nr_item' v-for="(item,index) in lookList" :key="index" @click="toDetail(item.id)" >
<image :src="item.mainPic||'https://aliyunoss.hn12301.net/sd/all_moren.png'" style="width: 268rpx;height: 268rpx;"></image>
<view class="nr_item_r">
<text class="n_text">{{item.name||''}}</text>
<view style="display: flex;gap: 12rpx;flex-wrap: wrap;">
<text :class="index1==0?'t_text1':index1==1?'t_text':index1==2?'t_text2':'t_text3'" v-for="(item1,index1) in ['节日福利/春游秋游','余额券','满减券']">{{item1}}</text>
</view>
<view class="r_text">{{item.subTypeId}}</view>
<!-- <u-tag :text="" bg-color='#FEEFC3' color='#D17516' mode="dark" /> -->
<view style="width: 380rpx;text-align: right;color:#4F4F4F;font-size: 12rpx;position: absolute;bottom: 60rpx;right:0rpx;">
原售价<text
style="font-size: 28rpx;text-decoration: line-through;font-weight: bold;">{{(item.price/100).toFixed(0)}}</text>元
</view>
<view class="p_text">工会补贴价¥<text
style="font-size: 32rpx;font-style: italic;font-weight: bold;margin-bottom: 8rpx;">{{(item.unitPrice/100).toFixed(0)}}</text>元
</view>
</view>
</view>
<u-loadmore :status="status" />
<u-picker mode="selector" v-model="show" :range="selector1" @close='selectAraeInput' confirm-color='#3B94E6' range-key="name"
@confirm='araeConfirm'></u-picker>
<u-picker mode="selector" v-model="show1" :range="selector" @close='selectTypeInput' confirm-color='#3B94E6' range-key="label"
@confirm='typeConfirm'></u-picker>
<!-- xuchao: 订单悬浮按钮 -->
<gmy-float-touch :imgLists="imgLists" :mainImg="mainImg" @menuClick="floatTouchClick"></gmy-float-touch>
</view>
</template>
<script>
// xuchao: 门票列表页(启动页/入口页)—— 进页必须登录
import auth from '@/common/auth.js'
import gmyFloatTouch from "@/components/gmy-float-touch/gmy-float-touch.vue"
var that = ''
export default {
components: { gmyFloatTouch },
data() {
return {
mainImg: "../../static/logo4.png",
imgLists: ["../../static/logo1.png", "../../static/logo2.png", "../../static/logo3.png",
"../../static/logo3.png", "../../static/logo5.png"
],
status: 'loadmore',
keyword: '',
transform: 'rotate(0deg)',
transform1: 'rotate(0deg)',
cityName: '全部地区',
typeName: '全部类型',
icon: true,
show: false,
show1: false,
icon1: true,
selector1: [{id:'',name:'全部地区'}],
selector: [{id:'',label:'全部类型'}],
checked: false,
page: 1,
obj: {
"name": "",
"typeId": "",
"cityId": "",
"pageSize": 10,
"pageNum": 1,
"todayAvailable": false
},
pageAll:2,
isLoad:true,
lookList:[]
}
},
onLoad() {
that = this
// xuchao: 未登录则跳登录页,登录成功后回跳本页
if (!auth.requireLogin('/pages/ticket/scenic')) return
this.getTicketsTypesMethod()
this.getTicketsCitiesMethod()
this.queryTicketsPageMethod()
},
onReachBottom() {
this.queryTicketsPageMethod()
},
methods: {
getTicketsCitiesMethod(){
this.selector1=[{id:'',name:'全部地区'}]
this.$u.api.getTicketsCities().then(res => {
if (res) {
res.data.forEach(item=>{
this.selector1.push({id:item.id,name:item.name})
})
}
})
},
getTicketsTypesMethod(){
this.selector=[{id:'',label:'全部类型'}]
this.$u.api.getTicketsTypes().then(res => {
if (res) {
console.log(res.data);
res.data.forEach(item=>{
this.selector.push({id:item.id,label:item.label})
})
}
})
},
queryTicketsPageMethod() {
if (that.obj.pageNum <= that.pageAll&&this.isLoad) {
this.isLoad=false
this.$u.api.queryTicketsPage(this.obj).then(res => {
this.isLoad=true
that.obj.pageNum = that.obj.pageNum * 1 + 1;
that.total = res.data.total
that.pageAll = Math.ceil(res.data.total / 10)
if (that.page == 2) {
that.lookList = res.data.list
} else {
that.lookList = that.lookList.concat(res.data.list)
}
if (that.page > that.pageAll) {
that.status = "nomore"
}
})
}
},
toDetail(e) {
uni.navigateTo({
url: 'scenicdetail?id='+e
})
},
// xuchao: 悬浮按钮 —— 跳门票订单列表
floatTouchClick(e) {
if (e == 4) {
uni.navigateTo({
url: '/pages/ticket/orderlist'
})
}
},
selectArae() {
this.icon = !this.icon
this.show = !this.show
if (this.icon) {
this.transform = 'rotate(0deg)'
} else {
this.transform = 'rotate(180deg)'
}
},
selectAraeInput(e) {
console.log(e);
this.icon = !this.icon
this.show = e
if (this.icon) {
this.transform = 'rotate(0deg)'
} else {
this.transform = 'rotate(180deg)'
}
},
selectTypeInput(e) {
this.icon1 = !this.icon1
this.show1 = e
if (this.icon1) {
this.transform1 = 'rotate(0deg)'
} else {
this.transform1 = 'rotate(180deg)'
}
},
search(){
this.obj.pageNum=1
this.pageAll=2
this.lookList=[]
this.queryTicketsPageMethod()
},
selectType() {
this.icon1 = !this.icon1
this.show1 = !this.show1
if (this.icon1) {
this.transform1 = 'rotate(0deg)'
} else {
this.transform1 = 'rotate(180deg)'
}
},
typeConfirm(e) {
console.log(e);
this.typeName = this.selector[e[0]].label
this.obj.typeId= this.selector[e[0]].id
this.search()
},
araeConfirm(e) {
this.cityName=this.selector1[e[0]].name
this.obj.cityId=this.selector1[e[0]].id
this.search()
}
}
}
</script>
<style>
page {
background: #FFEFD5;
}
</style>
<style scoped lang="less">
.nr_item {
width: 702rpx;
display: flex;
margin: 24rpx 24rpx 0rpx 24rpx;
background: #fff;
padding: 12rpx;
.nr_item_r {
width: 390rpx;
margin-left: 20rpx;
display: flex;
gap: 8rpx;
flex-direction: column;
position: relative;
.p_text {
position: absolute;
bottom: 0rpx;
width: 240rpx;
right: 0rpx;
height: 50rpx;
background: url('https://aliyunoss.hn12301.net/xgh/image_bj_text.png');
background-size: 100% 100%;
display: flex;
align-items: center;
color: #fff;
font-size: 16rpx;
padding-left: 18rpx;
border-radius: 4rpx;
}
.r_text {
width: 390rpx;
overflow: hidden !important;
text-overflow: ellipsis !important;
display: -webkit-box !important;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-size: 20rpx;
}
.r_text1 {
width: 390rpx;
overflow: hidden !important;
text-overflow: ellipsis !important;
display: -webkit-box !important;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
font-size: 20rpx;
}
.n_text {
color: #008F90;
font-weight: bolder;
overflow: hidden !important;
text-overflow: ellipsis !important;
display: -webkit-box !important;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
font-size: 32rpx;
}
.n_text1{
color: #585858;
font-size: 28rpx;
font-weight: bold;
overflow: hidden !important;
text-overflow: ellipsis !important;
display: -webkit-box !important;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
font-size: 24rpx;
}
.t_text {
background-color: #FDEEC3;
font-size: 18rpx;
padding: 5rpx 10rpx;
color: #D57817;
border-radius: 4rpx;
}
.t_text1 {
background-color: #FDF4ED;
font-size: 18rpx;
padding: 5rpx 10rpx;
color: #AF4744;
border-radius: 4rpx;
}
.t_text2 {
background-color: #cbebfb;
font-size: 18rpx;
padding: 5rpx 10rpx;
color: #6ba0b3;
border-radius: 4rpx;
}
.t_text3 {
background-color: #F0F1F5;
font-size: 18rpx;
padding: 5rpx 10rpx;
color: #525357;
border-radius: 4rpx;
}
}
}
.item {
width: 702rpx;
padding: 12rpx;
border-radius: 8rpx;
background-color: #fff;
position: relative;
margin-top: 24rpx;
display: flex;
margin-left: 24rpx;
.item_name {
width: 434rpx;
line-height: normal;
color: #000;
font-size: 28rpx;
font-weight: bold;
overflow: hidden !important;
text-overflow: ellipsis !important;
display: -webkit-box !important;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.tag {
font-size: 20rpx;
color: #fff;
padding: 6rpx 5rpx;
background: linear-gradient(180deg, #FF9E49 0%, #ED3B1A 100%);
border-radius: 4rpx;
margin-top: 12rpx;
margin-right: 12rpx;
}
.tag1 {
font-size: 20rpx;
color: #999999;
padding: 5rpx;
border: 2rpx #999999 solid;
border-radius: 4rpx;
margin-top: 12rpx;
margin-right: 12rpx;
}
.hot_tag {
height: 36rpx;
color: #fff;
font-size: 20rpx;
position: absolute;
top: 12rpx;
left: 12rpx;
background: rgba(0, 0, 0, 0.5);
padding: 0rpx 8rpx;
border-radius: 8rpx 0rpx 8rpx 0rpx;
line-height: 36rpx;
}
}
</style>
+399
View File
@@ -0,0 +1,399 @@
<template>
<view v-if="obj">
<view class="wrap">
<u-swiper :list="list" height='750' mode='number' indicator-pos='bottomRight'
marginBottom='30rpx'></u-swiper>
</view>
<view style="position: absolute;top: 700rpx;">
<view class="title">
<view class="t_name">{{obj.tickets.name}} <text style="color: #FF8D28;">{{obj.shop.level}}</text></view>
<view class="t_info">{{obj.tickets.remark1}}</view>
<view class="t_opentime">
<view style="display: flex;gap: 8rpx;color: #FF8D28;">
<image src="https://aliyunoss.hn12301.net/xgh/ticket_opentime.png"
style="width: 36rpx;height: 36rpx;"></image>开园时间
</view>
<text style="color: #8E8E93;font-size: 24rpx;">{{obj.tickets.openDate}}</text>
</view>
<view class="t_address">
<view style="width: 548rpx;">{{obj.shop.address}}</view>
<image src="https://aliyunoss.hn12301.net/xgh/ticket_dh.png" @click="handleOpen()"></image>
<image style="margin-left: 24rpx;" src="https://aliyunoss.hn12301.net/xgh/ticket_dhua.png"
@click="playPhone()"></image>
</view>
<!-- <view style="color: #FF0000;font-size: 32rpx;margin-top: 24rpx;"><text
style="font-size: 20rpx;">¥</text>{{(obj.minPrice/100).toFixed(0)}} ~ {{(obj.maxPrice/100).toFixed(0)}}</view>
<view style="display: flex;margin-top: 24rpx;">
<text class="tag" v-for="item in obj.tickets.tags.split(',')" :key="item">{{item}}</text>
</view> -->
</view>
<view class="ticket">
<!-- <text style="color: #000;font-size: 36rpx;line-height: 88rpx;font-weight: 700;">成人票</text> -->
<view class="ticket_item" style="margin-top: 0rpx;" v-for="(item,index) in obj.skuList" :key="index">
<view style="width: 338rpx;display: flex;flex-direction: column;">
<text
style="color: #000;font-size: 28rpx;font-weight: 700;">【{{getSkuType(item.typeId)}}】{{item.skuName}}</text>
<view
style="color: #7C7C7E;display: flex;align-items: center;margin-top: 16rpx;font-size: 24rpx;">
{{item.bookTimeLimit}}之前{{item.bookType?'可订当天':'可订明日'}}<text
style="color: #DFE0E2;font-size: 48rpx;padding: 0rpx 12rpx;">·</text>
</view>
<view style="color: #0066F6;margin-top: 16rpx;" @click="seeSkuDetail(item.id)">预订须知 ></view>
</view>
<view
style="width: 292rpx;display: flex;flex-direction: column;margin-left: 24rpx;align-items: flex-end;">
<view
style="color: #FF0000;font-size: 28rpx;margin-top: 0rpx;display: flex;justify-content: flex-end;">
原售价<text
style="font-size: 28rpx;font-weight: normal;text-decoration: line-through;">¥{{item.calendar.listPrice?(item.calendar.listPrice/100).toFixed(2):0}}</text>
</view>
<view style="color: #FF0000;font-size: 36rpx;font-weight: bold;line-height: 88rpx;">
<text
style="font-size: 20rpx;font-weight: normal;">工会会员补贴价¥</text>{{item.calendar.salePrice?(item.calendar.salePrice/100).toFixed(2):0}}
</view>
<view class="btn" @tap="toOrderSure(item.id)">购买</view>
</view>
</view>
</view>
<view class="ticket">
<text style="color: #000;font-size: 36rpx;line-height: 88rpx;font-weight: 700;">产品介绍</text>
<u-parse :html="obj.tickets.introduction"></u-parse>
</view>
</view>
<u-popup v-model="show" border-radius='20' mode='bottom' height='1000'>
<view style="padding:0rpx 48rpx;" v-if="skuObj">
<view
style="width: 654rpx;height: 142rpx;line-height: 142rpx;text-align: center;color: #000;font-size: 32rpx;font-weight: bold;border-bottom: 2rpx #E1E1E1 dashed;">
{{skuObj.sku.skuName}}
</view>
<view style="width: 654rpx;padding: 48rpx 0rpx">
<text style="color: #000;font-size: 32rpx;font-weight: bold;">预订规则</text>
<view style="display: flex;margin-top: 24rpx;">
<view style="color: #808080;width: 120rpx;">预订时间</view>
<view style="width: 494rpx;margin-left: 48rpx;color: #000;">
{{skuObj.sku.bookTimeLimit}}之前{{skuObj.sku.bookType?'可订当天':'可订明日'}}
</view>
</view>
<view style="display: flex;margin-top: 24rpx;">
<view style="color: #808080;width: 120rpx;">生效时间</view>
<view style="width: 494rpx;margin-left: 48rpx;color: #000;">出票后立即使用</view>
</view>
<view style="display: flex;margin-top: 24rpx;">
<view style="color: #808080;width: 120rpx;">有效期</view>
<view style="width: 494rpx;margin-left: 48rpx;color: #000;">指定出行日期1天内有效</view>
</view>
<view style="display: flex;margin-top: 24rpx;">
<view style="color: #808080;width: 120rpx;">适用人群</view>
<view style="width: 494rpx;margin-left: 48rpx;color: #000;">{{skuObj.sku.typeInfo}}</view>
</view>
</view>
<view style="width: 654rpx;padding: 48rpx 0rpx">
<text style="color: #000;font-size: 32rpx;font-weight: bold;">费用说明</text>
<view style="display: flex;margin-top: 24rpx;">
<view style="color: #808080;width: 120rpx;">费用包含</view>
<view style="width: 494rpx;margin-left: 48rpx;color: #000;">{{skuObj.sku.contentWith}}</view>
</view>
<view style="display: flex;margin-top: 24rpx;">
<view style="color: #808080;width: 120rpx;">费用不含</view>
<view style="width: 494rpx;margin-left: 48rpx;color: #000;">{{skuObj.sku.contentWithout}}</view>
</view>
</view>
<view style="width: 654rpx;padding: 48rpx 0rpx">
<text style="color: #000;font-size: 32rpx;font-weight: bold;">使用说明</text>
<view style="display: flex;margin-top: 24rpx;">
<view style="color: #808080;width: 120rpx;">入园方式</view>
<view style="width: 494rpx;margin-left: 48rpx;color: #000;">
{{skuObj.sku.enterChangeFlag?'凭('+getTyepStr(skuObj.sku.enterType)+')换票入园':'无需换票'}}
</view>
</view>
<view style="display: flex;margin-top: 24rpx;" v-if="skuObj.sku.enterChangeFlag">
<view style="color: #808080;width: 120rpx;">换票时间</view>
<view style="width: 494rpx;margin-left: 48rpx;color: #000;">
{{skuObj.sku.changeStart}}~{{skuObj.sku.changeEnd}}
</view>
</view>
<view style="display: flex;margin-top: 24rpx;" v-if="skuObj.sku.enterChangeFlag">
<view style="color: #808080;width: 120rpx;">换票地点</view>
<view style="width: 494rpx;margin-left: 48rpx;color: #000;">{{skuObj.sku.changePostion}}</view>
</view>
<view style="display: flex;margin-top: 24rpx;">
<view style="color: #808080;width: 120rpx;">入园时间</view>
<view style="width: 494rpx;margin-left: 48rpx;color: #000;">
{{skuObj.sku.enterStart}}~{{skuObj.sku.enterEnd}}
</view>
</view>
<view style="display: flex;margin-top: 24rpx;">
<view style="color: #808080;width: 120rpx;">入园地址</view>
<view style="width: 494rpx;margin-left: 48rpx;color: #000;">{{skuObj.sku.enterPostion}}</view>
</view>
</view>
<view style="width: 654rpx;padding: 48rpx 0rpx">
<text style="color: #000;font-size: 32rpx;font-weight: bold;">取消政策</text>
<u-parse style="margin-top: 24rpx;" :html="skuObj.sku.refundPolicy"></u-parse>
</view>
<view style="width: 654rpx;padding: 48rpx 0rpx">
<text style="color: #000;font-size: 32rpx;font-weight: bold;">其他说明</text>
<view style="display: flex;margin-top: 24rpx;">
<view style="color: #808080;width: 120rpx;">补充说明</view>
<view style="width: 494rpx;margin-left: 48rpx;color: #000;">{{skuObj.sku.remark}}</view>
</view>
<view style="display: flex;margin-top: 24rpx;">
<view style="color: #808080;width: 120rpx;">发票说明</view>
<view style="width: 494rpx;margin-left: 48rpx;color: #000;">{{skuObj.sku.receiptPolicy}}</view>
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
var that = ''
import {
getSkuType
} from '../../unit/utils.js'
export default {
data() {
return {
show: false,
list: [],
obj: '',
skuObj: '',
typeStr: '',
getSkuType: '',
enterTypeList: [{
value: "二维码",
label: 1
},
{
value: "实体票",
label: 2
},
{
value: "第三方凭证码",
label: 3
},
{
value: "身份证",
label: 4
},
{
value: "护照",
label: 5
},
{
value: "港澳居民来往内地通行证",
label: 6
},
{
value: "台湾居民来往大陆通行证",
label: 7
}
]
};
},
onLoad(e) {
that = this
this.getSkuType = getSkuType
this.getTicketsDetailMethod(e.id)
},
methods: {
playPhone() {
uni.makePhoneCall({
phoneNumber: that.obj.shop.mobile
})
},
// xuchao: 到景区去 —— 微信/浏览器环境用 uni.openLocation 打开地图,失败兜底跳高德网页
handleOpen() {
const lat = parseFloat(this.obj.shop.lat)
const lng = parseFloat(this.obj.shop.lng)
if (!lat || !lng) {
uni.showToast({
icon: 'none',
title: '暂无该景区位置信息'
})
return
}
uni.openLocation({
latitude: lat,
longitude: lng,
name: this.obj.shop.name,
address: this.obj.shop.address || '',
fail: () => {
// 备用方案:跳转高德地图网页
window.location.href =
`https://uri.amap.com/marker?position=${lng},${lat}&name=${this.obj.shop.name}`
}
})
},
getTyepStr(e) {
let typeStr = ''
e.split(',').forEach((item) => {
this.enterTypeList.forEach((item1) => {
if (item == item1.label) {
typeStr = typeStr + item1.value + '、'
}
})
})
return typeStr.slice(0, -1)
},
seeSkuDetail(e) {
this.$u.api.getSkuDetail({
id: e
}).then(res => {
if (res) {
this.skuObj = res.data
this.show = true
}
})
},
getTicketsDetailMethod(e) {
this.list = []
this.$u.api.getTicketsDetail({
id: e
}).then(res => {
if (res) {
if (res.data.tickets.propagatePic) {
res.data.tickets.propagatePic.split(',').forEach((item, index) => {
this.list.push({
image: item
})
})
}
this.obj = res.data
}
})
},
toOrderSure(e) {
this.$u.api.getSkuDetail({
id: e
}).then(res => {
if (res) {
this.skuObj = res.data
// this.$store.commit('setScenicDetail', res.data)
uni.setStorageSync('scenicDetail',res.data)
uni.navigateTo({
url: 'ordersure'
})
}
})
}
},
};
</script>
<style>
page {
background: #F8F9FC;
}
</style>
<style lang="less" scoped>
.wrap {
width: 750rpx;
height: 420rpx;
}
.ticket {
width: 750rpx;
background: #fff;
padding: 24rpx;
margin-top: 24rpx;
.ticket_item {
margin-top: 24rpx;
background: #F8F9FC;
border-radius: 8rpx;
padding: 24rpx;
display: flex;
}
.btn {
width: 152rpx;
height: 56rpx;
border-radius: 200rpx;
background: linear-gradient(180deg, #FF9E49 0%, #ED3B1A 100%);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
margin-top: 20rpx;
}
}
.title {
width: 750rpx;
background-color: #fff;
margin-top: 50rpx;
padding: 24rpx;
z-index: 10000;
.t_info {
color: #FF383C;
line-height: 48rpx;
margin-top: 12rpx;
font-weight: bold;
}
.t_opentime {
background-color: #F8F9FD;
padding: 8rpx;
display: flex;
flex-direction: column;
gap: 12rpx;
margin-top: 24rpx;
}
.t_address {
width: 702rpx;
height: 100rpx;
margin-top: 24rpx;
background: url('https://aliyunoss.hn12301.net/xgh/t_address_bj.png');
background-size: 100% 100%;
color: #000;
display: flex;
align-items: center;
padding-left: 24rpx;
image {
width: 40rpx;
height: 70rpx;
}
}
.t_name {
width: 702rpx;
color: #000;
font-size: 36rpx;
font-weight: 700;
line-height: 48rpx;
}
.tag {
color: #7C7C7E;
font-size: 20rpx;
padding: 5rpx 10rpx;
background: #F8F9FC;
border-radius: 4rpx;
display: block;
margin-right: 12rpx;
}
}
</style>
+119
View File
@@ -0,0 +1,119 @@
<template>
<view>
<text class="text">需添加 &nbsp;{{value}}&nbsp;个出行人</text>
<view class="h_item" @click="toAddPerson">
<text class="text1">新增出行人</text>
<text class="text2">+</text>
</view>
<view class="item" v-for="(item,index) in list" :key="index">
<image src="https://aliyunoss.hn12301.net/sd/ticket_edit.png" style="width: 48rpx;height: 48rpx;" @click="toPerson(item)"></image>
<text style="margin-left: 24rpx;">{{item.name}}</text>
<text style="margin-left: 24rpx;">{{item.identityNo}}</text>
<view style="position: absolute;right: 0rpx;">
<u-checkbox v-model="item.isSelect" active-color="#457AF7"></u-checkbox>
</view>
</view>
<view style="width: 702rpx;left: 24rpx;position: fixed;bottom: 24rpx;">
<u-button shape="circle" size="default" style="background: linear-gradient(180deg, #FF9E49 0%, #ED3B1A 100%);color: #fff;" @click="select">完成</u-button>
</view>
</view>
</template>
<script>
var that=''
export default {
data() {
return {
checked:true,
list:[],
value:0
};
},
onLoad(e){
that=this
this.value=e.value
},
onShow(){
this.getMemberTouristMethod()
},
methods: {
// 选中某个复选框时,由checkbox时触发
checkboxChange(e) {
console.log(e);
},
toAddPerson(){
uni.navigateTo({
url: 'person'
})
},
toPerson(e){
uni.navigateTo({
url: 'person?info='+JSON.stringify(e)
})
},
getMemberTouristMethod(){
this.$u.api.getMemberTourist({mobile:uni.getStorageSync('phone')}).then(res => {
if (res) {
res.data.forEach(item=>{
this.$set(item,'isSelect',false)
})
this.list=res.data
}
})
},
select(){
let arr =[]
this.list.forEach(item=>{
if(item.isSelect){
arr.push(item)
}
})
let pages = getCurrentPages(); //获取所有页面栈实例列表
let nowPage = pages[pages.length - 1]; //当前页页面实例
let prevPage = pages[pages.length - 2]; //上一页页面实例
prevPage.objitem = JSON.stringify(arr); //修改上一页面的 couponNumber 参数值为 value
uni.navigateBack({ //uni.navigateTo跳转的返回,默认1为返回上一级
delta: 1
});
}
}
};
</script>
<style lang="less" scoped>
.text{
color: rgba(0, 0, 0, 0.8);
margin: 24rpx 0rpx 0rpx 24rpx;
font-size: 36rpx;
height: 88rpx;
font-weight: bold;
}
.h_item{
width: 702rpx;
margin-top: 24rpx;
display: flex;
margin-left: 24rpx;
justify-content: space-between;
border-bottom: 1px dashed #E1E1E1;
align-items: center;
padding-bottom: 24rpx;
.text1{
color:rgba(0, 0, 0, 0.8);
}
.text2{
color:#457AF7;
font-size: 40rpx;
font-weight: bold;
}
}
.item{
width: 702rpx;
margin-left: 24rpx;
height: 112rpx;
display: flex;
align-items: center;
position: relative;
}
</style>