diff --git a/src/api/mall/product/spu.ts b/src/api/mall/product/spu.ts index d7ccfc5c..0ea324b8 100644 --- a/src/api/mall/product/spu.ts +++ b/src/api/mall/product/spu.ts @@ -86,6 +86,11 @@ export const getSpu = (id: number) => { return request.get({ url: `/product/spu/get-detail?id=${id}` }) } +// 获得商品 Spu 详情列表 +export const getSpuDetailList = (ids: number[]) => { + return request.get({ url: `/product/spu/list?spuIds=${ids}` }) +} + // 删除商品 Spu export const deleteSpu = (id: number) => { return request.delete({ url: `/product/spu/delete?id=${id}` }) diff --git a/src/api/mall/promotion/combination/combinationactivity.ts b/src/api/mall/promotion/combination/combinationactivity.ts new file mode 100644 index 00000000..71d5d2a4 --- /dev/null +++ b/src/api/mall/promotion/combination/combinationactivity.ts @@ -0,0 +1,63 @@ +import request from '@/config/axios' +import { Sku, Spu } from '@/api/mall/product/spu' + +// TODO @puhui999: combinationActivity.ts + +export interface CombinationActivityVO { + id?: number + name?: string + spuId?: 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 + skuId: number + activePrice: number // 拼团价格 +} + +// 扩展 Sku 配置 +export type SkuExtension = Sku & { + productConfig: CombinationProductVO +} + +export interface SpuExtension extends Spu { + skus: SkuExtension[] // 重写类型 +} + +// 查询拼团活动列表 +export const getCombinationActivityPage = async (params) => { + return await request.get({ url: '/promotion/combination-activity/page', params }) +} + +// 查询拼团活动详情 +export const getCombinationActivity = async (id: number) => { + return await request.get({ url: '/promotion/combination-activity/get?id=' + id }) +} + +// 新增拼团活动 +export const createCombinationActivity = async (data: CombinationActivityVO) => { + return await request.post({ url: '/promotion/combination-activity/create', data }) +} + +// 修改拼团活动 +export const updateCombinationActivity = async (data: CombinationActivityVO) => { + return await request.put({ url: '/promotion/combination-activity/update', data }) +} + +// 删除拼团活动 +export const deleteCombinationActivity = async (id: number) => { + return await request.delete({ url: '/promotion/combination-activity/delete?id=' + id }) +} diff --git a/src/api/mall/promotion/seckill/seckillActivity.ts b/src/api/mall/promotion/seckill/seckillActivity.ts index 0f1f08d1..42c1c31c 100644 --- a/src/api/mall/promotion/seckill/seckillActivity.ts +++ b/src/api/mall/promotion/seckill/seckillActivity.ts @@ -2,35 +2,34 @@ 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[] } // 秒杀活动所需属性 export interface SeckillProductVO { - spuId: number skuId: number seckillPrice: number stock: number } // 扩展 Sku 配置 -type SkuExtension = Sku & { +export type SkuExtension = Sku & { productConfig: SeckillProductVO } diff --git a/src/api/mall/promotion/seckill/seckillConfig.ts b/src/api/mall/promotion/seckill/seckillConfig.ts index 07b7d55c..eee82115 100644 --- a/src/api/mall/promotion/seckill/seckillConfig.ts +++ b/src/api/mall/promotion/seckill/seckillConfig.ts @@ -5,7 +5,7 @@ export interface SeckillConfigVO { name: string startTime: string endTime: string - picUrl: string + sliderPicUrls: string[] status: number } diff --git a/src/utils/formatTime.ts b/src/utils/formatTime.ts index c9d80618..5e5c854d 100644 --- a/src/utils/formatTime.ts +++ b/src/utils/formatTime.ts @@ -23,6 +23,13 @@ export function formatDate(date: Date, format?: string): string { return dayjs(date).format(format) } +/** + * 获取当前的日期+时间 + */ +export function getNowDateTime() { + return dayjs() +} + /** * 获取当前日期是第几周 * @param dateTime 当前传入的日期值 diff --git a/src/views/mall/product/spu/components/SkuList.vue b/src/views/mall/product/spu/components/SkuList.vue index e033b233..ed1a356d 100644 --- a/src/views/mall/product/spu/components/SkuList.vue +++ b/src/views/mall/product/spu/components/SkuList.vue @@ -2,7 +2,7 @@ {} }, propertyList: { - type: Array as PropType, + type: Array as PropType, default: () => [] }, ruleConfig: { @@ -480,7 +482,7 @@ const build = (propertyValuesList: Property[][]) => { /** 监听属性列表,生成相关参数和表头 */ watch( () => props.propertyList, - (propertyList: Properties[]) => { + (propertyList: PropertyAndValues[]) => { // 如果不是多规格则结束 if (!formData.value!.specType) { return @@ -514,7 +516,6 @@ watch( // name加属性项index区分属性值 tableHeaders.value.push({ prop: `name${index}`, label: item.name }) }) - // 如果回显的 sku 属性和添加的属性一致则不处理 if (validateData(propertyList)) { return @@ -531,6 +532,10 @@ watch( immediate: true } ) +const activitySkuListRef = ref>() +const clearSelection = () => { + activitySkuListRef.value.clearSelection() +} // 暴露出生成 sku 方法,给添加属性成功时调用 -defineExpose({ generateTableData, validateSku }) +defineExpose({ generateTableData, validateSku, clearSelection }) diff --git a/src/views/mall/product/spu/components/index.ts b/src/views/mall/product/spu/components/index.ts index ca61ff6b..1160dbd1 100644 --- a/src/views/mall/product/spu/components/index.ts +++ b/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 } diff --git a/src/views/mall/promotion/combination/activity/CombinationActivityForm.vue b/src/views/mall/promotion/combination/activity/CombinationActivityForm.vue new file mode 100644 index 00000000..36ede848 --- /dev/null +++ b/src/views/mall/promotion/combination/activity/CombinationActivityForm.vue @@ -0,0 +1,189 @@ + + diff --git a/src/views/mall/promotion/combination/activity/combinationActivity.data.ts b/src/views/mall/promotion/combination/activity/combinationActivity.data.ts new file mode 100644 index 00000000..2ddb8d19 --- /dev/null +++ b/src/views/mall/promotion/combination/activity/combinationActivity.data.ts @@ -0,0 +1,151 @@ +import type { CrudSchema } from '@/hooks/web/useCrudSchemas' +import { dateFormatter, getNowDateTime } from '@/utils/formatTime' + +// 表单校验 +export const rules = reactive({ + name: [required], + totalLimitCount: [required], + singleLimitCount: [required], + startTime: [required], + endTime: [required], + userSize: [required], + totalNum: [required], + successNum: [required], + orderUserCount: [required], + virtualGroup: [required], + status: [required], + limitDuration: [required] +}) + +// CrudSchema https://doc.iocoder.cn/vue3/crud-schema/ +const crudSchemas = reactive([ + { + label: '拼团名称', + field: 'name', + isSearch: true, + isTable: false, + form: { + colProps: { + span: 24 + } + } + }, + { + label: '活动时间', + field: 'activityTime', + formatter: dateFormatter, + search: { + show: true, + component: 'DatePicker', + componentProps: { + valueFormat: 'x', + type: 'datetimerange', + rangeSeparator: '至' + } + }, + form: { + component: 'DatePicker', + componentProps: { + valueFormat: 'x', + type: 'datetimerange', + rangeSeparator: '至' + }, + value: [getNowDateTime().valueOf(), getNowDateTime().valueOf()], + colProps: { + span: 24 + } + } + }, + { + label: '参与人数', + field: 'orderUserCount', + isSearch: false, + form: { + component: 'InputNumber', + labelMessage: '参与人数不能少于两人', + value: 2 + } + }, + { + label: '限制时长', + field: 'limitDuration', + isSearch: false, + isTable: false, + form: { + component: 'InputNumber', + labelMessage: '限制时长(小时)', + componentProps: { + placeholder: '请输入限制时长(小时)' + } + } + }, + { + label: '总限购数量', + field: 'totalLimitCount', + isSearch: false, + isTable: false, + form: { + component: 'InputNumber', + value: 0 + } + }, + { + label: '单次限购数量', + field: 'singleLimitCount', + isSearch: false, + isTable: false, + form: { + component: 'InputNumber', + value: 0 + } + }, + { + label: '购买人数', + field: 'userSize', + isSearch: false, + isForm: false + }, + { + label: '开团组数', + field: 'totalNum', + isSearch: false, + isForm: false + }, + { + label: '成团组数', + field: 'successNum', + isSearch: false, + isForm: false + }, + { + label: '虚拟成团', + field: 'virtualGroup', + isSearch: false, + isTable: false, + isForm: false + }, + { + label: '活动状态', + field: 'status', + dictType: DICT_TYPE.COMMON_STATUS, + dictClass: 'number', + isSearch: true, + isForm: false + }, + { + label: '拼团商品', + field: 'spuId', + isSearch: false, + form: { + colProps: { + span: 24 + } + } + }, + { + label: '操作', + field: 'action', + isForm: false + } +]) +export const { allSchemas } = useCrudSchemas(crudSchemas) diff --git a/src/views/mall/promotion/combination/activity/index.vue b/src/views/mall/promotion/combination/activity/index.vue new file mode 100644 index 00000000..c76f1787 --- /dev/null +++ b/src/views/mall/promotion/combination/activity/index.vue @@ -0,0 +1,117 @@ + + diff --git a/src/views/mall/promotion/components/SpuAndSkuList.vue b/src/views/mall/promotion/components/SpuAndSkuList.vue index e239a39a..db29de2d 100644 --- a/src/views/mall/promotion/components/SpuAndSkuList.vue +++ b/src/views/mall/promotion/components/SpuAndSkuList.vue @@ -1,5 +1,5 @@ diff --git a/src/views/mall/promotion/seckill/activity/seckillActivity.data.ts b/src/views/mall/promotion/seckill/activity/seckillActivity.data.ts index c858374c..70766d49 100644 --- a/src/views/mall/promotion/seckill/activity/seckillActivity.data.ts +++ b/src/views/mall/promotion/seckill/activity/seckillActivity.data.ts @@ -152,6 +152,17 @@ const crudSchemas = reactive([ width: 120 } }, + { + label: '排序', + field: 'sort', + form: { + component: 'InputNumber', + value: 0 + }, + table: { + width: 80 + } + }, { label: '秒杀库存', field: 'stock', @@ -167,18 +178,15 @@ const crudSchemas = reactive([ { label: '秒杀总库存', field: 'totalStock', - form: { - component: 'InputNumber', - value: 0 - }, + isForm: false, table: { width: 120 } }, { label: '秒杀活动商品', - field: 'spuIds', - isTable: false, + field: 'spuId', + isTable: true, isSearch: false, form: { colProps: { @@ -186,7 +194,7 @@ const crudSchemas = reactive([ } }, table: { - width: 200 + width: 300 } }, { @@ -206,17 +214,6 @@ const crudSchemas = reactive([ width: 120 } }, - { - label: '排序', - field: 'sort', - form: { - component: 'InputNumber', - value: 0 - }, - table: { - width: 80 - } - }, { label: '状态', field: 'status', diff --git a/src/views/mall/promotion/seckill/config/SeckillConfigForm.vue b/src/views/mall/promotion/seckill/config/SeckillConfigForm.vue index e25f8fce..22b07d3a 100644 --- a/src/views/mall/promotion/seckill/config/SeckillConfigForm.vue +++ b/src/views/mall/promotion/seckill/config/SeckillConfigForm.vue @@ -10,6 +10,7 @@