<template> <view class="orderBox"> <view class="head"> </view> <view class="middle"> <view class="list" v-for="(item,index) in productList" :key='item.id'> <view class="list-top"> <!-- --------------------------------------------产品信息部分------------------------------------- --> <view class="list-Product"> <view class="merchantName"> <text class="title-text"> {{ item.merchantName || '' }} </text> <text> {{ item.name || '' }} </text> </view> <view @click="showBuyKnow(index)" class="buyKnow"> <view> <!-- 索道写死 --> <!-- <text v-if="item.merchantId=='z0015605022691a5945bbe463141668c'"> 有条件退 </text> <template v-else> <text v-if="item.backChangeRule == 0">不可退</text> <text v-if="item.backChangeRule == 1">有条件退</text> <text v-if="item.backChangeRule == 2">随时可退</text> </template> --> <text v-if="item.backChangeRule == 0">不可退</text> <text v-if="item.backChangeRule == 1">有条件退</text> <text v-if="item.backChangeRule == 2">随时可退</text> <text v-if="item.isFetch == 1" style="margin-left: 10rpx;">无需取号</text> </view> <view> 购买须知 <u-icon name="arrow-right" color='#FC6703'></u-icon> </view> </view> </view> <!--需要排队并且站点数大于1--> <view class="list-place" @click="openArea(index)" v-if="item.isFetch ==1&& item.productAreaList.length >1&&item.areaUp"> <view> 出发站点 </view> <view> {{ item.areaObj.areaName || '请选择站点' }} </view> <view> <u-icon name="arrow-right" color="#3688FF"></u-icon> </view> </view> <!--需要排队并且为一个站点--> <!-- <view class="list-place" v-if="item.isFetch == 1 && item.productAreaList.length == 1 &&item.areaUp" @click="getSortInfo()"> <view> 获取排队信息 </view> <view> {{ areaObj.areaName }} </view> <view> <u-icon name="arrow-right" color="#3688FF"></u-icon> </view> </view> --> <view class="list-Date"> <view class="title-text">游玩日期</view> <view class="list-Datelist"> <scroll-view class="date-content" scroll-x="true" :scroll-left="item.dateScroll" v-if="item.priceStockList&&item.priceStockList.length > 0"> <view class="date-list" v-for="(item2,index2) of item.priceStockList" :class="{ on:item.dateActive == index2 }" @click="dateChoose(item,item2,index2)" :key="index2"> <view v-if="item2.week"> <text v-if="item2.week != '今天' && item2.week != '明天' && item2.week != '后天'">周</text> {{ item2.week }} </view> <view> {{ item2.startTime ? item2.startTime.substr(5, 5) : '' }} </view> <view class="date-price"> ¥<text style="font-weight: bold;">{{ item2.sellingPrice }}</text> </view> <view v-if="item.dateActive == index2" class="date-icon"> <u-icon name="checkmark" color="#ffffff"></u-icon> </view> </view> </scroll-view> <text v-else class="no-date"> 不可购买 </text> <view class="dateMore" @click="showCalendar(index)"> <view class="date-more-content"> <view>更多</view> <view>日期</view> </view> <u-icon name="arrow-right"></u-icon> </view> </view> </view> <view class="list-time" v-if="item.productType == 3"> <view class="title-text"> 场次 </view> <view class="list-timelist"> <scroll-view class="time-content" scroll-x="true" :scroll-left="item.timeScroll" v-if="item.timeList&&item.timeList.length> 0"> <view class="time-list" :style="{color:item2.copyLast=='售罄'?'#ff0000':''}" v-for="(item2,index2) of item.timeList" @click="chooseTime(item,item2,index2)" :class="{ on:item.timeActive == index2 }" :key="index2" > <view> {{ item2.startPlanTime ? item2.startPlanTime.substr(0, 5) : '' }} <text v-if="!item2.saleOnlyShowFromDate"> -{{ item2.endPlanTime ? item2.endPlanTime.substr(0, 5) : '' }} </text> </view> <view> <text v-if="item2.copyLast!='余票充足'&&item2.copyLast!='售罄'">剩余:</text> {{ item2.copyLast }} </view> <view v-if="item.timeActive == index2" class="date-icon"> <u-icon name="checkmark" color="#ffffff"></u-icon> </view> </view> </scroll-view> <text class="no-time" v-if="item.startDate && item.endDate && item.timeList.length == 0"> 该日票种已售罄,请选择其他日期 </text> <text class="no-time" v-if="!item.startDate || !item.endDate"> 请先选游玩日期 </text> <view class="timeMore" @click="showTime(item,index)"> <view class="time-more-content"> <view>更多</view> <view>场次</view> </view> <u-icon name="arrow-right"></u-icon> </view> </view> </view> <view class="list-divider"> </view> <view class="list-Number"> <view class="title-text"> 购买数量 </view> <view> <u-number-box :max="item.realMaxNum" v-model="item.buyNum" @change='buyNumChange' :name='index'> <view slot="minus" class="number-minus" > <u-icon name="minus" color="#FFFFFF" size="32"></u-icon> </view> <text slot="input" class="number-input">{{item.buyNum}}</text> <view slot="plus" class="number-plus"> <u-icon name="plus" color="#FFFFFF" size="32"></u-icon> </view> </u-number-box> </view> </view> <!-- 有可用优惠券,并且未选中 --> <view class=" list-coupon" v-if="item.couponData&&item.couponData.masterSlaveCouponList&&item.couponData.masterSlaveCouponList.length>0&&!item.chooseCouponObj" @click="showCoupon(index)"> <view> 券 </view> <view> {{item.couponData.masterSlaveCouponList[0].couponName}} </view> <view > 未使用优惠券 </view> <u-icon name="arrow-right" color="#3688FF"></u-icon> </view> <!-- 有可用优惠券 --> <view class=" list-coupon" v-if="item.chooseCouponObj&&item.chooseCouponObj.savedMoney>0" @click="showCoupon(index)"> <view> 券 </view> <view> {{item.chooseCouponObj.couponName}} </view> <view style="font-size: 32rpx;"> <text style="font-size: 24rpx;position: relative;top: 6rpx;">¥</text> {{parseFloat(item.chooseCouponObj.savedMoney.toFixed(2))}} </view> <u-icon name="arrow-right" color="#3688FF"></u-icon> </view> <!-- 可用优惠券条件--> <view class=" list-coupon" v-if="item.ableConpon" @click="showCoupon(index)"> <view> 券 </view> <view> {{item.ableConpon.couponName}} </view> <view> {{item.ableConpon.couponRule}} </view> <u-icon name="arrow-right" color="#3688FF"></u-icon> </view> </view> <view class="list-divider"> </view> <!-- ---------------------------------------------游客信息-------------------------------------------- --> <view class="list-bottom" v-if="item.tripTemplateFlag != 2"> <view class="list-visitor"> <view class="visitorTitle"> <text class="title-text"> 用户信息 </text> <text> 需填<text class="title-bold">{{item.contactNum }}</text>位出行人 <!-- <text class="title-bold" v-if="contactNum - chooseContact.length > 0">,还需{{ contactNum - chooseContact.length }}位</text> --> </text> </view> <view class="visitorPlus" v-if="item.contactTotal&&item.contactTotal.length>0"> <!-- 这里key必须是index,如果是id会出现数据改变和样式不改变的bug --> <view class="plus-list" :class="{on:item2.ifChoose}" v-for="(item2, index2) of item.contactTotal.slice(0,3)" @click="visitorChoose(index,index2)" :key="index2" > <text class="one-txt-cut">{{item2.name}}</text> <!-- contactVos为该联系人满足该产品的证件信息列表 --> <text v-if="!item2.contactVos||item2.contactVos.length==0" style="font-size: 20rpx;color: #ff0000;">请补充证件</text> <view v-if="item2.ifChoose" class="date-icon"> <u-icon name="checkmark" color="#ffffff"></u-icon> </view> </view> <view @click="showContacts(index)" class="plus-list plus-list-last"> 选择/新增 <u-icon name="arrow-right" color="#3688FF"></u-icon> </view> </view> <view class="visitorBtn" v-else @click="showEdit('',index)"> <u-icon name="plus-circle" color="#3688FF" size="52"></u-icon> <text style="margin-left:16rpx;">新增</text> </view> <view class="visitorEdit" v-show="item.chooseContact&&item.chooseContact.length>0"> <view class="edit-list" v-for="(item2, index2) of item.chooseContact" :key="item2.id"> <view @click="delChooseContact(item,item2,index2)"> <u-icon name="close-circle" color="#3688ff" size="40"></u-icon> </view> <view> {{ item2.name }} </view> <view> {{ item2.credentialNumber ? item2.credentialNumber.substr(0, 3) + '****' + item2.credentialNumber.substr(item2.credentialNumber.length-4, 4) : ''}} </view> <view @click="showEdit(item2,index)"> <u-icon name="edit-pen-fill" color="#3688ff" size="48"></u-icon> </view> </view> </view> </view> </view> <!-- ---------------------------------------------产品押金部分---------------------------------------- --> <view class="productDeposit" v-if="item.deposit"> <view> {{ item.name }} <text style="color: #FC6703;margin-left: 10rpx;">押金</text> </view> <view style="color: #FC6703"> {{ item.deposit }}元 </view> </view> </view> <view class="telephone"> <text> 联系电话: </text> <input type="number" maxlength="11" placeholder="请输入联系电话" v-model.trim="ticketPhone" /> </view> </view> <view class="bottom"> <view class="bottom-left"> <text> ¥{{ originalTotal || 0 }} </text> <text> <text>¥</text>{{ sellTotal || 0 }} </text> </view> <view class="bottom-right"> <view @click="showDetail()" class="bottom-detail"> 明细 <u-icon name="arrow-down"></u-icon> </view> <view class="bottom-btn"> <text v-if="orderStatus == 1">已下架</text> <template v-else> <text v-if="parseInt(maxBookNum)<1">暂无库存</text> <text v-if="parseInt(maxBookNum)>0" @click="goPay()" style="background:#3688FF;">去支付</text> </template> </view> </view> </view> <calendar ref="calendar" @dateConfig="dateConfig" :dateList="chooseDateList" v-show="chooseDateList.length > 0"></calendar> <buyKnow ref="buyKnow" :buyKnowData="buyKnowData"></buyKnow> <detail ref="detail" :productList="productList" :sellTotal="sellTotal" ></detail> <chooseArea v-if="showChooseArea" :areaList="productAreaList" @areaSure="areaSure" :sortArr="sortArr" :defaultAreaCode="defaultAreaCode" ></chooseArea> <times ref="times" :chooseTimeList="chooseTimeList" @timeConfig="timeConfig" :timeActive="timeActive"></times> <editContacts ref="editContacts" :editContactData="editContactData" :credential='chooseCredential'></editContacts> <contactList @contactListConfig='contactListConfig' ref="contactList" :contactTotal="productList[moreContactIndex].contactTotal" :contactNum="productList[moreContactIndex].contactNum" :moreContactIndex='moreContactIndex' ></contactList> <orderCoupon :couponData="couponData" ref="orderCoupon" @couponChoose="couponChoose" :chooseCouponObj="chooseCouponObj"></orderCoupon> <!--一个站点时获取排队信息弹窗--> <!-- <u-popup :show="sortInforPop" :round="10" closeable @close="sortInforPop = false"> <view style="padding: 40rpx 60rpx"> <view> 景区名称: <text class="sortPoptext" style="font-size: 28rpx">{{ productIfo.merchantName }}</text> </view> <view style="margin-top: 40rpx"> 排队人数: <text class="sortPoptext">{{ sortIfo.peopleNumber }}</text> </view> <view style="margin-top: 40rpx"> 当前可排队: <text class="sortPoptext">{{ sortIfo.showStart }}-</text> <text class="sortPoptext">{{ sortIfo.showEnd }}</text> </view> <view style="margin-top: 40rpx"> 当前排号至: <text class="sortPoptext">{{ sortIfo.sortTotalCapacity }}</text> </view> <view style="margin-top: 40rpx; text-align: center" @click="sortInforPop = false"> <text class="list-btn">确定</text> </view> </view> </u-popup> --> </view> </template> <script> import calendar from '../scenicComponents/calendar' //日历组件 import buyKnow from '@/components/buyKnow.vue' //购票须知 import orderCoupon from '@/components/orderCoupon' //优惠券 import detail from '../scenicComponents/combiDetail.vue' //明细弹窗 import chooseArea from '../scenicComponents/chooseArea' //选择站点 import contactList from '../scenicComponents/contactList' //联系人弹窗 import editContacts from '../scenicComponents/editContacts' //编辑联系人弹窗 import times from '../scenicComponents/times' //更多时间弹窗 export default { components: { calendar, buyKnow, detail, contactList, editContacts, times, chooseArea, orderCoupon }, data() { return { groupId:'',//组合Id groupChannelId:'',//组合渠道Id orderSource: '', //订单来源 1公众号平台、2公众号组合页面1、3公众号组合页面2、4胖丁伙伴app、5第三方自助机、6第三方票房窗口 thirdOpenid: '', //第三方openid companyId: '', //公司Id productList:[],//初始化产品数据 productIdList:[],//产品id列表入参 timeActive: 10000, //时间下标,默认不选中 buyKnowData: '', //购买须知数据 editContactData: '', //编辑联系人传值对象 ticketPhone: '', //联系电话 timeNumber: '', //当前时间转化为数字 timeFlag: '', //setTimeout函数 productDepositTotal: 0, //产品总押金 docQuery: '', //元素变量 timeScroll: '' ,//时间滚动值 openid:uni.getStorageSync('openid') || '',//openid orderStatus:'',//上下架状态,任何一个产品状态为下架,该状态为下架 chooseTimeList:[],//选中产品时间列表 chooseDateList:[],//点击更多日期时对应的日期列表 areaIndex:0,//选择站点时对应的产品下标 originalTotal:0,//原价总价 sellTotal:0,//卖价总价 maxBookNum:999,//最大购买数量 productAreaList:[],//长江索道选择站点数据 sortArr: [], //多个站点排号信息列表 sortIfo: '', //单个站点排号信息 sortInforPop: false, //一个站点时获取排队信息弹窗 showChooseArea: false, //控制选择站点弹窗显示隐藏 defaultAreaCode:'',//默认站点 moreDateIndex:0,//点击的更多日期下标 moreTimeIndex:0,//点击的更多时间下标 moreContactIndex:0,//点击的选择、新增联系人下标 couponIndex:'',//点击的券的下标 couponData:[], //选择产品的所有劵数据 chooseCouponObj: '', //选择产品选中的券 chooseCredential:'',//选中的产品的需要的证件类型 timer:null,//时间函数 sortStatus:true,//排号状态 } }, onUnload() { if(this.timer) { clearTimeout(this.timer) this.timer = null } }, onLoad(option) { this.companyId=this.$commonjs.getCompanyId(option)|| '' this.groupId=option.groupId||'' this.groupChannelId=option.groupChannelId||'' this.orderSource=option.orderSource||'' this.thirdOpenid=option.thirdOpenid||'' let idList=JSON.parse(option.productIdList)||[] this.productIdList=idList.map((item)=>{ return {productId:item} }) let times = new Date().Format('yyyy-MM-dd hh:mm:ss') this.timeNumber = parseInt(this.$commonjs.changeTime(times)) //将当前时间转化为数字 this.initData() //页面初始化数据 this.docQuery = uni.createSelectorQuery().in(this) }, methods: { //---页面初始化数据,获取产品基本信息 initData() { let data={ productList:this.productIdList,//产品id列表 } this.$request('scenic/groupGood/loadProductList', data).then(res => { if (res.code == '00'){ this.productList=res.data||[] this.productIdList=this.productList.map((item)=>{//id集合用于请求价格库存列表接口 return item.id }) for(let i=0;i<this.productList.length;i++){ let item=this.productList[i] item.buyNum=1,//默认为1 item.chooseContact=[]//选中的游客信息列表 item.contactNum=1//需要选择几位联系人数量 if(item.status==1){//任何一个产品下架,该组合票为下架状态 this.orderStatus=1 return } if(item.productType!=3){//不为班次票时,开始时间为当前时间,结束时间为23:59:59 item.startPlayTime=new Date().Format('hh:mm:ss') item.endPlayTime='23:59:59' } } this.getPriceList() } else { uni.showToast({ title: res.message, icon: 'none' }) } }) }, //---获取产品价格库存列表 getPriceList() { let data={ productIds:this.productIdList,//产品id集合 } this.$request('scenic/user/product/groupPriceStockList', data).then(res => { if (res.code == '00') { //所有产品的价格库存列表 let stockList=res.data this.productList.forEach((item,index)=>{ //把价格列表合并到对应的产品上面 stockList.forEach(item2=>{ if(item.id==item2.productId){ item.priceStockList=item2.priceStockList||[] } }) }) let today = this.$commonjs.today() //今天 let tomorrow = this.$commonjs.tomorrow() //明天 let afterTomorrow = this.$commonjs.afterTomorrow() //后天 for(let index=0;index<this.productList.length;index++){ let item=this.productList[index] if(item.priceStockList.length>0){ //获取价格列表的第一个日期+预订最晚时间 let time1=item.priceStockList[0].startTime.substr(0,10)+item.bookTime let timeNum1=parseInt(this.$commonjs.changeTime(time1)) let time2=new Date().Format('yyyy-MM-dd hh:mm:ss') let timeNum2 =parseInt(this.$commonjs.changeTime(time2)) //将当前时间转化为数字 if(timeNum2>timeNum1){ //如果当前时间大于价格列表第一个日期+预订最晚时间,第一个价格不显示 item.priceStockList.splice(0,1) } item.priceStockList.forEach((item2, index) => { //价格上面时间小于当前时间加上需预定天数之后的需删除 let date = new Date() date.setDate(date.getDate() + item.beforeBookDays) let newDate = date.Format('yyyy-MM-dd') let priceTime = this.$commonjs.changeTime(item2.endTime.substr(0, 10)) let newTime = this.$commonjs.changeTime(newDate) if (priceTime < newTime) { delete item.priceStockList[index] } }) item.priceStockList = item.priceStockList.filter(val => { return val }) if(item.priceStockList.length==0){ uni.showToast({title: '没有库存',icon: 'none'}) this.maxBookNum=0 return } item.priceStockList.forEach(item2=>{//循环单个产品的价格列表 item2.week='日一二三四五六'.charAt(new Date(item2.startTime.substr(0,10)).getDay()) if(item2.startTime.substr(0,10)==today){ item2.week='今天' } if(item2.startTime.substr(0,10)==tomorrow){ item2.week='明天' } if(item2.startTime.substr(0,10)==afterTomorrow){ item2.week='后天' } }) //需要排号 if(item.isFetch==1){ this.areaIndex=index this.sortUpDown(item) } //默认选择每个产品第一个日期的值 // this.dateChoose(item,item.priceStockList[0],0) }else{ uni.showToast({title: '没有库存',icon: 'none'}) this.maxBookNum=0 return } } this.getContactList() this.computedPrice()//计算价格 //解决初始化日期不显示的情况 this.$forceUpdate() } else { this.maxBookNum=0 uni.showToast({ title: res.message, icon: 'none' }) } }) }, //---排号是否上下架 sortUpDown(item) { let data = { merchantCode:item.merchantVo.code //商户code } this.$request('distribution/distribution/findNewFetchInfoFromSceinc', data,true).then(res => { if (res.code == '00') { //请求成功,默认为上架状态 this.sortStatus=true this.sortArr = res.data.data||[] let data = res.data item.areaObj={} if(item.productAreaList.length>1){ //有库存并且需要选择两个站点以上的票种,显示区域组件 for (let key in data.main) { if (data.main[key].sceneSortStatus == '1'){ //上架 item.areaUp = true this.productAreaList=item.productAreaList if(item.defaultAreaCode){ //有默认的站点 this.defaultAreaCode=item.defaultAreaCode item.productAreaList.forEach(item2=>{ if(item2.areaCode==item.defaultAreaCode){ item.areaObj.areaCode=item2.areaCode item.areaObj.areaName=item2.areaName } }) } //暂时下面只适应长江索道 this.showChooseArea = true } } } if (item.productAreaList.length == 1) { //只有一个站点时,直接选中站点(现目前还没有一个站点的景区) for (let item in data.main) { if (data.main[item].sceneSortStatus == '1') { //上架 item.areaUp = true item.areaObj.areaCode = item.productAreaList[0].areaCode item.areaObj.areaName = item.productAreaList[0].areaName } } } }else{ //请求失败,默认为下架状态 this.sortStatus=false } }).catch(err => { //请求失败,默认为下架状态 this.sortStatus=false this.timer = setTimeout(() => { this.sortUpDown(item) }, 2000) }) }, //---获取班次票 getTimeStock(item) { item.timeList=[] let data = { endDate: item.endDate, //结束日期 startDate: item.startDate, //开始日期 interfaceCode: item.merchantVo.interfaceCompanyId, //接口编号 merchantCode: item.merchantVo.code, //商户code productCode: item.code //产品code } this.$request('distribution/distribution/getTimeStock', data).then(res => { if (res.code == '00') { item.timeList=res.data||[] //增加一个时间Number字段,用于判断当前时间大于班次结束时间时,显示售罄 item.timeList.forEach(item2=>{ let text=parseFloat((item2.last/item2.total).toFixed(2))||0 if(text>0.4){ item2.copyLast='余票充足' }else{ item2.copyLast=item2.last } item2.timeNumber=parseInt(this.$commonjs.changeTime(item2.planDate.substr(0,10)+item2.endPlanTime)) if(this.timeNumber>item2.timeNumber||item2.last<=0){ item2.copyLast='售罄' } }) //解决初始化班次不显示的情况 this.$forceUpdate() } else { uni.showToast({ title: res.message, icon: 'none' }) } }) }, //---计算价格 computedPrice(){ let savedMoney=0 let original=0 let sell=0 let deposit=0 this.productDepositTotal=0 this.productList.forEach((item)=>{ original+=item.originalPrice*item.buyNum sell+=item.sellingPrice*item.buyNum if(item.chooseCouponObj){ if(item.chooseCouponObj.slaveList&&item.chooseCouponObj.slaveList.length>0){ savedMoney+=item.chooseCouponObj.slaveList[0].savedMoney }else{ savedMoney+=item.chooseCouponObj.savedMoney } } if(item.depositType==1){//等于1,押金金额跟数量没关系 deposit=item.deposit }else if(item.depositType==2){//等于2,押金单价乘购买数量 deposit=item.deposit*item.buyNum } this.productDepositTotal+=deposit }) this.originalTotal=parseFloat((original+this.productDepositTotal).toFixed(2))||0 //产品总价+产品押金 this.sellTotal=parseFloat((sell+this.productDepositTotal-savedMoney).toFixed(2))||0 }, //---获取排号信息---暂时未使用 getSortInfo(merchantCode) { let data = { merchantCode //商户code } this.$request('distribution/distribution/findNewFetchInfoFromSceinc', data).then(res => { if (res.code == '00') { this.sortInforPop = true res.data.forEach(item => { item.peopleNumber = Math.max(item.sortTotalCapacity - item.showEnd, 0) }) let index = res.data.findIndex(item => { return item.projectId == this.areaObj.areaCode }) this.sortIfo = res.data[index] } }) }, //---获取子组件的传值 areaSure(data) { this.productList[this.areaIndex].areaObj=data }, //---展示选择站点 openArea(index) { this.areaIndex=index this.showChooseArea = true }, //---关闭选择站点 closeArea() { this.showChooseArea = false }, //---展示详情弹窗 showDetail() { this.$refs.detail.showPop = true }, //---展示日历 showCalendar(index) { this.$refs.calendar.defaultDate=this.productList[index].chooseDate//日历组件选中日期 this.moreDateIndex=index this.chooseDateList=this.productList[index].priceStockList this.$refs.calendar.showPop = true }, //---日期选择 dateChoose(item,item2,index) { item.dateActive=index//修改选中样式 this.maxBookNum=999//默认可以去支付 //由于会多次进行比较,防止出现bug,故重新增加一个字段,获取实际最大购买数量 item.realMaxNum=Math.min(item.maxBookNum,item2.surplus) for(let i=0;i<this.productList.length;i++){ let item=this.productList[i] //任何一个产品无库存时,无法进行支付 if(parseFloat(item.realMaxNum)<1){ this.maxBookNum=0 return } } item.originalPrice=item2.originalPrice//产品原价为当前选中日期的原价 item.sellingPrice=item2.sellingPrice//产品卖价为当前选中日期的卖价 item.chooseDate=item2.startTime.substr(0,10) this.$refs.calendar.defaultDate=item.chooseDate//日历组件选中日期 item.endDate=item2.endTime//开始日期 item.startDate=item2.startTime//结束日期 this.initCoupon(item) if(item.productType==3){ //productType=3为场次票 item.cruisePlanId='' item.timeActive=10000 this.timeActive=10000 this.getTimeStock(item) } this.computedPrice() //解决点击日期无反应的情况 this.$forceUpdate() }, //---日历确认事件 dateConfig(data) { let index2=this.chooseDateList.findIndex(item=>{ return item.startTime.substr(0,10)==data }) let item=this.productList[this.moreDateIndex] let item2=item.priceStockList[index2] this.dateChoose(item,item2,index2) //选中确认的日期 this.docQuery.select('.date-list').boundingClientRect(data => { item.dateScroll=(data.width+6)*index2 //解决不滚动问题 this.$forceUpdate() }).exec() }, //---展示更多时间 showTime(item,index) { this.chooseTimeList=item.timeList this.moreTimeIndex=index if(item.timeActive>=0){ this.timeActive=item.timeActive//组件的默认下标 }else{ this.timeActive=10000 } this.$refs.times.showPop = true }, //---时间选择 chooseTime(item,item2,index2) { if(item2.copyLast!='售罄'){ item.timeActive=index2 item.cruisePlanId=item2.cruisePlanId//获取班次Id item.realMaxNum=Math.min(item.realMaxNum,item2.last) //如果为场次票,开始时间为班次时间的开始时间,结束时间为班次时间的结束时间,班次时间的结束时间为空时,结束时间为班次时间的开始时间 item.startPlayTime=item2.startPlanTime item.endPlayTime=item2.endPlanTime||item2.startPlanTime //解决时间下标未及时选中的问题 this.$forceUpdate() } }, //---时间确认事件 timeConfig(index2) { let item=this.productList[this.moreTimeIndex] let item2=this.chooseTimeList[index2] this.chooseTime(item,item2,index2) //由于没有数据需要测试 this.docQuery.select('.time-list').boundingClientRect(data => { item.timeScroll=(data.width+6)*index2 //解决不滚动问题 this.$forceUpdate() }).exec() }, //---删除选中的联系人 delChooseContact(item,item2,index2) { //所有联系人中找到删除联系人下标,改成未选中状态 let sub = item.contactTotal.findIndex(item3 => item3.id == item2.id) item.contactTotal[sub].ifChoose = false item.chooseContact.splice(index2, 1) //删除数组 //解决样式和数据未及时更新问题 this.$forceUpdate() }, //---展示编辑联系人 showEdit(data,index) { let obj=data||'' this.$refs.editContacts.showPop = true this.editContactData = obj this.chooseCredential=this.productList[index].credential }, //---展示新增联系人,并获取联系人列表 showContacts(index) { this.moreContactIndex=index this.$refs.contactList.showPop = true }, //---联系人列表弹窗确认选中 contactListConfig(data){ let index=this.moreContactIndex this.productList[index].chooseContact=data this.productList[index].contactTotal.forEach(item=>{ //在总的列表里面回去选中的联系人 item.ifChoose=false this.productList[index].chooseContact.forEach(item2=>{ if(item.id==item2.id){ item.ifChoose=true } }) }) //选中的排在前面 this.productList[index].contactTotal.sort(function (a, b) { return b.ifChoose-a.ifChoose }) //选中样式以及选中数据的更新 this.$forceUpdate() }, //---游客选择 visitorChoose(index,index2) { //底层原理不明,特殊情况,需特殊处理 //直接传入item,item2时 会报错,故选择传入下标 let item=this.productList[index] let item2=this.productList[index].contactTotal[index2] if(!item2.contactVos||item2.contactVos.length==0){ //证件信息不全时,补充证件信息 this.$refs.editContacts.showPop=true this.editContactData = item2 this.chooseCredential=this.productList[index].credential return } item2.ifChoose=!item2.ifChoose if (item2.ifChoose) { if (item.chooseContact.length == item.contactNum) { //需要人数满足时,点击增加联系人时,删除最后一个,增加点击的那个人 item.contactTotal.forEach(item3=>{ if(item3.id==item.chooseContact[item.chooseContact.length - 1].id){ item3.ifChoose=false } }) item.chooseContact.splice(item.chooseContact.length - 1, 1) } item.chooseContact.push(item2) //加入数组 } else { let index = item.chooseContact.findIndex(items => { return items.id == item2.id }) item.chooseContact.splice(index, 1) //删除数组 } //解决选中联系人样式不更新的bug this.$forceUpdate() }, //---初始化联系人列表 getContactList() { let data = { openid:this.openid } this.$request('wechatUser/contact/findContactList', data).then(res => { if (res.code == '00') { let contactTotal = res.data||[] contactTotal.forEach(item => { //用于判断是否被选中 item.ifChoose = false }) this.productList.forEach((item)=>{ item.contactTotal=JSON.parse(JSON.stringify(contactTotal)) if(item.chooseContact&&item.chooseContact.length>0){ //编辑成功重新调该方法时,把之前选中的游客,设为选中状态 item.contactTotal.forEach(item2 => { item.chooseContact.forEach(item3 => { if (item2.id == item3.id) { item2.ifChoose = true //更新选中的联系人的值 item3.credentialNumber=item2.credentialNumber item3.name=item2.name item3.phone=item2.phone } }) }) //删除联系人成功重新调该方法时,之前选中的联系人,数据库可能被删除,删除该联系人 item.chooseContact.forEach((item2, index) => { if (!item.contactTotal.find(item3 => item2.id == item3.id)) { item.chooseContact.splice(index, 1) } }) } //用于联系人证件信息对应该产品是否填写判断 if(item.credential){ //credential对应是该产品联系人可以填写的联系人证件列表 item.credentialList=item.credential.split(',') if(item.credentialList.length>0){ item.contactTotal.forEach(item2=>{ //contactVos为该产品联系人实际填写的联系人证件信息 item2.contactVos.forEach((item3,index)=>{ if(!item.credentialList.find(item4=>item4==item3.credentialType)){ delete item2.contactVos[index] } }) item2.contactVos=item2.contactVos.filter((val=>{ return val })) //由于数据结构变化,重新组装数据 if(item2.contactVos.length>0){ item2.credentialNumber=item2.contactVos[0].credentialNumber item2.credentialType=item2.contactVos[0].credentialType } }) } }else{ //有可能部分产品没有配置credential,但是接口数据进行了变化,还是需要重新组装数据 item.contactTotal.forEach(item2=>{ if(item2.contactVos.length>0){ item2.id=item2.contactVos[0].id item2.credentialNumber=item2.contactVos[0].credentialNumber item2.credentialType=item2.contactVos[0].credentialType } }) } //数据不出现问题 this.$forceUpdate() }) } else { uni.showToast({ title: res.message, icon: 'none' }) } }) }, //---添加并选中联系人--用于添加联系人之后直接从联系人列表选出需要填写的几位联系人 addChoose() { let data = { openid:this.openid } this.$request('wechatUser/contact/findContactList', data).then(res => { if (res.code == '00') { let contactTotal = res.data||[] contactTotal.forEach(item => { //用于判断是否被选中 item.ifChoose = false }) this.productList.forEach((item)=>{ item.contactTotal=JSON.parse(JSON.stringify(contactTotal)) item.chooseContact=[] for(let i=0;i<item.contactTotal.length;i++){ let item2=item.contactTotal[i] //联系人满足证件要求,并且选中联系人数量小于需要的联系人数量时 if(item2.contactVos.length>0&&item.chooseContact.length<item.contactNum){ item2.ifChoose=true item.chooseContact.push(item2) } } //用于联系人证件信息对应该产品是否填写判断 if(item.credential){ //credential对应是该产品联系人可以填写的联系人证件列表 item.credentialList=item.credential.split(',') if(item.credentialList.length>0){ item.contactTotal.forEach(item2=>{ //contactVos为该产品联系人实际填写的联系人证件信息 item2.contactVos.forEach((item3,index)=>{ if(!item.credentialList.find(item4=>item4==item3.credentialType)){ delete item2.contactVos[index] } }) item2.contactVos=item2.contactVos.filter((val=>{ return val })) //由于数据结构变化,重新组装数据 if(item2.contactVos.length>0){ item2.credentialNumber=item2.contactVos[0].credentialNumber item2.credentialType=item2.contactVos[0].credentialType } }) } }else{ //有可能部分产品没有配置credential,但是接口数据进行了变化,还是需要重新组装数据 item.contactTotal.forEach(item2=>{ if(item2.contactVos.length>0){ item2.id=item2.contactVos[0].id item2.credentialNumber=item2.contactVos[0].credentialNumber item2.credentialType=item2.contactVos[0].credentialType } }) } //数据不出现问题 this.$forceUpdate() }) } else { uni.showToast({ title: res.message, icon: 'none' }) } }) }, //---订单数量变化 buyNumChange(e) { let value=e.value let index=e.name let item=this.productList[index] //由于buyNum页面数据未及时更新,在这里进行赋值一遍 item.buyNum=value //超过最大值时进行文字提示 if(value >= item.realMaxNum) { uni.showToast({ title: '最大可预订数量为' + item.realMaxNum, icon: 'none' }) } if(item.tripTemplateFlag == 1) { //实名制 item.contactNum = value if (item.chooseContact.length>item.contactNum) { //当选中联系人数量大于购买数量时 item.chooseContact.splice(item.chooseContact.length - 1, 1) //删除多余的联系人 //联系人列表重新判断是否选中 item.contactTotal.forEach(item2=>{ item2.ifChoose=false }) item.chooseContact.forEach(item2=>{ item.contactTotal.forEach(item3=>{ if(item2.id==item3.id){ item3.ifChoose=true } }) }) } } if (item.tripTemplateFlag == 0) { //非实名制 item.contactNum = 1 } this.computedPrice() clearTimeout(this.timeFlag) this.timeFlag = setTimeout(()=>{ this.initCoupon(item) }, 1500) }, //---展示购票须知 showBuyKnow(index) { this.buyKnowData=this.productList[index] this.$refs.buyKnow.showPop = true }, //---加载优惠券 initCoupon(item) { let savedMoneyList = [] item.chooseCouponObj='' item.ableConpon='' item.couponData=[] let data = { productId: item.id, //产品id tickets: item.buyNum, //数量 singleMoney:item.sellingPrice, //单价 money: parseFloat((item.buyNum * item.sellingPrice).toFixed(2)), //订单总价,不算券,和现金红包 merchantId: item.merchantId, //商户Id openid:this.openid } this.$request('wechatUser/myPage/usableCouponList', data,true).then((res) => { if (res.code == '00') { item.couponData = res.data let masterSlaveCouponList=res.data.masterSlaveCouponList if (masterSlaveCouponList&&masterSlaveCouponList.length>0) { masterSlaveCouponList.forEach((item2) => { //获取最优券 savedMoneyList.push(item2.savedMoney) }) let maxMoney = Math.max.apply(null, savedMoneyList) let arr=masterSlaveCouponList.filter((item2)=>{//找到最大值的数组 return item2.savedMoney==maxMoney }) if(arr.length==1){ item.chooseCouponObj=arr[0] }else{ let index=arr.findIndex((item2)=>{//如果有多个,找到是否有平台券,平台劵优先 return item2.createSource==1 }) if(index>-1){ item.chooseCouponObj=arr[index] }else{ item.chooseCouponObj=arr[0] } } item.savedMoney=item.chooseCouponObj.savedMoney } else { if (res.data.unusableCouponList.length > 0) { res.data.unusableCouponList.forEach((item2, i) => { //没有可用优惠券,有达到条件可以用的优惠券,先显示条件,达到条件时显示可用优惠券 if (item2.isProduct == 1) { item.ableConpon = item2 } }) } } this.computedPrice()//计算价格 } }) }, //---子组件券选择之后触发的事件 couponChoose(data) { if(data){ this.productList[this.couponIndex].chooseCouponObj=data }else{ this.productList[this.couponIndex].chooseCouponObj='' } this.computedPrice() //复制公众号,还未复现是否需要 this.$forceUpdate() }, //---展示券列表 showCoupon(index) { this.couponIndex=index this.couponData=this.productList[index].couponData this.chooseCouponObj=this.productList[index].chooseCouponObj this.$refs.orderCoupon.showPop=true }, //---下单 goPay() { if (this.orderStatus == 1) { //下架状态,点击无效 return } if (!this.sortStatus) { //防止排号上下架接口调用失败时,游客下单之后,未上传站点信息给后端 uni.showToast({ title: '获取排号信息失败,请尝试退出并重新进入小程序', icon: 'none' }) return } for(let i=0;i<this.productList.length;i++){ let item=this.productList[i] //没有库存情况 if(!item.priceStockList||item.priceStockList.length==0){ uni.showToast({ title:item.merchantName+'没有库存', icon: 'none' }) return } //最大购买数量大于1,才可以下单 if(parseFloat(item.realMaxNum)<1){ uni.showToast({ title:item.merchantName+'没有库存', icon: 'none' }) return } if (item.isFetch == 1 && item.areaUp) { //需要选择站点的票种,必须选择站点 if (!item.areaObj.areaCode) { uni.showToast({ title: '请选择站点', icon: 'none' }) return } } if (!item.startDate || !item.endDate) { //游玩日期未选择 uni.showToast({ title:item.merchantName+'请选择游玩日期', icon: 'none' }) return } if(item.productType==3){ //如果为班次票,需要选择班次 if(!item.cruisePlanId){ uni.showToast({ title: '请选择'+item.merchantName+'游玩时间', icon: 'none' }) return } } if(item.tripTemplateFlag!=2&&item.chooseContact.length!=item.contactNum){ uni.showToast({ title: item.merchantName+'需要添加'+item.contactNum+'位出行人', icon: 'none' }) return } } if (!this.$commonjs.phoneReg().test(this.ticketPhone)) { //未填写正确手机号码 uni.showToast({ title: '请填写正确的手机号码', icon: 'none' }) return } this.preOrder() }, //---预下单 preOrder() { this.productList.forEach(item=>{ //获取游客信息参数 item.orderTouristList =item.chooseContact.map((item2) => { return { category: 0, name: item2.name, credentialNumber: item2.credentialNumber, credentialType:item2.credentialType||0,//证件类型 } }) //获取券参数 if(item.chooseCouponObj){ //有从券取值从券,没有从券取值主劵 if(item.chooseCouponObj.slaveList.length>0){ item.couponList=[//券列表 { couponId:item.chooseCouponObj.slaveCouponId,//券id isMerchant:item.chooseCouponObj.slaveCreateSource,//是否是商户的券 myCouponId:item.chooseCouponObj.slaveId,//领取人编号 couponType:item.chooseCouponObj.couponType,//券类型 couponPrice:item.chooseCouponObj.savedMoney,//券价格 } ] }else{ item.couponList=[ { couponId:item.chooseCouponObj.couponId,//券id isMerchant:item.chooseCouponObj.createSource,//是否是商户的券 myCouponId:item.chooseCouponObj.id,//领取人编号 couponType:item.chooseCouponObj.couponType,//券类型 couponPrice:item.chooseCouponObj.savedMoney,//券价格 } ] } }else{ item.couponList=[] } }) //额外服务不为空,联票购买不为空,带有儿童票,组合购买不为空,单品购买为空 let orderProductList=this.productList.map((item)=>{ return { extendContent:'{"openid":'+'"'+this.openid+'"'+','+'"zr":'+'"'+this.thirdOpenid+'"'+'}', buyNum:item.buyNum,//购买数量 cruisePlanId:item.cruisePlanId,//班次Id playDate:item.startDate.substr(0,10),//开始日期 endPlayDate:item.endDate.substr(0,10),//结束日期 startPlayTime:item.startPlayTime,//开始时间 endPlayTime:item.endPlayTime,//结束时间 isMaster:0,//是否主产品 1 否, 0 是 merchantId:item.merchantId,//商户id productId:item.id,//产品Id subOrderType:0,//产品类型,网络 unitPrice:item.sellingPrice,//产品单价 distributionPrice:item.sellingPrice,//临时用 productAreaCode:item.areaObj?item.areaObj.areaCode:'',//出发站点 orderTouristList:item.orderTouristList,//游客信息 couponList:item.couponList//优惠券 } }) let data={ companyId:this.companyId,//公司Id groupChannelId:this.groupChannelId,//组合渠道编号 ,组合订单必传 groupId:this.groupId,//组合编号 ,组合订单必传 buyMethod:3,// 单品购买,2套票、联票购买,3组合购买 userId:this.openid,//用户id ticketPhone:this.ticketPhone,//联系电话 cash:0,//现金红包 orderMoney:this.sellTotal,//订单总价 = 订单原价 - 优惠券价格 - 现金抵扣价格 orderType:1,//订单类型,景区 orderSource:this.orderSource||1, //订单来源 1公众号平台、2公众号组合页面1、3公众号组合页面2、4胖丁伙伴app、5第三方自助机、6第三方票房窗口 orderProductList,//额外服务不为空,联票购买不为空,带有儿童票,组合购买不为空,单品购买为空 } this.$request('orderc/order/createOrder', data).then((res) => { if (res.code == '00') { if (res.data.id) { uni.navigateTo({ url: '/pages/payment/orderPayment/orderPayment?orderId='+res.data.id }) } else { uni.showToast({ title: '下单失败', icon: 'none' }) } } else { uni.showToast({ title: res.message, icon: 'none' }) } }) } } } </script> <style lang="scss" scoped="scoped"> .head { height: 160rpx; background: linear-gradient(to bottom, #2984ef, #d8eaf6); } .orderBox { min-height: 100%; background: #f5f5f5; } .middle{ position: relative; top: -100rpx; background: #ffffff; padding:0 20rpx 30rpx 20rpx; } .list{ padding-top: 30rpx; } .title-text{ font-size: 32rpx; font-weight: bold; } /*中间上面部分*/ .merchantName { display: flex; align-items: center; } .merchantName text:nth-child(2) { color: #666666; margin-left: 20rpx; } .buyKnow { margin-top: 20rpx; background: #fef0e6; height: 56rpx; font-size: 24rpx; display: flex; justify-content: space-between; padding-left: 10rpx; align-items: center; border-radius: 5rpx; color:$red; } .buyKnow view:nth-child(2) { display: flex; } .list-place { height: 100rpx; display: flex; justify-content: space-between; align-items: center; } .list-place view:nth-child(2) { flex: 1; margin-left: 20rpx; color: $theme; font-size: 28rpx; font-weight: bolder; } .list-Date{ margin-top: 40rpx; } .list-Datelist { display: flex; justify-content: space-between; align-items: center; margin-top: 30rpx; } .date-content { flex: 1; overflow-x: scroll; white-space: nowrap; } .date-content::-webkit-scrollbar { display: none; } .date-list { width: 140rpx; text-align: center; margin-right:12rpx; border-radius: 10rpx; position: relative; display: inline-block; background: #f2f2f2; padding-bottom: 8rpx; } .date-list.on { border: 1px solid $theme; background: #DAE6F6; } .date-list>view{ margin-top: 6rpx; } .date-price { font-size: 32rpx; color: $red; } .no-date { color: $red; flex: 1; margin-left: 30rpx; font-weight: bolder; } .date-icon { position: absolute; right: -1px; bottom: -1px; display: inline-block; width: 30rpx; height: 28rpx; background:$theme; border-radius: 10rpx 0; } .dateMore { flex-shrink: 0; padding: 20rpx 0; width: 120rpx; display: flex; justify-content: center; align-items: center; } .date-more-content { margin-right:8rpx; } .list-time{ margin-top: 40rpx; } .list-timelist { display: flex; justify-content: space-between; align-items: center; margin-top: 30rpx; } .time-content { flex: 1; overflow-x: scroll; white-space: nowrap; height: 90rpx; } .time-content::-webkit-scrollbar { display: none; } .time-list { width: 200rpx; height: 90rpx; line-height: 30rpx; text-align: center; margin-right: 8rpx; border-radius: 15rpx; display: inline-block; background:#f2f2f2; position: relative; padding-bottom: 8rpx; } .time-list view { margin-top: 10rpx; } .time-list.on { border: 1px solid $theme; background: #DAE6F6; } .timeMore { flex-shrink: 0; width: 120rpx; display: flex; justify-content: center; align-items: center; } .time-more-content { margin-right:8rpx; } .no-time { color:$red; flex: 1; font-weight: bolder; } .list-divider{ height: 2rpx; background:$divider; margin: 40rpx 0; } .list-Number { display: flex; justify-content: space-between; align-items: center; } .number-minus { width: 52rpx; height: 52rpx; background:#ccc; border-radius: 50%; display: flex; justify-content: center; align-items: center; } .number-input { padding:0 20rpx; width: 100rpx; text-align: center; font-size: 40rpx; } .number-plus{ width: 52rpx; height: 52rpx; background:$theme; border-radius: 50%; display: flex; justify-content: center; align-items: center; } .list-coupon{ display: flex; justify-content: space-between; align-items: center; padding:30rpx 0; } .list-coupon view:first-child{ width: 36rpx; height: 36rpx; background: $theme; color: #FFFFFF; text-align: center; line-height:32rpx; border-radius:4rpx; } .list-coupon view:nth-child(2){ flex: 1; margin-left: 10rpx; } .list-coupon view:nth-child(3){ display: flex; color: $theme; font-weight: bold; } /*中间下面部分*/ .list-visitor { padding-bottom: 40rpx; border-bottom: 1px solid $divider; } .visitorTitle > text:nth-child(2) { font-size: 24rpx; color: #666666; margin-left: 10rpx; } .title-bold { color: #f9690e; font-weight: bolder; font-size: 28rpx; } .visitorBtn{ display: flex; align-items: center; justify-content: center; height: 88rpx; background:#ECF3FE; margin-top: 40rpx; color: $theme; font-size: 32rpx; border-radius:20rpx; } .visitorPlus { margin-top: 20rpx; display: flex; flex-wrap: wrap; } .plus-list { height: 70rpx; display: flex; justify-content: center; align-items: center; flex-wrap: wrap; padding: 5rpx 0; width: 145rpx; text-align: center; background: #f2f2f2; border-radius: 5rpx; position: relative; margin: 20rpx 15rpx 0 0; } .plus-list-last { color: $theme; background: #efefef; width: 170rpx; border: none; } .plus-list.on { border: 1px solid $theme; background: #DAE6F6; } .visitorEdit { margin-top: 40rpx; } .visitorEdit > view:not(first-child) { margin-top: 25rpx; } .edit-list { display: flex; justify-content: space-between; align-items: center; } .edit-list view:nth-child(2) { display: inline-block; width: 120rpx; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; margin-left: 30rpx; } .edit-list view:nth-child(3) { flex: 1; } .telephone { margin-top: 30rpx; display: flex; align-items: center; font-weight: bold; } .telephone input { flex: 1; } /*押金部分*/ .productDeposit { padding: 40rpx 15rpx; background: #ffffff; border-radius: 10rpx; margin-top: 20rpx; display: flex; justify-content: space-between; align-items: center; } /*底部部分*/ .bottom { height: 100rpx; display: flex; justify-content: space-between; align-items: center; background: #ffffff; position: fixed; bottom: 0; width: 100%; max-width: 750rpx; z-index: 10; padding: 0 24rpx 0 40rpx; box-shadow: 0px 4px 12px rgba(0,0,0,0.16) } .bottom-left > text:first-child { font-size: 28rpx; text-decoration: line-through; margin-right: 16rpx; } .bottom-left text:nth-child(2) { font-size: 40rpx; font-weight: bolder; color: #f45803; } .bottom-left text:nth-child(2) text { font-size: 32rpx; } .bottom-right { display: flex; align-items: center; } .bottom-detail { display: flex; } .bottom-btn { position: relative; width: 240rpx; height: 80rpx; margin-left: 20rpx; line-height: 80rpx; font-size: 32rpx; font-weight: bolder; text-align: center; } .bottom-btn text { position: absolute; width: 100%; height: 100%; display: inline-block; left: 0; color: #ffffff; top: 0; background:#C0C0C0; border-radius: 24rpx; } .sortPoptext { font-size: 30rpx; font-weight: bolder; color: #f32048; } </style>