1. 程式人生 > >樂優商城(三十六)——訂單微服務

樂優商城(三十六)——訂單微服務

目錄

二、訂單結算頁

2.1 頁面跳轉

2.2 收貨人資訊

2.3 支付方式

2.4 商品列表

2.4.1 購物車資訊獲取

2.4.2 頁面渲染

2.5 總金額

2.6 提交訂單

2.6.1 頁面提交

2.6.2 精度損失問題

三、微信支付

3.1 介紹

3.2 開發流程

3.2.1 介紹

3.2.2 具體工作

3.3 生成二維碼

3.3.1 生成預交易連結

3.3.2 生成二維碼

3.4 付款狀態查詢

3.4.1 頁面迴圈查詢支付狀態

3.4.2 付款成功頁面


二、訂單結算頁

2.1 頁面跳轉

在購物車頁面的最下方,有一個去結算按鈕:

當點選結算,我們應該跳轉到訂單結算頁,即:getOrderInfo.html

檢視購物車的結算按鈕:

可以看到,地址是正確的。但是隻有登入使用者才可以去結算付款,因此不能直接跳轉,而是在跳轉前校驗使用者的登入狀態,如果發現是未登入,應該重定向到登入頁!

繫結點選事件:

toOrderInfo(){
                //1.判斷是否登入
                ly.verifyUser().then(() => {
                    //2.已登入
                    window.location.href = "/getOrderInfo.html";
                }).catch(() => {
                    window.location.href = "/login.html?returnUrl=" + window.location.href;
                })
            }

登入後測試:

此處頁面需要渲染的內容主要包含3部分:

  • 收貨人資訊

  • 支付方式

  • 商品資訊

2.2 收貨人資訊

這裡的收貨人資訊肯定是當前登入使用者的收貨地址。所以需要根據當前登入使用者去查詢,目前是假資料,為了展示效果,具體開發,下一篇介紹。

2.3 支付方式

支付方式有2種:

  • 微信支付

  • 貨到付款

與訂單資料中的paymentType關聯:

所以在Vue例項中定義一個屬性來記錄支付方式:

然後在頁面渲染時與這個變數關聯:

2.4 商品列表

效果圖:

這裡的送貨清單,其實就是購物車中使用者選擇的要付款的商品

因此,需要在購物車跳轉過來的同時,攜帶選中的購物車的資訊

2.4.1 購物車資訊獲取

修改cart.html中的頁面跳轉邏輯,把使用者選中的購物車資訊傳遞過來:

然後在created鉤子函式中獲取購物車資料,儲存到本地屬性,要注意的是,應該在獲取資料前校驗使用者登入狀態,如果發現未登入,則直接重定向到登入頁:

重新載入頁面,檢視本地資料:

2.4.2 頁面渲染

2.5 總金額

可以看出這裡主要有4個數據:

  • 總金額:totalPay

  • 優惠返現:discount

  • 運費:postFee

  • 實付金額:actualPay

不過我們沒有做優惠活動,另外運費需要結合物流系統來計算,暫時都設定為0,在order屬性中寫死:

通過計算屬性來得到totalPayactualPay值:

computed:{
                totalNum(){
                    return this.carts.reduce((c1,c2) => c1 + c2.num,0);
				},
				totalPay(){
                    return this.carts.reduce((c1,c2) => c1 + c2.price * c2.num,0);
				},
				actualPay(){
                    return this.totalPay + this.order.postFee - this.order.discount;
				}
			}

然後在頁面渲染:

效果:

2.6 提交訂單

2.6.1 頁面提交

分析

檢視訂單介面所需要的資料

{
  "totalPay": 236800,
  "postFee": 0,
  "paymentType": 2,
  "actualPay": 236800,
  "buyerMessage": null,
  "buyerNick": "huge",
  "orderDetails": [
    {
      "skuId": 3893493,
      "num": 1,
      "title": "蘋果(Apple)iPhone 6 (A1586) 16GB 金色 移動聯通電信4G手機3",
      "price": 236800,
      "ownSpec": "{\"機身顏色\":\"鑽雕藍\",\"記憶體\":\"4GB\",\"機身儲存\":\"64GB\"}",
      "image": "http://image.leyou.com/images/9/4/1524297342728.jpg"
    }
  ],
  "receiver": "鋒哥",
  "receiverMobile": "15800000000",
  "receiverState": "上海",
  "receiverCity": "上海",
  "receiverDistrict": "浦東新籤",
  "receiverAddress": "航頭鎮航頭路18號傳智播客3號樓",
  "receiverZip": "210000",
  "invoiceType": 0,
  "sourceType":2
}
  • 訂單本身的基本資訊

    • 總金額

    • 實付金額

    • 付款型別

    • 買家資訊就是當前使用者

  • 訂單詳情

    • 就是購物車中的商品,不過購物車資料會多出一個userId,去除即可:

  • 物流資訊:當前使用者選中的地址

繫結事件

注:使用@click.prevent是因為要阻止a標籤的預設跳轉,去執行submit函式。

方法

 submit(){
                    //1.把購物車資料處理成訂單物件
                    const orderDetails = this.carts.map(({userId, ...rest}) => rest);
                    //1.1將ownSpec欄位轉換成json
                    orderDetails.forEach(s =>{
                        s.ownSpec = JSON.stringify(s.ownSpec);
                    });
                    //2.處理物流資訊
                    const addr = this.addresses[this.selectedAddress];
                    const obj = {
                        receiver:addr.name,
                        receiverState:addr.state,
                        receiverCity:addr.city,
                        receiverAddress:addr.address,
                        receiverDistrict:addr.district,
                        receiverMobile:addr.phone,
                        receiverZip:addr.zipCode
                    };
                    //3.複製到訂單物件
                    Object.assign(this.order,obj,{
                        orderDetails,
                        totalPay:this.totalPay,
                        actualPay:this.actualPay,
                    });
                    //4.提交訂單
                    //console.log(this.order);
                    ly.http.post("/order",this.order).then(({data}) => {
                        //4.1線上支付,需要到付款頁
                        window.location = "pay.html?orderId=" + data;
                    }).catch(() => {
                        alert("訂單提交失敗,請稍後再試!");
                    })
                }

2.6.2 精度損失問題

頁面點選提交進行測試:

生成訂單成功!

然後頁面跳轉:

好像有什麼不對?訂單號的最後2位不正確啊!

這其實是因為JS的長整數精度有限,java的Long型別資料超出了範圍,所以出現了精度損失。

因為後臺返回的是Json的字串,在axios內部會自動呼叫 JSON.parse()方法把json字串轉為JS資料,就會出現進度損失。如果不進行轉換,依然當做字串來使用,就不會有問題了。

因此,重寫axios對響應的處理回撥函式:

三、微信支付

3.1 介紹

微信支付官方文件:https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F

選擇開發文件,而後進入選擇頁面:

選擇掃碼支付:

此處使用模式二來開發

3.2 開發流程

3.2.1 介紹

模式二與模式一相比,流程更為簡單,不依賴設定的回撥支付URL。商戶後臺系統先呼叫微信支付的統一下單介面,微信後臺系統返回連結引數code_url,商戶後臺系統將code_url值生成二維碼圖片,使用者使用微信客戶端掃碼後發起支付。注意:code_url有效期為2小時,過期後掃碼不能再發起支付。

流程圖:

業務流程說明:

(1)商戶後臺系統根據使用者選購的商品生成訂單。

(2)使用者確認支付後呼叫微信支付【統一下單API】生成預支付交易;

(3)微信支付系統收到請求後生成預支付交易單,並返回交易會話的二維碼連結code_url。

(4)商戶後臺系統根據返回的code_url生成二維碼。

(5)使用者開啟微信“掃一掃”掃描二維碼,微信客戶端將掃碼內容傳送到微信支付系統。

(6)微信支付系統收到客戶端請求,驗證連結有效性後發起使用者支付,要求使用者授權。

(7)使用者在微信客戶端輸入密碼,確認支付後,微信客戶端提交授權。

(8)微信支付系統根據使用者授權完成支付交易。

(9)微信支付系統完成支付交易後給微信客戶端返回交易結果,並將交易結果通過簡訊、微信訊息提示使用者。微信客戶端展示支付交易結果頁面。

(10)微信支付系統通過傳送非同步訊息通知商戶後臺系統支付結果。商戶後臺系統需回覆接收情況,通知微信後臺系統不再發送該單的支付通知。

(11)未收到支付通知的情況,商戶後臺系統呼叫【查詢訂單API】。

(12)商戶確認訂單已支付後給使用者發貨。

3.2.2 具體工作

這裡把商戶要做的事情總結一下:

  • 1、商戶生成訂單

  • 2、商戶呼叫微信下單介面,獲取預交易的連結

  • 3、商戶將連結生成二維碼圖片,展示給使用者;

  • 4、使用者支付並確認

  • 5、支付結果通知:

    • 微信非同步通知商戶支付結果,商戶告知微信支付接收情況

    • 商戶如果沒有收到通知,可以呼叫介面,查詢支付狀態

  • 6、如果支付成功,發貨,修改訂單狀態

在前面的業務中,已經完成了:

  • 1、生成訂單

接下來需要完成的是:

  • 2、呼叫微信介面,生成連結。

  • 3、並且生成二維碼圖片

3.3 生成二維碼

3.3.1 生成預交易連結

先根據訂單的編號,呼叫後臺服務,生成交易連結,而後才能根據連結生成二維碼。

在頁面發起請求:

var payVm = new Vue({
        el:"#payVm",
        data:{
            ly,
            orderId:0, //訂單id
        },
        components:{
            shortcut: () => import("/js/pages/shortcut.js")
        },
        created(){
            this.loadData();
        },
        methods:{
            loadData(){
                //1.判斷使用者是否登入
                ly.verifyUser().then(() => {
                    //2.獲取訂單編號
                    this.orderId = ly.getUrlParam("orderId");
                    //3.獲取請求連結
                    ly.http.get("/order/url/" + this.orderId).then(resp => {
                        console.log(resp.data);
                        new QRCode(document.getElementById("qrImage"),{
                            text:resp.data,
                            width:250,
                            height:250,
                            colorDark: "#000000",
                            colorLight: "#ffffff",
                            correctLevel: QRCode.CorrectLevel.H
                        });
                    });
                }).catch(() => {
                    //4.未登入,跳轉至登入頁
                    location.href = "/login.html?returnUrl=" + location.href;
                })
            }
        }
    });

注意:app.js要最後引入,因為要先有id為app的div,vue才能獲取相應的元素。否則會報錯: [Vue warn]: Cannot find element

後臺已經定義好生成付款地址的介面:

重新整理頁面:

3.3.2 生成二維碼

使用一個生成二維碼的JS外掛:qrcode,官網:https://github.com/davidshimjs/qrcodejs

將這個指令碼引入到專案中

官方使用案例

頁面引用

頁面定義一個div用來展示二維碼

獲取到付款連結後生成二維碼

效果

此時,客戶用手機掃描二維碼,可以看到付款頁面。

3.4 付款狀態查詢

跳轉到支付頁面後,等待使用者付款,付款完成則跳轉到付款成功頁面

3.4.1 頁面迴圈查詢支付狀態

不過,因為不清楚使用者何時會付款,因此這裡採用迴圈的方式,不斷請求判斷是否支付成功。

3.4.2 付款成功頁面

當付款成功後,自動跳轉到付款成功頁面: