| <template> | |
|   <view> | |
|     <uv-popup ref="popup" mode="bottom" bgColor="none" @change="onPopupChange"> | |
|       <view class="popup__view"> | |
|         <view class="flex header"> | |
|           选择日期/套餐/人数 | |
|         </view> | |
|         <uv-form  | |
|           ref="form" | |
|           :model="form" | |
|           :rules="rules" | |
|           errorType="toast" | |
|         > | |
|           <view class="section"> | |
|             <uv-form-item prop="time" :customStyle="formItemStyle"> | |
|               <view class="flex section-header"> | |
|                 <view>选择团期</view> | |
|                 <button class="flex btn" @click="openTimePicker"> | |
|                   <view class="highlight">日历选择</view> | |
|                   <image class="img" src="@/static/image/icon-arrow-right.png" mode="widthFix"></image> | |
|                 </button> | |
|               </view> | |
|               <timeCalendarSelect ref="timeCalendarSelect" v-model="form.time" :options="data.dateList"></timeCalendarSelect> | |
|               <view class="flex section-content"> | |
|                 <timeOptionsSelect style="width: calc(100vw - 40rpx*2);"  | |
|                   v-model="form.time"  | |
|                   :options="data.dateList" | |
|                 ></timeOptionsSelect> | |
|               </view> | |
|             </uv-form-item> | |
|           </view> | |
|           <view class="section"> | |
|             <uv-form-item prop="prices" :customStyle="formItemStyle"> | |
|               <view class="flex section-header"> | |
|                 <view>选择人数</view> | |
|               </view> | |
|               <view class="flex section-content"> | |
|                 <peopleNumberInput style="width: calc(100vw - 40rpx*2);" | |
|                   v-model="form.prices" | |
|                   :options="priceList" | |
|                 ></peopleNumberInput> | |
|               </view> | |
|             </uv-form-item> | |
|           </view> | |
|           <view class="section"> | |
|             <uv-form-item prop="members" :customStyle="formItemStyle"> | |
|               <view class="flex section-header"> | |
|                 <view>选择人员</view> | |
|                 <button class="flex btn" @click="jumpToSelectMember"> | |
|                   <view>请选择出行人</view> | |
|                   <image class="img" src="@/static/image/icon-arrow-right.png" mode="widthFix"></image> | |
|                 </button> | |
|               </view> | |
|               <view class="flex section-content member"> | |
|                 <view class="member-item" v-for="item in form.members" :key="item.id"> | |
|                   {{ item.name }} | |
|                 </view> | |
|               </view> | |
|             </uv-form-item> | |
|           </view> | |
|         </uv-form> | |
|         <view class="footer"> | |
|           <button class="flex btn" @click="onConfirm">填写订单</button> | |
|         </view> | |
|       </view> | |
| 		</uv-popup> | |
|   </view> | |
| </template> | |
| 
 | |
| <script> | |
|   import { mapState } from 'vuex' | |
| 
 | |
|   import timeOptionsSelect from '@/pages_order/order/orderConfirm/timeOptionsSelect.vue' | |
|   import timeCalendarSelect from '@/pages_order/order/orderConfirm/timeCalendarSelect.vue' | |
|   import peopleNumberInput from '@/pages_order/order/orderConfirm/peopleNumberInput.vue' | |
| 
 | |
|   const TYPE_INDEX_MAPPING = { | |
|     '成人': 0, | |
|     '青少年': 1, | |
|     '儿童': 2, | |
|   } | |
| 
 | |
|   export default { | |
|     components: { | |
|       timeOptionsSelect, | |
|       timeCalendarSelect, | |
|       peopleNumberInput, | |
|     }, | |
|     props: { | |
|       data: { | |
|         type: Object, | |
|         default() { | |
|           return {} | |
|         } | |
|       }, | |
|     }, | |
|     data() { | |
|       return { | |
|         options: [], | |
|         form: { | |
|           time: null, | |
|           prices: [], | |
|           members: [], | |
|         }, | |
|         rules: { | |
|           'time': { | |
|             type: 'string', | |
|             required: true, | |
|             message: '请选择团期', | |
|           }, | |
|           'prices': { | |
|             type: 'array', | |
|             message: '请选择人数', | |
|             validator: (rule, value, callback) => { | |
| 
 | |
|               if (value.some(num => num > 0)) { | |
|                 return true | |
|               } | |
| 
 | |
|               return false | |
|             }, | |
|           }, | |
|           'members': { | |
|             type: 'array', | |
|             required: true, | |
|             message: '请选择出行人', | |
|           }, | |
|         }, | |
|         formItemStyle: { padding: 0 }, | |
|       } | |
|     }, | |
|     computed : { | |
|       ...mapState(['configList', 'userInfo', 'travelerList']), | |
|       priceList() { | |
|         const { time: id } = this.form | |
|         const { dateList } = this.data | |
| 
 | |
|         let priceList = dateList?.[0]?.priceList || [] | |
| 
 | |
|         if (id) { | |
|           priceList = dateList?.find?.(option => option.id === id)?.priceList || [] | |
|         } | |
| 
 | |
|         priceList.sort((a, b) => { | |
|           return TYPE_INDEX_MAPPING[a.period_dictText] - TYPE_INDEX_MAPPING[b.period_dictText] | |
|         }) | |
| 
 | |
|         return priceList | |
|       }, | |
|     }, | |
|     watch: { | |
|       travelerList(val) { | |
|         if (val?.length) { | |
|           this.form.members = val | |
|           this.$store.commit('setTravelerList', []) | |
|         } | |
|       }, | |
|     }, | |
| 		onReady() { | |
| 			this.$refs.form.setRules(this.rules); | |
| 		}, | |
|     methods: { | |
|       openTimePicker() { | |
|         this.$refs.timeCalendarSelect.open() | |
|       }, | |
|       async getDefaultMembers() { | |
|         try { | |
|           return (await this.$fetch('queryTouristList', { pageNo: 1, pageSize: 1000, isDefault: '1' })).records | |
|         } catch (err) { | |
|           return [] | |
|         } | |
|       }, | |
|       jumpToSelectMember() { | |
|         const { members } = this.form | |
|         const selectIds = members.map(item => item.id).join(',') | |
|         console.log('jumpToSelectMember', selectIds) | |
| 
 | |
|         this.$utils.navigateTo(`/pages_order/traveler/travelerList?selectIds=${selectIds}`) | |
|       }, | |
|       async open(data) { | |
| 
 | |
|         const { selectTime } = data || {} | |
| 
 | |
|         const defaultMembers = await this.getDefaultMembers() | |
| 
 | |
|         this.form.time = selectTime || null | |
|         this.form.members = defaultMembers | |
| 
 | |
|         this.$refs.popup.open() | |
|       }, | |
|       close() { | |
|         this.$refs.popup.close() | |
|       }, | |
|       async onConfirm() { | |
|          | |
|         try { | |
|           await this.$refs.form.validate() | |
| 
 | |
|           const { | |
|             time, | |
|             prices, | |
|             members, | |
|           } = this.form | |
| 
 | |
|           const orderInfo = { | |
|             product: this.data, | |
|             priceList: this.priceList, | |
|             time, | |
|             prices, | |
|             members, | |
|           } | |
|           this.$store.commit('setOrderInfo', orderInfo) | |
| 
 | |
|           uni.navigateTo({ | |
|             url: '/pages_order/order/orderConfirm/index' | |
|           }) | |
|         } catch (err) { | |
| 
 | |
|         } | |
|       }, | |
|       onPopupChange(e) { | |
|         if (e.show) { | |
|           return | |
|         } | |
|         this.$emit('timeChange', this.form.time) | |
|       }, | |
|     }, | |
|   } | |
| </script> | |
| 
 | |
| <style lang="scss" scoped> | |
| 
 | |
|   .popup__view { | |
|     width: 100vw; | |
|     display: flex; | |
|     flex-direction: column; | |
|     box-sizing: border-box; | |
|     font-family: PingFang SC; | |
|     font-weight: 400; | |
|     line-height: 1.4; | |
|     background: #FFFFFF; | |
|     border-top-left-radius: 32rpx; | |
|     border-top-right-radius: 32rpx; | |
|   } | |
| 
 | |
|   .header { | |
|     position: relative; | |
|     width: 100%; | |
|     padding: 24rpx 0; | |
|     box-sizing: border-box; | |
|     font-family: PingFang SC; | |
|     font-weight: 500; | |
|     font-size: 34rpx; | |
|     line-height: 1.4; | |
|     color: #181818; | |
|     border-bottom: 2rpx solid #EEEEEE; | |
|   } | |
| 
 | |
|   .section { | |
|     padding: 24rpx 40rpx; | |
|     font-family: PingFang SC; | |
|     font-weight: 400; | |
| 
 | |
|     &-header { | |
|       justify-content: space-between; | |
|       font-size: 32rpx; | |
|       font-weight: 500; | |
|       color: #181818; | |
|        | |
|       .btn { | |
|         column-gap: 4rpx; | |
|         font-size: 32rpx; | |
|         font-weight: 400; | |
|         color: #8B8B8B; | |
| 
 | |
|         .highlight { | |
|           color: #181818; | |
|         } | |
| 
 | |
|         .img { | |
|           width: 32rpx; | |
|           height: auto; | |
|         } | |
|       } | |
|     } | |
| 
 | |
|     &-content { | |
|       margin-top: 20rpx; | |
|     } | |
|   } | |
| 
 | |
|   .member { | |
|     display: grid; | |
|     grid-template-columns: repeat(3, 1fr); | |
|     gap: 12rpx; | |
| 
 | |
|     &-item { | |
|       padding: 16rpx; | |
|       text-align: center; | |
|       font-size: 28rpx; | |
|       color: #181818; | |
|       background: #F9F9F9; | |
|       border-radius: 16rpx; | |
|     } | |
|   } | |
| 
 | |
|   .footer { | |
|     width: 100%; | |
|     // height: 214rpx; | |
|     padding: 32rpx 40rpx; | |
|     box-sizing: border-box; | |
| 
 | |
|     .btn { | |
|       width: 100%; | |
|       padding: 14rpx 0; | |
|       font-family: PingFang SC; | |
|       font-weight: 500; | |
|       font-size: 36rpx; | |
|       line-height: 1.4; | |
|       color: #FFFFFF; | |
|       background-image: linear-gradient(to right, #21FEEC, #019AF9); | |
|       border: 2rpx solid #00A9FF; | |
|       border-radius: 41rpx; | |
|     } | |
|   } | |
| </style> |