index.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. <template>
  2. <el-scrollbar ref="containerRef" class="z-1 min-h-30px" wrap-class="w-full">
  3. <!-- 商品网格 -->
  4. <div
  5. :style="{
  6. gridGap: `${property.space}px`,
  7. gridTemplateColumns,
  8. width: scrollbarWidth
  9. }"
  10. class="grid overflow-x-auto"
  11. >
  12. <!-- 商品 -->
  13. <div
  14. v-for="(spu, index) in spuList"
  15. :key="index"
  16. :style="{
  17. borderTopLeftRadius: `${property.borderRadiusTop}px`,
  18. borderTopRightRadius: `${property.borderRadiusTop}px`,
  19. borderBottomLeftRadius: `${property.borderRadiusBottom}px`,
  20. borderBottomRightRadius: `${property.borderRadiusBottom}px`
  21. }"
  22. class="relative box-content flex flex-row flex-wrap overflow-hidden bg-white"
  23. >
  24. <!-- 角标 -->
  25. <div
  26. v-if="property.badge.show"
  27. class="absolute left-0 top-0 z-1 items-center justify-center"
  28. >
  29. <el-image :src="property.badge.imgUrl" class="h-26px w-38px" fit="cover" />
  30. </div>
  31. <!-- 商品封面图 -->
  32. <el-image :src="spu.picUrl" :style="{ width: imageSize, height: imageSize }" fit="cover" />
  33. <div
  34. :class="[
  35. 'flex flex-col gap-8px p-8px box-border',
  36. {
  37. 'w-[calc(100%-64px)]': columns === 2,
  38. 'w-full': columns === 3
  39. }
  40. ]"
  41. >
  42. <!-- 商品名称 -->
  43. <div
  44. v-if="property.fields.name.show"
  45. :style="{ color: property.fields.name.color }"
  46. class="truncate text-12px"
  47. >
  48. {{ spu.name }}
  49. </div>
  50. <div>
  51. <!-- 商品价格 -->
  52. <span
  53. v-if="property.fields.price.show"
  54. :style="{ color: property.fields.price.color }"
  55. class="text-12px"
  56. >
  57. ¥{{ fenToYuan(spu.combinationPrice || spu.price || 0) }}
  58. </span>
  59. </div>
  60. </div>
  61. </div>
  62. </div>
  63. </el-scrollbar>
  64. </template>
  65. <script lang="ts" setup>
  66. import { PromotionCombinationProperty } from './config'
  67. import * as ProductSpuApi from '@/api/mall/product/spu'
  68. import { Spu } from '@/api/mall/product/spu'
  69. import * as CombinationActivityApi from '@/api/mall/promotion/combination/combinationActivity'
  70. import { CombinationProductVO } from '@/api/mall/promotion/combination/combinationActivity'
  71. import { fenToYuan } from '@/utils'
  72. /** 拼团 */
  73. defineOptions({ name: 'PromotionCombination' })
  74. // 定义属性
  75. const props = defineProps<{ property: PromotionCombinationProperty }>()
  76. // 商品列表
  77. const spuList = ref<ProductSpuApi.Spu[]>([])
  78. watch(
  79. () => props.property.activityId,
  80. async () => {
  81. if (!props.property.activityId) return
  82. const activity = await CombinationActivityApi.getCombinationActivity(props.property.activityId)
  83. if (!activity?.spuId) return
  84. spuList.value = [await ProductSpuApi.getSpu(activity.spuId)]
  85. // 循环活动信息,赋值拼团价格
  86. activity.products.forEach((product: CombinationProductVO) => {
  87. spuList.value.forEach((spu: Spu) => {
  88. // 商品原售价和拼团价,哪个便宜就赋值哪个
  89. spu.combinationPrice = Math.min(spu.combinationPrice || Infinity, product.combinationPrice) // 设置 SPU 的最低价格
  90. })
  91. })
  92. },
  93. {
  94. immediate: true,
  95. deep: true
  96. }
  97. )
  98. // 手机宽度
  99. const phoneWidth = ref(375)
  100. // 容器
  101. const containerRef = ref()
  102. // 商品的列数
  103. const columns = ref(2)
  104. // 滚动条宽度
  105. const scrollbarWidth = ref('100%')
  106. // 商品图大小
  107. const imageSize = ref('0')
  108. // 商品网络列数
  109. const gridTemplateColumns = ref('')
  110. // 计算布局参数
  111. watch(
  112. () => [props.property, phoneWidth, spuList.value.length],
  113. () => {
  114. // 计算列数
  115. columns.value = props.property.layoutType === 'oneCol' ? 1 : 3
  116. // 每列的宽度为:(总宽度 - 间距 * (列数 - 1))/ 列数
  117. const productWidth =
  118. (phoneWidth.value - props.property.space * (columns.value - 1)) / columns.value
  119. // 商品图布局:2列时,左右布局 3列时,上下布局
  120. imageSize.value = columns.value === 2 ? '64px' : `${productWidth}px`
  121. // 指定列数
  122. gridTemplateColumns.value = `repeat(${columns.value}, auto)`
  123. // 不滚动
  124. scrollbarWidth.value = '100%'
  125. },
  126. { immediate: true, deep: true }
  127. )
  128. onMounted(() => {
  129. // 提取手机宽度
  130. phoneWidth.value = containerRef.value?.wrapRef?.offsetWidth || 375
  131. })
  132. </script>
  133. <style lang="scss" scoped></style>