select-seat.js
const api = require('../../../utils/api.js')
const app = getApp();
let that;
Page({
/**
* 页面的初始数据
*/
data: {
height: "",
seats: [],
lineTop: 0,
lineHeight: "",
lineArray: [],
reset: false,
columnNumber: 0,
selectX: 0,
selectY: 0,
selectedSeat: [],
price:'',
rowSize: '',
seatTypeList: [],
seatArea: '',
timer: null,
maxY:'',
maxX:'',
loadComplete:false,
hidden:true
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
that = this;
let movie = JSON.parse(options.paramsStr);
let price = movie.sellPrice;
this.setData({
price: price,
movie: movie,
seatArea: app.globalData.screenHeight - app.globalData.statusBarHeight - (500 * app.globalData.screenWidth / 750),
rpxToPx: app.globalData.screenWidth / 750
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
let seats = [];
api.post('/api/cinema/trade_seat', { showId: this.data.movie.showId }).then(function (res) {
seats =that.prosessSeats(res.seatList.rows);
that.setData({
seatTypeList: res.seatTypeList,
seats: seats,
columnNumber: res.seatList.rowSize
})
that.prosessMaxSeat(res.seatList);
const query = wx.createSelectorQuery()
query.select('#seatView').boundingClientRect()
query.exec((r) => {
let height = r[0].heighrt;
let newHeight =that.data.seatScaleHeight;
let top = r[0].top;
that.setData({
lineHeight: newHeight,
lineTop: top-80
})
})
})
},
prosessSeats:function(data){
let seatData=data;
seatData.forEach(e => {
e.columns.forEach(j=>{
if(j.status=="CAN_SELL"){
j.icon="/assets/icon/seatPre.png";
j.flag=0;
}else if(j.status=="EMPTY"){
j.icon="";
}else{
j.flag=1;
j.icon="/assets/icon/seatDone.png";
}
})
});
return seatData;
},
//计算最大座位数,生成影厅图大小
prosessMaxSeat: function(value) {
let seatList = value
let maxY = seatList.rowSize;
let maxX = seatList.rows[0]['columns'].length;
let seatRealWidth = parseInt(maxX) * 70 * this.data.rpxToPx
let seatRealheight = parseInt(maxY) * 70 * this.data.rpxToPx
let seatScale = 1;
let seatScaleX = 1;
let seatScaleY = 1;
let seatAreaWidth = 630 * this.data.rpxToPx
let seatAreaHeight = this.data.seatArea - 200 * this.data.rpxToPx
if (seatRealWidth > seatAreaWidth) {
seatScaleX = seatAreaWidth / seatRealWidth
}
if (seatRealheight > seatAreaHeight) {
seatScaleY = seatAreaHeight / seatRealheight
}
if (seatScaleX < 1 || seatScaleY < 1) {
seatScale = seatScaleX < seatScaleY ? seatScaleX : seatScaleY
}
this.setData({
maxY: parseInt(maxY),
maxX: parseInt(maxX),
seatScale: seatScale,
seatScaleHeight: seatScale * 70 * this.data.rpxToPx,
loadComplete:true
});
},
//解决官方bug
handleScale: function (e) {
if (this.data.timer) {
clearTimeout(this.data.timer)
}
let timer = setTimeout(() => {
this.setData({
seatArea: this.data.seatArea
});
}, 200)
},
onScale(e) {
const query = wx.createSelectorQuery()
query.select('#seatView').boundingClientRect()
query.exec((res) => {
let height = res[0].height;
let top = res[0].top;
let newHeight = that.data.seatScaleHeight;
this.setData({
lineHeight: newHeight,
lineTop: top
})
})
},
selectSeat(e) {
let rowid = e.currentTarget.dataset.rowid;
let columnid = e.currentTarget.dataset.columnid;
let flag = e.currentTarget.dataset.flag;
let seats=that.data.seats
if(flag==1){
for (var a = 0; a < that.data.selectedSeat.length; a++) {
if (that.data.selectedSeat[a].rowid == rowid&&that.data.selectedSeat[a].columnid==columnid) {
that.data.selectedSeat.splice(a, 1);
break;
}
}
}else{
if(that.data.selectedSeat.length==4){
wx.showToast({
title: '最多只能选4个座哦~~',
icon:'none'
})
return;
}
let seat = {
rowid:rowid,
columnid:columnid
};
that.data.selectedSeat.push(seat);
}
seats.forEach(e=>{
e.columns.forEach(c=>{
if(rowid==e.rowId&&c.columnId==columnid){
if(c.flag==1){
c.flag=0;
c.icon="/assets/icon/seatPre.png";
}else if(c.flag==0){
c.flag=1;
c.icon="/assets/icon/selectIcon.png";
}
}
})
})
let hidden=true;
if(that.data.selectedSeat.length!=0){
hidden=false;
}
that.setData({
hidden:hidden,
seats:seats,
selectedSeat: that.data.selectedSeat,
totalPrice: that.data.selectedSeat.length*that.data.price
})
},
cancelSeat(e) {
let rowid = e.currentTarget.dataset.rowid;
let columnid = e.currentTarget.dataset.columnid;
let seats=that.data.seats
for (var a = 0; a < that.data.selectedSeat.length; a++) {
if (that.data.selectedSeat[a].rowid == rowid&&that.data.selectedSeat[a].columnid==columnid) {
that.data.selectedSeat.splice(a, 1);
break;
}
}
seats.forEach(e=>{
e.columns.forEach(c=>{
if(rowid==e.rowId&&c.columnId==columnid){
c.flag=0;
c.icon="/assets/icon/seatPre.png";
}
})
})
let hidden=false;
if(that.data.selectedSeat.length==0){
hidden=true;
}
that.setData({
hidden:hidden,
selectedSeat: that.data.selectedSeat,
totalPrice: that.data.selectedSeat.length*that.data.price,
seats:seats
})
},
confirmHandle() {
if(that.data.selectedSeat.length==0){
wx.showToast({
title: '至少得选1个座位哦~~',
icon:'none'
})
return;
}
}
})
select-seat.wxml
<!--电影信息-->
<view class='info'>
<view class='movieName'>{{movie.filmName}}</view>
<view class='planDetail'>{{movie.startDate}} {{movie.startTime}}</view>
<!-- 使用时注释dom view class='about' 即可 .about css 在app.wxss中 -->
</view>
<!--座位示例图 -->
<view class="seatDemosBack" wx:if="{{loadComplete}}">
<view class="seatDemos">
<block wx:for="{{seatTypeList}}" wx:for-index="index" wx:for-item="seatTypeItem" wx:key="index">
<view class="seatDemo">
<image class="seatDemoItem" mode="widthFix" src="{{seatTypeItem.icon}}"></image>
<view class="seatDemoItem"> {{seatTypeItem.name}}</view>
</view>
</block>
</view>
</view>
<movable-area scale-area="true" class="defaultArea" style="height:{{seatArea}}px; width: 750rpx;">
<movable-view class='movableOne' bindscale="handleScale" style="height:{{seatArea}}px; width: 750rpx;" scale="true" direction="all" scale-max="2" scale-value="1" out-of-bounds="true">
<view class='seatArea' id="seatView" style='width:{{seatScaleHeight * maxX}}px;height:{{seatScaleHeight * maxY}}px'>
<view class='hallName'>
<text>{{movie.hallName}}</text>
</view>
<view class='x' wx:for="{{seats}}" wx:key="keys" wx:for-item="item" wx:for-index="idx">
<view class='y' wx:for="{{item.columns}}" wx:key="items" wx:for-index="idy" wx:for-item="items" style="left:{{(items.columnId-1)* seatScaleHeight}}px;top:{{(item.rowNum-1) * seatScaleHeight}}px;width: {{seatScaleHeight}}px;height: {{seatScaleHeight}}px">
<image wx:if="{{items.status!='EMPTY'&&items.status!='CAN_SELL'}}" class="img" src='{{items.icon}}' data-rowid='{{item.rowId}}' data-flag="{{items.flag}}" data-index="{{idy}}" data-columnid='{{items.columnId}}'></image>
<image wx:elif="{{items.status=='EMPTY'}}" class="img" src=''></image>
<image wx:elif="{{items.status=='CAN_SELL'}}" class="img" bind:tap='selectSeat' src='{{items.icon}}' data-rowid='{{item.rowId}}' data-flag="{{items.flag}}" data-index="{{idy}}" data-columnid='{{items.columnId}}'></image>
</view>
</view>
</view>
</movable-view>
</movable-area>
<!--下部分座位示例图 -->
<!-- 用户选中的座位详情 -->
<view class='selectSeatInfo' hidden='{{hidden}}'>
<scroll-view class="scrollSeat" scroll-x style="width: 100%">
<!-- 普通座位 -->
<block wx:for="{{selectedSeat}}" wx:key="id" wx:for-item="selectedSeatItem">
<view class='scrollItem' bindtap='cancelSeat' data-rowid="{{selectedSeatItem.rowid}}" data-columnid="{{selectedSeatItem.columnid}}">
<view class='scrollTextTop'>
{{selectedSeatItem.rowid}}排{{selectedSeatItem.columnid}}座
</view>
<view class='scrollTextBottom'>
¥{{price}}
</view>
<image src='/assets/images/close.png'></image>
</view>
</block>
</scroll-view>
</view>
<!-- 快速选座 -->
<view class='selectSeatInfo' hidden='{{!hidden}}'>
<scroll-view class="scrollSeat" scroll-x style="width: 100%">
<view class='quickItem' bindtap='quickSeat' data-num='1'>
1人座
</view>
<view class='quickItem' bindtap='quickSeat' data-num='2'>
2人座
</view>
<view class='quickItem' bindtap='quickSeat' data-num='3'>
3人座
</view>
<view class='quickItem' bindtap='quickSeat' data-num='4'>
4人座
</view>
</scroll-view>
</view>
<!-- 以下是确认选座 -->
<view class='orderComfirm' style="flex-direction:row;">
<view class='comfirm' bindtap='confirmHandle'>¥
<text>{{totalPrice}}</text> 元 确认选座</view>
</view>
select-seat.wxss
/*
*@zenghao 2018-06-12
*/
page {
background: #eee;
}
/*
*上方影片名称样式
*/
@import "/style/main.wxss";
@import "/style/icon.wxss";
.movieName {
font-size: 35rpx;
font-weight: 600;
margin-bottom: 10rpx;
}
/*
*上方排期信息样式
*/
.planDetail {
color: #aaa;
font-size: 27rpx;
}
/*
*上方影片,排期信息的父级
*/
.info {
width: 100%;
height: 80rpx;
background: #fff;
border-top: 1rpx solid #eee;
border-bottom: 1rpx solid #eee;
padding: 30rpx 30rpx;
position: relative;
}
.seatDemosBack {
background: #fff;
}
/*
*座位样式的父级
*/
.seatDemos {
color: #aaa;
background: #fff;
position: relative;
margin: 0 auto;
width: 80%;
box-sizing: border-box;
font-size: 25rpx;
height: 70rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.areaSeatDemos {
width: 100%;
height: 80rpx;
position: fixed;
bottom: 100rpx;
}
.seatDemosScroll {
color: #aaa;
background: #fff;
width: 100%;
height: 100%;
font-size: 25rpx;
white-space: nowrap;
}
.seatDemosScrollItem {
height: 90rpx;
white-space: nowrap;
overflow: hidden;
margin-left: 15px;
display: inline-block;
align-items: center;
margin-top: 25rpx;
}
.seatDemosScrollItem.Itemnormal image {
margin-right: 10rpx;
width: 40rpx;
height: 40rpx;
vertical-align: -30%;
}
/*
*情侣座位的图片样式
*/
.seatDemosScrollItem.Itemlove image {
margin: 0;
width: 40rpx;
height: 40rpx;
vertical-align: -30%;
}
/*
*情侣座位的字体样式
*/
.seatDemosScrollItem.Itemlove text {
margin-left: 10rpx;
}
.seatDemo image {
width: 45rpx;
height: 45rpx;
}
/*
*普通座位的图片样式
*/
.seatDemoItem {
white-space: nowrap;
width: 45rpx;
display: block;
}
/*
*情侣座位的图片样式
*/
.seatDemo {
display: flex;
align-items: center;
}
/*
*情侣座位的字体样式
*/
.loveSeatDemo text {
margin-left: 10rpx;
}
/*
*影厅图上方显示影厅名字区域
*/
.hallName {
width: 200rpx;
height: 0;
border-top: 40rpx solid #ccc;
border-right: 20rpx solid transparent;
border-left: 20rpx solid transparent;
line-height: 30rpx;
color: white;
position: absolute;
top: -100rpx;
z-index: 2;
left: 50%;
transform: translateX(-50%);
white-space: nowrap;
}
/*
*影厅图上方显示影厅名字区域字体样式
*/
.hallName text {
font-size: 20rpx;
position: absolute;
left: 50%;
transform: translateX(-50%);
top: -35rpx;
}
/*
*所有座位的区域
*/
.seatArea {
margin: 0 auto;
font-size: 10rpx;
position: relative;
}
/*
*中轴线
*/
/* .alignLine {
position: absolute;
left: 50%;
height: 100%;
border-left: 1px dashed #aaa;
transform: translateX(-100%);
} */
/*
*选座区域普通座位的图片样式
*/
.normal {
position: relative;
/* margin: 10rpx; */
width: 100%;
height: 100%;
}
/*
*选座区域情侣座位的图片样式
*/
.LoveSeat {
position: relative;
/* margin: 10rpx 0; */
width: 70rpx;
height: 70rpx;
}
/*
*所有座位的图片样式下方透明可点击区域
*/
.seatTap {
position: absolute;
}
/*
*情侣座位的图片样式下方透明可点击区域
*/
.LoveSeatTap {
position: absolute;
top: 0;
width: 70rpx;
height: 70rpx;
}
/*
* 座位图限制区域
*/
movable-area {
background: #eee;
overflow: hidden;
}
/*
* 座位图可移动区域(座位图)
*/
.movableOne {
box-sizing: border-box;
padding: 100rpx 60rpx;
color: #fff;
}
/*
* 座位图可移动区域(左边座位排号栏)
*/
.movableTwo {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 1400rpx;
width: 30rpx;
padding: 100rpx 0;
color: #fff;
}
/*
* (左边座位排号栏整体)
*/
.seatTool {
width: 30rpx;
padding: 100rpx 0;
opacity: 0.5;
}
.seatToolArea {
background: rgba(0, 0, 0, 0.2);
border-radius: 50rpx;
}
/*
* (左边座位排号栏每一个块)
*/
.seatTag {
text-align: center;
color: rgba(0, 0, 0, 0.5);
}
/*
*页面最下方确认选座区域
*/
.orderComfirm {
background: #fff;
position: fixed;
display: flex;
bottom: 0rpx;
width: 100%;
line-height: 100rpx;
z-index: 3;
}
/*
*页面最下方价格区域
*/
.orderPrice {
text-indent: 30rpx;
color: black;
height: 100rpx;
width: 60%;
}
/*
*页面最下方价格字体样式
*/
.orderPrice text {
color: red;
}
/*
*页面最下方确认选座区域渐变色
*/
.comfirm {
font-weight: 900;
text-align: center;
color: white;
width: 100%;
background: linear-gradient(to right, #C26DFE, #6F50F5);
height: 100rpx;
}
/*
*用户选中的座位区域
*/
.selectSeatInfo {
background: #fff;
position: fixed;
bottom: 100rpx;
height: 80rpx;
width: 100%;
padding: 10rpx 0;
}
/*
*用户选中的座位详情滑块
*/
.scrollSeat {
height: 90rpx;
white-space: nowrap;
}
/*
*每块用户选中的座位详情
*/
.scrollItem {
border: 1rpx solid #bbb;
border-radius: 10rpx;
width: 180rpx;
display: inline-block;
margin-left: 20rpx;
position: relative;
}
/*
* 快速选座模块
*/
.quickItem {
border: 1rpx solid #bbb;
color: #aaa;
font-size: 28rpx;
border-radius: 10rpx;
width: 160rpx;
height: 75rpx;
line-height: 75rpx;
text-align: center;
display: inline-block;
margin-left: 20rpx;
position: relative;
}
/*
*每块用户选中的座位详情上方文字
*/
.scrollTextTop {
color: #555;
text-indent: 30rpx;
line-height: 25rpx;
font-size: 26rpx;
height: 25rpx;
margin-top: 10rpx;
}
/*
*每块用户选中的座位详情下方文字
*/
.scrollTextBottom {
font-weight: 600;
font-size: 26rpx;
color: #ff005a;
text-indent: 40rpx;
height: 25rpx;
line-height: 25rpx;
margin: 10rpx 0;
}
/*
*每块用户选中的座位详情关闭按钮
*/
.scrollItem image {
position: absolute;
z-index: 2;
width: 30rpx;
height: 30rpx;
right: 10rpx;
top: 50%;
transform: translateY(-50%);
}
.seatAreaTip {
position: relative;
width: 750rpx;
height: 50rpx;
line-height: 50rpx;
text-align: center;
font-size: 16rpx;
color: rgba(0, 0, 0, 0.1);
border-top: 1rpx dashed rgba(0, 0, 0, 0.1);
}
.x {
display: flex;
flex-direction: row;
}
.y {
display: flex;
flex-direction: column;
}
.img {
margin: 5rpx;
height: 60rpx;
width: 60rpx;
}
.imgSelect {
margin: 5rpx;
height: 60rpx;
width: 60rpx;
background: #fd4f68;
}
.line {
opacity: 0.5;
display: flex;
flex-direction: column;
justify-content: center;
position: fixed;
left: 5rpx;
background: #585656;
}
.text {
opacity: 0.5;
margin: 5rpx;
text-align: center;
width: 60rpx;
font-size: auto;
}
.hallTitle {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
position: fixed;
width: 460rpx;
background: #e2e2e2;
border-bottom-left-radius: 90rpx;
border-bottom-right-radius: 90rpx;
}
.hallTitle text {
padding: 10rpx;
font-size: 28rpx;
color: #666;
text-align: center;
}
select-seat.json
{
"disableScroll": true,
"navigationBarTitleText": "选座购票"
}
app.js
//app.js
const QQMapWX = require('./assets/libs/qqmap-wx-jssdk.min.js');
let qqmapsdk;
qqmapsdk = new QQMapWX({
key: '********************************'
});
App({
onLaunch: function () {
this.initPage()
},
initPage(){
// 获取用户授权信息信息,防止重复出现授权弹框
wx.getSetting({
success: res => {
//已有权限直接获得信息,否则出现授权弹框
if (res.authSetting['scope.userLocation']) {
this.getUserLocation()
} else {
this.getUserLocation()
}
}
})
wx.getSystemInfo({
success: res => {
this.globalData.screenHeight = res.screenHeight;
this.globalData.screenWidth = res.screenWidth;
this.globalData.statusBarHeight = res.statusBarHeight
}
})
},
//获取用户的位置信息
getUserLocation() {
wx.getLocation({
//成功授权
success: (res) => {
const latitude = res.latitude;
const longitude = res.longitude;
// 使用腾讯地图接口将位置坐标转出成名称(为什么弹框出出现两次?)
qqmapsdk.reverseGeocoder({
location: { //文档说location默认为当前位置可以省略,但是还是要手动加上,否则弹框会出现两次,手机端则出现问题
latitude,
longitude
},
success: (res) => {
const cityFullname = res.result.address_component.city;
const location_id=res.result.ad_info.city_code;
const cityInfo = {
latitude,
longitude,
cityName: cityFullname.substring(0, cityFullname.length - 1),
status:1,
location_id:location_id.substr(3)
}
this.globalData.userLocation = { ...cityInfo} //浅拷贝对象
this.globalData.selectCity = { ...cityInfo } //浅拷贝对象
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回,所以此处加入 callback 以防止这种情况
if (this.userLocationReadyCallback) {
this.userLocationReadyCallback()
}
}
})
},
fail:()=>{
this.globalData.userLocation = {status:0}
this.globalData.selectCity.location_id=false
//防止当弹框出现后,用户长时间不选择,
if (this.userLocationReadyCallback) {
this.userLocationReadyCallback()
}
}
})
},
globalData: {
userLocation: null, //用户的位置信息
selectCity: {location_id:150100}, //用户切换的城市
host:"https://movie.xxx.com",
screenHeight:null,
screenWidth:null,
statusBarHeight:null
}
})