SpuAndSkuList.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. <template>
  2. <el-table :data="spuData">
  3. <el-table-column type="expand" width="30">
  4. <template #default="{ row }">
  5. <SkuList
  6. ref="skuListRef"
  7. :is-activity-component="true"
  8. :prop-form-data="spuPropertyList.find((item) => item.spuId === row.id)?.spuDetail"
  9. :property-list="spuPropertyList.find((item) => item.spuId === row.id)?.propertyList"
  10. :rule-config="ruleConfig"
  11. >
  12. <template #extension>
  13. <el-table-column align="center" label="秒杀库存" min-width="168">
  14. <template #default="{ row: sku }">
  15. <el-input-number v-model="sku.productConfig.stock" :min="0" class="w-100%" />
  16. </template>
  17. </el-table-column>
  18. <el-table-column align="center" label="秒杀价格(元)" min-width="168">
  19. <template #default="{ row: sku }">
  20. <el-input-number
  21. v-model="sku.productConfig.seckillPrice"
  22. :min="0"
  23. :precision="2"
  24. :step="0.1"
  25. class="w-100%"
  26. />
  27. </template>
  28. </el-table-column>
  29. </template>
  30. </SkuList>
  31. </template>
  32. </el-table-column>
  33. <el-table-column key="id" align="center" label="商品编号" prop="id" />
  34. <el-table-column label="商品图" min-width="80">
  35. <template #default="{ row }">
  36. <el-image :src="row.picUrl" class="w-30px h-30px" @click="imagePreview(row.picUrl)" />
  37. </template>
  38. </el-table-column>
  39. <el-table-column :show-overflow-tooltip="true" label="商品名称" min-width="300" prop="name" />
  40. <el-table-column align="center" label="商品售价" min-width="90" prop="price">
  41. <template #default="{ row }">
  42. {{ formatToFraction(row.price) }}
  43. </template>
  44. </el-table-column>
  45. <el-table-column align="center" label="销量" min-width="90" prop="salesCount" />
  46. <el-table-column align="center" label="库存" min-width="90" prop="stock" />
  47. </el-table>
  48. </template>
  49. <script lang="ts" name="SpuAndSkuList" setup>
  50. // TODO 后续计划重新封装作为活动商品配置通用组件
  51. import { formatToFraction } from '@/utils'
  52. import { createImageViewer } from '@/components/ImageViewer'
  53. import * as ProductSpuApi from '@/api/mall/product/spu'
  54. import { SpuRespVO } from '@/api/mall/product/spu'
  55. import {
  56. getPropertyList,
  57. Properties,
  58. RuleConfig,
  59. SkuList
  60. } from '@/views/mall/product/spu/components'
  61. import { SeckillProductVO, SpuExtension } from '@/api/mall/promotion/seckill/seckillActivity'
  62. const props = defineProps({
  63. spuList: {
  64. type: Array,
  65. default: () => []
  66. }
  67. })
  68. const spuData = ref<SpuRespVO[]>([]) // spu 详情数据列表
  69. const skuListRef = ref() // 商品属性列表Ref
  70. interface spuProperty {
  71. spuId: number
  72. spuDetail: SpuExtension
  73. propertyList: Properties[]
  74. }
  75. const spuPropertyList = ref<spuProperty[]>([]) // spuId 对应的 sku 的属性列表
  76. /**
  77. * 获取 SPU 详情
  78. * @param spuIds
  79. */
  80. const getSpuDetails = async (spuIds: number[]) => {
  81. const spuProperties: spuProperty[] = []
  82. // TODO puhui999: 考虑后端添加通过 spuIds 批量获取
  83. for (const spuId of spuIds) {
  84. // 获取 SPU 详情
  85. const res = (await ProductSpuApi.getSpu(spuId)) as SpuExtension
  86. if (!res) {
  87. continue
  88. }
  89. // 初始化每个 sku 秒杀配置
  90. res.skus?.forEach((sku) => {
  91. const config: SeckillProductVO = {
  92. spuId,
  93. skuId: sku.id!,
  94. stock: 0,
  95. seckillPrice: 0
  96. }
  97. sku.productConfig = config
  98. })
  99. spuProperties.push({ spuId, spuDetail: res, propertyList: getPropertyList(res) })
  100. }
  101. spuPropertyList.value = spuProperties
  102. }
  103. const ruleConfig: RuleConfig[] = [
  104. {
  105. name: 'stock',
  106. geValue: 10
  107. },
  108. {
  109. name: 'seckillPrice',
  110. geValue: 0.01
  111. }
  112. ]
  113. const message = useMessage() // 消息弹窗
  114. /**
  115. * 获取所有 sku 秒杀配置
  116. */
  117. const getSkuConfigs = (): SeckillProductVO[] => {
  118. if (!skuListRef.value.validateSku()) {
  119. // TODO 作为通用组件是需要进一步完善
  120. message.warning('请检查商品相关属性配置!!')
  121. throw new Error('请检查商品相关属性配置!!')
  122. }
  123. const seckillProducts: SeckillProductVO[] = []
  124. spuPropertyList.value.forEach((item) => {
  125. item.spuDetail.skus.forEach((sku) => {
  126. seckillProducts.push(sku.productConfig)
  127. })
  128. })
  129. return seckillProducts
  130. }
  131. // 暴露出给表单提交时使用
  132. defineExpose({ getSkuConfigs })
  133. /** 商品图预览 */
  134. const imagePreview = (imgUrl: string) => {
  135. createImageViewer({
  136. zIndex: 99999999,
  137. urlList: [imgUrl]
  138. })
  139. }
  140. /**
  141. * 将传进来的值赋值给 skuList
  142. */
  143. watch(
  144. () => props.spuList,
  145. (data) => {
  146. if (!data) return
  147. spuData.value = data as SpuRespVO[]
  148. getSpuDetails(spuData.value.map((spu) => spu.id!))
  149. },
  150. {
  151. deep: true,
  152. immediate: true
  153. }
  154. )
  155. </script>