Browse Source

fix: mall SeckillActivity

puhui999 1 year ago
parent
commit
ce3ca7c6ce

+ 17 - 17
src/api/mall/promotion/seckill/seckillActivity.ts

@@ -2,23 +2,23 @@ import request from '@/config/axios'
 import { Sku, Spu } from '@/api/mall/product/spu'
 
 export interface SeckillActivityVO {
-  id: number
-  spuIds: number[]
-  name: string
-  status: number
-  remark: string
-  startTime: Date
-  endTime: Date
-  sort: number
-  configIds: string
-  orderCount: number
-  userCount: number
-  totalPrice: number
-  totalLimitCount: number
-  singleLimitCount: number
-  stock: number
-  totalStock: number
-  products: SeckillProductVO[]
+  id?: number
+  spuId?: number
+  name?: string
+  status?: number
+  remark?: string
+  startTime?: Date
+  endTime?: Date
+  sort?: number
+  configIds?: string
+  orderCount?: number
+  userCount?: number
+  totalPrice?: number
+  totalLimitCount?: number
+  singleLimitCount?: number
+  stock?: number
+  totalStock?: number
+  products?: SeckillProductVO[]
 }
 
 // 秒杀活动所需属性

+ 7 - 3
src/views/mall/product/spu/components/SkuList.vue

@@ -113,6 +113,7 @@
   <!-- 情况二:详情 -->
   <el-table
     v-if="isDetail"
+    ref="activitySkuListRef"
     :data="formData!.skus"
     border
     max-height="500"
@@ -194,7 +195,6 @@
   <!-- 情况三:作为活动组件 -->
   <el-table
     v-if="isActivityComponent"
-    ref="activitySkuListRef"
     :data="formData!.skus"
     border
     max-height="500"
@@ -261,6 +261,7 @@ import type { Property, Sku, Spu } from '@/api/mall/product/spu'
 import { createImageViewer } from '@/components/ImageViewer'
 import { RuleConfig } from '@/views/mall/product/spu/components/index'
 import { Properties } from './index'
+import { ElTable } from 'element-plus'
 
 defineOptions({ name: 'SkuList' })
 const message = useMessage() // 消息弹窗
@@ -515,7 +516,6 @@ watch(
       // name加属性项index区分属性值
       tableHeaders.value.push({ prop: `name${index}`, label: item.name })
     })
-
     // 如果回显的 sku 属性和添加的属性一致则不处理
     if (validateData(propertyList)) {
       return
@@ -532,6 +532,10 @@ watch(
     immediate: true
   }
 )
+const activitySkuListRef = ref<InstanceType<typeof ElTable>>()
+const clearSelection = () => {
+  activitySkuListRef.value.clearSelection()
+}
 // 暴露出生成 sku 方法,给添加属性成功时调用
-defineExpose({ generateTableData, validateSku })
+defineExpose({ generateTableData, validateSku, clearSelection })
 </script>

+ 6 - 3
src/views/mall/promotion/components/SpuAndSkuList.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-table :data="spuData" :default-expand-all="true">
+  <el-table :data="spuData" :expand-row-keys="expandRowKeys" row-key="id">
     <el-table-column type="expand" width="30">
       <template #default="{ row }">
         <SkuList
@@ -48,9 +48,8 @@ const props = defineProps<{
 
 const spuData = ref<Spu[]>([]) // spu 详情数据列表
 const skuListRef = ref() // 商品属性列表Ref
-
 const spuPropertyList = ref<SpuProperty<T>[]>([]) // spuId 对应的 sku 的属性列表
-
+const expandRowKeys = ref<number[]>() // 控制展开行需要设置 row-key 属性才能使用,该属性为展开行的 keys 数组。
 /**
  * 获取所有 sku 活动配置
  * @param extendedAttribute 在 sku 上扩展的属性,例:秒杀活动 sku 扩展属性 productConfig 请参考 seckillActivity.ts
@@ -98,6 +97,10 @@ watch(
   (data) => {
     if (!data) return
     spuPropertyList.value = data as SpuProperty<T>[]
+    // 解决如果之前选择的是单规格 spu 的话后面选择多规格 sku 多规格属性信息不展示的问题。解决方法:让 SkuList 组件重新渲染(行折叠会干掉包含的组件展开时会重新加载)
+    setTimeout(() => {
+      expandRowKeys.value = data.map((item) => item.spuId)
+    }, 200)
   },
   {
     deep: true,

+ 6 - 0
src/views/mall/promotion/components/SpuSelect.vue

@@ -57,6 +57,7 @@
           <template #default>
             <SkuList
               v-if="isExpand"
+              ref="skuListRef"
               :isComponent="true"
               :isDetail="true"
               :prop-form-data="spuData"
@@ -145,6 +146,7 @@ const queryParams = ref({
 }) // 查询参数
 const propertyList = ref<Properties[]>([]) // 商品属性列表
 const spuListRef = ref<InstanceType<typeof ElTable>>()
+const skuListRef = ref() // 商品属性选择 Ref
 const spuData = ref<ProductSpuApi.Spu>() // 商品详情
 const isExpand = ref(false) // 控制 SKU 列表显示
 const expandRowKeys = ref<number[]>() // 控制展开行需要设置 row-key 属性才能使用,该属性为展开行的 keys 数组。
@@ -154,6 +156,8 @@ const selectedSpuId = ref<number>(0) // 选中的商品 spuId
 const selectedSkuIds = ref<number[]>([]) // 选中的商品 skuIds
 const selectSku = (val: ProductSpuApi.Sku[]) => {
   if (selectedSpuId.value === 0) {
+    message.warning('请先选择商品再选择相应的规格!!!')
+    skuListRef.value.clearSelection()
     return
   }
   selectedSkuIds.value = val.map((sku) => sku.id!)
@@ -233,6 +237,8 @@ const confirm = () => {
     : emits('confirm', selectedSpuId.value)
   // 关闭弹窗
   dialogVisible.value = false
+  selectedSpuId.value = 0
+  selectedSkuIds.value = []
 }
 
 /** 打开弹窗 */

+ 28 - 8
src/views/mall/promotion/seckill/activity/SeckillActivityForm.vue

@@ -50,7 +50,7 @@ import * as SeckillActivityApi from '@/api/mall/promotion/seckill/seckillActivit
 import { SeckillProductVO } from '@/api/mall/promotion/seckill/seckillActivity'
 import * as ProductSpuApi from '@/api/mall/product/spu'
 import { getPropertyList, RuleConfig } from '@/views/mall/product/spu/components'
-import { convertToInteger } from '@/utils'
+import { convertToInteger, formatToFraction } from '@/utils'
 
 defineOptions({ name: 'PromotionSeckillActivityForm' })
 
@@ -89,7 +89,11 @@ const selectSpu = (spuId: number, skuIds: number[]) => {
  * 获取 SPU 详情
  * @param spuIds
  */
-const getSpuDetails = async (spuId: number, skuIds: number[]) => {
+const getSpuDetails = async (
+  spuId: number,
+  skuIds: number[] | undefined,
+  products?: SeckillProductVO[]
+) => {
   const spuProperties: SpuProperty<SeckillActivityApi.SpuExtension>[] = []
   const res = (await ProductSpuApi.getSpuDetailList([spuId])) as SeckillActivityApi.SpuExtension[]
   if (res.length == 0) {
@@ -98,13 +102,22 @@ const getSpuDetails = async (spuId: number, skuIds: number[]) => {
   spuList.value = []
   // 因为只能选择一个
   const spu = res[0]
-  const selectSkus = spu?.skus?.filter((sku) => skuIds.includes(sku.id!))
+  const selectSkus =
+    typeof skuIds === 'undefined' ? spu?.skus : spu?.skus?.filter((sku) => skuIds.includes(sku.id!))
   selectSkus?.forEach((sku) => {
-    const config: SeckillActivityApi.SeckillProductVO = {
+    let config: SeckillActivityApi.SeckillProductVO = {
       skuId: sku.id!,
       stock: 0,
       seckillPrice: 0
     }
+    if (typeof products !== 'undefined') {
+      const product = products.find((item) => item.skuId === sku.id)
+      if (product) {
+        // 元转分
+        product.seckillPrice = formatToFraction(product.seckillPrice)
+      }
+      config = product || config
+    }
     sku.productConfig = config
   })
   spu.skus = selectSkus as SeckillActivityApi.SkuExtension[]
@@ -113,7 +126,7 @@ const getSpuDetails = async (spuId: number, skuIds: number[]) => {
     spuDetail: spu,
     propertyList: getPropertyList(spu)
   })
-  spuList.value.push(...res)
+  spuList.value.push(spu)
   spuPropertyList.value = spuProperties
 }
 
@@ -125,11 +138,18 @@ const open = async (type: string, id?: number) => {
   dialogTitle.value = t('action.' + type)
   formType.value = type
   await resetForm()
-  // 修改时,设置数据 TODO 没测试估计有问题
+  // 修改时,设置数据
   if (id) {
     formLoading.value = true
     try {
-      const data = await SeckillActivityApi.getSeckillActivity(id)
+      const data = (await SeckillActivityApi.getSeckillActivity(
+        id
+      )) as SeckillActivityApi.SeckillActivityVO
+      await getSpuDetails(
+        data.spuId!,
+        data.products?.map((sku) => sku.skuId),
+        data.products
+      )
       formRef.value.setValues(data)
     } finally {
       formLoading.value = false
@@ -162,7 +182,7 @@ const submitForm = async () => {
       item.seckillPrice = convertToInteger(item.seckillPrice)
     })
     // 获取秒杀商品配置
-    data.products = spuAndSkuListRef.value.getSkuConfigs('productConfig')
+    data.products = products
     if (formType.value === 'create') {
       await SeckillActivityApi.createSeckillActivity(data)
       message.success(t('common.createSuccess'))