Explorar o código

fix: mall SeckillActivity and CombinationActivity

puhui999 hai 1 ano
pai
achega
4057130275

+ 31 - 13
src/api/mall/promotion/combination/combinationactivity.ts

@@ -1,20 +1,38 @@
 import request from '@/config/axios'
+import { Sku, Spu } from '@/api/mall/product/spu'
 
 export interface CombinationActivityVO {
-  id: number
-  name: string
+  id?: number
+  name?: string
+  spuIds?: number[]
+  totalLimitCount?: number
+  singleLimitCount?: number
+  startTime?: Date
+  endTime?: Date
+  userSize?: number
+  totalNum?: number
+  successNum?: number
+  orderUserCount?: number
+  virtualGroup?: number
+  status?: number
+  limitDuration?: number
+  products: CombinationProductVO[]
+}
+
+// 拼团活动所需属性
+export interface CombinationProductVO {
   spuId: number
-  totalLimitCount: number
-  singleLimitCount: number
-  startTime: Date
-  endTime: Date
-  userSize: number
-  totalNum: number
-  successNum: number
-  orderUserCount: number
-  virtualGroup: number
-  status: number
-  limitDuration: number
+  skuId: number
+  activePrice: number // 拼团价格
+}
+
+// 扩展 Sku 配置
+type SkuExtension = Sku & {
+  productConfig: CombinationProductVO
+}
+
+export interface SpuExtension extends Spu {
+  skus: SkuExtension[] // 重写类型
 }
 
 // 查询拼团活动列表

+ 1 - 1
src/utils/formatTime.ts

@@ -27,7 +27,7 @@ export function formatDate(date: Date, format?: string): string {
  * 获取当前的日期+时间
  */
 export function getNowDateTime() {
-  return dayjs().format('YYYY-MM-DD HH:mm:ss')
+  return dayjs()
 }
 
 /**

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

@@ -2,7 +2,7 @@
   <!-- 情况一:添加/修改 -->
   <el-table
     v-if="!isDetail && !isActivityComponent"
-    :data="isBatch ? skuList : formData!.skus"
+    :data="isBatch ? skuList : formData!.skus!"
     border
     class="tabNumWidth"
     max-height="500"
@@ -114,7 +114,7 @@
   <el-table
     v-if="isDetail"
     ref="activitySkuListRef"
-    :data="formData!.skus"
+    :data="formData!.skus!"
     border
     max-height="500"
     size="small"
@@ -195,7 +195,7 @@
   <!-- 情况三:作为活动组件 -->
   <el-table
     v-if="isActivityComponent"
-    :data="formData!.skus"
+    :data="formData!.skus!"
     border
     max-height="500"
     size="small"
@@ -260,7 +260,7 @@ import { UploadImg } from '@/components/UploadFile'
 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 { PropertyAndValues } from './index'
 import { ElTable } from 'element-plus'
 
 defineOptions({ name: 'SkuList' })
@@ -272,7 +272,7 @@ const props = defineProps({
     default: () => {}
   },
   propertyList: {
-    type: Array as PropType<Properties[]>,
+    type: Array as PropType<PropertyAndValues[]>,
     default: () => []
   },
   ruleConfig: {
@@ -482,7 +482,7 @@ const build = (propertyValuesList: Property[][]) => {
 /** 监听属性列表,生成相关参数和表头 */
 watch(
   () => props.propertyList,
-  (propertyList: Properties[]) => {
+  (propertyList: PropertyAndValues[]) => {
     // 如果不是多规格则结束
     if (!formData.value!.specType) {
       return

+ 8 - 8
src/views/mall/product/spu/components/index.ts

@@ -7,11 +7,11 @@ import SkuList from './SkuList.vue'
 
 import { Spu } from '@/api/mall/product/spu'
 
-// TODO @puhui999:Properties 改成 Property 更合适?
-interface Properties {
+// TODO @puhui999:Properties 改成 Property 更合适?Property 在 Spu 中已存在避免冲突 PropertyAndValues
+interface PropertyAndValues {
   id: number
   name: string
-  values?: Properties[]
+  values?: PropertyAndValues[]
 }
 
 interface RuleConfig {
@@ -23,7 +23,7 @@ interface RuleConfig {
   // 例:需要校验价格必须大于0.01
   // {
   //  name:'price',
-  //  rule:(arg) => arg > 0.01
+  //  rule:(arg: number) => arg > 0.01
   // }
   rule: (arg: any) => boolean
   // 校验不通过时的消息提示
@@ -34,11 +34,11 @@ interface RuleConfig {
  * 获得商品的规格列表
  *
  * @param spu
- * @return Property 规格列表
+ * @return PropertyAndValues 规格列表
  */
-const getPropertyList = (spu: Spu): Properties[] => {
+const getPropertyList = (spu: Spu): PropertyAndValues[] => {
   //  直接拿返回的 skus 属性逆向生成出 propertyList
-  const properties: Properties[] = []
+  const properties: PropertyAndValues[] = []
   // 只有是多规格才处理
   if (spu.specType) {
     spu.skus?.forEach((sku) => {
@@ -66,6 +66,6 @@ export {
   ProductPropertyAddForm,
   SkuList,
   getPropertyList,
-  Properties,
+  PropertyAndValues,
   RuleConfig
 }

+ 82 - 2
src/views/mall/promotion/combination/activity/CombinationActivityForm.vue

@@ -1,21 +1,49 @@
 <template>
-  <Dialog v-model="dialogVisible" :title="dialogTitle">
+  <Dialog v-model="dialogVisible" :title="dialogTitle" width="65%">
     <Form
       ref="formRef"
       v-loading="formLoading"
       :is-col="true"
       :rules="rules"
       :schema="allSchemas.formSchema"
-    />
+    >
+      <template #spuIds>
+        <el-button @click="spuSelectRef.open()">选择商品</el-button>
+        <SpuAndSkuList
+          ref="spuAndSkuListRef"
+          :rule-config="ruleConfig"
+          :spu-list="spuList"
+          :spu-property-list-p="spuPropertyList"
+        >
+          <el-table-column align="center" label="拼团价格(元)" min-width="168">
+            <template #default="{ row: sku }">
+              <el-input-number
+                v-model="sku.productConfig.activePrice"
+                :min="0"
+                :precision="2"
+                :step="0.1"
+                class="w-100%"
+              />
+            </template>
+          </el-table-column>
+        </SpuAndSkuList>
+      </template>
+    </Form>
     <template #footer>
       <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
+  <SpuSelect ref="spuSelectRef" @confirm="selectSpu" />
 </template>
 <script lang="ts" setup>
 import * as CombinationActivityApi from '@/api/mall/promotion/combination/combinationactivity'
+import { CombinationProductVO } from '@/api/mall/promotion/combination/combinationactivity'
 import { allSchemas, rules } from './combinationActivity.data'
+import { SpuAndSkuList, SpuProperty, SpuSelect } from '@/views/mall/promotion/components'
+import { getPropertyList, RuleConfig } from '@/views/mall/product/spu/components'
+import * as ProductSpuApi from '@/api/mall/product/spu'
+import { convertToInteger } from '@/utils'
 
 defineOptions({ name: 'PromotionCombinationActivityForm' })
 
@@ -28,6 +56,52 @@ const formLoading = ref(false) // 表单的加载中:1)修改时的数据加
 const formType = ref('') // 表单的类型:create - 新增;update - 修改
 const formRef = ref() // 表单 Ref
 
+// ================= 商品选择相关 =================
+
+const spuSelectRef = ref() // 商品和属性选择 Ref
+const spuAndSkuListRef = ref() // sku 秒杀配置组件Ref
+const spuList = ref<CombinationActivityApi.SpuExtension[]>([]) // 选择的 spu
+const spuPropertyList = ref<SpuProperty<CombinationActivityApi.SpuExtension>[]>([])
+const ruleConfig: RuleConfig[] = [
+  {
+    name: 'productConfig.activePrice',
+    rule: (arg) => arg > 0.01,
+    message: '商品拼团价格不能小于0.01 !!!'
+  }
+]
+const selectSpu = (spuId: number, skuIds: number[]) => {
+  formRef.value.setValues({ spuId })
+  getSpuDetails([spuId])
+  console.log(skuIds)
+}
+/**
+ * 获取 SPU 详情
+ * @param spuIds
+ */
+const getSpuDetails = async (spuIds: number[]) => {
+  const spuProperties: SpuProperty<CombinationActivityApi.SpuExtension>[] = []
+  const res = (await ProductSpuApi.getSpuDetailList(
+    spuIds
+  )) as CombinationActivityApi.SpuExtension[]
+  spuList.value = []
+  res?.forEach((spu) => {
+    // 初始化每个 sku 秒杀配置
+    spu.skus?.forEach((sku) => {
+      const config: CombinationActivityApi.CombinationProductVO = {
+        spuId: spu.id!,
+        skuId: sku.id!,
+        activePrice: 0
+      }
+      sku.productConfig = config
+    })
+    spuProperties.push({ spuId: spu.id!, spuDetail: spu, propertyList: getPropertyList(spu) })
+  })
+  spuList.value.push(...res)
+  spuPropertyList.value = spuProperties
+}
+
+// ================= end =================
+
 /** 打开弹窗 */
 const open = async (type: string, id?: number) => {
   dialogVisible.value = true
@@ -57,6 +131,12 @@ const submitForm = async () => {
   formLoading.value = true
   try {
     const data = formRef.value.formModel as CombinationActivityApi.CombinationActivityVO
+    const products = spuAndSkuListRef.value.getSkuConfigs('productConfig')
+    products.forEach((item: CombinationProductVO) => {
+      // 拼团价格元转分
+      item.activePrice = convertToInteger(item.activePrice)
+    })
+    data.products = products
     if (formType.value === 'create') {
       await CombinationActivityApi.createCombinationActivity(data)
       message.success(t('common.createSuccess'))

+ 9 - 26
src/views/mall/promotion/combination/activity/combinationActivity.data.ts

@@ -38,17 +38,19 @@ const crudSchemas = reactive<CrudSchema[]>([
       show: true,
       component: 'DatePicker',
       componentProps: {
-        valueFormat: 'YYYY-MM-DD HH:mm:ss',
-        type: 'datetimerange'
+        valueFormat: 'x',
+        type: 'datetimerange',
+        rangeSeparator: '至'
       }
     },
     form: {
       component: 'DatePicker',
       componentProps: {
-        valueFormat: 'YYYY-MM-DD HH:mm:ss',
-        type: 'datetimerange'
+        valueFormat: 'x',
+        type: 'datetimerange',
+        rangeSeparator: '至'
       },
-      value: [getNowDateTime(), getNowDateTime()],
+      value: [getNowDateTime().valueOf(), getNowDateTime().valueOf()],
       colProps: {
         span: 24
       }
@@ -120,10 +122,7 @@ const crudSchemas = reactive<CrudSchema[]>([
     field: 'virtualGroup',
     isSearch: false,
     isTable: false,
-    form: {
-      component: 'InputNumber',
-      value: 0
-    }
+    isForm: false
   },
   {
     label: '活动状态',
@@ -133,25 +132,9 @@ const crudSchemas = reactive<CrudSchema[]>([
     isSearch: true,
     isForm: false
   },
-  {
-    label: '创建时间',
-    field: 'createTime',
-    formatter: dateFormatter,
-    isSearch: false,
-    isTable: false,
-    search: {
-      component: 'DatePicker',
-      componentProps: {
-        valueFormat: 'YYYY-MM-DD HH:mm:ss',
-        type: 'daterange',
-        defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')]
-      }
-    },
-    isForm: false
-  },
   {
     label: '拼团商品',
-    field: 'spuId',
+    field: 'spuIds',
     isSearch: false,
     form: {
       colProps: {

+ 2 - 2
src/views/mall/promotion/components/SpuSelect.vue

@@ -111,7 +111,7 @@
 </template>
 
 <script lang="ts" setup>
-import { getPropertyList, Properties, SkuList } from '@/views/mall/product/spu/components'
+import { getPropertyList, PropertyAndValues, SkuList } from '@/views/mall/product/spu/components'
 import { ElTable } from 'element-plus'
 import { dateFormatter } from '@/utils/formatTime'
 import { createImageViewer } from '@/components/ImageViewer'
@@ -144,7 +144,7 @@ const queryParams = ref({
   categoryId: null,
   createTime: []
 }) // 查询参数
-const propertyList = ref<Properties[]>([]) // 商品属性列表
+const propertyList = ref<PropertyAndValues[]>([]) // 商品属性列表
 const spuListRef = ref<InstanceType<typeof ElTable>>()
 const skuListRef = ref() // 商品属性选择 Ref
 const spuData = ref<ProductSpuApi.Spu>() // 商品详情

+ 2 - 2
src/views/mall/promotion/components/index.ts

@@ -1,11 +1,11 @@
 import SpuSelect from './SpuSelect.vue'
 import SpuAndSkuList from './SpuAndSkuList.vue'
-import { Properties } from '@/views/mall/product/spu/components'
+import { PropertyAndValues } from '@/views/mall/product/spu/components'
 
 type SpuProperty<T> = {
   spuId: number
   spuDetail: T
-  propertyList: Properties[]
+  propertyList: PropertyAndValues[]
 }
 
 /**

+ 10 - 4
src/views/mall/promotion/seckill/activity/index.vue

@@ -66,6 +66,7 @@ import { allSchemas } from './seckillActivity.data'
 import { getListAllSimple } from '@/api/mall/promotion/seckill/seckillConfig'
 import * as SeckillActivityApi from '@/api/mall/promotion/seckill/seckillActivity'
 import SeckillActivityForm from './SeckillActivityForm.vue'
+import { cloneDeep } from 'lodash-es'
 
 defineOptions({ name: 'PromotionSeckillActivity' })
 
@@ -90,11 +91,10 @@ const handleDelete = (id: number) => {
   tableMethods.delList(id, false)
 }
 
-// TODO @puhui:是不是直接叫 configList 就好啦
-const seckillConfigAllSimple = ref([]) // 时段配置精简列表
+const configList = ref([]) // 时段配置精简列表
 const convertSeckillConfigNames = computed(
   () => (row) =>
-    seckillConfigAllSimple.value
+    configList.value
       ?.filter((item) => row.configIds.includes(item.id))
       ?.map((config) => config.name)
 )
@@ -106,7 +106,13 @@ const expandChange = (row, expandedRows) => {
 
 /** 初始化 **/
 onMounted(async () => {
+  // 处理一下表格列让商品往前
+  const index = allSchemas.tableColumns.findIndex((item) => item.field === 'spuId')
+  const column = cloneDeep(allSchemas.tableColumns[index])
+  allSchemas.tableColumns.splice(index, 1)
+  // 添加到开头
+  allSchemas.tableColumns.unshift(column)
   await getList()
-  seckillConfigAllSimple.value = await getListAllSimple()
+  configList.value = await getListAllSimple()
 })
 </script>

+ 1 - 1
src/views/mall/promotion/seckill/activity/seckillActivity.data.ts

@@ -186,7 +186,7 @@ const crudSchemas = reactive<CrudSchema[]>([
   {
     label: '秒杀活动商品',
     field: 'spuId',
-    isTable: false,
+    isTable: true,
     isSearch: false,
     form: {
       colProps: {