目录

二、订单结算页

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 付款成功页面

当付款成功后,自动跳转到付款成功页面:

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐