fix: mall SeckillActivity

This commit is contained in:
puhui999 2023-07-05 11:32:32 +08:00
parent b98149f1a7
commit 36c0bce184
6 changed files with 140 additions and 97 deletions

View File

@ -23,14 +23,13 @@ export interface SeckillActivityVO {
// 秒杀活动所需属性 // 秒杀活动所需属性
export interface SeckillProductVO { export interface SeckillProductVO {
spuId: number
skuId: number skuId: number
seckillPrice: number seckillPrice: number
stock: number stock: number
} }
// 扩展 Sku 配置 // 扩展 Sku 配置
type SkuExtension = Sku & { export type SkuExtension = Sku & {
productConfig: SeckillProductVO productConfig: SeckillProductVO
} }

View File

@ -194,6 +194,7 @@
<!-- 情况三作为活动组件 --> <!-- 情况三作为活动组件 -->
<el-table <el-table
v-if="isActivityComponent" v-if="isActivityComponent"
ref="activitySkuListRef"
:data="formData!.skus" :data="formData!.skus"
border border
max-height="500" max-height="500"

View File

@ -10,22 +10,7 @@
:rule-config="ruleConfig" :rule-config="ruleConfig"
> >
<template #extension> <template #extension>
<el-table-column align="center" label="秒杀库存" min-width="168"> <slot></slot>
<template #default="{ row: sku }">
<el-input-number v-model="sku.productConfig.stock" :min="0" class="w-100%" />
</template>
</el-table-column>
<el-table-column align="center" label="秒杀价格(元)" min-width="168">
<template #default="{ row: sku }">
<el-input-number
v-model="sku.productConfig.seckillPrice"
:min="0"
:precision="2"
:step="0.1"
class="w-100%"
/>
</template>
</el-table-column>
</template> </template>
</SkuList> </SkuList>
</template> </template>
@ -56,7 +41,7 @@ import { SpuProperty } from '@/views/mall/promotion/components/index'
defineOptions({ name: 'PromotionSpuAndSkuList' }) defineOptions({ name: 'PromotionSpuAndSkuList' })
const props = defineProps<{ const props = defineProps<{
spuList: T[] spuList: T[] // TODO 便 spu spu spu
ruleConfig: RuleConfig[] ruleConfig: RuleConfig[]
spuPropertyListP: SpuProperty<T>[] spuPropertyListP: SpuProperty<T>[]
}>() }>()

View File

@ -145,17 +145,61 @@ const queryParams = ref({
}) // }) //
const propertyList = ref<Properties[]>([]) // const propertyList = ref<Properties[]>([]) //
const spuListRef = ref<InstanceType<typeof ElTable>>() const spuListRef = ref<InstanceType<typeof ElTable>>()
const spuData = ref<ProductSpuApi.Spu | {}>() // const spuData = ref<ProductSpuApi.Spu>() //
const isExpand = ref(false) // SKU const isExpand = ref(false) // SKU
const expandRowKeys = ref<number[]>() // row-key 使 keys const expandRowKeys = ref<number[]>() // row-key 使 keys
//============ ============
const selectedSpuId = ref<number>(0) // spuId
const selectedSkuIds = ref<number[]>([]) // skuIds
const selectSku = (val: ProductSpuApi.Sku[]) => {
if (selectedSpuId.value === 0) {
return
}
selectedSkuIds.value = val.map((sku) => sku.id!)
}
const selectSpu = (val: ProductSpuApi.Spu[]) => {
if (val.length === 0) {
selectedSpuId.value = 0
return
}
//
selectedSpuId.value = val.map((spu) => spu.id!)[0]
// spu sku , sku spu
if (selectedSkuIds.value.length > 0) {
selectedSkuIds.value = []
}
// 1
if (val.length > 1) {
//
spuListRef.value.clearSelection()
//
spuListRef.value.toggleRowSelection(val.pop(), true)
return
}
expandChange(val[0], val)
}
// //
const expandChange = async (row: ProductSpuApi.Spu, expandedRows: ProductSpuApi.Spu[]) => { const expandChange = async (row: ProductSpuApi.Spu, expandedRows?: ProductSpuApi.Spu[]) => {
// spuId === spuId A A skuList A B
// sku
if (selectedSpuId.value !== 0) {
if (row.id !== selectedSpuId.value) {
message.warning('你已选择商品请先取消')
expandRowKeys.value = [selectedSpuId.value]
return
}
// skuList spu skuList
if (isExpand.value && spuData.value?.id === row.id) {
return
}
}
spuData.value = {} spuData.value = {}
propertyList.value = [] propertyList.value = []
isExpand.value = false isExpand.value = false
if (expandedRows?.length === 0) {
// 0 // 0
if (expandedRows.length === 0) {
expandRowKeys.value = [] expandRowKeys.value = []
return return
} }
@ -167,33 +211,15 @@ const expandChange = async (row: ProductSpuApi.Spu, expandedRows: ProductSpuApi.
expandRowKeys.value = [row.id!] expandRowKeys.value = [row.id!]
} }
//============ ============
const selectedSpuIds = ref<number[]>([]) // spuIds
const selectedSkuIds = ref<number[]>([]) // skuIds
const selectSku = (val: ProductSpuApi.Sku[]) => {
selectedSkuIds.value = val.map((sku) => sku.id!)
}
const selectSpu = (val: ProductSpuApi.Spu[]) => {
selectedSpuIds.value = val.map((spu) => spu.id!)
// //
// selectedSpu.value = val[0]
// // 1
// if (val.length > 1) {
// //
// spuListRef.value.clearSelection()
// //
// spuListRef.value.toggleRowSelection(val.pop(), true)
// }
}
// //
const emits = defineEmits<{ const emits = defineEmits<{
(e: 'confirm', spuIds: number[], skuIds?: number[]): void (e: 'confirm', spuId: number, skuIds?: number[]): void
}>() }>()
/** /**
* 确认选择返回选中的 spu sku (如果需要选择sku的话) * 确认选择返回选中的 spu sku (如果需要选择sku的话)
*/ */
const confirm = () => { const confirm = () => {
if (selectedSpuIds.value.length === 0) { if (selectedSpuId.value === 0) {
message.warning('没有选择任何商品') message.warning('没有选择任何商品')
return return
} }
@ -203,8 +229,8 @@ const confirm = () => {
} }
// id // id
props.isSelectSku props.isSelectSku
? emits('confirm', selectedSpuIds.value, selectedSkuIds.value) ? emits('confirm', selectedSpuId.value, selectedSkuIds.value)
: emits('confirm', selectedSpuIds.value) : emits('confirm', selectedSpuId.value)
// //
dialogVisible.value = false dialogVisible.value = false
} }

View File

@ -8,30 +8,49 @@
:schema="allSchemas.formSchema" :schema="allSchemas.formSchema"
> >
<!-- 先选择 --> <!-- 先选择 -->
<template #spuIds> <template #spuId>
<el-button @click="spuSelectRef.open()">选择商品</el-button> <el-button @click="spuSelectRef.open()">选择商品</el-button>
<SpuAndSkuList <SpuAndSkuList
ref="spuAndSkuListRef" ref="spuAndSkuListRef"
:rule-config="ruleConfig" :rule-config="ruleConfig"
:spu-list="spuList" :spu-list="spuList"
:spu-property-list-p="spuPropertyList" :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.stock" :min="0" class="w-100%" />
</template>
</el-table-column>
<el-table-column align="center" label="秒杀价格(元)" min-width="168">
<template #default="{ row: sku }">
<el-input-number
v-model="sku.productConfig.seckillPrice"
:min="0"
:precision="2"
:step="0.1"
class="w-100%"
/> />
</template> </template>
</el-table-column>
</SpuAndSkuList>
</template>
</Form> </Form>
<template #footer> <template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button> <el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button> <el-button @click="dialogVisible = false"> </el-button>
</template> </template>
</Dialog> </Dialog>
<SpuSelect ref="spuSelectRef" @confirm="selectSpu" /> <SpuSelect ref="spuSelectRef" :isSelectSku="true" @confirm="selectSpu" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { SpuAndSkuList, SpuProperty, SpuSelect } from '../../components' import { SpuAndSkuList, SpuProperty, SpuSelect } from '../../components'
import { allSchemas, rules } from './seckillActivity.data' import { allSchemas, rules } from './seckillActivity.data'
import * as SeckillActivityApi from '@/api/mall/promotion/seckill/seckillActivity' import * as SeckillActivityApi from '@/api/mall/promotion/seckill/seckillActivity'
import { SeckillProductVO } from '@/api/mall/promotion/seckill/seckillActivity'
import * as ProductSpuApi from '@/api/mall/product/spu' import * as ProductSpuApi from '@/api/mall/product/spu'
import { getPropertyList, RuleConfig } from '@/views/mall/product/spu/components' import { getPropertyList, RuleConfig } from '@/views/mall/product/spu/components'
import { convertToInteger } from '@/utils'
defineOptions({ name: 'PromotionSeckillActivityForm' }) defineOptions({ name: 'PromotionSeckillActivityForm' })
@ -43,6 +62,9 @@ const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 12 const formLoading = ref(false) // 12
const formType = ref('') // create - update - const formType = ref('') // create - update -
const formRef = ref() // Ref const formRef = ref() // Ref
// ================= =================
const spuSelectRef = ref() // Ref const spuSelectRef = ref() // Ref
const spuAndSkuListRef = ref() // sku Ref const spuAndSkuListRef = ref() // sku Ref
const ruleConfig: RuleConfig[] = [ const ruleConfig: RuleConfig[] = [
@ -57,6 +79,46 @@ const ruleConfig: RuleConfig[] = [
message: '商品秒杀价格必须大于 0.01 ' message: '商品秒杀价格必须大于 0.01 '
} }
] ]
const spuList = ref<SeckillActivityApi.SpuExtension[]>([]) // spu
const spuPropertyList = ref<SpuProperty<SeckillActivityApi.SpuExtension>[]>([])
const selectSpu = (spuId: number, skuIds: number[]) => {
formRef.value.setValues({ spuId })
getSpuDetails(spuId, skuIds)
}
/**
* 获取 SPU 详情
* @param spuIds
*/
const getSpuDetails = async (spuId: number, skuIds: number[]) => {
const spuProperties: SpuProperty<SeckillActivityApi.SpuExtension>[] = []
const res = (await ProductSpuApi.getSpuDetailList([spuId])) as SeckillActivityApi.SpuExtension[]
if (res.length == 0) {
return
}
spuList.value = []
//
const spu = res[0]
const selectSkus = spu?.skus?.filter((sku) => skuIds.includes(sku.id!))
selectSkus?.forEach((sku) => {
const config: SeckillActivityApi.SeckillProductVO = {
skuId: sku.id!,
stock: 0,
seckillPrice: 0
}
sku.productConfig = config
})
spu.skus = selectSkus as SeckillActivityApi.SkuExtension[]
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) => { const open = async (type: string, id?: number) => {
dialogVisible.value = true dialogVisible.value = true
@ -76,38 +138,6 @@ const open = async (type: string, id?: number) => {
} }
defineExpose({ open }) // open defineExpose({ open }) // open
const spuList = ref<SeckillActivityApi.SpuExtension[]>([]) // spu
const spuPropertyList = ref<SpuProperty<SeckillActivityApi.SpuExtension>[]>([])
const selectSpu = (spuIds: number[]) => {
formRef.value.setValues({ spuIds })
getSpuDetails(spuIds)
}
/**
* 获取 SPU 详情
* TODO 获取 SPU 详情放到各自活动表单来做 SpuAndSkuList 职责单一点
* @param spuIds
*/
const getSpuDetails = async (spuIds: number[]) => {
const spuProperties: SpuProperty<SeckillActivityApi.SpuExtension>[] = []
const res = (await ProductSpuApi.getSpuDetailList(spuIds)) as SeckillActivityApi.SpuExtension[]
spuList.value = []
res?.forEach((spu) => {
// sku
spu.skus?.forEach((sku) => {
const config: SeckillActivityApi.SeckillProductVO = {
spuId: spu.id!,
skuId: sku.id!,
stock: 0,
seckillPrice: 0
}
sku.productConfig = config
})
spuProperties.push({ spuId: spu.id!, spuDetail: spu, propertyList: getPropertyList(spu) })
})
spuList.value.push(...res)
spuPropertyList.value = spuProperties
}
/** 重置表单 */ /** 重置表单 */
const resetForm = async () => { const resetForm = async () => {
spuList.value = [] spuList.value = []
@ -126,7 +156,12 @@ const submitForm = async () => {
formLoading.value = true formLoading.value = true
try { try {
const data = formRef.value.formModel as SeckillActivityApi.SeckillActivityVO const data = formRef.value.formModel as SeckillActivityApi.SeckillActivityVO
data.spuIds = spuList.value.map((spu) => spu.id!) const products = spuAndSkuListRef.value.getSkuConfigs('productConfig')
products.forEach((item: SeckillProductVO) => {
//
item.seckillPrice = convertToInteger(item.seckillPrice)
})
//
data.products = spuAndSkuListRef.value.getSkuConfigs('productConfig') data.products = spuAndSkuListRef.value.getSkuConfigs('productConfig')
if (formType.value === 'create') { if (formType.value === 'create') {
await SeckillActivityApi.createSeckillActivity(data) await SeckillActivityApi.createSeckillActivity(data)

View File

@ -152,6 +152,17 @@ const crudSchemas = reactive<CrudSchema[]>([
width: 120 width: 120
} }
}, },
{
label: '排序',
field: 'sort',
form: {
component: 'InputNumber',
value: 0
},
table: {
width: 80
}
},
{ {
label: '秒杀库存', label: '秒杀库存',
field: 'stock', field: 'stock',
@ -167,17 +178,14 @@ const crudSchemas = reactive<CrudSchema[]>([
{ {
label: '秒杀总库存', label: '秒杀总库存',
field: 'totalStock', field: 'totalStock',
form: { isForm: false,
component: 'InputNumber',
value: 0
},
table: { table: {
width: 120 width: 120
} }
}, },
{ {
label: '秒杀活动商品', label: '秒杀活动商品',
field: 'spuIds', field: 'spuId',
isTable: false, isTable: false,
isSearch: false, isSearch: false,
form: { form: {
@ -206,17 +214,6 @@ const crudSchemas = reactive<CrudSchema[]>([
width: 120 width: 120
} }
}, },
{
label: '排序',
field: 'sort',
form: {
component: 'InputNumber',
value: 0
},
table: {
width: 80
}
},
{ {
label: '状态', label: '状态',
field: 'status', field: 'status',