Просмотр исходного кода

feat(home-preview): 对齐首页预览展示效果

- 调整 hdApp 首页配置预览的商户标题、搜索、轮播、公告、活动和商品模块样式

- 新增预览所需 SVG 图标资源,并同步 mallApp 活动倒计时天数展示与购物车位置
shizhongqi 1 день назад
Родитель
Сommit
a27a191667

+ 1 - 12
hdApp/src/admin/homePageConfig/index.vue

@@ -4,7 +4,7 @@
 -->
 <template>
   <view class="app-content">
-    <view class="tip-bar">支持上下拖拽调整展示顺序</view>
+    <view class="tip-bar">点击名称进入对应模块配置页,同时支持上下拖拽调整展示顺序</view>
 
     <view class="list-wrap">
       <view
@@ -30,9 +30,6 @@
           <view class="list-title">{{ item.name }}</view>
           <view class="list-desc">{{ item.desc }}</view>
         </view>
-        <view class="list-edit" @click.stop="goEdit(item)" @touchstart.stop>
-          编辑
-        </view>
         <view class="list-switch" @click.stop @touchstart.stop>
           <switch
             :checked="item.enabled == 1"
@@ -416,14 +413,6 @@ export default {
   white-space: nowrap;
 }
 
-.list-edit {
-  flex-shrink: 0;
-  color: #09C567;
-  font-size: 28upx;
-  padding: 10upx 16upx;
-  margin-right: 4upx;
-}
-
 .list-switch {
   flex-shrink: 0;
   @include disFlex(center, center);

+ 35 - 5
hdApp/src/admin/homePageConfig/preview.vue

@@ -1,19 +1,25 @@
 <!--
   门店首页预览页
   只读展示已保存的首页配置最终效果,数据结构与顾客端 mallApp 首页完全一致(后端共用 HomePageDisplayClass),
-  用于商家在保存配置后确认展示效果,不涉及下单等交互。
+  视觉结构/样式与 mallApp pages/home/index 对齐,用于商家在保存配置后确认展示效果,不涉及下单等交互。
 -->
 <template>
   <view class="pv-page">
     <view v-if="loading" class="pv-loading">加载中...</view>
     <block v-else>
+      <!-- 仿真商户名称条:与真实首页 customNavBar 视觉一致,去掉返回按钮与状态栏占位 -->
+      <preview-shop-header-bar
+        :title="merchantName"
+        :bg-color="topNavBgColor"
+      />
       <block v-for="mod in modules" :key="mod.key">
         <template v-if="mod.enabled == 1">
           <preview-top-nav v-if="mod.key === 'topNav'" :data="pageData.topNav" />
-          <template v-else-if="mod.key === 'banner'">
+          <!-- 轮播+公告整块白底,与页面灰底区分(对齐真实首页 home-banner-block) -->
+          <view v-else-if="mod.key === 'banner'" class="pv-banner-block">
             <preview-banner-swiper :data="pageData.banner" :show-service="showService" />
             <preview-notice-bar />
-          </template>
+          </view>
           <preview-nav-grid v-else-if="mod.key === 'navGrid'" :data="pageData.navGrid" />
           <preview-activity-section v-else-if="mod.key === 'seckill'" :data="pageData.seckill" type="seckill" />
           <preview-activity-section v-else-if="mod.key === 'groupBuy'" :data="pageData.groupBuy" type="groupBuy" />
@@ -28,6 +34,7 @@
 </template>
 
 <script>
+import PreviewShopHeaderBar from './previewParts/shopHeaderBar.vue'
 import PreviewTopNav from './previewParts/topNav.vue'
 import PreviewBannerSwiper from './previewParts/bannerSwiper.vue'
 import PreviewNoticeBar from './previewParts/noticeBar.vue'
@@ -39,6 +46,7 @@ import { getHomePreview } from '@/api/home-page-config'
 export default {
   name: 'homePagePreview',
   components: {
+    PreviewShopHeaderBar,
     PreviewTopNav,
     PreviewBannerSwiper,
     PreviewNoticeBar,
@@ -56,6 +64,22 @@ export default {
     modules() {
       return (this.pageData && this.pageData.modules) || []
     },
+    /** 商户名称:来自 get-home.topNav.merchantName */
+    merchantName() {
+      const topNav = this.pageData && this.pageData.topNav
+      return (topNav && topNav.merchantName) || ''
+    },
+    /** topNav 模块是否启用(未加载完成时默认按启用处理,避免闪白) */
+    hasTopNavEnabled() {
+      if (!this.pageData) return true
+      const mod = this.modules.find((item) => item.key === 'topNav')
+      const topNav = this.pageData.topNav
+      return !!(mod && mod.enabled == 1 && topNav && topNav.enabled == 1)
+    },
+    /** 与真实首页 topNavBgColor 一致;未启用 topNav 时回落页面底色 */
+    topNavBgColor() {
+      return this.hasTopNavEnabled ? '#FFE0E6' : '#f5f5f5'
+    },
     showService() {
       const topNav = this.pageData && this.pageData.topNav
       return !!(topNav && topNav.enabled == 1 && topNav.customerServiceEnabled == 1)
@@ -84,13 +108,19 @@ export default {
 <style lang="scss" scoped>
 .pv-page {
   min-height: 100vh;
-  background: $backColor;
+  background: #f5f5f5;
 }
 .pv-loading {
   padding: 200upx 0;
   text-align: center;
   font-size: 26upx;
-  color: $fontColor3;
+  color: #999;
+}
+/* 轮播图与公告条区域:白底;flex 阻断子元素 margin 塌陷,加大公告下边距时仍露白底而非页面灰底 */
+.pv-banner-block {
+  display: flex;
+  flex-direction: column;
+  background: #ffffff;
 }
 .pv-bottom-space {
   height: 40upx;

+ 184 - 54
hdApp/src/admin/homePageConfig/previewParts/activitySection.vue

@@ -1,42 +1,54 @@
 <!--
   首页预览-秒杀专区/团购专区
-  只读展示:按 layoutCols(1/2/3) 渲染活动商品,含倒计时;秒杀按钮为「立即抢购」,团购按钮为「去开团」
+  只读展示:按 layoutCols(1/2/3) 渲染活动商品,含倒计时(支持天数);
+  仅在活动有效期内(startTime~endTime)展示,未开始或结束后整块隐藏;
+  结构/样式与 mallApp 真实首页 activitySection 完全一致,不响应点击跳转。
 -->
 <template>
-  <view v-if="data && data.enabled == 1 && data.goods && data.goods.length" class="pv-activity">
+  <view v-if="isActive && data && data.enabled == 1 && data.goods && data.goods.length" class="pv-activity">
     <view class="pv-activity-head">
-      <view class="pv-activity-title-row">
-        <text class="pv-activity-title">{{ data.title || (isGroupBuy ? '团购优惠' : '限时秒杀') }}</text>
-        <view v-if="data.showCountdown == 1 && data.status == 1" class="pv-countdown">
-          <text class="pv-countdown-unit">{{ countdown.h }}</text>
-          <text class="pv-countdown-colon">:</text>
-          <text class="pv-countdown-unit">{{ countdown.m }}</text>
-          <text class="pv-countdown-colon">:</text>
-          <text class="pv-countdown-unit">{{ countdown.s }}</text>
+      <view class="pv-activity-head-row">
+        <view class="pv-activity-title-row">
+          <text class="pv-activity-title">{{ data.title || (isGroupBuy ? '团购优惠' : '限时秒杀') }}</text>
+          <view v-if="data.showCountdown == 1 && data.status == 1" class="pv-countdown">
+            <!-- 剩余超过 24 小时时展示「天」单位,避免小时数无限增大 -->
+            <template v-if="countdown.showDay">
+              <text class="pv-countdown-unit">{{ countdown.d }}</text>
+              <text class="pv-countdown-day">天</text>
+            </template>
+            <text class="pv-countdown-unit">{{ countdown.h }}</text>
+            <text class="pv-countdown-colon">:</text>
+            <text class="pv-countdown-unit">{{ countdown.m }}</text>
+            <text class="pv-countdown-colon">:</text>
+            <text class="pv-countdown-unit">{{ countdown.s }}</text>
+          </view>
         </view>
+        <text v-if="showMore" class="pv-section-more">更多 ></text>
       </view>
-      <text class="pv-activity-more">{{ data.subtitle || (isGroupBuy ? '多人拼团更实惠' : '每日精选 限时特惠') }}</text>
+      <text class="pv-activity-subtitle">{{ data.subtitle || (isGroupBuy ? '多人拼团更实惠' : '每日精选 限时特惠') }}</text>
     </view>
 
-    <!-- 1排1列:横向列表 -->
+    <!-- 1排1列:左图右文,底部价格与按钮同行 -->
     <view v-if="cols === 1" class="pv-list-1">
-      <view v-for="g in data.goods" :key="g.goodsId" class="pv-row-card">
+      <view v-for="g in data.goods" :key="g.id || g.goodsId" class="pv-row-card">
         <image class="pv-row-cover" :src="g.coverUrl" mode="aspectFill" />
-        <view class="pv-row-body">
+        <view class="pv-row-content">
           <text class="pv-row-name">{{ g.name }}</text>
           <text class="pv-row-desc">{{ isGroupBuy ? (g.groupSize + '人团') : '限时特惠' }}</text>
+          <view class="pv-row-bottom">
+            <view class="pv-row-price-wrap">
+              <text class="pv-price">¥{{ formatPrice(g.price) }}</text>
+              <text class="pv-origin-price">¥{{ formatPrice(g.originPrice) }}</text>
+            </view>
+            <view class="pv-action-btn">{{ actionText }} ></view>
+          </view>
         </view>
-        <view class="pv-row-price-wrap">
-          <text class="pv-price">¥{{ formatPrice(g.price) }}</text>
-          <text class="pv-origin-price">¥{{ formatPrice(g.originPrice) }}</text>
-        </view>
-        <view class="pv-action-btn">{{ actionText }} ></view>
       </view>
     </view>
 
     <!-- 1排2列 / 1排3列:网格 -->
-    <view v-else class="pv-grid" :class="'cols-' + cols">
-      <view v-for="g in data.goods" :key="g.goodsId" class="pv-grid-card">
+    <view v-else class="pv-goods-grid" :class="'cols-' + cols">
+      <view v-for="g in data.goods" :key="g.id || g.goodsId" class="pv-grid-card">
         <view class="pv-grid-cover-wrap">
           <image class="pv-grid-cover" :src="g.coverUrl" mode="aspectFill" />
           <view v-if="isGroupBuy" class="pv-group-badge">{{ g.groupSize }}人团</view>
@@ -68,7 +80,10 @@ export default {
   },
   data() {
     return {
-      countdown: { h: '00', m: '00', s: '00' },
+      // showDay:剩余 ≥24h 时展示天;d/h/m/s 为补零后的展示字符串
+      countdown: { showDay: false, d: '00', h: '00', m: '00', s: '00' },
+      /** 是否处于活动有效期,控制整块专区显隐 */
+      isActive: false,
       _timer: null
     }
   },
@@ -82,18 +97,26 @@ export default {
     cols() {
       const c = parseInt(this.data && this.data.layoutCols, 10)
       return [1, 2, 3].includes(c) ? c : 3
+    },
+    /** 展示数量小于商品总数时显示「更多」文案(预览只读,不可点击) */
+    showMore() {
+      return Number(this.data && this.data.goodsTotal || 0) > ((this.data && this.data.goods) || []).length
     }
   },
   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) {
@@ -101,24 +124,82 @@ export default {
       if (isNaN(n)) return '0'
       return n % 1 === 0 ? String(n) : n.toFixed(2)
     },
+    /** 清除倒计时定时器,避免页面销毁或活动结束后空转 */
+    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] 时展示;
+     * 剩余 ≥24h 时拆出天单位,小时限制在 0–23。
+     */
     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 = { showDay: false, d: '00', h: '00', m: '00', s: '00' }
+        this.clearTimer()
+        return
+      }
+
+      // 未到开始时间:暂不展示,定时器继续等待到点
+      if (now < start) {
+        this.isActive = false
+        this.countdown = { showDay: false, d: '00', h: '00', m: '00', s: '00' }
+        return
+      }
+
+      // 活动进行中:展示专区并更新剩余天/时/分/秒(≥24h 拆出天)
+      this.isActive = true
       let diff = end - now
       if (diff < 0) diff = 0
-      const h = Math.floor(diff / 3600)
+      const d = Math.floor(diff / 86400)
+      const h = Math.floor((diff % 86400) / 3600)
       const m = Math.floor((diff % 3600) / 60)
       const s = diff % 60
       this.countdown = {
+        showDay: d > 0,
+        d: String(d).padStart(2, '0'),
         h: String(h).padStart(2, '0'),
         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()
+      }
     }
   }
 }
@@ -126,17 +207,24 @@ export default {
 
 <style lang="scss" scoped>
 .pv-activity {
-  margin: 20upx 20upx 0;
+  margin-top: 3upx;
   padding: 24upx;
-  border-radius: 16upx;
   background: #fff;
   box-shadow: 0 4upx 20upx rgba(255, 107, 136, 0.08);
 }
 .pv-activity-head {
   margin-bottom: 20upx;
 }
+.pv-activity-head-row {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
 .pv-activity-title-row {
-  @include disFlex(center, space-between);
+  display: flex;
+  align-items: center;
+  flex: 1;
+  min-width: 0;
 }
 .pv-activity-title {
   font-size: 32upx;
@@ -144,7 +232,9 @@ export default {
   color: #FF4D6D;
 }
 .pv-countdown {
-  @include disFlex(center, flex-end);
+  display: flex;
+  align-items: center;
+  margin-left: 22upx;
 }
 .pv-countdown-unit {
   min-width: 44upx;
@@ -161,16 +251,29 @@ export default {
   color: #FF4D6D;
   font-weight: 700;
 }
-.pv-activity-more {
+.pv-countdown-day {
+  margin: 0 6upx 0 4upx;
+  font-size: 22upx;
+  color: #FF4D6D;
+  font-weight: 700;
+}
+.pv-section-more {
+  flex-shrink: 0;
+  margin-left: 16upx;
+  font-size: 22upx;
+  color: #999;
+}
+.pv-activity-subtitle {
   display: block;
   margin-top: 8upx;
   font-size: 22upx;
-  color: $fontColor3;
+  color: #999;
 }
 
-/* 1排1列 */
+/* 1排1列:左图 + 右侧标题/描述/价格按钮 */
 .pv-row-card {
-  @include disFlex(center, flex-start);
+  display: flex;
+  align-items: center;
   padding: 16upx 0;
   border-bottom: 1px solid #f5f5f5;
   &:last-child {
@@ -184,61 +287,87 @@ export default {
   flex-shrink: 0;
   background: #f5f5f5;
 }
-.pv-row-body {
+.pv-row-content {
   flex: 1;
   min-width: 0;
-  padding: 0 16upx;
+  margin-left: 16upx;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  min-height: 140upx;
 }
 .pv-row-name {
   display: block;
-  font-size: 28upx;
+  font-size: 30upx;
   color: #333;
-  font-weight: 600;
-  margin-bottom: 8upx;
+  font-weight: 700;
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
 }
 .pv-row-desc {
+  display: block;
+  margin-top: 8upx;
   font-size: 22upx;
-  color: $fontColor3;
+  color: #999;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+.pv-row-bottom {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-top: 12upx;
 }
 .pv-row-price-wrap {
-  flex-shrink: 0;
-  text-align: right;
-  margin-right: 16upx;
+  display: flex;
+  align-items: baseline;
+  flex: 1;
+  min-width: 0;
+  margin-right: 12upx;
 }
-.pv-price {
-  display: block;
-  font-size: 30upx;
+.pv-row-price-wrap .pv-price {
+  font-size: 36upx;
   color: #FF4D6D;
   font-weight: 700;
+  margin-right: 8upx;
 }
-.pv-origin-price {
+.pv-row-price-wrap .pv-origin-price {
   font-size: 22upx;
   color: #bbb;
   text-decoration: line-through;
 }
 .pv-action-btn {
   flex-shrink: 0;
-  padding: 12upx 22upx;
-  font-size: 24upx;
+  padding: 10upx 20upx;
+  font-size: 22upx;
   color: #fff;
   background: linear-gradient(135deg, #FF8FA3, #FF4D6D);
   border-radius: 30upx;
   white-space: nowrap;
 }
+.pv-price {
+  font-size: 30upx;
+  color: #FF4D6D;
+  font-weight: 700;
+}
+.pv-origin-price {
+  font-size: 22upx;
+  color: #bbb;
+  text-decoration: line-through;
+}
 
 /* 网格 2/3 列 */
-.pv-grid {
+.pv-goods-grid {
   display: flex;
   flex-wrap: wrap;
   margin: 0 -8upx;
 }
-.pv-grid.cols-2 .pv-grid-card {
+.pv-goods-grid.cols-2 .pv-grid-card {
   width: 50%;
 }
-.pv-grid.cols-3 .pv-grid-card {
+.pv-goods-grid.cols-3 .pv-grid-card {
   width: 33.33%;
 }
 .pv-grid-card {
@@ -281,7 +410,8 @@ export default {
   white-space: nowrap;
 }
 .pv-grid-price-row {
-  @include disFlex(center, flex-start);
+  display: flex;
+  align-items: center;
   margin-top: 6upx;
 }
 .pv-grid-btn {

+ 17 - 10
hdApp/src/admin/homePageConfig/previewParts/bannerSwiper.vue

@@ -1,21 +1,28 @@
 <!--
   首页预览-轮播图
-  只读展示:按配置的轮播间隔自动播放;右下角客服悬浮图标按顶部导航的客服开关显隐
+  只读展示:按配置的轮播间隔自动播放,底部圆点指示器与真实首页一致;
+  右下角客服悬浮图标按顶部导航的客服开关显隐,不响应点击跳转。
 -->
 <template>
   <view v-if="data && data.enabled == 1 && data.list && data.list.length" class="pv-banner-wrap">
+    <!-- 底部圆点指示器:高亮色与首页统一粉红(同加购按钮 #FF4D6D) -->
     <swiper
       class="pv-swiper"
       circular
       :autoplay="true"
       :interval="(data.interval || 3) * 1000"
       duration="500"
+      indicator-dots
+      indicator-color="rgba(255, 255, 255, 0.55)"
+      indicator-active-color="#FF4D6D"
     >
-      <swiper-item v-for="(item, index) in data.list" :key="'banner-' + index">
+      <swiper-item v-for="(item, index) in data.list" :key="index">
         <image class="pv-banner-img" :src="item.imgUrl" mode="aspectFill" />
       </swiper-item>
     </swiper>
-    <view v-if="showService" class="pv-service-float">🎧</view>
+    <view v-if="showService" class="pv-service-float">
+      <zui-svg-icon icon="general-customerService" :width="24" :height="24" style="margin-top: 2upx" />
+    </view>
   </view>
 </template>
 
@@ -49,13 +56,13 @@ export default {
 }
 .pv-service-float {
   position: absolute;
-  right: 20upx;
-  bottom: 20upx;
-  width: 76upx;
-  height: 76upx;
-  line-height: 76upx;
-  text-align: center;
-  font-size: 34upx;
+  right: 10upx;
+  bottom: 10upx;
+  width: 70upx;
+  height: 70upx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
   border-radius: 50%;
   background: rgba(255, 255, 255, 0.92);
   box-shadow: 0 4upx 16upx rgba(0, 0, 0, 0.15);

+ 58 - 36
hdApp/src/admin/homePageConfig/previewParts/goodsSection.vue

@@ -1,12 +1,13 @@
 <!--
   首页预览-热门推荐/今日上新/下拉商品
-  只读展示:按 layoutCols(1/2/3) 渲染已解析出的真实商品列表
+  只读展示:按 layoutCols(1/2/3) 渲染已解析出的真实商品列表;
+  结构/样式与 mallApp 真实首页 goodsSection 完全一致,不响应加购/详情跳转。
 -->
 <template>
   <view v-if="data && data.enabled == 1 && data.goods && data.goods.length" class="pv-goods-section">
     <view class="pv-section-head">
       <text class="pv-section-title">{{ data.name }}</text>
-      <text class="pv-section-more">更多 ></text>
+      <text v-if="showMore" class="pv-section-more">更多 ></text>
     </view>
 
     <!-- 1排1列:横向列表 -->
@@ -23,17 +24,23 @@
     </view>
 
     <!-- 1排2列 / 1排3列:网格 -->
-    <view v-else class="pv-grid" :class="'cols-' + cols">
+    <view v-else class="pv-goods-grid" :class="'cols-' + cols">
       <view v-for="g in data.goods" :key="g.id" class="pv-grid-card">
         <view class="pv-grid-cover-wrap">
           <image class="pv-grid-cover" :src="g.coverUrl" mode="aspectFill" />
-          <view v-if="cols === 2" class="pv-add-btn-float">+</view>
         </view>
-        <text class="pv-grid-name">{{ g.name }}</text>
-        <view class="pv-grid-bottom-row">
-          <text class="pv-price">¥{{ formatPrice(g.price) }}</text>
-          <text v-if="cols === 2" class="pv-sold">已售 {{ formatSold(g.sold) }}</text>
-          <view v-if="cols === 3" class="pv-cart-icon">🛒</view>
+        <view class="pv-grid-info">
+          <text class="pv-grid-name">{{ g.name }}</text>
+          <view class="pv-grid-bottom-row">
+            <view class="pv-grid-price-col">
+              <text class="pv-price">¥{{ formatPrice(g.price) }}</text>
+              <text class="pv-sold">已售 {{ formatSold(g.sold) }}</text>
+            </view>
+            <!-- 加购:圆形底 + 白色购物车 SVG,与设计稿/真实首页一致,预览只读不响应 -->
+            <view class="pv-cart-icon">
+              <zui-svg-icon icon="general-cartFull" :width="16" :height="16" color="#fff" style="margin-top: 6upx" />
+            </view>
+          </view>
         </view>
       </view>
     </view>
@@ -53,6 +60,10 @@ export default {
     cols() {
       const c = parseInt(this.data && this.data.layoutCols, 10)
       return [1, 2, 3].includes(c) ? c : 3
+    },
+    /** 展示数量小于商品总数时显示「更多」文案(预览只读,不可点击) */
+    showMore() {
+      return Number(this.data && this.data.goodsTotal || 0) > ((this.data && this.data.goods) || []).length
     }
   },
   methods: {
@@ -72,13 +83,14 @@ export default {
 
 <style lang="scss" scoped>
 .pv-goods-section {
-  margin: 20upx 20upx 0;
+  margin-top: 3upx;
   padding: 24upx;
-  border-radius: 16upx;
   background: #fff;
 }
 .pv-section-head {
-  @include disFlex(center, space-between);
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
   margin-bottom: 20upx;
 }
 .pv-section-title {
@@ -88,12 +100,13 @@ export default {
 }
 .pv-section-more {
   font-size: 22upx;
-  color: $fontColor3;
+  color: #999;
 }
 
 /* 1排1列 */
 .pv-row-card {
-  @include disFlex(center, flex-start);
+  display: flex;
+  align-items: center;
   padding: 16upx 0;
   border-bottom: 1px solid #f5f5f5;
   &:last-child {
@@ -124,13 +137,15 @@ export default {
 }
 .pv-row-sold {
   font-size: 22upx;
-  color: $fontColor3;
+  color: #999;
+}
+.pv-row-card .pv-price {
+  margin-right: 16upx;
 }
 .pv-price {
   font-size: 30upx;
   color: #FF4D6D;
   font-weight: 700;
-  margin-right: 16upx;
 }
 .pv-add-btn {
   flex-shrink: 0;
@@ -145,15 +160,15 @@ export default {
 }
 
 /* 网格 2/3 列 */
-.pv-grid {
+.pv-goods-grid {
   display: flex;
   flex-wrap: wrap;
   margin: 0 -8upx;
 }
-.pv-grid.cols-2 .pv-grid-card {
+.pv-goods-grid.cols-2 .pv-grid-card {
   width: 50%;
 }
-.pv-grid.cols-3 .pv-grid-card {
+.pv-goods-grid.cols-3 .pv-grid-card {
   width: 33.33%;
 }
 .pv-grid-card {
@@ -176,22 +191,15 @@ export default {
   width: 100%;
   height: 100%;
 }
-.pv-add-btn-float {
-  position: absolute;
-  right: 8upx;
-  bottom: 8upx;
-  width: 44upx;
-  height: 44upx;
-  line-height: 40upx;
-  text-align: center;
-  font-size: 26upx;
-  color: #fff;
-  background: linear-gradient(135deg, #FF8FA3, #FF4D6D);
-  border-radius: 50%;
+.pv-grid-info {
+  margin-top: -4upx;
+  border: 1px solid #eee;
+  border-radius: 12upx;
+  border-top: none;
+  padding: 12upx;
 }
 .pv-grid-name {
   display: block;
-  margin-top: 10upx;
   font-size: 26upx;
   color: #333;
   overflow: hidden;
@@ -199,15 +207,29 @@ export default {
   white-space: nowrap;
 }
 .pv-grid-bottom-row {
-  @include disFlex(center, space-between);
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
   margin-top: 6upx;
 }
+.pv-grid-price-col {
+  display: flex;
+  flex-direction: column;
+}
 .pv-sold {
+  margin-top: 4upx;
   font-size: 20upx;
-  color: $fontColor3;
+  color: #999;
 }
+/* 加购按钮:圆形底 + 白色购物车,与设计稿一致 */
 .pv-cart-icon {
-  font-size: 24upx;
-  color: #FF4D6D;
+  flex-shrink: 0;
+  width: 52upx;
+  height: 52upx;
+  border-radius: 50%;
+  background: #FF4D6D;
+  display: flex;
+  align-items: center;
+  justify-content: center;
 }
 </style>

+ 86 - 11
hdApp/src/admin/homePageConfig/previewParts/noticeBar.vue

@@ -1,37 +1,112 @@
 <!--
   首页预览-公告条
-  纯静态样式展示,暂无后台配置开关;文案先写死,后续如需可再接配置
+  复用 hdApp /shop-notice/show-list 按 position=1 拉取首页公告;
+  样式与 mallApp 真实首页 noticeBar 一致:喇叭图标 +「公告」标签 + 纵向轮播 + 箭头;
+  预览页只读,不跳转公告详情;无数据时整块不渲染。
 -->
 <template>
-  <view class="pv-notice-bar">
-    <text class="pv-notice-icon">📢</text>
-    <text class="pv-notice-text">每月11号会员日,全场花束8.8折</text>
+  <view class="pv-notice-bar" v-if="noticeList.length">
+    <zui-svg-icon class="pv-notice-icon" icon="general-notice-horn" :width="16" :height="16" />
+    <text class="pv-notice-tag">公告</text>
+    <swiper
+      class="pv-notice-swiper"
+      :key="'pv-notice-' + noticeList.length"
+      vertical
+      :autoplay="noticeList.length > 1"
+      :circular="noticeList.length > 1"
+      :interval="6000"
+      :duration="400"
+      :skip-hidden-item-layout="true"
+    >
+      <swiper-item v-for="item in noticeList" :key="item.id">
+        <text class="pv-notice-text">{{ item.summary }}</text>
+      </swiper-item>
+    </swiper>
+    <text class="pv-notice-arrow">›</text>
   </view>
 </template>
 
 <script>
+import { shopNoticeShowList } from '@/api/shop-notice'
+
+/** 商城首页展示位置,与 mallApp noticeBar / hdApp shopNotice positionOptions 一致 */
+const NOTICE_POSITION_HOME = 1
+
 export default {
-  name: 'previewNoticeBar'
+  name: 'previewNoticeBar',
+  data() {
+    return {
+      noticeList: []
+    }
+  },
+  created() {
+    this.loadNoticeList()
+  },
+  methods: {
+    /**
+     * 拉取首页位置公告列表
+     * 无数据时组件自隐藏,避免空条占位
+     */
+    loadNoticeList() {
+      return shopNoticeShowList({ position: NOTICE_POSITION_HOME }).then((res) => {
+        const data = res.data || {}
+        this.noticeList = data.list || []
+      }).catch(() => {
+        this.noticeList = []
+      })
+    }
+  }
 }
 </script>
 
 <style lang="scss" scoped>
 .pv-notice-bar {
-  @include disFlex(center, flex-start);
+  display: flex;
+  align-items: center;
   height: 64upx;
-  padding: 0 24upx;
-  background: #FFF3F5;
+  margin: 8upx 24upx 12upx;
+  padding: 0 20upx;
+  border-radius: 32upx;
+  background: #FFF0F3;
+  box-shadow: 0 2upx 12upx rgba(255, 77, 125, 0.1);
+  box-sizing: border-box;
 }
 .pv-notice-icon {
-  font-size: 24upx;
+  flex-shrink: 0;
+  margin-right: 8upx;
+}
+.pv-notice-tag {
+  flex-shrink: 0;
+  height: 32upx;
+  line-height: 30upx;
+  padding: 0 8upx;
   margin-right: 12upx;
+  font-size: 20upx;
+  color: #FF4D7D;
+  border: 1upx solid #FF4D7D;
+  border-radius: 6upx;
+  box-sizing: border-box;
 }
-.pv-notice-text {
+.pv-notice-swiper {
   flex: 1;
+  width: 0;
+  height: 40upx;
+  min-width: 0;
+}
+.pv-notice-text {
+  display: block;
   font-size: 24upx;
-  color: #D6336C;
+  color: #FF4D7D;
+  line-height: 40upx;
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
 }
+.pv-notice-arrow {
+  flex-shrink: 0;
+  font-size: 32upx;
+  line-height: 1;
+  color: #FF4D7D;
+  margin-left: 8upx;
+}
 </style>

+ 54 - 0
hdApp/src/admin/homePageConfig/previewParts/shopHeaderBar.vue

@@ -0,0 +1,54 @@
+<!--
+  首页预览-商户名称展示条
+  仿 mallApp 店铺首页 customNavBar 的视觉:粉色背景 + 居中加粗店名;
+  预览页位于后台,去掉状态栏占位与返回按钮,仅做只读展示。
+-->
+<template>
+  <view class="pv-shop-header" :style="{ background: bgColor }">
+    <view class="pv-shop-header__title">{{ title || '门店名称' }}</view>
+  </view>
+</template>
+
+<script>
+export default {
+  name: 'previewShopHeaderBar',
+  props: {
+    /** 商户名称,来自 get-home.topNav.merchantName */
+    title: {
+      type: String,
+      default: ''
+    },
+    /**
+     * 导航栏背景色:与真实首页 topNavBgColor 一致
+     * topNav 启用时用粉色,未启用时回落页面灰底
+     */
+    bgColor: {
+      type: String,
+      default: '#FFE0E6'
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.pv-shop-header {
+  width: 100%;
+  flex-shrink: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 88upx;
+  box-sizing: border-box;
+  padding: 0 24upx;
+}
+.pv-shop-header__title {
+  width: 100%;
+  font-size: 32upx;
+  font-weight: 700;
+  color: #333;
+  text-align: center;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+</style>

+ 38 - 29
hdApp/src/admin/homePageConfig/previewParts/topNav.vue

@@ -1,20 +1,24 @@
 <!--
   首页预览-顶部导航与搜索
-  只读展示:门店名称 + 搜索框(按钮色/文字色取配置)+ 客服入口图标
+  只读展示:搜索框(按钮色/文字色取配置)+ 消息中心图标;
+  门店名称由页面级 shopHeaderBar 展示,客服入口由轮播悬浮球承担,与 mallApp 真实首页一致。
 -->
 <template>
   <view v-if="data && data.enabled == 1" class="pv-top-nav">
-    <view class="pv-shop-name">{{ data.merchantName || '门店名称' }}</view>
     <view class="pv-search-row">
       <view class="pv-search-input">
-        <text class="pv-search-icon">🔍</text>
+        <view class="pv-search-icon">
+          <zui-svg-icon icon="general-search" :width="24" :height="24" color="#999" />
+        </view>
         <text class="pv-search-ph">{{ data.placeholder || '搜索鲜花、花束、绿植等' }}</text>
+        <view
+          class="pv-search-btn"
+          :style="{ background: data.searchBtnColor || '#FF6B88', color: data.searchFontColor || '#FFFFFF' }"
+        >搜索</view>
+      </view>
+      <view class="pv-message-icon">
+        <zui-svg-icon icon="general-message" :width="24" :height="24" color="#999" />
       </view>
-      <view
-        class="pv-search-btn"
-        :style="{ background: data.searchBtnColor || '#FF6B88', color: data.searchFontColor || '#FFFFFF' }"
-      >搜索</view>
-      <view v-if="data.customerServiceEnabled == 1" class="pv-service-icon">🎧</view>
     </view>
   </view>
 </template>
@@ -36,48 +40,53 @@ export default {
   padding: 16upx 24upx 20upx;
   background: linear-gradient(180deg, #FFE0E6 0%, #FFF3F5 100%);
 }
-.pv-shop-name {
-  font-size: 32upx;
-  font-weight: 700;
-  color: #333;
-  margin-bottom: 16upx;
-}
 .pv-search-row {
-  @include disFlex(center, flex-start);
+  display: flex;
+  align-items: center;
 }
 .pv-search-input {
   flex: 1;
   height: 68upx;
-  padding: 0 20upx;
+  padding: 6upx 6upx 6upx 20upx;
   border-radius: 34upx;
   background: rgba(255, 255, 255, 0.9);
-  @include disFlex(center, flex-start);
+  display: flex;
+  align-items: center;
 }
 .pv-search-icon {
-  font-size: 26upx;
-  margin-right: 8upx;
+  flex-shrink: 0;
+  width: 48upx;
+  height: 48upx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  line-height: 1;
 }
 .pv-search-ph {
+  flex: 1;
   font-size: 26upx;
   color: #999;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
 }
 .pv-search-btn {
   flex-shrink: 0;
-  height: 68upx;
-  line-height: 68upx;
+  height: 56upx;
+  line-height: 56upx;
   padding: 0 28upx;
-  margin-left: 16upx;
-  border-radius: 34upx;
+  margin-left: 8upx;
+  border-radius: 28upx;
   font-size: 26upx;
   text-align: center;
 }
-.pv-service-icon {
+.pv-message-icon {
   flex-shrink: 0;
-  width: 68upx;
-  height: 68upx;
-  line-height: 68upx;
-  text-align: center;
-  font-size: 32upx;
+  width: 48upx;
+  height: 48upx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
   margin-left: 12upx;
   border-radius: 50%;
   background: rgba(255, 255, 255, 0.9);

+ 0 - 26
hdApp/src/admin/homePageConfig/topNavSearch.vue

@@ -62,7 +62,6 @@
       <view class="preview-box">
         <view class="preview-shop" :style="{ color: form.searchBtnColor }">
           {{ merchantName || '门店名称' }}
-          <text class="preview-arrow">▼</text>
         </view>
         <view class="preview-search">
           <text class="preview-placeholder">{{ form.placeholder || '请输入搜索占位文案' }}</text>
@@ -71,9 +70,6 @@
             :style="{ background: form.searchBtnColor, color: form.searchFontColor }"
           >搜索</view>
         </view>
-        <view v-if="form.customerServiceEnabled == 1" class="preview-cs" :style="{ borderColor: form.searchBtnColor }">
-          <text class="preview-cs-icon" :style="{ color: form.searchBtnColor }">☎</text>
-        </view>
       </view>
     </view>
 
@@ -296,11 +292,6 @@ export default {
   margin-bottom: 24upx;
 }
 
-.preview-arrow {
-  font-size: 18upx;
-  margin-left: 6upx;
-}
-
 .preview-search {
   @include disFlex(center, space-between);
   background: #fff;
@@ -329,23 +320,6 @@ export default {
   font-weight: 600;
 }
 
-.preview-cs {
-  position: absolute;
-  right: 24upx;
-  bottom: 20upx;
-  width: 64upx;
-  height: 64upx;
-  border-radius: 50%;
-  background: #fff;
-  border: 2upx solid #09C567;
-  @include disFlex(center, center);
-  box-shadow: 0 4upx 12upx rgba(0, 0, 0, 0.08);
-}
-
-.preview-cs-icon {
-  font-size: 32upx;
-}
-
 .bottom-bar {
   position: fixed;
   left: 0;

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
hdApp/src/assets/svg-icons/general/cartFull.svg


+ 1 - 0
hdApp/src/assets/svg-icons/general/customerService.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1785746702311" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2993" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M139.6 372.4v232.7H46.5V372.4h93.1m0-46.6H46.5c-25.6 0-46.5 21-46.5 46.6v232.7c0 25.6 20.9 46.5 46.5 46.5h93.1c25.6 0 46.5-20.9 46.5-46.5V372.4c0.1-25.6-20.9-46.6-46.5-46.6zM977.5 372.4v232.7h-93.1V372.4h93.1m0-46.6h-93.1c-25.6 0-46.5 20.9-46.5 46.5V605c0 25.6 20.9 46.5 46.5 46.5h93.1c25.6 0 46.5-20.9 46.5-46.5V372.4c0-25.6-20.9-46.6-46.5-46.6zM512 791.3c51.3 0 93.1 41.8 93.1 93.1s-41.8 93.1-93.1 93.1-93.1-41.8-93.1-93.1 41.8-93.1 93.1-93.1m0-46.6c-77.1 0-139.6 62.5-139.6 139.6S434.9 1024 512 1024s139.6-62.5 139.6-139.6S589.1 744.7 512 744.7zM418.9 325.8h-93.1v93.1h93.1v-93.1zM698.2 325.8h-93.1v93.1h93.1v-93.1zM672.3 558.5c-32.3 55.4-91.7 93.1-160.3 93.1s-128-37.7-160.3-93.1h-52.8c35.9 82.1 117.7 139.6 213.1 139.6s177.1-57.5 213.1-139.6h-52.8z" fill="#515151" p-id="2994"></path><path d="M117.5 325.8C175.2 163.4 330 46.5 512 46.5s336.8 116.8 394.5 279.3h49.6C896.8 137 720.4 0 512 0S127.2 137 67.9 325.8h49.6zM886.7 651.6c-48.2 96.6-132.4 171.8-235.1 208.3v49.6C780.4 869 884.9 774 938.4 651.6h-51.7z" fill="#515151" p-id="2995"></path></svg>

+ 1 - 0
hdApp/src/assets/svg-icons/general/message.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1785746241908" class="icon" viewBox="0 0 1080 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1975" xmlns:xlink="http://www.w3.org/1999/xlink" width="210.9375" height="200"><path d="M207.303111 458.638222a64.284444 64.284444 0 1 0 128.455111 0 64.284444 64.284444 0 0 0-128.455111 0z m253.895111 0a64.284444 64.284444 0 1 0 128.455111 0 64.284444 64.284444 0 0 0-128.455111 0z m253.838222 0a64.284444 64.284444 0 1 0 128.512 0 64.284444 64.284444 0 0 0-128.512 0z m288.654223-180.053333a458.467556 458.467556 0 0 0-111.786667-145.692445C794.396444 47.217778 665.144889 0.341333 527.928889 0.341333c-137.272889 0-266.524444 47.104-363.861333 132.551111A456.817778 456.817778 0 0 0 52.280889 278.584889a412.046222 412.046222 0 0 0-41.358222 180.053333 419.271111 419.271111 0 0 0 57.685333 210.659556c32.995556 56.490667 79.644444 106.951111 135.623111 146.944v151.836444a36.693333 36.693333 0 0 0 54.954667 31.687111l160.654222-92.728889c35.384889 6.712889 71.850667 10.069333 108.145778 10.069334 137.329778 0 266.581333-47.160889 363.918222-132.551111a456.817778 456.817778 0 0 0 111.786667-145.749334 412.046222 412.046222 0 0 0 41.358222-180.053333 409.998222 409.998222 0 0 0-41.358222-180.167111z m-475.704889 565.248a509.952 509.952 0 0 1-106.780445-11.264 36.579556 36.579556 0 0 0-25.941333 4.096l-117.76 68.096V797.013333a36.977778 36.977778 0 0 0-16.497778-30.663111c-112.469333-73.671111-176.981333-185.799111-176.981333-307.768889 0-212.366222 199.111111-385.024 443.960889-385.024 244.736 0 444.017778 172.657778 444.017778 385.080889 0 212.366222-199.281778 385.251556-444.017778 385.251556z" fill="#000000" p-id="1976"></path></svg>

+ 5 - 0
hdApp/src/assets/svg-icons/general/notice-horn.svg

@@ -0,0 +1,5 @@
+<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
+  <path fill="#FF4D7D" d="M4 12h4l6-6v20l-6-6H4c-1.1 0-2-.9-2-2v-4c0-1.1.9-2 2-2z"/>
+  <path fill="#FF4D7D" d="M22 10c2 2 2 12 0 14l-2-2c1-1 1-9 0-10l2-2z"/>
+  <path fill="#FF4D7D" d="M26 8c3 3 3 14 0 17l-2-2c2-2 2-11 0-13l2-2z"/>
+</svg>

+ 1 - 0
hdApp/src/assets/svg-icons/general/search.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1779194195244" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13746" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M482.133333 724.845714A252.952381 252.952381 0 1 1 735.085714 471.893333a253.318095 253.318095 0 0 1-252.952381 252.952381z m0-457.142857A204.190476 204.190476 0 1 0 686.32381 471.893333 204.312381 204.312381 0 0 0 482.133333 268.190476z" fill="#000000" p-id="13747"></path><path d="M615.94819 660.72381l34.486858-34.486858L787.748571 763.550476l-34.474666 34.486857z" fill="#000000" p-id="13748"></path></svg>

Разница между файлами не показана из-за своего большого размера
+ 11 - 3
hdApp/src/static/svg-icons-lib.js


+ 22 - 6
mallApp/src/components/home/activitySection.vue

@@ -11,6 +11,11 @@
         <view class="activity-title-row">
           <text class="activity-title">{{ data.title || (isGroupBuy ? '团购优惠' : '限时秒杀') }}</text>
           <view v-if="data.showCountdown == 1 && data.status == 1" class="countdown">
+            <!-- 剩余超过 24 小时时展示「天」单位,避免小时数无限增大 -->
+            <template v-if="countdown.showDay">
+              <text class="countdown-unit">{{ countdown.d }}</text>
+              <text class="countdown-day">天</text>
+            </template>
             <text class="countdown-unit">{{ countdown.h }}</text>
             <text class="countdown-colon">:</text>
             <text class="countdown-unit">{{ countdown.m }}</text>
@@ -83,7 +88,8 @@ export default {
   },
   data() {
     return {
-      countdown: { h: '00', m: '00', s: '00' },
+      // showDay:剩余 ≥24h 时展示天;d/h/m/s 为补零后的展示字符串
+      countdown: { showDay: false, d: '00', h: '00', m: '00', s: '00' },
       /** 是否处于活动有效期,控制整块专区显隐 */
       isActive: false,
       _timer: null
@@ -187,7 +193,8 @@ export default {
     },
     /**
      * 按 startTime/endTime 刷新专区显隐与倒计时数字;
-     * 与后端 calcActivityStatus 一致:仅 now ∈ [start, end] 时展示。
+     * 与后端 calcActivityStatus 一致:仅 now ∈ [start, end] 时展示;
+     * 剩余 ≥24h 时拆出天单位,小时限制在 0–23。
      */
     tickCountdown() {
       const start = parseInt(this.data && this.data.startTime, 10) || 0
@@ -197,7 +204,7 @@ export default {
       // 无有效时间或已超过结束时间:隐藏专区并停表
       if (start <= 0 || end <= 0 || now > end) {
         this.isActive = false
-        this.countdown = { h: '00', m: '00', s: '00' }
+        this.countdown = { showDay: false, d: '00', h: '00', m: '00', s: '00' }
         this.clearTimer()
         return
       }
@@ -205,18 +212,21 @@ export default {
       // 未到开始时间:暂不展示,定时器继续等待到点
       if (now < start) {
         this.isActive = false
-        this.countdown = { h: '00', m: '00', s: '00' }
+        this.countdown = { showDay: false, d: '00', h: '00', m: '00', s: '00' }
         return
       }
 
-      // 活动进行中:展示专区并更新剩余时分秒
+      // 活动进行中:展示专区并更新剩余天///(≥24h 拆出天)
       this.isActive = true
       let diff = end - now
       if (diff < 0) diff = 0
-      const h = Math.floor(diff / 3600)
+      const d = Math.floor(diff / 86400)
+      const h = Math.floor((diff % 86400) / 3600)
       const m = Math.floor((diff % 3600) / 60)
       const s = diff % 60
       this.countdown = {
+        showDay: d > 0,
+        d: String(d).padStart(2, '0'),
         h: String(h).padStart(2, '0'),
         m: String(m).padStart(2, '0'),
         s: String(s).padStart(2, '0')
@@ -277,6 +287,12 @@ export default {
   color: #FF4D6D;
   font-weight: 700;
 }
+.countdown-day {
+  margin: 0 6upx 0 4upx;
+  font-size: 22upx;
+  color: #FF4D6D;
+  font-weight: 700;
+}
 .section-more {
   flex-shrink: 0;
   margin-left: 16upx;

+ 1 - 2
mallApp/src/components/home/goodsSection.vue

@@ -38,8 +38,7 @@
             </view>
             <!-- 加购:圆形底 + 白色购物车 SVG,与设计稿一致 -->
             <view class="cart-icon" @click.stop="handleCartClick(g)">
-              <!-- 购物车 SVG 视觉重心偏上,略下移以在圆内光学居中 -->
-              <zui-svg-icon icon="general-cartFull" :width="16" :height="16" color="#fff" style="margin-top: 4upx" />
+              <zui-svg-icon icon="general-cartFull" :width="16" :height="16" color="#fff" style="margin-top: 6upx" />
             </view>
           </view>
         </view>

Некоторые файлы не были показаны из-за большого количества измененных файлов