From a75720ec0646f4fe5bdf21126bd5c3cf719170e9 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sat, 17 Jun 2023 21:20:28 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=E7=A7=92=E6=9D=80=E6=97=B6?= =?UTF-8?q?=E6=AE=B5=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mall/promotion/seckill/seckillConfig.ts | 41 +++++++ src/utils/formatTime.ts | 4 +- .../seckill/config/SeckillConfigForm.vue | 70 ++++++++++++ .../mall/promotion/seckill/config/index.vue | 101 ++++++++++++++++++ .../seckill/config/seckillConfig.data.ts | 93 ++++++++++++++++ 5 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 src/api/mall/promotion/seckill/seckillConfig.ts create mode 100644 src/views/mall/promotion/seckill/config/SeckillConfigForm.vue create mode 100644 src/views/mall/promotion/seckill/config/index.vue create mode 100644 src/views/mall/promotion/seckill/config/seckillConfig.data.ts diff --git a/src/api/mall/promotion/seckill/seckillConfig.ts b/src/api/mall/promotion/seckill/seckillConfig.ts new file mode 100644 index 00000000..d941ed4d --- /dev/null +++ b/src/api/mall/promotion/seckill/seckillConfig.ts @@ -0,0 +1,41 @@ +import request from '@/config/axios' + +export interface SeckillConfigVO { + id: number + name: string + startTime: Date + endTime: Date + seckillActivityCount: number + picUrl: string + status: number +} + +// 查询秒杀时段配置列表 +export const getSeckillConfigPage = async (params) => { + return await request.get({ url: '/promotion/seckill-config/page', params }) +} + +// 查询秒杀时段配置详情 +export const getSeckillConfig = async (id: number) => { + return await request.get({ url: '/promotion/seckill-config/get?id=' + id }) +} + +// 新增秒杀时段配置 +export const createSeckillConfig = async (data: SeckillConfigVO) => { + return await request.post({ url: '/promotion/seckill-config/create', data }) +} + +// 修改秒杀时段配置 +export const updateSeckillConfig = async (data: SeckillConfigVO) => { + return await request.put({ url: '/promotion/seckill-config/update', data }) +} + +// 删除秒杀时段配置 +export const deleteSeckillConfig = async (id: number) => { + return await request.delete({ url: '/promotion/seckill-config/delete?id=' + id }) +} + +// 导出秒杀时段配置 Excel +export const exportSeckillConfigApi = async (params) => { + return await request.download({ url: '/promotion/seckill-config/export-excel', params }) +} diff --git a/src/utils/formatTime.ts b/src/utils/formatTime.ts index 0d68e362..b27cabdf 100644 --- a/src/utils/formatTime.ts +++ b/src/utils/formatTime.ts @@ -155,7 +155,7 @@ export const dateFormatter = (row, column, cellValue) => { * @returns 带时间00:00:00的日期 */ export function beginOfDay(param: Date) { - return new Date(param.getFullYear(), param.getMonth(), param.getDate(), 0, 0, 0, 0) + return new Date(param.getFullYear(), param.getMonth(), param.getDate(), 0, 0, 0) } /** @@ -164,7 +164,7 @@ export function beginOfDay(param: Date) { * @returns 带时间23:59:59的日期 */ export function endOfDay(param: Date) { - return new Date(param.getFullYear(), param.getMonth(), param.getDate(), 23, 59, 59, 999) + return new Date(param.getFullYear(), param.getMonth(), param.getDate(), 23, 59, 59) } /** diff --git a/src/views/mall/promotion/seckill/config/SeckillConfigForm.vue b/src/views/mall/promotion/seckill/config/SeckillConfigForm.vue new file mode 100644 index 00000000..a4675f71 --- /dev/null +++ b/src/views/mall/promotion/seckill/config/SeckillConfigForm.vue @@ -0,0 +1,70 @@ + + diff --git a/src/views/mall/promotion/seckill/config/index.vue b/src/views/mall/promotion/seckill/config/index.vue new file mode 100644 index 00000000..8c7dee8d --- /dev/null +++ b/src/views/mall/promotion/seckill/config/index.vue @@ -0,0 +1,101 @@ + + diff --git a/src/views/mall/promotion/seckill/config/seckillConfig.data.ts b/src/views/mall/promotion/seckill/config/seckillConfig.data.ts new file mode 100644 index 00000000..65c35611 --- /dev/null +++ b/src/views/mall/promotion/seckill/config/seckillConfig.data.ts @@ -0,0 +1,93 @@ +import type { CrudSchema } from '@/hooks/web/useCrudSchemas' +import { dateFormatter } from '@/utils/formatTime' + +// 表单校验 +export const rules = reactive({ + name: [required], + startTime: [required], + endTime: [required], + seckillActivityCount: [required], + picUrl: [required], + status: [required] +}) + +// CrudSchema https://doc.iocoder.cn/vue3/crud-schema/ +const crudSchemas = reactive([ + { + label: '秒杀时段名称', + field: 'name', + isSearch: true + }, + { + label: '开始时间点', + field: 'startTime', + isSearch: false, + search: { + component: 'TimePicker' + }, + form: { + component: 'TimePicker', + componentProps: { + valueFormat: 'HH:mm:ss' + } + } + }, + { + label: '结束时间点', + field: 'endTime', + isSearch: false, + search: { + component: 'TimePicker' + }, + form: { + component: 'TimePicker', + componentProps: { + valueFormat: 'HH:mm:ss' + } + } + }, + { + label: '秒杀主图', + field: 'picUrl', + isSearch: false, + form: { + component: 'UploadImg' + } + }, + { + label: '状态', + field: 'status', + dictType: DICT_TYPE.COMMON_STATUS, + dictClass: 'number', + isSearch: true, + form: { + component: 'Radio' + } + }, + { + label: '创建时间', + field: 'createTime', + isForm: false, + isSearch: false, + formatter: dateFormatter + }, + { + label: '操作', + field: 'action', + isForm: false + } +]) +export const { allSchemas } = useCrudSchemas(crudSchemas) + +/** + * 添加这个函数呢是因为数据库表使用 time 类型存的时分秒信息,对应实体类字段使用的 LocalTime,然后返回给前端的就数据是 + * '00:05:00' 会变成 [0,5],所以才使用此方法转一道。我想着或许直接后台返回字符串格式的 + * @param data + */ +export const format = (data: number[]): string => { + if (typeof data === 'undefined') { + return '' + } + const paddedData = data.length >= 3 ? data.slice(0, 3) : [...data, 0, 0].slice(0, 3) + return paddedData.map((num) => num.toString().padStart(2, '0')).join(':') +} From f7b195b226308e4f016817a1bba5ca1a52921906 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Mon, 19 Jun 2023 10:20:43 +0800 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20=E5=AE=8C=E4=BA=8B=E7=A7=92?= =?UTF-8?q?=E6=9D=80=E6=97=B6=E6=AE=B5=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mall/promotion/seckill/seckillConfig.ts | 14 ++++++-- .../seckill/config/SeckillConfigForm.vue | 6 +--- .../mall/promotion/seckill/config/index.vue | 35 ++++++++++++++----- .../seckill/config/seckillConfig.data.ts | 14 -------- 4 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/api/mall/promotion/seckill/seckillConfig.ts b/src/api/mall/promotion/seckill/seckillConfig.ts index d941ed4d..fb72936b 100644 --- a/src/api/mall/promotion/seckill/seckillConfig.ts +++ b/src/api/mall/promotion/seckill/seckillConfig.ts @@ -3,9 +3,8 @@ import request from '@/config/axios' export interface SeckillConfigVO { id: number name: string - startTime: Date - endTime: Date - seckillActivityCount: number + startTime: string + endTime: string picUrl: string status: number } @@ -30,6 +29,15 @@ export const updateSeckillConfig = async (data: SeckillConfigVO) => { return await request.put({ url: '/promotion/seckill-config/update', data }) } +// 修改时段配置状态 +export const updateSeckillConfigStatus = (id: number, status: number) => { + const data = { + id, + status + } + return request.put({ url: '/promotion/seckill-config/update-status', data: data }) +} + // 删除秒杀时段配置 export const deleteSeckillConfig = async (id: number) => { return await request.delete({ url: '/promotion/seckill-config/delete?id=' + id }) diff --git a/src/views/mall/promotion/seckill/config/SeckillConfigForm.vue b/src/views/mall/promotion/seckill/config/SeckillConfigForm.vue index a4675f71..e25f8fce 100644 --- a/src/views/mall/promotion/seckill/config/SeckillConfigForm.vue +++ b/src/views/mall/promotion/seckill/config/SeckillConfigForm.vue @@ -8,9 +8,8 @@ + diff --git a/src/views/mall/promotion/seckill/activity/components/SpuAndSkuSelectForm.vue b/src/views/mall/promotion/seckill/activity/components/SpuAndSkuSelectForm.vue new file mode 100644 index 00000000..cf538fc2 --- /dev/null +++ b/src/views/mall/promotion/seckill/activity/components/SpuAndSkuSelectForm.vue @@ -0,0 +1,290 @@ + + + diff --git a/src/views/mall/promotion/seckill/activity/components/index.ts b/src/views/mall/promotion/seckill/activity/components/index.ts new file mode 100644 index 00000000..69dd429a --- /dev/null +++ b/src/views/mall/promotion/seckill/activity/components/index.ts @@ -0,0 +1,3 @@ +import SpuAndSkuSelectForm from './SpuAndSkuSelectForm.vue' + +export { SpuAndSkuSelectForm } diff --git a/src/views/mall/promotion/seckill/activity/index.vue b/src/views/mall/promotion/seckill/activity/index.vue new file mode 100644 index 00000000..de9f71db --- /dev/null +++ b/src/views/mall/promotion/seckill/activity/index.vue @@ -0,0 +1,86 @@ + + diff --git a/src/views/mall/promotion/seckill/activity/seckillActivity.data.ts b/src/views/mall/promotion/seckill/activity/seckillActivity.data.ts new file mode 100644 index 00000000..70524b91 --- /dev/null +++ b/src/views/mall/promotion/seckill/activity/seckillActivity.data.ts @@ -0,0 +1,261 @@ +import type { CrudSchema } from '@/hooks/web/useCrudSchemas' +import { dateFormatter } from '@/utils/formatTime' +import { getListAllSimple } from '@/api/mall/promotion/seckill/seckillConfig' + +// 表单校验 +export const rules = reactive({ + spuId: [required], + name: [required], + startTime: [required], + endTime: [required], + sort: [required], + configIds: [required], + totalLimitCount: [required], + singleLimitCount: [required], + totalStock: [required] +}) + +// CrudSchema https://doc.iocoder.cn/vue3/crud-schema/ +const crudSchemas = reactive([ + { + label: '秒杀活动名称', + field: 'name', + isSearch: true, + form: { + colProps: { + span: 24 + } + }, + table: { + width: 120 + } + }, + { + label: '活动开始时间', + field: 'startTime', + formatter: dateFormatter, + isSearch: true, + 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')] + } + }, + form: { + component: 'DatePicker', + componentProps: { + type: 'date', + valueFormat: 'x' + } + }, + table: { + width: 300 + } + }, + { + label: '活动结束时间', + field: 'endTime', + formatter: dateFormatter, + isSearch: true, + 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')] + } + }, + form: { + component: 'DatePicker', + componentProps: { + type: 'date', + valueFormat: 'x' + } + }, + table: { + width: 300 + } + }, + { + label: '秒杀时段', + field: 'configIds', + form: { + component: 'Select', + componentProps: { + multiple: true, + optionsAlias: { + labelField: 'name', + valueField: 'id' + } + }, + api: getListAllSimple + }, + table: { + width: 300 + } + }, + { + label: '新增订单数', + field: 'orderCount', + isForm: false, + form: { + component: 'InputNumber', + value: 0 + }, + table: { + width: 300 + } + }, + { + label: '付款人数', + field: 'userCount', + isForm: false, + form: { + component: 'InputNumber', + value: 0 + }, + table: { + width: 300 + } + }, + { + label: '订单实付金额', + field: 'totalPrice', + isForm: false, + form: { + component: 'InputNumber', + value: 0 + }, + table: { + width: 300 + } + }, + { + label: '总限购数量', + field: 'totalLimitCount', + form: { + component: 'InputNumber', + value: 0 + }, + table: { + width: 300 + } + }, + { + label: '单次限够数量', + field: 'singleLimitCount', + form: { + component: 'InputNumber', + value: 0 + }, + table: { + width: 300 + } + }, + { + label: '秒杀库存', + field: 'stock', + isForm: false, + form: { + component: 'InputNumber', + value: 0 + }, + table: { + width: 300 + } + }, + { + label: '秒杀总库存', + field: 'totalStock', + form: { + component: 'InputNumber', + value: 0 + }, + table: { + width: 300 + } + }, + { + label: '秒杀活动商品', + field: 'spuId', + form: { + colProps: { + span: 24 + } + }, + table: { + width: 200 + } + }, + { + label: '创建时间', + field: 'createTime', + formatter: dateFormatter, + 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, + table: { + width: 300 + } + }, + { + label: '排序', + field: 'sort', + form: { + component: 'InputNumber', + value: 0 + }, + table: { + width: 300 + } + }, + { + label: '状态', + field: 'status', + dictType: DICT_TYPE.COMMON_STATUS, + dictClass: 'number', + isForm: false, + isSearch: true, + form: { + component: 'Radio' + }, + table: { + width: 80 + } + }, + { + label: '备注', + field: 'remark', + form: { + component: 'Input', + componentProps: { + type: 'textarea', + rows: 4 + }, + colProps: { + span: 24 + } + }, + table: { + width: 300 + } + }, + { + label: '操作', + field: 'action', + isForm: false, + table: { + width: 120, + fixed: 'right' + } + } +]) +export const { allSchemas } = useCrudSchemas(crudSchemas) From b1e7f149638243885ae97f6c31f5df24d9b6ffa2 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sat, 24 Jun 2023 01:48:07 +0800 Subject: [PATCH 6/6] =?UTF-8?q?fix=EF=BC=9A=E5=AE=8C=E5=96=84=E7=A7=92?= =?UTF-8?q?=E6=9D=80=E6=B4=BB=E5=8A=A8=E7=AE=A1=E7=90=86=E2=91=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/mall/product/spu.ts | 10 ++ .../mall/promotion/seckill/seckillActivity.ts | 19 ++- .../mall/product/spu/components/SkuList.vue | 87 +++++++++- .../mall/product/spu/components/index.ts | 44 ++++- .../seckill/activity/SeckillActivityForm.vue | 50 +----- .../activity/components/SpuAndSkuList.vue | 157 ++++++++++++++++++ .../components/SpuAndSkuSelectForm.vue | 32 +--- .../seckill/activity/components/index.ts | 3 +- 8 files changed, 327 insertions(+), 75 deletions(-) create mode 100644 src/views/mall/promotion/seckill/activity/components/SpuAndSkuList.vue diff --git a/src/api/mall/product/spu.ts b/src/api/mall/product/spu.ts index b6bec97e..5ddaa92e 100644 --- a/src/api/mall/product/spu.ts +++ b/src/api/mall/product/spu.ts @@ -49,6 +49,16 @@ export interface Spu { recommendGood?: boolean // 是否优品 } +export interface SpuRespVO extends Spu { + price: number + salesCount: number + marketPrice: number + costPrice: number + stock: number + createTime: Date + status: number +} + // 获得 Spu 列表 export const getSpuPage = (params: PageParam) => { return request.get({ url: '/product/spu/page', params }) diff --git a/src/api/mall/promotion/seckill/seckillActivity.ts b/src/api/mall/promotion/seckill/seckillActivity.ts index 2c59319c..fc2d1871 100644 --- a/src/api/mall/promotion/seckill/seckillActivity.ts +++ b/src/api/mall/promotion/seckill/seckillActivity.ts @@ -1,8 +1,9 @@ import request from '@/config/axios' +import { Sku, SpuRespVO } from '@/api/mall/product/spu' export interface SeckillActivityVO { id: number - spuId: number + spuIds: number[] name: string status: number remark: string @@ -17,6 +18,22 @@ export interface SeckillActivityVO { singleLimitCount: number stock: number totalStock: number + products: SeckillProductVO[] +} + +export interface SeckillProductVO { + spuId: number + skuId: number + seckillPrice: number + stock: number +} + +type SkuExtension = Sku & { + productConfig: SeckillProductVO +} + +export interface SpuExtension extends SpuRespVO { + skus: SkuExtension[] // 重写类型 } // 查询秒杀活动列表 diff --git a/src/views/mall/product/spu/components/SkuList.vue b/src/views/mall/product/spu/components/SkuList.vue index 6aa26a2b..04718f3d 100644 --- a/src/views/mall/product/spu/components/SkuList.vue +++ b/src/views/mall/product/spu/components/SkuList.vue @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/views/mall/promotion/seckill/activity/components/SpuAndSkuSelectForm.vue b/src/views/mall/promotion/seckill/activity/components/SpuAndSkuSelectForm.vue index cf538fc2..c3de9a2b 100644 --- a/src/views/mall/promotion/seckill/activity/components/SpuAndSkuSelectForm.vue +++ b/src/views/mall/promotion/seckill/activity/components/SpuAndSkuSelectForm.vue @@ -51,7 +51,7 @@ :data="list" :expand-row-keys="expandRowKeys" row-key="id" - @expandChange="getPropertyList" + @expand-change="expandChange" @selection-change="selectSpu" > @@ -111,7 +111,7 @@