From a3904cff117999d0f91307d7a4f82872a75d1ff0 Mon Sep 17 00:00:00 2001 From: liujiang <569804566@qq.com> Date: Sun, 22 Jun 2025 22:31:55 +0800 Subject: [PATCH] =?UTF-8?q?master=EF=BC=9A=E6=A1=A3=E5=8F=A3=E6=8E=A8?= =?UTF-8?q?=E5=B9=BF=E8=90=A5=E9=94=80=E9=83=A8=E5=88=86=E8=B0=83=E6=95=B4?= =?UTF-8?q?=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/xkt/AdvertRoundController.java | 30 +++ .../advertRound/AdRoundStoreBoughtResVO.java | 47 ++++ .../AdRoundTypeRoundBoughtResVO.java | 47 ++++ .../vo/advertRound/AdRoundTypeRoundResVO.java | 47 ++++ .../advertRound/AdRoundStoreBoughtResDTO.java | 50 ++++ .../AdRoundTypeRoundBoughtResDTO.java | 51 ++++ .../advertRound/AdRoundTypeRoundResDTO.java | 47 ++++ .../xkt/service/IAdvertRoundService.java | 27 +- .../service/impl/AdvertRoundServiceImpl.java | 251 +++++++++++++++++- 9 files changed, 590 insertions(+), 7 deletions(-) create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundStoreBoughtResVO.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundTypeRoundBoughtResVO.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundTypeRoundResVO.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundStoreBoughtResDTO.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundTypeRoundBoughtResDTO.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundTypeRoundResDTO.java diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/AdvertRoundController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/AdvertRoundController.java index 403e2cdc6..0b3eb08d0 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/AdvertRoundController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/AdvertRoundController.java @@ -33,6 +33,13 @@ public class AdvertRoundController extends XktBaseController { final IAdvertRoundService advertRoundService; + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin,store')||@ss.hasSupplierSubRole()") + @ApiOperation(value = "获取当前系统时间", httpMethod = "GET", response = R.class) + @GetMapping("/sys-time") + public R sysTime() { + return R.ok(System.currentTimeMillis()); + } + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin,store')||@ss.hasSupplierSubRole()") @ApiOperation(value = "档口购买推广营销", httpMethod = "POST", response = R.class) @Log(title = "档口购买推广营销", businessType = BusinessType.INSERT) @@ -48,6 +55,29 @@ public class AdvertRoundController extends XktBaseController { return R.ok(BeanUtil.toBean(advertRoundService.getStoreAdInfo(storeId, advertId, showType), AdRoundStoreResVO.class)); } + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin,store')||@ss.hasSupplierSubRole()") + @ApiOperation(value = "获取当前推广所有轮次", httpMethod = "GET", response = R.class) + @GetMapping(value = "/rounds/{storeId}/{typeId}") + public R> getTypeRoundList(@PathVariable("storeId") Long storeId, @PathVariable("typeId") Long typeId) { + return R.ok(BeanUtil.copyToList(advertRoundService.getTypeRoundList(storeId, typeId), AdRoundTypeRoundResVO.class)); + } + + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin,store')||@ss.hasSupplierSubRole()") + @ApiOperation(value = "获取位置枚举的推广位当前轮次购买情况", httpMethod = "GET", response = R.class) + @GetMapping(value = "/position-bought/{typeId}/{roundId}/{storeId}") + public R> getTypeRoundBoughtInfo(@PathVariable("roundId") Long roundId, @PathVariable("storeId") Long storeId, + @PathVariable("typeId") Long typeId) { + return R.ok(BeanUtil.copyToList(advertRoundService.getTypeRoundBoughtInfo(storeId, typeId, roundId), AdRoundTypeRoundBoughtResVO.class)); + } + + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin,store')||@ss.hasSupplierSubRole()") + @ApiOperation(value = "当前档口已购推广列表", httpMethod = "GET", response = R.class) + @GetMapping(value = "/bought-record/{storeId}") + public R> getStoreBoughtRecord(@PathVariable("storeId") Long storeId) { + return R.ok(BeanUtil.copyToList(advertRoundService.getStoreBoughtRecord(storeId), AdRoundStoreBoughtResVO.class)); + } + + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin,store')||@ss.hasSupplierSubRole()") @ApiOperation(value = "获取当前最新的出价及设置的商品", httpMethod = "POST", response = R.class) @PostMapping(value = "/latest") diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundStoreBoughtResVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundStoreBoughtResVO.java new file mode 100644 index 000000000..f56d517a6 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundStoreBoughtResVO.java @@ -0,0 +1,47 @@ +package com.ruoyi.web.controller.xkt.vo.advertRound; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("档口购买的推广列表") +@Data +@Accessors(chain = true) +public class AdRoundStoreBoughtResVO { + + @ApiModelProperty(value = "广告ID") + private Long advertId; + @ApiModelProperty(value = "广告轮次ID") + private Integer roundId; + @ApiModelProperty(value = "广告类型ID") + private Integer typeId; + @ApiModelProperty(value = "广告类型名称") + private String typeName; + @ApiModelProperty(value = "推广档口ID") + private Long storeId; + @ApiModelProperty(value = "投放开始时间") + @JsonFormat(pattern = "MM月dd日", timezone = "GMT+8") + private Date startTime; + @ApiModelProperty(value = "投放结束时间") + @JsonFormat(pattern = "MM月dd日", timezone = "GMT+8") + private Date endTime; + @ApiModelProperty(value = "对象锁符号") + private String symbol; + @ApiModelProperty(value = "广告位置 A B C D E") + private String position; + @ApiModelProperty(value = "竞价状态") + private Integer biddingStatus; + @ApiModelProperty(value = "竞价状态名称及描述") + private String biddingStatusName; + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundTypeRoundBoughtResVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundTypeRoundBoughtResVO.java new file mode 100644 index 000000000..e0eef5e35 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundTypeRoundBoughtResVO.java @@ -0,0 +1,47 @@ +package com.ruoyi.web.controller.xkt.vo.advertRound; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("位置枚举的类型购买数据") +@Data +@Accessors(chain = true) +public class AdRoundTypeRoundBoughtResVO { + + @ApiModelProperty(value = "广告ID") + private Long advertId; + @ApiModelProperty(value = "广告轮次ID") + private Integer roundId; + @ApiModelProperty(value = "typeId") + private Integer typeId; + @ApiModelProperty(value = "广告位置 A B C D E") + private String position; + @ApiModelProperty(value = "起拍价格") + private BigDecimal startPrice; + @ApiModelProperty(value = "推广档口出价") + private BigDecimal payPrice; + @ApiModelProperty(value = "投放开始时间") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date startTime; + @ApiModelProperty(value = "投放结束时间") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date endTime; + @ApiModelProperty(value = "竞价状态") + private Integer biddingStatus; + @ApiModelProperty(value = "竞价状态名称") + private String biddingStatusName; + @ApiModelProperty(value = "对象锁符号") + private String symbol; + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundTypeRoundResVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundTypeRoundResVO.java new file mode 100644 index 000000000..80d26d5a9 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/advertRound/AdRoundTypeRoundResVO.java @@ -0,0 +1,47 @@ +package com.ruoyi.web.controller.xkt.vo.advertRound; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("推广类型所有轮次") +@Data +@Accessors(chain = true) +public class AdRoundTypeRoundResVO { + + @ApiModelProperty(value = "广告ID") + private Long advertId; + @ApiModelProperty(value = "广告轮次ID") + private Integer roundId; + @ApiModelProperty(value = "投放开始时间") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date startTime; + @ApiModelProperty(value = "投放开始时间星期几") + private String startWeekDay; + @ApiModelProperty(value = "投放结束时间") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date endTime; + @ApiModelProperty(value = "投放结束时间星期几") + private String endWeekDay; + @ApiModelProperty(value = "轮次持续时间") + private Integer durationDay; + @ApiModelProperty(value = "起拍价格") + private BigDecimal startPrice; + @ApiModelProperty(value = "对象锁符号") + private String symbol; + @ApiModelProperty(value = "竞价状态") + private Integer biddingStatus; + @ApiModelProperty(value = "竞价状态名称") + private String biddingStatusName; + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundStoreBoughtResDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundStoreBoughtResDTO.java new file mode 100644 index 000000000..1aca06662 --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundStoreBoughtResDTO.java @@ -0,0 +1,50 @@ +package com.ruoyi.xkt.dto.advertRound; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.Date; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("档口购买的推广列表") +@Data +@Accessors(chain = true) +public class AdRoundStoreBoughtResDTO { + + @ApiModelProperty(value = "推广轮次ID") + private Long advertRoundId; + @ApiModelProperty(value = "广告ID") + private Long advertId; + @ApiModelProperty(value = "广告轮次ID") + private Integer roundId; + @ApiModelProperty(value = "广告类型ID") + private Integer typeId; + @ApiModelProperty(value = "广告类型名称") + private String typeName; + @ApiModelProperty(value = "推广档口ID") + private Long storeId; + @ApiModelProperty(value = "1 时间范围 2位置枚举") + private Integer showType; + @ApiModelProperty(value = "投放开始时间") + @JsonFormat(pattern = "MM月dd日", timezone = "GMT+8") + private Date startTime; + @ApiModelProperty(value = "投放结束时间") + @JsonFormat(pattern = "MM月dd日", timezone = "GMT+8") + private Date endTime; + @ApiModelProperty(value = "对象锁符号") + private String symbol; + @ApiModelProperty(value = "广告位置 A B C D E") + private String position; + @ApiModelProperty(value = "竞价状态") + private Integer biddingStatus; + @ApiModelProperty(value = "竞价状态名称及描述") + private String biddingStatusName; + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundTypeRoundBoughtResDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundTypeRoundBoughtResDTO.java new file mode 100644 index 000000000..9b69e0f8c --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundTypeRoundBoughtResDTO.java @@ -0,0 +1,51 @@ +package com.ruoyi.xkt.dto.advertRound; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("位置枚举的类型购买数据") +@Data +@Accessors(chain = true) +public class AdRoundTypeRoundBoughtResDTO { + + @ApiModelProperty(value = "推广轮次ID") + private Long advertRoundId; + @ApiModelProperty(value = "广告ID") + private Long advertId; + @ApiModelProperty(value = "广告轮次ID") + private Integer roundId; + @ApiModelProperty(value = "typeId") + private Integer typeId; + @ApiModelProperty(value = "广告位置 A B C D E") + private String position; + @ApiModelProperty(value = "档口ID") + private Long storeId; + @ApiModelProperty(value = "起拍价格") + private BigDecimal startPrice; + @ApiModelProperty(value = "推广档口出价") + private BigDecimal payPrice; + @ApiModelProperty(value = "投放开始时间") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date startTime; + @ApiModelProperty(value = "投放结束时间") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date endTime; + @ApiModelProperty(value = "竞价状态") + private Integer biddingStatus; + @ApiModelProperty(value = "竞价状态名称") + private String biddingStatusName; + @ApiModelProperty(value = "对象锁符号") + private String symbol; + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundTypeRoundResDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundTypeRoundResDTO.java new file mode 100644 index 000000000..ad82271a4 --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundTypeRoundResDTO.java @@ -0,0 +1,47 @@ +package com.ruoyi.xkt.dto.advertRound; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("推广类型所有轮次") +@Data +@Accessors(chain = true) +public class AdRoundTypeRoundResDTO { + + @ApiModelProperty(value = "广告ID") + private Long advertId; + @ApiModelProperty(value = "广告轮次ID") + private Integer roundId; + @ApiModelProperty(value = "投放开始时间") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date startTime; + @ApiModelProperty(value = "投放开始时间星期几") + private String startWeekDay; + @ApiModelProperty(value = "投放结束时间") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date endTime; + @ApiModelProperty(value = "投放结束时间星期几") + private String endWeekDay; + @ApiModelProperty(value = "轮次持续时间") + private Integer durationDay; + @ApiModelProperty(value = "起拍价格") + private BigDecimal startPrice; + @ApiModelProperty(value = "对象锁符号") + private String symbol; + @ApiModelProperty(value = "竞价状态") + private Integer biddingStatus; + @ApiModelProperty(value = "竞价状态名称") + private String biddingStatusName; + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/IAdvertRoundService.java b/xkt/src/main/java/com/ruoyi/xkt/service/IAdvertRoundService.java index 94d00ddb0..97b854367 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/IAdvertRoundService.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/IAdvertRoundService.java @@ -34,7 +34,6 @@ public interface IAdvertRoundService { /** * 初始化每天购买广告的截止时间 - * */ void saveAdvertDeadlineToRedis(); @@ -113,4 +112,30 @@ public interface IAdvertRoundService { */ String getRejectReason(Long advertRoundId); + /** + * 获取推广类型所有轮次 + * + * @param storeId 档口ID + * @param typeId 推广类型ID + * @return List + */ + List getTypeRoundList(Long storeId, Long typeId); + + /** + * 位置枚举的推广位档口购买情况 + * + * @param storeId 档口ID + * @param typeId 类型ID + * @param roundId 轮次ID + * @return List + */ + List getTypeRoundBoughtInfo(Long storeId, Long typeId, Long roundId); + + /** + * 档口购买推广轮次列表 + * + * @param storeId 档口ID + * @return List + */ + List getStoreBoughtRecord(Long storeId); } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/AdvertRoundServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/AdvertRoundServiceImpl.java index d60430766..8cfb27337 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/AdvertRoundServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/AdvertRoundServiceImpl.java @@ -176,6 +176,243 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { return storeProdList.stream().map(x -> new AdRoundSetProdResDTO().setStoreProdId(x.getId()).setProdArtNum(x.getProdArtNum())).collect(Collectors.toList()); } + /** + * 获取推广类型所有轮次 + * + * @param typeId 推广类型ID + * @param storeId 档口ID + * @return List + */ + @Override + @Transactional(readOnly = true) + public List getTypeRoundList(Long storeId, Long typeId) { + final LocalTime now = LocalTime.now(); + // 当前时间 是否在 晚上22:00:00 到 晚上23:59:59之间 决定 biddingStatus 和 biddingTempStatus 用那一个字段 + boolean tenClockAfter = now.isAfter(LocalTime.of(22, 0, 0)) && now.isBefore(LocalTime.of(23, 59, 59)); + // 获取当前 typeId 所有 正在投放 和 待投放的推广轮次 + List advertRoundList = this.advertRoundMapper.selectList(new LambdaQueryWrapper() + .eq(AdvertRound::getDelFlag, Constants.UNDELETED).eq(AdvertRound::getTypeId, typeId) + .in(AdvertRound::getLaunchStatus, Arrays.asList(AdLaunchStatus.LAUNCHING.getValue(), AdLaunchStatus.UN_LAUNCH.getValue()))); + if (CollectionUtils.isEmpty(advertRoundList)) { + return new ArrayList<>(); + } + // 当天 + final Date voucherDate = java.sql.Date.valueOf(LocalDate.now()); + // 第一轮结束投放时间 + final Date firstRoundEndTime = advertRoundList.stream().filter(x -> x.getRoundId().equals(AdRoundType.PLAY_ROUND.getValue())) + .max(Comparator.comparing(AdvertRound::getEndTime)) + .orElseThrow(() -> new ServiceException("获取推广结束时间失败,请联系客服!", HttpStatus.ERROR)).getEndTime(); + // 如果当前非第一轮最后一天,则展示前3轮;如果当前是第一轮最后一天,则展示第2到第4轮。 + advertRoundList = voucherDate.before(firstRoundEndTime) + ? advertRoundList.stream().filter(x -> !Objects.equals(x.getRoundId(), AdRoundType.FOURTH_ROUND.getValue())).collect(Collectors.toList()) + : advertRoundList.stream().filter(x -> !Objects.equals(x.getRoundId(), AdRoundType.PLAY_ROUND.getValue())).collect(Collectors.toList()); + Integer minRoundId = advertRoundList.stream().min(Comparator.comparing(AdvertRound::getRoundId)) + .orElseThrow(() -> new ServiceException("获取最小推广轮次失败,请联系客服!", HttpStatus.ERROR)).getRoundId(); + if (CollectionUtils.isEmpty(advertRoundList)) { + return new ArrayList<>(); + } + // 该档口在这些轮次竞价失败的记录 + List recordList = this.advertRoundRecordMapper.selectList(new LambdaQueryWrapper() + .eq(AdvertRoundRecord::getDelFlag, Constants.UNDELETED).eq(AdvertRoundRecord::getTypeId, typeId) + .eq(AdvertRoundRecord::getStoreId, storeId).eq(AdvertRoundRecord::getVoucherDate, voucherDate) + .in(AdvertRoundRecord::getAdvertRoundId, advertRoundList.stream().map(AdvertRound::getId).collect(Collectors.toList()))); + Map> roundRecordMap = recordList.stream().collect(Collectors.groupingBy(AdvertRoundRecord::getRoundId)); + List resList = new ArrayList<>(); + final Date date = new Date(); + advertRoundList.stream().collect(Collectors.groupingBy(AdvertRound::getRoundId)) + .forEach((roundId, list) -> { + AdvertRound advertRound = list.get(0); + Integer durationDay = calculateDurationDay(advertRound.getStartTime(), advertRound.getEndTime(), Boolean.TRUE); + AdRoundTypeRoundResDTO typeRoundResDTO = new AdRoundTypeRoundResDTO().setAdvertId(advertRound.getAdvertId()).setRoundId(advertRound.getRoundId()) + .setSymbol(advertRound.getSymbol()).setStartTime(advertRound.getStartTime()).setEndTime(advertRound.getEndTime()) + .setStartWeekDay(getDayOfWeek(advertRound.getStartTime())).setEndWeekDay(getDayOfWeek(advertRound.getEndTime())).setDurationDay(durationDay); + // 展示类型 为时间范围 则,修改价格并显示每一轮竞价状态 + if (Objects.equals(advertRound.getShowType(), AdShowType.TIME_RANGE.getValue())) { + // 只有时间范围类型才显示起始价格 + typeRoundResDTO.setStartPrice(advertRound.getStartPrice()); + // 只有播放轮才按照时间计算折扣价 + if (Objects.equals(advertRound.getRoundId(), AdRoundType.PLAY_ROUND.getValue())) { + // 根据当前日期与截止日期的占比修改推广价格 + final BigDecimal curStartPrice = BigDecimal.valueOf(calculateDurationDay(date, advertRound.getEndTime(), Boolean.FALSE)) + .divide(BigDecimal.valueOf(durationDay), 10, RoundingMode.DOWN).multiply(advertRound.getStartPrice()) + .setScale(0, RoundingMode.DOWN); + typeRoundResDTO.setStartPrice(curStartPrice); + } + // 当前档口购买的轮次 + AdvertRound boughtRound = list.stream().filter(x -> Objects.equals(x.getStoreId(), storeId)).findFirst().orElse(null); + if (ObjectUtils.isNotEmpty(boughtRound)) { + // 如果是最近的播放轮次,且当前时间在 晚上10:00:01 之后到 当天23:59:59 都显示 biddingTempStatus 字段 + Integer biddingStatus = tenClockAfter && Objects.equals(typeRoundResDTO.getRoundId(), minRoundId) + ? boughtRound.getBiddingTempStatus() : boughtRound.getBiddingStatus(); + typeRoundResDTO.setBiddingStatus(biddingStatus); + typeRoundResDTO.setBiddingStatusName(AdBiddingStatus.of(biddingStatus).getLabel()); + } else { + // 当前档口在今天购买失败的轮次 + List boughtFailList = roundRecordMap.get(roundId); + if (CollectionUtils.isNotEmpty(boughtFailList)) { + typeRoundResDTO.setBiddingStatus(boughtFailList.get(0).getBiddingStatus()); + typeRoundResDTO.setBiddingStatusName(AdBiddingStatus.of(boughtFailList.get(0).getBiddingStatus()).getLabel()); + } + } + } + resList.add(typeRoundResDTO); + }); + return resList; + } + + /** + * 位置枚举的推广位档口购买情况 + * + * @param storeId 档口ID + * @param typeId 类型ID + * @param roundId 轮次ID + * @return List + */ + @Override + @Transactional(readOnly = true) + public List getTypeRoundBoughtInfo(Long storeId, Long typeId, Long roundId) { + // 档口在当前类型,当前轮次 购买的位置枚举推广位列表 + List advertRoundList = this.advertRoundMapper.selectList(new LambdaQueryWrapper() + .eq(AdvertRound::getDelFlag, Constants.UNDELETED).eq(AdvertRound::getTypeId, typeId).eq(AdvertRound::getRoundId, roundId) + .in(AdvertRound::getLaunchStatus, Arrays.asList(AdLaunchStatus.LAUNCHING.getValue(), AdLaunchStatus.UN_LAUNCH.getValue()))); + if (CollectionUtils.isEmpty(advertRoundList)) { + return new ArrayList<>(); + } + final LocalTime now = LocalTime.now(); + // 当前时间 是否在 晚上22:00:00 到 晚上23:59:59之间 决定 biddingStatus 和 biddingTempStatus 用那一个字段 + boolean tenClockAfter = now.isAfter(LocalTime.of(22, 0, 0)) && now.isBefore(LocalTime.of(23, 59, 59)); + List resList = advertRoundList.stream().map(advertRound -> { + AdRoundTypeRoundBoughtResDTO bought = new AdRoundTypeRoundBoughtResDTO().setTypeId(advertRound.getTypeId()).setAdvertRoundId(advertRound.getId()) + .setAdvertId(advertRound.getAdvertId()).setRoundId(advertRound.getRoundId()).setPosition(advertRound.getPosition()) + .setStartPrice(advertRound.getStartPrice()).setPayPrice(advertRound.getPayPrice()).setStoreId(storeId) + .setStartTime(advertRound.getStartTime()).setEndTime(advertRound.getEndTime()).setSymbol(advertRound.getSymbol()); + // 当前档口购买的推广位置 + if (Objects.equals(advertRound.getStoreId(), storeId)) { + Integer biddingStatus = tenClockAfter ? advertRound.getBiddingTempStatus() : advertRound.getBiddingStatus(); + bought.setBiddingStatus(biddingStatus); + bought.setBiddingStatusName(AdBiddingStatus.of(biddingStatus).getLabel()); + } + return bought; + }).collect(Collectors.toList()); + // 档口未竞价成功的位置 + List unBoughtPositionList = advertRoundList.stream().filter(x -> ObjectUtils.isNotEmpty(x.getStoreId()) && !Objects.equals(x.getStoreId(), storeId)) + .map(x -> x.getPosition()).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(unBoughtPositionList)) { + return resList; + } + // 当天竞价失败的位置 + List recordList = this.advertRoundRecordMapper.selectList(new LambdaQueryWrapper() + .eq(AdvertRoundRecord::getDelFlag, Constants.UNDELETED).eq(AdvertRoundRecord::getTypeId, typeId) + .eq(AdvertRoundRecord::getRoundId, roundId).eq(AdvertRoundRecord::getStoreId, storeId) + .eq(AdvertRoundRecord::getVoucherDate, java.sql.Date.valueOf(LocalDate.now())) + .in(AdvertRoundRecord::getPosition, unBoughtPositionList)); + if (CollectionUtils.isEmpty(recordList)) { + return resList; + } + // 竞价失败的位置 + Map bindingFailMap = recordList.stream().collect(Collectors.toMap(x -> x.getAdvertRoundId(), x -> x.getBiddingStatus(), (s1, s2) -> s2)); + resList.forEach(x -> { + Integer biddingStatus = bindingFailMap.get(x.getAdvertRoundId()); + if (ObjectUtils.isNotEmpty(biddingStatus)) { + x.setBiddingStatus(biddingStatus); + x.setBiddingStatusName(AdBiddingStatus.of(biddingStatus).getLabel()); + } + }); + return resList; + } + + /** + * 档口购买推广轮次列表 + * + * @param storeId 档口ID + * @return List + */ + @Override + @Transactional(readOnly = true) + public List getStoreBoughtRecord(Long storeId) { + final LocalTime now = LocalTime.now(); + // 当前时间 是否在 晚上22:00:00 到 晚上23:59:59之间 决定 biddingStatus 和 biddingTempStatus 用那一个字段 + boolean tenClockAfter = now.isAfter(LocalTime.of(22, 0, 0)) && now.isBefore(LocalTime.of(23, 59, 59)); + // 当天 + final Date voucherDate = java.sql.Date.valueOf(LocalDate.now()); + // 获取当前所有 正在投放 和 待投放的推广轮次 + List allRoundList = this.advertRoundMapper.selectList(new LambdaQueryWrapper() + .eq(AdvertRound::getDelFlag, Constants.UNDELETED) + .in(AdvertRound::getLaunchStatus, Arrays.asList(AdLaunchStatus.LAUNCHING.getValue(), AdLaunchStatus.UN_LAUNCH.getValue()))); + if (CollectionUtils.isEmpty(allRoundList)) { + return new ArrayList<>(); + } + // 当前 档口 在所有 待投放 及 投放中 的推广轮次竞价失败记录 + List allRecordList = this.advertRoundRecordMapper.selectList(new LambdaQueryWrapper() + .eq(AdvertRoundRecord::getDelFlag, Constants.UNDELETED).eq(AdvertRoundRecord::getStoreId, storeId) + .eq(AdvertRoundRecord::getVoucherDate, voucherDate) + .in(AdvertRoundRecord::getAdvertRoundId, allRoundList.stream().map(AdvertRound::getId).collect(Collectors.toList()))); + // 按照advertId进行分组,取最小的roundId列表 + Map> minRoundIdMap = allRoundList.stream().collect(Collectors.groupingBy(AdvertRound::getAdvertId, + Collectors.mapping(AdvertRound::getRoundId, Collectors.minBy(Comparator.comparing(Integer::intValue))))); + // 最小的roundId列表 + List roundIdList = minRoundIdMap.values().stream().filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList()); + // 筛选档口 所有的 已购买 推广位数据 + List boughtRoundList = allRoundList.stream().filter(x -> Objects.equals(x.getStoreId(), storeId)) + .map(x -> { + // 如果是最近的播放轮次,且当前时间在 晚上10:00:01 之后到 当天23:59:59 都显示 biddingTempStatus 字段 + final Integer biddingStatus = tenClockAfter && roundIdList.contains(x.getRoundId()) ? x.getBiddingTempStatus() : x.getBiddingStatus(); + return BeanUtil.toBean(x, AdRoundStoreBoughtResDTO.class).setAdvertRoundId(x.getId()).setBiddingStatus(biddingStatus) + .setBiddingStatusName(AdBiddingStatus.of(biddingStatus).getLabel()).setTypeName(AdType.of(x.getTypeId()).getLabel()) + // 如果是时间范围则不返回position + .setPosition(Objects.equals(x.getShowType(), AdShowType.TIME_RANGE.getValue()) ? null : x.getPosition()); + }) + .collect(Collectors.toList()); + // showType 为 时间范围的 每一轮最高的出价map + Map timeRangeRoundMaxPriceMap = allRoundList.stream() + .filter(x -> Objects.equals(x.getShowType(), AdShowType.TIME_RANGE.getValue())) + .filter(x -> ObjectUtils.isNotEmpty(x.getPayPrice())) + .collect(Collectors + .groupingBy(AdvertRound::getRoundId, Collectors + .mapping(AdvertRound::getPayPrice, Collectors.reducing(BigDecimal.ZERO, BigDecimal::max)))); + // showType 为 位置枚举的 每一个位置最高出价的 map + Map positionEnumMaxPriceMap = allRoundList.stream() + .filter(x -> Objects.equals(x.getShowType(), AdShowType.POSITION_ENUM.getValue())) + .filter(x -> ObjectUtils.isNotEmpty(x.getPayPrice())) + .collect(Collectors.toMap(AdvertRound::getId, AdvertRound::getPayPrice)); + // 已购买的 时间范围播放轮次 的roundId列表 + final List boughtTimeRangeRoundIdList = boughtRoundList.stream().filter(x -> Objects.equals(x.getShowType(), AdShowType.TIME_RANGE.getValue())) + .map(AdRoundStoreBoughtResDTO::getRoundId).collect(Collectors.toList()); + // 已购买的 位置枚举 的 advertRoundId 列表 + final List boughtPositionAdvertRoundIdList = boughtRoundList.stream().filter(x -> Objects.equals(x.getShowType(), AdShowType.POSITION_ENUM.getValue())) + .map(AdRoundStoreBoughtResDTO::getAdvertRoundId).collect(Collectors.toList()); + // 购买失败的 时间范围播放轮次的 列表 + Map unBoughtTimeRangeMap = allRecordList.stream() + .filter(x -> Objects.equals(x.getShowType(), AdShowType.TIME_RANGE.getValue())) + .filter(x -> !boughtTimeRangeRoundIdList.contains(x.getRoundId())) + .collect(Collectors.toMap(AdvertRoundRecord::getRoundId, Function.identity(), + BinaryOperator.maxBy(Comparator.comparingLong(AdvertRoundRecord::getId)))); + // 购买失败的 位置枚举播放轮次的 列表 + Map unBoughtPositionMap = allRecordList.stream() + .filter(x -> Objects.equals(x.getShowType(), AdShowType.POSITION_ENUM.getValue())) + .filter(x -> !boughtPositionAdvertRoundIdList.contains(x.getAdvertRoundId())) + .collect(Collectors.toMap(AdvertRoundRecord::getAdvertRoundId, Function.identity(), + BinaryOperator.maxBy(Comparator.comparingLong(AdvertRoundRecord::getId)))); + if (MapUtils.isNotEmpty(unBoughtTimeRangeMap)) { + unBoughtTimeRangeMap.forEach((roundId, record) -> { + boughtRoundList.add(BeanUtil.toBean(record, AdRoundStoreBoughtResDTO.class).setPosition(null) + .setTypeName(AdType.of(record.getTypeId()).getLabel()) + .setBiddingStatusName(AdBiddingStatus.of(record.getBiddingStatus()).getLabel() + + ",最新出价:" + timeRangeRoundMaxPriceMap.get(record.getRoundId()))); + }); + } + if (MapUtils.isNotEmpty(unBoughtPositionMap)) { + unBoughtPositionMap.forEach((advertRoundId, record) -> { + boughtRoundList.add(BeanUtil.toBean(record, AdRoundStoreBoughtResDTO.class) + .setTypeName(AdType.of(record.getTypeId()).getLabel()) + .setBiddingStatusName(AdBiddingStatus.of(record.getBiddingStatus()).getLabel() + + ",最新出价:" + positionEnumMaxPriceMap.get(record.getAdvertRoundId())) + ); + }); + } + return boughtRoundList; + } + /** * 根据广告ID获取推广轮次列表,并返回当前档口在这些推广轮次的数据 @@ -237,7 +474,7 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { List rangeDTOList = advertRoundList.stream().map(x -> new AdRoundStoreResDTO.ADRSRoundTimeRangeDTO() .setAdvertId(x.getAdvertId()).setRoundId(x.getRoundId()).setSymbol(x.getSymbol()).setStartTime(x.getStartTime()).setEndTime(x.getEndTime()) .setStartWeekDay(getDayOfWeek(x.getStartTime())).setEndWeekDay(getDayOfWeek(x.getEndTime())).setStartPrice(x.getStartPrice()) - .setDurationDay(calculateDurationDay(x.getStartTime(), x.getEndTime()))) + .setDurationDay(calculateDurationDay(x.getStartTime(), x.getEndTime(), Boolean.TRUE))) .distinct().collect(Collectors.toList()); // 当前档口购买的推广轮次 Map boughtRoundMap = advertRoundList.stream().filter(x -> Objects.equals(x.getStoreId(), storeId)) @@ -258,7 +495,7 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { // 只有播放轮才按照时间计算折扣价 if (Objects.equals(x.getRoundId(), AdRoundType.PLAY_ROUND.getValue())) { // 根据当前日期与截止日期的占比修改推广价格 - final BigDecimal curStartPrice = BigDecimal.valueOf(calculateDurationDay(date, x.getEndTime())) + final BigDecimal curStartPrice = BigDecimal.valueOf(calculateDurationDay(date, x.getEndTime(), Boolean.TRUE)) .divide(BigDecimal.valueOf(x.getDurationDay()), 10, RoundingMode.DOWN).multiply(x.getStartPrice()) .setScale(0, RoundingMode.DOWN); x.setStartPrice(curStartPrice); @@ -668,6 +905,7 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { return advertRound.getRejectReason(); } + /** * 通过定时任务往redis中放当前推广位 当前播放轮 或 即将播放轮 的截止时间;每晚12:05:00执行 * 比如:5.1 - 5.3 @@ -795,14 +1033,15 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { /** * 计算两天之间相差多少天 * - * @param startDate 开始日期 - * @param endDate 截止日期 + * @param startDate 开始日期 + * @param endDate 截止日期 + * @param isContainToday true 包含今天的时间间隔 false 不包含 * @return diffDay */ - public static int calculateDurationDay(Date startDate, Date endDate) { + public static int calculateDurationDay(Date startDate, Date endDate, Boolean isContainToday) { LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); LocalDate end = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); - return (int) start.until(end, ChronoUnit.DAYS) + 1; + return (int) start.until(end, ChronoUnit.DAYS) + (isContainToday ? 1 : 0); } /**