day84:luffy:优惠活动策略&用户认证&购物车商品的勾选/
目录1.课程列表页活动和真实价格计算 1.优惠活动策略的model表结构 2.课程列表页显示优惠类型名称 3.课程列表页显示真实价格 4.将优惠类型名称和真实价格显示到前端页面上 5.课程列表页显示具体结束时间 2.添加购物车/查看购物车的用户认证 3.购物车商品价格的勾选/结算 1.每个课程的真实价格显示到购物车页面上 2.勾选/非勾选应在redis中实时存储-后端接口 3.勾选/非勾选应该在前端页面重新计算价格 4.购物车列表显示-后端接口 1.课程列表页活动和真实价格计算既然提到了活动,那与之对应的肯定是优惠策略、优惠活动等等。 所以我们要为优惠活动策略单独建立表结构 1.优惠活动策略的model表结构class CourseDiscountType(BaseModel): """课程优惠类型""" name = models.CharField(max_length=32,verbose_name="优惠类型名称") remark = models.CharField(max_length=250,blank=True,null=True,1)">备注信息) Meta: db_table = ly_course_discount_type verbose_name = verbose_name_plural = " def __str__(self): return %s" % (self.name) CourseDiscount(BaseModel): 课程优惠模型 discount_type = models.ForeignKey(CourseDiscountType",on_delete=models.CASCADE,related_name='coursediscounts',1)">优惠类型) condition = models.IntegerField(blank=True,default=0,1)">满足优惠的价格条件设置参与优惠的价格门槛,表示商品必须在xx价格以上的时候才参与优惠活动,<br>如果不填,则不设置门槛") #因为有的课程不足100,你减免100,还亏钱了 sale = models.TextField(verbose_name=优惠公式 不填表示免费;<br> *号开头表示折扣价,例如*0.82表示八二折;<br> -号开头则表示减免,例如-20表示原价-20;<br> 如果需要表示满减,则需要使用 原价-优惠价格,例如表示课程价格大于100,优惠10;大于200,优惠25,格式如下:<br> 满100-10<br> 满200-25<br> ly_course_discount价格优惠策略价格优惠:%s,优惠条件:%s,优惠值:%s (self.discount_type.name,self.condition,self.sale) Activity(BaseModel): 优惠活动 name = models.CharField(max_length=150,1)">活动名称) start_time = models.DateTimeField(verbose_name=优惠策略的开始时间) end_time = models.DateTimeField(verbose_name=优惠策略的结束时间ly_activity verbose_name=商品活动 verbose_name_plural=return self.name CoursePriceDiscount(BaseModel): 课程与优惠策略的关系表 course = models.ForeignKey(Courseactiveprices课程) active = models.ForeignKey(Activityactivecourses活动) discount = models.ForeignKey(CourseDiscountdiscountcourse优惠折扣ly_course_price_dicount课程:%s,优惠活动: %s,开始时间:%s,结束时间:%s" % (self.course.name,self.active.name,self.active.start_time,self.active.end_time)
Course: def activity(self): import datetime now = datetime.datetime.now() 获取课程参加的活动名称 activity_list = self.activeprices.filter(is_show=True,is_deleted=False,active__start_time__lte=now,active__end_time__gte=now) activity_list 优惠类型名称 discount_name(self): dis_name = '' a = self.activity() if a: discount_n_list = [] for i in a: 获取课程的折扣类型名称 discount_n = i.discount.discount_type.name discount_n_list.append(discount_n) dis_name = discount_n_list[0] return dis_name 2.course/serializers.py 序列化器加入该字段 CourseModelSerializer:
field = [,discount_name]
CourseDetailModelSerializer:
field = [,discount_name]
3.drf测试:course/courses 3.课程列表页显示真实价格1.dev.py USE_TZ = False 修改时区
2.course/models.py Course: real_price(self): price = float(self.price) 获取真实价格 r_price = price a = self.activity() 获取课程对应的活动名称 if a: 如果课程参加了活动 sale = a[0].discount.sale 查看活动对应的优惠公式 condition_price = a[0].discount.condition 查看活动对应的满足优惠的价格条件 限时免费 if not sale.strip(): r_price = 0 限时折扣 *0.5 elif *' sale.strip(): if price >= condition_price: _,d = sale.split(') r_price = price * float(d) 限时减免 -100 elif sale.strip().startswith(-): ) r_price = price - 满减 满100-15 满 sale: if price >= condition_price: 只有价格满足优惠条件价格才能满减 l1 = sale.split(rn) dis_list = [] 10 50 25 l1: a,b = i[1:].split() 当商品价格(400) 满足100-200-300 应该选择满300那个优惠 float(a): dis_list.append(float(b)) max_dis = max(dis_list) 取到最大的那个满减优惠 r_price = price - max_dis 原价格-满减价格=真实价格 return r_price 3.course/serializers.py
2.课程详情页前端Detail.vue ="sale-time"p ="sale-type">{{course_data.discount_name}}p="expire">距离结束:仅剩 567 天 12小时 52分 ="second">32> 秒="course-price">活动价="discount">¥{{course_data.real_price}}="original">¥{{course_data.price}}> 5.课程列表页显示具体结束时间1.course/models.py left_time(self): datetime now = datetime.datetime.now().timestamp() 获取当前时间戳 left_t = 0 a = self.activity() 获取当前课程参加的活动 如果当前课程有参加活动 end_time = a[0].active.end_time.timestamp() 获取当前课程活动的结束时间 left_t = end_time - now 剩余时间=结束时间-当前时间 return left_t 2.序列化器放入left_time course/serializers.py Detail.vue 补充:让页面可以显示出0x分0x秒的效果→过滤器 Detail.vue--html -->
>距离结束:仅剩 {{course_data.left_time/60/60/24 | pInt}}天 Detail.vue--js filters:{ pInt(val){ let a = parseInt(val); if (a < 10){ a = `0${a}`; } a } } 2.添加购物车/查看购物车的用户认证为视图添加IsAuthenticated用户认证 ? cart/views.py AddCartView: 请求头必须携带着token permission_classes = [IsAuthenticated,] 添加用户认证 add: user_id = request.user.id 获取真实的用户id ''' request = user_obj ''' drf接口: cart/add_cart 获取不到数据,因为加了IsAuthenticated认证 添加购物车时需要携带token 否则不能添加购物车 Detail.vue 添加购物车 methods: { addCart(){ let token = localStorage.token || sessionStorage.token; (token){ this.$axios.post(`${this.$settings.Host}/users/verify/`,{ token:token,}).then((res)=>{ this.$settings.Host}/cart/add_cart/`,{ course_id:this.course_id,},{ 向后端提交数据需要加上header项,将token也要提交过去 headers:{ 'Authorization':'jwt ' + token } }).then((res)=>{ .$message.success(res.data.msg); console.log('>>>>>',.$store) this.$store.commit('add_cart',res.data.cart_length) ; console.log(.$store.state); }) }).catch((error)=>{ ...... }) } else { ...... }) } }, 查看购物车时需要携带token 否则不能添加购物车 Cart.vue 购物车页面 created() { let token = sessionStorage.token || localStorage.token; (token){ 查看购物车页面也要携带token 否则不能查看 headers:{ 'Authorization':'jwt ' + token } }) .then((res)=>{ this.cart_data_list = res.data.cart_data_list }) ..$message.error(error.response.data.msg); }) cart/views.py AddCartView: cart_list(self,request): ...... cart_data_list.append({ ...... real_price: course_obj.real_price(),...... }) ...... cartitem.vue ="cart_column column_4">¥{{cart.real_price}}> AddCartView: change_select(self,request): 拿到课程id course_id = request.data.get(course_id) 校验课程id合法性 try: models.Course.objects.get(id=course_id) except: return Response({msg': 课程不存在,不要乱搞!'},status=status.HTTP_400_BAD_REQUEST) 拿到user_id user_id = request.user.id 去redis数据库:cart conn = get_redis_connection(cart redis存数据-用集合存:用户id:勾选课程id conn.sadd(selected_cart_%s' % user_id,course_id) ':勾选成功}) cancel_select(self,request): course_id = request.data.get() status.HTTP_400_BAD_REQUEST) user_id = request.user.id conn = get_redis_connection(') 1:{1,3} conn.srem(恭喜你!少花钱了,但是你真的不学习了吗!'}) 为两个函数配置路由 cart/urls.py from django.urls path,re_path from . views urlpatterns = [ path(add_cart/postaddgetcart_listpatchchange_selectputcancel_select'})) 不同的请求方法走不同函数 ] 当用户点击前面的勾选框时,会改变selected的值 近而会被watch监听到 在监听中 无论是选中还是取消选中都会触发父级标签重新计算价格的动作(this.$emit) el-checkbox ="my_el_checkbox" v-model="cart.selected"></el-checkbox> Cartitem.vue watch:{ 'cart.selected':function (){ 添加选中 let token = localStorage.token || sessionStorage.token; if (.cart.selected){ this.$axios.patch(`${.cart.course_id,{ headers:{ 'Authorization':'jwt ' + token } }).then((res)=>.$message.success(res.data.msg); this.$emit('cal_t_p') 触发cart组件计算商品总价格的方法 })..$message.error(res.data.msg); }) } { 取消选中 this.$axios.put(`${.$message.error(res.data.msg); }) } },} 触发Cart组件(父组件)的计算商品总价格的方法 Cart.vue --> ="cart_course_list"> CartItem v-for="(value,index) in cart_data_list" :key="index" :cart="value" @cal_t_p="cal_total_price"CartItem> Cart.vue methods:{ cal_total_price(){ let t_price = 0 this.cart_data_list.forEach((v,k)=>{ v是值 k是索引 (v.selected){ t_price += v.real_price } }) this.total_price = t_price } } 4.购物车列表显示-后端接口request.user.id conn = get_redis_connection() conn.delete( user_id) ret = conn.hgetall(cart_%s' % user_id) dict {b'1': b'0',b'2': b'0'} cart_data_list = [] for cid,eid ret.items(): course_id = cid.decode(utf-8') 取出用户购物车里的课程id(redis中存着呢) expire_id = eid.decode( 取出用户购物车里的有效期id(redis中存着呢) course_obj = models.Course.objects.get(id=course_id) 根据课程id,通过ORM查询得到课程对象,在下面就可以通过课程对象.字段 取到对应课程的参数信息 cart_data_list.append({ : course_obj.id,name: course_obj.name,1)">course_img': constants.SERVER_ADDR + course_obj.course_img.url,1)">price: course_obj.price,1)">expire_id: expire_id,1)">selected': False,1)"> 默认没有勾选 }) Exception: logger.error(获取购物车数据失败) 后台数据库出问题了,请联系管理员status.HTTP_507_INSUFFICIENT_STORAGE) xxxcart_data_list: cart_data_list}) BUG:勾选两个课程 刷新页面 redis中仍然存着两个课程id ) 用户刷新页面时,从redis中删除用户对应的课程id conn.delete( user_id) ret = conn.hgetall( user_id) ...... ? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |