電影 票

<template>
  <div class="wrapper">
    <div class="cinema-wrapper">
      <h1 class="title">電影院推薦座位功能</h1>
      <div class="btn-wrapper">
        <div class="btn-buy" @click="buySeat">
          選定座位
        </div>
        <div class="btn-buy" @click="resetSeat">
          重置座位
        </div>
        <!--智能選擇-->
        <template v-for="(item,index) in smartChooseMaxNum">
          <div class="btn-buy smart" @click="smartChoose(index+1)">
            推薦選座{{index+1}}人
          </div>
        </template>
      </div>
      <div class="seat-wrapper">
        <div class="illustration">
          <div class="illustration-img-wrapper unselected-seat">
          </div>
          <span class="illustration-text">可選</span>
          <div class="illustration-img-wrapper selected-seat">
          </div>
          <span class="illustration-text">已選</span>
          <div class="illustration-img-wrapper bought-seat">
          </div>
          <span class="illustration-text">不可選</span>
        </div>
        <div class="screen">
          3號激光廳銀幕
        </div>
        <div class="screen-center">
          銀幕中央
          <div class="mid-line"></div>
        </div>
        <div class="inner-seat-wrapper" ref="innerSeatWrapper" >
          <div v-for="row in seatRow">
            <!--這裏的v-if很重要,若是沒有則會致使報錯,由於seatArray初始狀態爲空-->
            <div v-for="col in seatCol"
                 v-if="seatArray.length>0"
                 class="seat"
                 :style="{width:seatSize+'px',height:seatSize+'px'}">
              <div class="inner-seat"
                   @click="handleChooseSeat(row-1,col-1)"
                   v-if="seatArray[row-1][col-1]!==-1"
                   :class="seatArray[row-1][col-1]===2?'bought-seat':(seatArray[row-1][col-1]===1?'selected-seat':'unselected-seat')">
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
	export default {
		name: 'cinemaSeatChoose',
		data () {
			return {
				//影院座位的二維數組,-1爲非座位,0爲未購座位,1爲已選座位(綠色),2爲已購座位(紅色)
				seatArray:[],
        //影院座位行數
        seatRow:10,
        //影院座位列數
        seatCol:20,
        //座位尺寸
        seatSize:'',
        //推薦選座最大數量
        smartChooseMaxNum:5

			}
		},
    computed:{
    },
    methods:{
			//向先後某個方向進行搜索的函數,參數是起始行,終止行,推薦座位個數
      searchSeatByDirection: function(fromRow,toRow,num){
        /*
         * 推薦座位規則
         * (1)初始狀態從座位行數的一半處的後一排的中間開始向左右分別搜索,取離中間最近的,若是知足條件,
         *    記錄下該結果離座位中軸線的距離,後排搜索完成後取距離最小的那個結果座位最終結果,優先向後排進行搜索,
         *    後排都沒有才往前排搜,前排邏輯同上
         *
         * (2)只考慮並排且連續的座位,不能不在一排或者一排中間有分隔
         *
         * */

        /*
         * 保存當前方向搜索結果的數組,元素是對象,result是結果數組,offset表明與中軸線的偏移距離
         * {
         *   result:Array([x,y])
         *   offset:Number
         * }
         *
         */
        let currentDirectionSearchResult = [];

        let largeRow = fromRow>toRow?fromRow:toRow,
            smallRow = fromRow>toRow?toRow:fromRow;

        for(let i=smallRow;i<=largeRow;i++){
          //每一排的搜索,找出該排裏中軸線最近的一組座位
          let tempRowResult = [],
              minDistanceToMidLine=Infinity;
          for(let j=0;j<=this.seatCol - num;j++){
            //若是有合法位置
            if(this.checkRowSeatContinusAndEmpty(i,j,j+num-1)){
              //計算該組位置距離中軸線的距離:該組位置的中間位置到中軸線的距離
              let resultMidPos = parseInt((j+num/2),10);
              let distance = Math.abs(parseInt(this.seatCol/2) - resultMidPos);
              //若是距離較短則更新
              if(distance<minDistanceToMidLine){
                minDistanceToMidLine = distance;
                //該行的最終結果
                tempRowResult = this.generateRowResult(i,j,j+num-1)
              }
            }
          }
          //保存該行的最終結果
          currentDirectionSearchResult.push({
            result:tempRowResult,
            offset:minDistanceToMidLine
          })
        }

        //處理後排的搜索結果:找到距離中軸線最短的一個
        //注意這裏的邏輯須要區分先後排,對於後排是從前日後,前排則是從後往前找
        let isBackDir = fromRow < toRow;
        let finalReuslt = [],minDistanceToMid = Infinity;
        if(isBackDir){
        	//後排狀況,從前日後
          currentDirectionSearchResult.forEach((item)=>{
            if(item.offset < minDistanceToMid){
              finalReuslt = item.result;
              minDistanceToMid = item.offset;
            }
          });
        }else{
        	//前排狀況,從後往前找
          currentDirectionSearchResult.reverse().forEach((item)=>{
            if(item.offset < minDistanceToMid){
              finalReuslt = item.result;
              minDistanceToMid = item.offset;
            }
          })
        }

        //直接返回結果
        return finalReuslt
      },


			//推薦選座,參數是推薦座位數目
      smartChoose: function(num){
        //找到影院座位水平垂直中間位置的後一排
        let rowStart = parseInt((this.seatRow-1)/2,10)+1;
        //先從中間排日後排搜索
      	let backResult = this.searchSeatByDirection(rowStart,this.seatRow-1,num);
      	if(backResult.length>0){
      		this.chooseSeat(backResult);
          return
        }
      	//再從中間排往前排搜索
        let forwardResult = this.searchSeatByDirection(rowStart-1,0,num);
        if(forwardResult.length>0) {
          this.chooseSeat(forwardResult);
          return
        }
        //提示用戶無合法位置可選
        alert('無合法位置可選!')

      },

      /*輔助函數,判斷每一行座位從i列到j列是否所有空餘且連續
       *
       */
      checkRowSeatContinusAndEmpty: function(rowNum,startPos,endPos){
      	  let isValid = true;
          for(let i=startPos;i<=endPos;i++){
          	if(this.seatArray[rowNum][i]!==0){
          		isValid=false;
          		break;
            }
          }
          return isValid
      },
      //輔助函數:返回每一行的某個合理位置的座位數組
      generateRowResult: function(row,startPos,endPos){
      	let result = [];
      	for(let i=startPos;i<=endPos;i++){
      		result.push([row,i])
        }
        return result
      },
      //輔助函數:智能推薦的選座操做
      chooseSeat: function(result){
        let oldArray = this.seatArray.slice();
        for(let i=0;i<result.length;i++){
        	//選定座位
        	oldArray[result[i][0]][result[i][1]] = 1
        }
        this.seatArray = oldArray;
      },


			//重置座位
      resetSeat: function(){
        //將全部座位的值變爲0
        let oldArray = this.seatArray.slice();
        for(let i=0;i<this.seatRow;i++){
          for(let j=0;j<this.seatCol;j++){
          	if(oldArray[i][j]!==-1){
              oldArray[i][j]=0
            }
          }
        }
        this.seatArray = oldArray;
      },
			//選定且購買座位
      buySeat: function(){
      	//遍歷seatArray,將值爲1的座位變爲2
        let oldArray = this.seatArray.slice();
        for(let i=0;i<this.seatRow;i++){
        	for(let j=0;j<this.seatCol;j++){
        		if(oldArray[i][j]===1){
              oldArray[i][j]=2
            }
          }
        }
        this.seatArray = oldArray;
      },
			//處理座位選擇邏輯
      handleChooseSeat: function(row,col){
      	let seatValue = this.seatArray[row][col];
      	let newArray = this.seatArray;
      	//若是是已購座位,直接返回
        if(seatValue===2) return
        //若是是已選座位點擊後變未選
        if(seatValue === 1){
          newArray[row][col]=0
        }else if(seatValue === 0){
          newArray[row][col]=1
        }
        //必須總體更新二維數組,Vue沒法檢測到數組某一項更新,必須slice複製一個數組才行
        this.seatArray = newArray.slice();

      },
      //初始座位數組
      initSeatArray: function(){
        let seatArray = Array(this.seatRow).fill(0).map(()=>Array(this.seatCol).fill(0));
        this.seatArray = seatArray;
        this.seatSize = this.$refs.innerSeatWrapper
                        ? parseInt(parseInt(window.getComputedStyle(this.$refs.innerSeatWrapper).width,10) / this.seatCol,10)
                        :0;
        //初始化不是座位的地方
        this.initNonSeatPlace();
      },
      //初始化不是座位的地方
      initNonSeatPlace: function(){
      	for(let i=0;i<9;i++){
          this.seatArray[i][0]=-1;
        }
        for(let i=0;i<8;i++){
          this.seatArray[i][this.seatArray[0].length-1]=-1;
          this.seatArray[i][this.seatArray[0].length-2]=-1;
        }
        for(let i=0;i<9;i++){
          this.seatArray[i][this.seatArray[0].length-3]=-1;
        }
        for(let i=0;i<this.seatArray[0].length;i++){
        	this.seatArray[2][i]=-1;
        }

      }

    },

    mounted:function(){
      this.initSeatArray(10,20)

    }
	}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  .wrapper{
    height:100%;
    padding: 40px;
    box-sizing: border-box;
  }
  .cinema-wrapper{
    height:100%;
  }
  .title{
    text-align: center;
  }
  .seat-wrapper{
    height:700px;
    width:1000px;
    border:1px dotted #c5c5c5;
    margin: 0 auto;
    position: relative;
    overflow: hidden;
  }
  .screen{
    margin: 0 auto;
    height:30px;
    width:300px;
    background-color: #e3e3e3;
    border-radius: 0 0 30px 30px;
    color: #585858;
    line-height: 30px;
    text-align: center;
  }
  .inner-seat-wrapper{
    position: absolute;
    top:120px;
    bottom:0;
    width:100%;
    box-sizing: border-box;
  }
  .seat{
    float:left;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .inner-seat{
    width:80%;
    height:80%;
    cursor: pointer;
  }
  .selected-seat{
    background: url('./../assets/selected.png') center center no-repeat;
    background-size: 100% 100%;
  }
  .unselected-seat{
    background: url('./../assets/unselected.png') center center no-repeat;
    background-size: 100% 100%;
  }
  .bought-seat{
    background: url('./../assets/bought.png') center center no-repeat;
    background-size: 100% 100%;
  }
  .screen-center{
    position: absolute;
    left:50%;
    transform: translateX(-50%);
    padding:5px;
    font-size: 13px;
    border-radius: 5px;
    top:50px;
    background-color: #f6f6f6;
    color: #636363;
    border:1px solid #b1b1b1;
  }
  .mid-line{
    position: absolute;
    left:50%;
    transform: translateX(-50%);
    top:100%;
    width:1px;
    height:800px;
    border-left:1px dashed #919191;
  }
  .btn-wrapper{
    margin: 20px auto;
    width:1000px;
    height:30px;
    text-align: center;
  }
  .btn-buy{
    height:100%;
    line-height: 30px;
    font-size: 14px;
    border-radius: 5px;
    padding:0 5px;
    background-color: #ffa349;
    color: #ffffff;
    display: inline-block;
    cursor: pointer;
    margin-right: 10px;
  }
  .smart{
    background-color: #39ac6a;
  }
  .illustration{
    position: absolute;
    left:0;
    top:0;
    height:35px;
    width:300px;
  }
  .illustration-img-wrapper{
    width:25px;
    height:25px;
    position: relative;
    top:50%;
    display: inline-block;
    transform: translateY(-50%);
    margin-left: 10px;
  }
  .illustration-text{
    display: inline-block;
    height:100%;
    line-height: 35px;
    font-size: 14px;
    position: relative;
    top:-2px;
  }

</style>
複製代碼
本站公眾號
   歡迎關注本站公眾號,獲取更多信息