订单结算

订单结算

订单结算页面所需的数据从购物车中勾选而来。

1. 后端接口设计

请求方式 : GET /orders/settlement/

请求参数: 无

返回数据: JSON

参数 类型 是否必须 说明
freight decimal 运费
skus sku[] 结算的商品列表
id int 商品id
name str 商品名称
default_image_url str 商品默认图片
price decimal 商品单价
count int 商品数量
{
    "freight":"10.00",
    "skus":[
        {
            "id":10,
            "name":"华为 HUAWEI P10 Plus 6GB+128GB 钻雕金 移动联通电信4G手机 双卡双待",
             "default_image_url":"http://image.meiduo.site:8888/group1/M00/00/02/CtM3BVrRchWAMc8rAARfIK95am88158618",
            "price":"3788.00",
            "count":1
        },
        {
            "id":16,
            "name":"华为 HUAWEI P10 Plus 6GB+128GB 曜石黑 移动联通电信4G手机 双卡双待",
            "default_image_url":"http://image.meiduo.site:8888/group1/M00/00/02/CtM3BVrRdPeAXNDMAAYJrpessGQ9777651",
            "price":"3788.00",
            "count":1
        }
    ]
}

2. 后端实现

在orders/serialziers.py中创建序列化器

class CartSKUSerializer(serializers.ModelSerializer):
    """
    购物车商品数据序列化器
    """
    count = serializers.IntegerField(label='数量')

    class Meta:
        model = SKU
        fields = ('id', 'name', 'default_image_url', 'price', 'count')


class OrderSettlementSerializer(serializers.Serializer):
    """
    订单结算数据序列化器
    """
    freight = serializers.DecimalField(label='运费', max_digits=10, decimal_places=2)
    skus = CartSKUSerializer(many=True)

在orders/views.py中编写视图

class OrderSettlementView(APIView):
    """
    订单结算
    """
    permission_classes = [IsAuthenticated]

    def get(self, request):
        """
        获取
        """
        user = request.user

        # 从购物车中获取用户勾选要结算的商品信息
        redis_conn = get_redis_connection('cart')
        redis_cart = redis_conn.hgetall('cart_%s' % user.id)
        cart_selected = redis_conn.smembers('cart_selected_%s' % user.id)

        cart = {}
        for sku_id in cart_selected:
            cart[int(sku_id)] = int(redis_cart[sku_id])

        # 查询商品信息
        skus = SKU.objects.filter(id__in=cart.keys())
        for sku in skus:
            sku.count = cart[sku.id]

        # 运费
        freight = Decimal('10.00')

        serializer = OrderSettlementSerializer({'freight': freight, 'skus': skus})
        return Response(serializer.data)

3. 前端实现

修改place_order.html,增加Vue变量

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>美多商城-提交订单</title>
    <link rel="stylesheet" type="text/css" href="css/reset.css">
    <link rel="stylesheet" type="text/css" href="css/main.css">
    <script type="text/javascript" src="js/host.js"></script>
    <script type="text/javascript" src="js/vue-2.5.16.js"></script>
    <script type="text/javascript" src="js/axios-0.18.0.min.js"></script>
    <script>
        var user_id = sessionStorage.user_id || localStorage.user_id;
        var token = sessionStorage.token || localStorage.token;
        if (!(user_id && token)) {
            location.href = '/login.html?next=/cart.html';
        }
    </script>
</head>
<body>
    <div id="app">
    <div class="header_con">
        <div class="header">
            <div class="welcome fl">欢迎来到美多商城!</div>
            <div class="fr">
                <div class="login_btn fl">
                    欢迎您:<em>{{ username }}</em>
                    <span>|</span>
                    <a @click="logout">退出</a>
                </div>
                <div class="user_link fl">
                    <span>|</span>
                    <a href="user_center_info.html">用户中心</a>
                    <span>|</span>
                    <a href="cart.html">我的购物车</a>
                    <span>|</span>
                    <a href="user_center_order.html">我的订单</a>
                </div>
            </div>
        </div>        
    </div>

    <div class="search_bar clearfix">
        <a href="index.html" class="logo fl"><img src="images/logo.png"></a>
        <div class="sub_page_name fl">|&nbsp;&nbsp;&nbsp;&nbsp;提交订单</div>
        <form method="get" action="/search.html" class="search_con fr mt40">
            <input type="text" class="input_text fl" name="q" placeholder="搜索商品">
            <input type="submit" class="input_btn fr" name="" value="搜索">
        </form>
    </div>

    <h3 class="common_title">确认收货地址</h3>

    <div class="common_list_con clearfix">
        <dl>
            <dt>寄送到:</dt>
            <dd v-for='address in addresses' :class="[(nowsite==address.id)?'current':'']" @click="nowsite=address.id"><input type="radio" name="get_site" :value="address.id" v-model="nowsite">{{ address.province }} {{address.city}} {{ address.district }} {{ address.place }} ({{ address.receiver }} 收) {{ address.mobile }}</dd>
        </dl>
        <a href="user_center_site.html" class="edit_site">编辑收货地址</a>
    </div>

    <h3 class="common_title">支付方式</h3>    
    <div class="common_list_con clearfix">
        <div class="pay_style_con clearfix">
            <input type="radio" name="pay_style" value="1" v-model="pay_method">
            <label class="cash">货到付款</label>
            <input type="radio" name="pay_style" value="2" v-model="pay_method">
            <label class="zhifubao"></label>
        </div>
    </div>

    <h3 class="common_title">商品列表</h3>

    <div class="common_list_con clearfix">
        <ul class="goods_list_th clearfix">
            <li class="col01">商品名称</li>
            <li class="col03">商品价格</li>
            <li class="col04">数量</li>
            <li class="col05">小计</li>        
        </ul>
        <ul class="goods_list_td clearfix" v-for="(sku,index) in skus">
            <li class="col01">{{index+1}}</li>
            <li class="col02"><img :src="sku.default_image_url"></li>
            <li class="col03">{{ sku.name }}</li>
            <li class="col05">{{ sku.price }}元</li>
            <li class="col06">{{ sku.count }}</li>
            <li class="col07">{{ sku.amount }}元</li>
        </ul>
    </div>

    <h3 class="common_title">总金额结算</h3>

    <div class="common_list_con clearfix">
        <div class="settle_con">
            <div class="total_goods_count">共<em>{{ total_count }}</em>件商品,总金额<b>{{ total_amount }}元</b></div>
            <div class="transit">运费:<b>{{ freight }}元</b></div>
            <div class="total_pay">实付款:<b>{{ payment_amount }}元</b></div>
        </div>
    </div>

    <div class="order_submit clearfix">
        <a @click="on_order_submit" id="order_btn">提交订单</a>
    </div>    

    <div class="footer">
        <div class="foot_link">
            <a href="#">关于我们</a>
            <span>|</span>
            <a href="#">联系我们</a>
            <span>|</span>
            <a href="#">招聘人才</a>
            <span>|</span>
            <a href="#">友情链接</a>        
        </div>
        <p>CopyRight © 2016 北京美多商业股份有限公司 All Rights Reserved</p>
        <p>电话:010-****888    京ICP备*******8号</p>
    </div>
    </div>

    <div class="popup_con">
        <div class="popup">
            <p>订单提交成功!</p>
        </div>

        <div class="mask"></div>
    </div>
    <script type="text/javascript" src="/js/place_order.js"></script>
</body>
</html>

新建place_order.js

var vm = new Vue({
    el: '#app',
    data: {
        host,
        username: sessionStorage.username || localStorage.username,
        user_id,
        token,
        skus: [],
        freight: 0, // 运费
        total_count: 0,
        total_amount: 0,
        payment_amount: 0,
        order_submitting: false, // 正在提交订单标志
        pay_method: 1, // 支付方式,
        nowsite:0, // 默认地址
        addresses: []
    },
    mounted: function(){
        // 获取地址信息
        axios.get(this.host + '/addresses/', {
                headers: {
                    'Authorization': 'JWT ' + this.token
                },
                responseType: 'json'
            })
            .then(response => {
                this.addresses = response.data.addresses;
                this.nowsite = response.data.default_address_id;
            })
            .catch(error => {
                status = error.response.status;
                if (status == 401 || status == 403) {
                    location.href = 'login.html?next=/user_center_site.html';
                } else {
                    alert(error.response.data.detail);
                }
            })
        // 获取结算商品信息
        axios.get(this.host+'/orders/settlement/', {
                headers: {
                    'Authorization': 'JWT ' + this.token
                },
                responseType: 'json'
            })
            .then(response => {
                this.skus = response.data.skus;
                this.freight = response.data.freight;
                this.total_count = 0;
                this.total_amount = 0;
                for(var i=0; i<this.skus.length; i++){
                    var amount = parseFloat(this.skus[i].price)*this.skus[i].count;
                    this.skus[i].amount = amount.toFixed(2);
                    this.total_count += this.skus[i].count;
                    this.total_amount += amount;
                }
                this.payment_amount = parseFloat(this.freight) + this.total_amount;
                this.payment_amount = this.payment_amount.toFixed(2);
                this.total_amount = this.total_amount.toFixed(2);
            })
            .catch(error => {
                if (error.response.status == 401){
                    location.href = '/login.html?next=/cart.html';
                } else{
                    console.log(error.response.data);
                }
            })
    },
    methods: {
        // 退出
        logout: function(){
            sessionStorage.clear();
            localStorage.clear();
            location.href = '/login.html';
        },
        // 提交订单
        on_order_submit: function(){

        }
    }
});