此階段是實際串接 API 的差異,串接 API 後的一頁式產品新增、刪除、修改的頁面。
先製作登入頁驗證使用者帳號,再導入產品頁。
// 登入頁面 html
<div id="app">
<div class="container">
<form class="form-sognin" @submit.prevent="signin">
<h1 class="h3 mb-3 font-weight-normal">請先登入</h1>
<div class="form-group">
<label for="inputEmail" class="sr-only">Email</label>
<input type="email" id="inputEmail"
v-model="user.email" class="form-control"
placeholder="請輸入Email" required
autofocus>
</div>
<div class="form-group">
<label for="inputPassword" class="sr-only">Email</label>
<input type="password" id="inputPassword"
v-model="user.password" class="form-control"
placeholder="請輸入密碼"
required>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">
登入
</button>
</form>
</div>
</div>
// JS 登入驗證
new Vue({
//指定
el: '#app',
//資料
data: {
user: {
email: '',
password: '',
},
},
//方法
methods: {
//登入 , 登入AJAX後 , 把 token(代碼) 和 expired(到期時間) 存到瀏覽器 cookie , 在跳轉頁面
signin() {
const api = `https://course-ec-api.hexschool.io/api/auth/login`; //連接登入api
axios.post(api, this.user).then((response) => {
const token = response.data.token; //建立token
const expired = response.data.expired; //建立expires
//存到瀏覽器 cookie , 並把 expires 設置有效時間
document.cookie = `token=${token};expires=${new Date(expired * 1000)};path=/
`;
window.location = 'Products.html'; //執行以上程式碼後 , 跳轉到產品頁
//* 一定要包在裡面 , 放到外面一層會因為非同步原因 , 會先執行跳轉頁面
}).catch((error) => { //填寫錯誤 , 報出錯誤訊息
console.log(error);
});
},
},
})
// 登入頁面 html
<div id="app" class="container mt-3">
<div class="text-right mt-4">
<button class="btn btn-primary" @click="openModal('new')">
建立新的產品
</button>
</div>
<table class="table mt-4">
<thead>
<tr>
<th width="15%">分類</th>
<th>產品名稱</th>
<th>產品圖像</th>
<th width="10%">原價</th>
<th width="10%">售價</th>
<th width="10%">是否啟用</th>
<th width="15%">編輯</th>
</tr>
</thead>
<tbody>
<tr v-for="(item , index) in products" :key="index">
<td>{{ item.category }}</td>
<td>{{ item.title }}</td>
<td><template>
<img class="thumb-img" :src="item.imageUrl" alt="">
</template></td>
<td class="text-right">{{ item.origin_price }}</td>
<td class="text-right">{{ item.price }}</td>
<td>
<span v-if="item.enabled" class="text-success">啟用</span>
<span v-else>未啟用</span>
</td>
<td>
<div class="btn-group">
<button class="btn btn-outline-primary btn-sm mr-2"
@click="openModal('edit' , item)"
:disabled="loadingBtn === item.id">
<span class="spinner-border spinner-border-sm"
role="status" aria-hidden="true"
v-if="loadingBtn === item.id"></span>
編輯</button>
<button class="btn btn-outline-danger btn-sm"
@click="openModal('delete' , item)">刪除</button>
</div>
</td>
</tr>
</tbody>
</table>
<!--分頁-->
<pagination :pages="pagination" @update="getProducts"></pagination>
<!-- productModal -->
<div id="productModal" class="modal fade" tabindex="-1" role="dialog"
aria-labelledby="exampleModalLabel"
aria-hidden="true">
<modal :api="api" :temp-product="tempProduct" @updata="getProducts"></modal>
</div>
<!--productModal END -->
<div id="delProductModal" class="modal fade" tabindex="-1" role="dialog"
aria-labelledby="exampleModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content border-0">
<div class="modal-header bg-danger text-white">
<h5 id="exampleModalLabel" class="modal-title">
<span>刪除產品</span>
</h5>
<!-- 關閉按鈕-->
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<!--modal-header END -->
<div class="modal-body">
是否刪除 <strong class="text-danger">{{ tempProduct.title }}</strong>
商品(刪除後將無法恢復)。
</div>
<!--modal-bady END -->
<div class="modal-footer">
<button class="btn btn-outline-secondary" type="button"
data-dismiss="modal">取消</button>
<button class="btn btn-danger" type="button" @click="delProduct">
確認刪除</button>
</div>
<!--modal-footer END -->
</div>
</div>
</div>
<!--delProductModal END -->
</div>
// 產品頁JS
new Vue({
//指定
el: '#app',
//資料
data: {
products: [],
pagination: {},
tempProduct: {
imageUrl: []
},
api: {
uuid: '',
path: ''
},
token: '',
isNew: '',
loadingBtn: '',
},
//創建
created() {
//取得存在 cookie 中的 token
this.token = document.cookie.replace(/(?:(?:^|.*;\s*)token\s*\=\s*([^;]*).*$)|^.*$/, "$1");
//預設帶入 token
axios.defaults.headers.common.Authorization = `Bearer ${this.token}`;
this.getProducts();
},
//方法
methods: {
//開啟視窗
openModal(isNew, item) {
switch (isNew) {
//新增
case 'new':
this.tempProduct = { imageUrl: [] };
$('#productModal').modal('show');
break;
//編輯
case 'edit':
//讀取效果
this.loadingBtn = item.id;
//取得遠端單筆資料
const url = `${this.api.path}${this.api.uuid}/admin/ec/product/${item.id}`;
//取得遠端資料
axios.get(url).then((res) => {
this.tempProduct = res.data.data;
$('#productModal').modal('show');
this.loadingBtn = '';
});
break;
//刪除
case 'delete':
this.tempProduct = Object.assign({}, item);
$('#delProductModal').modal('show');
break;
default:
break;
}
},
//刪除資料
delProduct() {
if (this.tempProduct.id) {
const id = this.tempProduct.id;
this.products.forEach((item, i) => {
if (item.id === id) {
this.products.splice(i, 1);
this.tempProduct = {};
}
});
}
$('#delProductModal').modal('hide');
},
//取得資料
getProducts(num = 1) {
//取得遠端後台管理API
const url = `${this.api.path}${this.api.uuid}/admin/ec/products?page=${num}`;
//取得遠端資料
axios.get(url).then((res) => {
this.products = res.data.data;
this.pagination = res.data.meta.pagination;
if (this.tempProduct.id) {
this.tempProduct = {
imageUrl: [],
};
$('#productModal').modal('hide');
};
});
},
},
});