0%

[技能檢定]題組三 步驟17 前台線上訂票功能-劃位功能及訂票完成

這邊題目給出的指示需要摸擬一個影廳的座位狀況,然後使用者可以點選座位來訂票,所以會需要一些建置前端頁面的工作;

這邊會先由前端頁面使用ajax來傳送電影id,日期,場次等資訊到api,然後在api程式中使用php來取出已訂位的資料,建置完座位區後,再以js來完成前端劃位的操作,最後再把訂單資料送到後端去儲存,完成整個訂票的功能。

頁面切換機制

  1. 在劃位的功能的處理上,我們不使用表單跳頁的方式,而是使用js來控制畫面區塊的切換,這樣就能保留表單的選擇狀態,回上一步時只要切換區塊即可。
  2. 我們也同時使用ajax的方式把選單的內容傳送到後端去產生一份劃位的頁面,並放在#booking區塊中
    1
    2
    3
    4
    5
    <div class="ct">
    <!--點擊選單的確定時,讓兩個div的顯示狀態切換,同時也向後端取得劃位畫面-->
    <button onclick="$('#orderForm,#booking').toggle();getBooking()">確定</button>
    <button onclick="reset()">重置</button>
    </div>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    //建立一個空的全域物件變數
    let order={};

    //用來向後端取得劃位頁面的ajax函式
    function getBooking(){

    //取得各個下拉選單的資料,並設定進order物件中
    order.movie=$("#movie option:selected").text()
    order.date=$("#date").val()
    order.session=$("#session").val()

    //將訂票資訊傳至後端get_booking.php,並取回劃位頁面html內容
    $.get("./api/get_booking.php",order,(booking)=>{

    //將劃位頁面的html放至#booking區塊中
    $("#booking").html(booking)
    })
    }

劃位頁面製作

  1. 劃位頁面的產生及劃位行為應該是本題組最複雜的一部份了,這邊要注意的細節比較多,同時也有很多的技巧用來簡化程式碼的撰寫。

  2. 首先我們先在類別 Order 中增加一個方法,這個方法會接收表單傳過來的電影,日期及場次資料,然後回傳剩餘的座位資訊
    /controller/Order.php

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    function seats($request){
    //將傳入的表單陣列解開為$movie,$date,$session三個變數
    extract($request);

    //根據電影名稱,日期及場次,取出所有的訂單
    $orders=$this->all(['movie'=>$movie,'date'=>$date,'session'=>$session]);

    //建立一個用來存放已訂位的座位空陣列
    $seats=[];

    //迴圈逐筆取出訂單
    foreach ($orders as $key => $order) {

    //還原訂位為陣列
    $tmp=unserialize($order['seats']);

    //使用array_merge()函式將訂位資料放在seats陣列中
    $seats=array_merge($seats,$tmp);
    }
    return $seats;
    }
  3. 接著我們建立劃位頁面的架構,並建立必要的class name
    api/booking.php

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <div class="theater">

    <!--建立一個容器來存放所有的座位-->
    <div class="seats">

    <!--seat是座位的基本樣式設定,
    null是空座位的css設定,
    booked是已被訂位的css設定-->
    <div class='seat null'></div>
    </div>
    </div>
    <div class="order-info">
    <div>您選擇的電影是:</div>
    <div>您選擇的時刻是:</div>
    <div>您已經勾選<span id="qt"></span>張票,最多可以購買四張票</div>
    <div class="ct">
    <button onclick="$('#order,#booking').toggle()">上一步</button>
    <button>訂購</button>
    </div>
    </div>
  4. 建立劃位頁面的css設定

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    #booking *{
    box-sizing: border-box;
    }
    .theater{
    width:540px;
    height:370px;
    background-image: url(./icon/03D04.png);
    background-repeat: no-repeat;
    background-position: center;
    margin:auto;
    padding-top:18px;
    }
    .seats{
    width:320px;
    height:340px;
    margin:auto;
    display:flex;
    flex-wrap: wrap;
    }
    .seat{
    width:64px;
    height:85px;
    text-align: center;
    position:relative;
    }
    .seat input{
    position:absolute;
    bottom:5px;
    right:5px;
    }
    .null,.booked{
    background-position: center;
    background-repeat: no-repeat;
    }
    .null{
    background-image: url("../icon/03D02.png");
    }
    .booked{
    background-image: url("../icon/03D03.png");
    }
    .order-info{
    width:540px;
    margin:auto;
    padding:0px 100px;
    }
    .order-info div{
    margin:5px;
    }
  5. 根據前端ajax傳來的資料取得劃位頁面需要的內容

    1
    2
    3
    4
    include_once "../base.php";

    //使用seats()方法來取得該場次的已訂位資訊
    $seats=$Order->seats($_GET);
  6. 使用迴圈來產生20個座位,包含座位資訊及選票框

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <div class="theater">
    <div class="seats">
    <?php
    for($i=0;$i<20;$i++){
    //取得座位資訊字串
    $position=(floor($i/5)+1)."排".($i%5+1)."號";
    ?>
    <!--判斷目前的座位值是否在陣列$seats中,決定要使用那個class-->
    <div class="seat <?=in_array($i,$seats)?'booked':'null';?>">
    <?=$position;?>
    <?php
    if(!in_array($i,$seats)){
    echo "<input type='checkbox' name='seat' value='{$i}'>";
    }
    ?>
    </div>
    <?php
    }
    ?>
    </div>
    </div>
  7. 根據ajax傳來的資訊,將訂位資訊顯示在下方訂票資訊區

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <div class="order-info">
    <div>您選擇的電影是:<?=$_GET['movie'];?></div>
    <div>您選擇的時刻是:<?=$_GET['date'];?> <?=$_GET['session'];?></div>
    <div>您已經勾選<span id="qt"></span>張票,最多可以購買四張票</div>
    <div class="ct">
    <button onclick="$('#order,#booking').toggle()">上一步</button>
    <button>訂購</button>
    </div>
    </div>
  8. 撰寫訂位行為的js程式碼

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    //建立一個js陣列用來儲存使用者選中的座位
    let seats=new Array();

    //監聽checkbox的改變事件
    $(".seat input").on("change",function(){
    //根據屬性checked的狀態來決定下一步是選擇位置還是取消位置
    if($(this).prop('checked')){

    //如果是選中的狀態,
    //先判斷目前選中的座位有沒有超過四個
    if(seats.length>=4){

    //如果選中的座位已經四張了,就會出現警告
    alert("最多只能購買四張票");

    //接著將選中的座位還原為不選中的狀態
    $(this).prop('checked',false)
    }else{

    //如果選中的座位數還沒有超過四個,
    //就把座位號碼放入陣列中
    seats.push($(this).val())
    }

    }else{
    //如果是要取消選中的座位,
    //則同時也在座位陣列中移除該座位號
    seats.splice(seats.indexOf($(this).val()),1)
    }

    //更新票數的文字
    $("#qt").text(seats.length)
    })



  9. 撰寫送出訂單函式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //確認訂單的函式
    function checkout(){
    order.seats=seats
    //使用ajax向api傳送訂單的資料
    $.post("./api/order.php",order,(result)=>{
    //取得訂單完成的頁面,並更新到#booking區塊中
    $("#booking").html(result)
    }
    )
    }
  10. 最後是製作訂單結果頁面,我們在劃位的最後按下訂購時,並沒有做頁面導向的動作,這邊一樣是利用ajax的方式把訂購資訊及劃位結果送去後端處理,等後端處理完後,再返回訂單的頁面給前端,然後我們再把訂單結果頁面整個取代掉原本的劃位區塊 #booking

api/order.php
根據訂單資料,處理成可以存入資料表的格式,並存入資料表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
include_once "../base.php";

//取得資料的id值用來製作編號
$max_id=$Order->max('id')+1;

//產生有流水號性質的訂單編號
$_POST['no']=date("Ymd") . sprintf("%04d",$max_id);

//計算座位的數量
$_POST['qt']=count($_POST['seats']);

//先將座位陣列排序過
sort($_POST['seats']);

//將陣列轉成格式化的字串
$_POST['seats']=serialize($_POST['seats']);

//將$_POST新增進資料表
$Order->save($_POST);

建立訂單完成頁面,回傳給前端使用
api/order.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<h3>感謝您的訂購,您的訂單編號是:<?=$_POST['no'];?></h3>
<p>電影名稱:<?=$_POST['movie'];?></p>
<p>日期:<?=$_POST['date'];?></p>
<p>場次時間:<?=$_POST['session'];?></p>
<p>座位:<br>
<?php
$seats=unserialize($_POST['seats']);
foreach($seats as $seat){
echo floor($seat/5)+1 . "排" . ($seat%5 +1 ) . "號";
echo "<br>";
}
?>
<br>
<?=count($seats);?>張電影票
</p>
<p class="ct">
<!--按下確定按鈕時將使用者導回首頁-->
<button onclick="location.href='index.php'">確定</button>
</p>

補充

上述的做法重點只在決定座位的資訊,然後送出訂單完成交易,但在實務上,只有checkbox的勾選在使用者互動上是有點薄弱的,因此我們可以在選中及取消座位時,使用我們設定的兩個class來做切換,讓劃位的視覺互動感受更具體一些:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$(".chk").on("change",function(){
//根據屬性checked的狀態來決定下一步是選擇位置還是取消位置
if($(this).prop('checked')){
if(seats.length>=4){
alert("最多只能購買四張票");
$(this).prop('checked',false)
}else{
seats.push($(this).val())
//如果是要增加座位的話則把已訂位的class加上去
$(this).parents(".seat").addClass("booking-seat")
}
}else{
seats.splice(seats.indexOf($(this).val()),1)

//如果是要取消座位的話則把已訂位的class移除後
//加上未訂位的class
$(this).parents(".seat").removeClass("booking-seat")
$(this).parents(".seat").addClass("null-seat")
}

//更新票數的文字
$("#tickets").text(seats.length)
})

最後的檢查

題組三的難點在於前台的預告片轉場動畫及訂票劃位功能上,所以如果做完有空,可以先檢查一下這兩個功能,確認分數有拿到;相較於一,二題以四小時內可以做完為目標,三,四題的目標放在四小時內可以做到及格就好了,因此可以在戰略上分配好,那些功能是可以押後來做,把時間留給有把握的功能上,並加強檢查。