|
|
@@ -1,7 +1,7 @@
|
|
|
<!--
|
|
|
团购详情 / 开团入口页
|
|
|
从首页团购专区点击进入(goodsId),或从分享卡片进入(id=groupBuyId)
|
|
|
- 展示商品信息、当前拼团卡片、开团玩法、底部开团/参团/分享操作
|
|
|
+ 展示商品信息、活动规则(land.desc)、商品详情图文(picTextGoods)、开团玩法、底部操作
|
|
|
-->
|
|
|
<template>
|
|
|
<view class="group-buy-detail-page">
|
|
|
@@ -36,7 +36,7 @@
|
|
|
/>
|
|
|
</view>
|
|
|
<text class="goods-name">{{ goods.name }}</text>
|
|
|
- <text class="goods-desc">{{ goods.subtitle || goods.desc || '精选鲜花,拼团更优惠' }}</text>
|
|
|
+ <text class="goods-desc">{{ goods.subtitle || '精选鲜花,拼团更优惠' }}</text>
|
|
|
</view>
|
|
|
|
|
|
<!-- 当前拼团中卡片 -->
|
|
|
@@ -67,18 +67,35 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 商品详情图 -->
|
|
|
- <view class="detail-section">
|
|
|
+ <!-- 团购活动说明:来自 getGoodsLanding 的 desc,按行拆成编号规则列表 -->
|
|
|
+ <view v-if="activityRules.length" class="rule-card">
|
|
|
+ <view class="rule-title-wrap">
|
|
|
+ <view class="rule-sparkle rule-sparkle-left"></view>
|
|
|
+ <text class="rule-title">活动规则</text>
|
|
|
+ <view class="rule-sparkle rule-sparkle-right"></view>
|
|
|
+ </view>
|
|
|
+ <view class="rule-list">
|
|
|
+ <view
|
|
|
+ v-for="(line, idx) in activityRules"
|
|
|
+ :key="idx"
|
|
|
+ class="rule-item"
|
|
|
+ >
|
|
|
+ <view class="rule-num">{{ idx + 1 }}</view>
|
|
|
+ <text class="rule-text">{{ line }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 商品详情卡片:与开团玩法同款白底圆角卡片,内容用 rich-media-viewer 渲染 -->
|
|
|
+ <view class="detail-card">
|
|
|
<text class="detail-title">商品详情</text>
|
|
|
- <image
|
|
|
- v-for="(img, idx) in detailImages"
|
|
|
- :key="idx"
|
|
|
- class="detail-img"
|
|
|
- :src="img"
|
|
|
- mode="widthFix"
|
|
|
- />
|
|
|
- <view v-if="!detailImages.length" class="detail-empty">
|
|
|
- <text>{{ goods.desc || '暂无更多详情' }}</text>
|
|
|
+ <view class="detail-content">
|
|
|
+ <rich-media-viewer
|
|
|
+ ref="richMediaViewerGoods"
|
|
|
+ :content="previewContent"
|
|
|
+ :startScroll="350"
|
|
|
+ :threshold="550"
|
|
|
+ />
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
@@ -119,6 +136,7 @@
|
|
|
import { mapGetters } from 'vuex'
|
|
|
import CountDown from '@/components/CountDown.vue'
|
|
|
import GroupAvatarStack from '@/components/GroupAvatarStack.vue'
|
|
|
+import RichMediaViewer from '@/components/RichMediaViewer/index.vue'
|
|
|
import wangCg from '@/components/wangCg'
|
|
|
import share from '@/mixins/share'
|
|
|
import {
|
|
|
@@ -131,7 +149,7 @@ import { GROUP_BUY_HD_NOT_BOUND } from '@/constant/errCode'
|
|
|
|
|
|
export default {
|
|
|
name: 'GroupBuyDetail',
|
|
|
- components: { CountDown, GroupAvatarStack, wangCg },
|
|
|
+ components: { CountDown, GroupAvatarStack, RichMediaViewer, wangCg },
|
|
|
mixins: [share],
|
|
|
data() {
|
|
|
return {
|
|
|
@@ -141,6 +159,8 @@ export default {
|
|
|
goods: {},
|
|
|
openGroup: null,
|
|
|
detailImages: [],
|
|
|
+ // 商品详情图文块列表,结构与商品详情页 previewContent 一致
|
|
|
+ previewContent: [],
|
|
|
swiperIndex: 0,
|
|
|
remainText: '00:00:00',
|
|
|
_remainTimer: null,
|
|
|
@@ -167,6 +187,18 @@ export default {
|
|
|
})
|
|
|
return list.length ? list : ['/static/images/user/attr-default.png']
|
|
|
},
|
|
|
+ /**
|
|
|
+ * 活动说明按换行拆成规则条目;去掉行首自带序号,避免与粉色编号球重复
|
|
|
+ */
|
|
|
+ activityRules() {
|
|
|
+ const desc = (this.goods && this.goods.desc) || ''
|
|
|
+ if (!String(desc).trim()) return []
|
|
|
+ return String(desc)
|
|
|
+ .split(/\r?\n/)
|
|
|
+ .map((s) => s.trim())
|
|
|
+ .filter(Boolean)
|
|
|
+ .map((line) => line.replace(/^\d+[\.、\)]\s*/, ''))
|
|
|
+ },
|
|
|
shareGroupId() {
|
|
|
if (this.groupBuyId) return this.groupBuyId
|
|
|
if (this.openGroup && this.openGroup.id) return this.openGroup.id
|
|
|
@@ -210,6 +242,14 @@ export default {
|
|
|
onUnload() {
|
|
|
this.clearRemainTimer()
|
|
|
},
|
|
|
+ // 页面滚动时驱动详情图懒加载可见性检测(与商品详情页一致)
|
|
|
+ onPageScroll(e) {
|
|
|
+ if (this.$refs.richMediaViewerGoods) {
|
|
|
+ this.$refs.richMediaViewerGoods.triggerCheckVisibility(
|
|
|
+ parseInt(e.scrollTop)
|
|
|
+ )
|
|
|
+ }
|
|
|
+ },
|
|
|
onShareAppMessage() {
|
|
|
return this.buildSharePayload()
|
|
|
},
|
|
|
@@ -306,15 +346,34 @@ export default {
|
|
|
endTime: data.endTime,
|
|
|
startTime: data.startTime,
|
|
|
subtitle: data.subtitle,
|
|
|
- desc: data.desc,
|
|
|
+ desc: data.desc, // 团购活动说明(活动规则卡片)
|
|
|
title: data.title
|
|
|
}
|
|
|
this.detailImages = data.detailImages || []
|
|
|
+ // 解析商品详情图文,供 rich-media-viewer 使用(与 goods/detail 一致)
|
|
|
+ this.previewContent = this.parsePicTextContent(
|
|
|
+ data.picTextGoods && data.picTextGoods.content
|
|
|
+ )
|
|
|
if (!keepOpenGroup || !this.openGroup) {
|
|
|
this.openGroup = data.openGroup || null
|
|
|
}
|
|
|
this.startRemainTimer()
|
|
|
},
|
|
|
+ /**
|
|
|
+ * 将接口返回的 picTextGoods.content 转为数组
|
|
|
+ * @param {string|Array} content JSON 字符串或已解析数组
|
|
|
+ * @returns {Array}
|
|
|
+ */
|
|
|
+ parsePicTextContent(content) {
|
|
|
+ if (!content) return []
|
|
|
+ if (Array.isArray(content)) return content
|
|
|
+ try {
|
|
|
+ const parsed = JSON.parse(content)
|
|
|
+ return Array.isArray(parsed) ? parsed : []
|
|
|
+ } catch (e) {
|
|
|
+ return []
|
|
|
+ }
|
|
|
+ },
|
|
|
applyGroupDetail(data) {
|
|
|
if (!data) return
|
|
|
this.groupBuyId = data.id
|
|
|
@@ -698,25 +757,103 @@ export default {
|
|
|
color: #999;
|
|
|
text-align: center;
|
|
|
}
|
|
|
-.detail-section {
|
|
|
- margin-top: 20upx;
|
|
|
+/* 活动规则卡片:浅粉底 + 居中标题 + 全宽编号列表 */
|
|
|
+.rule-card {
|
|
|
+ margin: 20upx 24upx 0;
|
|
|
+ padding: 28upx 28upx 24upx;
|
|
|
+ border-radius: 16upx;
|
|
|
+ background: #fff;
|
|
|
+}
|
|
|
+.rule-title-wrap {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+.rule-title {
|
|
|
+ font-size: 30upx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #333;
|
|
|
+ margin: 0 16upx;
|
|
|
+}
|
|
|
+.rule-sparkle {
|
|
|
+ width: 18upx;
|
|
|
+ height: 18upx;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+.rule-sparkle::before,
|
|
|
+.rule-sparkle::after {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ background: #ff8aa5;
|
|
|
+ border-radius: 2upx;
|
|
|
+}
|
|
|
+.rule-sparkle::before {
|
|
|
+ width: 16upx;
|
|
|
+ height: 4upx;
|
|
|
+ left: 1upx;
|
|
|
+ top: 7upx;
|
|
|
+ transform: rotate(-35deg);
|
|
|
+}
|
|
|
+.rule-sparkle::after {
|
|
|
+ width: 4upx;
|
|
|
+ height: 16upx;
|
|
|
+ left: 7upx;
|
|
|
+ top: 1upx;
|
|
|
+ transform: rotate(-35deg);
|
|
|
+}
|
|
|
+.rule-sparkle-right {
|
|
|
+ transform: scaleX(-1);
|
|
|
+}
|
|
|
+.rule-list {
|
|
|
+ margin-top: 24upx;
|
|
|
+}
|
|
|
+.rule-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: flex-start;
|
|
|
+ margin-top: 18upx;
|
|
|
+}
|
|
|
+.rule-item:first-child {
|
|
|
+ margin-top: 0;
|
|
|
+}
|
|
|
+.rule-num {
|
|
|
+ width: 36upx;
|
|
|
+ height: 36upx;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: #ff8aa5;
|
|
|
+ color: #fff;
|
|
|
+ font-size: 22upx;
|
|
|
+ font-weight: 600;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 36upx;
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-right: 16upx;
|
|
|
+ margin-top: 2upx;
|
|
|
+}
|
|
|
+.rule-text {
|
|
|
+ flex: 1;
|
|
|
+ font-size: 26upx;
|
|
|
+ color: #555;
|
|
|
+ line-height: 1.6;
|
|
|
+}
|
|
|
+/* 商品详情卡片:外边距/圆角/白底与 howto-card 保持一致 */
|
|
|
+.detail-card {
|
|
|
+ margin: 20upx 24upx 0;
|
|
|
background: #fff;
|
|
|
- padding: 28upx 0 40upx;
|
|
|
+ border-radius: 16upx;
|
|
|
+ padding: 28upx 20upx;
|
|
|
+ overflow: hidden;
|
|
|
}
|
|
|
.detail-title {
|
|
|
display: block;
|
|
|
- padding: 0 24upx 20upx;
|
|
|
font-size: 30upx;
|
|
|
font-weight: 600;
|
|
|
+ color: #222;
|
|
|
}
|
|
|
-.detail-img {
|
|
|
+.detail-content {
|
|
|
width: 100%;
|
|
|
- display: block;
|
|
|
-}
|
|
|
-.detail-empty {
|
|
|
- padding: 40upx 24upx;
|
|
|
- color: #999;
|
|
|
- font-size: 26upx;
|
|
|
+ margin-top: 20upx;
|
|
|
}
|
|
|
.foot-bar {
|
|
|
position: fixed;
|