--- 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) 的教學寫得相當詳盡也可以參考。