shoppe项目11----订单系统

订单模型设计

  1. 后台下单逻辑
    后台的下单逻辑是相当复杂的,这里只简单描述。
    后台接收到下订单的请求,为用户创建一个订单,此时订单会有如下几种状态:
    ‘待支付’ ,等待用户付款
    ‘待发货’, 用户付款成功,等待商户发货
    ‘待收货’,,商户已发货,等待用户收货
    ‘待评价’, 用户已确认收货, 待用户评价商品
    ‘已完成’,订单已完成,处于关闭状态
     
    实际生产环境可能会更复杂,比如,用户的退款,支付失败等。
    订单创建完成,其相关的数据存入mysql数据库,在有效期内,如果用户没有完成支付,则订单失效,自动关闭,并从mysql 删除该订单信息。

  2. 订单表结构设计
    订单表
    订单id、 varchar(100),主键
    用户、 外键
    收货地址、 外键
    总价、decimal(9,2)
    总商品数、int
    运费、decimal(7, 2)
    支付方式、char(10) (1支付宝 2银联)
    支付状态、char(10)
    创建时间、 datetime
    更新时间, datetime
     
    订单商品表
    id、int 主键
    商品id、外键
    数量、 int
    单价、decimal(7,2)
    评价、text
    评分、smallint, default =5 (0-5)
    订单id、 外键
    是否匿名评价、boolean
    是否评价 boolean

  3. 订单模型类定义

# 订单表:订单id、用户(外键)、收货地址(外键)、总价、总商品数、运费、支付方式、订单状态、创建时间
class Order(models.Model):
    order_id = models.CharField(max_length=100, primary_key=True, verbose_name='订单号') 
    user = models.ForeignKey(User, related_name='order', on_delete=models.CASCADE, verbose_name='用户') #related_name用于反向查询 user.order.all()
    
    address = models.ForeignKey(Addr, on_delete=models.CASCADE, verbose_name='收货地址')

    total_amount = models.DecimalField(max_digits=9, decimal_places=2, verbose_name='总价')
    freight = models.DecimalField(max_digits=7, decimal_places=2, verbose_name='运费')
    total_count = models.IntegerField(verbose_name='商品总数', default=1)

	pay_method = models.CharField(max_length=10, choices=((1, '支付宝'), (2, '银联')), verbose_name='支付方式')
    pay_status = models.CharField(max_length=10, choices=((0, '待支付'), (1, '待发货'), (2, '待收货'), (3, '待评价'), (4, '已完成')), verbose_name='支付状态')
    created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
	
	def __str__(self):
		return "订单:%s"%self.order_id
		
    class Meta:
        db_table = 'order_tb'
        verbose_name = '订单表'
        verbose_name_plural = verbose_name


# 订单商品表: id、商品id(外键)、数量、单价、评价、评分、订单id(外键)、是否匿名评价、是否评价
class OrderGoods(models.Model):
    """订单商品"""
    SCORE_CHOICES = (
        (0, '0分'),
        (1, '20分'),
        (2, '40分'),
        (3, '60分'),
        (4, '80分'),
        (5, '100分'),
    )
    
    good = models.ForeignKey(Good, on_delete=models.CASCADE, verbose_name="订单商品")
    count = models.IntegerField(default=1, verbose_name="数量")
    price = models.DecimalField(max_digits=7, decimal_places=2, verbose_name="单价")
    comment = models.TextField(default="", verbose_name="评价信息")
    score = models.SmallIntegerField(choices=SCORE_CHOICES, default=5, verbose_name='满意度评分')
    order = models.ForeignKey(Order, related_name='orderGood', on_delete=models.CASCADE, verbose_name="订单")
    is_anonymous = models.BooleanField(default=False, verbose_name='是否匿名评价')
    is_commented = models.BooleanField(default=False, verbose_name='是否评价')

    class Meta:
        db_table = "order_goods_table"
        verbose_name = '订单商品表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return "订单%s中的商品%s"%(self.order.order_id, self.good.sku_name)

订单确认页面

  1. 下单流程讲解
  • 在Vue的购物车页面,点击结算,跳转到Vue的订单确认页面
  • 在订单确认页面:展示用户的收货地址。向Django后端发送请求,查询所有收货地址,在Vue中循环展示。
  • 可以实现添加收货地址
  • 选择支付方式
  • 展示购物车中被选中的商品,从后端加载购物车中所有被选中的商品, 这里使用Vuex中管理的商品。
  • 点击 ‘结算’ ,向Django后端发送请求,创建订单。
  1. 收货地址添加
    在ConfirmOrder组件
<li class="add-address">
  <i class="el-icon-circle-plus-outline" @click="addAddr"></i>
  <p>添加新地址</p>
</li>


// 添加地址
addAddr(){
  console.log("正添加地址...")
  this.$store.dispatch("setAddMyAddr", true)
},
//展示添加地址组件AddMyAddr.vue
//子组件给父组件传值,使用的全局事件总线

另外还可以删除一个地址,直接发送delete请求。

  1. 收货地址确认
// ===========切换地址的选中==========
changeStatus(e, id){
  for(let i=0; i < this.address.length; i++){
    let temp = this.address[i]
    if(temp.id == id){
      temp.is_default = true
    }else{
      temp.is_default = false
    }
  }
},

订单购物信息展示

  1. 购物车选中商品展示
    可以从后端Django加载购物车中选中的商品,这里因为Vuex集中式状态管理的选中状态与后端一致,直接使用Vuex中的数据。

创建订单

  1. 创建订单的流程
    前端Vue的流程 + 后端Django的流程
// 创建订单
addOrder() {
  this.$axios
    .post("/orders/user/addOrder/", { 
      user: this.$store.getters.getUser,
      products: this.getCheckGoods, //获取勾选的商品{}
      addr: this.getSelectedAddr(),
      payMethod: this.radio, //支付方式:1支付宝 2银联卡
    })
    .then(res => {
      console.log("@@创建订单的响应:", res)
      
      let products = this.getCheckGoods
      switch (res.data.code) {
        case 200:   //多个条件执行共同代码,中间不能有间隔
        case 302:// 添加如下, 跳转到支付地址
          {
            //创建订单成功,删除前端购物车中购买的商品
            for (let i = 0; i < products.length; i++) {
              const temp = products[i];
              // 删除已经结算的购物车商品
              this.deleteShoppingCart(temp.productID);
            }
            
            // 跳转我的订单页面
            // this.$router.push({ path: "/order" });
            this.notifySucceed(res.data.msg)
            // 跳转到支付地址
            setTimeout(window.location.href = res.data.url, 2000);
          }
          break;
        default:
          this.notifyError(res.data.msg)
          
      }
    })
    .catch(err => {
      return Promise.reject(err);
    });
}
  1. Django后端创建订单
class OrderAPIView(APIView):
	@check_login
    def post(self, request):
        # 1. 获取当前登录用户
        user = request.user

        # 2. 接收前端数据products商品对象数组/addr(选中的地址id)/payMethod(str)
        goods_list = request.data.get("products")
        addr_id = request.data.get("addr")
        pay_method = request.data.get("payMethod")
		
		# 3. 准备订单数据
		# 唯一的订单编号
        order_id = datetime.now().strftime("%Y%m%d%H%M%S") + "_%s"%user.id
        # 查询地址对象
        try:
        	addr = Addr.objects.get(id=addr_id)
        except:
        	return Response({"code":204, "msg":"收货地址不存在"})
        total_amount = 0
        total_count = 0
        freight = 10
        # 4. 创建订单对象
       order = Order.objects.create(order_id=order_id, user=user, addr=addr, total_amount=total_amount, total_count=total_count, freight=freight, pay_method=pay_method, pay_status="0")
        
         # 5.
         # 创建订单商品对象,注意判断库存是否满足要求
         # 如果库存不足,就返回响应
         # 如果库存充足,正常购买,正常创建订单商品对象,并存储到数据库
         for i in goods_list:
             #i就是每一个商品字典
             try:
                 good = Good.objects.get(id=i.get("productID"))
                 origin_stock = good.stock
                 origin_count = good.count
                 #raise ValueError("商品库存不足!")

             except:
                 return Response({"code":204, "msg":"商品已下架!"})

             #对比库存
             if i.get("num") > origin_stock:
                 return Response({"code":204, "msg":"商品库存不足,无法购买!"})

             #创建订单商品对象,并保存
             OrderGoods.objects.create(good=good, count=i.get("num"), price=good.selling_price, order=order)
             # 6.
             # 更新购买商品的库存、销量。 更新一下订单里的总商品数 & 总价格
             new_stock = origin_stock - i.get("num")
             new_count = origin_count + i.get("num")
             good.stock = new_stock
             good.count = new_count
             good.save()

             total_count += i.get("num")
             total_amount += i.get("num")*i.get("selling_price")

         order.total_count = total_count
         order.total_amount = total_amount
         order.save()
         
         # 7.
         # 删除redis购物车里的已经购买的商品
         redis_conn = redis.Redis(host="localhost", port=6379, db=0)
         cart_key = "cart:%s"%user.id
         cart_selected_key = "cart_selected:%s"%user.id
         for i in goods:
             redis_conn.hdel(cart_key, i.get("productID"))
             redis_conn.srem(cart_selected_key, i.get("productID"))

         redis_conn.close()

         # 7.
         # 返回响应
         # {'code': 200, "msg": "创建订单成功!"}
		 # 201, 防止前端重定向
         return Response({"code":201, "msg":"创建订单成功!"})

  1. 后端查看订单
    在后端mysql数据库中,查看创建订单是否成功。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

laufing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值