Jelajahi Sumber

!545 【代码优化】商城: 限时折扣活动
Merge pull request !545 from puhui999/dev-crm

芋道源码 9 bulan lalu
induk
melakukan
1bd853bb32

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

@@ -180,17 +180,17 @@
     </el-table-column>
     <el-table-column align="center" label="销售价(元)" min-width="80">
       <template #default="{ row }">
-        {{ formatToFraction(row.price) }}
+        {{ row.price }}
       </template>
     </el-table-column>
     <el-table-column align="center" label="市场价(元)" min-width="80">
       <template #default="{ row }">
-        {{ formatToFraction(row.marketPrice) }}
+        {{ row.marketPrice }}
       </template>
     </el-table-column>
     <el-table-column align="center" label="成本价(元)" min-width="80">
       <template #default="{ row }">
-        {{ formatToFraction(row.costPrice) }}
+        {{ row.costPrice }}
       </template>
     </el-table-column>
     <el-table-column align="center" label="库存" min-width="80">
@@ -211,12 +211,12 @@
     <template v-if="formData!.subCommissionType">
       <el-table-column align="center" label="一级返佣(元)" min-width="80">
         <template #default="{ row }">
-          {{ formatToFraction(row.firstBrokeragePrice) }}
+          {{ row.firstBrokeragePrice }}
         </template>
       </el-table-column>
       <el-table-column align="center" label="二级返佣(元)" min-width="80">
         <template #default="{ row }">
-          {{ formatToFraction(row.secondBrokeragePrice) }}
+          {{ row.secondBrokeragePrice }}
         </template>
       </el-table-column>
     </template>

+ 9 - 9
src/views/mall/promotion/components/SpuAndSkuList.vue

@@ -30,13 +30,13 @@
     <el-table-column align="center" label="销量" min-width="90" prop="salesCount" />
     <el-table-column align="center" label="库存" min-width="90" prop="stock" />
     <el-table-column
-      v-if="spuData.length > 1 && isDelete"
+      v-if="spuData.length > 1 && deletable"
       align="center"
       label="操作"
       min-width="90"
     >
       <template #default="scope">
-        <el-button type="primary" link @click="deleteSpu(scope.row.id)"> 删除 </el-button>
+        <el-button link type="primary" @click="deleteSpu(scope.row.id)"> 删除</el-button>
       </template>
     </el-table-column>
   </el-table>
@@ -56,13 +56,13 @@ const props = defineProps<{
   spuList: T[]
   ruleConfig: RuleConfig[]
   spuPropertyListP: SpuProperty<T>[]
-  isDelete?: boolean // SPU 是否可删除;TODO deletable 换成这个名字好点。
+  deletable?: boolean // SPU 是否可删除;
 }>()
 
 const spuData = ref<Spu[]>([]) // spu 详情数据列表
 const skuListRef = ref() // 商品属性列表Ref
 const spuPropertyList = ref<SpuProperty<T>[]>([]) // spuId 对应的 sku 的属性列表
-const expandRowKeys = ref<number[]>() // 控制展开行需要设置 row-key 属性才能使用,该属性为展开行的 keys 数组。
+const expandRowKeys = ref<string[]>([]) // 控制展开行需要设置 row-key 属性才能使用,该属性为展开行的 keys 数组。
 
 /**
  * 获取所有 sku 活动配置
@@ -71,10 +71,10 @@ const expandRowKeys = ref<number[]>() // 控制展开行需要设置 row-key 属
  */
 const getSkuConfigs = (extendedAttribute: string) => {
   skuListRef.value.validateSku()
-  const seckillProducts = []
+  const seckillProducts: any[] = []
   spuPropertyList.value.forEach((item) => {
-    item.spuDetail.skus.forEach((sku) => {
-      seckillProducts.push(sku[extendedAttribute])
+    item.spuDetail.skus?.forEach((sku: any) => {
+      seckillProducts.push(sku[extendedAttribute] as any)
     })
   })
   return seckillProducts
@@ -124,10 +124,10 @@ watch(
   () => props.spuPropertyListP,
   (data) => {
     if (!data) return
-    spuPropertyList.value = data as SpuProperty<T>[]
+    spuPropertyList.value = data as SpuProperty<T>[] as any
     // 解决如果之前选择的是单规格 spu 的话后面选择多规格 sku 多规格属性信息不展示的问题。解决方法:让 SkuList 组件重新渲染(行折叠会干掉包含的组件展开时会重新加载)
     setTimeout(() => {
-      expandRowKeys.value = data.map((item) => item.spuId)
+      expandRowKeys.value = data.map((item) => item.spuId + '')
     }, 200)
   },
   {

+ 71 - 33
src/views/mall/promotion/discountActivity/DiscountActivityForm.vue

@@ -8,28 +8,40 @@
       :schema="allSchemas.formSchema"
     >
       <!-- 先选择 -->
-      <!-- TODO @zhangshuai:商品允许选择多个 -->
-      <!-- TODO @zhangshuai:选择后的 SKU,需要后面加个【删除】按钮 -->
-      <!-- TODO @zhangshuai:展示的金额,貌似不对,大了 100 倍,需要看下 -->
-      <!-- TODO @zhangshuai:“优惠类型”,是每个 SKU 可以自定义已设置哈。因为每个商品 SKU 的折扣和减少价格,可能不同。具体交互,可以注册一个 youzan.com 看看;它的交互方式是,如果设置了“优惠金额”,则算“减价”;如果再次设置了“折扣百分比”,就算“打折”;这样形成一个互斥的优惠类型 -->
       <template #spuId>
         <el-button @click="spuSelectRef.open()">选择商品</el-button>
         <SpuAndSkuList
           ref="spuAndSkuListRef"
+          :deletable="true"
           :rule-config="ruleConfig"
           :spu-list="spuList"
           :spu-property-list-p="spuPropertyList"
-          :isDelete="true"
           @delete="deleteSpu"
         >
           <el-table-column align="center" label="优惠金额" min-width="168">
-            <template #default="{ row: sku }">
-              <el-input-number v-model="sku.productConfig.discountPrice" :min="0" class="w-100%" />
+            <template #default="{ row }">
+              <el-input-number
+                v-model="row.productConfig.discountPrice"
+                :max="parseFloat(fenToYuan(row.price))"
+                :min="0"
+                :precision="2"
+                :step="0.1"
+                class="w-100%"
+                @change="handleSkuDiscountPriceChange(row)"
+              />
             </template>
           </el-table-column>
           <el-table-column align="center" label="折扣百分比(%)" min-width="168">
-            <template #default="{ row: sku }">
-              <el-input-number v-model="sku.productConfig.discountPercent" class="w-100%" />
+            <template #default="{ row }">
+              <el-input-number
+                v-model="row.productConfig.discountPercent"
+                :max="100"
+                :min="0"
+                :precision="2"
+                :step="0.1"
+                class="w-100%"
+                @change="handleSkuDiscountPercentChange(row)"
+              />
             </template>
           </el-table-column>
         </SpuAndSkuList>
@@ -45,11 +57,12 @@
 <script lang="ts" setup>
 import { SpuAndSkuList, SpuProperty, SpuSelect } from '../components'
 import { allSchemas, rules } from './discountActivity.data'
-import { cloneDeep } from 'lodash-es'
+import { cloneDeep, debounce } from 'lodash-es'
 import * as DiscountActivityApi from '@/api/mall/promotion/discount/discountActivity'
 import * as ProductSpuApi from '@/api/mall/product/spu'
 import { getPropertyList, RuleConfig } from '@/views/mall/product/spu/components'
-import { formatToFraction } from '@/utils'
+import { convertToInteger, erpCalculatePercentage, fenToYuan, yuanToFen } from '@/utils'
+import { PromotionDiscountTypeEnum } from '@/utils/constants'
 
 defineOptions({ name: 'PromotionDiscountActivityForm' })
 
@@ -65,11 +78,19 @@ const formRef = ref() // 表单 Ref
 
 const spuSelectRef = ref() // 商品和属性选择 Ref
 const spuAndSkuListRef = ref() // sku 限时折扣  配置组件Ref
-const ruleConfig: RuleConfig[] = []
+const ruleConfig: RuleConfig[] = [
+  {
+    name: 'productConfig.discountPrice',
+    rule: (arg) => arg > 0,
+    message: '商品优惠金额不能为 0 !!!'
+  }
+]
 const spuList = ref<DiscountActivityApi.SpuExtension[]>([]) // 选择的 spu
 const spuPropertyList = ref<SpuProperty<DiscountActivityApi.SpuExtension>[]>([])
 const spuIds = ref<number[]>([])
 const selectSpu = (spuId: number, skuIds: number[]) => {
+  // TODO puhui999: 艿艿现在限时折扣活动可以选择多个 spu ,那么 spuId 是不是得改成 spuIds 来存放多个?🤣
+  formRef.value.setValues({ spuId })
   getSpuDetails(spuId, skuIds)
 }
 /**
@@ -101,21 +122,20 @@ const getSpuDetails = async (
   selectSkus?.forEach((sku) => {
     let config: DiscountActivityApi.DiscountProductVO = {
       skuId: sku.id!,
-      spuId: spu.id,
+      spuId: spu.id!,
       discountType: 1,
       discountPercent: 0,
       discountPrice: 0
     }
     if (typeof products !== 'undefined') {
       const product = products.find((item) => item.skuId === sku.id)
+      if (product) {
+        product.discountPercent = fenToYuan(product.discountPercent) as any
+        product.discountPrice = fenToYuan(product.discountPrice) as any
+      }
       config = product || config
     }
     sku.productConfig = config
-    sku.price = formatToFraction(sku.price)
-    sku.marketPrice = formatToFraction(sku.marketPrice)
-    sku.costPrice = formatToFraction(sku.costPrice)
-    sku.firstBrokeragePrice = formatToFraction(sku.firstBrokeragePrice)
-    sku.secondBrokeragePrice = formatToFraction(sku.secondBrokeragePrice)
   })
   spu.skus = selectSkus as DiscountActivityApi.SkuExtension[]
   spuPropertyList.value.push({
@@ -168,25 +188,13 @@ const submitForm = async () => {
   // 提交请求
   formLoading.value = true
   try {
-    const data = formRef.value.formModel as DiscountActivityApi.DiscountActivityVO
     // 获取折扣商品配置
     const products = cloneDeep(spuAndSkuListRef.value.getSkuConfigs('productConfig'))
-    // 校验优惠金额、折扣百分比,是否正确
-    // TODO @puhui999:这个交互,可以参考下 youzan 的
-    let discountInvalid = false
     products.forEach((item: DiscountActivityApi.DiscountProductVO) => {
-      if (item.discountPrice != null && item.discountPrice > 0) {
-        item.discountType = 1
-      } else if (item.discountPercent != null && item.discountPercent > 0) {
-        item.discountType = 2
-      } else {
-        discountInvalid = true
-      }
+      item.discountPercent = convertToInteger(item.discountPercent)
+      item.discountPrice = convertToInteger(item.discountPrice)
     })
-    if (discountInvalid) {
-      message.error('优惠金额和折扣百分比需要填写一个')
-      return
-    }
+    const data = cloneDeep(formRef.value.formModel) as DiscountActivityApi.DiscountActivityVO
     data.products = products
     // 真正提交
     if (formType.value === 'create') {
@@ -204,6 +212,36 @@ const submitForm = async () => {
   }
 }
 
+/** 处理 sku 优惠金额变动 */
+const handleSkuDiscountPriceChange = debounce((row: any) => {
+  // 校验边界
+  if (row.productConfig.discountPrice <= 0) {
+    return
+  }
+
+  // 设置优惠类型:满减
+  row.productConfig.discountType = PromotionDiscountTypeEnum.PRICE.type
+  // 设置折扣
+  row.productConfig.discountPercent = erpCalculatePercentage(
+    row.price - yuanToFen(row.productConfig.discountPrice),
+    row.price
+  )
+}, 200)
+/** 处理 sku 优惠折扣变动 */
+const handleSkuDiscountPercentChange = debounce((row: any) => {
+  // 校验边界
+  if (row.productConfig.discountPercent <= 0 || row.productConfig.discountPercent >= 100) {
+    return
+  }
+
+  // 设置优惠类型:折扣
+  row.productConfig.discountType = PromotionDiscountTypeEnum.PERCENT.type
+  // 设置满减金额
+  row.productConfig.discountPrice = fenToYuan(
+    row.price - row.price * (row.productConfig.discountPercent / 100.0 || 0)
+  )
+}, 200)
+
 /** 重置表单 */
 const resetForm = async () => {
   spuList.value = []