Explorar o código

fix(mallApp): 按活动有效期展示首页专区

- 首页秒杀/团购专区仅在 startTime 到 endTime 内展示

- 倒计时同时监听开始和结束时间,活动结束后清理定时器并隐藏专区
shizhongqi hai 1 semana
pai
achega
94b339f052
Modificáronse 1 ficheiros con 66 adicións e 5 borrados
  1. 66 5
      mallApp/src/components/home/activitySection.vue

+ 66 - 5
mallApp/src/components/home/activitySection.vue

@@ -1,10 +1,11 @@
 <!--
   店铺首页-秒杀专区/团购专区
   按 layoutCols(1/2/3) 渲染活动商品,含倒计时;秒杀按钮为「立即抢购」,团购按钮为「去开团」;
+  仅在活动有效期内(startTime~endTime)展示,未开始或结束后整块隐藏;
   点击商品/按钮跳转商品详情页(秒杀/团购下单流程暂沿用商品详情页,未来可扩展专属下单页)
 -->
 <template>
-  <view v-if="data && data.enabled == 1 && data.goods && data.goods.length" class="home-activity">
+  <view v-if="isActive && data && data.enabled == 1 && data.goods && data.goods.length" class="home-activity">
     <view class="activity-head">
       <view class="activity-head-row">
         <view class="activity-title-row">
@@ -83,6 +84,8 @@ export default {
   data() {
     return {
       countdown: { h: '00', m: '00', s: '00' },
+      /** 是否处于活动有效期,控制整块专区显隐 */
+      isActive: false,
       _timer: null
     }
   },
@@ -103,15 +106,19 @@ export default {
     }
   },
   watch: {
-    'data.endTime': {
+    // 活动起止时间变更时重算有效期与倒计时(接口刷新后同步)
+    'data.startTime': {
       immediate: true,
       handler() {
         this.restartCountdown()
       }
+    },
+    'data.endTime'() {
+      this.restartCountdown()
     }
   },
   beforeDestroy() {
-    if (this._timer) clearInterval(this._timer)
+    this.clearTimer()
   },
   methods: {
     formatPrice(val) {
@@ -133,14 +140,63 @@ export default {
         url: `/pages/goods/section-list?moduleKey=${this.type}&title=${encodeURIComponent(title)}&account=${this.account}&hdId=${this.hdId}`
       })
     },
+    /** 清除倒计时定时器,避免页面销毁或活动结束后空转 */
+    clearTimer() {
+      if (this._timer) {
+        clearInterval(this._timer)
+        this._timer = null
+      }
+    },
+    /**
+     * 重启倒计时:先立即算一次有效期,再每秒刷新;
+     * 未开始时定时器继续跑以便到点展示,结束后停表并隐藏。
+     */
     restartCountdown() {
-      if (this._timer) clearInterval(this._timer)
+      this.clearTimer()
       this.tickCountdown()
-      this._timer = setInterval(this.tickCountdown, 1000)
+      // 已结束则无需再开定时器;未开始/进行中继续每秒刷新
+      if (this._shouldKeepTimer()) {
+        this._timer = setInterval(this.tickCountdown, 1000)
+      }
+    },
+    /**
+     * 是否还需维持定时器:时间配置有效且未到结束时刻
+     * (未开始也要继续跑,以便到点自动展示)
+     * @returns {boolean}
+     */
+    _shouldKeepTimer() {
+      const start = parseInt(this.data && this.data.startTime, 10) || 0
+      const end = parseInt(this.data && this.data.endTime, 10) || 0
+      if (start <= 0 || end <= 0) return false
+      const now = Math.floor(Date.now() / 1000)
+      return now < end
     },
+    /**
+     * 按 startTime/endTime 刷新专区显隐与倒计时数字;
+     * 与后端 calcActivityStatus 一致:仅 now ∈ [start, end] 时展示。
+     */
     tickCountdown() {
+      const start = parseInt(this.data && this.data.startTime, 10) || 0
       const end = parseInt(this.data && this.data.endTime, 10) || 0
       const now = Math.floor(Date.now() / 1000)
+
+      // 无有效时间或已超过结束时间:隐藏专区并停表
+      if (start <= 0 || end <= 0 || now > end) {
+        this.isActive = false
+        this.countdown = { h: '00', m: '00', s: '00' }
+        this.clearTimer()
+        return
+      }
+
+      // 未到开始时间:暂不展示,定时器继续等待到点
+      if (now < start) {
+        this.isActive = false
+        this.countdown = { h: '00', m: '00', s: '00' }
+        return
+      }
+
+      // 活动进行中:展示专区并更新剩余时分秒
+      this.isActive = true
       let diff = end - now
       if (diff < 0) diff = 0
       const h = Math.floor(diff / 3600)
@@ -151,6 +207,11 @@ export default {
         m: String(m).padStart(2, '0'),
         s: String(s).padStart(2, '0')
       }
+      // 刚好走到结束点时下一秒会隐藏;diff 为 0 时也立即隐藏,避免残留 00:00:00
+      if (diff === 0) {
+        this.isActive = false
+        this.clearTimer()
+      }
     }
   }
 }