Browse Source

使用优惠券购买课程

ChengYuXuan 5 years ago
parent
commit
fc8d1b8794
6 changed files with 257 additions and 171 deletions
  1. 2 2
      src/api/_prefix.js
  2. 12 0
      src/api/coupon.js
  3. 28 12
      src/api/course.js
  4. 56 19
      src/api/order.js
  5. 146 120
      src/views/student/CourseList.vue
  6. 13 18
      src/views/student/CoursePeek.vue

+ 2 - 2
src/api/_prefix.js

@@ -5,5 +5,5 @@ export const ORDER_MODULE = `${API_VERSION}/course_order`;
 export const COURSE_WARE = `${API_VERSION}/course_ware`;
 export const FILE_MODULE = `${API_VERSION}/file`;
 export const USER_MODULE = `${API_VERSION}/user`;
-export const RECHARGE_MODULE = `${API_VERSION}/recharge`
-export const COUPON_MODULE = `${API_VERSION}/coupon`
+export const RECHARGE_MODULE = `${API_VERSION}/recharge`;
+export const COUPON_MODULE = `${API_VERSION}/coupon`;

+ 12 - 0
src/api/coupon.js

@@ -0,0 +1,12 @@
+import { COUPON_MODULE } from "@/api/_prefix";
+import axios from "axios";
+
+export const getAvailableCouponsForOrder = orderId => {
+  return axios.get(`${COUPON_MODULE}/getForOrder`, {
+    params: {
+      orderId
+    }
+  }).then(res=>res.data);
+};
+
+

+ 28 - 12
src/api/course.js

@@ -20,10 +20,12 @@ export const getCourseById = payload => {
  */
 export const getCoursesByKey = payload => {
   const { uid, key, page } = payload;
-  return axios.get(`${COURSE_MODULE}/all/${page}?uid=${uid}&key=${key}`).then(res => {
-    return res.data;
-  });
-}
+  return axios
+    .get(`${COURSE_MODULE}/all/${page}?uid=${uid}&key=${key}`)
+    .then(res => {
+      return res.data;
+    });
+};
 
 /**
  * 根据课程分类 分页获取课程列表 GET course/type/{page}?uid={uid}&type={type}
@@ -32,10 +34,12 @@ export const getCoursesByKey = payload => {
  */
 export const getCoursesByType = payload => {
   const { uid, type, page } = payload;
-  return axios.get(`${COURSE_MODULE}/type/${page}?uid=${uid}&type=${type}`).then(res => {
-    return res.data;
-  });
-}
+  return axios
+    .get(`${COURSE_MODULE}/type/${page}?uid=${uid}&type=${type}`)
+    .then(res => {
+      return res.data;
+    });
+};
 
 /**
  * 获取用户已购买的课程列表 GET course/sid/{sid}
@@ -68,14 +72,26 @@ export const createCourse = payload => {
   });
 }
 
+/**
+ * 获取热门课程
+ * @returns {Promise<*>}
+ */
 export const getHotCourses = () => {
   return axios.get(`${COURSE_MODULE}/hot/1`).then(res => {
     return res.data
   })
 }
 
+/**
+ * 点赞课程
+ * @param uid
+ * @param courseId
+ * @returns {Promise<*>}
+ */
 export const setCourseLike = (uid, courseId) => {
-  return axios.post(`${COURSE_MODULE}/like/${courseId}?uid=${uid}`).then(res => {
-    return res.data
-  })
-}
+  return axios
+    .post(`${COURSE_MODULE}/like/${courseId}?uid=${uid}`)
+    .then(res => {
+      return res.data;
+    });
+};

+ 56 - 19
src/api/order.js

@@ -3,37 +3,74 @@ import { ORDER_MODULE } from "./_prefix";
 
 /**
  * 生成课程订单(可用于购买课程或赠送课程) POST course_order/create
- * @param {*} payload status 1 - 已支付成功; 2 - 待支付(若余额足够则直接付款,并将status转为1); 3 - 已支付等待发货
- * @returns 
+ * @param {*}
+ * @returns
  */
-export const createOrder = payload => {
-  const { courseId, courseName, cost, userId, status } = payload;
-  return axios.post(`${ORDER_MODULE}/create`, {
-    courseId, courseName, cost, userId, status
-  }).then(res => {
-    return res.data;
-  });
-}
+export const createOrder = (uid,courseId) => {
+  return axios
+    .post(`${ORDER_MODULE}/create?uid=${uid}&courseId=${courseId}`)
+    .then(res => {
+      return res.data;
+    });
+};
 
 /**
  * 更新订单状态 POST course_order/update
- * @param {*} payload 
- * @returns 
+ * @param {*} payload
+ * @returns
  */
 export const updateOrder = payload => {
   const { orderId, orderStatus } = payload;
-  return axios.post(`${ORDER_MODULE}/update?orderId=${orderId}&orderStatus=${orderStatus}`).then(res => {
-    return res.data;
-  });
-}
+  return axios
+    .post(
+      `${ORDER_MODULE}/update?orderId=${orderId}&orderStatus=${orderStatus}`
+    )
+    .then(res => {
+      return res.data;
+    });
+};
 
 /**
  * 获取某用户的所有订单 GET course_order/uid/{uid}
- * @param {*} uid 
- * @returns 
+ * @param {*} uid
+ * @returns
  */
 export const getOrdersByUser = uid => {
   return axios.get(`${ORDER_MODULE}/uid/${uid}`).then(res => {
     return res.data;
   });
-}
+};
+/**
+ * 获取某一订单信息
+ * @param orderId
+ * @returns {Promise<*>}
+ */
+export const getOrderById = orderId => {
+  return axios.get(`${ORDER_MODULE}/orderId/${orderId}`).then(res => {
+    return res.data;
+  });
+};
+
+/**
+ * 使用优惠券
+ * @param order
+ * @param couponId
+ * @returns {Promise<AxiosResponse<any>>}
+ */
+export const useCoupon = (order, couponId) => {
+  return axios.post(`${ORDER_MODULE}/use_coupon?couponId=${couponId}`, order).then(res => res.data);
+};
+
+/**
+ * 取消使用优惠券
+ * @param order
+ * @param couponId
+ * @returns {Promise<AxiosResponse<any>>}
+ */
+export const cancelCoupon = (order, couponId) => {
+  return axios.post(`${ORDER_MODULE}/cancel_coupon?couponId=${couponId}`, order).then(res => res.data);
+};
+
+export const payOrder = orderId => {
+  return axios.post(`${ORDER_MODULE}/pay/${orderId}`).then(res=>res.data)
+}

+ 146 - 120
src/views/student/CourseList.vue

@@ -4,10 +4,10 @@
       <!-- 热门课程 -->
       <v-row class="mt-8 mb-2">
         <v-chip
-            class="ma-2"
-            color="deep-purple lighten-3"
-            label
-            text-color="white"
+          class="ma-2"
+          color="deep-purple lighten-3"
+          label
+          text-color="white"
         >
           <v-icon left>
             mdi-label
@@ -17,21 +17,21 @@
       </v-row>
       <v-row>
         <course-item
-            cols="12"
-            md="4"
-            v-for="course in hotCourseList"
-            :key="course.id"
-            :courseName="course.name"
-            :courseId="course.id"
-            :description="course.intro"
-            :type="course.type"
-            :cost="course.cost"
-            :bought="course.bought"
-            :manageable="course.manageable"
-            :course-color="colorList[course.id % colorList.length]"
-            :course-likes="course.likes"
-            @buy-course="showDialog"
-            @set-like="setLike"
+          cols="12"
+          md="4"
+          v-for="course in hotCourseList"
+          :key="course.id"
+          :courseName="course.name"
+          :courseId="course.id"
+          :description="course.intro"
+          :type="course.type"
+          :cost="course.cost"
+          :bought="course.bought"
+          :manageable="course.manageable"
+          :course-color="colorList[course.id % colorList.length]"
+          :course-likes="course.likes"
+          @buy-course="showDialog"
+          @set-like="setLike"
         >
         </course-item>
       </v-row>
@@ -185,27 +185,15 @@
     <!-- 购买提示对话框 -->
     <v-dialog v-model="dialog" width="1000">
       <v-card>
-        <v-card-title>购买课程</v-card-title>
-        <v-data-table
-            :headers="couponHeaders"
-            :items="coupons"
-            class="elevation-1"
-            show-select
-            @item-selected="onSelectCoupon"
-        >
-        </v-data-table>
-        <v-card-text>
-          是否花费 「{{ currentCoursePrice }}元」购买课程 「{{
-            currentCourseName
-          }}」?
-        </v-card-text>
+        <v-card-title>购买信息确认</v-card-title>
+        <v-card-text> 是否购买课程 「{{ currentCourseName }}」? </v-card-text>
 
         <v-divider></v-divider>
 
         <v-card-actions>
           <v-spacer></v-spacer>
-          <v-btn color="primary" text @click="handleBuyCourse">
-            确认
+          <v-btn color="primary" text @click="openSettleDialog">
+            选择结算方案
           </v-btn>
           <v-btn color="primary" text @click="dialog = false">
             取消
@@ -214,6 +202,30 @@
       </v-card>
     </v-dialog>
 
+    <v-dialog v-model="settleDialog" width="1000">
+      <v-card>
+        <v-card-title v-if="msg">{{ msg }}</v-card-title>
+        <div v-else>
+          <v-card-title>优惠券选择</v-card-title>
+          <v-data-table
+            :headers="couponHeaders"
+            :items="coupons"
+            class="elevation-1"
+            show-select
+            @item-selected="onSelectCoupon"
+          >
+          </v-data-table>
+          <v-row justify="center" class="mt-5"> </v-row>
+          <v-card-actions class="justify-space-around d-flex">
+            <v-alert type="info">课程原价: {{ currentOrder.origin }}</v-alert>
+            <v-alert type="success">实际付款: {{ currentOrder.cost }}</v-alert>
+            <v-btn color="primary" @click="confirmPayment">确认支付</v-btn>
+            <v-btn color="secondary" @click="leaveSettlement">离开</v-btn>
+          </v-card-actions>
+        </div>
+      </v-card>
+    </v-dialog>
+
     <!-- 购买结果 -->
     <v-dialog v-model="dialog2" width="500">
       <v-card>
@@ -233,9 +245,10 @@
         </v-card-actions>
       </v-card>
     </v-dialog>
-    <v-snackbar v-model="showLikeAlert" :color="setLikeColor" top>
-      {{ setLikeMsg }}
+    <v-snackbar v-model="showSnackBar" :color="snackBarColor" top>
+      {{ snackBarMsg }}
     </v-snackbar>
+
   </div>
 </template>
 
@@ -244,15 +257,18 @@ import CourseItem from "@/components/CourseItem.vue";
 import {
   getCoursesByType,
   getCoursesByKey,
-  getBoughtCourses, getHotCourses, setCourseLike,
+  getBoughtCourses,
+  getHotCourses,
+  setCourseLike
 } from "@/api/course";
-import { createOrder } from "@/api/order";
+import {cancelCoupon, createOrder, getOrderById, payOrder, useCoupon} from "@/api/order";
+import {getAvailableCouponsForOrder} from "@/api/coupon";
 
 export default {
   name: "StudentCourseList",
 
   components: {
-    CourseItem,
+    CourseItem
   },
 
   data() {
@@ -269,19 +285,19 @@ export default {
         name: "初级",
         totalPage: 1,
         currentPage: 1,
-        list: [],
+        list: []
       },
       medium: {
         name: "中级",
         totalPage: 1,
         currentPage: 1,
-        list: [],
+        list: []
       },
       advanced: {
         name: "高级",
         totalPage: 1,
         currentPage: 1,
-        list: [],
+        list: []
       },
       searchText: "",
       searchCourse: [],
@@ -290,10 +306,10 @@ export default {
       //
       boughtCoursesList: [],
       hotCourseList: [],
-      showLikeAlert: false,
-      setLikeMsg: '',
-      setLikeColor: 'success',
-      couponHeaders:[
+      showSnackBar: false,
+      snackBarMsg: "",
+      snackBarColor: "success",
+      couponHeaders: [
         {
           text: "优惠券名称",
           value: "name"
@@ -307,29 +323,20 @@ export default {
           value: "description"
         },
         {
-          text: "优惠额度",
-          value: "cutDown"
-        },
-        {
-          text: "优惠比例",
-          value: "discount"
+          text: "元数据",
+          value: "metadata"
         },
         {
           text: "与其他优惠券同时使用",
           value: "sharable"
-        },
+        }
       ],
-      coupons:[{
-        id: 1,
-        name:"name",
-        type:"universal",
-        description:"description",
-        cutDown: 20,
-        discount: 0,
-        sharable: false,
-        selected: false
-      }],
-      selectedCoupons:[]
+      coupons: [
+
+      ],
+      selectedCoupons: [],
+      settleDialog: false,
+      currentOrder: {}
     };
   },
 
@@ -337,19 +344,19 @@ export default {
     "primary.currentPage": {
       handler: function(val) {
         this.handleGetCoursesByType(val, "primary");
-      },
+      }
     },
 
     "medium.currentPage": {
       handler: function(val) {
         this.handleGetCoursesByType(val, "medium");
-      },
+      }
     },
 
     "advance.currentPage": {
       handler: function(val) {
         this.handleGetCoursesByType(val, "advanced");
-      },
+      }
     },
 
     searchCurrentPage: function() {
@@ -358,7 +365,7 @@ export default {
 
     searchText: function() {
       this.handleSearchCourse();
-    },
+    }
   },
 
   methods: {
@@ -368,30 +375,23 @@ export default {
       this.currentCoursePrice = coursePrice;
       this.dialog = true;
     },
-
-    handleBuyCourse() {
+    openSettleDialog() {
       const uid = window.localStorage.getItem("userId");
-      createOrder({
-        courseId: this.currentCourseId,
-        courseName: this.currentCourseName,
-        cost: this.currentCoursePrice,
-        userId: uid,
-        status: 2,
-        origin: this.currentCoursePrice
-      }).then((res) => {
+      createOrder(uid,this.currentCourseId).then(res=>{
         this.dialog = false;
-        this.msg =
-          (res.code === 1 ? "「购买成功」!" : "「购买失败」!") + res.msg;
-        this.dialog2 = true;
-        this.fetchData()
-      });
-    },
+        this.settleDialog = true;
+        this.currentOrder = res.data
 
+        getAvailableCouponsForOrder(this.currentOrder.id).then(res=>{
+          this.coupons = res.data
+          this.selectedCoupons = this.currentOrder.usedCoupons
+        })
+      })
+    },
     handleGetCoursesByType(page, type) {
       const uid = window.localStorage.getItem("userId");
       const typeMap = { primary: "初级", medium: "中级", advanced: "高级" };
-      getCoursesByType({ uid, type: typeMap[type], page }).then((res) => {
-        console.log(res);
+      getCoursesByType({ uid, type: typeMap[type], page }).then(res => {
         this[type].totalPage = res.pages;
         this[type].list = res.list;
       });
@@ -402,67 +402,93 @@ export default {
       getCoursesByKey({
         uid,
         key: this.searchText,
-        page: this.searchCurrentPage,
-      }).then((res) => {
-        console.log(res);
+        page: this.searchCurrentPage
+      }).then(res => {
         this.searchCourse = res.list;
         this.searchTotalPage = res.pages;
       });
     },
 
-    handleHotCourse(){
-      getHotCourses().then(res=>{
-        this.hotCourseList = res.list
-      })
+    handleHotCourse() {
+      getHotCourses().then(res => {
+        this.hotCourseList = res.list;
+      });
     },
 
     getUserBoughtCourses() {
       const uid = window.localStorage.getItem("userId");
-      getBoughtCourses(uid).then((res) => {
+      getBoughtCourses(uid).then(res => {
         this.boughtCoursesList = res || [];
       });
     },
 
-    fetchData(){
-      ["primary", "medium", "advanced"].forEach((t) => {
+    fetchData() {
+      ["primary", "medium", "advanced"].forEach(t => {
         this.handleGetCoursesByType(1, t);
       });
       this.handleSearchCourse();
       this.getUserBoughtCourses();
-      this.handleHotCourse()
-
+      this.handleHotCourse();
     },
 
-    onSelectCoupon({item, value}){
-      if(value){
-        this.selectedCoupons.push(item)
-      }else{
-        this.selectedCoupons = this.selectedCoupons.filter((val)=>{
-          return val.id !== item.id
+    onSelectCoupon({ item, value }) {
+      if (value) {
+        useCoupon(this.currentOrder, item.id).then((res)=>{
+          this.snackBarColor = 'success'
+          this.snackBarMsg = res.msg
+          this.showSnackBar = true
+              getOrderById(this.currentOrder.id).then(res=>{
+                this.currentOrder = res.data
+          })
+        })
+      } else {
+        cancelCoupon(this.currentOrder,item.id).then((res)=>{
+          this.snackBarColor = 'success'
+          this.snackBarMsg = res.msg
+          this.showSnackBar = true
+          getOrderById(this.currentOrder.id).then(res=>{
+            this.currentOrder = res.data
+          })
         })
       }
-      console.log(this.selectedCoupons)
     },
 
-    setLike(courseId){
-      const uid = window.localStorage.getItem('userId')
-      setCourseLike(uid, courseId).then(res=>{
-        if (res.code === 1){
-          this.setLikeMsg = res.msg
-          this.setLikeColor = 'success'
-          this.showLikeAlert = true
-          this.fetchData()
-        }else{
-          this.setLikeMsg = res.msg
-          this.setLikeColor = 'warning'
-          this.showLikeAlert = true
+    setLike(courseId) {
+      const uid = window.localStorage.getItem("userId");
+      setCourseLike(uid, courseId).then(res => {
+        if (res.code === 1) {
+          this.snackBarMsg = res.msg;
+          this.snackBarColor = "success";
+          this.showSnackBar = true;
+          this.fetchData();
+        } else {
+          this.snackBarMsg = res.msg;
+          this.snackBarColor = "warning";
+          this.showSnackBar = true;
         }
+      });
+    },
+    confirmPayment(){
+      this.settleDialog = false
+      payOrder(this.currentOrder.id).then((res)=>{
+        this.snackBarColor = 'success'
+        this.snackBarMsg = res.msg
+        this.showSnackBar = true
       })
+    },
+    leaveSettlement(){
+      this.currentOrder = {}
+      this.currentCourseId = 0
+      this.currentCoursePrice = 0
+      this.currentCourseName = ''
+      this.coupons = []
+      this.selectedCoupons = []
+      this.settleDialog = false
     }
   },
 
   mounted() {
-    this.fetchData()
-  },
+    this.fetchData();
+  }
 };
 </script>

+ 13 - 18
src/views/student/CoursePeek.vue

@@ -6,24 +6,19 @@
           <form class="pa-12 grey lighten-5 mt-8">
             <div class="d-flex justify-space-between">
               <v-text-field
-                  class="d-inline-block"
-                  v-model="courseInfo.name"
-                  label="课程名称"
-                  readonly
+                class="d-inline-block"
+                v-model="courseInfo.name"
+                label="课程名称"
+                readonly
               ></v-text-field>
-              <v-btn
-                  class="mx-2 align-self-center"
-                  fab
-                  dark
-                  small
-                  color="red"
-              >
+              <v-btn class="mx-2 align-self-center" fab dark small color="red">
                 <v-icon dark>
                   mdi-heart
                 </v-icon>
               </v-btn>
-              <span class="align-self-center">点赞: {{ courseInfo.likes }}</span>
-
+              <span class="align-self-center"
+                >点赞: {{ courseInfo.likes }}</span
+              >
             </div>
 
             <v-text-field
@@ -84,29 +79,29 @@ export default {
   data() {
     return {
       courseInfo: {},
-      types: ["初级", "中级", "高级"],
+      types: ["初级", "中级", "高级"]
     };
   },
 
   computed: {
     isCharge: function() {
       return this.courseInfo.cost !== 0;
-    },
+    }
   },
 
   methods: {
     loadCourse() {
       const { courseId } = this.$route.params;
       const uid = window.localStorage.getItem("userId");
-      getCourseById({ uid, courseId }).then((res) => {
+      getCourseById({ uid, courseId }).then(res => {
         this.courseInfo = res;
       });
-    },
+    }
   },
 
   mounted() {
     this.loadCourse();
-  },
+  }
 };
 </script>