订单结算
订单结算页面所需的数据从购物车中勾选而来。
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">| 提交订单</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(){
}
}
});