From adc58e6e05e33265db2eb295bfe46aa94b840b51 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=85=95=E4=B8=8B?= <484014559@qq.com>
Date: Sun, 29 Sep 2024 18:03:25 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=A7=AF=E5=88=86=E5=95=86?=
=?UTF-8?q?=E5=93=81=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=8B=BC=E5=9B=A2=E3=80=81?=
=?UTF-8?q?=E7=A7=92=E6=9D=80=E7=9A=84=E5=B0=8F=E7=A8=8B=E5=BA=8F=E4=BB=A5?=
=?UTF-8?q?=E5=8F=8A=E5=90=8E=E7=AB=AF=E5=95=86=E5=93=81=E6=9F=A5=E8=AF=A2?=
=?UTF-8?q?=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../pointmall/combinationActivity.ts | 66 +++++
.../src/api/mall/promotion/pointmall/index.ts | 48 +++
yudao-admin-vue3/src/utils/dict.ts | 1 +
.../promotion/pointmall/PointMallForm.vue | 205 +++++++++++++
.../activity/CombinationActivityForm.vue | 192 ++++++++++++
.../activity/combinationActivity.data.ts | 140 +++++++++
.../promotion/pointmall/activity/index.vue | 227 ++++++++++++++
.../views/mall/promotion/pointmall/index.vue | 277 ++++++++++++++++++
.../api/spu/dto/ProductSpuRespDTO.java | 10 +
.../promotion/enums/ErrorCodeConstants.java | 2 +
.../CombinationActivityController.java | 14 +
.../admin/pointmall/PointMallController.java | 127 ++++++++
.../PointMallCombinationActivityBaseVO.java | 59 ++++
...intMallCombinationActivityCreateReqVO.java | 23 ++
.../pointmall/vo/PointMallPageReqVO.java | 49 ++++
.../admin/pointmall/vo/PointMallRespVO.java | 62 ++++
.../pointmall/vo/PointMallSaveReqVO.java | 42 +++
.../seckill/SeckillActivityController.java | 30 ++
.../AppCombinationActivityController.java | 21 ++
.../seckill/AppSeckillActivityController.java | 35 +++
.../dal/dataobject/pointmall/PointMallDO.java | 69 +++++
.../dal/mysql/pointmall/PointMallMapper.java | 35 +++
.../service/pointmall/PointMallService.java | 57 ++++
.../pointmall/PointMallServiceImpl.java | 91 ++++++
.../mapper/pointmall/PointMallMapper.xml | 12 +
25 files changed, 1894 insertions(+)
create mode 100644 yudao-admin-vue3/src/api/mall/promotion/pointmall/combinationActivity.ts
create mode 100644 yudao-admin-vue3/src/api/mall/promotion/pointmall/index.ts
create mode 100644 yudao-admin-vue3/src/views/mall/promotion/pointmall/PointMallForm.vue
create mode 100644 yudao-admin-vue3/src/views/mall/promotion/pointmall/activity/CombinationActivityForm.vue
create mode 100644 yudao-admin-vue3/src/views/mall/promotion/pointmall/activity/combinationActivity.data.ts
create mode 100644 yudao-admin-vue3/src/views/mall/promotion/pointmall/activity/index.vue
create mode 100644 yudao-admin-vue3/src/views/mall/promotion/pointmall/index.vue
create mode 100644 yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/PointMallController.java
create mode 100644 yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallCombinationActivityBaseVO.java
create mode 100644 yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallCombinationActivityCreateReqVO.java
create mode 100644 yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallPageReqVO.java
create mode 100644 yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallRespVO.java
create mode 100644 yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallSaveReqVO.java
create mode 100644 yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/pointmall/PointMallDO.java
create mode 100644 yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/pointmall/PointMallMapper.java
create mode 100644 yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/pointmall/PointMallService.java
create mode 100644 yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/pointmall/PointMallServiceImpl.java
create mode 100644 yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/pointmall/PointMallMapper.xml
diff --git a/yudao-admin-vue3/src/api/mall/promotion/pointmall/combinationActivity.ts b/yudao-admin-vue3/src/api/mall/promotion/pointmall/combinationActivity.ts
new file mode 100644
index 0000000..a13d826
--- /dev/null
+++ b/yudao-admin-vue3/src/api/mall/promotion/pointmall/combinationActivity.ts
@@ -0,0 +1,66 @@
+import request from '@/config/axios'
+import { Sku, Spu } from '@/api/mall/product/spu'
+
+export interface CombinationActivityVO {
+ id?: number
+ name?: string
+ spuId?: number
+ totalLimitCount?: number
+ singleLimitCount?: number
+ startTime?: Date
+ endTime?: Date
+ userSize?: number
+ totalCount?: number
+ successCount?: number
+ orderUserCount?: number
+ virtualGroup?: number
+ status?: number
+ limitDuration?: number
+ products: CombinationProductVO[]
+}
+
+// 拼团活动所需属性
+export interface CombinationProductVO {
+ spuId: number
+ skuId: number
+ combinationPrice: 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/point-mall/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/point-mall/create', data })
+}
+
+// 修改拼团活动
+export const updateCombinationActivity = async (data: CombinationActivityVO) => {
+ return await request.put({ url: '/promotion/combination-activity/update', data })
+}
+
+// 关闭拼团活动
+export const closeCombinationActivity = async (id: number) => {
+ return await request.put({ url: '/promotion/point-mall/closePointMall?id=' + id })
+}
+
+// 删除拼团活动
+export const deleteCombinationActivity = async (id: number) => {
+ return await request.delete({ url: '/promotion/point-mall/delete?id=' + id })
+}
diff --git a/yudao-admin-vue3/src/api/mall/promotion/pointmall/index.ts b/yudao-admin-vue3/src/api/mall/promotion/pointmall/index.ts
new file mode 100644
index 0000000..bed6430
--- /dev/null
+++ b/yudao-admin-vue3/src/api/mall/promotion/pointmall/index.ts
@@ -0,0 +1,48 @@
+import request from '@/config/axios'
+
+// 积分商城 VO
+export interface PointMallVO {
+ id: number // 编号
+ productPicUrl: string // 商品主图
+ title: string // 标题
+ skuIds: string // sku数组
+ spuId: number // spu编号
+ exchangePointNum: number // 兑换积分
+ limited: number // 限量
+ surplusLimited: number // 剩余限量
+ status: number // 状态
+ sort: number // 排序
+}
+
+// 积分商城 API
+export const PointMallApi = {
+ // 查询积分商城分页
+ getPointMallPage: async (params: any) => {
+ return await request.get({ url: `/promotion/point-mall/page`, params })
+ },
+
+ // 查询积分商城详情
+ getPointMall: async (id: number) => {
+ return await request.get({ url: `/promotion/point-mall/get?id=` + id })
+ },
+
+ // 新增积分商城
+ createPointMall: async (data: PointMallVO) => {
+ return await request.post({ url: `/promotion/point-mall/create`, data })
+ },
+
+ // 修改积分商城
+ updatePointMall: async (data: PointMallVO) => {
+ return await request.put({ url: `/promotion/point-mall/update`, data })
+ },
+
+ // 删除积分商城
+ deletePointMall: async (id: number) => {
+ return await request.delete({ url: `/promotion/point-mall/delete?id=` + id })
+ },
+
+ // 导出积分商城 Excel
+ exportPointMall: async (params) => {
+ return await request.download({ url: `/promotion/point-mall/export-excel`, params })
+ }
+}
\ No newline at end of file
diff --git a/yudao-admin-vue3/src/utils/dict.ts b/yudao-admin-vue3/src/utils/dict.ts
index c23e726..eb7f4bf 100644
--- a/yudao-admin-vue3/src/utils/dict.ts
+++ b/yudao-admin-vue3/src/utils/dict.ts
@@ -186,6 +186,7 @@ export enum DICT_TYPE {
// ========== MALL - 商品模块 ==========
PRODUCT_SPU_STATUS = 'product_spu_status', //商品状态
+ POINT_PRODUCT_STATUS='point_product_status',//积分商品状态
// ========== MALL - 交易模块 ==========
EXPRESS_CHARGE_MODE = 'trade_delivery_express_charge_mode', //快递的计费方式
diff --git a/yudao-admin-vue3/src/views/mall/promotion/pointmall/PointMallForm.vue b/yudao-admin-vue3/src/views/mall/promotion/pointmall/PointMallForm.vue
new file mode 100644
index 0000000..012b90f
--- /dev/null
+++ b/yudao-admin-vue3/src/views/mall/promotion/pointmall/PointMallForm.vue
@@ -0,0 +1,205 @@
+
+
+
+
+
diff --git a/yudao-admin-vue3/src/views/mall/promotion/pointmall/activity/CombinationActivityForm.vue b/yudao-admin-vue3/src/views/mall/promotion/pointmall/activity/CombinationActivityForm.vue
new file mode 100644
index 0000000..87bd6cc
--- /dev/null
+++ b/yudao-admin-vue3/src/views/mall/promotion/pointmall/activity/CombinationActivityForm.vue
@@ -0,0 +1,192 @@
+
+
+
+
+
diff --git a/yudao-admin-vue3/src/views/mall/promotion/pointmall/activity/combinationActivity.data.ts b/yudao-admin-vue3/src/views/mall/promotion/pointmall/activity/combinationActivity.data.ts
new file mode 100644
index 0000000..e291f7d
--- /dev/null
+++ b/yudao-admin-vue3/src/views/mall/promotion/pointmall/activity/combinationActivity.data.ts
@@ -0,0 +1,140 @@
+import type { CrudSchema } from '@/hooks/web/useCrudSchemas'
+import { dateFormatter2 } from '@/utils/formatTime'
+
+// 表单校验
+export const rules = reactive({
+ // name: [required],
+ totalLimitCount: [required],
+ // singleLimitCount: [required],
+ // startTime: [required],
+ // endTime: [required],
+ // userSize: [required],
+ // limitDuration: [required],
+ // virtualGroup: [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: 'startTime',
+ // formatter: dateFormatter2,
+ // isSearch: true,
+ // search: {
+ // component: 'DatePicker',
+ // componentProps: {
+ // valueFormat: 'YYYY-MM-DD',
+ // type: 'daterange'
+ // }
+ // },
+ // form: {
+ // component: 'DatePicker',
+ // componentProps: {
+ // type: 'date',
+ // valueFormat: 'x'
+ // }
+ // },
+ // table: {
+ // width: 120
+ // }
+ // },
+ // {
+ // label: '拼团结束时间',
+ // field: 'endTime',
+ // formatter: dateFormatter2,
+ // isSearch: true,
+ // search: {
+ // component: 'DatePicker',
+ // componentProps: {
+ // valueFormat: 'YYYY-MM-DD',
+ // type: 'daterange'
+ // }
+ // },
+ // form: {
+ // component: 'DatePicker',
+ // componentProps: {
+ // type: 'date',
+ // valueFormat: 'x'
+ // }
+ // },
+ // table: {
+ // width: 120
+ // }
+ // },
+ // {
+ // label: '参与人数',
+ // field: 'userSize',
+ // 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: 'virtualGroup',
+ // dictType: DICT_TYPE.INFRA_BOOLEAN_STRING,
+ // dictClass: 'boolean',
+ // isSearch: true,
+ // form: {
+ // component: 'Radio',
+ // value: false
+ // }
+ // },
+ {
+ label: '拼团商品',
+ field: 'spuId',
+ isSearch: false,
+ form: {
+ colProps: {
+ span: 24
+ }
+ }
+ }
+])
+export const { allSchemas } = useCrudSchemas(crudSchemas)
diff --git a/yudao-admin-vue3/src/views/mall/promotion/pointmall/activity/index.vue b/yudao-admin-vue3/src/views/mall/promotion/pointmall/activity/index.vue
new file mode 100644
index 0000000..9b69d0a
--- /dev/null
+++ b/yudao-admin-vue3/src/views/mall/promotion/pointmall/activity/index.vue
@@ -0,0 +1,227 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+ 新增
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 下架
+
+
+ 上架
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/yudao-admin-vue3/src/views/mall/promotion/pointmall/index.vue b/yudao-admin-vue3/src/views/mall/promotion/pointmall/index.vue
new file mode 100644
index 0000000..90e9edf
--- /dev/null
+++ b/yudao-admin-vue3/src/views/mall/promotion/pointmall/index.vue
@@ -0,0 +1,277 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+ 新增
+
+
+ 导出
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 编辑
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
index e3ffa35..a0f8ac0 100644
--- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
+++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
@@ -103,4 +103,14 @@ public class ProductSpuRespDTO {
*/
private Boolean subCommissionType;
+ /**
+ * 活动编号
+ */
+ private Long activityId;
+
+ /**
+ * 兑换时所需积分数量
+ */
+ private Integer pointCount;
+
}
diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
index 52b260a..9f3ba83 100644
--- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
+++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
@@ -135,4 +135,6 @@ public interface ErrorCodeConstants {
ErrorCode CIRCLE_REVIEW_NOT_EXISTS = new ErrorCode(1_013_022_000, "动态的评论不存在");
+ ErrorCode POINT_MALL_NOT_EXISTS = new ErrorCode(1_013_023_000, "积分商城不存在");
+
}
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java
index 7d442b6..09f2def 100644
--- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java
@@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -114,5 +115,18 @@ public class CombinationActivityController {
return success(CombinationActivityConvert.INSTANCE.convertPage(pageResult, products,
groupCountMap, groupSuccessCountMap, recordCountMap, spus));
}
+ @GetMapping("/adminSpuList")
+ @Operation(summary = "获得拼团活动分页")
+ @Parameter(name = "count", description = "需要展示的数量", example = "6")
+ @PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
+ public CommonResult> getCombinationActivitySpuList(@RequestParam(name = "count", defaultValue = "6") Integer count){
+ List doList = combinationActivityService.getCombinationActivityListByCount(count);
+ ArrayList list = new ArrayList<>();
+ for (CombinationActivityDO activityDO : doList) {
+ list.add(activityDO.getSpuId());
+ }
+ return success(productSpuApi.getSpuList(list));
+ }
+
}
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/PointMallController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/PointMallController.java
new file mode 100644
index 0000000..a20baa3
--- /dev/null
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/PointMallController.java
@@ -0,0 +1,127 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.pointmall;
+
+import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
+import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import javax.validation.constraints.*;
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.math.BigDecimal;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
+
+import cn.iocoder.yudao.module.promotion.controller.admin.pointmall.vo.*;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.pointmall.PointMallDO;
+import cn.iocoder.yudao.module.promotion.service.pointmall.PointMallService;
+
+@Tag(name = "管理后台 - 积分商城")
+@RestController
+@RequestMapping("/promotion/point-mall")
+@Validated
+public class PointMallController {
+
+ @Resource
+ private PointMallService pointMallService;
+ @Resource
+ private ProductSpuApi productSpuApi;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建积分商城")
+ @PreAuthorize("@ss.hasPermission('promotion:point-mall:create')")
+ public CommonResult createPointMall(@Valid @RequestBody PointMallCombinationActivityCreateReqVO createReqVO) {
+ System.out.println("==============================");
+ System.out.println(createReqVO);
+ System.out.println("==============================");
+// PointMallSaveReqVO createReqVO
+ PointMallDO mallBySpuId = pointMallService.getPointMallBySpuId(createReqVO.getSpuId());
+ if (mallBySpuId != null){
+ return success(0L);
+ }
+ PointMallSaveReqVO reqVO = new PointMallSaveReqVO();
+ ProductSpuRespDTO spu = productSpuApi.getSpu(createReqVO.getSpuId());
+ reqVO.setExchangePointNum(BigDecimal.valueOf(createReqVO.getProducts().get(0).getCombinationPrice().longValue()).divide(new BigDecimal(100)).intValue());
+ reqVO.setLimited(createReqVO.getTotalLimitCount());
+ reqVO.setSurplusLimited(createReqVO.getTotalLimitCount());
+ reqVO.setProductPicUrl(spu.getPicUrl());
+ reqVO.setSpuId(createReqVO.getSpuId());
+ reqVO.setTitle(spu.getName());
+ reqVO.setStatus(0);
+ pointMallService.createPointMall(reqVO);
+ return success(1L);
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新积分商城")
+ @PreAuthorize("@ss.hasPermission('promotion:point-mall:update')")
+ public CommonResult updatePointMall(@Valid @RequestBody PointMallSaveReqVO updateReqVO) {
+ pointMallService.updatePointMall(updateReqVO);
+ return success(true);
+ }
+
+ @PutMapping("/closePointMall")
+ @Operation(summary = "关闭积分商品")
+ @PreAuthorize("@ss.hasPermission('promotion:point-mall:update')")
+ public CommonResult closePointMall(@RequestParam("id") Long id) {
+ pointMallService.closePointMall(id);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除积分商城")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('promotion:point-mall:delete')")
+ public CommonResult deletePointMall(@RequestParam("id") Long id) {
+ pointMallService.deletePointMall(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得积分商城")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('promotion:point-mall:query')")
+ public CommonResult getPointMall(@RequestParam("id") Long id) {
+ PointMallDO pointMall = pointMallService.getPointMall(id);
+ return success(BeanUtils.toBean(pointMall, PointMallRespVO.class));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得积分商城分页")
+ @PreAuthorize("@ss.hasPermission('promotion:point-mall:query')")
+ public CommonResult> getPointMallPage(@Valid PointMallPageReqVO pageReqVO) {
+ PageResult pageResult = pointMallService.getPointMallPage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, PointMallRespVO.class));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出积分商城 Excel")
+ @PreAuthorize("@ss.hasPermission('promotion:point-mall:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportPointMallExcel(@Valid PointMallPageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ List list = pointMallService.getPointMallPage(pageReqVO).getList();
+ // 导出 Excel
+ ExcelUtils.write(response, "积分商城.xls", "数据", PointMallRespVO.class,
+ BeanUtils.toBean(list, PointMallRespVO.class));
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallCombinationActivityBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallCombinationActivityBaseVO.java
new file mode 100644
index 0000000..ad9f790
--- /dev/null
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallCombinationActivityBaseVO.java
@@ -0,0 +1,59 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.pointmall.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+/**
+ * 拼团活动 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ *
+ * @author HUIHUI
+ */
+@Data
+public class PointMallCombinationActivityBaseVO {
+
+ @Schema(description = "拼团名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "越拼越省钱")
+// @NotNull(message = "拼团名称不能为空")
+ private String name;
+
+ @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+// @NotNull(message = "拼团商品不能为空")
+ private Long spuId;
+
+ @Schema(description = "总限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "16218")
+ @NotNull(message = "总限购数量不能为空")
+ private Integer totalLimitCount;
+
+ @Schema(description = "单次限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "28265")
+// @NotNull(message = "单次限购数量不能为空")
+ private Integer singleLimitCount;
+
+ @Schema(description = "活动时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 23:59:59]")
+// @NotNull(message = "活动时间不能为空")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime startTime;
+
+ @Schema(description = "活动时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 23:59:59]")
+// @NotNull(message = "活动时间不能为空")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime endTime;
+
+ @Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222")
+// @NotNull(message = "开团人数不能为空")
+ private Integer userSize;
+
+ @Schema(description = "虚拟成团", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
+// @NotNull(message = "虚拟成团不能为空")
+ private Boolean virtualGroup;
+
+ @Schema(description = "限制时长(小时)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+// @NotNull(message = "限制时长不能为空")
+ private Integer limitDuration;
+
+}
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallCombinationActivityCreateReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallCombinationActivityCreateReqVO.java
new file mode 100644
index 0000000..7fcd3bc
--- /dev/null
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallCombinationActivityCreateReqVO.java
@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.pointmall.vo;
+
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityBaseVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.Valid;
+import java.util.List;
+
+@Schema(description = "管理后台 - 拼团活动创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class PointMallCombinationActivityCreateReqVO extends PointMallCombinationActivityBaseVO {
+
+ @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED)
+ @Valid
+ private List products;
+
+}
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallPageReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallPageReqVO.java
new file mode 100644
index 0000000..20ab9b5
--- /dev/null
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallPageReqVO.java
@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.pointmall.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 积分商城分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class PointMallPageReqVO extends PageParam {
+
+ @Schema(description = "商品主图", example = "https://www.iocoder.cn")
+ private String productPicUrl;
+
+ @Schema(description = "标题")
+ private String title;
+
+ @Schema(description = "sku数组")
+ private String skuIds;
+
+ @Schema(description = "spu编号", example = "22695")
+ private Long spuId;
+
+ @Schema(description = "兑换积分")
+ private Integer exchangePointNum;
+
+ @Schema(description = "限量")
+ private Integer limited;
+
+ @Schema(description = "剩余限量")
+ private Integer surplusLimited;
+
+ @Schema(description = "状态", example = "1")
+ private Integer status;
+
+ @Schema(description = "排序")
+ private Long sort;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallRespVO.java
new file mode 100644
index 0000000..2c4788b
--- /dev/null
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallRespVO.java
@@ -0,0 +1,62 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.pointmall.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+
+@Schema(description = "管理后台 - 积分商城 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class PointMallRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3913")
+ @ExcelProperty("编号")
+ private Long id;
+
+ @Schema(description = "商品主图", example = "https://www.iocoder.cn")
+ @ExcelProperty("商品主图")
+ private String productPicUrl;
+
+ @Schema(description = "标题")
+ @ExcelProperty("标题")
+ private String title;
+
+ @Schema(description = "sku数组")
+ @ExcelProperty("sku数组")
+ private String skuIds;
+
+ @Schema(description = "spu编号", example = "22695")
+ @ExcelProperty("spu编号")
+ private Long spuId;
+
+ @Schema(description = "兑换积分")
+ @ExcelProperty("兑换积分")
+ private Integer exchangePointNum;
+
+ @Schema(description = "限量")
+ @ExcelProperty("限量")
+ private Integer limited;
+
+ @Schema(description = "剩余限量")
+ @ExcelProperty("剩余限量")
+ private Integer surplusLimited;
+
+ @Schema(description = "状态", example = "1")
+ @ExcelProperty(value = "状态", converter = DictConvert.class)
+ @DictFormat("point_product_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
+ private Integer status;
+
+ @Schema(description = "排序")
+ @ExcelProperty("排序")
+ private Long sort;
+
+ @Schema(description = "创建时间")
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallSaveReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallSaveReqVO.java
new file mode 100644
index 0000000..18b5c0b
--- /dev/null
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/pointmall/vo/PointMallSaveReqVO.java
@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.pointmall.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import javax.validation.constraints.*;
+
+@Schema(description = "管理后台 - 积分商城新增/修改 Request VO")
+@Data
+public class PointMallSaveReqVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3913")
+ private Long id;
+
+ @Schema(description = "商品主图", example = "https://www.iocoder.cn")
+ private String productPicUrl;
+
+ @Schema(description = "标题")
+ private String title;
+
+ @Schema(description = "sku数组")
+ private String skuIds;
+
+ @Schema(description = "spu编号", example = "22695")
+ private Long spuId;
+
+ @Schema(description = "兑换积分")
+ private Integer exchangePointNum;
+
+ @Schema(description = "限量")
+ private Integer limited;
+
+ @Schema(description = "剩余限量")
+ private Integer surplusLimited;
+
+ @Schema(description = "状态", example = "1")
+ private Integer status;
+
+ @Schema(description = "排序")
+ private Long sort;
+
+}
\ No newline at end of file
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillActivityController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillActivityController.java
index f0db690..c0c892a 100644
--- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillActivityController.java
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillActivityController.java
@@ -19,6 +19,7 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
+import java.util.ArrayList;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -96,4 +97,33 @@ public class SeckillActivityController {
return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, products, spuList));
}
+ @GetMapping("/adminSpuList")
+ @Operation(summary = "获得秒杀活动分页")
+ @Parameter(name = "count", description = "需要展示的数量", example = "6")
+ @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
+ public CommonResult> getSeckillActivitySupList(@RequestParam(name = "count", defaultValue = "6") Integer count) {
+ SeckillActivityPageReqVO pageVO = new SeckillActivityPageReqVO();
+ if (count == null || count == 0){
+ pageVO.setPageNo(1);
+ pageVO.setPageSize(count);
+ }
+ // 查询活动列表
+ PageResult pageResult = seckillActivityService.getSeckillActivityPage(pageVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(null);
+ }
+
+ // 拼接数据
+ List products = seckillActivityService.getSeckillProductListByActivityId(
+ convertSet(pageResult.getList(), SeckillActivityDO::getId));
+ List spuList = productSpuApi.getSpuList(
+ convertSet(pageResult.getList(), SeckillActivityDO::getSpuId));
+ PageResult convertPage = SeckillActivityConvert.INSTANCE.convertPage(pageResult, products, spuList);
+ ArrayList list = new ArrayList<>();
+ for (SeckillActivityRespVO seckillActivityRespVO : convertPage.getList()) {
+ list.add(seckillActivityRespVO.getSpuId());
+ }
+ return success(productSpuApi.getSpuList(list));
+ }
+
}
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationActivityController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationActivityController.java
index 6534c4e..7b93908 100644
--- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationActivityController.java
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationActivityController.java
@@ -27,7 +27,9 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.time.Duration;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -67,6 +69,25 @@ public class AppCombinationActivityController {
return success(combinationActivityListCache.getUnchecked(count));
}
+ @GetMapping("/spuList")
+ @Operation(summary = "获得拼团活动列表", description = "用于小程序首页")
+ @Parameter(name = "count", description = "需要展示的数量", example = "6")
+ public CommonResult> getCombinationActivitySpuList(
+ @RequestParam(name = "count", defaultValue = "6") Integer count) {
+ List list = combinationActivityListCache.getUnchecked(count);
+ ArrayList arrayList = new ArrayList<>();
+ HashMap map = new HashMap<>();
+ for (AppCombinationActivityRespVO respVO : list) {
+ arrayList.add(respVO.getSpuId());
+ map.put(respVO.getSpuId(),respVO.getId());
+ }
+ List spuList = spuApi.getSpuList(arrayList);
+ for (ProductSpuRespDTO dto : spuList) {
+ dto.setActivityId(map.get(dto.getId()));
+ }
+ return success(spuList);
+ }
+
private List getCombinationActivityList0(Integer count) {
List activityList = activityService.getCombinationActivityListByCount(count);
if (CollUtil.isEmpty(activityList)) {
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java
index 1b49453..1219c66 100644
--- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java
@@ -35,6 +35,8 @@ import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -109,6 +111,39 @@ public class AppSeckillActivityController {
return success(SeckillActivityConvert.INSTANCE.convertPage02(pageResult, productList, spuList));
}
+ @GetMapping("/spuList")
+ @Parameter(name = "count", description = "需要展示的数量", example = "6")
+ @Operation(summary = "获得秒杀活动分页")
+ public CommonResult> getSeckillActivitySupList(@RequestParam(name = "count", defaultValue = "6") Integer count) {
+ AppSeckillActivityPageReqVO pageReqVO = new AppSeckillActivityPageReqVO();
+ if (count == null || count == 0){
+ pageReqVO.setPageNo(1);
+ pageReqVO.setPageSize(count);
+ }
+ // 1. 查询满足当前阶段的活动
+ PageResult pageResult = activityService.getSeckillActivityAppPageByConfigId(pageReqVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(null);
+ }
+ List productList = activityService.getSeckillProductListByActivityId(
+ convertList(pageResult.getList(), SeckillActivityDO::getId));
+
+ // 2. 拼接数据
+ List spuList = spuApi.getSpuList(convertList(pageResult.getList(), SeckillActivityDO::getSpuId));
+ PageResult result = SeckillActivityConvert.INSTANCE.convertPage02(pageResult, productList, spuList);
+ ArrayList arrayList = new ArrayList<>();
+ HashMap hashMap = new HashMap<>();
+ for (AppSeckillActivityRespVO respVO : result.getList()) {
+ arrayList.add(respVO.getSpuId());
+ hashMap.put(respVO.getSpuId(),respVO.getId());
+ }
+ List list = spuApi.getSpuList(arrayList);
+ for (ProductSpuRespDTO respDTO : list) {
+ respDTO.setActivityId(hashMap.get(respDTO.getId()));
+ }
+ return success(list);
+ }
+
@GetMapping("/get-detail")
@Operation(summary = "获得秒杀活动明细")
@Parameter(name = "id", description = "活动编号", required = true, example = "1024")
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/pointmall/PointMallDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/pointmall/PointMallDO.java
new file mode 100644
index 0000000..49ed500
--- /dev/null
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/pointmall/PointMallDO.java
@@ -0,0 +1,69 @@
+package cn.iocoder.yudao.module.promotion.dal.dataobject.pointmall;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 积分商城 DO
+ *
+ * @author 管理员
+ */
+@TableName("promotion_point_mall")
+@KeySequence("promotion_point_mall_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class PointMallDO extends BaseDO {
+
+ /**
+ * 编号
+ */
+ @TableId
+ private Long id;
+ /**
+ * 商品主图
+ */
+ private String productPicUrl;
+ /**
+ * 标题
+ */
+ private String title;
+ /**
+ * sku数组
+ */
+ private String skuIds;
+ /**
+ * spu编号
+ */
+ private Long spuId;
+ /**
+ * 兑换积分
+ */
+ private Integer exchangePointNum;
+ /**
+ * 限量
+ */
+ private Integer limited;
+ /**
+ * 剩余限量
+ */
+ private Integer surplusLimited;
+ /**
+ * 状态
+ *
+ * 枚举 {@link TODO point_product_status 对应的类}
+ */
+ private Integer status;
+ /**
+ * 排序
+ */
+ private Long sort;
+
+}
\ No newline at end of file
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/pointmall/PointMallMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/pointmall/PointMallMapper.java
new file mode 100644
index 0000000..a195242
--- /dev/null
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/pointmall/PointMallMapper.java
@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.promotion.dal.mysql.pointmall;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.pointmall.PointMallDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.promotion.controller.admin.pointmall.vo.*;
+
+/**
+ * 积分商城 Mapper
+ *
+ * @author 管理员
+ */
+@Mapper
+public interface PointMallMapper extends BaseMapperX {
+
+ default PageResult selectPage(PointMallPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .eqIfPresent(PointMallDO::getProductPicUrl, reqVO.getProductPicUrl())
+ .eqIfPresent(PointMallDO::getTitle, reqVO.getTitle())
+ .eqIfPresent(PointMallDO::getSkuIds, reqVO.getSkuIds())
+ .eqIfPresent(PointMallDO::getSpuId, reqVO.getSpuId())
+ .eqIfPresent(PointMallDO::getExchangePointNum, reqVO.getExchangePointNum())
+ .eqIfPresent(PointMallDO::getLimited, reqVO.getLimited())
+ .eqIfPresent(PointMallDO::getSurplusLimited, reqVO.getSurplusLimited())
+ .eqIfPresent(PointMallDO::getStatus, reqVO.getStatus())
+ .eqIfPresent(PointMallDO::getSort, reqVO.getSort())
+ .betweenIfPresent(PointMallDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(PointMallDO::getId));
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/pointmall/PointMallService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/pointmall/PointMallService.java
new file mode 100644
index 0000000..c5b5d5f
--- /dev/null
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/pointmall/PointMallService.java
@@ -0,0 +1,57 @@
+package cn.iocoder.yudao.module.promotion.service.pointmall;
+
+import java.util.*;
+import javax.validation.*;
+import cn.iocoder.yudao.module.promotion.controller.admin.pointmall.vo.*;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.pointmall.PointMallDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+
+/**
+ * 积分商城 Service 接口
+ *
+ * @author 管理员
+ */
+public interface PointMallService {
+
+ /**
+ * 创建积分商城
+ *
+ * @param createReqVO 创建信息
+ * @return 编号
+ */
+ Long createPointMall(@Valid PointMallSaveReqVO createReqVO);
+
+ /**
+ * 更新积分商城
+ *
+ * @param updateReqVO 更新信息
+ */
+ void updatePointMall(@Valid PointMallSaveReqVO updateReqVO);
+ void closePointMall(Long id);
+
+ /**
+ * 删除积分商城
+ *
+ * @param id 编号
+ */
+ void deletePointMall(Long id);
+
+ /**
+ * 获得积分商城
+ *
+ * @param id 编号
+ * @return 积分商城
+ */
+ PointMallDO getPointMall(Long id);
+ PointMallDO getPointMallBySpuId(Long spuId);
+
+ /**
+ * 获得积分商城分页
+ *
+ * @param pageReqVO 分页查询
+ * @return 积分商城分页
+ */
+ PageResult getPointMallPage(PointMallPageReqVO pageReqVO);
+
+}
\ No newline at end of file
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/pointmall/PointMallServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/pointmall/PointMallServiceImpl.java
new file mode 100644
index 0000000..62bfac5
--- /dev/null
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/pointmall/PointMallServiceImpl.java
@@ -0,0 +1,91 @@
+package cn.iocoder.yudao.module.promotion.service.pointmall;
+
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import cn.iocoder.yudao.module.promotion.controller.admin.pointmall.vo.*;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.pointmall.PointMallDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
+import cn.iocoder.yudao.module.promotion.dal.mysql.pointmall.PointMallMapper;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
+
+/**
+ * 积分商城 Service 实现类
+ *
+ * @author 管理员
+ */
+@Service
+@Validated
+public class PointMallServiceImpl implements PointMallService {
+
+ @Resource
+ private PointMallMapper pointMallMapper;
+
+ @Override
+ public Long createPointMall(PointMallSaveReqVO createReqVO) {
+ // 插入
+ PointMallDO pointMall = BeanUtils.toBean(createReqVO, PointMallDO.class);
+ pointMallMapper.insert(pointMall);
+ // 返回
+ return pointMall.getId();
+ }
+
+ @Override
+ public void updatePointMall(PointMallSaveReqVO updateReqVO) {
+ // 校验存在
+ validatePointMallExists(updateReqVO.getId());
+ // 更新
+ PointMallDO updateObj = BeanUtils.toBean(updateReqVO, PointMallDO.class);
+ pointMallMapper.updateById(updateObj);
+ }
+
+ @Override
+ public void closePointMall(Long id) {
+ PointMallDO pointMallDO = pointMallMapper.selectOne("id", id);
+ if (pointMallDO.getStatus() == 1){
+ pointMallDO.setStatus(0);
+ }else if (pointMallDO.getStatus() == 0){
+ pointMallDO.setStatus(1);
+ }
+ pointMallMapper.updateById(pointMallDO);
+ }
+
+ @Override
+ public void deletePointMall(Long id) {
+ // 校验存在
+ validatePointMallExists(id);
+ // 删除
+ pointMallMapper.deleteById(id);
+ }
+
+ private void validatePointMallExists(Long id) {
+ if (pointMallMapper.selectById(id) == null) {
+ throw exception(POINT_MALL_NOT_EXISTS);
+ }
+ }
+
+ @Override
+ public PointMallDO getPointMall(Long id) {
+ return pointMallMapper.selectById(id);
+ }
+
+ @Override
+ public PointMallDO getPointMallBySpuId(Long id) {
+ PointMallDO mallDO = pointMallMapper.selectOne("spu_id", id);
+ return mallDO;
+ }
+
+ @Override
+ public PageResult getPointMallPage(PointMallPageReqVO pageReqVO) {
+ return pointMallMapper.selectPage(pageReqVO);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/pointmall/PointMallMapper.xml b/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/pointmall/PointMallMapper.xml
new file mode 100644
index 0000000..10ac6d5
--- /dev/null
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/pointmall/PointMallMapper.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
\ No newline at end of file