539 lines
20 KiB
Vue
539 lines
20 KiB
Vue
<template>
|
||
<view>
|
||
<u-navbar :autoBack="true" :bgColor="'white'" :leftIconColor="'#303133'">
|
||
<view slot='center' class="navbar_title">座位预定</view>
|
||
</u-navbar>
|
||
<view class="wrap" :style="{marginTop: paddingTop + 'px'}">
|
||
<view class="scroll-box">
|
||
<scroll-view scroll-x="true">
|
||
<view class="scroll-x">
|
||
<view class="tab">
|
||
<view class="box-show" style="border-color: #03AE80; background: #03AE80;">
|
||
<!-- <image src="../../static/image/seat/bought.png" mode="aspectFit"></image> -->
|
||
</view>
|
||
已售出
|
||
</view>
|
||
<view class="tab" v-for="(item, index) in detail.zoneList" :key="item.zoneId">
|
||
<view class="box-show" :class="['border-color-' + index % 9]"></view>
|
||
{{item.zoneName}} {{ item.price ? '¥' + item.price.price : '' }}
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
<view class="sm-title">{{pageData.hallName}}</view>
|
||
<view class="site-box" v-if="detail">
|
||
<scroll-view scroll-x="true">
|
||
<view class="row">
|
||
<view class="column" v-for="(i, index) in seatStateHeader" :key="index">
|
||
<view class="sm-icon unselect xuhao">{{i}}</view>
|
||
</view>
|
||
</view>
|
||
<view class="row" v-for="(value, key) in detail.venueSeats" :key="key">
|
||
<view class="column" v-for="(i, index) in value" :key="index" @click="selectItem(key, i[2], index)">
|
||
<!-- 未配置价格 -->
|
||
<view class="sm-icon disable" v-if="detail.saleList.length == 0"></view>
|
||
<template v-else>
|
||
<!-- 未选中 -->
|
||
<view class="sm-icon unselect" v-if="i[3] === 0 && i[1] === 1 && isSale(key, i[2], 1) && isLock(key, i[2])" :class="[borderColorFun(i), isPartition(key, index) ? 'gray' : '']"></view>
|
||
<!-- 选中 -->
|
||
<view class="sm-icon selected" v-if="isSale(key, i[2], 3)"></view>
|
||
<!-- 已售出 -->
|
||
<image v-if="i[3] === 1 && i[1] === 1" class="sm-icon" src="../../static/image/seat/bought.png" mode="aspectFit"></image>
|
||
<!-- 无座或者占座 -->
|
||
<view class="sm-icon disable" v-if="i[1] === 0 || isSale(key, i[2], 2) || !isLock(key, i[2])"></view>
|
||
</template>
|
||
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
<view class="sm-line-index">
|
||
<view class="text" v-for="(value, key) in detail.venueSeats" :key="key">
|
||
{{key}}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="info-box">
|
||
<view class="info">
|
||
<view class="info-title">{{pageData.ticketName}}</view>
|
||
<view class="info-sub-title">{{pageData.hallTime}}</view>
|
||
</view>
|
||
<view class="info" v-if="chooseTicket.length">
|
||
<view class="info-site-box">
|
||
<view class="info-site" v-for="(item, index) in chooseTicket" :key="item.id">
|
||
<view class="info-site-left">
|
||
<view>{{item.rowNum}}排{{item.seatNum}}座</view>
|
||
<view>¥{{item.sumPrice.toFixed(2)}}</view>
|
||
</view>
|
||
<view class="info-site-right" @click="delChoose(index)">
|
||
<u-icon name="close" color="#E1E1E1" size="24rpx"></u-icon>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="price" v-if="chooseTicket.length">
|
||
<span>¥</span>{{totalPrice}}<span>/{{chooseTicket.length}}张</span>
|
||
</view>
|
||
</view>
|
||
<view class="btn-box" :style="{paddingBottom: windowBottom + 'px'}">
|
||
<view class="btn" @click="confirm">确认选座</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
paddingTop: 0,
|
||
windowBottom: 0,
|
||
detail: null,
|
||
chooseTicket: [],
|
||
pageData: null,
|
||
seatStateHeader: []
|
||
};
|
||
},
|
||
computed: {
|
||
totalPrice() {
|
||
let total = 0
|
||
if (this.chooseTicket.length) {
|
||
this.chooseTicket.forEach(item => {
|
||
total += item.sumPrice
|
||
})
|
||
}
|
||
return total;
|
||
}
|
||
},
|
||
async onLoad(options) {
|
||
this.pageData = JSON.parse(decodeURIComponent(options.pageData));
|
||
this.paddingTop = this.$paddingTop;
|
||
this.windowBottom = this.$safeAreaBottom;
|
||
let info = await this.$http.getSalelnfo({
|
||
itemId: options.itemId,
|
||
hallId: options.hallId,
|
||
saleTime: this.pageData.saleTime
|
||
})
|
||
|
||
info.data.venueSeats = info.data.venueSeats ? JSON.parse(info.data.venueSeats) : {};
|
||
for (let i in info.data.venueSeats) {
|
||
for (var j = 0; j < info.data.venueSeats[i].length; j++) {
|
||
info.data.venueSeats[i][j][3] = 0;
|
||
}
|
||
}
|
||
this.getSeatStateHeader(info.data);
|
||
this.detail = info.data
|
||
},
|
||
methods: {
|
||
sortArrayByOddEven(seatStateHeader) {
|
||
let arr1 = [];
|
||
let arr2 = [];
|
||
seatStateHeader.forEach((item) => {
|
||
if (item % 2 == 0) {
|
||
arr2.push(item)
|
||
} else arr1.push(item)
|
||
})
|
||
arr2.sort((a, b) => {
|
||
return b - a;
|
||
})
|
||
arr1 = arr1.reverse();
|
||
arr2 = arr2.reverse();
|
||
arr1 = arr1.concat(arr2)
|
||
return arr1;
|
||
},
|
||
getSeatStateHeader (data) {
|
||
let seatStateHeader = [];
|
||
for (var i = 1; i <= data.seatNumsRow; i ++) {
|
||
seatStateHeader.push(i);
|
||
}
|
||
if (data.rowStart == 2) {
|
||
seatStateHeader = this.sortArrayByOddEven(seatStateHeader)
|
||
}
|
||
this.seatStateHeader = JSON.parse(JSON.stringify(seatStateHeader));
|
||
},
|
||
confirm() {
|
||
if (this.chooseTicket.length == 0) {
|
||
uni.showToast({
|
||
title: `请选择座位`,
|
||
icon: 'none',
|
||
mask: true
|
||
})
|
||
return
|
||
}
|
||
let obj = JSON.parse(JSON.stringify(this.pageData));
|
||
obj.chooseTicket = this.chooseTicket;
|
||
obj.totalPrice = this.totalPrice;
|
||
uni.redirectTo({
|
||
url: "/pages/scenic/ticktOrderConfirm?pageData=" + encodeURIComponent(JSON.stringify(obj))
|
||
})
|
||
},
|
||
selectItem(key, num, index) {
|
||
let data = this.detail.saleList.find((info) => {
|
||
return info.rowNum == key && info.seatNum == num;
|
||
})
|
||
if (!data) return false;
|
||
// 判断 是否是可买的状态& 是否被占座& 是否设置分区
|
||
if (data.seatState == 1 && data.lockSeat == 0 && !this.isPartition(key, index)) {
|
||
this.detail.zoneList.map((item) => {
|
||
if (item.zoneId == data.zoneId) {
|
||
data.sumPrice = item.price.price
|
||
data.zoneName = item.zoneName
|
||
}
|
||
})
|
||
let currentInd = this.chooseTicket.findIndex(ele => ele.id == data.id)
|
||
if (currentInd == -1) {
|
||
if (this.pageData.limit != null) {
|
||
// 是否小于限制数
|
||
if (this.chooseTicket.length >= this.pageData.limit) {
|
||
uni.showToast({
|
||
title: `最多可买${this.pageData.limit}张`,
|
||
icon: 'none',
|
||
mask: true
|
||
})
|
||
} else {
|
||
this.detail.venueSeats[key][index][3] = 1
|
||
this.chooseTicket.push(data)
|
||
}
|
||
} else {
|
||
this.detail.venueSeats[key][index][3] = 1
|
||
this.chooseTicket.push(data)
|
||
}
|
||
} else {
|
||
this.detail.venueSeats[key][index][3] = 0
|
||
this.chooseTicket.splice(currentInd, 1)
|
||
}
|
||
this.$forceUpdate()
|
||
}
|
||
},
|
||
borderColorFun(i) {
|
||
let ind = this.detail.zoneList.findIndex(item => item.zoneId == i[0])
|
||
return 'border-color-' + ind
|
||
},
|
||
// 是否售出
|
||
isSale(key, index, status) {
|
||
/** seatState 所有座位的状态,0不可选,1表示可售,2表示占座,3表示售出,在场次表中体现 */
|
||
let data = this.detail.saleList.find((info) => {
|
||
return info.rowNum == key && info.seatNum == index;
|
||
})
|
||
return data.seatState == status
|
||
},
|
||
// 是否分区
|
||
isPartition(key, index) {
|
||
let data = this.detail.saleList.find((info) => {
|
||
return info.rowNum == key && info.seatNum == (index + 1);
|
||
})
|
||
|
||
// 未设置分区的 禁止买
|
||
let arr = this.detail.zoneList.filter((item) => item.zoneId == data.zoneId)
|
||
// 未分区 true 分区 false
|
||
return arr.length ? false : true
|
||
},
|
||
// 是否锁座
|
||
isLock(key, index) {
|
||
/** lockSeat 付款锁定,0未锁定1,已锁定(待付款) */
|
||
let data = this.detail.saleList.find((info) => {
|
||
return info.rowNum == key && info.seatNum == index;
|
||
})
|
||
// 未锁座 true 锁座 false
|
||
return data.lockSeat == 0 ? true : false
|
||
},
|
||
delChoose(index) {
|
||
let item = this.chooseTicket[index]
|
||
this.detail.venueSeats[item.rowNum][item.seatNum - 1][3] = 0
|
||
this.chooseTicket.splice(index, 1)
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
page {
|
||
background-color: #FBFBFB;
|
||
}
|
||
</style>
|
||
|
||
<style lang="scss" scoped>
|
||
.wrap {
|
||
overflow-x: hidden;
|
||
box-sizing: border-box;
|
||
|
||
.scroll-box {
|
||
margin: 0 32rpx;
|
||
box-sizing: border-box;
|
||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||
|
||
.scroll-x {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 92rpx;
|
||
|
||
.tab {
|
||
margin-right: 30rpx;
|
||
white-space: nowrap;
|
||
font-size: 26rpx;
|
||
color: rgba(0, 0, 0, 0.45);
|
||
line-height: 30rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.box-show {
|
||
width: 38rpx;
|
||
height: 38rpx;
|
||
border-radius: 6rpx;
|
||
border-style: solid;
|
||
border-width: 2rpx;
|
||
margin-right: 12rpx;
|
||
box-sizing: border-box;
|
||
display: inline-block;
|
||
|
||
&>image {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.sm-title {
|
||
width: 100%;
|
||
text-align: center;
|
||
font-size: 30rpx;
|
||
color: rgba(0, 0, 0, 0.45);
|
||
margin-top: 30rpx;
|
||
margin-bottom: 60rpx;
|
||
}
|
||
|
||
.site-box {
|
||
position: relative;
|
||
.row {
|
||
white-space: nowrap;
|
||
text-align: center;
|
||
|
||
.column {
|
||
display: inline-block; margin: 8rpx; position: relative; width: 48rpx; height: 48rpx;
|
||
.sm-icon {
|
||
position: absolute; left: 0; top: 0; z-index: 3;
|
||
// margin: 8rpx;
|
||
width: 100%; height: 100%;
|
||
display: block;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.unselect {
|
||
border-style: solid;
|
||
border-width: 1rpx;
|
||
border-radius: 8rpx;
|
||
background: white;
|
||
}
|
||
|
||
.gray {
|
||
background: #F4F4F4;
|
||
border-color: #F4F4F4;
|
||
}
|
||
|
||
.selected {
|
||
border-radius: 8rpx;
|
||
background: #03AE80;
|
||
border: 1rpx solid #03AE80;
|
||
z-index: 5;
|
||
}
|
||
|
||
.disable {
|
||
background: #F4F4F4;
|
||
border-radius: 8rpx;
|
||
border: 1rpx solid rgba(0, 0, 0, 0.2);
|
||
z-index: 4;
|
||
}
|
||
.xuhao{ color: #666; font-size: 28rpx; border: none; background: transparent; text-align: center; line-height: 48rpx; }
|
||
}
|
||
}
|
||
|
||
.sm-line-index {
|
||
position: absolute;
|
||
top: 52rpx;
|
||
left: 32rpx;
|
||
border-radius: 24rpx;
|
||
background-color: rgba(0, 0, 0, 0.4);
|
||
overflow: hidden;
|
||
z-index: 3;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 10rpx 0;
|
||
|
||
.text {
|
||
min-width: 30rpx;
|
||
height: 48rpx;
|
||
line-height: 48rpx;
|
||
font-size: 24rpx;
|
||
color: #ffffff;
|
||
text-align: center;
|
||
margin-top: 20rpx;
|
||
margin: 8rpx 0 16rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
}
|
||
}
|
||
|
||
.info-box {
|
||
margin: 0 32rpx;
|
||
padding: 12rpx 24rpx 32rpx;
|
||
box-sizing: border-box;
|
||
background: #FFFFFF;
|
||
border-radius: 10rpx;
|
||
margin-top: 70rpx;
|
||
margin-bottom: 30rpx;
|
||
|
||
.info {
|
||
border-top: 1rpx solid rgba(0, 0, 0, 0.1);
|
||
box-sizing: border-box;
|
||
padding: 24rpx 0 0;
|
||
|
||
&:first-child {
|
||
border-top: none;
|
||
}
|
||
|
||
.info-title {
|
||
height: 42rpx;
|
||
font-weight: 600;
|
||
font-size: 30rpx;
|
||
color: rgba(0, 0, 0, 0.85);
|
||
line-height: 35rpx;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.info-sub-title {
|
||
height: 36rpx;
|
||
font-size: 26rpx;
|
||
color: rgba(0, 0, 0, 0.45);
|
||
line-height: 30rpx;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.info-site-box {
|
||
display: flex;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.info-site {
|
||
width: 156rpx;
|
||
height: 91rpx;
|
||
background: rgba(0, 0, 0, 0.03);
|
||
border-radius: 8rpx;
|
||
margin-right: 20rpx;
|
||
margin-bottom: 24rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 10rpx 16rpx;
|
||
|
||
.info-site-left {
|
||
box-sizing: border-box;
|
||
flex: 1;
|
||
padding-right: 20rpx;
|
||
border-right: 1rpx solid rgba(0, 0, 0, 0.05);
|
||
margin-right: 13rpx;
|
||
|
||
&>view:nth-child(1) {
|
||
height: 34rpx;
|
||
font-weight: 600;
|
||
font-size: 24rpx;
|
||
color: rgba(0, 0, 0, 0.85);
|
||
line-height: 28rpx;
|
||
margin-bottom: 6rpx;
|
||
}
|
||
|
||
&>view:nth-child(2) {
|
||
height: 31rpx;
|
||
font-size: 22rpx;
|
||
color: rgba(0, 0, 0, 0.65);
|
||
line-height: 26rpx;
|
||
}
|
||
}
|
||
|
||
.info-site-right {
|
||
height: 100%;
|
||
|
||
::v-deep .u-icon--right {
|
||
height: 100%;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.price {
|
||
height: 102rpx;
|
||
box-sizing: border-box;
|
||
padding-top: 24rpx;
|
||
text-align: right;
|
||
font-size: 64rpx;
|
||
color: #FF5833;
|
||
border-top: 1rpx solid rgba(0, 0, 0, 0.1);
|
||
|
||
&>span:nth-child(1) {
|
||
font-size: 36rpx;
|
||
}
|
||
|
||
&>span:last-child {
|
||
font-size: 24rpx;
|
||
color: rgba(0, 0, 0, 0.45);
|
||
line-height: 28rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.btn {
|
||
margin: 0 32rpx;
|
||
background: #03AE80;
|
||
height: 100rpx;
|
||
border-radius: 50rpx;
|
||
text-align: center;
|
||
line-height: 100rpx;
|
||
font-weight: 600;
|
||
font-size: 32rpx;
|
||
color: #FFFFFF;
|
||
}
|
||
}
|
||
|
||
.unselect {
|
||
border-color: rgba(0, 0, 0, 0.2);
|
||
}
|
||
.border-color-0 {
|
||
border-color: #FF3B44;
|
||
}
|
||
|
||
.border-color-1 {
|
||
border-color: #FF8319;
|
||
}
|
||
|
||
.border-color-2 {
|
||
border-color: #FFC53B;
|
||
}
|
||
|
||
.border-color-3 {
|
||
border-color: #FF67D6;
|
||
}
|
||
|
||
.border-color-4 {
|
||
border-color: #6795FE;
|
||
}
|
||
|
||
.border-color-5 {
|
||
border-color: #53CBBA;
|
||
}
|
||
.border-color-6 {
|
||
border-color: #8800FF;
|
||
}
|
||
|
||
.border-color-7 {
|
||
border-color: #97D5FF;
|
||
}
|
||
|
||
.border-color-8 {
|
||
border-color: #A70C13;
|
||
}
|
||
.border-color-9 {
|
||
border-color: #79FF19;
|
||
}
|
||
</style> |