Browse Source

添加优惠券

lex 2 years ago
parent
commit
1686fcebbf

+ 11 - 2
src/components/col-video/index.tsx

@@ -2,7 +2,7 @@ import { defineComponent, PropType } from 'vue'
 import styles from './index.module.less'
 import Plyr from 'plyr'
 import 'plyr/dist/plyr.css'
-import { Button, Icon } from 'vant'
+import { Button, Icon, Loading } from 'vant'
 
 import iconVideoPlay from '@/common/images/icon_video_play.png'
 import { browser } from '@/helpers/utils'
@@ -250,7 +250,16 @@ export default defineComponent({
             style={{
               height: this.height || '210px'
             }}
-          ></div>
+          >
+            <Loading
+              size={36}
+              color="#2dc7aa"
+              vertical
+              style={{ height: '100%', justifyContent: 'center' }}
+            >
+              加载中...
+            </Loading>
+          </div>
         )}
         {/* 试看结束 */}
         {this.trySee && this.computedSeeStatus && !this.loading && (

+ 2 - 2
src/views/coupons/index.tsx

@@ -4,11 +4,11 @@ import styles from './index.module.less'
 import List from './list'
 
 export default defineComponent({
-  name: 'coupons',
+  name: 'coupon-container',
   render() {
     return (
       <div class={styles.coupons}>
-        <Tabs color="#2DC7AA" lineWidth={44}>
+        <Tabs color="#2DC7AA" lineWidth={44} sticky>
           <Tab title="可使用">
             <List />
           </Tab>

+ 1 - 1
src/views/coupons/item.tsx

@@ -37,7 +37,7 @@ export default defineComponent({
         }}
       >
         {/* 可使用的优惠券 & 有选择按钮的 */}
-        {item.useState === 'USED' && this.isSelect && (
+        {item.useState === 'USABLE' && this.isSelect && (
           <img
             class={styles['img-icon']}
             src={item.checked ? activeIcon : inactiveIcon}

+ 11 - 11
src/views/coupons/list.tsx

@@ -68,17 +68,17 @@ export default defineComponent({
     ]
   },
   methods: {
-    onSort() {
-      this.params.page = 1
-      this.list = []
-      this.dataShow = true // 判断是否有数据
-      this.loading = false
-      this.finished = false
-      this.getList()
-    },
-    onSearch(value: string) {
-      this.onSort()
-    },
+    // onSort() {
+    //   this.params.page = 1
+    //   this.list = []
+    //   this.dataShow = true // 判断是否有数据
+    //   this.loading = false
+    //   this.finished = false
+    //   this.getList()
+    // },
+    // onSearch(value: string) {
+    //   this.onSort()
+    // },
     async getList() {
       try {
         // 判断是哪个端

+ 1 - 1
src/views/order-detail/index.module.less

@@ -30,7 +30,7 @@
 
   :global {
     .van-popup--bottom.van-popup--round {
-      border-radius: 6px 6px 0 0;
+      border-radius: 10px 10px 0 0;
     }
   }
 

+ 23 - 69
src/views/order-detail/index.tsx

@@ -17,7 +17,7 @@ import iconTips from '@common/images/icon_tips.png'
 import Payment from './payment'
 import ColHeader from '@/components/col-header'
 import { state } from '@/state'
-import { orderInfos, orderStatus } from './orderStatus'
+import { orderInfos, orderStatus, resestState } from './orderStatus'
 import OrderVideo from './order-video'
 import OrderLive from './order-live'
 import OrderPractice from './order-practice'
@@ -27,6 +27,7 @@ import { moneyFormat } from '@/helpers/utils'
 import OrderPinao from './order-pinao'
 import { getMusicDetail } from '@/student/trade/tradeOrder'
 import OrderActive from './order-active'
+import UseCoupon from './use-coupons'
 
 export default defineComponent({
   name: 'order-detail',
@@ -41,7 +42,8 @@ export default defineComponent({
       agreeStatus: false,
       popupShow: false,
       paymentStatus: false,
-      orderPrice: 0 // 支付金额
+      orderAmount: 0, // 订单金额,用于使用优惠券,余额,优惠等
+      orderPrice: 0 // 支付金额,最后支付金额
     }
   },
   unmounted() {
@@ -58,63 +60,6 @@ export default defineComponent({
       const orderObject = orderStatus.orderObject
       return orderObject.orderList || []
     }
-    // orderInfos() {
-    //   // 商品列表
-    //   const orderList = orderStatus.orderObject.orderList || []
-    //   return orderList.map((item: any) => {
-    //     const params = {
-    //       goodType: item.orderType,
-    //       goodName: item.goodsName,
-    //       recomUserId: item.recomUserId, // 推荐人id
-    //       bizContent: {}
-    //     }
-    //     if (item.orderType === 'VIDEO') {
-    //       params.bizContent = {
-    //         videoLessonGroupId: item.courseGroupId,
-    //         payMoney: item.coursePrice || 0
-    //       }
-    //     } else if (item.orderType === 'LIVE') {
-    //       params.bizContent = {
-    //         groupId: item.courseGroupId
-    //       }
-    //     } else if (item.orderType === 'PRACTICE') {
-    //       const tempTime = item.classTime || []
-    //       const classCourse: any = []
-    //       tempTime.forEach((time: any) => {
-    //         classCourse.push({
-    //           classDate: time.classDate,
-    //           startTime: time.startTime,
-    //           endTime: time.endTime
-    //         })
-    //       })
-    //       params.bizContent = {
-    //         courseGroupName: item.courseGroupName,
-    //         courseIntroduce: item.courseIntroduce,
-    //         subjectId: item.subjectId,
-    //         singleCourseMinutes: item.singleCourseMinutes,
-    //         courseNum: item.courseNum,
-    //         coursePrice: item.coursePrice,
-    //         teacherId: item.teacherId,
-    //         classTime: classCourse
-    //       }
-    //     } else if (item.orderType === 'VIP') {
-    //       params.bizContent = item.id
-    //     } else if (item.orderType === 'MUSIC') {
-    //       params.bizContent = {
-    //         musicSheetId: item.id,
-    //         actualPrice: item.actualPrice || 0,
-    //         clientType: state.platformType
-    //       }
-    //     } else if (item.orderType === 'PINAO_ROOM') {
-    //       params.bizContent = item.id
-    //     } else if (item.orderType === 'ACTI_REGIST') {
-    //       params.bizContent = {
-    //         activityId: item.activityId
-    //       }
-    //     }
-    //     return params
-    //   })
-    // }
   },
   async mounted() {
     // 判断是否是曲目购买(只有智能陪练才会有入口),其它地方不会有入口
@@ -147,6 +92,7 @@ export default defineComponent({
         //
       }
     }
+    this.orderAmount = orderStatus.orderObject.actualPrice || 0
     this.orderPrice = orderStatus.orderObject.actualPrice || 0
 
     // 0元支付特别处理
@@ -230,16 +176,17 @@ export default defineComponent({
     },
     onBackOut() {
       // 关闭订单后需要重置数据
-      orderStatus.orderObject = {
-        orderNo: '',
-        actualPrice: 0,
-        orderName: '',
-        orderDesc: '',
-        orderType: '',
-        recomUserId: null as any,
-        activityId: '',
-        orderList: []
-      }
+      resestState()
+    },
+    onCouponSelect(item: any) {
+      console.log('onCouponSelect', item)
+      const discountCount = item.map((list: any) => {
+        return Number(list.discountPrice || 0)
+      })
+      const lastAmount = Number(
+        (Number(this.orderAmount) - Number(discountCount)).toFixed(2)
+      )
+      this.orderPrice = lastAmount >= 0 ? lastAmount : 0
     }
   },
   render() {
@@ -267,6 +214,13 @@ export default defineComponent({
               }
             })}
 
+            {/* 优惠券使用 */}
+            <UseCoupon
+              orderAmount={this.orderAmount}
+              onCouponSelect={this.onCouponSelect}
+              disabled={orderStatus.orderObject.orderNo ? true : false}
+            />
+
             {/* <div class={styles.tips}>
           <h3>
             <Icon name={iconTips} size={15} />

+ 1 - 1
src/views/order-detail/order-vip/index.tsx

@@ -22,7 +22,7 @@ export default defineComponent({
         <CellGroup
           class={'mb12'}
           border={false}
-          style={{ borderRadius: '8px' }}
+          style={{ borderRadius: '8px', overflow: 'hidden' }}
         >
           <Cell
             center

+ 49 - 25
src/views/order-detail/orderStatus.ts

@@ -13,32 +13,56 @@ type orderType =
   | 'PINAO_ROOM'
   | 'ACTI_REGIST'
   | ''
-export const orderStatus = reactive({
-  orderType: '' as orderType, // 购买类型
-  // liveInfo: {} as any, // 直播购买信息
-  // videoInfo: {} as any, // 视频购买信息
-  // practiceInfo: {} as any, // 视频购买信息
-  // vipInfo: {} as any, // 会员购买信息
-  // musicInfo: {} as any, // 单曲购买信息
-  // orderList: [] as Array<any>, // 存放订单详情,可以是多个商品组合
-  orderInfo: {
-    // 订单信息
-    orderNo: '',
-    actualPrice: 0,
-    payStatus: true
-  },
-  orderObject: {
-    // 订单对象
-    orderNo: '',
-    actualPrice: 0,
-    orderName: '',
-    orderDesc: '',
-    orderType: '' as orderType,
-    recomUserId: null as any,
-    orderList: [] as Array<any>,
-    activityId: '' as any
+
+const original = () => {
+  return {
+    orderType: '' as orderType, // 购买类型
+    orderInfo: {
+      // 订单信息
+      orderNo: '',
+      actualPrice: 0,
+      payStatus: true
+    },
+    orderObject: {
+      // 订单对象
+      orderNo: '',
+      actualPrice: 0,
+      orderName: '',
+      orderDesc: '',
+      orderType: '' as orderType,
+      recomUserId: null as any,
+      orderList: [] as Array<any>,
+      activityId: '' as any
+    }
+    // orderObject: {
+    //   orderNo: '',
+    //   actualPrice: 28,
+    //   orderName: '小酷Ai月度会员',
+    //   orderDesc: '小酷Ai月度会员',
+    //   orderType: 'VIP',
+    //   recomUserId: 0,
+    //   activityId: null,
+    //   orderList: [
+    //     {
+    //       orderType: 'VIP',
+    //       goodsName: '小酷Ai月度会员',
+    //       id: 2,
+    //       title: '月度会员',
+    //       price: 28,
+    //       startTime: '2023-02-28',
+    //       endTime: '2023-03-28'
+    //     }
+    //   ]
+    // }
   }
-})
+}
+
+export const orderStatus = reactive(original())
+
+// 重置对象
+export const resestState = () => {
+  Object.assign(orderStatus, original())
+}
 
 export const orderInfos = () => {
   // 商品列表

+ 206 - 0
src/views/order-detail/use-coupons/choice-coupon.tsx

@@ -0,0 +1,206 @@
+import ColResult from '@/components/col-result'
+import Item from '@/views/coupons/item'
+import { Button, Loading } from 'vant'
+import { defineComponent } from 'vue'
+import styles from './index.module.less'
+
+export const list = [
+  {
+    couponType: 'FULL_DISCOUNT',
+    discountPrice: '2',
+    useLimit: '30',
+    endTime: new Date(),
+    id: 1,
+    name: '小酷Ai充值券',
+    startTime: new Date(),
+    useState: 'USABLE',
+    useTime: new Date()
+  },
+  {
+    couponType: 'FULL_DISCOUNT',
+    discountPrice: '5',
+    useLimit: '20',
+    endTime: new Date(),
+    id: 2,
+    name: '小酷Ai充值券',
+    startTime: new Date(),
+    useState: 'USABLE',
+    useTime: new Date()
+  },
+  {
+    couponType: 'FULL_DISCOUNT',
+    discountPrice: '3',
+    useLimit: '10',
+    endTime: new Date(),
+    id: 3,
+    name: '小酷Ai充值券',
+    startTime: new Date(),
+    useState: 'USABLE',
+    useTime: new Date()
+  },
+  {
+    couponType: 'FULL_DISCOUNT',
+    discountPrice: '1',
+    useLimit: '29',
+    endTime: new Date(),
+    id: 0,
+    name: '小酷Ai充值券',
+    startTime: new Date(),
+    useState: 'USABLE',
+    useTime: new Date()
+  }
+]
+export default defineComponent({
+  name: 'choice-coupon',
+  props: {
+    orderAmount: {
+      type: Number,
+      default: 0
+    },
+    useCoupon: {
+      type: Array,
+      default: () => []
+    }
+  },
+  emits: ['close', 'submit'],
+  data() {
+    return {
+      list: list,
+      consumeAmount: 0, // 消耗金额
+      dataLoading: false
+    }
+  },
+  computed: {
+    // 使用优惠券的数量
+    useLength() {
+      return this.list.filter((list: any) => list.checked).length || 0
+    }
+  },
+  async mounted() {
+    this.getList()
+  },
+  methods: {
+    async getList() {
+      this.dataLoading = true
+      setTimeout(() => {
+        this.dataLoading = false
+        // 处理可用优惠券是否支付使用
+        this.list.forEach((item: any) => {
+          // 如果使用金额大于订单金额则优惠券不可用
+          if (item.useLimit > this.orderAmount) {
+            item.disabled = true
+          } else {
+            item.disabled = false
+          }
+
+          // 处理显示已选择的优惠券
+          this.useCoupon.forEach((coupon: any) => {
+            if (item.id === coupon.id) {
+              item.checked = true
+            } else {
+              item.checked = false
+            }
+          })
+        })
+        // 初始化排序
+        const canUsable = this.list.filter((list: any) => !list.disabled)
+        const canUsed = this.list.filter((list: any) => list.disabled)
+        this.list = [...canUsable, ...canUsed]
+
+        this.calcCoupon()
+      }, 300)
+    },
+    onSubmit() {
+      // 返回选中的优惠券
+      this.$emit(
+        'submit',
+        this.list.filter((list: any) => list.checked)
+      )
+
+      this.list.forEach((item: any) => {
+        item.checked = false
+      })
+    },
+    onSelect(item: any) {
+      item.checked = !item.checked
+      this.calcCoupon()
+    },
+    calcCoupon() {
+      // 计算优惠券
+      // 已使用的优惠券
+      const useList = this.list.filter((list: any) => list.checked)
+      const limitCount = useList.map((list: any) => {
+        return Number(list.useLimit || 0)
+      })
+      const usePrice =
+        limitCount.length > 0
+          ? limitCount.reduce((sum: any, list: any) => {
+              return sum + list
+            })
+          : 0
+      // 使用优惠券后,可判断的金额
+      const useLastAmount = this.orderAmount - usePrice
+      // 判断使用优惠券之后还有没有其它优惠券可用
+      this.list.forEach((item: any) => {
+        if (Number(item.useLimit) >= useLastAmount && !item.checked) {
+          item.disabled = true
+        } else {
+          item.disabled = false
+        }
+      })
+    }
+  },
+  render() {
+    return (
+      <div class={styles.choiceCoupon}>
+        <div class={styles.couponTitle}>
+          <span>优惠券</span>
+          <i class={styles.iconClose} onClick={() => this.$emit('close')}></i>
+        </div>
+
+        <div class={styles.couponContent}>
+          {!this.dataLoading ? (
+            <>
+              {this.list.length > 0 ? (
+                <>
+                  {this.list.map((item: any) => (
+                    <Item item={item} isSelect onClick={this.onSelect} />
+                  ))}
+                </>
+              ) : (
+                <ColResult
+                  btnStatus={false}
+                  tips="暂无优惠券"
+                  classImgSize="SMALL"
+                />
+              )}
+            </>
+          ) : (
+            <Loading
+              size={48}
+              color="#2dc7aa"
+              vertical
+              style={{ height: '100%', justifyContent: 'center' }}
+            >
+              加载中...
+            </Loading>
+          )}
+        </div>
+
+        <div class={[styles.couponFooter, 'van-hairline--top']}>
+          <div class={styles.couponSelectText}>
+            已选<span>{this.useLength}</span>张
+          </div>
+          <Button
+            type="primary"
+            round
+            style={{ minWidth: '105px', fontSize: '16px' }}
+            onClick={this.onSubmit}
+          >
+            确定
+          </Button>
+        </div>
+      </div>
+    )
+  }
+})

+ 65 - 0
src/views/order-detail/use-coupons/index.module.less

@@ -0,0 +1,65 @@
+.useCoupon {
+  padding-top: 16px;
+  padding-bottom: 16px;
+
+  .couponCount {
+    color: #ff3535;
+    font-size: 16px;
+    font-weight: 600;
+    i {
+      font-style: normal;
+      font-size: 14px;
+    }
+  }
+}
+
+.choiceCoupon {
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+  height: 100%;
+}
+.couponTitle {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  flex-shrink: 0;
+  padding: 0 17px;
+  height: 60px;
+  line-height: 60px;
+  font-size: 18px;
+  font-weight: 600;
+  color: #1a1a1a;
+
+  .iconClose {
+    display: inline-block;
+    width: 24px;
+    height: 24px;
+    background: url('../../coupons/images/icon_close.png') no-repeat center;
+    background-size: contain;
+  }
+}
+
+.couponContent {
+  flex: 1 auto;
+  overflow-y: auto;
+  -webkit-overflow-scrolling: touch;
+  padding: 12px 14px;
+}
+
+.couponFooter {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  line-height: 56px;
+  padding: 0 16px;
+  .couponSelectText {
+    font-size: 16px;
+    color: #1a1a1a;
+    span {
+      padding: 0 9px;
+      font-weight: 600;
+      color: #fc1a19;
+    }
+  }
+}

+ 107 - 0
src/views/order-detail/use-coupons/index.tsx

@@ -0,0 +1,107 @@
+import { Cell, Popup } from 'vant'
+import { defineComponent } from 'vue'
+import ChoiceCoupon from './choice-coupon'
+import styles from './index.module.less'
+
+export default defineComponent({
+  name: 'use-conpon',
+  props: {
+    disabled: {
+      type: Boolean,
+      default: false
+    },
+    orderAmount: {
+      type: Number,
+      default: 0
+    }
+  },
+  emits: ['couponSelect'],
+  data() {
+    return {
+      popupStatus: false,
+      popupLoading: false,
+      useCouponList: [] as any,
+      useCouponCount: 1
+    }
+  },
+  computed: {
+    couponCount() {
+      const limitCount = this.useCouponList.map((list: any) => {
+        return Number(list.discountPrice || 0)
+      })
+      return limitCount.length > 0
+        ? limitCount.reduce((sum: any, list: any) => {
+            return sum + list
+          })
+        : 0
+    }
+  },
+  methods: {
+    onSubmit(item: any) {
+      // useCouponList
+      this.useCouponList = item
+      this.$emit('couponSelect', item)
+      this.popupStatus = false
+      this.popupLoading = false
+    }
+  },
+  render() {
+    return (
+      <>
+        <Cell
+          title="优惠券"
+          class={styles.useCoupon}
+          style={{ borderRadius: '8px' }}
+          isLink={!this.disabled}
+          clickable={false}
+          v-slots={{
+            value: () => (
+              <>
+                {/* 判断是否有选择优惠券 */}
+                {this.couponCount > 0 ? (
+                  <span class={styles.couponCount}>
+                    <i>-¥</i>
+                    {this.couponCount}
+                  </span>
+                ) : (
+                  <>
+                    {/* 判断是否有可以的优惠券 */}
+                    {this.useCouponCount > 0
+                      ? `${this.useCouponCount}张可使用`
+                      : '暂无可使用优惠券'}
+                  </>
+                )}
+              </>
+            )
+          }}
+          onClick={() => {
+            if (this.disabled) return
+            this.popupStatus = true
+            this.popupLoading = true
+          }}
+        ></Cell>
+
+        <Popup
+          v-model:show={this.popupStatus}
+          position="bottom"
+          round
+          safeAreaInsetBottom={true}
+          style={{ height: '75%' }}
+          onClosed={() => {
+            this.popupLoading = false
+          }}
+        >
+          {/* 优化体验 */}
+          {this.popupLoading && (
+            <ChoiceCoupon
+              useCoupon={this.useCouponList}
+              orderAmount={this.orderAmount}
+              onClose={() => (this.popupStatus = false)}
+              onSubmit={(item: any) => this.onSubmit(item)}
+            />
+          )}
+        </Popup>
+      </>
+    )
+  }
+})