潘志宝
8 天以前 f6ea543b3de9a770c1bf5db2baf3e8a5dc2c867a
提交 | 用户 | 时间
9259c2 1 <template>
H 2   <div ref="containerRef" :class="`box-content min-h-30px w-full flex flex-row flex-wrap`">
3     <div
4       v-for="(spu, index) in spuList"
5       :key="index"
6       :style="{
7         ...calculateSpace(index),
8         ...calculateWidth(),
9         borderTopLeftRadius: `${property.borderRadiusTop}px`,
10         borderTopRightRadius: `${property.borderRadiusTop}px`,
11         borderBottomLeftRadius: `${property.borderRadiusBottom}px`,
12         borderBottomRightRadius: `${property.borderRadiusBottom}px`
13       }"
14       class="relative box-content flex flex-row flex-wrap overflow-hidden bg-white"
15     >
16       <!-- 角标 -->
17       <div v-if="property.badge.show" class="absolute left-0 top-0 z-1 items-center justify-center">
18         <el-image :src="property.badge.imgUrl" class="h-26px w-38px" fit="cover" />
19       </div>
20       <!-- 商品封面图 -->
21       <div
22         :class="[
23           'h-140px',
24           {
25             'w-full': property.layoutType !== 'oneColSmallImg',
26             'w-140px': property.layoutType === 'oneColSmallImg'
27           }
28         ]"
29       >
30         <el-image :src="spu.picUrl" class="h-full w-full" fit="cover" />
31       </div>
32       <div
33         :class="[
34           ' flex flex-col gap-8px p-8px box-border',
35           {
36             'w-full': property.layoutType !== 'oneColSmallImg',
37             'w-[calc(100%-140px-16px)]': property.layoutType === 'oneColSmallImg'
38           }
39         ]"
40       >
41         <!-- 商品名称 -->
42         <div
43           v-if="property.fields.name.show"
44           :class="[
45             'text-14px ',
46             {
47               truncate: property.layoutType !== 'oneColSmallImg',
48               'overflow-ellipsis line-clamp-2': property.layoutType === 'oneColSmallImg'
49             }
50           ]"
51           :style="{ color: property.fields.name.color }"
52         >
53           {{ spu.name }}
54         </div>
55         <!-- 商品简介 -->
56         <div
57           v-if="property.fields.introduction.show"
58           :style="{ color: property.fields.introduction.color }"
59           class="truncate text-12px"
60         >
61           {{ spu.introduction }}
62         </div>
63         <div>
64           <!-- 积分 -->
65           <span
66             v-if="property.fields.price.show"
67             :style="{ color: property.fields.price.color }"
68             class="text-16px"
69           >
70             {{ spu.point }}积分
71             {{ !spu.pointPrice || spu.pointPrice === 0 ? '' : `+${fenToYuan(spu.pointPrice)}元` }}
72           </span>
73           <!-- 市场价 -->
74           <span
75             v-if="property.fields.marketPrice.show && spu.marketPrice"
76             :style="{ color: property.fields.marketPrice.color }"
77             class="ml-4px text-10px line-through"
78           >
79             ¥{{ fenToYuan(spu.marketPrice) }}
80           </span>
81         </div>
82         <div class="text-12px">
83           <!-- 销量 -->
84           <span
85             v-if="property.fields.salesCount.show"
86             :style="{ color: property.fields.salesCount.color }"
87           >
88             已兑{{ (spu.pointTotalStock || 0) - (spu.pointStock || 0) }}件
89           </span>
90           <!-- 库存 -->
91           <span v-if="property.fields.stock.show" :style="{ color: property.fields.stock.color }">
92             库存{{ spu.pointTotalStock || 0 }}
93           </span>
94         </div>
95       </div>
96       <!-- 购买按钮 -->
97       <div class="absolute bottom-8px right-8px">
98         <!-- 文字按钮 -->
99         <span
100           v-if="property.btnBuy.type === 'text'"
101           :style="{
102             background: `linear-gradient(to right, ${property.btnBuy.bgBeginColor}, ${property.btnBuy.bgEndColor}`
103           }"
104           class="rounded-full p-x-12px p-y-4px text-12px text-white"
105         >
106           {{ property.btnBuy.text }}
107         </span>
108         <!-- 图片按钮 -->
109         <el-image
110           v-else
111           :src="property.btnBuy.imgUrl"
112           class="h-28px w-28px rounded-full"
113           fit="cover"
114         />
115       </div>
116     </div>
117   </div>
118 </template>
119 <script lang="ts" setup>
120 import { PromotionPointProperty } from './config'
121 import * as ProductSpuApi from '@/api/mall/product/spu'
122 import { PointActivityApi, PointActivityVO, SpuExtension0 } from '@/api/mall/promotion/point'
123 import { fenToYuan } from '@/utils'
124
125 /** 积分商城卡片 */
126 defineOptions({ name: 'PromotionPoint' })
127 // 定义属性
128 const props = defineProps<{ property: PromotionPointProperty }>()
129 // 商品列表
130 const spuList = ref<SpuExtension0[]>([])
131 const spuIdList = ref<number[]>([])
132 const pointActivityList = ref<PointActivityVO[]>([])
133
134 watch(
135   () => props.property.activityIds,
136   async () => {
137     try {
138       // 新添加的积分商城组件,是没有活动ID的
139       const activityIds = props.property.activityIds
140       // 检查活动ID的有效性
141       if (Array.isArray(activityIds) && activityIds.length > 0) {
142         // 获取积分商城活动详情列表
143         pointActivityList.value = await PointActivityApi.getPointActivityListByIds(activityIds)
144
145         // 获取积分商城活动的 SPU 详情列表
146         spuList.value = []
147         spuIdList.value = pointActivityList.value.map((activity) => activity.spuId)
148         if (spuIdList.value.length > 0) {
149           spuList.value = await ProductSpuApi.getSpuDetailList(spuIdList.value)
150         }
151
152         // 更新 SPU 的最低兑换积分和所需兑换金额
153         pointActivityList.value.forEach((activity) => {
154           // 匹配spuId
155           const spu = spuList.value.find((spu) => spu.id === activity.spuId)
156           if (spu) {
157             spu.pointStock = activity.stock
158             spu.pointTotalStock = activity.totalStock
159             spu.point = activity.point
160             spu.pointPrice = activity.price
161           }
162         })
163       }
164     } catch (error) {
165       console.error('获取积分商城活动细节或 SPU 细节时出错:', error)
166     }
167   },
168   {
169     immediate: true,
170     deep: true
171   }
172 )
173
174 /**
175  * 计算商品的间距
176  * @param index 商品索引
177  */
178 const calculateSpace = (index: number) => {
179   // 商品的列数
180   const columns = props.property.layoutType === 'twoCol' ? 2 : 1
181   // 第一列没有左边距
182   const marginLeft = index % columns === 0 ? '0' : props.property.space + 'px'
183   // 第一行没有上边距
184   const marginTop = index < columns ? '0' : props.property.space + 'px'
185
186   return { marginLeft, marginTop }
187 }
188
189 // 容器
190 const containerRef = ref()
191 // 计算商品的宽度
192 const calculateWidth = () => {
193   let width = '100%'
194   // 双列时每列的宽度为:(总宽度 - 间距)/ 2
195   if (props.property.layoutType === 'twoCol') {
196     width = `${(containerRef.value.offsetWidth - props.property.space) / 2}px`
197   }
198   return { width }
199 }
200 </script>
201
202 <style lang="scss" scoped></style>