---
title: '玉山暑期實習學習紀錄'
tags: spring boot, vue.js, docker
---
玉山暑期實習紀錄
> [Github](https://github.com/mrwenwei/ESUN-Summer-Project)
## 目錄
[TOC]
## 需求分析
## 系統設計
### 開發時程
```mermaid
gantt
title 甘特圖
section 需求訪談
5days:2019-07-15, 5d
section 資料庫設計
12 days:2019-07-15 , 12d
section 後端程式設計
20 days:2019-07-22, 20d
section 前端程式設計
20 days:2019-07-29, 20d
section 文件撰寫
7 days:2019-08-18, 7d
section 測試
14 days:2019-08-18, 14d
```
## 資料庫
了解需求之後我們需要對每張單據設計一個資料庫,需要有存匯取款的所有資料,包含金額日期等等。
### ERD
初步設計出來的 ER Diagram
![](https://i.imgur.com/Nx1WOKA.png)
不過如果以這種方式建資料庫,在未來若有單據要擴充的話會很麻煩,因此學長有與我們建議使用 [CLOB](https://en.wikipedia.org/wiki/Character_large_object),後來 ERD 也簡化成如下:
![](https://i.imgur.com/RrOoq10.png)

如此一來就能在其中的一個欄位存一個 JSON,要使用時只需要 parse 過即可。
### Docker
Docker 的好處是可以將自己的 container 存成新的 image,上傳到 Docker Hub 供別人使用,所以你也可以直接使用建好資料庫的 image,不過缺點是若利用 commit 的方式更新 image ,這種方式建立的 Image 是難以重現的,比較好的方式是編寫 dockerfile,不過這個部分還在研究中因此待補上。
MSSQL 在 Docker 上的 image 安裝 (以下為 bash 指令):
1. Pull 官方的 SQL server image
```
$ sudo docker pull mcr.microsoft.com/mssql/server:2017-latest
```
2. run image 檔
<!-- 2. run image 檔,這裡要注意的點是 SQL Server 設定變更和資料庫檔案都會保存於容器中,即使使用 docker stop 和 docker start 來將容器重新啟動也一樣。不過,如果使用 docker rm 來移除容器,則會刪除容器中的所有項目,因此建議使用 [Volumn](https://docs.docker.com/storage/volumes/)(指令中 -v 的部分) -->
```
$ sudo docker run -e 'ACCEPT_EULA=Y' \
-e 'MSSQL_SA_PASSWORD=<YourStrong!Passw0rd>' \
-p 1433:1433 --name sql1
-d mcr.microsoft.com/mssql/server:2017-latest
```
ACCEPT_EULA 為授權合約需同意,密碼的長度至少必須是 8 個字元,包含下列四種集合的其中三種字元:大寫字母、小寫字母、以 10 為底數的數字,以及符號,1433 為 port,name 為容器名稱可任意定義,-d 為在背景執行。
3. 查看建立的 docker 容器
```
$ sudo docker ps -a
```
4. 執行容器(也可以下載 [Kitematic](https://kitematic.com/) 用圖形化介面操作)
```
$ sudo docker exec -it sql1 "bash"
```
5. 連線到 SQL server
```
root@xxxxxxxxx:/# /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "<YourNewStrong!Passw0rd>"
```
如果成功,畫面會長這個樣子
```
1>
```
再來就能開始操作 DB 了
6. 建立 Database
```
1> CREATE DATABASE your_db_name
1> COLLATE Chinese_PRC_CI_AS;
1> GO
```
**Docker 在使用資料庫時會發現無法插入中文資料,因此在建構資料庫時必須輸入以上指令:**
7. 而建立好 Database 的部分後可以直接從 SQLQuery 內的[資料夾](https://github.com/mrwenwei/ESUN-Summer-Project/tree/master/SQLQuery)執行 SQL 碼就行了(四個 table)。
做完以上步驟後即可在終端機中使用 SQL 指令操控資料庫,但如果你用不習慣 command line ,想要使用圖形介面這裡也介紹一個 Microsoft 推出的 [Azure Data Studio](https://docs.microsoft.com/zh-tw/sql/azure-data-studio/download?view=sql-server-2017),下載安裝好後只需要連線本地端的 SQL Server 帳密,並選擇資料庫,就可以使用像 MS SQL 那樣的圖形化介面,還有提供 notebook 的方式可以進行 Query,非常方便。
![](https://i.imgur.com/PDBmD8g.png)
## Spring Boot
### 建立專案
1. 點擊 command(ctrl)+N 找到 spring starter project,或者是使用官方網站提供的 [spring initializr](https://start.spring.io/) 下載並匯入。
![](https://i.imgur.com/Cgd4V0K.png)
2. 命名設定
![](https://i.imgur.com/YxVucnZ.png)
3. 將需要的套件加入專案,點擊 finish 完成專案建置,會自動生成 XML(專案需求需用到 web、JPA、MS SQL driver)。
![](https://i.imgur.com/m84mLWX.png)
pom.xml 內已配置好 dependency,也可以手動在這裡刪減。
![](https://i.imgur.com/2Urt7A4.png)
4. 將新增的專案新增到 server 上:右鍵點擊 wildfly server 選擇 add and remove,將專案加進 Configured,點擊 finish 即可。
![](https://i.imgur.com/iZS3T42.png)
### 專案架構
建立不同 package 來分別處理不同事情
![](https://i.imgur.com/edAMCU9.png =250x)
新增方式: 在 src/main/java 資料夾內點擊右鍵>new>package
共分為 Controller、Entity、Repository、Service 四類,以下我們以實作使用者帳戶的 table 為範例來詳細討論。
* Entity
新增方式: 在 entity 的 package 右鍵>new>class
![](https://i.imgur.com/QsiKNtK.png)
Entity 用來對應到資料庫中的 table,下圖是可看出在資料庫中有個叫 "AccountInfo" 的 table,在後端會將一個 row 當作一個這樣的物件來存取,定義好每個欄位的特性(ID、not null 等等),並定義 get/set 函式來取用或更改物件內容。
![](https://i.imgur.com/LY23mwU.png)
"@Entity" 的用途是告知 spring 這是一個 entity 的 class
這些 entity 的內容都是由 javax.persistence 提供,也就是 JPA,用來後續操控資料庫用。
* Repository
新增方式: 在 Repository 的 package 右鍵>new>class
與 DB 連接的橋樑。 DAO(Data Access Object)連接到數據庫,以在數據庫和服務層之間來回讀取和寫入數據。
JpaRepository 是 Spring 提供的 JPA library ([Doc](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/)),用法是在 Repository 裡繼承 JpaRepository 的 interface,底下也可以自己定義 function,不過 Spring 內建就有很多很好用的 function 了,如此一來不僅不需要打到 SQL 語法,也造成程式碼的整潔。
![](https://i.imgur.com/x3nuqa5.png)
* Service
新增方式:在 Service 的 package 右鍵>new>class
定義所有操作的詳細內容,像是新增、查詢、刪除、更新等等,寫出一套屬於自己的服務。
![](https://i.imgur.com/OLF2MJ4.png)
圖中的 @Autowired 是用來自動對應到別的 class 的內容,建立連結的概念,讓程式知道你是在呼叫前面定義好的 class,而這裡宣告出來的 userRepo 就可以使用 Spring data JPA 提供的 function 了,如圖中 22 行的 findAll(),其意思等同於「SELECT * from AccountInfo」。
其中 save 也是一個很好用的 function,當一個 entity 的 id 不存在 table 裡頭時,呼叫此 function 則會直接新增一個欄位,若 id 存在則是更新該欄位。
![](https://i.imgur.com/L2z8yjA.png)
* Controller
新增方式:在 Controller 的 package 右鍵>new>class
Controller 顧名思義是控制整個流程的地方
@RestController 是 @Controller 和 @ResponseBody 註釋的組合。@Controller 包含處理用戶請求的路由邏輯方法。 @ResponseBody 註釋用於提及必須通過具有 @Controller 註釋的類中定義的方法返回 http response。通過將這兩個功能組合到單個註釋中,Spring Boot 可以輕鬆實現,因此我們不會必須使用 @ResponseBody 註釋來註釋 @Controller 類的每個方法。此外,response 的返回類型默認配置為 JSON。
@RequestMapping 可以對應到前端傳送來的要求,例如圖中的 getAll() 是用 "GET/users" 標注起來(method 預設為 GET),當前端傳來 GET 要求並且網址符合就會呼叫此 function,並回傳 list of entity 到前端。
![](https://i.imgur.com/mUxZmXq.png)
到目前為止就寫出了一個符合 REST API 形式的 API,我們用 Postman 來測試看看。
![](https://i.imgur.com/mdlVWsw.png)
成功回傳 table 內的所有內容。
## Vue.js
### Vue.js 開發環境建置
#### 一、vue-cli 安裝
在開發Vue.js專案時,往往會搭配各種套件來取代重複性的人工作業,而 Vue-cli 是由 Vue 官方提供的專案樣板工具,可以快速透過指令建立出一個立即可用的開發環境。
```
$ npm install -g @vue/cli
```
#### 二、建立 Vue 專案
```
$ vue init <樣板名稱> <專案名稱>
```
(可用 $ vue list 查看官方預設樣板清單)
我們是以 webpack 樣板建立專案,如下:
```
$ vue init webpack EsunSummerProject
```
- 專案建立過程可依需求調整相關選項。
- 建議安裝 vue-router (作為路由)。
![](https://i.imgur.com/x7dUMM9.png)
- 建立完畢後,按照指示移動到專案路徑,並安裝所需模組
```
$ cd <專案資料夾>
$ npm install
```
- 啟動開發環境
```
$ npm run dev
```
- 打開瀏覽器就可以看到專案預設的畫面了
(預設是 localhost:8080)
#### 三、Visual Studio Code 安裝
https://code.visualstudio.com
VS Code是一款很好用的編輯器,除了介面好看易用之外,裡面也有許多好用的套件,這邊就不多作介紹,有興趣的人可以自行google。
#### 四、Vue.js 各種套件的安裝
如果有需要使用到套件,通常有兩種使用方式,一種是透過 npm 下載套件,另一種是直接以 CDN 網址來使用。
以Vuex套件來說,以 npm 安裝:
```
npm install vuex --save
```
以 CDN 使用直接在 script 中加入:
```javascript=
<script src="/path/to/vuex.js"></script>
```
### Vue.js 專案介紹
#### 一、專案架構
```
.
├── build // 與 webpack 相關
├── config // 與 webpack 相關
├── node_modules // node npm 模組
├── src // 主要開發環境 source code
| ├── assets // 圖片等靜態檔
| ├── router // vue 路由器
| ├── app.vue // 主要的樣板檔
| ├── main.js // 主要的 js 檔,套件 import 的入口文件
| └── components // vue 元件檔
├── static // 放置第三方 plugin 位置
├── index.html // 靜態 html檔
├── package.json
└── package-lock.json
```
#### 二、專案的起點
Vue.js 是個專注在視圖層 (View) 的框架,它不僅易於上手,還便於與第三方套件或既有專案整合。
- 一個頁面中的各個部分可以自行決定各自獨立運作或是相連。
![](https://i.imgur.com/GkGSoZz.png)
- 我們先來看 main.js 這個檔案,它是整個 Vue 專案的最源頭,裡面引入了 Vue 並創建了 Vue 實例,這個 Vue 實例有一個引入的 components: App。 這個App就是 components資料夾中的 App.vue 檔案,會有 .vue 這個副檔名是因為專案中有使用 webpack, webpack有一個套件 vue-loader 能夠將 .vue 檔解析成 js。
```javascript=
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>',
data: {
bgimg1: "../static/bgimg1.jpg"
}
})
```
- 以我們的這個專案來說,在 index.html 檔案的內容如下,可以看到上面Vue實例中註冊的 App.vue ,因此網頁一打開就會載入 App.vue 的內容。
```htmlmixed=
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>esp-front-end</title>
</head>
<body>
<!-- App.vue -->
<App></App>
</body>
</html>
```
### Vue.js 基本應用
Vue.js的官方文件有中文版,內容也很豐富,可以先從官方文件開始學習。
https://cn.vuejs.org/v2/guide/index.html
#### 一、利用 data 與 v-model 達到資料的雙向綁定
- data 用來儲存 vue 元件內部狀態或資料,並與 v-model 合作實現資料的雙向綁定。以下以本專案的匯款表單來說明:
![](https://i.imgur.com/uQAUcFg.png)
- 由於合計的部分顯示出來的資料是依據使用者輸入的資料來改變,因此我們以 mastache 語法 (雙大括號)來與 data 中的值綁定,當 data 中的 totalAmount 一改變,網頁顯示出來的合計值也會馬上更新。
```htmlmixed=
<!-- template -->
<div class="col-1">
<label>合計</label>
</div>
<div class="col-2">
<!-- 以 mastache 與 data中的 totalAmount 綁定 -->
<label>{{transferForm.totalAmount}}</label>
</div>
```
- data 中的 totalAmount 預設為0,當他被計算出來後,數值會同步更新到畫面上。
```javascript=
// script
export default {
data() {
return {
transferForm: {
//與 totalAmount 綁定
totalAmount: "0"
}
};
},
}
```
- 上述的 mastache 用法通常用來實現資料的單向流動,而 v-model 則是實現雙向綁定用的,常用在表單元件上,像是 input 、 select 和 textarea 等。以下以本專案的匯款表單來做說明:
![](https://i.imgur.com/dVTUPfY.png)
- 我們希望在使用者填寫表單後,輸入的內容可以同步更新在 data 中,因此使用了 v-model ,這樣的用法是雙向的,也就是不管是 html 中的表單元素,還是 javascript 中的 data,只要任一邊改變,另一邊都會同步改變。
```htmlmixed=
<!-- template -->
<div class="col-2">
<label for="transactAmount">匯款金額(新台幣)</label>
</div>
<div class="col-4">
<input
type="text"
class="form-control"
id="transactAmount"
placeholder="請輸入金額"
@input="transferFeeCounter()"
v-model="transferForm.transactAmount"
required
/>
</div>
```
```javascript=
//script
export default {
data() {
return {
transferForm: {
//預設值是0,當表單被使用者輸入,此處的內容會同步改變
transactAmount: "0",
}
};
},
}
```
#### 二、事件處理 (Event Handling) 與 Methods
- 為了能讓使用者與畫面互動,我們可以使用 v-on:method_name (簡寫@method_name) 綁定事件監聽器,藉此使用我們宣告的 method。以下以本專案的匯款表單來說明:
![](https://i.imgur.com/pGoavZh.png)
- 當使用者輸入匯款金額、匯款方式之後,會觸發 method 計算出匯費和合計金額。
```htmlmixed=
<!-- template -->
<div class="col-2">
<label for="transactAmount">匯款金額(新台幣)</label>
</div>
<div class="col-4">
<input
type="text"
class="form-control"
id="transactAmount"
placeholder="請輸入金額"
@input="transferFeeCounter()"
v-model="transferForm.transactAmount"
required
/>
</div>
```
- 在上面的 input 輸入欄位中, @input="transferFeeCounter()" 等同於 v-on:input="transferFeeCounter()" ,也就是當輸入欄位有更動時,就會去呼叫 "transferFeeCounter()" 方法。
```javascript=
export default {
methods:{
transferFeeCounter() {
//費用的計算方式
}
}
}
```
#### 三、v-for 迴圈
- v-for 跟一般常見的 for 迴圈差不多,常用來在 template中顯示陣列或是物件的內容。以下以 select 選單中的 v-for 應用來說明:
![](https://i.imgur.com/ktFM98D.png)
- 我們希望能將從後端抓來的銀行列表內的資料,當成下拉列表中的選項,因此使用了 v-for 來實作。
![](https://i.imgur.com/WvZwsdd.png =200x)
- 透過我們的 api 傳回來的銀行資料格式大概是這個樣子。
```json=
[
{
"name": "台灣銀行",
"swiftcode": "004"
},
{
"name": "土地銀行",
"swiftcode": "005"
},
{
"name": "合作金庫",
"swiftcode": "006"
}
]
```
- option 指的是 select 選單中的選項,我們以 v-for 遍歷陣列 banks , 把銀行的代碼和名稱顯示在選單中,並以前面提到的 v-model 把使用者選擇的值存入 data 中。
```htmlmixed=
<div class="col-2">
<label for="transferBank">收款銀行</label>
</div>
<div class="col-2">
<select
class="custom-select"
id="transferBank"
v-model="transferForm.transferBank"
required
>
<option v-for=" bank in banks">{{bank.swiftcode}} {{bank.name}}</option>
</select>
</div>
```
#### 四、v-if 條件渲染
- 如果希望某些畫面上的元素在特定條件下才出現,可以使用 v-if、 v-if-else 和 v-else,以條件式來決定畫面出現的內容。以下以交易單據中,銀行作業欄位的表單來說明:
![](https://i.imgur.com/Q1Px3Dg.png)
- 當交易是存款、匯款、提款時,這些行員必需詢問顧客的問題會不一樣,這時候為了避免同一份表單要設計很多種,可以使用 v-if 將不同的內容依條件顯示在畫面上,在這個例子中,紅圈圈起來的這一個問題在存款、匯款時的內容和提款時的不一樣,因此我們以 v-if 來判斷交易的 type,並顯示相對應的內容。
```htmlmixed=
<!-- 當交易是存款或匯款時顯示 -->
<label
for="question2"
class="col-md-4 col-form-label col-form-label-sm"
v-if="this.transact_data.type=='存款' || this.transact_data.type=='匯款'"
style="border:1px solid;"
>2.申請人是否認識存入帳戶的受款人
</label>
<!-- 當交易是提款時顯示 -->
<label
for="question2"
class="col-md-4 col-form-label col-form-label-sm"
v-if="this.transact_data.type=='取款'"
style="border:1px solid;"
>2.申請人是否認識陪同提款者(有陪同提款者時詢問)
</label>
```
### VueRouter 網站路由管理
[VueRouter官方文件](https://router.vuejs.org/zh/)
- vue 專案可以透過 vue-router 的設定檔來定義整體網站的路由規則,再利用 router-view 來定位子路由組件渲染的出口。
- 以下是本專案部分的路由檔案,vue router 的設定檔案會放在 components 資料夾中的 router資料夾內。
```javascript=
let router = new VueRouter({
mode: 'history',
routes: [
{
path: '/',
name: 'login',
component: login,
beforeEnter: (to, from, next) => {
if(store.getters.isLoggedIn){
next('home_'+store.getters.authToken)
}else{
next()
}
}
},
{
path: '/home_customer',
name: 'home_customer',
component: home_customer,
meta: {
requiresAuth: true,
allowAuth: 'customer'
},
},
]
})
export default router
```
#### 一、router-view
- router-view 簡單的作用就是在符合路由規則時,把指定路由組件取代父層組件中的視圖;而整個應用程式的第一個視圖就是在 App.vue 檔案中,也就表示在 vue-router 設定中的路由組件在匹配情境下,會直接取代 App.vue 中 router-view 元素。
![](https://i.imgur.com/a8uQfpv.jpg)
- App.vue
```htmlmixed=
<template>
<div>
NavBar
</div>
<router-view />
</template>
```
在上面的程式中,可以看到在NavBar的下面我們引入了router-view,因此顯示出來的是路由表中路徑為 '/' 的 login.vue。
#### 二、頁面的跳轉
- router.push 可以跳轉頁面,例如登入成功後,判斷使用者身份,如果是顧客的話,就將它轉移到顧客的首頁 home_customer。
```javascript=
this.$router.push("/home_customer");
```
### Axios 發送 http 請求
基本用法可以先參考官方文件,挺詳細的。
https://github.com/axios/axios
vue更新到2.0之後,作者就宣告不再對vue-resource更新,而是推薦使用 axios 來發送 http 請求。
以 npm 安裝:
```
$ npm install axios
```
以 CDN 使用:
```javascript=
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
```
一般常見的 Axios 寫法如下:
```javascript=
axios.get('/user?ID=12345')
.then(function (response) {
// 請求成功後執行
console.log(response);
})
.catch(function (error) {
// 錯誤處理
console.log(error);
})
.finally(function () {
// 不管請求成功或失敗都會執行
});
```
#### 一、API 呼叫
以下以我們匯款表單發送後的請求來示範 API 呼叫:
```javascript=
submit_form() {
//if user 點選確定
if (confirm("您確定要送出申請嗎?")) {
let uri = "api/POST/transaction";
this.axios
//發送 post 請求,將本次交易內容傳到後端
.post(uri, {
type: this.transactType,
receiptsData: JSON.stringify(this.transferForm),
branchCode: this.$store.getters.getBranchCode
})
//post 請求成功後,再以 get 請求後端返還本次交易ID
.then(response => {
this.axios
.get("api/GET/transaction/" + response.data.id)
.then(res => {
alert(
"已送出申請,即將返回首頁,您的交易編號為:" + res.data.tnum
);
});
});
//以 VueRouter 返回首頁
this.$router.push("home_customer");
}
}
```
#### 二、CORS 處理
在 config 資料夾下的 index.js 中, proxyTable 可以設定跨域請求的位置,之後只要以 '/api' 就能取代很長的網址。
```javascript=
proxyTable: {
'/api': {
target: 'http://172.20.10.2:8080/esp-back-end-0.0.1-SNAPSHOT/',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
},
```
### Vuex 與登入管理
基本用法可以先參考官方文件,挺詳細的。
https://vuex.vuejs.org/installation.html
從前幾個範例中,可以發現資料都是存放在各組件 script 的 data 裡面,但是一個大型系統中,重複使用到的資料會有很多(e.g. token, user info, shopping cart list),這樣各個頁面切換之間如何拿到同一筆資料呢?
因此我們需要一個集中管理資料的地方,這樣的需求可以用 Vuex 來完成, 透過 vuex 的 store 可以儲存多頁面共用的資料,像是登入資訊等等。
透過 npm 或 YARN 安裝
```
npm install vuex --save
```
打開 main.js 宣告使用 vuex
```javascript=
// 引入 vuex
import Vuex from 'vuex'
// 告訴 Vue 使用 vuex
Vue.use(Vuex)
```
以下以登入管理來示範 vuex 的 store 使用方法:
#### 一、建立 token
在 ./src/main.js 檔案加入以下:
```javascript=
import store from './store'
import Axios from 'axios'
Vue.prototype.$http = Axios;
const token = localStorage.getItem('token')
if (token) {
Vue.prototype.$http.defaults.headers.common['Authorization'] = token
}
[...]
```
#### 二、 store 的寫法
這些內容我們放在 src/store 資料夾下的 index.js 檔案
1. state: 負責記錄應用程式所有的 State。
2. mutations: 負責接收 action(commit) 資料並計算邏輯後改變 State,只有 mutation 可以改變 state。
3. action: 定義了整個應用程式的行為如:按下 login 這顆按鈕,它是一個 action!現在我們要開始登入囉!這樣的行為通常需要與 server 溝通,因此 call API 的行為(非同步)也會在 action 中執行! 它使用 commit 向 Mutations 溝通(傳遞資料)。
4. getters: 讓我們能在各個組件中存取 state 中的資料。例如:this.$store.getters.isLoggedIn 可以得知是否以登入。
```javascript=
export default new Vuex.Store({
//state,存放想要整個網站共享的資料能放在這裡
state: {
status: '',
token: localStorage.getItem('token') || '',
},
//mutation,只能透過 mutation 改變 state 內容
mutations: {
auth_request(state) {
state.status = 'loading'
},
auth_success(state, payload) {
state.status = 'success'
state.token = payload.token
},
auth_error(state) {
state.status = 'error'
},
},
//action,負責觸發 mutation
actions: {
login({ commit }, user) {
return new Promise((resolve, reject) => {
commit('auth_request')
//把使用者輸入的帳號密碼傳送到後端做比對
axios({ url: '/api/POST/user/auth/' + user.id, data: user, method: 'POST' })
//將回傳的 token 存到 localstorage中
.then(resp => {
const token = resp.data.role
localStorage.setItem('token', token)
axios.defaults.headers.common['Authorization'] = token
//透過 commit 呼叫 mutation,藉此改變 state 中的資料
commit('auth_success', {'token':token})
resolve(resp)
})
.catch(err => {
commit('auth_error')
localStorage.removeItem('token')
reject(err)
})
})
},
},
//getters
getters: {
isLoggedIn: state => !!state.token,
authStatus: state => state.status,
authToken: state => state.token,
}
})
```
#### 三、 Login 頁面中,按下 Login 按鈕後所觸發的事件
```javascript=
methods: {
login: function() {
//user輸入的id和password
let id = this.user.id;
let password = this.user.password;
//使用 vuex 的 store
this.$store
//呼叫 store 中的 action 中的 login method
.dispatch("login", { id, password })
//如果後端處理的結果判斷帳號錯誤
.then(() => {
if (this.$store.getters.authToken == "Wrong account") {
alert("帳號錯誤");
this.$store.dispatch("logout");
this.$router.push("/");
//如果後端處理的結果判斷密碼錯誤
} else if (this.$store.getters.authToken == "Wrong password") {
alert("密碼錯誤");
this.$store.dispatch("logout");
this.$router.push("/");
//如果帳密都正確,依照 token 被 push 到相對應的頁面
} else {
this.$router.push("/home_" + this.$store.getters.authToken);
this.$router.go()
}
})
.catch(err => console.log(err));
},
}
```
### Vue.js 元件式設計作法
在vue.js中,各個元件獨立運作,每個元件都有各自用途,然後再互相組合搭配,讓系統開發上比較結構化。
參考資料:
https://ithelp.ithome.com.tw/articles/10196032
https://ithelp.ithome.com.tw/articles/10196169
### Vue-tables-2 列表設計
vue 之套件,只要把資料傳進去就能輕易顯示出表格,並且做許多操作,像是篩選、搜尋等等,非常方便。
- 安裝
```
$ npm install vue-tables-2
```
- Import and register (main.js)
```htmlmixed=
import {ServerTable, ClientTable, Event} from 'vue-tables-2';
Vue.use(ClientTable);
Vue.use(ServerTable);
window.Event = Event;
Vue.use(Event);
window.moment = require('moment');
```
- 變數宣告
```htmlmixed=
data() {
return {
tableData: [],
columns: ["type", "tnum", "顧客姓名", "交易金額", "dateTime", "broker", "finishedTime", "finished"],
}
}
```
tableData 用陣列存所有列資料(Json),columns 可以選擇你想放的欄位,例如:tableData 內的資料含有:id, name, age,此時 columns: ["id", "name"] 就不會把 age 的資料顯示出來。
- 跟後端索取資料
```htmlmixed=
this.axios.get("api/GET/transactions/"+this.$store.getters.getBranchCode).then(res => {
this.tableData = res.data;
this.tableData.map(x => {
x.dateTime = moment(x.dateTime + " GMT+0000");
});
});
```
拿到資料後放進 tableData 內,若資料內有 datetime 之類的時間資料必須先用轉成 moment 物件,後面有 GMT+0000 是因為當時件資料庫時沒有設定成台灣時區,時區是在0的位置,而 moment 會預設傳進去的時區是當地的,因此要標示傳進來的時區,moment 才能辨認轉成正確時區。
- 顯示 table
```htmlmixed=
<v-client-table ref="myTable" :data="tableData" :columns="columns" :options="options">
</v-client-table>
```
如此就能顯示出資料表如下 (除 filter)
![](https://i.imgur.com/fnjXmM3.png)
- Filter 功能
vue-table-2 其中一項強大的功能就是簡易實現 filter,若我們要針對個別欄位搜尋,只要在 filterable 內加入想要 filter 的欄位即可。
```htmlmixed=
options: {
filterable: ["id", "type", "dateTime", "tnum"],
}
```
只不過預設是對字串的搜尋,如果想要客製化 filter 的功能像是 list filter,在 options 裡再加入 filterByColumn 及 listColumns:
```htmlmixed=
options: {
filterable: ["id", "type", "dateTime", "tnum"],
filterByColumn: true,
listColumns: {
type: [
{ id: "存款", text: "存款" },
{ id: "取款", text: "取款" },
{ id: "匯款", text: "匯款" }
]
},
}
```
vue-table-2 有提供許多 [options](https://www.npmjs.com/package/vue-tables-2#options) ,可以實現許多 incredible 的功能。
另外這個 [github](https://github.com/KarateJB/eBooks/tree/master/Vue.js) 的教學寫得相當詳盡也可以參考。