fix: mall SeckillActivity and CombinationActivity

This commit is contained in:
puhui999 2023-07-05 18:24:32 +08:00
parent ce3ca7c6ce
commit 4057130275
10 changed files with 152 additions and 65 deletions

View File

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

View File

@ -27,7 +27,7 @@ export function formatDate(date: Date, format?: string): string {
* + * +
*/ */
export function getNowDateTime() { export function getNowDateTime() {
return dayjs().format('YYYY-MM-DD HH:mm:ss') return dayjs()
} }
/** /**

View File

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

View File

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

View File

@ -1,21 +1,49 @@
<template> <template>
<Dialog v-model="dialogVisible" :title="dialogTitle"> <Dialog v-model="dialogVisible" :title="dialogTitle" width="65%">
<Form <Form
ref="formRef" ref="formRef"
v-loading="formLoading" v-loading="formLoading"
:is-col="true" :is-col="true"
:rules="rules" :rules="rules"
:schema="allSchemas.formSchema" :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> <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" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import * as CombinationActivityApi from '@/api/mall/promotion/combination/combinationactivity' import * as CombinationActivityApi from '@/api/mall/promotion/combination/combinationactivity'
import { CombinationProductVO } from '@/api/mall/promotion/combination/combinationactivity'
import { allSchemas, rules } from './combinationActivity.data' 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' }) defineOptions({ name: 'PromotionCombinationActivityForm' })
@ -28,6 +56,52 @@ const formLoading = ref(false) // 表单的加载中1修改时的数据加
const formType = ref('') // create - update - const formType = ref('') // create - update -
const formRef = ref() // Ref 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) => { const open = async (type: string, id?: number) => {
dialogVisible.value = true dialogVisible.value = true
@ -57,6 +131,12 @@ const submitForm = async () => {
formLoading.value = true formLoading.value = true
try { try {
const data = formRef.value.formModel as CombinationActivityApi.CombinationActivityVO 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') { if (formType.value === 'create') {
await CombinationActivityApi.createCombinationActivity(data) await CombinationActivityApi.createCombinationActivity(data)
message.success(t('common.createSuccess')) message.success(t('common.createSuccess'))

View File

@ -38,17 +38,19 @@ const crudSchemas = reactive<CrudSchema[]>([
show: true, show: true,
component: 'DatePicker', component: 'DatePicker',
componentProps: { componentProps: {
valueFormat: 'YYYY-MM-DD HH:mm:ss', valueFormat: 'x',
type: 'datetimerange' type: 'datetimerange',
rangeSeparator: '至'
} }
}, },
form: { form: {
component: 'DatePicker', component: 'DatePicker',
componentProps: { componentProps: {
valueFormat: 'YYYY-MM-DD HH:mm:ss', valueFormat: 'x',
type: 'datetimerange' type: 'datetimerange',
rangeSeparator: '至'
}, },
value: [getNowDateTime(), getNowDateTime()], value: [getNowDateTime().valueOf(), getNowDateTime().valueOf()],
colProps: { colProps: {
span: 24 span: 24
} }
@ -120,10 +122,7 @@ const crudSchemas = reactive<CrudSchema[]>([
field: 'virtualGroup', field: 'virtualGroup',
isSearch: false, isSearch: false,
isTable: false, isTable: false,
form: { isForm: false
component: 'InputNumber',
value: 0
}
}, },
{ {
label: '活动状态', label: '活动状态',
@ -133,25 +132,9 @@ const crudSchemas = reactive<CrudSchema[]>([
isSearch: true, isSearch: true,
isForm: false 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: '拼团商品', label: '拼团商品',
field: 'spuId', field: 'spuIds',
isSearch: false, isSearch: false,
form: { form: {
colProps: { colProps: {

View File

@ -111,7 +111,7 @@
</template> </template>
<script lang="ts" setup> <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 { ElTable } from 'element-plus'
import { dateFormatter } from '@/utils/formatTime' import { dateFormatter } from '@/utils/formatTime'
import { createImageViewer } from '@/components/ImageViewer' import { createImageViewer } from '@/components/ImageViewer'
@ -144,7 +144,7 @@ const queryParams = ref({
categoryId: null, categoryId: null,
createTime: [] createTime: []
}) // }) //
const propertyList = ref<Properties[]>([]) // const propertyList = ref<PropertyAndValues[]>([]) //
const spuListRef = ref<InstanceType<typeof ElTable>>() const spuListRef = ref<InstanceType<typeof ElTable>>()
const skuListRef = ref() // Ref const skuListRef = ref() // Ref
const spuData = ref<ProductSpuApi.Spu>() // const spuData = ref<ProductSpuApi.Spu>() //

View File

@ -1,11 +1,11 @@
import SpuSelect from './SpuSelect.vue' import SpuSelect from './SpuSelect.vue'
import SpuAndSkuList from './SpuAndSkuList.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> = { type SpuProperty<T> = {
spuId: number spuId: number
spuDetail: T spuDetail: T
propertyList: Properties[] propertyList: PropertyAndValues[]
} }
/** /**

View File

@ -66,6 +66,7 @@ import { allSchemas } from './seckillActivity.data'
import { getListAllSimple } from '@/api/mall/promotion/seckill/seckillConfig' import { getListAllSimple } from '@/api/mall/promotion/seckill/seckillConfig'
import * as SeckillActivityApi from '@/api/mall/promotion/seckill/seckillActivity' import * as SeckillActivityApi from '@/api/mall/promotion/seckill/seckillActivity'
import SeckillActivityForm from './SeckillActivityForm.vue' import SeckillActivityForm from './SeckillActivityForm.vue'
import { cloneDeep } from 'lodash-es'
defineOptions({ name: 'PromotionSeckillActivity' }) defineOptions({ name: 'PromotionSeckillActivity' })
@ -90,11 +91,10 @@ const handleDelete = (id: number) => {
tableMethods.delList(id, false) tableMethods.delList(id, false)
} }
// TODO @puhui configList const configList = ref([]) //
const seckillConfigAllSimple = ref([]) //
const convertSeckillConfigNames = computed( const convertSeckillConfigNames = computed(
() => (row) => () => (row) =>
seckillConfigAllSimple.value configList.value
?.filter((item) => row.configIds.includes(item.id)) ?.filter((item) => row.configIds.includes(item.id))
?.map((config) => config.name) ?.map((config) => config.name)
) )
@ -106,7 +106,13 @@ const expandChange = (row, expandedRows) => {
/** 初始化 **/ /** 初始化 **/
onMounted(async () => { 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() await getList()
seckillConfigAllSimple.value = await getListAllSimple() configList.value = await getListAllSimple()
}) })
</script> </script>

View File

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