diff --git a/sql/mall.sql b/sql/mall.sql index 92dc580ed..db60049ce 100644 --- a/sql/mall.sql +++ b/sql/mall.sql @@ -85,3 +85,28 @@ INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id` INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES ('品牌更新', 'product:brand:update', 3, 3, @parentId, '', '', '', 0); INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES ('品牌删除', 'product:brand:delete', 3, 4, @parentId, '', '', '', 0); INSERT INTO `system_menu`(`name`, `permission`, `menu_type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`) VALUES ('品牌导出', 'product:brand:export', 3, 5, @parentId, '', '', '', 0); + + +-- ---------------------------- +-- Table structure for market_activity +-- ---------------------------- +DROP TABLE IF EXISTS `market_activity`; +CREATE TABLE `market_activity` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '活动编号', + `title` varchar(50) NOT NULL DEFAULT '' COMMENT '活动标题', + `activity_type` tinyint(4) NOT NULL COMMENT '活动类型', + `status` tinyint(4) NOT NULL DEFAULT '-1' COMMENT '活动状态', + `start_time` datetime NOT NULL COMMENT '开始时间', + `end_time` datetime NOT NULL COMMENT '结束时间', + `invalid_time` datetime DEFAULT NULL COMMENT '失效时间', + `delete_time` datetime DEFAULT NULL COMMENT '删除时间', + `time_limited_discount` varchar(2000) DEFAULT NULL COMMENT '限制折扣字符串,使用 JSON 序列化成字符串存储', + `full_privilege` varchar(2000) DEFAULT NULL COMMENT '限制折扣字符串,使用 JSON 序列化成字符串存储', + `creator` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='促销活动'; \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/api/package-info.java b/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/api/package-info.java new file mode 100644 index 000000000..cb45004b6 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/api/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package cn.iocoder.yudao.module.market.api; \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/enums/ErrorCodeConstants.java new file mode 100644 index 000000000..101e84325 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/enums/ErrorCodeConstants.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.market.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * market 错误码枚举类 + *

+ * market 系统,使用 1-003-000-000 段 + */ +public interface ErrorCodeConstants { + + + // ========== 促销活动相关 1003001000============ + ErrorCode ACTIVITY_NOT_EXISTS = new ErrorCode(1003001000, "促销活动不存在"); +} diff --git a/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/enums/activity/MarketActivityStatusEnum.java b/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/enums/activity/MarketActivityStatusEnum.java new file mode 100644 index 000000000..a02b0269c --- /dev/null +++ b/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/enums/activity/MarketActivityStatusEnum.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.market.enums.activity; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; + +import java.util.Arrays; + +/** + * 促销活动状态枚举 + */ +public enum MarketActivityStatusEnum implements IntArrayValuable { + + WAIT(10, "未开始"), + RUN(20, "进行中"), + END(30, "已结束"), + /** + * 1. WAIT、RUN、END 可以转换成 INVALID 状态。 + * 2. INVALID 只可以转换成 DELETED 状态。 + */ + INVALID(40, "已撤销"), + DELETED(50, "已删除"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(MarketActivityStatusEnum::getValue).toArray(); + + /** + * 状态值 + */ + private final Integer value; + /** + * 状态名 + */ + private final String name; + + MarketActivityStatusEnum(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + + @Override + public int[] array() { + return ARRAYS; + } +} diff --git a/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/enums/activity/MarketActivityTypeEnum.java b/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/enums/activity/MarketActivityTypeEnum.java new file mode 100644 index 000000000..0413dba66 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/enums/activity/MarketActivityTypeEnum.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.market.enums.activity; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; + +import java.util.Arrays; + +/** + * 促销活动类型枚举 + */ +public enum MarketActivityTypeEnum implements IntArrayValuable { + + TIME_LIMITED_DISCOUNT(1, "限时折扣"), + FULL_PRIVILEGE(2, "满减送"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(MarketActivityTypeEnum::getValue).toArray(); + + /** + * 类型值 + */ + private final Integer value; + /** + * 类型名 + */ + private final String name; + + MarketActivityTypeEnum(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + + @Override + public int[] array() { + return ARRAYS; + } +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/ActivityController.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/ActivityController.java new file mode 100644 index 000000000..dac4211a6 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/ActivityController.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.market.controller.admin.activity; + +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.annotations.*; +import javax.validation.*; +import java.util.*; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import cn.iocoder.yudao.module.market.controller.admin.activity.vo.*; +import cn.iocoder.yudao.module.market.dal.dataobject.activity.ActivityDO; +import cn.iocoder.yudao.module.market.convert.activity.ActivityConvert; +import cn.iocoder.yudao.module.market.service.activity.ActivityService; + +@Api(tags = "管理后台 - 促销活动") +@RestController +@RequestMapping("/market/activity") +@Validated +public class ActivityController { + + @Resource + private ActivityService activityService; + + @PostMapping("/create") + @ApiOperation("创建促销活动") + @PreAuthorize("@ss.hasPermission('market:activity:create')") + public CommonResult createActivity(@Valid @RequestBody ActivityCreateReqVO createReqVO) { + return success(activityService.createActivity(createReqVO)); + } + + @PutMapping("/update") + @ApiOperation("更新促销活动") + @PreAuthorize("@ss.hasPermission('market:activity:update')") + public CommonResult updateActivity(@Valid @RequestBody ActivityUpdateReqVO updateReqVO) { + activityService.updateActivity(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @ApiOperation("删除促销活动") + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('market:activity:delete')") + public CommonResult deleteActivity(@RequestParam("id") Long id) { + activityService.deleteActivity(id); + return success(true); + } + + @GetMapping("/get") + @ApiOperation("获得促销活动") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('market:activity:query')") + public CommonResult getActivity(@RequestParam("id") Long id) { + ActivityDO activity = activityService.getActivity(id); + return success(ActivityConvert.INSTANCE.convert(activity)); + } + + @GetMapping("/list") + @ApiOperation("获得促销活动列表") + @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class) + @PreAuthorize("@ss.hasPermission('market:activity:query')") + public CommonResult> getActivityList(@RequestParam("ids") Collection ids) { + List list = activityService.getActivityList(ids); + return success(ActivityConvert.INSTANCE.convertList(list)); + } + + @GetMapping("/page") + @ApiOperation("获得促销活动分页") + @PreAuthorize("@ss.hasPermission('market:activity:query')") + public CommonResult> getActivityPage(@Valid ActivityPageReqVO pageVO) { + PageResult pageResult = activityService.getActivityPage(pageVO); + return success(ActivityConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityBaseVO.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityBaseVO.java new file mode 100644 index 000000000..3ae5cd679 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityBaseVO.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.market.controller.admin.activity.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.market.enums.activity.MarketActivityStatusEnum; +import cn.iocoder.yudao.module.market.enums.activity.MarketActivityTypeEnum; +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; +import org.springframework.format.annotation.DateTimeFormat; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** +* 促销活动 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class ActivityBaseVO { + + @ApiModelProperty(value = "活动标题", required = true) + @NotNull(message = "活动标题不能为空") + private String title; + + @ApiModelProperty(value = "活动类型", required = true) + @NotNull(message = "活动类型不能为空") + @InEnum(MarketActivityTypeEnum.class) + private Integer activityType; + + @ApiModelProperty(value = "活动状态", required = true) + @NotNull(message = "活动状态不能为空") + @InEnum(MarketActivityStatusEnum.class) + private Integer status; + + @ApiModelProperty(value = "开始时间", required = true) + @NotNull(message = "开始时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date startTime; + + @ApiModelProperty(value = "结束时间", required = true) + @NotNull(message = "结束时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date endTime; + + @ApiModelProperty(value = "失效时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date invalidTime; + + @ApiModelProperty(value = "删除时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date deleteTime; + + @ApiModelProperty(value = "限制折扣字符串,使用 JSON 序列化成字符串存储") + private String timeLimitedDiscount; + + @ApiModelProperty(value = "限制折扣字符串,使用 JSON 序列化成字符串存储") + private String fullPrivilege; + +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityCreateReqVO.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityCreateReqVO.java new file mode 100644 index 000000000..c031a361a --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.market.controller.admin.activity.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; + +@ApiModel("管理后台 - 促销活动创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ActivityCreateReqVO extends ActivityBaseVO { + +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityPageReqVO.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityPageReqVO.java new file mode 100644 index 000000000..f3a4155b0 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityPageReqVO.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.market.controller.admin.activity.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.market.enums.activity.MarketActivityStatusEnum; +import cn.iocoder.yudao.module.market.enums.activity.MarketActivityTypeEnum; +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel("管理后台 - 促销活动分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ActivityPageReqVO extends PageParam { + + @ApiModelProperty(value = "活动标题") + private String title; + + @ApiModelProperty(value = "活动类型") + @InEnum(MarketActivityTypeEnum.class) + private Integer activityType; + + @ApiModelProperty(value = "活动状态") + @InEnum(MarketActivityStatusEnum.class) + private Integer status; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "开始开始时间") + private Date beginStartTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "结束开始时间") + private Date endStartTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "开始结束时间") + private Date beginEndTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "结束结束时间") + private Date endEndTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "开始失效时间") + private Date beginInvalidTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "结束失效时间") + private Date endInvalidTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "开始删除时间") + private Date beginDeleteTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "结束删除时间") + private Date endDeleteTime; + + @ApiModelProperty(value = "限制折扣字符串,使用 JSON 序列化成字符串存储") + private String timeLimitedDiscount; + + @ApiModelProperty(value = "限制折扣字符串,使用 JSON 序列化成字符串存储") + private String fullPrivilege; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "开始创建时间") + private Date beginCreateTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "结束创建时间") + private Date endCreateTime; + +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityRespVO.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityRespVO.java new file mode 100644 index 000000000..de7ca3af2 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.market.controller.admin.activity.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; + +@ApiModel("管理后台 - 促销活动 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ActivityRespVO extends ActivityBaseVO { + + @ApiModelProperty(value = "活动编号", required = true) + private Long id; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityUpdateReqVO.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityUpdateReqVO.java new file mode 100644 index 000000000..1db24f259 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/admin/activity/vo/ActivityUpdateReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.market.controller.admin.activity.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; + +@ApiModel("管理后台 - 促销活动更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ActivityUpdateReqVO extends ActivityBaseVO { + + @ApiModelProperty(value = "活动编号", required = true) + @NotNull(message = "活动编号不能为空") + private Long id; + +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/convert/activity/ActivityConvert.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/convert/activity/ActivityConvert.java new file mode 100644 index 000000000..64ba73975 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/convert/activity/ActivityConvert.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.market.convert.activity; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; +import cn.iocoder.yudao.module.market.controller.admin.activity.vo.*; +import cn.iocoder.yudao.module.market.dal.dataobject.activity.ActivityDO; + +/** + * 促销活动 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface ActivityConvert { + + ActivityConvert INSTANCE = Mappers.getMapper(ActivityConvert.class); + + ActivityDO convert(ActivityCreateReqVO bean); + + ActivityDO convert(ActivityUpdateReqVO bean); + + ActivityRespVO convert(ActivityDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/dal/dataobject/activity/ActivityDO.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/dal/dataobject/activity/ActivityDO.java new file mode 100644 index 000000000..13dcbf67c --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/dal/dataobject/activity/ActivityDO.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.market.dal.dataobject.activity; + +import lombok.*; +import java.util.*; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 促销活动 DO + * + * @author 芋道源码 + */ +@TableName("market_activity") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ActivityDO extends BaseDO { + + /** + * 活动编号 + */ + @TableId + private Long id; + /** + * 活动标题 + */ + private String title; + /** + * 活动类型MarketActivityTypeEnum + */ + private Integer activityType; + /** + * 活动状态MarketActivityStatusEnum + */ + private Integer status; + /** + * 开始时间 + */ + private Date startTime; + /** + * 结束时间 + */ + private Date endTime; + /** + * 失效时间 + */ + private Date invalidTime; + /** + * 删除时间 + */ + private Date deleteTime; + /** + * 限制折扣字符串,使用 JSON 序列化成字符串存储 + */ + private String timeLimitedDiscount; + /** + * 限制折扣字符串,使用 JSON 序列化成字符串存储 + */ + private String fullPrivilege; + +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/dal/mysql/activity/ActivityMapper.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/dal/mysql/activity/ActivityMapper.java new file mode 100644 index 000000000..b786ad981 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/dal/mysql/activity/ActivityMapper.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.market.dal.mysql.activity; + +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.market.dal.dataobject.activity.ActivityDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.market.controller.admin.activity.vo.*; + +/** + * 促销活动 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ActivityMapper extends BaseMapperX { + + default PageResult selectPage(ActivityPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ActivityDO::getTitle, reqVO.getTitle()) + .eqIfPresent(ActivityDO::getActivityType, reqVO.getActivityType()) + .eqIfPresent(ActivityDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(ActivityDO::getStartTime, reqVO.getBeginStartTime(), reqVO.getEndStartTime()) + .betweenIfPresent(ActivityDO::getEndTime, reqVO.getBeginEndTime(), reqVO.getEndEndTime()) + .betweenIfPresent(ActivityDO::getInvalidTime, reqVO.getBeginInvalidTime(), reqVO.getEndInvalidTime()) + .betweenIfPresent(ActivityDO::getDeleteTime, reqVO.getBeginDeleteTime(), reqVO.getEndDeleteTime()) + .eqIfPresent(ActivityDO::getTimeLimitedDiscount, reqVO.getTimeLimitedDiscount()) + .eqIfPresent(ActivityDO::getFullPrivilege, reqVO.getFullPrivilege()) + .betweenIfPresent(ActivityDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .orderByDesc(ActivityDO::getId)); + } + +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/activity/ActivityService.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/activity/ActivityService.java new file mode 100644 index 000000000..1d5e27857 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/activity/ActivityService.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.market.service.activity; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.market.controller.admin.activity.vo.*; +import cn.iocoder.yudao.module.market.dal.dataobject.activity.ActivityDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +/** + * 促销活动 Service 接口 + * + * @author 芋道源码 + */ +public interface ActivityService { + + /** + * 创建促销活动 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createActivity(@Valid ActivityCreateReqVO createReqVO); + + /** + * 更新促销活动 + * + * @param updateReqVO 更新信息 + */ + void updateActivity(@Valid ActivityUpdateReqVO updateReqVO); + + /** + * 删除促销活动 + * + * @param id 编号 + */ + void deleteActivity(Long id); + + /** + * 获得促销活动 + * + * @param id 编号 + * @return 促销活动 + */ + ActivityDO getActivity(Long id); + + /** + * 获得促销活动列表 + * + * @param ids 编号 + * @return 促销活动列表 + */ + List getActivityList(Collection ids); + + /** + * 获得促销活动分页 + * + * @param pageReqVO 分页查询 + * @return 促销活动分页 + */ + PageResult getActivityPage(ActivityPageReqVO pageReqVO); + +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/activity/ActivityServiceImpl.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/activity/ActivityServiceImpl.java new file mode 100644 index 000000000..57bb9af53 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/activity/ActivityServiceImpl.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.market.service.activity; + +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; + +import java.util.*; +import cn.iocoder.yudao.module.market.controller.admin.activity.vo.*; +import cn.iocoder.yudao.module.market.dal.dataobject.activity.ActivityDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import cn.iocoder.yudao.module.market.convert.activity.ActivityConvert; +import cn.iocoder.yudao.module.market.dal.mysql.activity.ActivityMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.market.enums.ErrorCodeConstants.*; + +/** + * 促销活动 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ActivityServiceImpl implements ActivityService { + + @Resource + private ActivityMapper activityMapper; + + @Override + public Long createActivity(ActivityCreateReqVO createReqVO) { + // 插入 + ActivityDO activity = ActivityConvert.INSTANCE.convert(createReqVO); + activityMapper.insert(activity); + // 返回 + return activity.getId(); + } + + @Override + public void updateActivity(ActivityUpdateReqVO updateReqVO) { + // 校验存在 + this.validateActivityExists(updateReqVO.getId()); + // 更新 + ActivityDO updateObj = ActivityConvert.INSTANCE.convert(updateReqVO); + activityMapper.updateById(updateObj); + } + + @Override + public void deleteActivity(Long id) { + // 校验存在 + this.validateActivityExists(id); + // 删除 + activityMapper.deleteById(id); + } + + private void validateActivityExists(Long id) { + if (activityMapper.selectById(id) == null) { + throw exception(ACTIVITY_NOT_EXISTS); + } + } + + @Override + public ActivityDO getActivity(Long id) { + return activityMapper.selectById(id); + } + + @Override + public List getActivityList(Collection ids) { + return activityMapper.selectBatchIds(ids); + } + + @Override + public PageResult getActivityPage(ActivityPageReqVO pageReqVO) { + return activityMapper.selectPage(pageReqVO); + } + +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/test/java/cn/iocoder/yudao/module/market/service/activity/ActivityServiceImplTest.java b/yudao-module-mall/yudao-module-market-biz/src/test/java/cn/iocoder/yudao/module/market/service/activity/ActivityServiceImplTest.java new file mode 100644 index 000000000..f5b9a8b50 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/test/java/cn/iocoder/yudao/module/market/service/activity/ActivityServiceImplTest.java @@ -0,0 +1,202 @@ +package cn.iocoder.yudao.module.market.service.activity; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.market.controller.admin.activity.vo.*; +import cn.iocoder.yudao.module.market.dal.dataobject.activity.ActivityDO; +import cn.iocoder.yudao.module.market.dal.mysql.activity.ActivityMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import org.springframework.context.annotation.Import; + +import static cn.iocoder.yudao.module.market.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static org.junit.jupiter.api.Assertions.*; + +/** +* {@link ActivityServiceImpl} 的单元测试类 +* +* @author 芋道源码 +*/ +@Import(ActivityServiceImpl.class) +public class ActivityServiceImplTest extends BaseDbUnitTest { + + @Resource + private ActivityServiceImpl activityService; + + @Resource + private ActivityMapper activityMapper; + + @Test + public void testCreateActivity_success() { + // 准备参数 + ActivityCreateReqVO reqVO = randomPojo(ActivityCreateReqVO.class); + + // 调用 + Long activityId = activityService.createActivity(reqVO); + // 断言 + assertNotNull(activityId); + // 校验记录的属性是否正确 + ActivityDO activity = activityMapper.selectById(activityId); + assertPojoEquals(reqVO, activity); + } + + @Test + public void testUpdateActivity_success() { + // mock 数据 + ActivityDO dbActivity = randomPojo(ActivityDO.class); + activityMapper.insert(dbActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + ActivityUpdateReqVO reqVO = randomPojo(ActivityUpdateReqVO.class, o -> { + o.setId(dbActivity.getId()); // 设置更新的 ID + }); + + // 调用 + activityService.updateActivity(reqVO); + // 校验是否更新正确 + ActivityDO activity = activityMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, activity); + } + + @Test + public void testUpdateActivity_notExists() { + // 准备参数 + ActivityUpdateReqVO reqVO = randomPojo(ActivityUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> activityService.updateActivity(reqVO), ACTIVITY_NOT_EXISTS); + } + + @Test + public void testDeleteActivity_success() { + // mock 数据 + ActivityDO dbActivity = randomPojo(ActivityDO.class); + activityMapper.insert(dbActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbActivity.getId(); + + // 调用 + activityService.deleteActivity(id); + // 校验数据不存在了 + assertNull(activityMapper.selectById(id)); + } + + @Test + public void testDeleteActivity_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> activityService.deleteActivity(id), ACTIVITY_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetActivityPage() { + // mock 数据 + ActivityDO dbActivity = randomPojo(ActivityDO.class, o -> { // 等会查询到 + o.setTitle(null); + o.setActivityType(null); + o.setStatus(null); + o.setStartTime(null); + o.setEndTime(null); + o.setInvalidTime(null); + o.setDeleteTime(null); + o.setTimeLimitedDiscount(null); + o.setFullPrivilege(null); + o.setCreateTime(null); + }); + activityMapper.insert(dbActivity); + // 测试 title 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setTitle(null))); + // 测试 activityType 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setActivityType(null))); + // 测试 status 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setStatus(null))); + // 测试 startTime 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setStartTime(null))); + // 测试 endTime 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setEndTime(null))); + // 测试 invalidTime 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setInvalidTime(null))); + // 测试 deleteTime 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setDeleteTime(null))); + // 测试 timeLimitedDiscount 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setTimeLimitedDiscount(null))); + // 测试 fullPrivilege 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setFullPrivilege(null))); + // 测试 createTime 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setCreateTime(null))); + // 准备参数 + ActivityPageReqVO reqVO = new ActivityPageReqVO(); + reqVO.setTitle(null); + reqVO.setActivityType(null); + reqVO.setStatus(null); + reqVO.setBeginStartTime(null); + reqVO.setEndStartTime(null); + reqVO.setBeginEndTime(null); + reqVO.setEndEndTime(null); + reqVO.setBeginInvalidTime(null); + reqVO.setEndInvalidTime(null); + reqVO.setBeginDeleteTime(null); + reqVO.setEndDeleteTime(null); + reqVO.setTimeLimitedDiscount(null); + reqVO.setFullPrivilege(null); + reqVO.setBeginCreateTime(null); + reqVO.setEndCreateTime(null); + + // 调用 + PageResult pageResult = activityService.getActivityPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbActivity, pageResult.getList().get(0)); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetActivityList() { + // mock 数据 + ActivityDO dbActivity = randomPojo(ActivityDO.class, o -> { // 等会查询到 + o.setTitle(null); + o.setActivityType(null); + o.setStatus(null); + o.setStartTime(null); + o.setEndTime(null); + o.setInvalidTime(null); + o.setDeleteTime(null); + o.setTimeLimitedDiscount(null); + o.setFullPrivilege(null); + o.setCreateTime(null); + }); + activityMapper.insert(dbActivity); + // 测试 title 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setTitle(null))); + // 测试 activityType 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setActivityType(null))); + // 测试 status 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setStatus(null))); + // 测试 startTime 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setStartTime(null))); + // 测试 endTime 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setEndTime(null))); + // 测试 invalidTime 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setInvalidTime(null))); + // 测试 deleteTime 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setDeleteTime(null))); + // 测试 timeLimitedDiscount 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setTimeLimitedDiscount(null))); + // 测试 fullPrivilege 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setFullPrivilege(null))); + // 测试 createTime 不匹配 + activityMapper.insert(cloneIgnoreId(dbActivity, o -> o.setCreateTime(null))); + } + +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/test/resources/application-unit-test.yaml b/yudao-module-mall/yudao-module-market-biz/src/test/resources/application-unit-test.yaml new file mode 100644 index 000000000..60914d97f --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/test/resources/application-unit-test.yaml @@ -0,0 +1,49 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + datasource: + name: ruoyi-vue-pro + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 + driver-class-name: org.h2.Driver + username: sa + password: + druid: + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度 + initial-size: 1 # 单元测试,配置为 1,提升启动速度 + sql: + init: + schema-locations: classpath:/sql/create_tables.sql + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 16379 # 端口(单元测试,使用 16379 端口) + database: 0 # 数据库索引 + +mybatis: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +# Resilience4j 配置项 + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + info: + base-package: cn.iocoder.yudao.module diff --git a/yudao-module-mall/yudao-module-market-biz/src/test/resources/logback.xml b/yudao-module-mall/yudao-module-market-biz/src/test/resources/logback.xml new file mode 100644 index 000000000..daf756bff --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/test/resources/logback.xml @@ -0,0 +1,4 @@ + + + + diff --git a/yudao-module-mall/yudao-module-market-biz/src/test/resources/sql/clean.sql b/yudao-module-mall/yudao-module-market-biz/src/test/resources/sql/clean.sql new file mode 100644 index 000000000..abad7c069 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/test/resources/sql/clean.sql @@ -0,0 +1 @@ +DELETE FROM "market_activity"; diff --git a/yudao-module-mall/yudao-module-market-biz/src/test/resources/sql/create_tables.sql b/yudao-module-mall/yudao-module-market-biz/src/test/resources/sql/create_tables.sql new file mode 100644 index 000000000..3f3ce3c4d --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/test/resources/sql/create_tables.sql @@ -0,0 +1,19 @@ +CREATE TABLE IF NOT EXISTS "market_activity" ( + "id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "title" varchar(50) NOT NULL, + "activity_type" tinyint(4) NOT NULL, + "status" tinyint(4) NOT NULL, + "start_time" datetime NOT NULL, + "end_time" datetime NOT NULL, + "invalid_time" datetime, + "delete_time" datetime, + "time_limited_discount" varchar(2000), + "full_privilege" varchar(2000), + "creator" varchar(64) DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint(20) NOT NULL, + PRIMARY KEY ("id") + ) COMMENT '促销活动'; \ No newline at end of file