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

feat(goods): 优化商品列表加购与花束文案

- 为商城商品列表和专区列表增加加购入口、悬浮购物车角标与购物车跳转
- 调整活动倒计时展示,超过 24 小时时拆分天数和小时
- 统一花束管理相关菜单、页标题和新增按钮文案
shizhongqi 3 дней назад
Родитель
Сommit
5fe34898da

+ 3 - 3
hdApp/src/admin/goods/manage.vue

@@ -247,7 +247,7 @@
       </view>
     </view>
 
-    <button class="admin-button-com big blue footer-btn" @click="addCurrent">{{ activeType === 'goods' ? '新增商品' : '新增花材' }}</button>
+    <button class="admin-button-com big blue footer-btn" @click="addCurrent">{{ activeType === 'goods' ? '新增花束' : '新增花材' }}</button>
 
     <view v-if="showFilterPanel" class="filter-overlay" @click="closeFilterPanel">
       <view class="filter-panel" @click.stop>
@@ -1247,8 +1247,8 @@ page {
 .top-tabs {
   display: flex;
   align-items: flex-end;
-  height: 118upx;
-  padding: 10upx 120upx 0;
+  height: 100upx;
+  padding: 0 120upx 0;
   box-sizing: border-box;
   flex-shrink: 0;
 }

+ 2 - 2
hdApp/src/admin/home/homeMenus.js

@@ -11,9 +11,9 @@ export const APPLY_MENU_GROUPS = [
       { name: '商城码', icon: homeIcon('mall-filled'), url: '/admin/cg/mall', pf: 1 },
       { name: '商品管理', icon: homeIcon('bouquet'), url: '/admin/goods/manage', pf: 1 },
       { name: '新增花束', icon: homeIcon('add-bouquet'), url: '/admin/goods/add', pf: 1 },
-      { name: '分类', icon: homeIcon('category-filled'), url: '/admin/goods/categoryV2?tab=0', pf: 1 },
+      { name: '花束分类', icon: homeIcon('category-filled'), url: '/admin/goods/categoryV2?tab=0', pf: 1 },
       { name: '使用场景', icon: homeIcon('category-filled'), url: '/admin/useCase/list', pf: 1 },
-      { name: '排序', icon: homeIcon('sort-filled'), url: '/admin/goods/categorySort', pf: 1 },
+      { name: '花束排序', icon: homeIcon('sort-filled'), url: '/admin/goods/categorySort', pf: 1 },
       { name: '任务', icon: homeIcon('task-filled'), url: '/admin/work/list', pf: 1 },
       { name: '涨价设置', icon: homeIcon('price-increase'), url: '/admin/goods/price-increase', pf: 1 }
     ]

+ 1 - 1
hdApp/src/pages.json

@@ -348,7 +348,7 @@
 				{ "path": "kind", "style": { "navigationBarTitleText": "花束品类" } },
 				{ "path": "lzKind", "style": { "navigationBarTitleText": "绿植品类" } },
 				{ "path": "detail", "style": { "navigationBarTitleText": "商品详情" } },
-				{ "path": "add", "style": { "navigationBarTitleText": "新增商品" } },
+				{ "path": "add", "style": { "navigationBarTitleText": "新增花束" } },
 				{ "path": "selectItem", "style": { "navigationBarTitleText": "选择花材" } },
 				{ "path": "img-store", "style": { "navigationBarTitleText": "图库管理" } },
 				{ "path": "goods-name", "style": { "navigationBarTitleText": "填写商品信息" } },

+ 33 - 6
mallApp/src/components/CountDown.vue

@@ -2,11 +2,17 @@
   通用倒计时组件
   用途:团购详情页活动倒计时、拼团剩余时间等
   入参 endTime 为秒级 unix;结束后触发 ended 事件
+  剩余 ≥24h 时拆出「天」单位,小时限制在 0–23(与首页活动专区一致)
 -->
 <template>
   <view v-if="visible" class="count-down" :class="theme">
     <text v-if="label" class="cd-label">{{ label }}</text>
     <view class="cd-blocks">
+      <!-- 剩余超过 24 小时时展示「天」单位,避免小时数无限增大 -->
+      <template v-if="display.showDay">
+        <text class="cd-unit">{{ display.d }}</text>
+        <text class="cd-day">天</text>
+      </template>
       <text class="cd-unit">{{ display.h }}</text>
       <text class="cd-colon">:</text>
       <text class="cd-unit">{{ display.m }}</text>
@@ -30,7 +36,8 @@ export default {
   data() {
     return {
       visible: false,
-      display: { h: '00', m: '00', s: '00' },
+      // showDay:剩余 ≥24h 时展示天;d/h/m/s 为补零后的展示字符串
+      display: { showDay: false, d: '00', h: '00', m: '00', s: '00' },
       _timer: null
     }
   },
@@ -57,24 +64,34 @@ export default {
       this.tick()
       this._timer = setInterval(this.tick, 1000)
     },
+    /**
+     * 按 endTime 刷新展示;剩余 ≥24h 拆出天单位,小时为当天剩余 0–23
+     */
     tick() {
       const end = Number(this.endTime) || 0
       const now = Math.floor(Date.now() / 1000)
       if (end <= 0 || now >= end) {
         this.visible = false
-        this.display = { h: '00', m: '00', s: '00' }
+        this.display = { showDay: false, d: '00', h: '00', m: '00', s: '00' }
         this.clearTimer()
         this.$emit('ended')
         return
       }
       this.visible = true
       let diff = end - now
-      const h = Math.floor(diff / 3600)
-      diff -= h * 3600
-      const m = Math.floor(diff / 60)
+      if (diff < 0) diff = 0
+      const d = Math.floor(diff / 86400)
+      const h = Math.floor((diff % 86400) / 3600)
+      const m = Math.floor((diff % 3600) / 60)
       const s = diff % 60
       const pad = (n) => String(n).padStart(2, '0')
-      this.display = { h: pad(h), m: pad(m), s: pad(s) }
+      this.display = {
+        showDay: d > 0,
+        d: pad(d),
+        h: pad(h),
+        m: pad(m),
+        s: pad(s)
+      }
     }
   }
 }
@@ -113,9 +130,19 @@ export default {
   font-size: 22upx;
   font-weight: 600;
 }
+.cd-day {
+  margin: 0 6upx 0 4upx;
+  font-size: 22upx;
+  color: #ff4d6d;
+  font-weight: 600;
+}
 .pink {
   .cd-unit {
     background: #ff6b8a;
   }
+  .cd-day,
+  .cd-colon {
+    color: #ff6b8a;
+  }
 }
 </style>

+ 10 - 4
mallApp/src/pages/goods/detail.vue

@@ -240,6 +240,9 @@ export default {
       this.tickSeckillCountdown();
       this._seckillTimer = setInterval(this.tickSeckillCountdown, 1000);
     },
+    /**
+     * 刷新秒杀倒计时文案;剩余 ≥24h 时拆出「天」,小时限制在 0–23(与首页活动专区一致)
+     */
     tickSeckillCountdown() {
       const end = Number(this.activityEndTime) || 0;
       const now = Math.floor(Date.now() / 1000);
@@ -249,12 +252,15 @@ export default {
         return;
       }
       let diff = end - now;
-      const h = Math.floor(diff / 3600);
-      diff -= h * 3600;
-      const m = Math.floor(diff / 60);
+      if (diff < 0) diff = 0;
+      const d = Math.floor(diff / 86400);
+      const h = Math.floor((diff % 86400) / 3600);
+      const m = Math.floor((diff % 3600) / 60);
       const s = diff % 60;
       const pad = (n) => String(n).padStart(2, '0');
-      this.seckillCountdownText = `${pad(h)}:${pad(m)}:${pad(s)}`;
+      const hms = `${pad(h)}:${pad(m)}:${pad(s)}`;
+      // ≥1 天时前置「X天」,避免出现 48:00:00 这类超大小时数
+      this.seckillCountdownText = d > 0 ? `${d}天${hms}` : hms;
     },
     /** 用秒杀价覆盖详情展示价格,原价保留用于划线展示;仅覆盖展示层,实际下单价格由后端独立核价 */
     applySeckillPriceIfNeeded() {

+ 170 - 9
mallApp/src/pages/goods/list.vue

@@ -2,6 +2,8 @@
   商品列表页
   从店铺首页金刚区进入;支持搜索、分页触底加载、筛选弹窗(配送占位/价格/分类/场景)
   按钮配色与店铺首页统一:#FF4D6D / linear-gradient(135deg, #FF8FA3, #FF4D6D)
+  右侧购物车:单规格直接加购,多规格跳转详情选规格(与首页 goodsSection 一致)
+  左下角悬浮购物车:展示当前店铺购物车数量,点击跳转 pages/home/cart
 -->
 <template>
   <view class="goods-list-page">
@@ -47,12 +49,18 @@
             >{{ tag }}</text>
           </view>
           <view class="bottom-row">
-            <text class="price">
-              <text class="price-symbol">¥</text>
-              {{ formatPrice(item.price) }}
-              <text class="price-suffix">起</text>
-            </text>
-            <text class="sold">已售{{ formatSold(item.totalSold) }}件</text>
+            <view class="price-sold-col">
+              <text class="price">
+                <text class="price-symbol">¥</text>
+                {{ formatPrice(item.price) }}
+                <text class="price-suffix">起</text>
+              </text>
+              <text class="sold">已售{{ formatSold(item.totalSold) }}件</text>
+            </view>
+            <!-- 加购:圆形底 + 白色购物车 SVG,与首页商品区一致 -->
+            <view class="cart-icon" @click.stop="handleCartClick(item)">
+              <zui-svg-icon icon="general-cartFull" :width="16" :height="16" color="#fff" style="margin-top: 6upx" />
+            </view>
           </view>
         </view>
       </view>
@@ -62,6 +70,14 @@
       <app-wrapper-empty title="暂无商品" :is-empty="true" />
     </block>
 
+    <!-- 左下角悬浮购物车:白底圆形 + 角标数量,点击进店铺购物车页 -->
+    <view class="float-cart" @click="goToCart">
+      <zui-svg-icon icon="general-cartFull" :width="26" :height="26" color="#333" />
+      <view v-if="cartBadgeCount > 0" class="float-cart-badge">
+        <text class="float-cart-badge-text">{{ cartBadgeText }}</text>
+      </view>
+    </view>
+
     <!-- 筛选弹窗 -->
     <bottom-popup :show="filterShow" bgcolor="#f5f5f5" :height="0" @close="closeFilter">
       <view class="filter-panel">
@@ -157,6 +173,7 @@ import AppWrapperEmpty from '@/components/app-wrapper-empty'
 import BottomPopup from '@/components/plugin/bottom-popup'
 import { getClass, getList, getUseCaseList } from '@/api/category'
 import { list } from '@/mixins'
+import productMins from '@/mixins/cgProduct'
 
 const PRICE_PRESETS = [
   { key: 'lt50', label: '50元以下', min: '', max: '50' },
@@ -189,9 +206,12 @@ export default {
     AppWrapperEmpty,
     BottomPopup
   },
-  mixins: [list],
+  mixins: [list, productMins],
   data() {
     return {
+      // 购物车 pageType;关闭 mixin 自动拉花材列表,本页只复用加购能力
+      pageType: 'cg',
+      autoLoad: false,
       searchText: '',
       searchTimer: null,
       filterShow: false,
@@ -212,12 +232,55 @@ export default {
       draft: emptyDraft()
     }
   },
+  computed: {
+    /** 悬浮购物车角标:扎数 + 支数,与详情页/店铺 tab 统计口径一致 */
+    cartBadgeCount() {
+      if (!this.selectList || !this.selectList.length) {
+        return 0
+      }
+      const count = this.allCount || {}
+      return (Number(count.bigLength) || 0) + (Number(count.smallLength) || 0)
+    },
+    /** 角标文案:超过 99 显示 99+ */
+    cartBadgeText() {
+      return this.cartBadgeCount > 99 ? '99+' : String(this.cartBadgeCount)
+    }
+  },
+  /** 从详情/购物车返回时刷新角标,避免仍显示旧数量 */
+  onShow() {
+    this.restoreCartFromStorage()
+  },
   methods: {
     init() {
       this.applyRouteFilter()
+      // autoLoad=false 时需主动按店铺 account 恢复购物车,否则悬浮角标为 0
+      this.restoreCartFromStorage()
       this.loadFilterOptions()
       this.loadGoods()
     },
+    /**
+     * 从本地缓存恢复当前店铺购物车到 Vuex
+     * 缓存 key 与分类/详情/购物车页一致:selectListcg_hd_{account}
+     * 空数组也要写入,避免从购物车清空后返回仍显示旧角标
+     */
+    restoreCartFromStorage() {
+      const account = (this.option && this.option.account) || uni.getStorageSync('account') || ''
+      if (!account) {
+        return
+      }
+      const cached = uni.getStorageSync('selectListcg_hd_' + account)
+      if (Array.isArray(cached)) {
+        this.setSelectInfoByType({ type: this.pageType || 'cg', info: cached })
+      }
+    },
+    /** 跳转店铺购物车页 */
+    goToCart() {
+      const account = (this.option && this.option.account) || uni.getStorageSync('account') || ''
+      const hdId = (this.option && this.option.hdId) || uni.getStorageSync('hdId') || 0
+      this.pageTo({
+        url: '/pages/home/cart?account=' + account + '&hdId=' + hdId
+      })
+    },
     /**
      * 解析路由带入的 filterType / filterValue
      * type=2 商品ID列表、type=3 分类、type=4 场景(首页轮播/金刚区跳转)
@@ -405,6 +468,44 @@ export default {
       this.pageTo({
         url: `/pages/goods/detail?id=${item.id}&account=${account}&hdId=${hdId}`
       })
+    },
+    /**
+     * 列表加购:单规格(普通)直接加入购物车;多规格跳转详情选规格后再加购
+     * @param {Object} item 列表商品行(含 specEnabled / price)
+     */
+    handleCartClick(item) {
+      if (!item || !item.id) return
+      // 多规格:进入详情页选择规格
+      if (Number(item.specEnabled) === 1) {
+        this.goDetail(item)
+        return
+      }
+      if (!(Number(item.price) > 0)) {
+        this.$msg('商品还没有价格哦')
+        return
+      }
+      const account = (this.option && this.option.account) || uni.getStorageSync('account') || ''
+      const hdId = (this.option && this.option.hdId) || uni.getStorageSync('hdId') || ''
+      // rememberProduct 依赖 option.account,保证按店铺维度记忆购物车
+      if (!this.option) {
+        this.option = { account, hdId }
+      } else if (!this.option.account) {
+        this.option.account = account
+      }
+      const goods = {
+        ...item,
+        priceType: item.priceType != null ? item.priceType : 1,
+        cover: item.smallCover || item.cover,
+        smallCover: item.smallCover || item.cover
+      }
+      const ok = this.addBouquetToCart(goods, null, 1)
+      if (ok) {
+        uni.showToast({
+          title: '已加入购物车',
+          icon: 'none',
+          duration: 1500
+        })
+      }
     }
   },
   async onPullDownRefresh() {
@@ -430,7 +531,46 @@ export default {
 .goods-list-page {
   min-height: 100vh;
   background: #f5f5f5;
-  padding-bottom: 40upx;
+  /* 底部预留悬浮购物车高度,避免列表最后一项被遮挡 */
+  padding-bottom: calc(140upx + env(safe-area-inset-bottom));
+}
+
+/* 左下角悬浮购物车:白底圆形阴影 + 右上角数量红点 */
+.float-cart {
+  position: fixed;
+  left: 32upx;
+  bottom: calc(48upx + env(safe-area-inset-bottom));
+  z-index: 100;
+  width: 92upx;
+  height: 92upx;
+  border-radius: 50%;
+  background: #fff;
+  box-shadow: 0 8upx 24upx rgba(0, 0, 0, 0.12);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.float-cart-badge {
+  position: absolute;
+  top: -4upx;
+  right: -4upx;
+  min-width: 36upx;
+  height: 36upx;
+  padding: 0 8upx;
+  border-radius: 18upx;
+  background: #FF3B30;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-sizing: border-box;
+}
+
+.float-cart-badge-text {
+  font-size: 20upx;
+  color: #fff;
+  line-height: 1;
+  font-weight: 600;
 }
 
 .search-bar {
@@ -553,12 +693,19 @@ export default {
 
 .bottom-row {
   display: flex;
-  align-items: baseline;
+  align-items: center;
   justify-content: space-between;
   margin-top: auto;
   padding-top: 12upx;
 }
 
+.price-sold-col {
+  flex: 1;
+  min-width: 0;
+  display: flex;
+  flex-direction: column;
+}
+
 .price {
   font-size: 34upx;
   font-weight: 700;
@@ -577,10 +724,24 @@ export default {
 }
 
 .sold {
+  margin-top: 4upx;
   font-size: 22upx;
   color: #999;
 }
 
+/* 加购按钮:圆形底 + 白色购物车,与首页商品区一致 */
+.cart-icon {
+  flex-shrink: 0;
+  margin-left: 16upx;
+  width: 52upx;
+  height: 52upx;
+  border-radius: 50%;
+  background: #FF4D6D;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
 .list-end {
   padding: 30upx 0 20upx;
   text-align: center;

+ 149 - 3
mallApp/src/pages/goods/section-list.vue

@@ -3,6 +3,8 @@
   从秒杀/团购/热门推荐/今日上新/下拉商品的「更多」进入;
   样式参照 goods/list.vue,本次不包含搜索与筛选功能。
   秒杀/团购保留活动价、原价划线与团购人数展示。
+  右侧购物车:单规格直接加购,多规格跳转详情选规格(与 list.vue 一致)
+  左下角悬浮购物车:展示当前店铺购物车数量,点击跳转 pages/home/cart
 -->
 <template>
   <view class="goods-list-page">
@@ -31,6 +33,10 @@
               </text>
             </view>
             <text v-if="!isActivity" class="sold">已售{{ formatSold(item.sold || item.totalSold) }}件</text>
+            <!-- 加购:圆形底 + 白色购物车 SVG,与 list.vue / 首页商品区一致 -->
+            <view class="cart-icon" @click.stop="handleCartClick(item)">
+              <zui-svg-icon icon="general-cartFull" :width="16" :height="16" color="#fff" style="margin-top: 6upx" />
+            </view>
           </view>
         </view>
       </view>
@@ -39,6 +45,14 @@
     <block v-else-if="!list.loading">
       <app-wrapper-empty title="暂无商品" :is-empty="true" />
     </block>
+
+    <!-- 左下角悬浮购物车:白底圆形 + 角标数量,点击进店铺购物车页 -->
+    <view class="float-cart" @click="goToCart">
+      <zui-svg-icon icon="general-cartFull" :width="26" :height="26" color="#333" />
+      <view v-if="cartBadgeCount > 0" class="float-cart-badge">
+        <text class="float-cart-badge-text">{{ cartBadgeText }}</text>
+      </view>
+    </view>
   </view>
 </template>
 
@@ -46,15 +60,19 @@
 import AppWrapperEmpty from '@/components/app-wrapper-empty'
 import { getSectionGoods } from '@/api/home-page-config'
 import { list } from '@/mixins'
+import productMins from '@/mixins/cgProduct'
 
 export default {
   name: 'sectionGoodsList',
   components: {
     AppWrapperEmpty
   },
-  mixins: [list],
+  mixins: [list, productMins],
   data() {
     return {
+      // 购物车 pageType;关闭 mixin 自动拉花材列表,本页只复用加购能力
+      pageType: 'cg',
+      autoLoad: false,
       moduleKey: '',
       pageTitle: '商品列表',
       /** 秒杀活动结束时间,取自接口返回,用于点击商品时带给详情页 */
@@ -76,8 +94,24 @@ export default {
     },
     hdId() {
       return (this.option && this.option.hdId) || uni.getStorageSync('hdId') || ''
+    },
+    /** 悬浮购物车角标:扎数 + 支数,与详情页/店铺 tab 统计口径一致 */
+    cartBadgeCount() {
+      if (!this.selectList || !this.selectList.length) {
+        return 0
+      }
+      const count = this.allCount || {}
+      return (Number(count.bigLength) || 0) + (Number(count.smallLength) || 0)
+    },
+    /** 角标文案:超过 99 显示 99+ */
+    cartBadgeText() {
+      return this.cartBadgeCount > 99 ? '99+' : String(this.cartBadgeCount)
     }
   },
+  /** 从详情/购物车返回时刷新角标,避免仍显示旧数量 */
+  onShow() {
+    this.restoreCartFromStorage()
+  },
   methods: {
     init() {
       this.moduleKey = (this.option && this.option.moduleKey) || ''
@@ -89,8 +123,31 @@ export default {
       }
       this.pageTitle = title || '商品列表'
       uni.setNavigationBarTitle({ title: this.pageTitle })
+      // autoLoad=false 时需主动按店铺 account 恢复购物车,否则悬浮角标为 0
+      this.restoreCartFromStorage()
       this.loadGoods()
     },
+    /**
+     * 从本地缓存恢复当前店铺购物车到 Vuex
+     * 缓存 key 与分类/详情/购物车页一致:selectListcg_hd_{account}
+     * 空数组也要写入,避免从购物车清空后返回仍显示旧角标
+     */
+    restoreCartFromStorage() {
+      const account = this.account
+      if (!account) {
+        return
+      }
+      const cached = uni.getStorageSync('selectListcg_hd_' + account)
+      if (Array.isArray(cached)) {
+        this.setSelectInfoByType({ type: this.pageType || 'cg', info: cached })
+      }
+    },
+    /** 跳转店铺购物车页 */
+    goToCart() {
+      this.pageTo({
+        url: '/pages/home/cart?account=' + this.account + '&hdId=' + (this.hdId || 0)
+      })
+    },
     buildQuery() {
       return {
         moduleKey: this.moduleKey,
@@ -148,6 +205,43 @@ export default {
         url += `&activityType=seckill&activityPrice=${item.price}&activityLimit=${item.limit || 0}&activityStock=${item.stock || 0}&activityEndTime=${this.activityEndTime}`
       }
       this.pageTo({ url })
+    },
+    /**
+     * 列表加购:单规格(普通)直接加入购物车;多规格跳转详情选规格后再加购
+     * @param {Object} item 列表商品行(含 specEnabled / price)
+     */
+    handleCartClick(item) {
+      if (!item || !(item.id || item.goodsId)) return
+      // 多规格:进入详情页选择规格
+      if (Number(item.specEnabled) === 1) {
+        this.goDetail(item)
+        return
+      }
+      if (!(Number(item.price) > 0)) {
+        this.$msg('商品还没有价格哦')
+        return
+      }
+      // rememberProduct 依赖 option.account,保证按店铺维度记忆购物车
+      if (!this.option) {
+        this.option = { account: this.account, hdId: this.hdId }
+      } else if (!this.option.account) {
+        this.option.account = this.account
+      }
+      const goods = {
+        ...item,
+        id: item.id || item.goodsId,
+        priceType: item.priceType != null ? item.priceType : 1,
+        cover: item.coverUrl || item.smallCover || item.cover,
+        smallCover: item.smallCover || item.coverUrl || item.cover
+      }
+      const ok = this.addBouquetToCart(goods, null, 1)
+      if (ok) {
+        uni.showToast({
+          title: '已加入购物车',
+          icon: 'none',
+          duration: 1500
+        })
+      }
     }
   },
   async onPullDownRefresh() {
@@ -167,7 +261,46 @@ export default {
 .goods-list-page {
   min-height: 100vh;
   background: #f5f5f5;
-  padding-bottom: 40upx;
+  /* 底部预留悬浮购物车高度,避免列表最后一项被遮挡 */
+  padding-bottom: calc(140upx + env(safe-area-inset-bottom));
+}
+
+/* 左下角悬浮购物车:白底圆形阴影 + 右上角数量红点 */
+.float-cart {
+  position: fixed;
+  left: 32upx;
+  bottom: calc(48upx + env(safe-area-inset-bottom));
+  z-index: 100;
+  width: 92upx;
+  height: 92upx;
+  border-radius: 50%;
+  background: #fff;
+  box-shadow: 0 8upx 24upx rgba(0, 0, 0, 0.12);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.float-cart-badge {
+  position: absolute;
+  top: -4upx;
+  right: -4upx;
+  min-width: 36upx;
+  height: 36upx;
+  padding: 0 8upx;
+  border-radius: 18upx;
+  background: #FF3B30;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-sizing: border-box;
+}
+
+.float-cart-badge-text {
+  font-size: 20upx;
+  color: #fff;
+  line-height: 1;
+  font-weight: 600;
 }
 
 .card-list {
@@ -232,7 +365,7 @@ export default {
 
 .bottom-row {
   display: flex;
-  align-items: baseline;
+  align-items: center;
   justify-content: space-between;
   margin-top: auto;
   padding-top: 12upx;
@@ -269,6 +402,19 @@ export default {
   color: #999;
 }
 
+/* 加购按钮:圆形底 + 白色购物车,与首页商品区一致 */
+.cart-icon {
+  flex-shrink: 0;
+  margin-left: 16upx;
+  width: 52upx;
+  height: 52upx;
+  border-radius: 50%;
+  background: #FF4D6D;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
 .list-end {
   padding: 30upx 0 20upx;
   text-align: center;