Commit aee5f39a77a59eee0722ac09dc15cf60c817cb3c

Authored by 芋道源码
Committed by Gitee
2 parents 7056d89b d6b42697

!315 秒杀活动相关

Merge pull request !315 from halfninety/feature/1.8.0-uniapp
Showing 38 changed files with 2666 additions and 2 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java
... ... @@ -25,6 +25,8 @@ public class DateUtils {
25 25  
26 26 public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";
27 27  
  28 + public static final String FORMAT_HOUR_MINUTE_SECOND = "HH:mm:ss";
  29 +
28 30 /**
29 31 * 将 LocalDateTime 转换成 Date
30 32 *
... ...
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java
1 1 package cn.iocoder.yudao.framework.jackson.config;
2 2  
  3 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
3 4 import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeDeserializer;
4 5 import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeSerializer;
5   -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  6 +import cn.iocoder.yudao.framework.jackson.core.databind.LocalTimeJson;
6 7 import com.fasterxml.jackson.databind.ObjectMapper;
7 8 import com.fasterxml.jackson.databind.module.SimpleModule;
8 9 import lombok.extern.slf4j.Slf4j;
... ... @@ -12,6 +13,7 @@ import org.springframework.context.annotation.Bean;
12 13 import org.springframework.context.annotation.Configuration;
13 14  
14 15 import java.time.LocalDateTime;
  16 +import java.time.LocalTime;
15 17  
16 18 @Configuration(proxyBeanMethods = false)
17 19 @Slf4j
... ... @@ -30,12 +32,15 @@ public class YudaoJacksonAutoConfiguration {
30 32 /*
31 33 * 1. 新增Long类型序列化规则,数值超过2^53-1,在JS会出现精度丢失问题,因此Long自动序列化为字符串类型
32 34 * 2. 新增LocalDateTime序列化、反序列化规则
  35 + * 3. 新增LocalTime序列化、反序列化规则
33 36 */
34 37 simpleModule
35 38 // .addSerializer(Long.class, ToStringSerializer.instance)
36 39 // .addSerializer(Long.TYPE, ToStringSerializer.instance)
37 40 .addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE)
38   - .addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);
  41 + .addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE)
  42 + .addSerializer(LocalTime.class, LocalTimeJson.SERIALIZER)
  43 + .addDeserializer(LocalTime.class, LocalTimeJson.DESERIALIZABLE);
39 44  
40 45 objectMapper.registerModules(simpleModule);
41 46  
... ...
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/LocalTimeJson.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.jackson.core.databind;
  2 +
  3 +import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
  4 +import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
  5 +
  6 +import java.time.ZoneId;
  7 +import java.time.format.DateTimeFormatter;
  8 +
  9 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_HOUR_MINUTE_SECOND;
  10 +
  11 +public class LocalTimeJson {
  12 +
  13 + public static final LocalTimeSerializer SERIALIZER = new LocalTimeSerializer(DateTimeFormatter
  14 + .ofPattern(FORMAT_HOUR_MINUTE_SECOND)
  15 + .withZone(ZoneId.systemDefault()));
  16 +
  17 + public static final LocalTimeDeserializer DESERIALIZABLE = new LocalTimeDeserializer(DateTimeFormatter
  18 + .ofPattern(FORMAT_HOUR_MINUTE_SECOND)
  19 + .withZone(ZoneId.systemDefault()));
  20 +
  21 +}
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
... ... @@ -45,4 +45,16 @@ public interface ErrorCodeConstants {
45 45 // ========== Price 相关 1003007000 ============
46 46 ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1003007000, "支付价格计算异常,原因:价格小于等于 0");
47 47  
  48 + // ========== 秒杀活动 1003008000 ==========
  49 + ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1003008000, "秒杀活动不存在");
  50 + ErrorCode SECKILL_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1003008002, "存在商品参加了其它秒杀活动");
  51 + ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1003008003, "秒杀活动已关闭,不能修改");
  52 + ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1003008004, "秒杀活动未关闭或未结束,不能删除");
  53 + ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1003008005, "秒杀活动已关闭,不能重复关闭");
  54 + ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1003008006, "秒杀活动已结束,不能关闭");
  55 +
  56 + // ========== 秒杀时段 1003009000 ==========
  57 + ErrorCode SECKILL_TIME_NOT_EXISTS = new ErrorCode(1003009000, "秒杀时段不存在");
  58 + ErrorCode SECKILL_TIME_CONFLICTS = new ErrorCode(1003009001, "秒杀时段冲突");
  59 +
48 60 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckillactivity/SeckillActivityController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo.*;
  6 +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
  8 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
  9 +import cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity.SeckillActivityService;
  10 +import io.swagger.annotations.Api;
  11 +import io.swagger.annotations.ApiImplicitParam;
  12 +import io.swagger.annotations.ApiOperation;
  13 +import org.springframework.security.access.prepost.PreAuthorize;
  14 +import org.springframework.validation.annotation.Validated;
  15 +import org.springframework.web.bind.annotation.*;
  16 +
  17 +import javax.annotation.Resource;
  18 +import javax.validation.Valid;
  19 +import java.util.Collection;
  20 +import java.util.List;
  21 +
  22 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  23 +
  24 +@Api(tags = "管理后台 - 秒杀活动")
  25 +@RestController
  26 +@RequestMapping("/promotion/seckill-activity")
  27 +@Validated
  28 +public class SeckillActivityController {
  29 +
  30 + @Resource
  31 + private SeckillActivityService seckillActivityService;
  32 +
  33 + @PostMapping("/create")
  34 + @ApiOperation("创建秒杀活动")
  35 + @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:create')")
  36 + public CommonResult<Long> createSeckillActivity(@Valid @RequestBody SeckillActivityCreateReqVO createReqVO) {
  37 + return success(seckillActivityService.createSeckillActivity(createReqVO));
  38 + }
  39 +
  40 + @PutMapping("/update")
  41 + @ApiOperation("更新秒杀活动")
  42 + @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:update')")
  43 + public CommonResult<Boolean> updateSeckillActivity(@Valid @RequestBody SeckillActivityUpdateReqVO updateReqVO) {
  44 + seckillActivityService.updateSeckillActivity(updateReqVO);
  45 + return success(true);
  46 + }
  47 +
  48 + @PutMapping("/close")
  49 + @ApiOperation("关闭秒杀活动")
  50 + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
  51 + @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:close')")
  52 + public CommonResult<Boolean> closeSeckillActivity(@RequestParam("id") Long id) {
  53 + seckillActivityService.closeSeckillActivity(id);
  54 + return success(true);
  55 + }
  56 +
  57 + @DeleteMapping("/delete")
  58 + @ApiOperation("删除秒杀活动")
  59 + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
  60 + @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:delete')")
  61 + public CommonResult<Boolean> deleteSeckillActivity(@RequestParam("id") Long id) {
  62 + seckillActivityService.deleteSeckillActivity(id);
  63 + return success(true);
  64 + }
  65 +
  66 + @GetMapping("/get")
  67 + @ApiOperation("获得秒杀活动")
  68 + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
  69 + @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
  70 + public CommonResult<SeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
  71 + SeckillActivityDO seckillActivity = seckillActivityService.getSeckillActivity(id);
  72 + if (seckillActivity == null) {
  73 + return success(null);
  74 + }
  75 + List<SeckillProductDO> seckillProducts = seckillActivityService.getSeckillProductListByActivityId(id);
  76 + return success(SeckillActivityConvert.INSTANCE.convert(seckillActivity,seckillProducts));
  77 + }
  78 +
  79 + @GetMapping("/list")
  80 + @ApiOperation("获得秒杀活动列表")
  81 + @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
  82 + @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
  83 + public CommonResult<List<SeckillActivityRespVO>> getSeckillActivityList(@RequestParam("ids") Collection<Long> ids) {
  84 + List<SeckillActivityDO> list = seckillActivityService.getSeckillActivityList(ids);
  85 + return success(SeckillActivityConvert.INSTANCE.convertList(list));
  86 + }
  87 +
  88 + @GetMapping("/page")
  89 + @ApiOperation("获得秒杀活动分页")
  90 + @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
  91 + public CommonResult<PageResult<SeckillActivityRespVO>> getSeckillActivityPage(@Valid SeckillActivityPageReqVO pageVO) {
  92 + PageResult<SeckillActivityDO> pageResult = seckillActivityService.getSeckillActivityPage(pageVO);
  93 + return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult));
  94 + }
  95 +
  96 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckillactivity/vo/SeckillActivityBaseVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonFormat;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +
  9 +import javax.validation.constraints.Min;
  10 +import javax.validation.constraints.NotNull;
  11 +import java.time.LocalDateTime;
  12 +
  13 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  14 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
  15 +
  16 +/**
  17 +* 秒杀活动 Base VO,提供给添加、修改、详细的子 VO 使用
  18 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  19 +*/
  20 +@Data
  21 +public class SeckillActivityBaseVO {
  22 +
  23 + @ApiModelProperty(value = "秒杀活动名称", required = true, example = "晚九点限时秒杀")
  24 + @NotNull(message = "秒杀活动名称不能为空")
  25 + private String name;
  26 +
  27 + @ApiModelProperty(value = "活动开始时间", required = true)
  28 + @NotNull(message = "活动开始时间不能为空")
  29 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  30 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
  31 + private LocalDateTime startTime;
  32 +
  33 + @ApiModelProperty(value = "活动结束时间", required = true)
  34 + @NotNull(message = "活动结束时间不能为空")
  35 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  36 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
  37 + private LocalDateTime endTime;
  38 +
  39 +
  40 + @ApiModel("商品")
  41 + @Data
  42 + public static class Product {
  43 +
  44 + @ApiModelProperty(value = "商品 SPU 编号", required = true, example = "1")
  45 + @NotNull(message = "商品 SPU 编号不能为空")
  46 + private Long spuId;
  47 +
  48 + @ApiModelProperty(value = "商品 SKU 编号", required = true, example = "1")
  49 + @NotNull(message = "商品 SKU 编号不能为空")
  50 + private Long skuId;
  51 +
  52 + @ApiModelProperty(value = "秒杀金额", required = true, example = "12.00")
  53 + @NotNull(message = "秒杀金额不能为空")
  54 + private Integer seckillPrice;
  55 +
  56 + @ApiModelProperty(value = "秒杀库存", example = "80")
  57 + @Min(value = 0, message = "秒杀库存需要大于等于 0")
  58 + private Integer stock;
  59 +
  60 + @ApiModelProperty(value = "每人限购", example = "10", notes = "如果为0则不限购")
  61 + @Min(value = 0, message = "每人限购需要大于等于 0")
  62 + private Integer limitBuyCount;
  63 +
  64 + }
  65 +
  66 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckillactivity/vo/SeckillActivityCreateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import javax.validation.Valid;
  10 +import javax.validation.constraints.NotBlank;
  11 +import javax.validation.constraints.NotEmpty;
  12 +import javax.validation.constraints.NotNull;
  13 +import java.util.List;
  14 +
  15 +@ApiModel("管理后台 - 秒杀活动创建 Request VO")
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +public class SeckillActivityCreateReqVO extends SeckillActivityBaseVO {
  20 +
  21 + @ApiModelProperty(value = "备注", example = "限时秒杀活动")
  22 + private String remark;
  23 +
  24 + @ApiModelProperty(value = "排序", required = true)
  25 + @NotNull(message = "排序不能为空")
  26 + private Integer sort;
  27 +
  28 + @ApiModelProperty(value = "秒杀时段id", required = true)
  29 + @NotBlank(message = "参与场次不能为空")
  30 + private String timeId;
  31 +
  32 + /**
  33 + * 商品列表
  34 + */
  35 + @NotEmpty(message = "商品列表不能为空")
  36 + @Valid
  37 + private List<Product> products;
  38 +
  39 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckillactivity/vo/SeckillActivityDetailRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +import java.util.List;
  9 +
  10 +@ApiModel("管理后台 - 秒杀活动的详细 Response VO")
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ToString(callSuper = true)
  14 +public class SeckillActivityDetailRespVO extends SeckillActivityRespVO{
  15 +
  16 + /**
  17 + * 商品列表
  18 + */
  19 + private List<Product> products;
  20 +
  21 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckillactivity/vo/SeckillActivityPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import com.fasterxml.jackson.annotation.JsonFormat;
  5 +import io.swagger.annotations.ApiModel;
  6 +import io.swagger.annotations.ApiModelProperty;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import lombok.ToString;
  10 +import org.springframework.format.annotation.DateTimeFormat;
  11 +
  12 +import java.time.LocalDateTime;
  13 +
  14 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  15 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
  16 +
  17 +@ApiModel("管理后台 - 秒杀活动分页 Request VO")
  18 +@Data
  19 +@EqualsAndHashCode(callSuper = true)
  20 +@ToString(callSuper = true)
  21 +public class SeckillActivityPageReqVO extends PageParam {
  22 +
  23 + @ApiModelProperty(value = "秒杀活动名称", example = "晚九点限时秒杀")
  24 + private String name;
  25 +
  26 + @ApiModelProperty(value = "活动状态", example = "进行中")
  27 + private Integer status;
  28 +
  29 + @ApiModelProperty(value = "秒杀时段id")
  30 + private String timeId;
  31 +
  32 + @ApiModelProperty(value = "创建时间")
  33 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  34 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
  35 + private LocalDateTime[] createTime;
  36 +
  37 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckillactivity/vo/SeckillActivityRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import java.time.LocalDateTime;
  10 +
  11 +@ApiModel("管理后台 - 秒杀活动 Response VO")
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@ToString(callSuper = true)
  15 +public class SeckillActivityRespVO extends SeckillActivityBaseVO {
  16 +
  17 + @ApiModelProperty(value = "秒杀活动id", required = true, example = "1")
  18 + private Long id;
  19 +
  20 + @ApiModelProperty(value = "付款订单数", required = true)
  21 + private Integer orderCount;
  22 +
  23 + @ApiModelProperty(value = "付款人数", required = true)
  24 + private Integer userCount;
  25 +
  26 + @ApiModelProperty(value = "创建时间", required = true)
  27 + private LocalDateTime createTime;
  28 +
  29 + @ApiModelProperty(value = "秒杀时段id", required = true)
  30 + private String timeId;
  31 +
  32 + @ApiModelProperty(value = "排序", required = true)
  33 + private Integer sort;
  34 +
  35 + @ApiModelProperty(value = "备注", example = "限时秒杀活动")
  36 + private String remark;
  37 +
  38 + @ApiModelProperty(value = "活动状态", example = "进行中")
  39 + private Integer status;
  40 +
  41 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckillactivity/vo/SeckillActivityUpdateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import javax.validation.Valid;
  10 +import javax.validation.constraints.NotEmpty;
  11 +import javax.validation.constraints.NotNull;
  12 +import java.util.List;
  13 +
  14 +@ApiModel("管理后台 - 秒杀活动更新 Request VO")
  15 +@Data
  16 +@EqualsAndHashCode(callSuper = true)
  17 +@ToString(callSuper = true)
  18 +public class SeckillActivityUpdateReqVO extends SeckillActivityBaseVO {
  19 +
  20 + @ApiModelProperty(value = "秒杀活动编号", required = true, example = "224")
  21 + @NotNull(message = "秒杀活动编号不能为空")
  22 + private Long id;
  23 +
  24 + @ApiModelProperty(value = "备注", example = "限时秒杀活动")
  25 + private String remark;
  26 +
  27 + @ApiModelProperty(value = "排序", required = true)
  28 + @NotNull(message = "排序不能为空")
  29 + private Integer sort;
  30 +
  31 + @ApiModelProperty(value = "秒杀时段id", required = true)
  32 + @NotNull(message = "秒杀时段id不能为空")
  33 + private String timeId;
  34 +
  35 + /**
  36 + * 商品列表
  37 + */
  38 + @NotEmpty(message = "商品列表不能为空")
  39 + @Valid
  40 + private List<Product> products;
  41 +
  42 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckilltime/SeckillTimeController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo.SeckillTimeCreateReqVO;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo.SeckillTimeRespVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo.SeckillTimeUpdateReqVO;
  7 +import cn.iocoder.yudao.module.promotion.convert.seckill.seckilltime.SeckillTimeConvert;
  8 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckilltime.SeckillTimeDO;
  9 +import cn.iocoder.yudao.module.promotion.service.seckill.seckilltime.SeckillTimeService;
  10 +import io.swagger.annotations.Api;
  11 +import io.swagger.annotations.ApiImplicitParam;
  12 +import io.swagger.annotations.ApiOperation;
  13 +import org.springframework.security.access.prepost.PreAuthorize;
  14 +import org.springframework.validation.annotation.Validated;
  15 +import org.springframework.web.bind.annotation.*;
  16 +
  17 +import javax.annotation.Resource;
  18 +import javax.validation.Valid;
  19 +import java.util.List;
  20 +
  21 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  22 +
  23 +@Api(tags = "管理后台 - 秒杀时段")
  24 +@RestController
  25 +@RequestMapping("/promotion/seckill-time")
  26 +@Validated
  27 +public class SeckillTimeController {
  28 +
  29 + @Resource
  30 + private SeckillTimeService seckillTimeService;
  31 +
  32 + @PostMapping("/create")
  33 + @ApiOperation("创建秒杀时段")
  34 + @PreAuthorize("@ss.hasPermission('promotion:seckill-time:create')")
  35 + public CommonResult<Long> createSeckillTime(@Valid @RequestBody SeckillTimeCreateReqVO createReqVO) {
  36 + return success(seckillTimeService.createSeckillTime(createReqVO));
  37 + }
  38 +
  39 + @PutMapping("/update")
  40 + @ApiOperation("更新秒杀时段")
  41 + @PreAuthorize("@ss.hasPermission('promotion:seckill-time:update')")
  42 + public CommonResult<Boolean> updateSeckillTime(@Valid @RequestBody SeckillTimeUpdateReqVO updateReqVO) {
  43 + seckillTimeService.updateSeckillTime(updateReqVO);
  44 + return success(true);
  45 + }
  46 +
  47 + @DeleteMapping("/delete")
  48 + @ApiOperation("删除秒杀时段")
  49 + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
  50 + @PreAuthorize("@ss.hasPermission('promotion:seckill-time:delete')")
  51 + public CommonResult<Boolean> deleteSeckillTime(@RequestParam("id") Long id) {
  52 + seckillTimeService.deleteSeckillTime(id);
  53 + return success(true);
  54 + }
  55 +
  56 + @GetMapping("/get")
  57 + @ApiOperation("获得秒杀时段")
  58 + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
  59 + @PreAuthorize("@ss.hasPermission('promotion:seckill-time:query')")
  60 + public CommonResult<SeckillTimeRespVO> getSeckillTime(@RequestParam("id") Long id) {
  61 + SeckillTimeDO seckillTime = seckillTimeService.getSeckillTime(id);
  62 + return success(SeckillTimeConvert.INSTANCE.convert(seckillTime));
  63 + }
  64 +
  65 + @GetMapping("/list")
  66 + @ApiOperation("获得所有秒杀时段列表")
  67 +// @PreAuthorize("@ss.hasPermission('promotion:seckill-time:query')")
  68 + public CommonResult<List<SeckillTimeRespVO>> getSeckillTimeList() {
  69 + List<SeckillTimeDO> list = seckillTimeService.getSeckillTimeList();
  70 + return success(SeckillTimeConvert.INSTANCE.convertList(list));
  71 + }
  72 +
  73 +// @GetMapping("/page")
  74 +// @ApiOperation("获得秒杀时段分页")
  75 +// @PreAuthorize("@ss.hasPermission('promotion:seckill-time:query')")
  76 +// public CommonResult<PageResult<SeckillTimeRespVO>> getSeckillTimePage(@Valid SeckillTimePageReqVO pageVO) {
  77 +// PageResult<SeckillTimeDO> pageResult = seckillTimeService.getSeckillTimePage(pageVO);
  78 +// return success(SeckillTimeConvert.INSTANCE.convertPage(pageResult));
  79 +// }
  80 +
  81 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckilltime/vo/SeckillTimeBaseVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo;
  2 +
  3 +import lombok.*;
  4 +
  5 +import java.time.LocalTime;
  6 +import java.util.*;
  7 +import io.swagger.annotations.*;
  8 +import javax.validation.constraints.*;
  9 +import org.springframework.format.annotation.DateTimeFormat;
  10 +
  11 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  12 +
  13 +/**
  14 +* 秒杀时段 Base VO,提供给添加、修改、详细的子 VO 使用
  15 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  16 +*/
  17 +@Data
  18 +public class SeckillTimeBaseVO {
  19 +
  20 + @ApiModelProperty(value = "秒杀时段名称", required = true)
  21 + @NotNull(message = "秒杀时段名称不能为空")
  22 + private String name;
  23 +
  24 + @ApiModelProperty(value = "开始时间点", required = true)
  25 + @NotNull(message = "开始时间点不能为空")
  26 + private LocalTime startTime;
  27 +
  28 + @ApiModelProperty(value = "结束时间点", required = true)
  29 + @NotNull(message = "结束时间点不能为空")
  30 + private LocalTime endTime;
  31 +
  32 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckilltime/vo/SeckillTimeCreateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo;
  2 +
  3 +import lombok.*;
  4 +import io.swagger.annotations.*;
  5 +
  6 +@ApiModel("管理后台 - 秒杀时段创建 Request VO")
  7 +@Data
  8 +@EqualsAndHashCode(callSuper = true)
  9 +@ToString(callSuper = true)
  10 +public class SeckillTimeCreateReqVO extends SeckillTimeBaseVO {
  11 +
  12 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckilltime/vo/SeckillTimePageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +import org.springframework.format.annotation.DateTimeFormat;
  10 +
  11 +import java.time.LocalTime;
  12 +
  13 +@ApiModel("管理后台 - 秒杀时段分页 Request VO")
  14 +@Data
  15 +@EqualsAndHashCode(callSuper = true)
  16 +@ToString(callSuper = true)
  17 +public class SeckillTimePageReqVO extends PageParam {
  18 +
  19 + @ApiModelProperty(value = "秒杀时段名称")
  20 + private String name;
  21 +
  22 + @ApiModelProperty(value = "开始时间点")
  23 + @DateTimeFormat(pattern = "HH:mm:ss")
  24 + private LocalTime startTime;
  25 +
  26 + @ApiModelProperty(value = "结束时间点")
  27 + @DateTimeFormat(pattern = "HH:mm:ss")
  28 + private LocalTime endTime;
  29 +
  30 +
  31 +
  32 +
  33 +
  34 +
  35 +
  36 +// @ApiModelProperty(value = "创建时间")
  37 +// @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  38 +// private Date[] createTime;
  39 +
  40 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckilltime/vo/SeckillTimeRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.annotations.*;
  6 +
  7 +@ApiModel("管理后台 - 秒杀时段 Response VO")
  8 +@Data
  9 +@EqualsAndHashCode(callSuper = true)
  10 +@ToString(callSuper = true)
  11 +public class SeckillTimeRespVO extends SeckillTimeBaseVO {
  12 +
  13 + @ApiModelProperty(value = "编号", required = true)
  14 + private Long id;
  15 +
  16 + @ApiModelProperty(value = "秒杀活动数量", required = true)
  17 + private Integer seckillActivityCount;
  18 +
  19 + @ApiModelProperty(value = "创建时间", required = true)
  20 + private Date createTime;
  21 +
  22 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckilltime/vo/SeckillTimeSimpleRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo;
  2 +
  3 +public class SeckillTimeSimpleRespVO {
  4 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/seckilltime/vo/SeckillTimeUpdateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import javax.validation.constraints.NotNull;
  10 +
  11 +@ApiModel("管理后台 - 秒杀时段更新 Request VO")
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@ToString(callSuper = true)
  15 +public class SeckillTimeUpdateReqVO extends SeckillTimeBaseVO {
  16 +
  17 + @ApiModelProperty(value = "编号", required = true)
  18 + @NotNull(message = "编号不能为空")
  19 + private Long id;
  20 +
  21 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo.*;
  6 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
  8 +import org.mapstruct.Mapper;
  9 +import org.mapstruct.Mapping;
  10 +import org.mapstruct.Mappings;
  11 +import org.mapstruct.factory.Mappers;
  12 +
  13 +import java.util.List;
  14 +
  15 +/**
  16 + * 秒杀活动 Convert
  17 + *
  18 + * @author 芋道源码
  19 + */
  20 +@Mapper
  21 +public interface SeckillActivityConvert {
  22 +
  23 + SeckillActivityConvert INSTANCE = Mappers.getMapper(SeckillActivityConvert.class);
  24 +
  25 + SeckillProductDO convert(SeckillActivityBaseVO.Product product);
  26 +
  27 +
  28 + SeckillActivityDO convert(SeckillActivityCreateReqVO bean);
  29 +
  30 + default String map(Long[] value){
  31 + return value.toString();
  32 + }
  33 +
  34 + SeckillActivityDO convert(SeckillActivityUpdateReqVO bean);
  35 +
  36 + SeckillActivityRespVO convert(SeckillActivityDO bean);
  37 +
  38 + List<SeckillActivityRespVO> convertList(List<SeckillActivityDO> list);
  39 +
  40 + PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page);
  41 +
  42 + @Mappings({@Mapping(target = "products",source = "seckillProducts")})
  43 + SeckillActivityDetailRespVO convert(SeckillActivityDO seckillActivity, List<SeckillProductDO> seckillProducts);
  44 +
  45 +
  46 + /**
  47 + * 比较两个秒杀商品对象是否相等
  48 + *
  49 + * @param productDO 数据库中的商品
  50 + * @param productVO 前端传入的商品
  51 + * @return 是否匹配
  52 + */
  53 + default boolean isEquals(SeckillProductDO productDO, SeckillActivityBaseVO.Product productVO) {
  54 + return ObjectUtil.equals(productDO.getSpuId(), productVO.getSpuId())
  55 + && ObjectUtil.equals(productDO.getSkuId(), productVO.getSkuId())
  56 + && ObjectUtil.equals(productDO.getSeckillPrice(), productVO.getSeckillPrice())
  57 + && ObjectUtil.equals(productDO.getStock(), productVO.getStock())
  58 + && ObjectUtil.equals(productDO.getLimitBuyCount(), productVO.getLimitBuyCount());
  59 +
  60 + }
  61 +
  62 + /**
  63 + * 比较两个秒杀商品对象是否相等
  64 + *
  65 + * @param productDO 商品1
  66 + * @param productVO 商品2
  67 + * @return 是否匹配
  68 + */
  69 + default boolean isEquals(SeckillProductDO productDO, SeckillProductDO productVO) {
  70 + return ObjectUtil.equals(productDO.getSpuId(), productVO.getSpuId())
  71 + && ObjectUtil.equals(productDO.getSkuId(), productVO.getSkuId())
  72 + && ObjectUtil.equals(productDO.getSeckillPrice(), productVO.getSeckillPrice())
  73 + && ObjectUtil.equals(productDO.getStock(), productVO.getStock())
  74 + && ObjectUtil.equals(productDO.getLimitBuyCount(), productVO.getLimitBuyCount());
  75 +
  76 + }
  77 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckilltime/SeckillTimeConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.convert.seckill.seckilltime;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +
  7 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo.SeckillTimeCreateReqVO;
  8 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo.SeckillTimeRespVO;
  9 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo.SeckillTimeUpdateReqVO;
  10 +import org.mapstruct.Mapper;
  11 +import org.mapstruct.factory.Mappers;
  12 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckilltime.SeckillTimeDO;
  13 +
  14 +/**
  15 + * 秒杀时段 Convert
  16 + *
  17 + * @author 芋道源码
  18 + */
  19 +@Mapper
  20 +public interface SeckillTimeConvert {
  21 +
  22 + SeckillTimeConvert INSTANCE = Mappers.getMapper(SeckillTimeConvert.class);
  23 +
  24 + SeckillTimeDO convert(SeckillTimeCreateReqVO bean);
  25 +
  26 + SeckillTimeDO convert(SeckillTimeUpdateReqVO bean);
  27 +
  28 + SeckillTimeRespVO convert(SeckillTimeDO bean);
  29 +
  30 + List<SeckillTimeRespVO> convertList(List<SeckillTimeDO> list);
  31 +
  32 + PageResult<SeckillTimeRespVO> convertPage(PageResult<SeckillTimeDO> page);
  33 +
  34 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillActivityDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
  5 +import com.baomidou.mybatisplus.annotation.TableId;
  6 +import com.baomidou.mybatisplus.annotation.TableName;
  7 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
  8 +import lombok.*;
  9 +
  10 +import java.math.BigDecimal;
  11 +import java.time.LocalDateTime;
  12 +
  13 +/**
  14 + * 秒杀活动 DO
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@TableName("promotion_seckill_activity")
  19 +@KeySequence("promotion_seckill_activity_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  20 +@Data
  21 +@EqualsAndHashCode(callSuper = true)
  22 +@ToString(callSuper = true)
  23 +@Builder
  24 +@NoArgsConstructor
  25 +@AllArgsConstructor
  26 +public class SeckillActivityDO extends BaseDO {
  27 +
  28 + /**
  29 + * 秒杀活动编号
  30 + */
  31 + @TableId
  32 + private Long id;
  33 + /**
  34 + * 秒杀活动名称
  35 + */
  36 + private String name;
  37 + /**
  38 + * 活动状态
  39 + *
  40 + * 枚举 {@link PromotionActivityStatusEnum 对应的类}
  41 + */
  42 + private Integer status;
  43 + /**
  44 + * 备注
  45 + */
  46 + private String remark;
  47 + /**
  48 + * 活动开始时间
  49 + */
  50 + private LocalDateTime startTime;
  51 + /**
  52 + * 活动结束时间
  53 + */
  54 + private LocalDateTime endTime;
  55 + /**
  56 + * 排序
  57 + */
  58 + private Integer sort;
  59 + /**
  60 + * 秒杀时段id
  61 + */
  62 + private String timeId;
  63 + /**
  64 + * 付款订单数
  65 + */
  66 + private Integer orderCount;
  67 + /**
  68 + * 付款人数
  69 + */
  70 + private Integer userCount;
  71 + /**
  72 + * 订单实付金额,单位:分
  73 + */
  74 + private BigDecimal totalPrice;
  75 +
  76 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillProductDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.IdType;
  5 +import com.baomidou.mybatisplus.annotation.TableField;
  6 +import com.baomidou.mybatisplus.annotation.TableId;
  7 +import com.baomidou.mybatisplus.annotation.TableName;
  8 +import java.io.Serializable;
  9 +import java.math.BigDecimal;
  10 +import java.util.Date;
  11 +import lombok.Data;
  12 +
  13 +/**
  14 + * 秒杀参与商品
  15 + * @TableName promotion_seckill_product
  16 + */
  17 +@TableName(value ="promotion_seckill_product")
  18 +@Data
  19 +public class SeckillProductDO extends BaseDO {
  20 + /**
  21 + * 秒杀参与商品编号
  22 + */
  23 + @TableId(type = IdType.AUTO)
  24 + private Long id;
  25 +
  26 + /**
  27 + * 秒杀活动id
  28 + */
  29 + private Long activityId;
  30 +
  31 + /**
  32 + * 秒杀时段id
  33 + */
  34 + private Long timeId;
  35 +
  36 + /**
  37 + * 商品id
  38 + */
  39 + private Long spuId;
  40 +
  41 + /**
  42 + * 商品sku_id
  43 + */
  44 + private Long skuId;
  45 +
  46 + /**
  47 + * 秒杀金额
  48 + */
  49 + private Integer seckillPrice;
  50 +
  51 + /**
  52 + * 秒杀库存
  53 + */
  54 + private Integer stock;
  55 +
  56 + /**
  57 + * 每人限购
  58 + */
  59 + private Integer limitBuyCount;
  60 +}
0 61 \ No newline at end of file
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckilltime/SeckillTimeDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckilltime;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
  5 +import com.baomidou.mybatisplus.annotation.TableId;
  6 +import com.baomidou.mybatisplus.annotation.TableName;
  7 +import lombok.*;
  8 +
  9 +import java.time.LocalTime;
  10 +
  11 +/**
  12 + * 秒杀时段 DO
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@TableName("promotion_seckill_time")
  17 +@KeySequence("promotion_seckill_time_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  18 +@Data
  19 +@EqualsAndHashCode(callSuper = true)
  20 +@ToString(callSuper = true)
  21 +@Builder
  22 +@NoArgsConstructor
  23 +@AllArgsConstructor
  24 +public class SeckillTimeDO extends BaseDO {
  25 +
  26 + /**
  27 + * 编号
  28 + */
  29 + @TableId
  30 + private Long id;
  31 + /**
  32 + * 秒杀时段名称
  33 + */
  34 + private String name;
  35 + /**
  36 + * 开始时间点
  37 + */
  38 + private LocalTime startTime;
  39 + /**
  40 + * 结束时间点
  41 + */
  42 + private LocalTime endTime;
  43 + /**
  44 + * 秒杀活动数量
  45 + */
  46 + private Integer seckillActivityCount;
  47 +
  48 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo.SeckillActivityPageReqVO;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +/**
  11 + * 秒杀活动 Mapper
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Mapper
  16 +public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
  17 +// TODO: 2022/11/28 halfninety 秒杀活动通过场次查询使用like会出现问题,查询活动场次编号为1,则活动场次编号为 1,11,......的都会被查出来
  18 + default PageResult<SeckillActivityDO> selectPage(SeckillActivityPageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<SeckillActivityDO>()
  20 + .likeIfPresent(SeckillActivityDO::getName, reqVO.getName())
  21 + .eqIfPresent(SeckillActivityDO::getStatus, reqVO.getStatus())
  22 + .likeIfPresent(SeckillActivityDO::getTimeId, reqVO.getTimeId())
  23 +// .like(StringUtils.hasText(reqVO.getTimeId()),SeckillActivityDO::getTimeId, reqVO.getTimeId() + ",")
  24 + .betweenIfPresent(SeckillActivityDO::getCreateTime, reqVO.getCreateTime())
  25 + .orderByDesc(SeckillActivityDO::getId));
  26 + }
  27 +
  28 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillProductMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +
  7 +import java.util.Collection;
  8 +import java.util.List;
  9 +
  10 +@Mapper
  11 +public interface SeckillProductMapper extends BaseMapperX<SeckillProductDO> {
  12 +
  13 + default List<SeckillProductDO> selectListByActivityId(Long id){
  14 + return selectList(SeckillProductDO::getActivityId,id);
  15 + }
  16 +
  17 + default List<SeckillProductDO> selectListBySkuIds(Collection<Long> skuIds){
  18 + return selectList(SeckillProductDO::getSkuId,skuIds);
  19 + }
  20 +
  21 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckilltime/SeckillTimeMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckilltime;
  2 +
  3 +import java.time.LocalTime;
  4 +import java.util.*;
  5 +
  6 +import cn.hutool.core.collection.CollUtil;
  7 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  8 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckilltime.SeckillTimeDO;
  9 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  10 +import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
  11 +import org.apache.ibatis.annotations.Mapper;
  12 +
  13 +/**
  14 + * 秒杀时段 Mapper
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@Mapper
  19 +public interface SeckillTimeMapper extends BaseMapperX<SeckillTimeDO> {
  20 + default List<SeckillTimeDO> selectListWithTime(LocalTime time){
  21 + if (time == null) {
  22 + return Collections.emptyList();
  23 + }
  24 + return selectList(new LambdaQueryWrapper<SeckillTimeDO>()
  25 + .le(SeckillTimeDO::getStartTime,time)
  26 + .ge(SeckillTimeDO::getEndTime,time));
  27 + }
  28 +
  29 + default List<SeckillTimeDO> selectListWithTime(LocalTime startTime, LocalTime endTime){
  30 + if (startTime == null && endTime == null) {
  31 + return Collections.emptyList();
  32 + }
  33 + return selectList(new LambdaQueryWrapper<SeckillTimeDO>()
  34 + .ge(SeckillTimeDO::getStartTime,startTime)
  35 + .le(SeckillTimeDO::getEndTime,endTime));
  36 + }
  37 +
  38 + default void sekillActivityCountAdd(List<Long> ids){
  39 + if (CollUtil.isEmpty(ids)){
  40 + return;
  41 + }
  42 + new LambdaUpdateChainWrapper<SeckillTimeDO>(this)
  43 + .in(SeckillTimeDO::getId,ids)
  44 + .setSql("`seckill_activity_count` = `seckill_activity_count` + 1 ")
  45 + .update();
  46 + }
  47 +
  48 + default void sekillActivityCountReduce(List<Long> ids){
  49 + if (CollUtil.isEmpty(ids)){
  50 + return;
  51 + }
  52 + new LambdaUpdateChainWrapper<SeckillTimeDO>(this)
  53 + .in(SeckillTimeDO::getId,ids)
  54 + .setSql("`seckill_activity_count` = `seckill_activity_count` - 1 ")
  55 + .update();
  56 + }
  57 +
  58 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity;
  2 +
  3 +import java.util.*;
  4 +import javax.validation.*;
  5 +
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo.SeckillActivityCreateReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo.SeckillActivityPageReqVO;
  8 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo.SeckillActivityUpdateReqVO;
  9 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
  10 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  11 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
  12 +
  13 +/**
  14 + * 秒杀活动 Service 接口
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +public interface SeckillActivityService {
  19 +
  20 + /**
  21 + * 创建秒杀活动
  22 + *
  23 + * @param createReqVO 创建信息
  24 + * @return 编号
  25 + */
  26 + Long createSeckillActivity(@Valid SeckillActivityCreateReqVO createReqVO);
  27 +
  28 + /**
  29 + * 更新秒杀活动
  30 + *
  31 + * @param updateReqVO 更新信息
  32 + */
  33 + void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO);
  34 +
  35 + /**
  36 + * 关闭秒杀活动
  37 + * @param id 编号
  38 + */
  39 + void closeSeckillActivity(Long id);
  40 +
  41 + /**
  42 + * 删除秒杀活动
  43 + *
  44 + * @param id 编号
  45 + */
  46 + void deleteSeckillActivity(Long id);
  47 +
  48 + /**
  49 + * 获得秒杀活动
  50 + *
  51 + * @param id 编号
  52 + * @return 秒杀活动
  53 + */
  54 + SeckillActivityDO getSeckillActivity(Long id);
  55 +
  56 + /**
  57 + * 获得秒杀活动列表
  58 + *
  59 + * @param ids 编号
  60 + * @return 秒杀活动列表
  61 + */
  62 + List<SeckillActivityDO> getSeckillActivityList(Collection<Long> ids);
  63 +
  64 + /**
  65 + * 获得秒杀活动分页
  66 + *
  67 + * @param pageReqVO 分页查询
  68 + * @return 秒杀活动分页
  69 + */
  70 + PageResult<SeckillActivityDO> getSeckillActivityPage(SeckillActivityPageReqVO pageReqVO);
  71 +
  72 + /**
  73 + * 通过活动编号获取活动商品
  74 + * @param id 活动编号
  75 + * @return 活动商品列表
  76 + */
  77 + List<SeckillProductDO> getSeckillProductListByActivityId(Long id);
  78 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  6 +import cn.iocoder.yudao.framework.common.util.string.StrUtils;
  7 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo.SeckillActivityBaseVO;
  8 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo.SeckillActivityCreateReqVO;
  9 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo.SeckillActivityPageReqVO;
  10 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo.SeckillActivityUpdateReqVO;
  11 +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
  12 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
  13 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
  14 +import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper;
  15 +import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper;
  16 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
  17 +import cn.iocoder.yudao.module.promotion.service.seckill.seckilltime.SeckillTimeService;
  18 +import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
  19 +import org.springframework.stereotype.Service;
  20 +import org.springframework.validation.annotation.Validated;
  21 +
  22 +import javax.annotation.Resource;
  23 +import java.util.Collection;
  24 +import java.util.List;
  25 +import java.util.stream.Collectors;
  26 +
  27 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  28 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
  29 +import static java.util.Arrays.asList;
  30 +
  31 +/**
  32 + * 秒杀活动 Service 实现类
  33 + *
  34 + * @author 芋道源码
  35 + */
  36 +@Service
  37 +@Validated
  38 +public class SeckillActivityServiceImpl implements SeckillActivityService {
  39 +
  40 + @Resource
  41 + private SeckillActivityMapper seckillActivityMapper;
  42 +
  43 + @Resource
  44 + private SeckillProductMapper seckillProductMapper;
  45 +
  46 + @Resource
  47 + private SeckillTimeService seckillTimeService;
  48 +
  49 + @Override
  50 + public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) {
  51 + List<Integer> statuses = asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus());
  52 + // 校验商品是否冲突
  53 + validateSeckillActivityProductConflicts(null, createReqVO.getProducts());
  54 + // 更新秒杀时段的秒杀活动数量
  55 + seckillTimeService.sekillActivityCountAdd(StrUtils.splitToLong(createReqVO.getTimeId(),","));
  56 + // 插入秒杀活动
  57 + SeckillActivityDO seckillActivity = SeckillActivityConvert.INSTANCE.convert(createReqVO)
  58 + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime()));
  59 + seckillActivityMapper.insert(seckillActivity);
  60 + // 插入商品
  61 + List<SeckillProductDO> productDOS = CollectionUtils.convertList(createReqVO.getProducts(),
  62 + product -> SeckillActivityConvert.INSTANCE.convert(product).setActivityId(seckillActivity.getId()));
  63 + seckillProductMapper.insertBatch(productDOS);
  64 + return seckillActivity.getId();
  65 + }
  66 +
  67 + @Override
  68 + public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) {
  69 + // 校验存在
  70 + SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(updateReqVO.getId());
  71 + if (PromotionActivityStatusEnum.CLOSE.getStatus().equals(seckillActivity.getStatus())) {
  72 + throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
  73 + }
  74 + // 校验商品是否冲突
  75 + validateSeckillActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts());
  76 + // 更新秒杀时段的秒杀活动数量
  77 + updateSeckillTimeActivityCount(updateReqVO.getId(), updateReqVO.getTimeId());
  78 + // 更新活动
  79 + SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO)
  80 + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime()));
  81 + seckillActivityMapper.updateById(updateObj);
  82 + // 更新商品
  83 + updateSeckillProduct(updateReqVO);
  84 + }
  85 +
  86 + /**
  87 + * 更新秒杀时段的秒杀活动数量
  88 + *
  89 + * @param id
  90 + * @param timeId
  91 + */
  92 + private void updateSeckillTimeActivityCount(Long id, String timeId) {
  93 + List<Long> updateTimeIds = StrUtils.splitToLong(timeId, ",");
  94 + // 查出自己的timeIds
  95 + SeckillActivityDO seckillActivityDO = seckillActivityMapper.selectById(id);
  96 + List<Long> existsTimeIds = StrUtils.splitToLong(seckillActivityDO.getTimeId(), ",");
  97 + //需要减少的时间段
  98 + List<Long> reduceIds = existsTimeIds.stream()
  99 + .filter(existsTimeId -> !updateTimeIds.contains(existsTimeId))
  100 + .collect(Collectors.toList());
  101 + //需要添加的时间段
  102 + updateTimeIds.removeIf(updateTimeId -> existsTimeIds.contains(updateTimeId));
  103 + //更新减少时间段和增加时间段
  104 + seckillTimeService.sekillActivityCountAdd(updateTimeIds);
  105 + seckillTimeService.sekillActivityCountReduce(reduceIds);
  106 + }
  107 +
  108 + /**
  109 + * 更新秒杀商品
  110 + */
  111 + private void updateSeckillProduct(SeckillActivityUpdateReqVO updateReqVO) {
  112 + List<SeckillProductDO> seckillProductDOS = seckillProductMapper.selectListByActivityId(updateReqVO.getId());
  113 + List<SeckillActivityBaseVO.Product> products = updateReqVO.getProducts();
  114 + //对后台查出的数据和前台查出的数据进行遍历,
  115 + //1.对前台数据进行遍历:如果不存在于后台的sku中需要新增
  116 + //2.对后台数据进行遍历:如果不存在于前台的sku中需要删除
  117 + //计算需要删除的数据
  118 + List<Long> deleteIds = CollectionUtils.convertList(seckillProductDOS, SeckillProductDO::getId,
  119 + seckillProductDO -> products.stream()
  120 + .noneMatch(product -> SeckillActivityConvert.INSTANCE.isEquals(seckillProductDO, product)));
  121 + if (CollUtil.isNotEmpty(deleteIds)) {
  122 + seckillProductMapper.deleteBatchIds(deleteIds);
  123 + }
  124 + //计算需要新增的数据
  125 + List<SeckillProductDO> newSeckillProductDOs = CollectionUtils.convertList(products,
  126 + product -> SeckillActivityConvert.INSTANCE.convert(product).setActivityId(updateReqVO.getId()));
  127 + newSeckillProductDOs.removeIf(product -> seckillProductDOS.stream()
  128 + .anyMatch(seckillProduct -> SeckillActivityConvert.INSTANCE.isEquals(seckillProduct, product)));
  129 + if (CollUtil.isNotEmpty(newSeckillProductDOs)) {
  130 + seckillProductMapper.insertBatch(newSeckillProductDOs);
  131 + }
  132 + }
  133 +
  134 + /**
  135 + * 校验商品是否冲突
  136 + *
  137 + * @param id 秒杀活动编号
  138 + * @param products 商品列表
  139 + */
  140 + private void validateSeckillActivityProductConflicts(Long id, List<SeckillActivityBaseVO.Product> products) {
  141 + if (CollUtil.isEmpty(products)) {
  142 + return;
  143 + }
  144 + List<SeckillProductDO> seckillProductDOS = seckillProductMapper
  145 + .selectListBySkuIds(CollectionUtils.convertSet(products, SeckillActivityBaseVO.Product::getSkuId));
  146 + if (CollUtil.isEmpty(seckillProductDOS)) {
  147 + return;
  148 + }
  149 + List<SeckillActivityDO> seckillActivityDOS = seckillActivityMapper
  150 + .selectBatchIds(CollectionUtils.convertSet(seckillProductDOS, SeckillProductDO::getActivityId));
  151 + if (id != null) {// 排除自己这个活动
  152 + seckillActivityDOS.removeIf(item -> id.equals(item.getId()));
  153 + }
  154 + // 排除不满足status的活动
  155 + List<Integer> statuses = asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus());
  156 + seckillActivityDOS.removeIf(item -> !statuses.contains(item.getStatus()));
  157 + //如果非空,则说明冲突
  158 + if (CollUtil.isNotEmpty(seckillActivityDOS)) {
  159 + throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
  160 + }
  161 +
  162 + }
  163 +
  164 + @Override
  165 + public void closeSeckillActivity(Long id) {
  166 + // 校验存在
  167 + SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id);
  168 + if (PromotionActivityStatusEnum.CLOSE.getStatus().equals(seckillActivity.getStatus())) {
  169 + throw exception(SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED);
  170 + }
  171 + if (PromotionActivityStatusEnum.END.getStatus().equals(seckillActivity.getStatus())) {
  172 + throw exception(SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_END);
  173 + }
  174 + // 更新
  175 + SeckillActivityDO updateObj = new SeckillActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus());
  176 + seckillActivityMapper.updateById(updateObj);
  177 + }
  178 +
  179 + @Override
  180 + public void deleteSeckillActivity(Long id) {
  181 + // 校验存在
  182 + SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id);
  183 + List<Integer> statuses = asList(PromotionActivityStatusEnum.CLOSE.getStatus(), PromotionActivityStatusEnum.END.getStatus());
  184 + if (!statuses.contains(seckillActivity.getStatus())) {
  185 + throw exception(SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
  186 + }
  187 + // 更新秒杀时段的秒杀活动数量
  188 + seckillTimeService.sekillActivityCountReduce(StrUtils.splitToLong(seckillActivity.getTimeId(),","));
  189 + // 删除
  190 + seckillActivityMapper.deleteById(id);
  191 + }
  192 +
  193 + private SeckillActivityDO validateSeckillActivityExists(Long id) {
  194 + SeckillActivityDO seckillActivity = seckillActivityMapper.selectById(id);
  195 + if (seckillActivity == null) {
  196 + throw exception(SECKILL_ACTIVITY_NOT_EXISTS);
  197 + }
  198 + return seckillActivity;
  199 + }
  200 +
  201 + @Override
  202 + public SeckillActivityDO getSeckillActivity(Long id) {
  203 + return seckillActivityMapper.selectById(id);
  204 + }
  205 +
  206 + @Override
  207 + public List<SeckillActivityDO> getSeckillActivityList(Collection<Long> ids) {
  208 + return seckillActivityMapper.selectBatchIds(ids);
  209 + }
  210 +
  211 + @Override
  212 + public PageResult<SeckillActivityDO> getSeckillActivityPage(SeckillActivityPageReqVO pageReqVO) {
  213 + return seckillActivityMapper.selectPage(pageReqVO);
  214 + }
  215 +
  216 + @Override
  217 + public List<SeckillProductDO> getSeckillProductListByActivityId(Long id) {
  218 + return seckillProductMapper.selectListByActivityId(id);
  219 + }
  220 +
  221 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckilltime/SeckillTimeService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.service.seckill.seckilltime;
  2 +
  3 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo.SeckillTimeCreateReqVO;
  4 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo.SeckillTimeUpdateReqVO;
  5 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckilltime.SeckillTimeDO;
  6 +
  7 +import javax.validation.Valid;
  8 +import java.util.List;
  9 +
  10 +/**
  11 + * 秒杀时段 Service 接口
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public interface SeckillTimeService {
  16 +
  17 + /**
  18 + * 创建秒杀时段
  19 + *
  20 + * @param createReqVO 创建信息
  21 + * @return 编号
  22 + */
  23 + Long createSeckillTime(@Valid SeckillTimeCreateReqVO createReqVO);
  24 +
  25 + /**
  26 + * 更新秒杀时段
  27 + *
  28 + * @param updateReqVO 更新信息
  29 + */
  30 + void updateSeckillTime(@Valid SeckillTimeUpdateReqVO updateReqVO);
  31 +
  32 + /**
  33 + * 删除秒杀时段
  34 + *
  35 + * @param id 编号
  36 + */
  37 + void deleteSeckillTime(Long id);
  38 +
  39 + /**
  40 + * 获得秒杀时段
  41 + *
  42 + * @param id 编号
  43 + * @return 秒杀时段
  44 + */
  45 + SeckillTimeDO getSeckillTime(Long id);
  46 +
  47 + /**
  48 + * 获得所有秒杀时段列表
  49 + *
  50 + * @return 所有秒杀时段列表
  51 + */
  52 + List<SeckillTimeDO> getSeckillTimeList();
  53 +
  54 + /**
  55 + * 秒杀时段列表的秒杀活动数量加 1
  56 + *
  57 + * @param ids 秒杀时段id列表
  58 + */
  59 + void sekillActivityCountAdd(List<Long> ids);
  60 +
  61 +
  62 + /**
  63 + * 秒杀时段列表的秒杀活动数量减 1
  64 + *
  65 + * @param ids 秒杀时段id列表
  66 + */
  67 + void sekillActivityCountReduce(List<Long> ids);
  68 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckilltime/SeckillTimeServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.service.seckill.seckilltime;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo.SeckillTimeCreateReqVO;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo.SeckillTimeUpdateReqVO;
  6 +import org.springframework.stereotype.Service;
  7 +
  8 +import javax.annotation.Resource;
  9 +
  10 +import org.springframework.validation.annotation.Validated;
  11 +
  12 +import java.time.LocalTime;
  13 +import java.util.*;
  14 +
  15 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckilltime.SeckillTimeDO;
  16 +
  17 +import cn.iocoder.yudao.module.promotion.convert.seckill.seckilltime.SeckillTimeConvert;
  18 +import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckilltime.SeckillTimeMapper;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  21 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
  22 +
  23 +/**
  24 + * 秒杀时段 Service 实现类
  25 + *
  26 + * @author 芋道源码
  27 + */
  28 +@Service
  29 +@Validated
  30 +public class SeckillTimeServiceImpl implements SeckillTimeService {
  31 +
  32 +
  33 + @Resource
  34 + private SeckillTimeMapper seckillTimeMapper;
  35 +
  36 + @Override
  37 + public Long createSeckillTime(SeckillTimeCreateReqVO createReqVO) {
  38 + // 校验时间段是否冲突
  39 + validateSeckillTimeConflict(null,createReqVO.getStartTime(), createReqVO.getEndTime());
  40 + // 插入
  41 + SeckillTimeDO seckillTime = SeckillTimeConvert.INSTANCE.convert(createReqVO);
  42 + seckillTimeMapper.insert(seckillTime);
  43 + // 返回
  44 + return seckillTime.getId();
  45 + }
  46 +
  47 + @Override
  48 + public void updateSeckillTime(SeckillTimeUpdateReqVO updateReqVO) {
  49 + // 校验存在
  50 + this.validateSeckillTimeExists(updateReqVO.getId());
  51 + // 校验时间段是否冲突
  52 + validateSeckillTimeConflict(updateReqVO.getId(), updateReqVO.getStartTime(), updateReqVO.getEndTime());
  53 + // 更新
  54 + SeckillTimeDO updateObj = SeckillTimeConvert.INSTANCE.convert(updateReqVO);
  55 + seckillTimeMapper.updateById(updateObj);
  56 + }
  57 +
  58 + @Override
  59 + public void deleteSeckillTime(Long id) {
  60 + // 校验存在
  61 + this.validateSeckillTimeExists(id);
  62 + // 删除
  63 + seckillTimeMapper.deleteById(id);
  64 + }
  65 +
  66 + private void validateSeckillTimeExists(Long id) {
  67 + if (seckillTimeMapper.selectById(id) == null) {
  68 + throw exception(SECKILL_TIME_NOT_EXISTS);
  69 + }
  70 + }
  71 +
  72 + /**
  73 + * 校验时间是否存在冲突
  74 + *
  75 + * @param startTime 开始时间
  76 + * @param endTime 结束时间
  77 + */
  78 + private void validateSeckillTimeConflict(Long id, LocalTime startTime, LocalTime endTime) {
  79 + //查询开始时间,结束时间,是否在别人的时间段内
  80 + List<SeckillTimeDO> startTimeList = seckillTimeMapper.selectListWithTime(startTime);
  81 + List<SeckillTimeDO> endTimeList = seckillTimeMapper.selectListWithTime(endTime);
  82 + //查询自己时间段内是否有时间段
  83 + List<SeckillTimeDO> startEndTimeList = seckillTimeMapper.selectListWithTime(startTime, endTime);
  84 + if (id != null) {
  85 + //移除自己
  86 + startTimeList.removeIf(seckillTime -> Objects.equals(seckillTime.getId(), id));
  87 + endTimeList.removeIf(seckillTime -> Objects.equals(seckillTime.getId(), id));
  88 + startEndTimeList.removeIf(seckillTime -> Objects.equals(seckillTime.getId(), id));
  89 + }
  90 + if (CollUtil.isNotEmpty(startTimeList) || CollUtil.isNotEmpty(endTimeList)
  91 + || CollUtil.isNotEmpty(startEndTimeList)) {
  92 + throw exception(SECKILL_TIME_CONFLICTS);
  93 + }
  94 + }
  95 +
  96 +
  97 + @Override
  98 + public SeckillTimeDO getSeckillTime(Long id) {
  99 + return seckillTimeMapper.selectById(id);
  100 + }
  101 +
  102 + @Override
  103 + public List<SeckillTimeDO> getSeckillTimeList() {
  104 + return seckillTimeMapper.selectList();
  105 + }
  106 +
  107 + @Override
  108 + public void sekillActivityCountAdd(List<Long> ids) {
  109 + seckillTimeMapper.sekillActivityCountAdd(ids);
  110 + }
  111 +
  112 + @Override
  113 + public void sekillActivityCountReduce(List<Long> ids) {
  114 + seckillTimeMapper.sekillActivityCountReduce(ids);
  115 + }
  116 +
  117 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/seckillactivity/SeckillActivityMapper.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper">
  4 +
  5 + <!--
  6 + 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
  7 + 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
  8 + 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
  9 + 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
  10 + -->
  11 +
  12 +</mapper>
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/seckilltime/SeckillTimeMapper.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckilltime.SeckillTimeMapper">
  4 +
  5 + <!--
  6 + 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
  7 + 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
  8 + 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
  9 + 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
  10 + -->
  11 +
  12 +</mapper>
... ...
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/seckillactivity/SeckillActivityServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.service.seckillactivity;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo.SeckillActivityCreateReqVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo.SeckillActivityPageReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckillactivity.vo.SeckillActivityUpdateReqVO;
  8 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
  9 +import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper;
  10 +import cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity.SeckillActivityServiceImpl;
  11 +import org.junit.jupiter.api.Disabled;
  12 +import org.junit.jupiter.api.Test;
  13 +import org.springframework.context.annotation.Import;
  14 +
  15 +import javax.annotation.Resource;
  16 +import java.time.LocalDateTime;
  17 +
  18 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  19 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  20 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  21 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
  22 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  23 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_NOT_EXISTS;
  24 +import static org.junit.jupiter.api.Assertions.*;
  25 +
  26 +/**
  27 +* {@link SeckillActivityServiceImpl} 的单元测试类
  28 +*
  29 +* @author 芋道源码
  30 +*/
  31 +@Import(SeckillActivityServiceImpl.class)
  32 +public class SeckillActivityServiceImplTest extends BaseDbUnitTest {
  33 +
  34 + @Resource
  35 + private SeckillActivityServiceImpl seckillActivityService;
  36 +
  37 + @Resource
  38 + private SeckillActivityMapper seckillActivityMapper;
  39 +
  40 + @Test
  41 + public void testCreateSeckillActivity_success() {
  42 + // 准备参数
  43 + SeckillActivityCreateReqVO reqVO = randomPojo(SeckillActivityCreateReqVO.class);
  44 +
  45 + // 调用
  46 + Long seckillActivityId = seckillActivityService.createSeckillActivity(reqVO);
  47 + // 断言
  48 + assertNotNull(seckillActivityId);
  49 + // 校验记录的属性是否正确
  50 + SeckillActivityDO seckillActivity = seckillActivityMapper.selectById(seckillActivityId);
  51 + assertPojoEquals(reqVO, seckillActivity);
  52 + }
  53 +
  54 + @Test
  55 + public void testUpdateSeckillActivity_success() {
  56 + // mock 数据
  57 + SeckillActivityDO dbSeckillActivity = randomPojo(SeckillActivityDO.class);
  58 + seckillActivityMapper.insert(dbSeckillActivity);// @Sql: 先插入出一条存在的数据
  59 + // 准备参数
  60 + SeckillActivityUpdateReqVO reqVO = randomPojo(SeckillActivityUpdateReqVO.class, o -> {
  61 + o.setId(dbSeckillActivity.getId()); // 设置更新的 ID
  62 + });
  63 +
  64 + // 调用
  65 + seckillActivityService.updateSeckillActivity(reqVO);
  66 + // 校验是否更新正确
  67 + SeckillActivityDO seckillActivity = seckillActivityMapper.selectById(reqVO.getId()); // 获取最新的
  68 + assertPojoEquals(reqVO, seckillActivity);
  69 + }
  70 +
  71 + @Test
  72 + public void testUpdateSeckillActivity_notExists() {
  73 + // 准备参数
  74 + SeckillActivityUpdateReqVO reqVO = randomPojo(SeckillActivityUpdateReqVO.class);
  75 +
  76 + // 调用, 并断言异常
  77 + assertServiceException(() -> seckillActivityService.updateSeckillActivity(reqVO), SECKILL_ACTIVITY_NOT_EXISTS);
  78 + }
  79 +
  80 + @Test
  81 + public void testDeleteSeckillActivity_success() {
  82 + // mock 数据
  83 + SeckillActivityDO dbSeckillActivity = randomPojo(SeckillActivityDO.class);
  84 + seckillActivityMapper.insert(dbSeckillActivity);// @Sql: 先插入出一条存在的数据
  85 + // 准备参数
  86 + Long id = dbSeckillActivity.getId();
  87 +
  88 + // 调用
  89 + seckillActivityService.deleteSeckillActivity(id);
  90 + // 校验数据不存在了
  91 + assertNull(seckillActivityMapper.selectById(id));
  92 + }
  93 +
  94 + @Test
  95 + public void testDeleteSeckillActivity_notExists() {
  96 + // 准备参数
  97 + Long id = randomLongId();
  98 +
  99 + // 调用, 并断言异常
  100 + assertServiceException(() -> seckillActivityService.deleteSeckillActivity(id), SECKILL_ACTIVITY_NOT_EXISTS);
  101 + }
  102 +
  103 + @Test
  104 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  105 + public void testGetSeckillActivityPage() {
  106 + // mock 数据
  107 + SeckillActivityDO dbSeckillActivity = randomPojo(SeckillActivityDO.class, o -> { // 等会查询到
  108 + o.setName(null);
  109 + o.setStatus(null);
  110 + o.setTimeId(null);
  111 + o.setCreateTime(null);
  112 + });
  113 + seckillActivityMapper.insert(dbSeckillActivity);
  114 + // 测试 name 不匹配
  115 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setName(null)));
  116 + // 测试 status 不匹配
  117 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setStatus(null)));
  118 + // 测试 timeId 不匹配
  119 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setTimeId(null)));
  120 + // 测试 createTime 不匹配
  121 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setCreateTime(null)));
  122 + // 准备参数
  123 + SeckillActivityPageReqVO reqVO = new SeckillActivityPageReqVO();
  124 + reqVO.setName(null);
  125 + reqVO.setStatus(null);
  126 + reqVO.setTimeId(null);
  127 + reqVO.setCreateTime((new LocalDateTime[]{}));
  128 +
  129 + // 调用
  130 + PageResult<SeckillActivityDO> pageResult = seckillActivityService.getSeckillActivityPage(reqVO);
  131 + // 断言
  132 + assertEquals(1, pageResult.getTotal());
  133 + assertEquals(1, pageResult.getList().size());
  134 + assertPojoEquals(dbSeckillActivity, pageResult.getList().get(0));
  135 + }
  136 +
  137 + @Test
  138 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  139 + public void testGetSeckillActivityList() {
  140 + // mock 数据
  141 + SeckillActivityDO dbSeckillActivity = randomPojo(SeckillActivityDO.class, o -> { // 等会查询到
  142 + o.setName(null);
  143 + o.setStatus(null);
  144 + o.setTimeId(null);
  145 + o.setCreateTime(null);
  146 + });
  147 + seckillActivityMapper.insert(dbSeckillActivity);
  148 + // 测试 name 不匹配
  149 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setName(null)));
  150 + // 测试 status 不匹配
  151 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setStatus(null)));
  152 + // 测试 timeId 不匹配
  153 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setTimeId(null)));
  154 + // 测试 createTime 不匹配
  155 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setCreateTime(null)));
  156 + // 准备参数
  157 +// SeckillActivityExportReqVO reqVO = new SeckillActivityExportReqVO();
  158 +// reqVO.setName(null);
  159 +// reqVO.setStatus(null);
  160 +// reqVO.setTimeId(null);
  161 +// reqVO.setCreateTime((new Date[]{}));
  162 +//
  163 +// // 调用
  164 +// List<SeckillActivityDO> list = seckillActivityService.getSeckillActivityList(reqVO);
  165 +// // 断言
  166 +// assertEquals(1, list.size());
  167 +// assertPojoEquals(dbSeckillActivity, list.get(0));
  168 + }
  169 +
  170 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/seckilltime/SeckillTimeServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.service.seckilltime;
  2 +
  3 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo.SeckillTimeCreateReqVO;
  4 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.seckilltime.vo.SeckillTimeUpdateReqVO;
  5 +import cn.iocoder.yudao.module.promotion.service.seckill.seckilltime.SeckillTimeServiceImpl;
  6 +import com.fasterxml.jackson.core.JsonProcessingException;
  7 +import com.fasterxml.jackson.databind.ObjectMapper;
  8 +import org.junit.jupiter.api.Disabled;
  9 +import org.junit.jupiter.api.Test;
  10 +
  11 +import javax.annotation.Resource;
  12 +
  13 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  14 +
  15 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckilltime.SeckillTimeDO;
  16 +import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckilltime.SeckillTimeMapper;
  17 +
  18 +import org.springframework.context.annotation.Import;
  19 +
  20 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
  21 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
  22 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  23 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
  24 +import static org.junit.jupiter.api.Assertions.*;
  25 +
  26 +/**
  27 +* {@link SeckillTimeServiceImpl} 的单元测试类
  28 +*
  29 +* @author 芋道源码
  30 +*/
  31 +@Import(SeckillTimeServiceImpl.class)
  32 +public class SeckillTimeServiceImplTest extends BaseDbUnitTest {
  33 +
  34 + @Resource
  35 + private SeckillTimeServiceImpl seckillTimeService;
  36 +
  37 + @Resource
  38 + private SeckillTimeMapper seckillTimeMapper;
  39 +
  40 + @Resource
  41 + private ObjectMapper objectMapper;
  42 +
  43 + @Test
  44 + public void testJacksonSerializ(){
  45 +
  46 + // 准备参数
  47 + SeckillTimeCreateReqVO reqVO = randomPojo(SeckillTimeCreateReqVO.class);
  48 +// ObjectMapper objectMapper = new ObjectMapper();
  49 + try {
  50 + String string = objectMapper.writeValueAsString(reqVO);
  51 + System.out.println(string);
  52 + } catch (JsonProcessingException e) {
  53 + e.printStackTrace();
  54 + }
  55 +
  56 +
  57 + }
  58 +
  59 + @Test
  60 + public void testCreateSeckillTime_success() {
  61 + // 准备参数
  62 + SeckillTimeCreateReqVO reqVO = randomPojo(SeckillTimeCreateReqVO.class);
  63 +
  64 + // 调用
  65 + Long seckillTimeId = seckillTimeService.createSeckillTime(reqVO);
  66 + // 断言
  67 + assertNotNull(seckillTimeId);
  68 + // 校验记录的属性是否正确
  69 + SeckillTimeDO seckillTime = seckillTimeMapper.selectById(seckillTimeId);
  70 + assertPojoEquals(reqVO, seckillTime);
  71 + }
  72 +
  73 + @Test
  74 + public void testUpdateSeckillTime_success() {
  75 + // mock 数据
  76 + SeckillTimeDO dbSeckillTime = randomPojo(SeckillTimeDO.class);
  77 + seckillTimeMapper.insert(dbSeckillTime);// @Sql: 先插入出一条存在的数据
  78 + // 准备参数
  79 + SeckillTimeUpdateReqVO reqVO = randomPojo(SeckillTimeUpdateReqVO.class, o -> {
  80 + o.setId(dbSeckillTime.getId()); // 设置更新的 ID
  81 + });
  82 +
  83 + // 调用
  84 + seckillTimeService.updateSeckillTime(reqVO);
  85 + // 校验是否更新正确
  86 + SeckillTimeDO seckillTime = seckillTimeMapper.selectById(reqVO.getId()); // 获取最新的
  87 + assertPojoEquals(reqVO, seckillTime);
  88 + }
  89 +
  90 + @Test
  91 + public void testUpdateSeckillTime_notExists() {
  92 + // 准备参数
  93 + SeckillTimeUpdateReqVO reqVO = randomPojo(SeckillTimeUpdateReqVO.class);
  94 +
  95 + // 调用, 并断言异常
  96 + assertServiceException(() -> seckillTimeService.updateSeckillTime(reqVO), SECKILL_TIME_NOT_EXISTS);
  97 + }
  98 +
  99 + @Test
  100 + public void testDeleteSeckillTime_success() {
  101 + // mock 数据
  102 + SeckillTimeDO dbSeckillTime = randomPojo(SeckillTimeDO.class);
  103 + seckillTimeMapper.insert(dbSeckillTime);// @Sql: 先插入出一条存在的数据
  104 + // 准备参数
  105 + Long id = dbSeckillTime.getId();
  106 +
  107 + // 调用
  108 + seckillTimeService.deleteSeckillTime(id);
  109 + // 校验数据不存在了
  110 + assertNull(seckillTimeMapper.selectById(id));
  111 + }
  112 +
  113 + @Test
  114 + public void testDeleteSeckillTime_notExists() {
  115 + // 准备参数
  116 + Long id = randomLongId();
  117 +
  118 + // 调用, 并断言异常
  119 + assertServiceException(() -> seckillTimeService.deleteSeckillTime(id), SECKILL_TIME_NOT_EXISTS);
  120 + }
  121 +
  122 + @Test
  123 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  124 + public void testGetSeckillTimePage() {
  125 + // mock 数据
  126 +// SeckillTimeDO dbSeckillTime = randomPojo(SeckillTimeDO.class, o -> { // 等会查询到
  127 +// o.setName(null);
  128 +// o.setStartTime(null);
  129 +// o.setEndTime(null);
  130 +// o.setCreateTime(null);
  131 +// });
  132 +// seckillTimeMapper.insert(dbSeckillTime);
  133 +// // 测试 name 不匹配
  134 +// seckillTimeMapper.insert(cloneIgnoreId(dbSeckillTime, o -> o.setName(null)));
  135 +// // 测试 startTime 不匹配
  136 +// seckillTimeMapper.insert(cloneIgnoreId(dbSeckillTime, o -> o.setStartTime(null)));
  137 +// // 测试 endTime 不匹配
  138 +// seckillTimeMapper.insert(cloneIgnoreId(dbSeckillTime, o -> o.setEndTime(null)));
  139 +// // 测试 createTime 不匹配
  140 +// seckillTimeMapper.insert(cloneIgnoreId(dbSeckillTime, o -> o.setCreateTime(null)));
  141 +// // 准备参数
  142 +// SeckillTimePageReqVO reqVO = new SeckillTimePageReqVO();
  143 +// reqVO.setName(null);
  144 +//// reqVO.setStartTime((new LocalTime()));
  145 +//// reqVO.setEndTime((new LocalTime[]{}));
  146 +//// reqVO.setCreateTime((new Date[]{}));
  147 +//
  148 +// // 调用
  149 +// PageResult<SeckillTimeDO> pageResult = seckillTimeService.getSeckillTimePage(reqVO);
  150 +// // 断言
  151 +// assertEquals(1, pageResult.getTotal());
  152 +// assertEquals(1, pageResult.getList().size());
  153 +// assertPojoEquals(dbSeckillTime, pageResult.getList().get(0));
  154 + }
  155 +
  156 + @Test
  157 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  158 + public void testGetSeckillTimeList() {
  159 + // mock 数据
  160 + SeckillTimeDO dbSeckillTime = randomPojo(SeckillTimeDO.class, o -> { // 等会查询到
  161 + o.setName(null);
  162 + o.setStartTime(null);
  163 + o.setEndTime(null);
  164 + o.setCreateTime(null);
  165 + });
  166 + seckillTimeMapper.insert(dbSeckillTime);
  167 + // 测试 name 不匹配
  168 + seckillTimeMapper.insert(cloneIgnoreId(dbSeckillTime, o -> o.setName(null)));
  169 + // 测试 startTime 不匹配
  170 + seckillTimeMapper.insert(cloneIgnoreId(dbSeckillTime, o -> o.setStartTime(null)));
  171 + // 测试 endTime 不匹配
  172 + seckillTimeMapper.insert(cloneIgnoreId(dbSeckillTime, o -> o.setEndTime(null)));
  173 + // 测试 createTime 不匹配
  174 + seckillTimeMapper.insert(cloneIgnoreId(dbSeckillTime, o -> o.setCreateTime(null)));
  175 + // 准备参数
  176 +// SeckillTimeExportReqVO reqVO = new SeckillTimeExportReqVO();
  177 +// reqVO.setName(null);
  178 +// reqVO.setStartTime((new LocalTime[]{}));
  179 +// reqVO.setEndTime((new LocalTime[]{}));
  180 +// reqVO.setCreateTime((new Date[]{}));
  181 +//
  182 +// // 调用
  183 +// List<SeckillTimeDO> list = seckillTimeService.getSeckillTimeList(reqVO);
  184 +// // 断言
  185 +// assertEquals(1, list.size());
  186 +// assertPojoEquals(dbSeckillTime, list.get(0));
  187 + }
  188 +
  189 +}
... ...
yudao-ui-admin/src/api/mall/promotion/seckillActivity.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 创建秒杀活动
  4 +export function createSeckillActivity(data) {
  5 + return request({
  6 + url: '/promotion/seckill-activity/create',
  7 + method: 'post',
  8 + data: data
  9 + })
  10 +}
  11 +
  12 +// 更新秒杀活动
  13 +export function updateSeckillActivity(data) {
  14 + return request({
  15 + url: '/promotion/seckill-activity/update',
  16 + method: 'put',
  17 + data: data
  18 + })
  19 +}
  20 +
  21 +// 关闭限时折扣活动
  22 +export function closeSeckillActivity(id) {
  23 + return request({
  24 + url: '/promotion/seckill-activity/close?id=' + id,
  25 + method: 'put'
  26 + })
  27 +}
  28 +
  29 +// 删除秒杀活动
  30 +export function deleteSeckillActivity(id) {
  31 + return request({
  32 + url: '/promotion/seckill-activity/delete?id=' + id,
  33 + method: 'delete'
  34 + })
  35 +}
  36 +
  37 +// 获得秒杀活动
  38 +export function getSeckillActivity(id) {
  39 + return request({
  40 + url: '/promotion/seckill-activity/get?id=' + id,
  41 + method: 'get'
  42 + })
  43 +}
  44 +
  45 +// 获得秒杀活动分页
  46 +export function getSeckillActivityPage(query) {
  47 + return request({
  48 + url: '/promotion/seckill-activity/page',
  49 + method: 'get',
  50 + params: query
  51 + })
  52 +}
... ...
yudao-ui-admin/src/api/mall/promotion/seckillTime.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 创建秒杀时段
  4 +export function createSeckillTime(data) {
  5 + return request({
  6 + url: '/promotion/seckill-time/create',
  7 + method: 'post',
  8 + data: data
  9 + })
  10 +}
  11 +
  12 +// 更新秒杀时段
  13 +export function updateSeckillTime(data) {
  14 + return request({
  15 + url: '/promotion/seckill-time/update',
  16 + method: 'put',
  17 + data: data
  18 + })
  19 +}
  20 +
  21 +// 删除秒杀时段
  22 +export function deleteSeckillTime(id) {
  23 + return request({
  24 + url: '/promotion/seckill-time/delete?id=' + id,
  25 + method: 'delete'
  26 + })
  27 +}
  28 +
  29 +// 获得秒杀时段
  30 +export function getSeckillTime(id) {
  31 + return request({
  32 + url: '/promotion/seckill-time/get?id=' + id,
  33 + method: 'get'
  34 + })
  35 +}
  36 +
  37 +// 获得秒杀时段分页
  38 +export function getSeckillTimePage(query) {
  39 + return request({
  40 + url: '/promotion/seckill-time/page',
  41 + method: 'get',
  42 + params: query
  43 + })
  44 +}
  45 +
  46 +// 获取所有的秒杀时段
  47 +export function getSeckillTimeList() {
  48 + return request({
  49 + url: '/promotion/seckill-time/list',
  50 + method: 'get'
  51 + })
  52 +}
  53 +
  54 +// 导出秒杀时段 Excel
  55 +export function exportSeckillTimeExcel(query) {
  56 + return request({
  57 + url: '/promotion/seckill-time/export-excel',
  58 + method: 'get',
  59 + params: query,
  60 + responseType: 'blob'
  61 + })
  62 +}
... ...
yudao-ui-admin/src/views/mall/promotion/seckill/seckillActivity/index.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
  6 + label-width="68px">
  7 + <el-form-item label="活动名称" prop="name">
  8 + <el-input v-model="queryParams.name" placeholder="请输入秒杀活动名称" clearable
  9 + @keyup.enter.native="handleQuery" />
  10 + </el-form-item>
  11 + <el-form-item label="活动状态" prop="status">
  12 + <el-select v-model="queryParams.status" placeholder="请选择活动状态" clearable size="small">
  13 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_ACTIVITY_STATUS)" :key="dict.value"
  14 + :label="dict.label" :value="dict.value" />
  15 + </el-select>
  16 + </el-form-item>
  17 + <el-form-item label="参与场次" prop="timeId">
  18 + <el-select v-model="queryParams.timeId" placeholder="请选择参与场次" clearable size="small">
  19 + <el-option v-for="item in seckillTimeList" :key="item.id" :label="item.name" :value="item.id" />
  20 + </el-select>
  21 + </el-form-item>
  22 + <el-form-item label="创建时间" prop="createTime">
  23 + <el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss"
  24 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
  25 + :default-time="['00:00:00', '23:59:59']" />
  26 + </el-form-item>
  27 + <el-form-item>
  28 + <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
  29 + <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
  30 + </el-form-item>
  31 + </el-form>
  32 +
  33 + <!-- 操作工具栏 -->
  34 + <el-row :gutter="10" class="mb8">
  35 + <el-col :span="1.5">
  36 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
  37 + v-hasPermi="['promotion:seckill-activity:create']">新增秒杀活动</el-button>
  38 + </el-col>
  39 + <el-col :span="1.5">
  40 + <el-button type="primary" plain icon="el-icon-menu" size="mini" @click="openSeckillTime"
  41 + v-hasPermi="['promotion:seckill-activity:create']">管理参与场次</el-button>
  42 + </el-col>
  43 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  44 + </el-row>
  45 +
  46 + <!-- 列表 -->
  47 + <el-table v-loading="loading" :data="list">
  48 + <el-table-column label="活动名称" align="center" prop="name" />
  49 + <el-table-column label="活动状态" align="center" prop="status">
  50 + <template slot-scope="scope">
  51 + <dict-tag :type="DICT_TYPE.PROMOTION_ACTIVITY_STATUS" :value="scope.row.status" />
  52 + </template>
  53 + </el-table-column>
  54 + <el-table-column label="参与场次" prop="timeId" width="250">
  55 + <template slot-scope="scope">
  56 + <span v-for="item in seckillTimeList" :key="item.id"
  57 + v-if="scope.row.timeId.indexOf(item.id) !== -1">
  58 + <el-tag style="margin:4px;" size="small">{{ item.name }}</el-tag>
  59 + </span>
  60 + </template>
  61 + </el-table-column>
  62 + <el-table-column label="活动开始时间" align="center" prop="startTime" width="190">
  63 + <template slot-scope="scope">
  64 + <span>{{ "开始: " + parseTime(scope.row.startTime) }}</span>
  65 + <span>{{ "结束: " + parseTime(scope.row.endTime) }}</span>
  66 + </template>
  67 + </el-table-column>
  68 +
  69 + <el-table-column label="付款订单数" align="center" prop="orderCount" />
  70 + <el-table-column label="付款人数" align="center" prop="userCount" />
  71 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  72 + <template slot-scope="scope">
  73 + <span>{{ parseTime(scope.row.createTime) }}</span>
  74 + </template>
  75 + </el-table-column>
  76 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  77 + <template slot-scope="scope">
  78 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  79 + v-hasPermi="['promotion:seckill-activity:update']">修改</el-button>
  80 + <el-button size="mini" type="text" icon="el-icon-close" @click="handleClose(scope.row)"
  81 + v-hasPermi="['promotion:seckill-activity:delete']">关闭</el-button>
  82 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  83 + v-hasPermi="['promotion:seckill-activity:delete']">删除</el-button>
  84 + </template>
  85 + </el-table-column>
  86 + </el-table>
  87 + <!-- 分页组件 -->
  88 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  89 + @pagination="getList" />
  90 +
  91 + <!-- 对话框(添加 / 修改) -->
  92 + <el-dialog :title="title" :visible.sync="open" width="1200px" v-dialogDrag append-to-body>
  93 + <el-form ref="form" :model="form" :rules="rules" label-width="80px">
  94 + <el-form-item label="活动名称" prop="name">
  95 + <el-input v-model="form.name" placeholder="请输入秒杀活动名称" />
  96 + </el-form-item>
  97 + <el-form-item label="活动时间" prop="startAndEndTime">
  98 + <el-date-picker clearable v-model="form.startAndEndTime" type="datetimerange"
  99 + value-format="timestamp" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"
  100 + style="width: 1080px" />
  101 + </el-form-item>
  102 + <el-form-item label="排序" prop="sort">
  103 + <el-input-number v-model="form.sort" controls-position="right" :min="0" :max="10000">
  104 + </el-input-number>
  105 + </el-form-item>
  106 + <el-form-item label="备注" prop="remark">
  107 + <el-input type="textarea" v-model="form.remark" placeholder="请输入备注" />
  108 + </el-form-item>
  109 + <el-form-item label="场次选择">
  110 + <el-select v-model="form.timeId" placeholder="请选择参与场次" clearable size="small" multiple filterable
  111 + style="width: 880px">
  112 + <el-option v-for="item in seckillTimeList" :key="item.id" :label="item.name" :value="item.id">
  113 + <span style="float: left">{{ item.name + ': { ' }} {{ item.startTime }} -- {{ item.endTime +
  114 + ' }'
  115 + }}</span>
  116 + <span style="float: right; color: #8492a6; font-size: 13px"></span>
  117 + </el-option>
  118 + </el-select>
  119 + </el-form-item>
  120 + <el-form-item label="商品选择">
  121 + <el-select v-model="form.skuIds" placeholder="请选择活动商品" clearable size="small" multiple filterable
  122 + style="width: 880px" @change="changeFormSku">
  123 + <el-option v-for="item in productSkus" :key="item.id" :label="item.spuName + ' ' + item.name"
  124 + :value="item.id">
  125 + <span style="float: left">{{ item.spuName }} &nbsp; {{ item.name }}</span>
  126 + <span style="float: right; color: #8492a6; font-size: 13px">¥{{ (item.price /
  127 + 100.0).toFixed(2)
  128 + }}</span>
  129 + </el-option>
  130 + </el-select>
  131 + <el-row>
  132 + <el-button type="primary" size="mini" @click="batchEditProduct('limitBuyCount')">限购</el-button>
  133 + <el-button type="primary" size="mini" @click="batchEditProduct('seckillPrice')">秒杀价</el-button>
  134 + <el-button type="primary" size="mini" @click="batchEditProduct('seckillStock')">秒杀库存</el-button>
  135 + </el-row>
  136 + <el-table v-loading="loading" ref="productsTable" :data="form.products">
  137 + <el-table-column type="selection" width="55">
  138 + </el-table-column>
  139 + <el-table-column label="商品名称" align="center" width="200">
  140 + <template slot-scope="scope">
  141 + {{ scope.row.spuName }} &nbsp; {{ scope.row.name }}
  142 + </template>
  143 + </el-table-column>
  144 + <el-table-column label="商品价格" align="center" prop="price">
  145 + <template slot-scope="scope">
  146 + ¥{{ (scope.row.price / 100.0).toFixed(2) }}
  147 + </template>
  148 + </el-table-column>
  149 + <el-table-column label="库存" align="center" prop="productStock" />
  150 + <el-table-column label="限购(0为不限购)" align="center" width="150">
  151 + <template slot-scope="scope">
  152 + <el-input-number v-model="scope.row.limitBuyCount" size="mini" :min="0" :max="10000">
  153 + </el-input-number>
  154 + </template>
  155 + </el-table-column>
  156 + <el-table-column label="秒杀价(元)" align="center" width="150">
  157 + <template slot-scope="scope">
  158 + <el-input-number v-model="scope.row.seckillPrice" size="mini" :precision="2" :min="0"
  159 + :max="10000">
  160 + </el-input-number>
  161 + </template>
  162 + </el-table-column>
  163 + <el-table-column label="秒杀库存" align="center" width="150" prop="seckillStock">
  164 + <template slot-scope="scope">
  165 + <el-input-number v-model="scope.row.seckillStock" size="mini" :min="0" :max="10000">
  166 + </el-input-number>
  167 + </template>
  168 + </el-table-column>
  169 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  170 + <template slot-scope="scope">
  171 + <el-button size="mini" type="text" icon="el-icon-delete"
  172 + @click="removeFormSku(scope.row.skuId)">删除
  173 + </el-button>
  174 + </template>
  175 + </el-table-column>
  176 + </el-table>
  177 + </el-form-item>
  178 + </el-form>
  179 + <div slot="footer" class="dialog-footer">
  180 + <el-button type="primary" @click="submitForm">确 定</el-button>
  181 + <el-button @click="cancel">取 消</el-button>
  182 + </div>
  183 + </el-dialog>
  184 + </div>
  185 +</template>
  186 +
  187 +<script>
  188 +import { getSkuOptionList } from "@/api/mall/product/sku";
  189 +import { createSeckillActivity, updateSeckillActivity, closeSeckillActivity,deleteSeckillActivity, getSeckillActivity, getSeckillActivityPage, exportSeckillActivityExcel } from "@/api/mall/promotion/seckillActivity";
  190 +import { getSeckillTimeList } from "@/api/mall/promotion/seckillTime";
  191 +import { deepClone } from "@/utils";
  192 +
  193 +export default {
  194 + name: "SeckillActivity",
  195 + components: {
  196 + },
  197 + data() {
  198 + return {
  199 + // 遮罩层
  200 + loading: true,
  201 + // 显示搜索条件
  202 + showSearch: true,
  203 + // 总条数
  204 + total: 0,
  205 + // 秒杀活动列表
  206 + list: [],
  207 + // 秒杀场次列表
  208 + seckillTimeList: [],
  209 + // 弹出层标题
  210 + title: "",
  211 + // 是否显示弹出层
  212 + open: false,
  213 + // 查询参数
  214 + queryParams: {
  215 + pageNo: 1,
  216 + pageSize: 10,
  217 + name: null,
  218 + status: null,
  219 + timeId: null,
  220 + createTime: [],
  221 + },
  222 + // 表单参数
  223 + form: {
  224 + skuIds: [], // 选中的 SKU
  225 + products: [], // 商品信息
  226 + timeId: [], //选中的秒杀场次id
  227 + },
  228 + // 商品 SKU 列表
  229 + productSkus: [],
  230 + // 表单校验
  231 + rules: {
  232 + name: [{ required: true, message: "秒杀活动名称不能为空", trigger: "blur" }],
  233 + status: [{ required: true, message: "活动状态不能为空", trigger: "blur" }],
  234 + startAndEndTime: [{ required: true, message: "活动时间不能为空", trigger: "blur" }],
  235 + sort: [{ required: true, message: "排序不能为空", trigger: "blur" }],
  236 + timeId: [{ required: true, message: "秒杀场次不能为空", trigger: "blur" }],
  237 + totalPrice: [{ required: true, message: "订单实付金额,单位:分不能为空", trigger: "blur" }],
  238 + }
  239 + };
  240 + },
  241 + created() {
  242 + this.getList();
  243 + },
  244 + watch:{
  245 + $route: 'getList'
  246 + },
  247 + methods: {
  248 + /** 查询列表 */
  249 + getList() {
  250 + const timeId = this.$route.params && this.$route.params.timeId;
  251 + if (timeId) {
  252 + this.queryParams.timeId = timeId
  253 + }
  254 + this.loading = true;
  255 + // 执行查询
  256 + getSeckillActivityPage(this.queryParams).then(response => {
  257 + this.list = response.data.list;
  258 + this.total = response.data.total;
  259 + this.loading = false;
  260 + });
  261 + if (timeId) {
  262 + this.$route.params.timeId = undefined
  263 + }
  264 + // 获得 SKU 商品列表
  265 + getSkuOptionList().then(response => {
  266 + this.productSkus = response.data;
  267 + });
  268 + // 获取参与场次列表
  269 + getSeckillTimeList().then(response => {
  270 + this.seckillTimeList = response.data;
  271 + });
  272 + },
  273 + /** 取消按钮 */
  274 + cancel() {
  275 + this.open = false;
  276 + this.reset();
  277 + },
  278 + /** 表单重置 */
  279 + reset() {
  280 + this.form = {
  281 + id: undefined,
  282 + name: undefined,
  283 + status: undefined,
  284 + remark: undefined,
  285 + startTime: undefined,
  286 + endTime: undefined,
  287 + sort: undefined,
  288 + timeId: [],
  289 + totalPrice: undefined,
  290 + skuIds: [],
  291 + products: [],
  292 + };
  293 + this.resetForm("form");
  294 + },
  295 + /** 搜索按钮操作 */
  296 + handleQuery() {
  297 + this.queryParams.pageNo = 1;
  298 + this.getList();
  299 + },
  300 + /** 重置按钮操作 */
  301 + resetQuery() {
  302 + this.resetForm("queryForm");
  303 + this.handleQuery();
  304 + },
  305 + /**打开秒杀场次管理页面 */
  306 + openSeckillTime() {
  307 + this.$tab.openPage("秒杀场次管理", "/promotion/seckill-time");
  308 + },
  309 + /** 新增按钮操作 */
  310 + handleAdd() {
  311 + this.reset();
  312 + this.open = true;
  313 + this.title = "添加秒杀活动";
  314 + },
  315 + /** 修改按钮操作 */
  316 + handleUpdate(row) {
  317 + this.reset();
  318 + const id = row.id;
  319 + getSeckillActivity(id).then(response => {
  320 + var timeIdList = response.data.timeId.split(',')
  321 + this.form = response.data;
  322 + // 修改数据
  323 + this.form.startAndEndTime = [response.data.startTime, response.data.endTime];
  324 + this.form.timeId = timeIdList.map(item => parseInt(item))
  325 + this.form.skuIds = response.data.products.map(item => item.skuId);
  326 + this.form.products.forEach(product => {
  327 + // 获得对应的 SKU 信息
  328 + const sku = this.productSkus.find(item => item.id === product.skuId);
  329 + if (!sku) {
  330 + return;
  331 + }
  332 + // 设置商品信息
  333 + product.name = sku.name;
  334 + product.spuName = sku.spuName;
  335 + product.price = sku.price;
  336 + product.productStock = sku.stock;
  337 + this.$set(product,'seckillStock',product.stock);
  338 + product.seckillPrice = product.seckillPrice !== undefined ? product.seckillPrice / 100 : undefined;
  339 +
  340 + });
  341 + // 打开弹窗
  342 + this.open = true;
  343 + this.title = "修改限时折扣活动";
  344 + })
  345 + },
  346 + /** 提交按钮 */
  347 + submitForm() {
  348 + this.$refs["form"].validate(valid => {
  349 + if (!valid) {
  350 + return;
  351 + }
  352 + // 处理数据
  353 + const data = deepClone(this.form);
  354 + data.startTime = this.form.startAndEndTime[0];
  355 + data.endTime = this.form.startAndEndTime[1];
  356 + data.timeId = data.timeId.toString();
  357 + data.products.forEach(product => {
  358 + product.stock = product.seckillStock;
  359 + product.seckillPrice = product.seckillPrice !== undefined ? product.seckillPrice * 100 : undefined;
  360 + });
  361 + // 修改的提交
  362 + if (this.form.id != null) {
  363 + updateSeckillActivity(data).then(response => {
  364 + this.$modal.msgSuccess("修改成功");
  365 + this.open = false;
  366 + this.getList();
  367 + });
  368 + return;
  369 + }
  370 + // 添加的提交
  371 + createSeckillActivity(data).then(response => {
  372 + this.$modal.msgSuccess("新增成功");
  373 + this.open = false;
  374 + this.getList();
  375 + });
  376 + });
  377 + },
  378 + /** 关闭按钮操作 */
  379 + handleClose(row) {
  380 + const id = row.id;
  381 + this.$modal.confirm('是否确认关闭秒杀活动编号为"' + id + '"的数据项?').then(function () {
  382 + return closeSeckillActivity(id);
  383 + }).then(() => {
  384 + this.getList();
  385 + this.$modal.msgSuccess("关闭成功");
  386 + }).catch(() => { });
  387 + },
  388 + /** 删除按钮操作 */
  389 + handleDelete(row) {
  390 + const id = row.id;
  391 + this.$modal.confirm('是否确认删除秒杀活动编号为"' + id + '"的数据项?').then(function () {
  392 + return deleteSeckillActivity(id);
  393 + }).then(() => {
  394 + this.getList();
  395 + this.$modal.msgSuccess("删除成功");
  396 + }).catch(() => { });
  397 + },
  398 + /** 批量修改商品秒杀价,秒杀库存,每人限购数量 */
  399 + batchEditProduct(editType) {
  400 + const selectProducts = this.$refs.productsTable.selection;
  401 + if (selectProducts.length === 0) {
  402 + this.$modal.msgError("请选择需要修改的商品");
  403 + return;
  404 + }
  405 + let promptTitle = '请输入';
  406 + let regularPattern = /^[\s\S]*.*[^\s][\s\S]*$/; // 判断非空,且非空格
  407 + //限购数
  408 + if (editType === 'limitBuyCount') {
  409 + promptTitle = '限购数';
  410 + regularPattern = /^[0-9]*$/; //数字
  411 + }
  412 + //秒杀价
  413 + if (editType === 'seckillPrice') {
  414 + promptTitle = '秒杀价(元)';
  415 + regularPattern = /^[0-9]+(\.[0-9]{1,2})?$/; // 有一位或两位小数的正数
  416 + }
  417 + //秒杀库存
  418 + if (editType === 'seckillStock') {
  419 + promptTitle = '秒杀库存';
  420 + regularPattern = /^[0-9]*$/; //数字
  421 + }
  422 +
  423 + this.$prompt(promptTitle, '提示', {
  424 + confirmButtonText: '保存',
  425 + cancelButtonText: '取消',
  426 + inputPattern: regularPattern,
  427 + inputErrorMessage: promptTitle + '格式不正确'
  428 + }).then(({ value }) => {
  429 + if (editType === 'limitBuyCount') {
  430 + selectProducts.forEach((item) => {
  431 + item.limitBuyCount = value;
  432 + })
  433 + }
  434 + if (editType === 'seckillPrice') {
  435 + selectProducts.forEach((item) => {
  436 + item.seckillPrice = value;
  437 + })
  438 + }
  439 + if (editType === 'seckillStock') {
  440 + selectProducts.forEach((item) => {
  441 + item.seckillStock = value;
  442 + })
  443 + }
  444 + }).catch();
  445 + },
  446 + /** 当 Form 的 SKU 发生变化时 */
  447 + changeFormSku(skuIds) {
  448 + // 处理【新增】
  449 + skuIds.forEach(skuId => {
  450 + // 获得对应的 SKU 信息
  451 + const sku = this.productSkus.find(item => item.id === skuId);
  452 + if (!sku) {
  453 + return;
  454 + }
  455 + // 判断已存在,直接跳过
  456 + const product = this.form.products.find(item => item.skuId === skuId);
  457 + if (product) {
  458 + return;
  459 + }
  460 + this.form.products.push({
  461 + skuId: sku.id,
  462 + name: sku.name,
  463 + price: sku.price,
  464 + productStock: sku.stock,
  465 + spuId: sku.spuId,
  466 + spuName: sku.spuName,
  467 + limitBuyCount: 1,
  468 + seckillStock: sku.stock,
  469 + seckillPrice: sku.price,
  470 + });
  471 + });
  472 + // 处理【移除】
  473 + this.form.products.map((product, index) => {
  474 + if (!skuIds.includes(product.skuId)) {
  475 + this.form.products.splice(index, 1);
  476 + }
  477 + });
  478 + },
  479 + /** 移除 Form 的 SKU */
  480 + removeFormSku(skuId) {
  481 + this.form.skuIds.map((id, index) => {
  482 + if (skuId === id) {
  483 + this.form.skuIds.splice(index, 1);
  484 + }
  485 + });
  486 + this.changeFormSku(this.form.skuIds);
  487 + },
  488 + }
  489 +};
  490 +</script>
... ...
yudao-ui-admin/src/views/mall/promotion/seckill/seckillTime/index.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 操作工具栏 -->
  5 + <el-row :gutter="10" class="mb8">
  6 + <el-col :span="1.5">
  7 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
  8 + v-hasPermi="['promotion:seckill-time:create']">新增秒杀时段</el-button>
  9 + </el-col>
  10 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  11 + </el-row>
  12 +
  13 + <!-- 列表 -->
  14 + <el-table v-loading="loading" :data="list">
  15 + <el-table-column label="秒杀时段名称" align="center" prop="name" />
  16 + <el-table-column label="开始时间点" align="center" prop="startTime" width="180">
  17 + <template slot-scope="scope">
  18 + <span>{{ scope.row.startTime }}</span>
  19 + </template>
  20 + </el-table-column>
  21 + <el-table-column label="结束时间点" align="center" prop="endTime" width="180">
  22 + <template slot-scope="scope">
  23 + <span>{{ scope.row.endTime }}</span>
  24 + </template>
  25 + </el-table-column>
  26 + <el-table-column label="秒杀活动数量" align="center" prop="seckillActivityCount" />
  27 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  28 + <template slot-scope="scope">
  29 + <span>{{ parseTime(scope.row.createTime) }}</span>
  30 + </template>
  31 + </el-table-column>
  32 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  33 + <template slot-scope="scope">
  34 + <el-button size="mini" type="text" icon="el-icon-view" @click="handleOpenSeckillActivity(scope.row)">
  35 + 查看秒杀活动</el-button>
  36 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  37 + v-hasPermi="['promotion:seckill-time:update']">修改</el-button>
  38 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  39 + v-hasPermi="['promotion:seckill-time:delete']">删除</el-button>
  40 + </template>
  41 + </el-table-column>
  42 + </el-table>
  43 +
  44 + <!-- 对话框(添加 / 修改) -->
  45 + <el-dialog :title="title" :visible.sync="open" width="600px" v-dialogDrag append-to-body>
  46 + <el-form ref="form" :model="form" :rules="rules" label-width="140px">
  47 + <el-form-item label="秒杀场次名称" prop="name">
  48 + <el-input v-model="form.name" placeholder="请输入秒杀时段名称" clearable />
  49 + </el-form-item>
  50 + <el-form-item label="秒杀时间段" prop="startAndEndTime">
  51 + <el-time-picker is-range v-model="form.startAndEndTime" range-separator="至" start-placeholder="开始时间"
  52 + end-placeholder="结束时间" placeholder="选择时间范围" value-format="HH:mm:ss">
  53 + </el-time-picker>
  54 + </el-form-item>
  55 + </el-form>
  56 + <div slot="footer" class="dialog-footer">
  57 + <el-button type="primary" @click="submitForm">确 定</el-button>
  58 + <el-button @click="cancel">取 消</el-button>
  59 + </div>
  60 + </el-dialog>
  61 + </div>
  62 +</template>
  63 +
  64 +<script>
  65 +import { createSeckillTime, updateSeckillTime, deleteSeckillTime, getSeckillTime, getSeckillTimePage, exportSeckillTimeExcel, getSeckillTimeList } from "@/api/mall/promotion/seckillTime";
  66 +import router from "@/router";
  67 +import { deepClone } from "@/utils";
  68 +
  69 +export default {
  70 + name: "SeckillTime",
  71 + components: {
  72 + },
  73 + data() {
  74 + return {
  75 + // 遮罩层
  76 + loading: true,
  77 + // 导出遮罩层
  78 + exportLoading: false,
  79 + // 显示搜索条件
  80 + showSearch: true,
  81 + // 总条数
  82 + // total: 0,
  83 + // 秒杀时段列表
  84 + list: [],
  85 + // 弹出层标题
  86 + title: "",
  87 + // 是否显示弹出层
  88 + open: false,
  89 + // 表单参数
  90 + form: {},
  91 + // 表单校验
  92 + rules: {
  93 + name: [{ required: true, message: "秒杀时段名称不能为空", trigger: "blur" }],
  94 + startAndEndTime: [{ required: true, message: "秒杀时间段不能为空", trigger: "blur" }],
  95 + }
  96 + };
  97 + },
  98 + created() {
  99 + this.getList();
  100 + },
  101 + methods: {
  102 + /** 查询列表 */
  103 + getList() {
  104 + this.loading = true;
  105 + // 执行查询
  106 + getSeckillTimeList().then(response => {
  107 + this.list = response.data;
  108 + this.loading = false;
  109 + });
  110 + },
  111 + /** 取消按钮 */
  112 + cancel() {
  113 + this.open = false;
  114 + this.reset();
  115 + },
  116 + /** 表单重置 */
  117 + reset() {
  118 + this.form = {
  119 + id: undefined,
  120 + name: undefined,
  121 + startAndEndTime: undefined,
  122 + startTime: undefined,
  123 + endTime: undefined,
  124 + };
  125 + this.resetForm("form");
  126 + },
  127 + /** 搜索按钮操作 */
  128 + handleQuery() {
  129 + this.getList();
  130 + },
  131 + /** 重置按钮操作 */
  132 + resetQuery() {
  133 + this.resetForm("queryForm");
  134 + this.handleQuery();
  135 + },
  136 + /**查看当前秒杀时段的秒杀活动 */
  137 + handleOpenSeckillActivity(row) {
  138 + router.push({ name: 'SeckillActivity', params: { timeId: row.id } })
  139 + },
  140 + /** 新增按钮操作 */
  141 + handleAdd() {
  142 + this.reset();
  143 + this.open = true;
  144 + this.title = "添加秒杀时段";
  145 + },
  146 + /** 修改按钮操作 */
  147 + handleUpdate(row) {
  148 + this.reset();
  149 + const id = row.id;
  150 + getSeckillTime(id).then(response => {
  151 + response.data.startAndEndTime = [response.data.startTime, response.data.endTime]
  152 + this.form = response.data;
  153 + this.open = true;
  154 + this.title = "修改秒杀时段";
  155 + });
  156 + },
  157 + /** 提交按钮 */
  158 + submitForm() {
  159 + this.$refs["form"].validate(valid => {
  160 + console.log(valid, "是否通过");
  161 + if (!valid) {
  162 + return;
  163 + }
  164 + // 处理数据
  165 + const data = deepClone(this.form);
  166 + data.startTime = this.form.startAndEndTime[0];
  167 + data.endTime = this.form.startAndEndTime[1];
  168 + // 修改的提交
  169 + if (this.form.id != null) {
  170 + updateSeckillTime(data).then(response => {
  171 + this.$modal.msgSuccess("修改成功");
  172 + this.open = false;
  173 + this.getList();
  174 + });
  175 + return;
  176 + }
  177 + // 添加的提交
  178 + createSeckillTime(data).then(response => {
  179 + this.$modal.msgSuccess("新增成功");
  180 + this.open = false;
  181 + this.getList();
  182 + });
  183 + });
  184 + },
  185 + /** 删除按钮操作 */
  186 + handleDelete(row) {
  187 + const id = row.id;
  188 + this.$modal.confirm('是否确认删除秒杀时段编号为"' + id + '"的数据项?').then(function () {
  189 + return deleteSeckillTime(id);
  190 + }).then(() => {
  191 + this.getList();
  192 + this.$modal.msgSuccess("删除成功");
  193 + }).catch(() => { });
  194 + },
  195 + }
  196 +};
  197 +</script>
... ...