潘志宝
6 天以前 ca22cdd5550cfa0defb0f430c538698182cdaec1
提交 | 用户 | 时间
820397 1 <template>
H 2   <div :class="`box-content min-h-30px w-full flex flex-row flex-wrap`" ref="containerRef">
3     <div
4       class="relative box-content flex flex-row flex-wrap overflow-hidden bg-white"
5       :style="{
6         ...calculateSpace(index),
7         ...calculateWidth(),
8         borderTopLeftRadius: `${property.borderRadiusTop}px`,
9         borderTopRightRadius: `${property.borderRadiusTop}px`,
10         borderBottomLeftRadius: `${property.borderRadiusBottom}px`,
11         borderBottomRightRadius: `${property.borderRadiusBottom}px`
12       }"
13       v-for="(spu, index) in spuList"
14       :key="index"
15     >
16       <!-- 角标 -->
17       <div v-if="property.badge.show" class="absolute left-0 top-0 z-1 items-center justify-center">
18         <el-image fit="cover" :src="property.badge.imgUrl" class="h-26px w-38px" />
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 fit="cover" class="h-full w-full" :src="spu.picUrl" />
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           class="truncate text-12px"
59           :style="{ color: property.fields.introduction.color }"
60         >
61           {{ spu.introduction }}
62         </div>
63         <div>
64           <!-- 价格 -->
65           <span
66             v-if="property.fields.price.show"
67             class="text-16px"
68             :style="{ color: property.fields.price.color }"
69           >
9259c2 70             ¥{{ fenToYuan(spu.price as any) }}
820397 71           </span>
H 72           <!-- 市场价 -->
73           <span
74             v-if="property.fields.marketPrice.show && spu.marketPrice"
75             class="ml-4px text-10px line-through"
76             :style="{ color: property.fields.marketPrice.color }"
9259c2 77             >¥{{ fenToYuan(spu.marketPrice) }}
H 78           </span>
820397 79         </div>
H 80         <div class="text-12px">
81           <!-- 销量 -->
82           <span
83             v-if="property.fields.salesCount.show"
84             :style="{ color: property.fields.salesCount.color }"
85           >
86             已售{{ (spu.salesCount || 0) + (spu.virtualSalesCount || 0) }}件
87           </span>
88           <!-- 库存 -->
89           <span v-if="property.fields.stock.show" :style="{ color: property.fields.stock.color }">
90             库存{{ spu.stock || 0 }}
91           </span>
92         </div>
93       </div>
94       <!-- 购买按钮 -->
95       <div class="absolute bottom-8px right-8px">
96         <!-- 文字按钮 -->
97         <span
98           v-if="property.btnBuy.type === 'text'"
99           class="rounded-full p-x-12px p-y-4px text-12px text-white"
100           :style="{
101             background: `linear-gradient(to right, ${property.btnBuy.bgBeginColor}, ${property.btnBuy.bgEndColor}`
102           }"
103         >
104           {{ property.btnBuy.text }}
105         </span>
106         <!-- 图片按钮 -->
107         <el-image
108           v-else
109           class="h-28px w-28px rounded-full"
110           fit="cover"
111           :src="property.btnBuy.imgUrl"
112         />
113       </div>
114     </div>
115   </div>
116 </template>
117 <script setup lang="ts">
118 import { ProductCardProperty } from './config'
119 import * as ProductSpuApi from '@/api/mall/product/spu'
9259c2 120 import { fenToYuan } from '../../../../../utils'
820397 121
H 122 /** 商品卡片 */
123 defineOptions({ name: 'ProductCard' })
124 // 定义属性
125 const props = defineProps<{ property: ProductCardProperty }>()
126 // 商品列表
127 const spuList = ref<ProductSpuApi.Spu[]>([])
128 watch(
129   () => props.property.spuIds,
130   async () => {
131     spuList.value = await ProductSpuApi.getSpuDetailList(props.property.spuIds)
132   },
133   {
134     immediate: true,
135     deep: true
136   }
137 )
138
139 /**
140  * 计算商品的间距
141  * @param index 商品索引
142  */
143 const calculateSpace = (index: number) => {
144   // 商品的列数
145   const columns = props.property.layoutType === 'twoCol' ? 2 : 1
146   // 第一列没有左边距
147   const marginLeft = index % columns === 0 ? '0' : props.property.space + 'px'
148   // 第一行没有上边距
149   const marginTop = index < columns ? '0' : props.property.space + 'px'
150
151   return { marginLeft, marginTop }
152 }
153
154 // 容器
155 const containerRef = ref()
156 // 计算商品的宽度
157 const calculateWidth = () => {
158   let width = '100%'
159   // 双列时每列的宽度为:(总宽度 - 间距)/ 2
160   if (props.property.layoutType === 'twoCol') {
161     width = `${(containerRef.value.offsetWidth - props.property.space) / 2}px`
162   }
163   return { width }
164 }
165 </script>
166
167 <style scoped lang="scss"></style>