Przeglądaj źródła

feat:超级订阅优惠活动

yangfeng 3 lat temu
rodzic
commit
8296d70f7e

+ 10 - 0
src/api/modules/marketing.js

@@ -31,3 +31,13 @@ export function getAppointmentInfo (data) {
     data
   })
 }
+
+// 是否已预约
+export function getIsAppointment (data) {
+  return request({
+    baseURL: '/marketing',
+    url: '/appointment/isAppointment',
+    method: 'post',
+    data
+  })
+}

BIN
src/assets/images/icon/icon-crown.png


+ 2 - 7
src/components/collect-info/CollectInfo.vue

@@ -61,7 +61,6 @@
                       @focus="companyFocus" @input="searchCompany" placeholder="请输入准确的公司名称">
                     </el-input>
                   </el-form-item>
-                  
                   <div class="company-result" v-if="showSearchResult">
                     <div class="company-list" v-for="item in companyList" :key="item" @click="selectCompany(item)"
                       v-html="item"></div>
@@ -876,7 +875,6 @@ export default {
     /*滚动条整体样式*/
     width: 6px;
     height: 1px;
-    
   }
   .user-data-dialog ::-webkit-scrollbar-thumb {
     /*滚动条里面小方块*/
@@ -1014,7 +1012,7 @@ export default {
     border-radius: 4px 4px 4px 4px;
     opacity: 1;
     margin-bottom: 10px;
-    text-align: center;  
+    text-align: center;
     display: flex;
     justify-content: center;
     align-items: center;
@@ -1024,7 +1022,6 @@ export default {
         height: 15px;
         background: url('../../assets/images/icon/icon-warning1.png') no-repeat;
         background-size: contain;
-        
         }
     .warm-text{
       // text-align: center;
@@ -1034,10 +1031,8 @@ export default {
       font-weight: 400;
       color: #F56500;
       margin-left: 2px;
-   
     }
-    }        
-  
+  }
   .dialog-footer {
     padding-top: 20px;
     text-align: center;

+ 9 - 0
src/components/common/SpecCard.vue

@@ -2,6 +2,7 @@
   <div class="spec-card" :class="{ active: active }" @click="clickCard">
     <span class="float-tip" :class="floatTipClass" v-if="showFloatTip">
       <slot name="float-tip">
+        <span class="icon-crown"></span>
         <span v-if="defaultFloatTipText">{{ defaultFloatTipText }}</span>
       </slot>
     </span>
@@ -78,6 +79,14 @@ export default {
     border-radius: 8px 2px 10px 2px;
     background-color: #2abed1;
     z-index: 9;
+    .icon-crown{
+      display: inline-block;
+      width: 12px;
+      height: 10px;
+      margin-right: 4px;
+      background: url('~@/assets/images/icon/icon-crown.png') no-repeat center;
+      background-size: cover;
+    }
   }
 }
 </style>

+ 12 - 1
src/components/coupon/BuySubmit.vue

@@ -36,7 +36,7 @@
           </el-checkbox>
         </div>
         <div class="price-submit-container">
-          <button class="price-submit" :disabled="confirmButtonDisabled" @click="buySubmit">确定支付</button>
+          <button class="price-submit" :disabled="confirmButtonDisabled" @click="buySubmit">{{submitText}}</button>
         </div>
       </div>
     </div>
@@ -88,6 +88,10 @@ export default {
     linkUnderline: {
       type: Boolean,
       default: false
+    },
+    submitText: {
+      type: String,
+      default: '确定支付'
     }
   },
   computed: {
@@ -120,6 +124,13 @@ export default {
     formatPrice,
     buySubmit () {
       this.$emit('submit')
+    },
+    changeBtnText (flag) {
+      if (flag) {
+        this.submitText = '立即抢购'
+      } else {
+        this.submitText = '确定支付'
+      }
     }
   }
 }

+ 6 - 0
src/components/coupon/CouponGiftList.vue

@@ -62,12 +62,18 @@ export default {
       const { data } = await getGiftList(info)
       if (Array.isArray(data)) {
         this.giftList = data.map(item => {
+          item.preStartTime = item.preheatingTime.toString().length === 10 ? item.preheatingTime * 1000 : item.preheatingTime
+          item.startTime = item.beginDate.toString().length === 10 ? item.beginDate * 1000 : item.beginDate
+          item.endTime = item.endDate.toString().length === 10 ? item.endDate * 1000 : item.endDate
+          item.isReceive = item.IsReceive
           const giftInfo = this.sortGiftInfo(item)
           return {
             ...item,
             giftInfo
           }
         })
+      } else {
+        this.giftList = []
       }
       this.giftListLoaded(this.giftList.length)
     },

+ 3 - 3
src/components/coupon/SpecList.vue

@@ -3,7 +3,7 @@
     <SpecCard
       v-for="spec in list"
       :key="spec.id"
-      :showFloatTip="!!spec.tipText && spec[activeType] === active"
+      :showFloatTip="!!spec.tipText"
       floatTipClass="spec-c-tip"
       :defaultFloatTipText="spec.tipText"
       :active="spec[activeType] === active"
@@ -88,8 +88,8 @@ export default {
     }
     .spec-c-tip {
       top: -10px;
-      border-radius: 2px 10px 2px 2px;
-      background: linear-gradient(90deg, #FF3A20 0%, #FF621F 100%);
+      border-radius: 9px 0;
+      background: linear-gradient(98deg, #FF7C32 0%, #F33838 100%);
     }
   }
 }

+ 83 - 12
src/components/limited-banner/index.vue

@@ -1,15 +1,17 @@
 <template>
   <div class="limited-discount">
     <div class="limited-bg">
-      <div class="limited-badge">{{ badge }}</div>
-      <div class="limited-content">{{ content }}</div>
+      <div class="limited-badge">{{ getBadge }}</div>
+      <div class="limited-content">{{ getActivityName }}</div>
       <div class="limited-countdown">
-        <LimitedCountDown :endTime="1659427812000"></LimitedCountDown>
+        <LimitedCountDown :endTime="activityTime" :startText="startText" @curTime="getCurTime"></LimitedCountDown>
       </div>
       <div class="limited-handel">
-        <div class="cycle-running" v-if="status === 0" @click.stop="$emit('subscribe')"></div>
-        <div class="cycle-already" v-if="status === 1"></div>
-        <div class="cycle-empty" v-if="status === 2"></div>
+        <div class="cycle-running" v-if="isAppointment" @click.stop="$emit('sub')"></div>
+        <div v-else>
+          <div class="cycle-already" v-if="status === 1"></div>
+          <div class="cycle-empty" v-if="status === 0 && stockNumber === 0"></div>
+        </div>
       </div>
     </div>
   </div>
@@ -23,21 +25,87 @@ export default {
     LimitedCountDown
   },
   props: {
-    badge: {
+    activityType: {
+      type: Number,
+      default: 0
+    },
+    activityName: {
       type: String,
-      default: '限时特惠'
+      default: ''
     },
-    content: {
+    activityId: {
+      type: Number,
+      default: 0
+    },
+    activityDesc: {
       type: String,
-      default: '夏季福利季月度计划一口价30元'
+      default: ''
     },
-    status: {
+    preStartTime: {
       type: Number,
-      default: 1
+      default: 0
+    },
+    startTime: {
+      type: Number,
+      default: 0
     },
     endTime: {
       type: Number,
       default: 0
+    },
+    stockNumber: {
+      type: Number,
+      default: -1
+    },
+    status: {
+      type: Number,
+      default: -1
+    }
+  },
+  data () {
+    return {
+      activityTime: this.startTime,
+      startText: '开始倒计时:',
+      getActivityName: this.activityName,
+      curTime: 0
+    }
+  },
+  computed: {
+    getBadge () {
+      const type = this.activityType
+      const title = {
+        0: '满减',
+        1: '折扣券',
+        2: '满赠',
+        3: '限时促销',
+        4: '限时折扣',
+        5: '限时减免'
+      }
+      return title[type]
+    },
+    isAppointment () {
+      // 当前时间小于活动开始时间且未预约状态且还有库存
+      return this.curTime < this.startTime && this.status === 0 && this.stockNumber > 0
+    }
+  },
+  watch: {
+    activityName (val) {
+      this.getActivityName = val
+    }
+  },
+  methods: {
+    getCurTime (data) {
+      const beginDate = this.startTime.toString().length === 10 ? this.startTime * 1000 : this.startTime
+      if (beginDate > data) {
+        this.activityTime = beginDate
+        this.startText = '开始倒计时:'
+      } else {
+        this.activityTime = this.endTime
+        this.startText = '倒计时:'
+        this.getActivityName = this.stockNumber > 0 ? `优惠仅剩${this.stockNumber}个,快抢快抢!` : '优惠名额已抢空'
+      }
+      this.curTime = data
+      this.$emit('curTime', data)
     }
   }
 }
@@ -73,10 +141,13 @@ export default {
     font-size: 18px;
   }
   .limited-countdown{
+    min-width: 240px;
+    min-height: 32px;
     padding: 7px 16px;
     background: linear-gradient(163deg, #CB1313 0%, rgba(248,36,36,0) 100%);
     border-radius: 16px;
     line-height: 18px;
+    margin-right: 16px;
   }
   .cycle-running{
     width: 112px;

+ 10 - 5
src/components/limited-countdown/index.vue

@@ -36,7 +36,7 @@ export default {
      */
     endText: {
       type: String,
-      default: '活动结束'
+      default: ''
     },
     /**
      * 时间单位为空是否展示占位
@@ -59,12 +59,15 @@ export default {
       this.countdown(val)
     }
   },
+  created () {
+    this.initAdjustTime ()
+  },
   mounted () {
     this.countdown(this.endTime)
     document.addEventListener('visibilitychange', () => {
       if (document.visibilityState === 'visible') {
-        console.log('切出当前页')
-        this.initAdjustTime()
+        // console.log('切出当前页')
+        // this.initAdjustTime()
       }
     })
   },
@@ -89,11 +92,13 @@ export default {
         return
       }
       const localCurrentTime = performance.now()
-      return Math.floor(this.serverInitTime + (localCurrentTime - this.localInitTime))
+      const curTime = Math.floor(this.serverInitTime + (localCurrentTime - this.localInitTime))
+      this.$emit('curTime', curTime)
+      return curTime
     },
     async countdown (timestamp) {
       await this.initAdjustTime()
-      console.log(this.serverInitTime, timestamp)
+      // console.log(this.serverInitTime, timestamp)
       const timer = setInterval(() => {
         const nowTime = this.getCurrentTime()
         const stopTime = timestamp.toString().length === 10 ? timestamp * 1000 : timestamp

+ 133 - 8
src/views/vipsubscribe/Buy.vue

@@ -1,6 +1,6 @@
 <template>
   <div>
-    <LimitedBanner></LimitedBanner>
+    <LimitedBanner v-if="isActivity" v-bind="activity" @sub="onSubscribe" @curTime="getCurTime"></LimitedBanner>
     <Layout class="vip-subscribe-buy" contentWithState="full" :needAd="false">
       <div class="vip-subscribe-title">{{ buyTypeText }}超级订阅</div>
       <div class="vip-subscribe-content">
@@ -54,6 +54,7 @@
             <div slot="header" class="vip-sub-item-title">赠品</div>
             <div class="vip-sub-item-content">
               <CouponGiftList
+                :parentProductId="parentProductId"
                 :productionId="specActiveItem.productionId"
                 @loaded="giftListLoaded" />
             </div>
@@ -68,6 +69,7 @@
           </SelectorCard>
         </div>
         <BuySubmit
+          ref="buySubmitRef"
           :pass="allPass"
           :productionTotal="computedPrice.total / 100"
           :productionDiscount="computedPrice.discount / 100"
@@ -96,6 +98,7 @@ import BuySubmit from '@/components/coupon/BuySubmit.vue'
 import Contrast from '@/views/vipsubscribe/components/Contrast.vue'
 import LimitedBanner from '@/components/limited-banner/index.vue'
 import { Dialog } from 'element-ui'
+import { fen2Yuan } from '@/utils/'
 
 import {
   getGoodsPrice,
@@ -103,7 +106,10 @@ import {
   getSVIPBuyInfo,
   getUserAccountInfo,
   getUserPower,
-  createCommonOrder
+  createCommonOrder,
+  getGiftList,
+  appointmentAdd,
+  getIsAppointment
 } from '@/api/modules/'
 
 export default {
@@ -186,11 +192,15 @@ export default {
           tipText: ''
         }
       ],
+      parentProductId: 101,
       computedPrice: {
         total: 0,
         discount: 0,
         pay: 0
-      }
+      },
+      isActivity: false,
+      activity: {},
+      appointmentStatus: -1 // 预约状态
     }
   },
   computed: {
@@ -278,6 +288,7 @@ export default {
     this.getGoodsPrice()
     this.getUserPower() // 获取最新的power
     this.getUserAccountInfo()
+    this.getAllGiftList()
   },
   beforeRouteEnter (to, from, next) {
     const title = document.title
@@ -384,12 +395,13 @@ export default {
       this.updatePrice()
     },
     specChange (spec) {
+      this.activity = {}
       if (this.buyType === 'upgrade') {
         spec.productionId = 1015
       }
       this.specActiveItem = spec
       this.resetCouponList()
-      this.resetGiftInfo()
+      // this.resetGiftInfo()
       this.updatePrice()
     },
     resetGiftInfo () {
@@ -409,13 +421,22 @@ export default {
       this.couponActiveItem = coupon
       this.updatePrice()
     },
-    giftListLoaded ({ list }) {
-      if (Array.isArray(list) && list.length) {
+    async giftListLoaded ({ list }) {
+      if (Array.isArray(list) && list.length > 0) {
+        this.isActivity = true
+        const activity = list[0]
+        for (const key in activity) {
+          this.activity[key] = activity[key]
+        }
+        this.activity.status = this.appointmentStatus
+        this.updatePrice()
         const gift = list[0]
-        this.specActiveItem.tipText = `加赠${gift.giftInfo}`
+        // this.specActiveItem.tipText = gift.giftInfo ? `加赠${gift.giftInfo}` : ''
         this.$set(this.specActiveItem, 'discountId', gift.discountId)
       } else {
-        this.specActiveItem.tipText = ''
+        this.isActivity = false
+        this.activity = {}
+        // this.specActiveItem.tipText = ''
         this.$set(this.specActiveItem, 'discountId', '')
       }
     },
@@ -473,6 +494,14 @@ export default {
       const params = this.getSubmitParam()
       const { data, success } = await getSelectPrice(params)
       if (success) {
+        const { reduce, promotionalPrice, discount } = this.activity
+        if (reduce) {
+          data.order_price = data.order_price - reduce
+        } else if (promotionalPrice) {
+          data.order_price = promotionalPrice
+        } else if (discount) {
+          data.order_price = data.order_price * (discount / 10)
+        }
         this.computedPrice.total = data.original_price
         this.computedPrice.pay = data.order_price
         this.computedPrice.discount = data.original_price - data.order_price
@@ -562,6 +591,102 @@ export default {
       } else {
         this.$toast(error_msg)
       }
+    },
+    async onSubscribe () {
+      const { error_msg: msg, data } = await appointmentAdd({
+        productId: this.activity.productCode,
+        useProductType: 0
+      })
+      if (data) {
+        if (data.status === 1) {
+          this.$toast('预约成功,活动开始前10分钟,将通过站内信再次通知您,请注意查收')
+        } else {
+          this.$toast(msg)
+        }
+        this.activity.status = data.status
+        this.$forceUpdate()
+      }
+    },
+    // 查所有规格商品下的特惠信息
+    async getAllGiftList () {
+      var info = {
+        useProduct: this.parentProductId,
+        useProductType: 0
+      }
+      const { data } = await getGiftList(info)
+      if (data && data.length > 0) {
+        this.getActivityStatus(data[0].activityId)
+        this.specList.forEach(v => {
+          data.forEach(s => {
+            if (v.productionId === s.productCode) {
+              if (s.time) {
+                // 赠周期
+                v.tipText = this.sortGiftInfo(s)
+              } else {
+                // 折扣、满减、特惠
+                v.tipText = this.sortActivityInfo(s)
+              }
+            }
+          })
+        })
+      } else {
+        this.specList.forEach(v => {
+          v.tipText = ''
+        })
+      }
+    },
+    sortActivityInfo (item) {
+      if (item.reduce) {
+        return `立减${fen2Yuan(item.reduce)}元`
+      } else if (item.promotionalPrice) {
+        return `特惠价${fen2Yuan(item.promotionalPrice)}元`
+      } else if (item.discount) {
+        return `${item.discount}折`
+      } else {
+        return ''
+      }
+    },
+    sortGiftInfo (gift) {
+      const info = gift
+      let timeType = ''
+      if (info.timeType === 1) {
+        timeType = '天'
+        return `${info.time}${timeType}`
+      } else if (info.timeType === 2) {
+        timeType = '月'
+        return `${info.time}个${timeType}`
+      }
+      return ''
+    },
+    // 获取活动是否已预约
+    async getActivityStatus (id) {
+      if (!id) return
+      const { data } = await getIsAppointment({
+        activityId: id
+      })
+      if (data) {
+        this.appointmentStatus = data?.status
+      } else {
+        this.appointmentStatus = -1
+      }
+    },
+    getCurTime (data) {
+      if (data > this.activity.startTime && data < this.activity.endTime) {
+        this.$nextTick(() => {
+          this.$refs.buySubmitRef.changeBtnText(true)
+        })
+      }
+      if (data >= this.activity.endTime) {
+        // 会有毫秒延迟
+        setTimeout(() => {
+          this.isActivity = false
+          this.activity = {}
+          this.getAllGiftList()
+          this.updatePrice()
+          this.$refs.buySubmitRef.changeBtnText(false)
+        }, 300)
+        this.$forceUpdate()
+      }
     }
   }
 }

+ 11 - 10
vue.config.js

@@ -28,8 +28,8 @@ module.exports = {
       //   logLevel: 'debug'
       // },
       '^/bigmember': {
-        target: 'https://jybx2-webtest.jydev.jianyu360.com',
-        // target: 'http://127.0.0.1:814',
+        // target: 'https://jybx2-webtest.jydev.jianyu360.com',
+        target: 'http://192.168.3.240:814',
         changeOrigin: true,
         logLevel: 'debug',
         pathRewrite: {
@@ -37,20 +37,20 @@ module.exports = {
         }
       },
       '^/jypay': {
-        target: 'https://jybx2-webtest.jydev.jianyu360.com',
-        // target: 'http://127.0.0.1:86',
+        // target: 'https://jybx2-webtest.jydev.jianyu360.com',
+        target: 'http://192.168.3.240:86',
         changeOrigin: true,
         logLevel: 'debug'
       },
       '^/publicapply': {
-        target: 'https://jybx2-webtest.jydev.jianyu360.com',
-        // target: 'http://127.0.0.1:828',
+        // target: 'https://jybx2-webtest.jydev.jianyu360.com',
+        target: 'http://192.168.3.240:828',
         changeOrigin: true,
         logLevel: 'debug'
       },
       '^/subscribepay': {
-        target: 'https://jybx2-webtest.jydev.jianyu360.com',
-        // target: 'http://127.0.0.1:86',
+        // target: 'https://jybx2-webtest.jydev.jianyu360.com',
+        target: 'http://192.168.3.240:86',
         changeOrigin: true,
         logLevel: 'debug'
       },
@@ -73,12 +73,13 @@ module.exports = {
         logLevel: 'debug'
       },
       '^/jyCoupon': {
-        target: 'https://jybx2-webtest.jydev.jianyu360.com',
+        // target: 'https://jybx2-webtest.jydev.jianyu360.com',
+        target: 'http://192.168.3.240:826',
         changeOrigin: true,
         logLevel: 'debug'
       },
       '^/marketing': {
-        target: 'http://192.168.3.240:709',
+        target: 'http://192.168.3.240:8077',
         changeOrigin: true,
         logLevel: 'debug'
       }