# 飲料點餐版面(Vue最終進階版)
###### codepen在這邊:https://codepen.io/liu_0821/pen/GRBrwzW?editors=0011

## 前情提要
###### 前面的版本在這邊~~ [**版本1**](https://hackmd.io/@LindaLiu/HkTU3gSqi) [**版本2**](https://hackmd.io/@LindaLiu/ryBeOxt9i)
##### 修修改改終於來到最後一版,目前增加的內容一定會有更好的寫法(Computed),但未來的路還很長,想說目前先改這樣,等後續再來做修改d(`・∀・)b
#### 額外增加的內容
##### 1. 點選品項下方的訂單會隱藏起來~
##### 2. 個別修改訂單資料~
#### 目前先這樣~一樣下方都有註解,直接看下方程式碼瞜
## HTML
```
<div id="app">
<div class="container gx-2">
<div class="row gx-3 bg-light py-3">
<div class="col-md-4">
<div class="list-group">
<a
href="#"
class="list-group-item list-group-item-action"
@click.prevent="selectedItem(item)"
v-for="(item,key) in products"
:key="item.name"
:class="{'active':selectProduct.name === item.name}"
>
<h6 class="card-title mb-1">{{item.name}}</h6>
<div
class="d-flex align-items-center justify-content-between"
>
<p class="mb-0"><small>{{item.engName}}</small></p>
<p class="mb-0"><small>NT$ {{item.price}}</small></p>
</div>
</a>
</div>
</div>
<div class="col-md-8">
<div class="card mb-2">
<div
v-if="!selectProduct.name "
class="position-absolute text-white d-flex align-items-center justify-content-center"
style="
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.65);
z-index: 100;
"
>
請先選擇飲品
</div>
<div class="card-body px-4">
<div class="mb-3">
<label for="productNum" class="form-label">數量</label>
<input
type="number"
class="form-control"
id="productNum"
placeholder="數量"
min="1"
v-model="selectProduct.count"
/>
</div>
<div class="mb-3">
<label for="productNum" class="form-label d-block"
>冰塊*</label
>
<div
class="form-check form-check-inline"
v-for="(item,key) in iceType"
:key="'ice'+ key"
>
<input
class="form-check-input"
name="iceType"
type="radio"
:value="item"
:id="'ice'+ key"
v-model="selectProduct.ice"
:disabled="!selectProduct.hasOwnProperty('defaults') || (selectProduct.defaults.ice !== '' && selectProduct.defaults.ice !== item)"
/>
<!--hasOwnProperty 測試屬性是否存在-->
<label class="form-check-label" :for="'ice'+ key"
>{{item}}</label
>
</div>
</div>
<div class="mb-3">
<label for="productNum" class="form-label d-block"
>甜度*</label
>
<div
class="form-check form-check-inline"
v-for="(item,key) in sugarType"
:key="'sugar'+ key"
>
<input
class="form-check-input"
name="sugarType"
type="radio"
:id="'sugar'+ key"
:value="item"
v-model="selectProduct.sugar"
:disabled="!selectProduct.hasOwnProperty('defaults') || (selectProduct.defaults.sugar !== '' && selectProduct.defaults.sugar !== item)"
/>
<label class="form-check-label" :for="'sugar'+ key"
>{{item}}</label
>
</div>
</div>
<div class="mb-3">
<label for="productNum" class="form-label d-block"
>加料</label
>
<div
class="form-check form-check-inline"
v-for="(item,key) in toppingsType"
:key="'topping'+key"
>
<input
class="form-check-input"
type="checkbox"
:id="'topping'+key"
:value="item"
v-model="selectProduct.topping"
:disabled="!selectProduct.hasOwnProperty('defaults') || selectProduct.defaults.toppings.includes(item)"
/>
<label class="form-check-label" :for="'topping'+key"
>{{item}}</label
>
</div>
</div>
<div class="mb-3">
<label for="productNotice" class="form-label"
>備註</label
>
<textarea
class="form-control"
id="productNotice"
rows="2"
v-model="selectProduct.text"
></textarea>
</div>
<div class="d-flex gap-2">
<button
class="btn btn-outline-primary w-100"
type="button"
>
取消
</button>
<button
class="btn btn-primary w-100"
@click.prevent="addToShoppingCart(selectProduct)"
type="button"
>
加入
</button>
</div>
</div>
</div>
<div class="card">
<div class="card-body">
<table class="table">
<thead>
<tr>
<th scope="col">品項</th>
<th scope="col">冰塊</th>
<th scope="col">甜度</th>
<th scope="col">加料</th>
<th scope="col">單價</th>
<th scope="col">數量</th>
<th scope="col">小計</th>
<th scope="col">修改</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="(item,key) in orderList" :key="'data'+key">
<th scope="row">
{{item.name}}<br />
<small class="text-muted fw-normal"
>備註:{{item.text}}</small
>
</th>
<td>{{item.ice}}</td>
<td>{{item.sugar}}</td>
<td>{{item.topping.toString()}}</td>
<td>{{item.calculatePrice}}</td>
<td>{{item.count}}</td>
<td>{{item.calculatePrice*item.count}}</td>
<td class="text-end">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="currentColor"
class="bi bi-pencil-square editIcon"
viewBox="0 0 16 16"
@click.prevent="editOrder(item)"
>
<path
d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z"
/>
<path
fill-rule="evenodd"
d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5v11z"
/>
</svg>
</td>
<td class="text-end">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="currentColor"
class="bi bi-x delIcon"
viewBox="0 0 16 16"
@click.prevent="deleteOrder(item)"
>
<path
d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"
/>
</svg>
</td>
</tr>
</tbody>
</table>
<p class="text-end">共 NT$ {{totalPrice}} 元</p>
<div class="d-flex gap-2">
<button
class="btn btn-sm btn-outline-secondary w-100"
@click.prevent="clearOrder"
>
清空購物車
</button>
<button
class="btn btn-sm btn-secondary w-100"
@click.prevent="outputOrder(orderList,totalPrice)"
:disabled="orderList.length === 0"
>
產生訂單
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="bg-light p-3 mt-3"
v-if="checkedOrder.orders.length >0 "
>
<div
class="bg-white p-3 d-flex flex-column"
style="min-height: 450px"
>
<table class="table">
<thead>
<tr>
<th scope="col">品項</th>
<th scope="col">冰塊</th>
<th scope="col">甜度</th>
<th scope="col">加料</th>
<th scope="col">單價</th>
<th scope="col">數量</th>
<th scope="col">小計</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,id) in checkedOrder.orders" :key="'id'+id">
<th scope="row">
{{item.name}}<br />
<small class="text-muted fw-normal"
>備註:{{item.text}}</small
>
</th>
<td>{{item.ice}}</td>
<td>{{item.sugar}}</td>
<td>{{item.topping.toString()}}</td>
<td>{{item.calculatePrice}}</td>
<td>{{item.count}}</td>
<td class="text-end">{{item.calculatePrice*item.count}}</td>
</tr>
</tbody>
</table>
<p class="mt-3 mb-1">訂單成立時間:{{checkedOrder.date}}</p>
<p class="mb-1">餐點數: {{checkedOrder.orderCount}}</p>
<p class="mb-1">付款狀態:未付款</p>
<p class="text-end mt-auto">
共 NT$ {{checkedOrder.checkOrderPrice}} 元
</p>
</div>
</div>
</div>
```
## JS(Vue)
###### 這邊避免太長太拖(? 直接放上我有改的部分 (。◕∀◕。)
> `selectProduct` 放被選擇的項目
`orderList` 購物車
`totalPrice` 總價
`checkedOrder` 結帳
`calculatePrice` 計算金額
**data的部分**
```
// 在原本的資料結構上有更動
selectProduct: {
id: "", -> 判斷修改還是新增的依據
calculatePrice:0, -> 計算小計
},
orderList: [],
checkedOrder: {
orders: [],
date: "",
orderCount: 1,
checkOrderPrice: "",
}
```
**計算價格**
```
addToShoppingCart(selectProduct) {
/* 把小計的部份另外拉出來算 */
this.selectProduct.calculatePrice =
this.selectProduct.price + this.selectProduct.topping.length * 10;
if (!this.selectProduct.id) {
this.selectProduct.id = new Date().getTime();
const order = {
...selectProduct,
total:0 -> 預設
};
this.orderList.push(order);
} else {
this.orderList.map((item, i) => {
if (item.id === this.selectProduct.id) {
this.orderList[i] = this.selectProduct;
}
});
}
this.countTotal();
this.resetOrder(); // 加入購物車後清空
}
```
```
countTotal() {
this.totalPrice = 0;
this.orderList.forEach((item) => {
// 計算整筆訂單的總價格(暴力拆解?)
this.totalPrice += (item.price + item.topping.length*10)*item.count;
});
},
```
## 後續補充
##### 有發現一些小問題有在做重新調整,以及有一些建議把它紀錄下來
* ##### 更新訂單`outputOrder()`時建議如下的寫法,除了更為精簡,其次是創造一筆全新的資料保持資料不變 (immutable) (這就比較偏架構程式的方法,並沒有對錯)。
##### 補充資料:
##### [前端的 immutable 設計樣式](https://blog.yyisyou.tw/c30df041/)
---
#### ヽ(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人(゚∀゚)人( ゚∀)ノヽ(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人(゚∀゚)人( ゚∀)人
##### 以上 如果註解哪裡有錯誤或有問題,歡迎提出來一起討論~~~~