[題目解析] 技能檢定!網頁設計乙級術科考題分析(題組三)

本篇為網乙解析系列之題組三,難度算是最高的,題目動作與資料庫少,但大量依賴前端 JSJQ 進行視覺與動態資料操作占用時間,步驟不熟悉一旦卡住某小節設計,整題後續都將無法完成,若題目沒有特別要求的視覺操作盡可能不要花時間求媲美於示意圖。本篇之前置作業 (lib.php 與 MySQL 規劃)不再進行說明。

No.3 主選單 (15%)

調整 index.php 選單的有效連接,以及規劃好帳號登入功能。

q3t3

主選單的有效連結

先修正正確的檔案名稱之超連結,在三個素材版型內找到

修改 index.php & order.php & admin.php

index.php & order.php & admin.php
<div id="top2">
<a href="03P01.htm">首頁</a> <a href="03P02.htm">線上訂票</a> <a href="#">會員系統</a> <a href="03P03.htm">管理系統</a>
</div>

修改為

index.php & order.php & admin.php
<div id="top2">
<a href="index.php">首頁</a>
<a href="order.php">線上訂票</a>
<a href="#">會員系統</a>
<a href="admin.php">管理系統</a>
</div>

另外先插入各頁首連接 lib.php ,方便之後任何 PHP 與 SQL 處理。

index.php & order.php & admin.php
<?php
include "lib.php";
?>

前台首頁的內容切換

這裡會有三組切換,包含預設畫面、內容細節、登入畫面。所以設計一個內容切換。把 div.mm 的內容都抽取出來

修改 index.php

main.php
<div class="half" style="vertical-align:top;">
<h1>預告片介紹</h1>
<div class="rb tab" style="width:95%;">
<div id="abgne-block-20111227">
<ul class="lists">
</ul>
<ul class="controls">
</ul>
</div>
</div>
</div>
<div class="half">
<h1>院線片清單</h1>
<div class="rb tab" style="width:95%;">
<table>
<tbody>
<tr> </tr>
</tbody>
</table>
<div class="ct"> </div>
</div>
</div>

取代為下列代碼,上列代碼另存為 main.php

index.php
<?php include $main.".php"?>

以及開頭記得做判斷

index.php
$main = (empty($_GET['do'])) ? "main" : $_GET['do'];

後台選單的超連結簡化

在後台設計上大部分都是 do=admin&redo=XX。順手將 redo 拿掉只留一個變數就好。

修改 admin.php

admin.php
<div class="ct a rb" style="position:relative; width:101.5%; left:-1%; padding:3px; top:-9px;"> <a href="?do=admin&redo=tit">網站標題管理</a>| <a href="?do=admin&redo=go">動態文字管理</a>| <a href="?do=admin&redo=rr">預告片海報管理</a>| <a href="?do=admin&redo=vv">院線片管理</a>| <a href="?do=admin&redo=order">電影訂票管理</a> </div>

更改為

admin.php
<div class="ct a rb" style="position:relative; width:101.5%; left:-1%; padding:3px; top:-9px;">
<a href="?do=tit">網站標題管理</a> |
<a href="?do=go">動態文字管理</a> |
<a href="?do=rr">預告片海報管理</a> |
<a href="?do=vv">院線片管理</a> |
<a href="?do=orderlist">電影訂票管理</a>
</div>

後台選單的內容切換

抽取後台選單對應的主內容,拿來做對應的分割區域。並另存為 admain.php,連結回 admin 首頁

修改 admin.php

將下面代抽出來另存為admain.php

admain.php
<h2 class="ct">請選擇所需功能</h2>

改為

index.php
<?php include $admain . ".php" ?>

後台管理也有自己的選單內容,所以我們要做個選單內容服務。寫入到最上面的 php

index.php
$admain=(empty($_GET['do']))?"admain":$_GET['do'];

判斷是否登入

如果沒有偵測到 SESSION[‘admin’] 存在,就踢到前台的登入畫面。

增添 admin.php

在頁首處增加以下代碼

admin.php
if (empty($_SESSION['admin'])) plo("index.php?do=login");

建立 login.php

設計 login 表單並提交到 api.php,同時順便設計之後有登入過就直接轉回 admin.php 不用到登入面

login.php
<form action="api.php?do=login" method="post">
帳號:<input type="text" name="acc" id=""><br><br>
密碼:<input type="text" name="pwd" id=""><br><br>
<input type="submit" value="送出">
</form>

建立 api.php

規劃 switch,並開始做 login 的提交處理

api.php
<?php
include "lib.php";
switch ($_GET['do']) {
case 'login':
if ($_POST['acc'] == "admin" && $_POST['pwd'] == "1234") {
$_SESSION['admin'] = true;
plo("admin.php");
} else echo "<script>alert('輸入錯誤');window.history.back()</script>";
break;
}
?>

題目沒要求,這裡不一定需要設計登出功能,因為前後台都能同存操作。

No.5 後台之預告片海報管理 (25%)

跟第四題同一組,這裡先做第五題的後台新增修改刪除,最後才再回設計第四題之前台設計。

  • 這題先做出大概版型 -> 做好新增 -> 修改刪除 -> 前台顯示
  • 所有的 form 都提交到 api 處理

q3t5

規劃版型

我們先設計列表,同時先預訂進行以下設計:

  • 所有的異動處理,直接大表單一併提交到 api.php?do=rrmdy 進行資料處理
  • 資料顯示部分使用 input:checkbox[name=dpy[ID]],value 為 0 與 1(先全部為 0,需要的靠覆蓋特性為 1)
  • 資料刪除部分使用 input:checkbox[name=del[]],value 為 ID
  • 沒有內容修改要求,唯一修改的是資料排序,為了減省時間使用數字做處理, input[name=odr[ID]],value 為排序值

建立 rr.php

rr.php
<h3 class="ct">預告片清單</h3>
<form action="api.php?do=rrmdy" method="post" class="ct">
<table width="100%">
<tr>
<td>預告片海報</td>
<td>預告片片名</td>
<td>播放順序</td>
<td>操作</td>
</tr>
<?php
$re = select("q3t5_img", "1 order by odr");
foreach ($re as $ro) {
?>
<tr>
<td><img width=100 src="img/<?= $ro['img'] ?>" alt=""></td>
<td><?= $ro['text'] ?></td>
<td><input type="text" name="odr[<?= $ro['id'] ?>]" value="<?= $ro['odr'] ?>"></td>
<td>
<input type="hidden" name="dpy[<?= $ro['id'] ?>]" value=0>
<input type="checkbox" name="dpy[<?= $ro['id'] ?>]" value="1" <?= ($ro['dpy']) ? "checked" : "" ?>>顯示
<input type="checkbox" name="del[]" value="<?= $ro['id'] ?>">刪除
</td>
</tr>
<?php
}
?>
</table>
<div class="ct"><input type="submit" value="編輯"></div>
</form>

規劃新增功能

  • 參考示意圖,在版面最底下另外獨立表單且彼此用 hr 分開,我們先做新增方便之後的修改刪除測試。
  • 注意 form 需要宣告 enctpye。並提交到 api.php?do=rradd 處理
  • 新增時沒有指定 odr 值,預設將會是 0。而 dpy 值亦同。

增添 rr.php

rr.php
<hr>
<h3 class="ct">新增預告片</h3>
<form action="api.php?do=rradd" method="post" enctype="multipart/form-data" class="ct">
預告片海報<input type="file" name="img" id=""> 預告片片名<input type="text" name="text" id=""><br><br>
<input type="submit" value="新增">
</form>

增添 api.php

api.php
case 'rradd':
$_POST['img'] = addfile($_FILES['img']);
insert($_POST, "q3t5_img");
plo("admin.php?do=rr");
break;

試著增添幾筆,檢查 sql 以及 img 資料夾有無新成功。

做修改刪除

題目要求很簡單只有新增刪除而已。且修改只要求顯示與排序。為了考試節省時間,用 Input 數字來處理排序就好。在版型設計時已完成,這裡接著處理提交行為:

增添 api.php

api.php
case 'rrmdy':
update($_POST, "q3t5_img");
delete($_POST, "q3t5_img");
plo("admin.php?do=rr");
break;

轉場特效選項

題目還要求要給前端的轉場特效,參考示意圖可跟之前的 form 表單做在一起,在 from 與 table 標籤之間加入一個 select 表單。

增添 rr.php

rr.php
<form action="api.php?do=rrmdy" method="post" class="ct">
<select name="eft">
<?php
$re = select("q3t5_effect", 1);
$ro = $re[0];
?>
<option value="1" <?= ($ro['once'] == 1) ? "selected" : "" ?>>淡入</option>
<option value="2" <?= ($ro['once'] == 2) ? "selected" : "" ?>>縮放</option>
<option value="3" <?= ($ro['once'] == 3) ? "selected" : "" ?>>移出</option>
</select>
<hr>
<table>

修改 api.php

到剛剛的 api.php 添加調整一下。

  • 將 once 這個欄位抽取出來另存為 $post 陣列進行 update 到 q3t5_effect
  • 舊的陣列可清可不清除,不存在的 field 被 update 到 q3t5_img 並不會被受理。
  • 此外這裡的陣列規劃 $post['field name']['num id']=data value 符合函式結構進行處理
api.php
case 'rrmdy':
$gg['once'][1] = $_POST['eft'];
update($gg, "q3t5_effect");
update($_POST, "q3t5_img");
delete($_POST, "q3t5_img");
plo("admin.php?do=rr");
break;

先處理資料庫的 CRUD 四部曲為止,實際的 effect 設計在接下來的前台著手設計。

No.4 前台之預告片海報導覽 (30%)

做好第五題時已經擁有一些資料。便可以開始設計前台。需要一些 css animate 以及第一題的按鈕互動。

q3t4

按鈕列設計

第五題完成後才處理第四題關於前台的 slider 素材,可以去偷取第一題的 img 箭頭以及 JS 來改寫。箭頭利用 windows 檔案總管右鍵快速旋轉並用小畫家儲存為 left.jpg 跟 right.jpg。將圖片放到 img 內待用。

從 web01 取得的 JavaScript 為

var nowpage=0,num=0;
function pp(x)
{
var s,t;
if(x==1&&nowpage-1>=0)
{nowpage--;}
if(x==2&&(nowpage+1)*3<=num*1+3)
{nowpage++;}
$(".im").hide()
for(s=0;s<=2;s++)
{
t=s*1+nowpage*1;
$("#ssaa"+t).show()
}
pp(1)

已知的關鍵是

  1. .im 會自隱藏,#ssaa 會自顯示
  2. nowpage 是初始狀態,num 是總圖數
  3. pp(1) 跟 pp(2) 分別是方向鍵
  4. if(x==2&&(nowpage+1)3<=num1+3) 算式有誤,要調整。

修改 main.php

多利用 chrome 慢慢調整 style,開始設計版型位於

main.php
<ul class="controls">
</ul>

設計為(條件有顯示與排序大小)

main.php
<ul class="controls" style="height:100px">
<img src="img/left.jpg" style="padding:40px 0" onclick="pp(1)">
<?php
$re = select("q3t5_img", "dpy=1 order by odr");
$num = count($re);
foreach ($re as $key => $ro)
echo '<img class="im" id="ssaa' . $key . '" onclick="ani(' . $key . ')" style="height:100%" src="img/' . $ro['img'] . '" alt="' . $ro['text'] . '">';
?>
<img src="img/right.jpg" style="padding:40px 0" onclick="pp(2)" >
</ul>

目前為全顯示出來且溢位,需要透過以持有的 JavaScript 素材進行指定四張顯示以及左右按鈕的切換:

  1. 這裡需要偷塞個文字標題到 alt 內,方便之後 jQuery 時抓取為標題區。
  2. 同時預留 img 的 onclick=ani 帶參數,做之後點選時的 JavaScript 動作
  3. 讓點選左右鍵可以正常反應
  4. num 總數可透過前面 PHP 算過的$num 來用

加入 JavaScript:

main.php
<script>
var nowpage = 0, num = <?= $num ?>;
function pp(x) {
var s, t;
if (x == 1 && nowpage - 1 >= 0) nowpage--;
if (x == 2 && (nowpage + 1) <= num - 4) nowpage++;
$(".im").hide();
for (s = 0; s <= 3; s++) {
t = s * 1 + nowpage * 1;
$("#ssaa" + t).show()
}
}
pp(); //先跑一遍 hide 與 show,x 值沒有意義
</script>

海報展示區

繼續設計海報主題區域。試著任意一張假圖片與標題文字為版型的調整試作。多利用 chrome 慢慢調整 style,開始設計版型。同時多了 flex 容器方便做效果使用。

修改 main.php

main.php
<ul class="lists">
</ul>

更改為

main.php
<div style="display:flex;justify-content:center;height:300px">
<ul class="lists" style="transform:scale(1); transition:transform 0.5s;">
<img id=simg src="img/03A07.jpg" style="height:90%;width:auto">
<div id=stxt class=ct>1234</div>
</ul>
</div>

點選播放

點選過後的 JavaScript 處理動作為:

  1. 取得新替換的文字與圖片
  2. 根據特效設定決定不同的效果轉場,先轉出,替換,再轉入
  3. 取得目前替換的 ID 為何,之後讓自動播放可以知道下一張該換誰

修改 main.php

main.php
function ani(id) {
img = $("#ssaa" + id).attr("src");
txt = $("#ssaa" + id).attr("alt");
<?php //t5
$re = select("q3t5_effect", 1);
$eft = $re[0]['once'];
// $eft = 1;
?>
switch (<?= $eft ?>) {
case 1:
$(".lists").fadeToggle(() => {
$("#simg").attr("src", img);
$("#stxt").text(txt);
$(".lists").fadeToggle();
});
break;
case 2:
// animate 不支援使用 transform: "scale(0)",改為增添 style 並持有轉場動畫並配合時間回歸
$(".lists").css('transform', 'scale(0)');
setTimeout(() => {
$("#simg").attr("src", img);
$("#stxt").text(txt);
$(".lists").css('transform', 'scale(1)');
}, 500);
break;
case 3:
$(".lists").animate({
left: "-400px"
}, () => {
$(".lists").css("left", "400px");
$("#simg").attr("src", img);
$("#stxt").text(txt);
$(".lists").animate({
left: "0"
});
});
break;
}
run = id;
}

自動播放

當點選效果都能正常動畫時,設計一個自動會去執行 ani(參數),最後一張的 ID 最大是多少記得回到第一張輪播

修改 main.php

main.php
function auto() { //run=0~5,num=6
run = (run == (num - 1)) ? 0 : run + 1;
ani(run);
}
setInterval(auto, 3000);
ani(0);

ani(0) 是讓畫面載入時先跑第一張

以下為 main.php 完整代碼

main.php
<div class="half" style="vertical-align:top;">
<h1>預告片介紹</h1>
<div class="rb tab" style="width:95%;">
<div id="abgne-block-20111227">
<div style="display:flex;justify-content:center;height:300px">
<ul class="lists" style="transform:scale(1); transition:transform 0.5s;">
<img id=simg src="img/03A07.jpg" style="height:90%;width:auto">
<div id=stxt class=ct>1234</div>
</ul>
</div>
<ul class="controls" style="height:100px">

<img src="img/left.jpg" style="padding:40px 0" onclick="pp(1)">
<?php
$re = select("q3t5_img", "dpy=1 order by odr");
$num = count($re);
foreach ($re as $key => $ro)
echo '<img class="im" id="ssaa' . $key . '" onclick="ani(' . $key . ')" style="height:100%" src="img/' . $ro['img'] . '" alt="' . $ro['text'] . '">';
?>
<img src="img/right.jpg" style="padding:40px 0" onclick="pp(2)">

</ul>
<script>
//for control start
var nowpage = 0,
num = <?= $num ?>;

function pp(x) {
var s, t;
if (x == 1 && nowpage - 1 >= 0) nowpage--;
if (x == 2 && (nowpage + 1) <= num - 4) nowpage++;
$(".im").hide();
for (s = 0; s <= 3; s++) {
t = s * 1 + nowpage * 1;
$("#ssaa" + t).show()
}
}
pp(); //先跑一遍 hide 與 show,x 值沒有意義

//onclick to change list content
function ani(id) {
img = $("#ssaa" + id).attr("src");
txt = $("#ssaa" + id).attr("alt");
<?php //t5
$re = select("q3t5_effect", 1);
$eft = $re[0]['once'];
// $eft = 1;
?>
switch (<?= $eft ?>) {
case 1:
$(".lists").fadeToggle(() => {
$("#simg").attr("src", img);
$("#stxt").text(txt);
$(".lists").fadeToggle();
});
break;
case 2:
// animate 不支援使用 transform: "scale(0)",改為增添 style 並持有轉場動畫並配合時間回歸
$(".lists").css('transform', 'scale(0)');
setTimeout(() => {
$("#simg").attr("src", img);
$("#stxt").text(txt);
$(".lists").css('transform', 'scale(1)');
}, 500);
break;
case 3:
$(".lists").animate({
left: "-400px"
}, () => {
$(".lists").css("left", "400px");
$("#simg").attr("src", img);
$("#stxt").text(txt);
$(".lists").animate({
left: "0"
});
});
break;
}
run = id;
}

// auto run change list
function auto() { //run=0~5,num=6
run = (run == (num - 1)) ? 0 : run + 1;
ani(run);
}
setInterval(auto, 3000);
ani(0);
</script>
</div>
</div>
</div>
<div class="half">
<h1>院線片清單</h1>
<div class="rb tab" style="width:95%;">
<table>
<tbody>
<tr> </tr>
</tbody>
</table>
<div class="ct"> </div>
</div>
</div>

No.7 後台院線片清單管理 (25%)

版型可從第五題開始複製調整,步驟應先設計版型、新增、修改刪除、單獨修改。因版型來自複製修改,程度夠可以連同版型一口氣弄好修改刪除功能之初階段,之後可新增時再做驗證測試。

q2t7

顯示+修改+排序+刪除的版型

跟第五題不同的是欄位較多,版型不用太配合,只要該顯示資訊該有功能使用即可。

  1. 新增電影的連接按鈕放到上面,帶到 do=vvadd 之頁面
  2. 單修改的連結按鈕到 api.php?do=vvchg 之處理
  3. 單一刪除的連結則是 vvdel,利用 GET 抓 ID
  4. 批次修改排序的連結則是 vvmdy
  5. 因 update 會拆成一筆筆,所以每一個欄位都需要利用格數當作 id 索引。
  6. 排序效果跟第五題一樣,透過數字來控制就好。
  7. 影片分級的圖片記得命名為 1.2.3.4(跟資料庫內的命名相同)

建立 vv.php(參考 rr.php)

vv.php
<h3 class="ct">電影清單</h3>
<input type="button" value="新增電影" onclick="<?= jlo("?do=vvadd") ?>">
<hr>
<form action="api.php?do=vvmdy" method="post" class="ct">
<table width=100%>
<?php
$re = select("q3t7_movie", "1 order by odr");
foreach ($re as $ro) {
?>
<tr>
<td rowspan=3><img width=100 src="img/<?= $ro['img'] ?>" alt=""></td>
<td rowspan=3 valign="center">分級:<img src="img/<?= $ro['cls'] ?>.png" alt=""></td>
<td>
片名:<?= $ro['title'] ?>
   片長:<?= $ro['length'] ?>
   上映日期:<?= $ro['date'] ?>
</td>
</tr>
<tr>
<td>
排序:<input type="text" name="odr[<?= $ro['id'] ?>]" value="<?= $ro['odr'] ?>">
<input type="button" value="編輯電影" onclick="<?= jlo("?do=vvchg&id=" . $ro['id']) ?>">
<input type="button" value="刪除電影" onclick="<?= jlo("api.php?do=vvdel&id=" . $ro['id']) ?>">
</td>
</tr>
<tr>
<td>劇情介紹:<?= $ro['text'] ?></td>
</tr>
<tr>
<td colspan=3>
<hr>
</td>
</tr>
<?php
}
?>
</table>
<div class="ct"><input type="submit" value="編輯排序"></div>
</form>

修改排序與單一刪除處理

修改排序直接丟函式就好,反而刪除部分要利用 GET 產生一個陣列處理刪除部分

增建 api.php

api.php
case 'vvmdy':
update($_POST, "q3t7_movie");
plo("admin.php?do=vv");
break;
case 'vvdel':
$_POST['del'][] = $_GET['id'];
delete($_POST, "q3t7_movie");
plo("admin.php?do=vv");
break;

新增單筆電影

欄位較多,求快可以直接 br 處理而不用 table。日期依題目要求分三欄。之後提交 api 再另行合併。

建立 vvadd.php

vvadd.php
<form action="api.php?do=vvadd" method="post" enctype="multipart/form-data">
影片資料
<hr>
片名:<input type="text" name="title" id=""><br><br>
分級:
<select name="cls" id="">
<option value="1">普遍級</option>
<option value="2">保護級</option>
<option value="3">輔導級</option>
<option value="4">限制級</option>
</select><br><br>
片長:<input type="text" name="length" id=""><br><br>
上映日期:
<select name="yy" id="">
<option value="">西元年</option>
<?php for ($i = date("Y"); $i < date("Y") + 2; $i++) echo '<option value="' . $i . '">' . $i . '</option>'; ?>
</select>
<select name="mm" id="">
<option value="">月份</option>
<?php for ($i = 1; $i < 13; $i++) echo '<option value="' . $i . '">' . $i . '</option>'; ?>
</select>
<select name="dd" id="">
<option value="">日期</option>
<?php for ($i = 1; $i < 32; $i++) echo '<option value="' . $i . '">' . $i . '</option>'; ?>
</select><br><br>
發行商:<input type="text" name="corp" id=""><br><br>
導演:<input type="text" name="corp" id=""><br><br>
預告影片:<input type="file" name="video" id=""><br><br>
電影海報:<input type="file" name="img" id=""><br><br>
劇情簡介
<hr>
<textarea name="text" id="" cols="30" rows="10"></textarea><br><br>
<input type="submit" value="新增">
</form>

增添 api.php

日期需要合併成一個 POST 欄位方便且合併完後要清除掉,insert 才能與 SQL 對應作業。檔案都需要拆開,一次只能丟一筆到 addfile() 並取得黨名。所以有的檔案都會被放置到 upload 且已被更名。

api.php
case 'vvadd':
$_POST['img'] = addfile($_FILES['img']);
$_POST['video'] = addfile($_FILES['video']);
$_POST['date'] = $_POST['yy'] . "-" . $_POST['mm'] . "-" . $_POST['dd'];
unset($_POST['yy'], $_POST['mm'], $_POST['dd']);
insert($_POST, "q3t7_movie");
plo("admin.php?do=vv");
break;

修改單筆電影

兩者欄位與版型相同,建議求快就不需帶預設值。時間投資太大除了每個欄位都要設定舊值 value,select 也要判斷 selected 處,檔案上傳也是要在後端處理判斷是否有上傳,有才進行 file copy & update。建議直接就題目動作 提供修改功能進行敷衍(才五分)。

新增 vvchg.php(參考 vvadd.php)

vvchg.php
<h3 class="ct">修改電影資料</h3>
<form action="api.php?do=vvchg&id=<?= $_GET['id'] ?>" method="post" enctype="multipart/form-data">
影片資料
<hr>
片名:<input type="text" name="title[<?= $_GET['id'] ?>]" id=""><br><br>
分級:
<select name="cls[<?= $_GET['id'] ?>]" id="">
<option value="1">普遍級</option>
<option value="2">保護級</option>
<option value="3">輔導級</option>
<option value="4">限制級</option>
</select><br><br>
片長:<input type="text" name="length[<?= $_GET['id'] ?>]" id=""><br><br>
上映日期:
<select name="yy" id="">
<option value=""></option>
<?php for ($i = date("Y"); $i < date("Y") + 2; $i++) echo '<option value="' . $i . '">' . $i . '</option>'; ?>
</select>
<select name="mm" id="">
<option value=""></option>
<?php for ($i = 1; $i < 13; $i++) echo '<option value="' . $i . '">' . $i . '</option>'; ?>
</select>
<select name="dd" id="">
<option value=""></option>
<?php for ($i = 1; $i < 32; $i++) echo '<option value="' . $i . '">' . $i . '</option>'; ?>
</select><br><br>
發行商:<input type="text" name="corp[<?= $_GET['id'] ?>]" id=""><br><br>
導演:<input type="text" name="corp[<?= $_GET['id'] ?>]" id=""><br><br>
預告影片:<input type="file" name="video" id=""><br><br>
電影海報:<input type="file" name="img" id=""><br><br>
劇情簡介
<hr>
<textarea name="text[<?= $_GET['id'] ?>]" id="" cols="30" rows="10"></textarea><br><br>
<input type="submit" value="修改">
</form>

增添 api.php

不考慮是否有抓到檔案,都直接做更新,沒有輸入或檔案就是會變空的內容。

api.php
case 'vvchg':
$_POST['img'][$_GET['id']] = addfile($_FILES['img']);
$_POST['video'][$_GET['id']] = addfile($_FILES['video']);
$_POST['date'][$_GET['id']] = $_POST['yy'] . "-" . $_POST['mm'] . "-" . $_POST['dd'];
unset($_POST['yy'], $_POST['mm'], $_POST['dd']);
update($_POST, "q3t7_movie");
plo("admin.php?do=vv");
break;

No.6 院線片清單 (40%)

做好第七題,你已經擁有一些資料。便可以開始設計前台。

q3t6

設計院線片顯示區域

一開始需要設定一個有效時間差異三天(含當天),所以是今天,昨天,前天的上映日期為有效。則就是今天日期減兩天等於前天。設定好此時間差異做之後的判斷

增添 lib.php

lib.php
//t6
$minday=date("Y-m-d",strtotime("-2days"));
$today=date("Y-m-d");

修改 main.php

預設給的寫入位置<tr></tr>,在內部建立四組 td。透過 td 指定寬度並設定 float:left,能製造出 2X2 的排版效果。先以假資訊模擬出適合的版型。示意圖的設計不符合比例,不用特別雷同只要有題目動作的操作與文字項目即可。

main.php
<div class="half">
<h1>院線片清單</h1>
<div class="rb tab" style="width:95%;">
<table width="100%" style="font-size:0.8rem">
<tr>
<td width=210 style="float:left;padding:20px 0">
<img src="img/03B01.png" style="float:left;width:50px;padding:10px">
AAA<br>
分級:<img src="img/1.png" style="height:1em"><br>
上映日期:2020-05-22<br>
<div style="clear:both;text-align:center">
<input type="button" value="劇情簡介" onclick="<?= jlo("?do=info&id=x") ?>">
<input type="button" value="線上訂票" onclick="<?= jlo("order.php?do=step1&id=x") ?>">
</div>
</td>
<td width=210 style="float:left;padding:20px 0">
<img src="img/03B01.png" style="float:left;width:50px;padding:10px">
AAA<br>
分級:<img src="img/1.png" style="height:1em"><br>
上映日期:2020-05-22<br>
<div style="clear:both;text-align:center">
<input type="button" value="劇情簡介" onclick="<?= jlo("?do=info&id=x") ?>">
<input type="button" value="線上訂票" onclick="<?= jlo("order.php?do=step1&id=x") ?>">
</div>
</td>
<td width=210 style="float:left;padding:20px 0">
<img src="img/03B01.png" style="float:left;width:50px;padding:10px">
AAA<br>
分級:<img src="img/1.png" style="height:1em"><br>
上映日期:2020-05-22<br>
<div style="clear:both;text-align:center">
<input type="button" value="劇情簡介" onclick="<?= jlo("?do=info&id=x") ?>">
<input type="button" value="線上訂票" onclick="<?= jlo("order.php?do=step1&id=x") ?>">
</div>
</td>
<td width=210 style="float:left;padding:20px 0">
<img src="img/03B01.png" style="float:left;width:50px;padding:10px">
AAA<br>
分級:<img src="img/1.png" style="height:1em"><br>
上映日期:2019-04-21<br>
<div style="clear:both;text-align:center">
<input type="button" value="劇情簡介" onclick="<?= jlo("?do=info&id=x") ?>">
<input type="button" value="線上訂票" onclick="<?= jlo("order.php?do=step1&id=x") ?>">
</div>
</td>
</tr>
</table>
<div class="ct"> </div>
</div>
</div>

接著在前置作業進行 select limit 每次四筆。規劃迴圈並指定好超連結。並注意題目要求上映有效為三天含當日。所以需要特別去計算:期限日≦上映日期≦今天。

main.php
<div class="half">
<h1>院線片清單</h1>
<div class="rb tab" style="width:95%;">
<table width="100%" style="font-size:0.8rem">
<tr>
<?php
$nw = (empty($_GET['page'])) ? 1 : $_GET['page'];
$ba = ($nw - 1) * 4;
$re = select("q3t7_movie", "'" . $minday . "'<=date and date<='" . $today . "' order by odr limit " . $ba . ",4");
foreach ($re as $ro) {
?>
<td width=210 style="float:left;padding:20px 0">
<img src="img/<?= $ro['img'] ?>" style="float:left;width:50px;padding:10px">
<?= $ro['title'] ?><br>
分級:<img src="img/<?= $ro['cls'] ?>.png" style="height:1em"><br>
上映日期:<?= $ro['date'] ?><br>
<div style="clear:both;text-align:center">
<input type="button" value="劇情簡介" onclick="<?= jlo("?do=info&id=" . $ro['id']) ?>">
<input type="button" value="線上訂票" onclick="<?= jlo("order.php?do=step1&id=" . $ro['id']) ?>">
</div>
</td>
<?php
}
?>
</tr>
</table>
<div class="ct"> </div>
</div>
</div>

規劃分頁導覽

使用函式庫設計的 navpage(table,sql,range,page) 回傳陣列,並轉為連接網址。找到

修改 main.php

<div class="ct"> </div>

main.php
<div class="ct">
<?php
$pg = navpage("q3t7_movie", "'" . $minday . "'<=date and date<='" . $today . "' order by odr", 4, $nw);
foreach ($pg as $key => $value) echo '<a href="?page=' . $value . '">' . $key . '</a>';
?>
</div>

劇情簡介版面

素材有提供劇情簡介版面,先前被放在 order.php 內而跟 order.php 內容無關,找到以下代碼存到 info.php 內 (被 div#mm 所包覆)

新增 info.php(抽取自 order.php)

info.php
<div style="background:#FFF; width:100%; color:#333; text-align:left">
<video src="movie/03B20v.avi" width="300px" height="250px" controls="" style="float:right;"></video>
<font style="font-size:24px"> <img src="Profile page_files/03B20.png" width="200px" height="250px" style="margin:10px; float:left">
<p style="margin:3px">影片名稱 :
<input type="button" value="線上訂票" onclick="lof(&#39;?do=order&amp;id=4&#39;)" style="margin-left:50px; padding:2px 4px" class="b2_btu">
</p>
<p style="margin:3px">影片分級 : <img src="Profile page_files/03C04.png" style="display:inline-block;">限制級 </p>
<p style="margin:3px">影片片長 : 時/分</p>
<p style="margin:3px">上映日期 2014/02/14</p>
<p style="margin:3px">發行商 : </p>
<p style="margin:3px">導演 : </p>
<br>
<p style="margin:10px 3px 3px 3px; word-break:break-all"> 劇情簡介:<br>
</p>
</font>
<table width="100%" border="0">
<tbody>
<tr>
<td align="center"><input type="button" value="院線片清單" onclick="lof(&#39;?&#39;)"></td>
</tr>
</tbody>
</table>
</div>

並加入 select,調整為正確的內容顯示。ID 為透過 GET 取得該資訊。按鈕導向到 order.php?do=step1&id=xx.

info.php
<?php
$re = select("q3t7_movie", "id=" . $_GET['id']);
$ro = $re[0];
?>
<div style="background:#FFF; width:100%; color:#333; text-align:left">
<video src="img/03B20v.avi" width="300px" height="250px" controls="" style="float:right;"></video>
<font style="font-size:24px"> <img src="img/<?= $ro['img'] ?>" width="200px" height="250px" style="margin:10px; float:left">
<p style="margin:3px">影片名稱 :<?= $ro['title'] ?>
<input type="button" value="線上訂票" onclick="<?= jlo("order.php?do=step1&id=" . $_GET['id']) ?>" style="margin-left:50px; padding:2px 4px" class="b2_btu">
</p>
<p style="margin:3px">影片分級 : <img src="img/<?= $ro['cls'] ?>.png" style="display:inline-block;"></p>
<p style="margin:3px">影片片長 : <?= $ro['length'] ?></p>
<p style="margin:3px">上映日期 : <?= $ro['date'] ?></p>
<p style="margin:3px">發行商 : <?= $ro['corp'] ?></p>
<p style="margin:3px">導演 : <?= $ro['maker'] ?></p>
<br>
<p style="margin:10px 3px 3px 3px; word-break:break-all"> 劇情簡介:<br><?= $ro['text'] ?>
</p>
</font>
<table width="100%" border="0">
<tbody>
<tr>
<td align="center"><input type="button" value="院線片清單" onclick="<?= jlo('index.php') ?>"></td>
</tr>
</tbody>
</table>
</div>

導向到 Order 的畫面於第八題時設計,記住要設計會有 GET[id] 能提供給 order 做自動選取電影。第八題會有 step1,step2,step3 等不同的動作。

No.8 前台線上訂票 (35%)

題目要求有三個步驟:選取電影場次、選取座位、結果顯示。因此你會需要設計 URL 轉址參數。

  1. 電影場次的下拉選單透過 ajax api 進行查詢回傳。同時去搜索 table.seat 座位(陣列以字串儲存,取出時轉回陣列並計算列數)
  2. 選取座位有條件選擇,透過 JQ 去控制超過四筆不顯示。以及資料 select 時,有資料不提供 checkbox
  3. 結果顯示的流水號使用日期+索引組合即可,題目要求沒有很明確流水號的方式。

q3t8A
q3t8B

table.q3t8_book 的欄位只需要索引,電影 ID, 訂購日,場次,座位陣列 (string) 即可,訂購數可透過座位陣列算得。

先設計好 URL 轉址參數

之前已被抽取過主內容給 info.php,這裡直接改主內容區部分,找到

修改 order.php

order.php
<div id="mm">
<div class="tab rb" style="width:87%;">
</div>
</div>

改成

order.php
<div id="mm">
<div class="tab rb" style="width:87%;">
<?php include $main . ".php"; ?>
</div>
</div>

並在頁首 PHP 段落塞入參數

$main = (empty($_GET['do'])) ? "step1" : $_GET['do'];

STEP1 訂票選單

  1. 依據題目初始有 已知 movie id沒有選擇 兩種來源。接著每次點選需對應相對的其次欄位內容。
  2. 這裡需要 JQ 搭配 AJAX 來完成下拉選單的內值。根據前一項 select 標籤的變化去做 ajax 出後一項的內容。
  3. select 標籤的影響為 電影=> 影響有效日期(在 api.php 處理),日期=> 影響是否今日有效時段(在 JS 內提供一個參數是否為今日,在 php 內做顯示從幾筆開始輸出)
  4. 同時注意只能撈取顯示有效期限的電影。提交到 step2.php 建議採用 target=”_blank” 利於回到本頁面仍有舊選項之要求。

建立 step1.php

step1.php
<form action="?do=step2" method="post" target="_blank">
電影:<select name="mm" id="sm" onchange="gd()">
<?php
$re = select("q3t7_movie", "'" . $minday . "'<=date and date<='" . $today . "'");
foreach ($re as $ro) echo '<option value="' . $ro['title'] . '" ' . ((!empty($_GET['id']) && $_GET['id'] == $ro['id']) ? "selected" : "") . '>' . $ro['title'] . '</option>';
?>
</select>
日期:<select name="dd" id="sd" onchange="gt()">
</select>
場次:<select name="tt" id="st">
</select><br><br>
<input type="submit" value="確定"> <input type="reset" value="重置">
</form>

JS 部分,透過 AJAX 提交到 api.php 處理回傳

  1. 當選擇電影有變化時,自動呼叫 gd() 去算出有效日期的選項。
  2. 若一開始就有帶 MOVE ID 參數,也會自動去跑 getdate()
  3. 當選擇日期時,呼叫 getime() 算出時間場次。
  4. 執行 getimeg 時,當日期等於今天時,today 成立,否則為不。
  5. 最後都由 api.php 進行 SQL 分析與輸出處理。

此時 JS 規劃為

step1.php
<script>
if($("#sm").length>0) gd();
function gd(){
title=$("#sm").val();
$.post("api.php?do=gd",{title},(re)=>{
$("#sd").html(re);
gt();
});
}
function gt(){
title=$("#sm").val();
date=$("#sd").val();
$.post("api.php?do=gt",{title,date},(re)=>{
$("#st").html(re);
});
}
</script>

增添 api.php

AJAX 提交動作的處理

api.php
case 'gd':
$re = select("q3t7_movie", "title='" . $_POST['title'] . "'");
$ro = $re[0];
$num = (strtotime($ro['date']) - strtotime($minday)) / 3600 / 24; //該資料與最舊有效日相差幾天,可能值 0~2
for ($i = 0; $i <= $num; $i++)
echo '<option value="' . date("Y-m-d", strtotime("+" . $i . "days")) . '">' . date("Y-m-d", strtotime("+" . $i . "days")) . '</option>';
break;
case 'gt':
$re = select("q3t8_book", "movie='" . $_POST['title'] . "' and date='" . $_POST['date'] . "'");
$ary = array(0, 0, 0, 0, 0);
foreach ($re as $ro) $ary[$ro['time']] += count(unserialize($ro['seat'])); //收集各時段已售出之量
$now = (date("H") >= 14 && $today == $_POST['date']) ? floor(date("H") / 2 - 6) : 0; //如果今天且下午
//只有當天的可選時段會變化,可能是從 0 開始跑或從現在時間(轉成時段)開始跑
//if 現在是 pm3 -> 15/2-6=1(無條件捨去) -> se_time[1]=1600~1800
for ($i = $now; $i < 5; $i++) echo '<option value="' . $i . '">' . $seat[$i] . ' 剩餘座位 ' . (20 - $ary[$i]) . '</option>';
break;

增添 lib.php

這裡加一段座位的代碼到公用 PHP 表內,後面會重複用到

//t8
$seat[0]="14:00~16:00";
$seat[1]="16:00~18:00";
$seat[2]="18:00~20:00";
$seat[3]="20:00~22:00";
$seat[4]="22:00~24:00";

STEP2 選位功能

  1. 取得 step1.php 得來的資料進行版面規劃,並還要再包一次到 input:hidden。才能在 step3.php 真正做總資料處理。
  2. 算位置時利用迴圈去跑,同時每五筆斷行。同時負責 seat 的資料為字串化陣列,需轉回陣列格式 (unserialize)
  3. 訂單多筆有多筆不一樣的陣列。需要一個新陣列每次加入合併這些 foreachf 取的單陣列。
  4. JS 部分要記錄點選 checkbox 數量並阻止超過選擇數
  5. 最後送出到 api.php,進行 order 作業

建立 step2.php

step2.php
<form action="api.php?do=order" method="post">
<?php
$re = select("q3t8_book", "movie='" . $_POST['mm'] . "' and date='" . $_POST['dd'] . "' and time=" . $_POST['tt']);
$set = array();
foreach ($re as $row) $set = array_merge($set, unserialize($row['seat'])); //將所有該時段的多筆座位陣列都倒入到一個新陣列

for ($i = 1; $i < 21; $i++) {
if (in_array($i, $set)) echo '<img src="img/03D03.png" style="padding-right:30px">';
else echo '
<img src="img/03D02.png" alt="">
<input class="seat" type="checkbox" name="ss[]" value="' . $i . '">
';
if ($i % 5 == 0) echo '<br>';
}
?>
<hr>
<input type="hidden" name="movie" value="<?= $_POST['mm'] ?>">
<input type="hidden" name="date" value="<?= $_POST['dd'] ?>">
<input type="hidden" name="time" value="<?= $_POST['tt'] ?>">
您選擇的電影是:<?= $_POST['mm'] ?><br>
您選擇的時刻是:<?= $_POST['dd'] ?> <?= $seat[$_POST['tt']] ?><br>
您勾選了<span id=nn>0</span>張票,最多可購買 4 張票<br>
<input type="button" value="上一步" onclick="window.close()"> <input type="submit" value="確定">
</form>

JS 部分,從 0 開始數,每一次被 check 打勾時,如果還沒超過 4 就繼續數,否則把打勾取消。反之被取消打勾就記數少一

step2.php
num = 0;
$(".seat").click(function() {
if (this.checked)
(num < 4) ? num++ : this.checked = false;
else num--;
$("#nn").text(num);
});

增添 api.php

進行資料上傳,並先將 seat 陣列給字串化。這樣一筆訂單就是一筆 DATA,方便訂單管理。

api.php
case 'order':
$_POST['seat'] = serialize($_POST['ss']);
$_POST['buydate'] = date("Y-m-d");
unset($_POST['ss']);
$id = insert($_POST, "q3t8_book");
plo("order.php?do=step3&id=" . $id);
break;

STEP3 檢視訂票結果

很簡單的做撈取動作,訂單編號部分利用日期與 ID 合併即可,不需要特地在設計該 SQL 欄位。

建立 step3.php

step3.php
<?php
$re = select("q3t8_book", "id=" . $_GET['id']);
$ro = $re[0];
$seq = date("Ymd0000", strtotime($ro['buydate'])) + $ro['id'];
$ss = unserialize($ro['seat']);
?>

訂單資訊:<?= $seq ?>
<hr>
您選擇的電影是:<?= $ro['movie'] ?><br>
您選擇的時刻是:<?= $ro['date'] ?> <?= $seat[$ro['time']] ?><br>
您勾選的座位是:<br>
<?php
foreach ($ss as $value) echo $value . '號<br>';
?>

No.9 後台電影票訂單管理 (25%)

先試著在前台新增多筆訂單,接著在進行後台設計。主要重點在於刪除功能,分為單筆刪除與批次刪除。難度不高,只需記得單筆刪除直接使用 onclick 帶 GET 網址到 api 處理即可。至於批次刪除利用 form 表單搭配 input typey 到 api 處理。處理批次只需對 where 描述正確即可。

q3t9

清單檢視版型

這題不適合參考任何前面的版型,重新畫一個 table 會比較快。

建立 orderlist.php

orderlist.php
<table width="100%">
<tr>
<td>訂單編號</td>
<td>電影名稱</td>
<td>觀看日期</td>
<td>場次時間</td>
<td>訂購數量</td>
<td>訂購位置</td>
<td>操作</td>
</tr>
<?php
$re = select("q3t8_book", "1 order by id desc");
foreach ($re as $ro) {
$seq = date("Ymd0000", strtotime($ro['buydate'])) + $ro['id'];
$ss = unserialize($ro['seat']);
?>
<tr>
<td><?= $seq ?></td>
<td><?= $ro['movie'] ?></td>
<td><?= $ro['date'] ?></td>
<td><?= $seat[$ro['time']] ?></td>
<td><?= count($ss) ?></td>
<td><?php foreach ($ss as $value) echo $value . '號<br>'; ?></td>
<td><input type="button" value="刪除" onclick="<?= jlo("api.php?do=orderdel&id=" . $ro['id']) ?>"></td>
</tr>
<?php
}
?>
</table>

單獨刪除功能

取得訂單 ID 針對該訂單刪除

增添 api.php

api.php
case 'orderdel':
$_POST['del'][] = $_GET['id'];
delete($_POST, "q3t8_book");
plo("admin.php?do=orderlist");
break;

快速刪除之版型

題目要求需要快速刪除前有提示,所以 from 多個 onsubmit 的 JS 動作。radio 咬個 required 比較不會被亂搞。

修改 orderlist.php

orderlist
<h3 class="ct">訂單清單</h3>
<hr>
<form action="api.php?do=orderfast" method="post" onsubmit="return confirm('幹你確定嗎?')">
<input type="radio" name="sw" value="1" required>依日期 <input type="date" name="date">
<input type="radio" name="sw" value="2">電影名稱
<select name="movie">
<?php
$re = select("q3t7_movie", 1);
foreach ($re as $ro) echo '<option value="' . $ro['title'] . '">' . $ro['title'] . '</option>';
?>
</select>
<input type="submit" value="快速刪除">
</form>
<hr>

增添 api.php

判斷何種刪除法,做對應刪除之條件

api.php
case 'orderfast':
switch ($_POST["sw"]) {
case 1:
$post['delat'] = "date='" . $_POST['date'] . "'";
break;
case 2:
$post['delat'] = "movie='" . $_POST['movie'] . "'";
break;
}
delete($post, "q3t8_book");
plo("admin.php?do=orderlist");
break;

END 調整版面 (5%)

這題動作如果來不及做可以放棄,元素材差異性下有可能不會被考官所注意到。

q3layout

修改 index.php & admin.php & order.php

找到主區域的 div 修改為

index.php & admin.php & order.php
<div id="main" style="overflow-y: scroll;width: 1024px;height: 768px;margin: 10px auto;border: 0;">

修改 main.php

院線片清單版型有被擠壓到跑版,對 main.php 的這部分調整一下到 100%

main.php
<div class="rb tab" style="width:100%;">

修改 admin.php

雖然題目未提及,如果有空則消除無效的連結

admin.php
<div class="ct a rb" style="position:relative; width:101.5%; left:-1%; padding:3px; top:-9px;">
<a href="#">網站標題管理</a> |
<a href="#">動態文字管理</a> |
<a href="?do=rr">預告片海報管理</a> |
<a href="?do=vv">院線片管理</a> |
<a href="?do=orderlist">電影訂票管理</a>
</div>

透過 Chrome 遊覽器檢查可以得到 1024*768 且上下左右 10px 並垂直至中的動作要求。