支付和订单(3)

后端接受支付结果

支付宝会返回的参数如下列表:

http://www.luffycity.cn:8080?
charset=utf-8&
out_trade_no=2019040217080000000010976&
method=alipay.trade.page.pay.return&
total_amount=1206.44&
sign=XKJG5826fH%2F9%2B3jCWw2ODjlc%2FuGLfqmr5RnimSAqrh%2B5bFkWcbLDh5V6VYtMqCpwnYp3FuGPqEeUeRO6WK62Qz0Q5nQGOA394IdxPfTOzry7PXuwYf41PCbDq53yg7vCYrobz4Tt8uajeADJLJwIsL%2F%2B88vbDEISUDUujL4442kl3oLh3EDD8DxZc2LLsv1Z%2FEFGJMfcTA47A4T7qmjB%2BbLKJetZZBISdt9RDL0q8A%2BAfb8B3Ux1nq%2F0EiNGiwIlWC1pvUCHK2UXMJW3kmgU9P9Zoujrj4ER28oieQt6Rt4gQXeah5uYtAMkftWfZpiyu%2FjUkr6iRx%2B4mP5IFz4Uew%3D%3D&
trade_no=2019040222001439881000005802&
auth_app_id=2016091600523592&
version=1.0&
app_id=2016091600523592&
sign_type=RSA2&
seller_id=2088102175868026&
timestamp=2019-04-02%2017%3A13%3A15

后端完成 支付宝支付结果的处理并更新订单和购买记录

users/models.py,模型代码:

from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    """用户模型类"""
    mobile = models.CharField(max_length=11, unique=True, verbose_name='手机号')

    class Meta:
        db_table = 'ly_users'
        verbose_name = '用户'
        verbose_name_plural = verbose_name


from luffy.utils.models import BaseModel
from courses.models import Course
class UserCourse(BaseModel):
    pay_choices = (
        (0, '支付宝'),
        (1, '微信支付'),
        (2, '免费活动'),
        (3, '活动赠品'),
        (4, '系统赠送'),
    )
    user = models.ForeignKey(User, related_name='user_courses', on_delete=models.DO_NOTHING,verbose_name="用户")
    course = models.ForeignKey(Course, related_name='course_users', on_delete=models.DO_NOTHING, verbose_name="课程")
    buy_number = models.CharField(max_length=128, null=True, verbose_name="账单号")
    buy_type = models.SmallIntegerField(choices=pay_choices, default=0, verbose_name="购买方式")
    pay_time = models.DateTimeField(null=True, verbose_name="购买时间")
    out_time = models.DateTimeField(null=True, verbose_name="过期时间")

    class Meta:
        db_table = 'ly_user_course'
        verbose_name = '课程购买记录'
        verbose_name_plural = verbose_name

payments/views.py,视图代码:

from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from orders.models import Order
from coupon.models import UserCoupon
from alipay import AliPay
from django.conf import settings
import os
from django.db import transaction
from decimal import Decimal
import logging
log = logging.getLogger("django")
from datetime import datetime
from users.models import UserCourse

class AlipayAPIView(APIView):
    # permission_classes = [IsAuthenticated]

    def get(self,request):
        """生成支付宝支付地址"""
        # 接受参数[优惠券,订单号]
        coupon_id = request.query_params.get("coupon_id")
        order_number  = request.query_params.get("order_number")
        try:
            order = Order.objects.get(order_number=order_number)
        except Order.DoesNotExist:
            return Response({"message":"对不起,当前订单信息不存在!无法进行支付"},status=status.HTTP_400_BAD_REQUEST)

        if coupon_id != None and coupon_id != "0":
            with transaction.atomic():
                save_id = transaction.savepoint()
                # 重新计算订单实际支付价格
                try:
                    user_coupon = UserCoupon.objects.get(pk=coupon_id)
                except UserCoupon.DoesNotExist:
                    return Response({"message": "对不起,当前订单使用的优惠券不存在!无法进行支付"}, status=status.HTTP_400_BAD_REQUEST)

                if user_coupon.coupon.coupon_type == 0:
                    """折扣优惠"""
                    order.real_price = order.total_price * Decimal(user_coupon.coupon.sale[1:])
                elif user_coupon.coupon.coupon_type == 1:
                    order.real_price = order.total_price - Decimal(user_coupon.coupon.sale[1:])
                else:
                    return Response({"message": "当前优惠券无法使用!无法进行支付"}, status=status.HTTP_400_BAD_REQUEST)

                try:
                    # 经过上面的计算,保存实付价格和使用的优惠券
                    order.use_coupon = True
                    order.coupon = user_coupon.id
                    order.save()

                    # 上面的优惠券已经被使用了,所以我们需要修改优惠券的状态
                    user_coupon.is_use = True
                    user_coupon.save()

                except:
                    transaction.savepoint_rollback(save_id)
                    return Response({"message": "系统异常,无法进行支付"}, status=status.HTTP_400_BAD_REQUEST)

        # 构造支付宝支付链接地址
        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=settings.APP_NOTIFY_URL,  # 默认回调url
            app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/app_private_key.pem"),
            # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
            alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/alipay_public_key.pem"),
            sign_type="RSA2",  # RSA 或者 RSA2
            debug=settings.ALIPAY_DEBUG
        )

        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=order.order_number,
            total_amount= "%.2f" % order.real_price,
            subject=order.order_title,
            return_url=settings.ALIPAY_RETURN_URL,
            notify_url=settings.ALIPAY_NOTIFY_URL,
        )

        url = settings.APIPAY_GATEWAY + "?" + order_string

        return Response({"message":"发起支付成功","url":url})


class AlipayResult(APIView):
    def get(self,request):
        # 获取支付结果的所有参数,并转换成字典
        data = request.query_params.dict()
        # 在字典中移除sign签名
        signature = data.pop("sign")

        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=settings.APP_NOTIFY_URL,  # 默认回调url
            app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/app_private_key.pem"),
            # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
            alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/alipay_public_key.pem"),
            sign_type="RSA2",  # RSA 或者 RSA2
            debug=settings.ALIPAY_DEBUG
        )

        success = alipay.verify(data, signature)
        if success:
            # 支付成功!
            # 更新订单
            order_number = data.get("out_trade_no")
            try:
                order = Order.objects.get( order_number=order_number )
            except Order.DoesNotExist:
                log.error("订单号:%s不存在!" % order_number )
                return Response({"message": "无效的订单号"},status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            with transaction.atomic():
                save_id = transaction.savepoint()
                try:
                    order.order_status = 1
                    order.pay_time = datetime.now()
                    # order.pay_time = data.get("timestamp")
                    order.save()

                    # 课程与用户之间添加一条购买记录
                    detail_list = order.order_courses.all()
                    course_list = []
                    for detail in detail_list:

                        if detail.expire=='-1':
                            out_time = "2099-01-01 00:00:00"
                        else:
                            out_time = datetime.now().timestamp() + detail.expire * 86400
                            # 日期时间对象 = fromtimestamp(数值时间戳)
                            out_time = datetime.fromtimestamp(out_time)
                            out_time = out_time.strftime("%Y-%m-%d %H:%M:%S")

                        UserCourse.objects.create(
                            user=order.user,
                            course=detail.course,
                            buy_number=data.get("trade_no"),
                            buy_type=0,
                            pay_time=data.get("timestamp"),
                            out_time=out_time
                        )

                        course_list.append(detail.course.name)

                    return Response({"message":{
                        "pay_time": order.pay_time.strftime("%Y-%m-%d %H:%M:%S"),
                        "real_price": order.real_price,
                        "course_list":course_list,
                    }})

                except:
                    log.error("修改订单和购买记录发生异常!")
                    transaction.savepoint_rollback(save_id)
                    return Response({"message":"系统异常!"},status=status.HTTP_500_INTERNAL_SERVER_ERROR)

payments/urls.py,路由代码:

from django.urls import path,re_path
from . import views
urlpatterns = [
    path("alipay/url/",views.AlipayAPIView.as_view() ),
    path("alipay/result/",views.AlipayResult.as_view() ),
]

前端把地址栏上面返回的同步支付结果转发给服务端

Success.vue

<template>
  <div class="success">
    <Header/>
    <div class="main">
        <div class="title">
<!--          <img src="../../static/images/right.svg" alt="">-->
          <div class="success-tips">
              <p class="tips1">您已成功购买 {{order_info.course_list.length}} 门课程!</p>
              <p class="tips2">你还可以加入QQ群 <span>747556033</span> 学习交流</p>
          </div>
        </div>
        <div class="order-info">
            <p class="info1"><b>付款时间:</b><span>{{order_info.pay_time}}</span></p>
            <p class="info2"><b>付款金额:</b><span >¥{{order_info.real_price}}元</span></p>
            <p class="info3"><b>课程信息:</b><span><span>{{order_info.course_list2}}</span></span></p>
        </div>
        <div class="wechat-code">
<!--          <img src="../../static/images/server.cf99f78.png" alt="" class="er">-->
<!--          <p><img src="../../static/images/tan.svg" alt="">重要!微信扫码关注获得学习通知&amp;课程更新提醒!否则将严重影响学习进度和课程体验!</p>-->
        </div>
        <div class="study">
          <span>立即学习</span>
        </div>
    </div>
    <Footer/>
  </div>
</template>

<script>
  import Header from "./common/Header"
  import Footer from "./common/Footer"
  export default{
    name:"Success",
    data(){
      return {
        order_info:{
          course_list:[]
        }
      };
    },
    created(){
        let token = localStorage.token || sessionStorage.token;

        if(!token){
          this.$alert("对不起,您尚未登录!请登录!","警告",{
            callback(){
              _this.$router.push("/login");
            }
          })
        }

        // 转发支付结果到后端
        this.$axios.get(this.$settings.Host+"/payments/alipay/result/"+location.search,{
          headers:{
            // 注意下方的空格!!!
            "Authorization":"jwt " + token,
          },
        }).then(response=>{
          this.order_info = response.data.message;
          this.order_info.course_list2 = "";
          this.order_info.course_list.forEach(course=>{
            this.order_info.course_list2+=`《${course}》`;
          })
        }).catch(error=>{

          console.log(error.response);
        })
    },
    components:{
      Header,
      Footer,
    }
  }
</script>

<style scoped>
.success{
  padding-top: 80px;
}
.main{
    height: 100%;
    padding-top: 25px;
    padding-bottom: 25px;
    margin: 0 auto;
    width: 1200px;
    background: #fff;
}
.main .title{
    display: flex;
    -ms-flex-align: center;
    align-items: center;
    padding: 25px 40px;
    border-bottom: 1px solid #f2f2f2;
}
.main .title .success-tips{
    box-sizing: border-box;
}
.title img{
    vertical-align: middle;
    width: 60px;
    height: 60px;
    margin-right: 40px;
}
.title .success-tips{
    box-sizing: border-box;
}
.title .tips1{
    font-size: 22px;
    color: #000;
}
.title .tips2{
    font-size: 16px;
    color: #4a4a4a;
    letter-spacing: 0;
    text-align: center;
    margin-top: 10px;
}
.title .tips2 span{
    color: #ec6730;
}
.order-info{
    padding: 25px 48px;
    padding-bottom: 15px;
    border-bottom: 1px solid #f2f2f2;
}
.order-info p{
  font-family: PingFangSC-Regular;
    display: -ms-flexbox;
    display: flex;
    margin-bottom: 10px;
    font-size: 16px;
}
.order-info p b{
  font-weight: 400;
  color: #9d9d9d;
  white-space: nowrap;
}
.wechat-code{
    display: flex;
    -ms-flex-align: center;
    align-items: center;
    padding: 25px 40px;
    border-bottom: 1px solid #f2f2f2;
}
.wechat-code>img{
    width: 100px;
    height: 100px;
    margin-right: 15px;
}
.wechat-code p{
    font-family: PingFangSC-Regular;
    font-size: 14px;
    color: #d0021b;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-align: center;
    align-items: center;
}
.wechat-code p>img{
    width: 16px;
    height: 16px;
    margin-right: 10px;
}
.study{
      padding: 25px 40px;
}
.study span{
  display: block;
  width: 140px;
  height: 42px;
  text-align: center;
  line-height: 42px;
  cursor: pointer;
  background: #ffc210;
  border-radius: 6px;
  font-family: PingFangSC-Regular;
  font-size: 16px;
  color: #fff;
}
</style>

修改订单结果[新增接口接受异步支付结果]

from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from orders.models import Order
from coupon.models import UserCoupon
from alipay import AliPay
from django.conf import settings
import os
from django.db import transaction
from decimal import Decimal
import logging
log = logging.getLogger("django")
from datetime import datetime
from users.models import UserCourse

class AlipayAPIView(APIView):
    ......


class AlipayResult(APIView):
    def get(self,request):
        ......

   def post(self,request):

        data = request.data.dict()
        # 在字典中移除sign签名
        signature = data.pop("sign")

        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=settings.APP_NOTIFY_URL,  # 默认回调url
            app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/app_private_key.pem"),
            # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
            alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/alipay_public_key.pem"),
            sign_type="RSA2",  # RSA 或者 RSA2
            debug=settings.ALIPAY_DEBUG
        )

        success = alipay.verify(data, signature)
        if success:
            # 支付成功!
            # 更新订单
            order_number = data.get("out_trade_no")
            try:
                order = Order.objects.get( order_number=order_number )
            except Order.DoesNotExist:
                log.error("订单号:%s不存在!" % order_number )
                return Response({"message": "无效的订单号"},status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            with transaction.atomic():
                save_id = transaction.savepoint()
                try:
                    order.order_status = 1
                    order.pay_time = datetime.now()
                    # order.pay_time = data.get("timestamp")
                    order.save()

                    # 课程与用户之间添加一条购买记录
                    detail_list = order.order_courses.all()
                    course_list = []
                    for detail in detail_list:

                        if detail.expire=='-1':
                            out_time = "2099-01-01 00:00:00"
                        else:
                            out_time = datetime.now().timestamp() + detail.expire * 86400
                            # 日期时间对象 = fromtimestamp(数值时间戳)
                            out_time = datetime.fromtimestamp(out_time)
                            out_time = out_time.strftime("%Y-%m-%d %H:%M:%S")

                        UserCourse.objects.create(
                            user=order.user,
                            course=detail.course,
                            buy_number=data.get("trade_no"),
                            buy_type=0,
                            pay_time=data.get("timestamp"),
                            out_time=out_time
                        )

                        course_list.append(detail.course.name)

                    return Response("success", content_type="text/html")

                except:
                    log.error("修改订单和购买记录发生异常!")
                    transaction.savepoint_rollback(save_id)
                    return Response({"message":"系统异常!"},status=status.HTTP_500_INTERNAL_SERVER_ERROR)

我的订单

<template>
  <div class="user-order">
    <Header/>
    <div class="main">
        <div class="banner"></div>
          <div class="profile">
              <div class="profile-info">
                  <div class="avatar"><img class="newImg" width="100%" alt="" src="/static/img/logo@2x.png"></div>
                  <span class="user-name">Mixtea</span>
                  <span class="user-job">深圳市 | 程序员</span>
              </div>
              <ul class="my-item">
                  <li>我的账户</li>
                  <li class="active">我的订单</li>
                  <li>个人资料</li>
                  <li>账号安全</li>
              </ul>
            </div>
          <div class="user-data">
            <ul class="nav">
              <li class="order-info">订单</li>
              <li class="course-expire">有效期</li>
              <li class="course-price">课程价格</li>
              <li class="real-price">实付金额</li>
              <li class="order-status">交易状态</li>
              <li class="order-do">交易操作</li>
            </ul>
            <div class="my-order-item">
                <div class="user-data-header">
                  <span class="order-time">2019-04-02 10:27:49</span>
                  <span class="order-num">订单号:
                      <span class="my-older-number">20190402102749606</span>
                  </span>
                </div>
                <ul class="nav user-data-list">
              <li class="order-info">
                  <img src="../../static/course/1544059695.jpeg" alt="">
                  <div class="order-info-title">
                    <p class="course-title">Pycharm使用秘籍</p>
                    <p class="price-service">限时免费</p>
                  </div>
              </li>
              <li class="course-expire">永久有效</li>
              <li class="course-price">977.00</li>
              <li class="real-price">577.00</li>
              <li class="order-status">交易成功</li>
              <li class="order-do">
                <span class="btn btn2">去学习</span>
              </li>
            </ul>
            </div>
            <div class="my-order-item">
                <div class="user-data-header">
                  <span class="order-time">2019-04-02 10:27:49</span>
                  <span class="order-num">订单号:
                      <span class="my-older-number">20190402102749606</span>
                  </span>
                </div>
                <ul class="nav user-data-list">
              <li class="order-info">
                  <img src="../../static/course/1544059695.jpeg" alt="">
                  <div class="order-info-title">
                    <p class="course-title">Pycharm使用秘籍</p>
                    <p class="price-service">限时免费</p>
                  </div>
              </li>
              <li class="course-expire">永久有效</li>
              <li class="course-price">977.00</li>
              <li class="real-price">577.00</li>
              <li class="order-status">交易成功</li>
              <li class="order-do">
                <span class="btn btn2">去学习</span>
              </li>
            </ul>
            </div>
            <div class="my-order-item">
                <div class="user-data-header">
                  <span class="order-time">2019-04-02 10:27:49</span>
                  <span class="order-num">订单号:
                      <span class="my-older-number">20190402102749606</span>
                  </span>
                </div>
                <ul class="nav user-data-list">
              <li class="order-info">
                  <img src="../../static/course/1544059695.jpeg" alt="">
                  <div class="order-info-title">
                    <p class="course-title">Pycharm使用秘籍</p>
                    <p class="price-service">限时免费</p>
                  </div>
              </li>
              <li class="course-expire">永久有效</li>
              <li class="course-price">977.00</li>
              <li class="real-price">577.00</li>
              <li class="order-status">交易成功</li>
              <li class="order-do">
                <span class="btn btn2">去学习</span>
              </li>
            </ul>
            </div>
            <div class="my-order-item">
                <div class="user-data-header">
                  <span class="order-time">2019-04-02 10:27:49</span>
                  <span class="order-num">订单号:
                      <span class="my-older-number">20190402102749606</span>
                  </span>
                </div>
                <ul class="nav user-data-list">
              <li class="order-info">
                  <img src="../../static/course/1544059695.jpeg" alt="">
                  <div class="order-info-title">
                    <p class="course-title">Pycharm使用秘籍</p>
                    <p class="price-service">限时免费</p>
                  </div>
              </li>
              <li class="course-expire">永久有效</li>
              <li class="course-price">977.00</li>
              <li class="real-price">577.00</li>
              <li class="order-status">交易成功</li>
              <li class="order-do">
                <span class="btn btn2">去学习</span>
              </li>
            </ul>
            </div>
            <div class="my-order-item">
                <div class="user-data-header">
                  <span class="order-time">2019-04-02 10:27:49</span>
                  <span class="order-num">订单号:
                      <span class="my-older-number">20190402102749606</span>
                  </span>
                </div>
                <ul class="nav user-data-list">
              <li class="order-info">
                  <img src="../../static/course/1544059695.jpeg" alt="">
                  <div class="order-info-title">
                    <p class="course-title">Pycharm使用秘籍</p>
                    <p class="price-service">限时免费</p>
                  </div>
              </li>
              <li class="course-expire">永久有效</li>
              <li class="course-price">977.00</li>
              <li class="real-price">577.00</li>
              <li class="order-status">交易成功</li>
              <li class="order-do">
                <span class="btn btn2">去学习</span>
              </li>
            </ul>
            </div>
        </div>
    </div>
    <Footer/>
  </div>
</template>

<script>
  import Header from "./common/Header"
  import Footer from "./common/Footer"
  export default{
    name:"UserOrder",
    data(){
      return {
      };
    },
    components:{
      Header,
      Footer,
    }
  }
</script>

<style scoped>
.user-order{
  padding-top: 80px;
}
.main .banner{
    width: 100%;
    height: 324px;
    background: url(/static/img/my_bkging.0648ebe.png) no-repeat;
    background-size: cover;
    z-index: 1;
}
.profile{
    width: 1200px;
    margin: 0 auto;
}
.profile-info{
    text-align: center;
    margin-top: -80px;
}
.avatar{
    width: 120px;
    height: 120px;
    border-radius: 60px;
    overflow: hidden;
    margin: 0 auto;
}
.user-name{
    display: block;
    font-size: 24px;
    color: #4a4a4a;
    margin-top: 14px;
}
.user-job{
    display: block;
    font-size: 11px;
    color: #9b9b9b;
 }
.my-item{
    list-style: none;
    line-height: 1.42857143;
    color: #333;
    width: 474px;
    height: 31px;
    display: -ms-flexbox;
    display: flex;
    cursor: pointer;
    margin: 41px auto 0;
    -ms-flex-pack: justify;
    justify-content: space-between;
}
.my-item .active{
    border-bottom: 1px solid #000;
}
.user-data{
    width: 1200px;
    height: auto;
    margin: 0 auto;
    padding-top: 30px;
    border-top: 1px solid #e8e8e8;
    margin-bottom: 63px;
}
.nav{
    width: 100%;
    height: 60px;
    background: #e9e9e9;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-align: center;
    align-items: center;
}
.nav li{
    margin-left: 20px;
    margin-right: 28px;
    height: 60px;
    line-height: 60px;
    list-style: none;
    font-family: PingFangSC-Medium;
    font-size: 13px;
    color: #333;
    border-bottom: 1px solid #e9e9e9;
  width: 160px;
}
.nav .order-info{ width: 325px; }
.nav .course-expire{ width: 60px; }
.nav .course-price{ width: 130px; }
.user-data-header{
    display: flex;
    height: 44px;
    color: #4a4a4a;
    font-size: 14px;
    background: #f3f3f3;
    -ms-flex-align: center;
    align-items: center;
    font-family: PingFangSC-Regular;
}
.order-time{
    font-size: 12px;
    display: inline-block;
    margin-left: 20px;
}
.order-num{
    font-size: 12px;
    display: inline-block;
    margin-left: 29px;
}
.user-data-list{
    height: 100%;
    display: flex;
}
.user-data-list{
  background: none;
}
.user-data-list li{
    height: 60px;
    line-height: 60px;
}
.user-data-list .order-info{
    display: flex;
    align-items: center;
    margin-right: 28px;
}
.user-data-list .order-info img{
    max-width: 100px;
    max-height: 75px;
    margin-right: 22px;
}
.course-title{
    width: 203px;
    font-size: 13px;
    color: #333;
    line-height: 20px;
    font-family: PingFangSC-Medium;
    margin-top: -10px;
}
.order-info-title .price-service{
    line-height: 18px;
}
.price-service{
    font-size: 12px;
    color: #fa6240;
    padding: 0 5px;
    border: 1px solid #fa6240;
    border-radius: 4px;
    margin-top: 4px;
    position: absolute;
}
.order-info-title{
    margin-top: -10px;
}
.user-data-list .course-expire{
    font-size: 12px;
    color: #ff5502;
    font-family: PingFangSC-Medium;
    width: 60px;

    text-align: center;
}
.btn {
  width: 100px;
  height: 32px;
  font-size: 14px;
  color: #fff;
  background: #ffc210;
  border-radius: 4px;
  border: none;
  outline: none;
  font-family: PingFangSC-Medium;
  transition: all .25s ease;
  display: inline-block;
  line-height: 32px;
  text-align: center;
  cursor: pointer;
}
</style>

路由注册:

import Vue from "vue"
import Router from "vue-router"

// 导入页面组件
。。。
import User from "../components/User"
import UserOrder from "../components/UserOrder"


Vue.use(Router);

export default new Router({
  // 设置路由模式为‘history’,去掉默认的#
  mode: "history",
  routes:[
   ....
    {
      name:"User",
      path:"/my",
      component: User,
      // children:[  // 设置子路由,在父级路由对应的组件中如果存在父子公用部分页面,可以使用router-view来实现子路由
      //   {
      //     name:"UserOrder",
      //     path:"/order",
      //     component: UserOrder,
      //   }
      // ]
    },
    {
      name:"UserOrder",
      path:"/my/order",
      component: UserOrder,
    },
  ]
})

后端提供查询当前登录用户的订单列表信息。

orders/models.py,模型新增返回订单状态的文本格式

class Order(BaseModel):
    """订单记录"""
    。。。。
    def order_status_text(self):
        return self.status_choices[self.order_status][1]

users/serializers.py,序列化器,代码:

"""会员订单"""
from orders.models import Order,OrderDetail
class OrderDetailListModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrderDetail
        fields = ("price","real_price","discount_name","expire_text","course_img","course_name","course")

class OrderListModelSerializer(serializers.ModelSerializer):
    order_courses = OrderDetailListModelSerializer(many=True)
    class Meta:
        model = Order
        fields = ("order_courses","id","create_time","pay_time","order_number","real_price","total_price","order_status","order_status_text","pay_type")

class UserOrderModelSerializer(serializers.ModelSerializer):
    user_orders = OrderListModelSerializer(many=True)
    class Meta:
        model = User
        # fields = ("username","身份信息..")
        fields = ("username","user_orders")

users/views.py,视图代码:

from .serializers import UserOrderModelSerializer
from rest_framework.generics import RetrieveAPIView
from rest_framework.permissions import IsAuthenticated
class UserOrderAPIView(RetrieveAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = UserOrderModelSerializer
    queryset = User.objects.all()

users/urls.py,路由代码:

re_path(r'(?P<pk>\d+)/orders/',views.UserOrderAPIView.as_view()),

前端请求获取当前登录用户的订单信息

<template>
  <div class="user-order">
    <Header/>
    <div class="main">
        <div class="banner"></div>
          <div class="profile">
              <div class="profile-info">
                  <div class="avatar"><img class="newImg" width="100%" alt="" src="/static/img/logo@2x.png"></div>
                  <span class="user-name">{{user_info.username}}</span>
                  <span class="user-job">深圳市 | 程序员</span>
              </div>
              <ul class="my-item">
                  <li>我的账户</li>
                  <li class="active">我的订单</li>
                  <li>个人资料</li>
                  <li>账号安全</li>
              </ul>
            </div>
          <div class="user-data">
            <ul class="nav">
              <li class="order-info">订单</li>
              <li class="course-expire">有效期</li>
              <li class="course-price">课程价格</li>
              <li class="real-price">实付金额</li>
              <li class="order-status">交易状态</li>
              <li class="order-do">交易操作</li>
            </ul>
            <div class="my-order-item" v-for="order in user_info.user_orders">
                <div class="user-data-header">
                  <div class="order-time">
                    下单时间: {{new Date(order.create_time).toLocaleString()}}
                    <span style="padding-left: 20px;" v-if="order.pay_time">付款时间: {{new Date(order.pay_time).toLocaleString()}}</span>
                  </div>
                  <span class="order-num">订单号:
                      <span class="my-older-number">{{order.order_number}}</span>
                  </span>
                </div>
              <ul class="nav user-data-list" v-for="course in order.order_courses">
                <li class="order-info">
                    <img :src="$settings.Host+course.course_img" alt="">
                    <div class="order-info-title">
                      <p class="course-title">{{course.course_name}}</p>
                      <p v-if="course.discount_name" class="price-service">{{course.discount_name}}</p>
                    </div>
                </li>
                <li class="course-expire">{{course.expire_text}}</li>
                <li class="course-price">{{course.price}}</li>
                <li class="real-price">{{course.real_price}}</li>
                <li class="order-status">{{order.order_status_text}}</li>
                <li class="order-do">
                  <router-link v-if="order.order_status==1" to="/my/course" class="btn btn2">去学习</router-link>
                  <router-link v-if="order.order_status==0" :to="'/orders/'+order.order_number" class="btn btn2">去付款</router-link>
                </li>
              </ul>

            </div>

        </div>
    </div>
    <Footer/>
  </div>
</template>

<script>
  import Header from "./common/Header"
  import Footer from "./common/Footer"
  export default{
    name:"UserOrder",
    data(){
      return {
        user_info:{}
      };
    },
    created(){
        let token = localStorage.token || sessionStorage.token;
        let user_id = localStorage.user_id || sessionStorage.user_id;
        if(!token){
          this.$alert("对不起,您尚未登录!请登录!","警告",{
            callback(){
              _this.$router.push("/login");
            }
          })
        }

        this.$axios.get(this.$settings.Host+`/users/${user_id}/orders/`,{
          headers:{
            // 注意下方的空格!!!
            "Authorization":"jwt " + token,
          },
        }).then(response=>{
          this.user_info = response.data;
          console.log(this.user_info);
        }).catch(error=>{
          console.log( error.response )
        })
    },
    components:{
      Header,
      Footer,
    }
  }
</script>

<style scoped>
.user-order{
  padding-top: 80px;
}
.main .banner{
    width: 100%;
    height: 324px;
    background: url(/static/img/my_bkging.0648ebe.png) no-repeat;
    background-size: cover;
    z-index: 1;
}
.profile{
    width: 1200px;
    margin: 0 auto;
}
.profile-info{
    text-align: center;
    margin-top: -80px;
}
.avatar{
    width: 120px;
    height: 120px;
    border-radius: 60px;
    overflow: hidden;
    margin: 0 auto;
}
.user-name{
    display: block;
    font-size: 24px;
    color: #4a4a4a;
    margin-top: 14px;
}
.user-job{
    display: block;
    font-size: 11px;
    color: #9b9b9b;
 }
.my-item{
    list-style: none;
    line-height: 1.42857143;
    color: #333;
    width: 474px;
    height: 31px;
    display: -ms-flexbox;
    display: flex;
    cursor: pointer;
    margin: 41px auto 0;
    -ms-flex-pack: justify;
    justify-content: space-between;
}
.my-item .active{
    border-bottom: 1px solid #000;
}
.user-data{
    width: 1200px;
    height: auto;
    margin: 0 auto;
    padding-top: 30px;
    border-top: 1px solid #e8e8e8;
    margin-bottom: 63px;
}
.nav{
    width: 100%;
    height: 60px;
    background: #e9e9e9;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-align: center;
    align-items: center;
}
.nav li{
    margin-left: 20px;
    margin-right: 28px;
    height: 60px;
    line-height: 60px;
    list-style: none;
    font-family: PingFangSC-Medium;
    font-size: 13px;
    color: #333;
    border-bottom: 1px solid #e9e9e9;
  width: 160px;
}
.nav .order-info{ width: 325px; }
.nav .course-expire{ width: 60px; }
.nav .course-price{ width: 130px; }
.user-data-header{
    display: flex;
    height: 44px;
    color: #4a4a4a;
    font-size: 14px;
    background: #f3f3f3;
    -ms-flex-align: center;
    align-items: center;
    font-family: PingFangSC-Regular;
}
.order-time{
    font-size: 12px;
    display: inline-block;
    margin-left: 20px;
}
.order-num{
    font-size: 12px;
    display: inline-block;
    margin-left: 29px;
}
.user-data-list{
    height: 100%;
    display: flex;
}
.user-data-list{
  background: none;
}
.user-data-list li{
    height: 60px;
    line-height: 60px;
}
.user-data-list .order-info{
    display: flex;
    align-items: center;
    margin-right: 28px;
}
.user-data-list .order-info img{
    max-width: 100px;
    max-height: 75px;
    margin-right: 22px;
}
.course-title{
    width: 203px;
    font-size: 13px;
    color: #333;
    line-height: 20px;
    font-family: PingFangSC-Medium;
    margin-top: -10px;
}
.order-info-title .price-service{
    line-height: 18px;
}
.price-service{
    font-size: 12px;
    color: #fa6240;
    padding: 0 5px;
    border: 1px solid #fa6240;
    border-radius: 4px;
    margin-top: 4px;
    position: absolute;
}
.order-info-title{
    margin-top: -10px;
}
.user-data-list .course-expire{
    font-size: 12px;
    color: #ff5502;
    font-family: PingFangSC-Medium;
    width: 60px;

    text-align: center;
}
.btn {
  width: 100px;
  height: 32px;
  font-size: 14px;
  color: #fff;
  background: #ffc210;
  border-radius: 4px;
  border: none;
  outline: none;
  font-family: PingFangSC-Medium;
  transition: all .25s ease;
  display: inline-block;
  line-height: 32px;
  text-align: center;
  cursor: pointer;
}
</style>
订单状态显示分析
根据订单状态显示:
1. 如果未支付[order.order_stauts=0],则显示"去支付"按钮
2. 如果已支付[order.order_stauts=1],则显示"去学习"按钮
3. 如果未支付,并超过指定时间[12个小时],则显示"已取消" [celery+RabbitMQ / Django-crontab 定时任务 ]
   用户下单在12小时以后自动判断订单状态如果是0,则直接改成3

转载于:https://www.cnblogs.com/pankypan/p/11192014.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值