秒杀活动增删改查

This commit is contained in:
halfninety 2022-11-28 20:45:54 +08:00
parent cd62c4d220
commit 7bc1ae5f35
19 changed files with 473 additions and 236 deletions

View File

@ -48,4 +48,9 @@ public interface ErrorCodeConstants {
// ========== 秒杀活动 1003008000 ==========
ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1003008000, "秒杀活动不存在");
ErrorCode SECKILL_TIME_NOT_EXISTS = new ErrorCode(1003008001, "秒杀时段不存在");
ErrorCode SECKILL_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1003008001, "存在商品参加了其它秒杀活动");
ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1003006002, "秒杀活动已关闭,不能修改");
ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1003006003, "秒杀活动未关闭,不能删除");
ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1003006004, "秒杀活动已关闭,不能重复关闭");
ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1003006004, "秒杀活动已结束,不能关闭");
}

View File

@ -1,35 +1,26 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.*;
import cn.iocoder.yudao.module.promotion.convert.seckillactivity.SeckillActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity.SeckillProductDO;
import cn.iocoder.yudao.module.promotion.service.seckillactivity.SeckillActivityService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
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.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.convert.seckillactivity.SeckillActivityConvert;
import cn.iocoder.yudao.module.promotion.service.seckillactivity.SeckillActivityService;
@Api(tags = "管理后台 - 秒杀活动")
@RestController
@RequestMapping("/promotion/seckill-activity")
@ -54,6 +45,15 @@ public class SeckillActivityController {
return success(true);
}
@PutMapping("/close")
@ApiOperation("关闭秒杀活动")
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('promotion:seckill-activity:close')")
public CommonResult<Boolean> closeSeckillActivity(@RequestParam("id") Long id) {
seckillActivityService.closeSeckillActivity(id);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除秒杀活动")
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
@ -67,12 +67,13 @@ public class SeckillActivityController {
@ApiOperation("获得秒杀活动")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
public CommonResult<SeckillActivityRespVO> getSeckillActivity(@RequestParam("id") Long id) {
public CommonResult<SeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
SeckillActivityDO seckillActivity = seckillActivityService.getSeckillActivity(id);
if (seckillActivity == null) {
return success(null);
}
return success(SeckillActivityConvert.INSTANCE.convert(seckillActivity));
List<SeckillProductDO> seckillProducts = seckillActivityService.getSeckillProductListByActivityId(id);
return success(SeckillActivityConvert.INSTANCE.convert(seckillActivity,seckillProducts));
}
@GetMapping("/list")
@ -92,16 +93,4 @@ public class SeckillActivityController {
return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult));
}
@GetMapping("/export-excel")
@ApiOperation("导出秒杀活动 Excel")
@PreAuthorize("@ss.hasPermission('promotion:seckill-activity:export')")
@OperateLog(type = EXPORT)
public void exportSeckillActivityExcel(@Valid SeckillActivityExportReqVO exportReqVO,
HttpServletResponse response) throws IOException {
List<SeckillActivityDO> list = seckillActivityService.getSeckillActivityList(exportReqVO);
// 导出 Excel
List<SeckillActivityExcelVO> datas = SeckillActivityConvert.INSTANCE.convertList02(list);
ExcelUtils.write(response, "秒杀活动.xls", "数据", SeckillActivityExcelVO.class, datas);
}
}

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.Min;
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;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
/**
* 秒杀活动 Base VO提供给添加修改详细的子 VO 使用
@ -20,22 +24,43 @@ public class SeckillActivityBaseVO {
@NotNull(message = "秒杀活动名称不能为空")
private String name;
@ApiModelProperty(value = "活动状态", required = true, example = "进行中")
@NotNull(message = "活动状态不能为空")
private Integer status;
@ApiModelProperty(value = "活动开始时间", required = true)
@NotNull(message = "活动开始时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date startTime;
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
private LocalDateTime startTime;
@ApiModelProperty(value = "活动结束时间", required = true)
@NotNull(message = "活动结束时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date endTime;
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
private LocalDateTime endTime;
@ApiModelProperty(value = "订单实付金额,单位:分", required = true)
@NotNull(message = "订单实付金额,单位:分不能为空")
private BigDecimal totalPrice;
@ApiModel("商品")
@Data
public static class Product {
@ApiModelProperty(value = "商品 SPU 编号", required = true, example = "1")
@NotNull(message = "商品 SPU 编号不能为空")
private Long spuId;
@ApiModelProperty(value = "商品 SKU 编号", required = true, example = "1")
@NotNull(message = "商品 SKU 编号不能为空")
private Long skuId;
@ApiModelProperty(value = "秒杀金额", required = true, example = "12.00")
@NotNull(message = "秒杀金额不能为空")
private Integer seckillPrice;
@ApiModelProperty(value = "秒杀库存", example = "80")
@Min(value = 0, message = "秒杀库存需要大于等于 0")
private Integer stock;
@ApiModelProperty(value = "每人限购", example = "10", notes = "如果为0则不限购")
@Min(value = 0, message = "每人限购需要大于等于 0")
private Integer limitBuyCount;
}
}

View File

@ -1,9 +1,16 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
@ApiModel("管理后台 - 秒杀活动创建 Request VO")
@Data
@ -19,7 +26,14 @@ public class SeckillActivityCreateReqVO extends SeckillActivityBaseVO {
private Integer sort;
@ApiModelProperty(value = "秒杀时段id", required = true)
@NotNull(message = "秒杀时段id不能为空")
@NotBlank(message = "参与场次不能为空")
private String timeId;
/**
* 商品列表
*/
@NotEmpty(message = "商品列表不能为空")
@Valid
private List<Product> products;
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.List;
@ApiModel("管理后台 - 秒杀活动的详细 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SeckillActivityDetailRespVO extends SeckillActivityRespVO{
/**
* 商品列表
*/
private List<Product> products;
}

View File

@ -1,46 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import io.swagger.annotations.*;
import com.alibaba.excel.annotation.ExcelProperty;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
/**
* 秒杀活动 Excel VO
*
* @author 芋道源码
*/
@Data
public class SeckillActivityExcelVO {
@ExcelProperty("秒杀活动名称")
private String name;
@ExcelProperty(value = "活动状态", converter = DictConvert.class)
@DictFormat("promotion_activity_status") // TODO 代码优化建议设置到对应的 XXXDictTypeConstants 枚举类中
private Integer status;
@ExcelProperty("活动开始时间")
private Date startTime;
@ExcelProperty("活动结束时间")
private Date endTime;
@ExcelProperty("付款订单数")
private Integer orderCount;
@ExcelProperty("付款人数")
private Integer userCount;
@ExcelProperty("订单实付金额,单位:分")
private BigDecimal totalPrice;
@ExcelProperty("创建时间")
private Date createTime;
}

View File

@ -1,28 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo;
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(value = "管理后台 - 秒杀活动 Excel 导出 Request VO", description = "参数和 SeckillActivityPageReqVO 是一致的")
@Data
public class SeckillActivityExportReqVO {
@ApiModelProperty(value = "秒杀活动名称", example = "晚九点限时秒杀")
private String name;
@ApiModelProperty(value = "活动状态", example = "进行中")
private Integer status;
@ApiModelProperty(value = "秒杀时段id")
private String timeId;
@ApiModelProperty(value = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] createTime;
}

View File

@ -1,12 +1,18 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
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;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
@ApiModel("管理后台 - 秒杀活动分页 Request VO")
@Data
@ -25,6 +31,7 @@ public class SeckillActivityPageReqVO extends PageParam {
@ApiModelProperty(value = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] createTime;
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
private LocalDateTime[] createTime;
}

View File

@ -1,10 +1,12 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
@ApiModel("管理后台 - 秒杀活动 Response VO")
@Data
@ -22,9 +24,18 @@ public class SeckillActivityRespVO extends SeckillActivityBaseVO {
private Integer userCount;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
private LocalDateTime createTime;
@ApiModelProperty(value = "秒杀时段id", required = true)
private String timeId;
@ApiModelProperty(value = "排序", required = true)
private Integer sort;
@ApiModelProperty(value = "备注", example = "限时秒杀活动")
private String remark;
@ApiModelProperty(value = "活动状态", example = "进行中")
private Integer status;
}

View File

@ -1,9 +1,15 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
@ApiModel("管理后台 - 秒杀活动更新 Request VO")
@Data
@ -26,4 +32,11 @@ public class SeckillActivityUpdateReqVO extends SeckillActivityBaseVO {
@NotNull(message = "秒杀时段id不能为空")
private String timeId;
/**
* 商品列表
*/
@NotEmpty(message = "商品列表不能为空")
@Valid
private List<Product> products;
}

View File

@ -1,13 +1,16 @@
package cn.iocoder.yudao.module.promotion.convert.seckillactivity;
import java.util.*;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity.SeckillProductDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 秒杀活动 Convert
@ -19,8 +22,15 @@ public interface SeckillActivityConvert {
SeckillActivityConvert INSTANCE = Mappers.getMapper(SeckillActivityConvert.class);
SeckillProductDO convert(SeckillActivityBaseVO.Product product);
SeckillActivityDO convert(SeckillActivityCreateReqVO bean);
default String map(Long[] value){
return value.toString();
}
SeckillActivityDO convert(SeckillActivityUpdateReqVO bean);
SeckillActivityRespVO convert(SeckillActivityDO bean);
@ -29,6 +39,39 @@ public interface SeckillActivityConvert {
PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page);
List<SeckillActivityExcelVO> convertList02(List<SeckillActivityDO> list);
@Mappings({@Mapping(target = "products",source = "seckillProducts")})
SeckillActivityDetailRespVO convert(SeckillActivityDO seckillActivity,List<SeckillProductDO> seckillProducts);
/**
* 比较两个秒杀商品对象是否相等
*
* @param productDO 数据库中的商品
* @param productVO 前端传入的商品
* @return 是否匹配
*/
default boolean isEquals(SeckillProductDO productDO, SeckillActivityBaseVO.Product productVO) {
return ObjectUtil.equals(productDO.getSpuId(), productVO.getSpuId())
&& ObjectUtil.equals(productDO.getSkuId(), productVO.getSkuId())
&& ObjectUtil.equals(productDO.getSeckillPrice(), productVO.getSeckillPrice())
&& ObjectUtil.equals(productDO.getStock(), productVO.getStock())
&& ObjectUtil.equals(productDO.getLimitBuyCount(), productVO.getLimitBuyCount());
}
/**
* 比较两个秒杀商品对象是否相等
*
* @param productDO 商品1
* @param productVO 商品2
* @return 是否匹配
*/
default boolean isEquals(SeckillProductDO productDO, SeckillProductDO productVO) {
return ObjectUtil.equals(productDO.getSpuId(), productVO.getSpuId())
&& ObjectUtil.equals(productDO.getSkuId(), productVO.getSkuId())
&& ObjectUtil.equals(productDO.getSeckillPrice(), productVO.getSeckillPrice())
&& ObjectUtil.equals(productDO.getStock(), productVO.getStock())
&& ObjectUtil.equals(productDO.getLimitBuyCount(), productVO.getLimitBuyCount());
}
}

View File

@ -1,10 +1,14 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 秒杀活动 DO
@ -33,7 +37,7 @@ public class SeckillActivityDO extends BaseDO {
/**
* 活动状态
*
* 枚举 {@link TODO promotion_activity_status 对应的类}
* 枚举 {@link PromotionActivityStatusEnum 对应的类}
*/
private Integer status;
/**
@ -43,11 +47,11 @@ public class SeckillActivityDO extends BaseDO {
/**
* 活动开始时间
*/
private Date startTime;
private LocalDateTime startTime;
/**
* 活动结束时间
*/
private Date endTime;
private LocalDateTime endTime;
/**
* 排序
*/

View File

@ -0,0 +1,60 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import lombok.Data;
/**
* 秒杀参与商品
* @TableName promotion_seckill_product
*/
@TableName(value ="promotion_seckill_product")
@Data
public class SeckillProductDO extends BaseDO {
/**
* 秒杀参与商品编号
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 秒杀活动id
*/
private Long activityId;
/**
* 秒杀时段id
*/
private Long timeId;
/**
* 商品id
*/
private Long spuId;
/**
* 商品sku_id
*/
private Long skuId;
/**
* 秒杀金额
*/
private Integer seckillPrice;
/**
* 秒杀库存
*/
private Integer stock;
/**
* 每人限购
*/
private Integer limitBuyCount;
}

View File

@ -1,13 +1,11 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.seckillactivity;
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.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.SeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity.SeckillActivityDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.*;
/**
* 秒杀活动 Mapper
@ -16,21 +14,13 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.*;
*/
@Mapper
public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
// TODO: 2022/11/28 halfninety 秒杀活动通过场次查询使用like会出现问题查询活动场次编号为1则活动场次编号为 111......的都会被查出来
default PageResult<SeckillActivityDO> selectPage(SeckillActivityPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<SeckillActivityDO>()
.likeIfPresent(SeckillActivityDO::getName, reqVO.getName())
.eqIfPresent(SeckillActivityDO::getStatus, reqVO.getStatus())
.eqIfPresent(SeckillActivityDO::getTimeId, reqVO.getTimeId())
.betweenIfPresent(SeckillActivityDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(SeckillActivityDO::getId));
}
default List<SeckillActivityDO> selectList(SeckillActivityExportReqVO reqVO) {
return selectList(new LambdaQueryWrapperX<SeckillActivityDO>()
.likeIfPresent(SeckillActivityDO::getName, reqVO.getName())
.eqIfPresent(SeckillActivityDO::getStatus, reqVO.getStatus())
.eqIfPresent(SeckillActivityDO::getTimeId, reqVO.getTimeId())
.likeIfPresent(SeckillActivityDO::getTimeId, reqVO.getTimeId())
// .like(StringUtils.hasText(reqVO.getTimeId()),SeckillActivityDO::getTimeId, reqVO.getTimeId() + ",")
.betweenIfPresent(SeckillActivityDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(SeckillActivityDO::getId));
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.seckillactivity;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity.SeckillProductDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
@Mapper
public interface SeckillProductMapper extends BaseMapperX<SeckillProductDO> {
default List<SeckillProductDO> selectListByActivityId(Long id){
return selectList(SeckillProductDO::getActivityId,id);
}
default List<SeckillProductDO> selectListBySkuIds(Collection<Long> skuIds){
return selectList(SeckillProductDO::getSkuId,skuIds);
}
}

View File

@ -5,6 +5,7 @@ import javax.validation.*;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity.SeckillActivityDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity.SeckillProductDO;
/**
* 秒杀活动 Service 接口
@ -28,6 +29,12 @@ public interface SeckillActivityService {
*/
void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO);
/**
* 关闭秒杀活动
* @param id 编号
*/
void closeSeckillActivity(Long id);
/**
* 删除秒杀活动
*
@ -60,11 +67,9 @@ public interface SeckillActivityService {
PageResult<SeckillActivityDO> getSeckillActivityPage(SeckillActivityPageReqVO pageReqVO);
/**
* 获得秒杀活动列表, 用于 Excel 导出
*
* @param exportReqVO 查询条件
* @return 秒杀活动列表
* 通过活动编号获取活动商品
* @param id 活动编号
* @return 活动商品列表
*/
List<SeckillActivityDO> getSeckillActivityList(SeckillActivityExportReqVO exportReqVO);
List<SeckillProductDO> getSeckillProductListByActivityId(Long id);
}

View File

@ -1,19 +1,29 @@
package cn.iocoder.yudao.module.promotion.service.seckillactivity;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.SeckillActivityBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.SeckillActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.SeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.SeckillActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.convert.seckillactivity.SeckillActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity.SeckillProductDO;
import cn.iocoder.yudao.module.promotion.dal.mysql.seckillactivity.SeckillActivityMapper;
import cn.iocoder.yudao.module.promotion.dal.mysql.seckillactivity.SeckillProductMapper;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import java.util.*;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity.SeckillActivityDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.convert.seckillactivity.SeckillActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.mysql.seckillactivity.SeckillActivityMapper;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
import static java.util.Arrays.asList;
/**
* 秒杀活动 Service 实现类
@ -27,11 +37,24 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
@Resource
private SeckillActivityMapper seckillActivityMapper;
@Resource
private SeckillProductMapper seckillProductMapper;
@Override
public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) {
// 插入
SeckillActivityDO seckillActivity = SeckillActivityConvert.INSTANCE.convert(createReqVO);
// validateSeckillActivityProductConflicts(null,createReqVO.getProducts());
List<Integer> statuses = asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus());
// 校验商品是否冲突
validateSeckillActivityProductConflicts(null, createReqVO.getProducts());
// 插入秒杀活动
SeckillActivityDO seckillActivity = SeckillActivityConvert.INSTANCE.convert(createReqVO)
.setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime()));;
seckillActivityMapper.insert(seckillActivity);
// 插入商品
List<SeckillProductDO> productDOS = CollectionUtils.convertList(createReqVO.getProducts(),
product -> SeckillActivityConvert.INSTANCE.convert(product).setActivityId(seckillActivity.getId()));
seckillProductMapper.insertBatch(productDOS);
// 返回
return seckillActivity.getId();
}
@ -39,24 +62,110 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
@Override
public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) {
// 校验存在
this.validateSeckillActivityExists(updateReqVO.getId());
// 更新
SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO);
SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(updateReqVO.getId());
if (PromotionActivityStatusEnum.CLOSE.getStatus().equals(seckillActivity.getStatus())) {
throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
}
List<Integer> statuses = asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus());
// 校验商品是否冲突
validateSeckillActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts());
// 更新活动
SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO)
.setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime()));
seckillActivityMapper.updateById(updateObj);
// 更新商品
updateSeckillProduct(updateReqVO);
}
/**
* 更新秒杀商品
*/
private void updateSeckillProduct(SeckillActivityUpdateReqVO updateReqVO) {
List<SeckillProductDO> seckillProductDOS = seckillProductMapper.selectListByActivityId(updateReqVO.getId());
List<SeckillActivityBaseVO.Product> products = updateReqVO.getProducts();
//对后台查出的数据和前台查出的数据进行遍历
//1.对前台数据进行遍历如果不存在于后台的sku中需要新增
//2.对后台数据进行遍历如果不存在于前台的sku中需要删除
//计算需要删除的数据
List<Long> deleteIds = CollectionUtils.convertList(seckillProductDOS, SeckillProductDO::getId,
seckillProductDO -> products.stream()
.noneMatch(product -> SeckillActivityConvert.INSTANCE.isEquals(seckillProductDO, product)));
if (CollUtil.isNotEmpty(deleteIds)) {
seckillProductMapper.deleteBatchIds(deleteIds);
}
//计算需要新增的数据
List<SeckillProductDO> newSeckillProductDOs = CollectionUtils.convertList(products,
product -> SeckillActivityConvert.INSTANCE.convert(product).setActivityId(updateReqVO.getId()));
newSeckillProductDOs.removeIf(product -> seckillProductDOS.stream()
.anyMatch(seckillProduct -> SeckillActivityConvert.INSTANCE.isEquals(seckillProduct, product)));
if (CollUtil.isNotEmpty(newSeckillProductDOs)) {
seckillProductMapper.insertBatch(newSeckillProductDOs);
}
}
/**
* 校验商品是否冲突
*
* @param id 秒杀活动编号
* @param products 商品列表
*/
public void validateSeckillActivityProductConflicts(Long id, List<SeckillActivityBaseVO.Product> products) {
if (CollUtil.isEmpty(products)) {
return;
}
List<SeckillProductDO> seckillProductDOS = seckillProductMapper
.selectListBySkuIds(CollectionUtils.convertSet(products, SeckillActivityBaseVO.Product::getSkuId));
if (CollUtil.isEmpty(seckillProductDOS)) {
return;
}
List<SeckillActivityDO> seckillActivityDOS = seckillActivityMapper
.selectBatchIds(CollectionUtils.convertSet(seckillProductDOS, SeckillProductDO::getActivityId));
if (id != null) {// 排除自己这个活动
seckillActivityDOS.removeIf(item -> id.equals(item.getId()));
}
// 排除不满足status的活动
List<Integer> statuses = asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus());
seckillActivityDOS.removeIf(item -> !statuses.contains(item.getStatus()));
//如果非空则说明冲突
if (CollUtil.isNotEmpty(seckillActivityDOS)) {
throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
}
}
@Override
public void closeSeckillActivity(Long id) {
// 校验存在
SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id);
if (PromotionActivityStatusEnum.CLOSE.getStatus().equals(seckillActivity.getStatus())) {
throw exception(SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED);
}
if (PromotionActivityStatusEnum.END.getStatus().equals(seckillActivity.getStatus())) {
throw exception(SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_END);
}
// 更新
SeckillActivityDO updateObj = new SeckillActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus());
seckillActivityMapper.updateById(updateObj);
}
@Override
public void deleteSeckillActivity(Long id) {
// 校验存在
this.validateSeckillActivityExists(id);
SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id);
if (!PromotionActivityStatusEnum.CLOSE.getStatus().equals(seckillActivity.getStatus())) {
throw exception(SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED);
}
// 删除
seckillActivityMapper.deleteById(id);
}
private void validateSeckillActivityExists(Long id) {
if (seckillActivityMapper.selectById(id) == null) {
private SeckillActivityDO validateSeckillActivityExists(Long id) {
SeckillActivityDO seckillActivity = seckillActivityMapper.selectById(id);
if (seckillActivity == null) {
throw exception(SECKILL_ACTIVITY_NOT_EXISTS);
}
return seckillActivity;
}
@Override
@ -75,8 +184,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
}
@Override
public List<SeckillActivityDO> getSeckillActivityList(SeckillActivityExportReqVO exportReqVO) {
return seckillActivityMapper.selectList(exportReqVO);
public List<SeckillProductDO> getSeckillProductListByActivityId(Long id) {
return seckillProductMapper.selectListByActivityId(id);
}
}

View File

@ -1,30 +1,26 @@
package cn.iocoder.yudao.module.promotion.service.seckillactivity;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import javax.annotation.Resource;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.*;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.SeckillActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.SeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckillactivity.vo.SeckillActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckillactivity.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.mysql.seckillactivity.SeckillActivityMapper;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import org.springframework.context.annotation.Import;
import java.util.*;
import java.time.LocalDateTime;
import static cn.hutool.core.util.RandomUtil.*;
import static cn.iocoder.yudao.module.promotion.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 cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_NOT_EXISTS;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
/**
* {@link SeckillActivityServiceImpl} 的单元测试类
@ -127,7 +123,7 @@ public class SeckillActivityServiceImplTest extends BaseDbUnitTest {
reqVO.setName(null);
reqVO.setStatus(null);
reqVO.setTimeId(null);
reqVO.setCreateTime((new Date[]{}));
reqVO.setCreateTime((new LocalDateTime[]{}));
// 调用
PageResult<SeckillActivityDO> pageResult = seckillActivityService.getSeckillActivityPage(reqVO);
@ -157,17 +153,17 @@ public class SeckillActivityServiceImplTest extends BaseDbUnitTest {
// 测试 createTime 不匹配
seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setCreateTime(null)));
// 准备参数
SeckillActivityExportReqVO reqVO = new SeckillActivityExportReqVO();
reqVO.setName(null);
reqVO.setStatus(null);
reqVO.setTimeId(null);
reqVO.setCreateTime((new Date[]{}));
// 调用
List<SeckillActivityDO> list = seckillActivityService.getSeckillActivityList(reqVO);
// 断言
assertEquals(1, list.size());
assertPojoEquals(dbSeckillActivity, list.get(0));
// SeckillActivityExportReqVO reqVO = new SeckillActivityExportReqVO();
// reqVO.setName(null);
// reqVO.setStatus(null);
// reqVO.setTimeId(null);
// reqVO.setCreateTime((new Date[]{}));
//
// // 调用
// List<SeckillActivityDO> list = seckillActivityService.getSeckillActivityList(reqVO);
// // 断言
// assertEquals(1, list.size());
// assertPojoEquals(dbSeckillActivity, list.get(0));
}
}

View File

@ -18,6 +18,14 @@ export function updateSeckillActivity(data) {
})
}
// 关闭限时折扣活动
export function closeSeckillActivity(id) {
return request({
url: '/promotion/seckill-activity/close?id=' + id,
method: 'put'
})
}
// 删除秒杀活动
export function deleteSeckillActivity(id) {
return request({
@ -42,13 +50,3 @@ export function getSeckillActivityPage(query) {
params: query
})
}
// 导出秒杀活动 Excel
export function exportSeckillActivityExcel(query) {
return request({
url: '/promotion/seckill-activity/export-excel',
method: 'get',
params: query,
responseType: 'blob'
})
}