day86:luffy:前端发送请求生成订单&结算页面优惠劵的实现
1.前端发送请求生成订单 1.前端点击支付按钮生成订单 2.结算成功之后应该清除结算页面的数据 3.后端计算结算页面总原价格和总的真实价格并存到数据库订单表中 2.优惠劵 1.准备工作 2.前端展示优惠券信息-初始化 3.优惠券-前端获取优惠券数据+后端接口 4.结算页面计算真实总价格 5.优惠券是否真的能够使用+优惠劵前端计算 1.优惠劵的选中效果 2.不可点击的不应该具有点击效果 3.优惠券箭头收缩之后 取消优惠券的选中状态 4.当选中的优惠劵发生变化时 重新计算总价 6.优惠劵后端对优惠劵进行校验
点击支付按钮,触发生成订单事件,生成一个订单 order.vue <!-- html --> 给支付按钮绑定一个事件 该事件向后端发起请求来生成订单 <el-col :span="4" class="cart-pay"><span @click="payhander">支付</span></el-col> // js // 生成订单 payhander(){ let token = localStorage.token || sessionStorage.token; this.$axios.post(`${this.$settings.Host}/order/add_money/`,{ 生成订单需要提交的支付类型、优惠券、积分 "pay_type":this.pay_type,"coupon":.current_coupon,"credit":0 },{ headers:{ 'Authorization':'jwt ' + token } }).then((res)=>{ this.$message.success('订单已经生成,马上跳转支付页面') }).catch((error)=>.$message.error(error.response.data.msg); }) } 2.结算成功之后应该清除结算页面的数据
所以应该redis中删除用户选中的课程id,也就是selected_cart的数据 order/serializers.py # serializers.py def create(self,validated_data): 结算成功之后,再清除 conn = get_redis_connection('cart') conn.delete(selected_cart_%s' % user_id) return order_obj 3.后端计算结算页面总原价格和总的真实价格并存到数据库订单表中order/serializers.py try: 生成订单号 [日期,用户id,自增数据] total_price = 0 总原价 total_real_price = 0 总真实价格 with transaction.atomic(): 添加事务 生成订单,保存到数据库中 ...... 生成订单详情 计算所有课程的总原价 total_price += course_obj.price 计算所有课程的总真实价格 total_real_price += course_obj.real_price(expire_id) 将订单总原价和总真实价格存到数据库表中 order_obj.total_price = total_price order_obj.real_price = total_real_price order_obj.save() except Exception: raise models.Order.DoesNotExist return order_obj 2.优惠劵1.准备工作1.创建coupon应用,并配置INSTALLAPP python3 ../../manage.py startapp coupon 2.coupon/models.py from django.db import models from lyapi.utils.models BaseModel from users.models User from datetime timedelta Create your models here. class Coupon(BaseModel): """优惠券""" coupon_choices = ( (0,折扣优惠),(1,减免优惠) ) name = models.CharField(max_length=32,verbose_name="优惠券标题") coupon_type = models.SmallIntegerField(choices=coupon_choices,default=0,1)">优惠券类型) timer = models.IntegerField(verbose_name=优惠券有效期",default=7,help_text=默认当前优惠券7天有效,如果设置值为-1则表示当前优惠券永久有效) condition = models.IntegerField(blank=True,1)">满足使用优惠券的价格条件,如果设置值为0,则表示没有任何条件) sale = models.TextField(verbose_name=优惠公式 *号开头表示折扣价,例如*0.82表示八二折;<br> -号开头表示减免价,例如-10表示在总价基础上减免10元<br> ) Meta: db_table = ly_coupon verbose_name= verbose_name_plural=" def __str__(self): return %s" % (self.name) UserCoupon(BaseModel): user = models.ForeignKey(User,on_delete=models.CASCADE,related_name=coupons用户) coupon = models.ForeignKey(Coupon,1)">users) start_time = models.DateTimeField(verbose_name=优惠策略的开始时间) is_use = models.BooleanField(default=False,1)">优惠券是否使用过ly_user_coupon verbose_name = 用户的优惠券 verbose_name_plural = 优惠券:%s,用户:%s (self.coupon.name,self.user.username) @property end_time(self): s_time = self.start_time timer = self.coupon.timer 天数 return s_time + timedelta(days=timer) 3.数据库迁移指令 python3 ../../manage.py makemigrations
python3 ../../manage.py migrate
4.adminx注册 coupon/adminx.py xadmin from .models Coupon CouponModelAdmin(object): 优惠券模型管理类 list_display = [namecoupon_typetimer] xadmin.site.register(Coupon,CouponModelAdmin) UserCoupon UserCouponModelAdmin(object): 我的优惠券模型管理类usercouponstart_timeis_use] xadmin.site.register(UserCoupon,UserCouponModelAdmin) 5.插入一些数据 INSERT INTO `ly_coupon` VALUES (1,1); font-weight: bold">0,'2019-08-21 15:59:04.568037',1)">2019-08-21 15:59:04.568061十元优惠券30,1); font-weight: bold">10,1)">-10'),(2,1)">2019-08-21 15:59:33.7648072019-08-21 15:59:33.764830五十元优惠券50,1)">-503,1)">2019-08-21 16:00:10.0901002019-08-21 16:00:10.0901269折优惠券7,1)">*0.9); INTO `ly_user_coupon` VALUES (2019-08-21 16:00:40.8239772019-08-23 19:23:58.1176002019-08-21 01:00:00.00000012019-08-21 16:00:49.8685972019-08-22 09:37:46.0100372019-10-01 01:00:00.0000002019-08-21 16:01:09.0518622019-08-23 19:31:02.6052532019-08-21 01:01:00.0000004,1); font-weight: bold">5,1)">2019-08-22 08:48:56.4066712019-08-22 08:48:56.4066942019-08-22 17:48:00.0000001); div ="discount"> id="accordion"> ="coupon-box"> ="icon-box"> ="select-coupon">使用优惠劵:a ="select-icon unselect" :class="use_coupon?'is_selected':''" @click="use_coupon=!use_coupon"img ="sign is_show_select" src="../../static/img/12.png" alt=""a="coupon-num">有0张可用divp ="sum-price-wrap">商品总金额:="sum-price">0.00元p="collapSEOne" v-if="use_coupon"ul ="coupon-list" v-if="coupon_list.length>0"li ="coupon-item"="select_coupon(index,coupon.id)" v-for="(coupon,index) in coupon_list"="change_coupon(index,coupon.id)"> ="coupon-name">8.5折优惠券="coupon-condition">满0元可以使用="coupon-time start_time">开始时间:="coupon-time end_time">过期时间:li> ul="no-coupon"="coupon_list.length<1"="no-coupon-tips">暂无可用优惠券="credit-box"label ="my_el_check_box"el-checkbox ="my_el_checkbox" v-model="use_credit"el-checkboxlabel="discount-num1"="!use_credit">使用我的贝里="discount-num2" v-else>总积分:100,已抵扣 ¥0.00,本次花费0积分="sun-coupon-num">优惠券抵扣:> > /* css */ .coupon-box{ text-align: left; padding-bottom: 22px; padding-left:30px; border-bottom: 1px solid #e8e8e8; } .coupon-box::after{ content: ""; display: block; clear: both; } .icon-box{ float: left; } .icon-box .select-coupon{ color: #666; font-size: 16px; } .icon-box::after{"";both; block; } .select-icon{ width: 20px; height: .select-icon img{ max-height:100%; max-width: 100%; margin-top: 2px; transform: rotate(-90deg); transition: transform .5s; } .is_show_select{ rotate(0deg)!important; } .coupon-num{ height: line-height: padding: 0 5px; text-align: center; font-size: 12px; float: color: #fff; letter-spacing: .27px; background: #fa6240; border-radius: margin-left: 20px; } .sum-price-wrap{ right; 16px; #4a4a4a; margin-right: 45px; } .sum-price-wrap .sum-price{ 18px; #fa6240; } .no-coupon{ padding: 50px 0px; align-items: justify-content: center; 文本两端对其 */ 1px solid rgb(232,232,232); } .no-coupon-tips{ #9b9b9b; } .credit-box{ 30px; 40px; flex; flex-end } .my_el_check_box{ position: relative; } .my_el_checkbox{ margin-right: 10px; .discount{ overflow: hidden; } .discount-num1{ #9b9b9b; .discount-num2{ 45px; #4a4a4a; } .sun-coupon-num{ margin-bottom:43px; inline-block; right; } .sun-coupon-num span{ .coupon-list{ margin: 20px 0; } .coupon-list::after{ .coupon-item{ 15px 8px; 180px; 100px; 5px; background-color: #fa3030; cursor: pointer; } .coupon-list .active{ #fa9000; } .coupon-list .disable{ not-allowed; #fa6060; } .coupon-condition{ #fff; } .coupon-name{ 24px; center; } .coupon-time{ 12px; } .unselect{ margin-left: 0px; rotate(-90deg); } .is_selected{ rotate(-1turn)!important; } .coupon-item p{ margin: 0; 0; } coupon/urls.py coupon/urls.py from django.urls path,re_path from . views urlpatterns = [ re_path(rlist/,views.CouponView.as_view(),),] lyapi/urls.py lyapi/urls.py from xadmin.plugins xversion xversion.register_models() urlpatterns = [ ...... path(rcoupon/coupon.urls)),1)">coupon/views.py order.vue html --> > > >{{coupon.coupon.name}}>满{{coupon.coupon.condition}}元可以使用>开始时间:{{coupon.start_time.replace('T',' ')}}>过期时间:{{coupon.end_time.replace('T',1)">> > 之前的结算页面只差真实的总价格没有计算了。现在通过后端计算真实总价格然后发送给前端。
1.后端计算好结算页面的总价格和总真实价格cart/views.py cart/views.py 结算页面数据 show_pay_info(self,request): user_id = request.user.id conn = get_redis_connection() select_list = conn.smembers( user_id) data = [] ret = conn.hgetall(cart_%s' % user_id) dict {b'1': b'0',b'2': b'0'} total_price = 0 total_real_price = 0 for cid,eid in ret.items(): expire_id = int(eid.decode(utf-8)) if cid select_list: course_id = int(cid.decode()) course_obj = models.Course.objects.get(id=course_id) if expire_id > 0: expire_obj = models.CourseExpire.objects.get(id=expire_id) 查询到每个已勾选课程的真实价格 course_real_price = course_obj.real_price(expire_id) 计算出所有课程的总真实价格 total_real_price += course_real_price data.append({ course_id:course_obj.id,1)">:course_obj.name,1)">course_img':contains.SERVER_ADDR + course_obj.course_img.url, 结算页面的每条数据都显示为每个课程的真实价格 real_price:course_real_price,1)">expire_text:expire_obj.expire_text,}) else: course_real_price = course_obj.real_price(expire_id) total_real_price += course_real_price data.append({ : course_obj.id,1)">: course_obj.name,1)">': contains.SERVER_ADDR +: course_real_price,1)">': 永久有效return Response({data':data,1)">total_real_price':total_real_price}) 2.前端发送请求 获取结算页面的数据、总价格、总真实价格 Order.vue
get_order_data(){
let token = localStorage.token ||this.$settings.Host}/cart/expires/`,{
headers:{
'Authorization':'jwt ' + 获取到课程名称、课程封面图、有效期信息等
this.course_list = res.data.data;
获取到后端发送过来的总真实价格
this.total_real_price = res.data.total_real_price;
获取到后端发送过来的总原价格
this.total_price = res.data.total_real_price;
})
},
如果选中了当期优惠劵,则应该给优惠劵设置为选中的效果 order.vue js
select_coupon(index,coupon_id){
拿到你当前点击的那条优惠劵数据
let current_c = .coupon_list[index]
if (this.total_real_price < current_c.coupon.condition){
return 'disable'
}
'/1000'拿到时间戳
let current_time = new Date() / 1000;
let s_time = new Date(current_c.start_time) / 1000
let e_time = new Date(current_c.end_time) / 1000
如果优惠劵不在活动时间范围内 则设置效果为不可选中
if (current_time < s_time || current_time > e_time){
}
如果优惠劵是当前被选中的优惠劵 则设置效果为选中
this.current_coupon === coupon_id){
return 'active'
}
return ''
},1)"> order.vue html >
watch:{
use_coupon(){
如果点击箭头收缩 那么就将优惠劵的选中状态取消
this.use_coupon === ){
this.current_coupon = 0;
}
},
order.vue ? ? 前端虽然对优惠劵进行校验,但是前端所显示的都是虚假的,后端也要对优惠劵进行校验。 ? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |