Explorar el Código

feat(miniapp): 商品详情页按会员身份显示会员价/原价,支付价按身份计算

Xiaogang Liao hace 1 mes
padre
commit
d072a461d5

+ 98 - 15
cfc-frontend/pages/discover-detail/product-detail/product-detail.vue

@@ -14,7 +14,15 @@
           <text class="product-name">{{ product.name }}</text>
         </view>
         <view class="price-row">
-          <text class="price">{{ formatPriceWithSymbol(displayPrice) }}</text>
+          <view class="price-main">
+            <text class="price">{{ formatPriceWithSymbol(displayPrice) }}</text>
+            <text v-if="hasMemberPrice" class="member-tag">会员价</text>
+          </view>
+          <view v-if="hasMemberPrice" class="price-original">
+            <text class="original-label">原价</text>
+            <text class="original-text">{{ formatPriceWithSymbol(originalPriceVal) }}</text>
+          </view>
+          <view v-if="!isMember" class="member-hint" @click="goUpgrade">开通会员享会员价 ›</view>
         </view>
         <view v-if="product.giftLevelName" class="gift-tag">购买即送 {{ product.giftLevelName }} 会员</view>
         <view class="meta-row">
@@ -115,7 +123,7 @@
 
 <script>
 import config from '@/config.js'
-import { productDetail, productOrderCreate, productOrderPay, cartAdd, getShareQrCode, productSpecMap, getProductCoupons, exchangeCoupon } from '@/utils/api.js'
+import { productDetail, productOrderCreate, productOrderPay, cartAdd, getShareQrCode, productSpecMap, getProductCoupons, exchangeCoupon, getMyMembership } from '@/utils/api.js'
 import MpHtml from '@/components/mp-html/mp-html.vue'
 import ContentSharePoster from '@/components/ContentSharePoster.vue'
 import shareMixin from '../../../components/share-mixin.js'
@@ -135,7 +143,10 @@ export default {
       specGroups: [],
       selectedSpecs: {},
       selectedSku: null,
-      productCoupons: []
+      productCoupons: [],
+      // 会员身份(实时调 getMyMembership,FREE=非会员)
+      isMember: false,
+      memberLevel: 'FREE'
     }
   },
   computed: {
@@ -161,8 +172,31 @@ export default {
     },
     priceText() {
       if (!this.product || !this.product.price) return ''
-      var txt = this.formatPriceWithSymbol(this.product.price)
-      return txt
+      // 海报场景: 有会员价且当前是会员,展示会员价; 否则展示原价
+      if (this.hasMemberPrice && this.isMember) {
+        return this.formatPriceWithSymbol(this.product.memberPrice)
+      }
+      return this.formatPriceWithSymbol(this.product.price)
+    },
+    // 商品是否设置了会员价(memberPrice > 0)
+    hasMemberPrice: function() {
+      return !!(this.product && this.product.memberPrice && this.product.memberPrice > 0)
+    },
+    // 会员价(SKU场景下用商品级会员价,因为SKU没有独立memberPrice)
+    memberPriceVal: function() {
+      return (this.product && this.product.memberPrice) || 0
+    },
+    // 原始价格(原价): SKU优先,否则商品价
+    originalPriceVal: function() {
+      if (this.selectedSku) return this.selectedSku.price
+      return (this.product && this.product.price) || 0
+    },
+    // 用户实际需支付的价格: 按会员身份判定
+    actualPrice: function() {
+      if (this.hasMemberPrice && this.isMember) {
+        return this.memberPriceVal
+      }
+      return this.originalPriceVal
     },
     productDimension() {
       var p = this.product
@@ -208,9 +242,8 @@ export default {
       return true
     },
     displayPrice: function() {
-      if (this.selectedSku) return this.selectedSku.price
-      if (this.hasSku) return this.product.price || 0
-      return this.product.price || 0
+      // 实际支付价(按会员身份)
+      return this.actualPrice
     },
     displayStock: function() {
       if (this.selectedSku) return this.selectedSku.stock || 0
@@ -239,6 +272,22 @@ export default {
     if (pid) {
       this.loadDetail(pid)
     }
+    // 实时查询会员身份,用于会员价展示和实付价计算
+    this.loadMembership()
+  },
+  loadMembership: function() {
+    var that = this
+    getMyMembership().then(function(res) {
+      if (res && res.code === 200 && res.data) {
+        var lvl = res.data.memberLevel || 'FREE'
+        that.memberLevel = lvl
+        that.isMember = lvl !== 'FREE' && lvl !== ''
+      }
+    }).catch(function() {
+      // 查询失败按非会员处理,不阻塞页面
+      that.isMember = false
+      that.memberLevel = 'FREE'
+    })
   },
   methods: {
     getImageUrl: function(path) {
@@ -435,7 +484,7 @@ export default {
         uni.navigateTo({ url: '/pages/login/login' })
         return
       }
-      var price = this.selectedSku ? this.selectedSku.price : this.product.price
+      var price = this.actualPrice
       var productData = {
         productId: this.product.id,
         productName: this.product.name,
@@ -582,11 +631,50 @@ export default {
   flex-direction: column;
   margin-bottom: 16rpx;
 }
+.price-main {
+  display: flex;
+  align-items: baseline;
+  gap: 12rpx;
+}
 .price {
   font-size: 40rpx;
   color: #F97316;
   font-weight: bold;
 }
+.member-tag {
+  display: inline-block;
+  font-size: 22rpx;
+  color: #F97316;
+  background: #FFF7ED;
+  border: 1rpx solid #FED7AA;
+  padding: 2rpx 10rpx;
+  border-radius: 6rpx;
+  font-weight: normal;
+}
+.price-original {
+  display: flex;
+  align-items: baseline;
+  gap: 8rpx;
+  margin-top: 6rpx;
+}
+.original-label {
+  font-size: 22rpx;
+  color: #999;
+}
+.original-text {
+  font-size: 24rpx;
+  color: #999;
+  text-decoration: line-through;
+}
+.member-hint {
+  margin-top: 10rpx;
+  font-size: 24rpx;
+  color: #F97316;
+  background: #FFF7ED;
+  padding: 6rpx 16rpx;
+  border-radius: 8rpx;
+  align-self: flex-start;
+}
 .gift-tag {
   display: inline-block;
   margin-top: 12rpx;
@@ -749,12 +837,7 @@ export default {
 .coupon-exchange-btn::after {
   border: none;
 }
-.member-price-row,
-.member-price-hint,
-.member-price-original,
-.member-price-current,
-.bottom-member-highlight,
-.bottom-member { display: none; }
+/* 历史会员价占位类已废弃, 新价格展示用 .price-main / .price-original / .member-hint */
 .btn-disabled {
   opacity: 0.5;
 }