Quellcode durchsuchen

fix(frontend): 商品详情页修复 — 封面轮播、字段映射修正、按钮等大

- 封面图替换为 swiper 轮播,支持 coverImage + imageList 多图切换
- 添加 getImageUrl() 自动补全 API_BASE_URL 前缀
- 修正字段映射:商品介绍 → intro,商品详情 → description
- 价格/会员价上下排列,会员价字体缩小
- 加购物车和立即购买按钮统一字体大小
- 供应商编辑页新增「商品简介」intro 字段
liaoxg vor 1 Monat
Ursprung
Commit
67dfad3e3c

+ 45 - 22
cfc-frontend/pages/discover-detail/product-detail/product-detail.vue

@@ -4,12 +4,11 @@
       <text class="loading-text">加载中...</text>
     </view>
     <scroll-view v-else-if="product.id" scroll-y class="content">
-      <image
-        class="cover"
-        :src="coverImageUrl || '/static/default-product.png'"
-        mode="widthFix"
-        @error="onImageError"
-      />
+      <swiper class="cover-swiper" indicator-dots autoplay circular indicator-active-color="#F97316">
+        <swiper-item v-for="(img, idx) in displayImages" :key="idx">
+          <image class="swiper-image" :src="getImageUrl(img)" mode="widthFix" @error="onSwiperImageError(idx)" />
+        </swiper-item>
+      </swiper>
       <view class="info-section">
         <view class="name-row">
           <text class="product-name">{{ product.name }}</text>
@@ -30,14 +29,14 @@
         </view>
       </view>
 
-      <view class="desc-section" v-if="product.description">
+      <view class="intro-section" v-if="product.intro">
         <text class="section-title">商品介绍</text>
-        <mp-html :content="product.description" />
+        <mp-html :content="product.intro" />
       </view>
 
-      <view v-if="product.intro" class="intro-section">
-        <text class="section-title">详细介绍</text>
-        <mp-html :content="product.intro" />
+      <view class="desc-section" v-if="product.description">
+        <text class="section-title">商品详情</text>
+        <mp-html :content="product.description" />
       </view>
 
       <view class="bottom-bar">
@@ -65,6 +64,7 @@
 </template>
 
 <script>
+import config from '@/config.js'
 import { productDetail, productOrderCreate, productOrderPay, cartAdd, getShareQrCode } from '@/utils/api.js'
 import MpHtml from '@/components/mp-html/mp-html.vue'
 import ContentSharePoster from '@/components/ContentSharePoster.vue'
@@ -134,6 +134,16 @@ export default {
       }
       if (p.domain) return p.domain
       return ''
+    },
+    displayImages() {
+      var images = []
+      if (this.product.coverImage) {
+        images.push(this.product.coverImage)
+      }
+      if (this.product.imageList && this.product.imageList.length) {
+        images = images.concat(this.product.imageList)
+      }
+      return images.length ? images : ['/static/default-product.png']
     }
   },
   onLoad(options) {
@@ -152,9 +162,17 @@ export default {
     }
   },
   methods: {
-    onImageError(e) {
-      // 图片加载失败时,使用占位图(default-activity.png 已存在于 static/)
-      this.product.coverImage = '/static/default-activity.png'
+    getImageUrl: function(path) {
+      if (!path) return '/static/default-product.png'
+      if (path.startsWith('http') || path.startsWith('/static/')) return path
+      return config.API_BASE_URL + path
+    },
+    onSwiperImageError: function(idx) {
+      // 单张图片加载失败时,替换为占位图
+      var images = this.displayImages
+      if (images[idx] && images[idx] !== '/static/default-product.png') {
+        images[idx] = '/static/default-product.png'
+      }
     },
     loadDetail(id) {
       this.loading = true
@@ -280,10 +298,15 @@ export default {
   height: calc(100vh - 120rpx);
   padding-bottom: 120rpx;
 }
-.cover {
+.cover-swiper {
   width: 100%;
+  height: 750rpx;
   background: #f0f0f0;
 }
+.swiper-image {
+  width: 100%;
+  height: 750rpx;
+}
 .info-section {
   background: #fff;
   padding: 30rpx;
@@ -300,18 +323,18 @@ export default {
 }
 .price-row {
   display: flex;
-  align-items: baseline;
+  flex-direction: column;
   margin-bottom: 16rpx;
 }
 .price {
   font-size: 40rpx;
   color: #F97316;
   font-weight: bold;
-  margin-right: 20rpx;
 }
 .member-price {
-  font-size: 26rpx;
+  font-size: 22rpx;
   color: #999;
+  margin-top: 4rpx;
 }
 .gift-tag {
   display: inline-block;
@@ -429,11 +452,11 @@ export default {
   background: #fff;
   color: #F97316;
   border: 2rpx solid #F97316;
-  font-size: 26rpx;
+  font-size: 28rpx;
   padding: 0 24rpx;
-  height: 64rpx;
-  line-height: 64rpx;
-  border-radius: 32rpx;
+  height: 72rpx;
+  line-height: 72rpx;
+  border-radius: 36rpx;
 }
 .btn-cart::after {
   border: none;

+ 9 - 1
cfc-frontend/pages/vendor/product-edit/product-edit.vue

@@ -31,9 +31,14 @@
         </view>
       </view>
 
+      <view class="form-item">
+        <text class="form-label">商品简介</text>
+        <textarea class="form-textarea" v-model="form.intro" placeholder="商品简介(可选,简短介绍)" />
+      </view>
+
       <view class="form-item">
         <text class="form-label">商品描述</text>
-        <textarea class="form-textarea" v-model="form.description" placeholder="商品描述(可选)" />
+        <textarea class="form-textarea" v-model="form.description" placeholder="商品描述(可选,详细内容)" />
       </view>
     </view>
 
@@ -68,6 +73,7 @@ export default {
         price: 0,
         stock: 0,
         coverImage: '',
+        intro: '',
         description: ''
       }
     }
@@ -94,6 +100,7 @@ export default {
         if (res.code === 200 && res.data) {
           const p = res.data
           this.form.name = p.name || ''
+          this.form.intro = p.intro || ''
           this.form.description = p.description || ''
           this.form.coverImage = p.coverImage || ''
           this.form.price = p.price || 0
@@ -130,6 +137,7 @@ export default {
         price: Number(this.form.price),
         stock: Number(this.form.stock),
         coverImage: this.form.coverImage || '',
+        intro: this.form.intro || '',
         description: this.form.description || ''
       }
       var apiCall = this.isEdit