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 6ba1f5a65..d0aa8ebad 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 @@ -43,16 +43,18 @@ public class AdvertRoundController extends XktBaseController { /** - * 根据类型查询当前档口的推广营销数据 + * 根据广告ID获取推广轮次列表,并返回当前档口在这些推广轮次的数据 */ - @ApiOperation(value = "根据类型查询当前档口的推广营销数据", httpMethod = "GET", response = R.class) - @GetMapping(value = "/{typeId}/{storeId}") - public R getStoreAdInfo(@PathVariable("typeId") Integer typeId, + @ApiOperation(value = "根据广告ID获取推广轮次列表,并返回当前档口在这些推广轮次的数据", httpMethod = "GET", response = R.class) + @GetMapping(value = "/{advertId}/{storeId}/{typeId}") + public R getStoreAdInfo(@PathVariable("advertId") Long advertId, + @PathVariable("typeId") Integer typeId, @PathVariable("storeId") Long storeId) { - return R.ok(BeanUtil.toBean(advertRoundService.getStoreAdInfo(storeId, typeId), AdRoundStoreResVO.class)); + return R.ok(BeanUtil.toBean(advertRoundService.getStoreAdInfo(storeId, advertId, typeId), AdRoundStoreResVO.class)); } + @GetMapping("/test") public void test() throws ParseException { advertRoundService.saveAdvertDeadlineToRedis(); @@ -62,8 +64,6 @@ public class AdvertRoundController extends XktBaseController { // TODO 退订 - // TODO 每晚定时任务 调整 推广营销的offerStatus - // TODO 获取最受欢迎推广位8个,固定不动了 @@ -73,8 +73,4 @@ public class AdvertRoundController extends XktBaseController { - - - - } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ShoppingCartController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ShoppingCartController.java index 030222c67..bb818bdde 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ShoppingCartController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ShoppingCartController.java @@ -6,10 +6,7 @@ import com.ruoyi.common.core.controller.XktBaseController; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.page.Page; import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.web.controller.xkt.vo.userShoppingCart.ShopCartDetailResVO; -import com.ruoyi.web.controller.xkt.vo.userShoppingCart.ShopCartEditVO; -import com.ruoyi.web.controller.xkt.vo.userShoppingCart.ShopCartPageVO; -import com.ruoyi.web.controller.xkt.vo.userShoppingCart.ShopCartVO; +import com.ruoyi.web.controller.xkt.vo.userShoppingCart.*; import com.ruoyi.xkt.dto.userShoppingCart.ShopCartPageDTO; import com.ruoyi.xkt.dto.userShoppingCart.ShopCartPageResDTO; import com.ruoyi.xkt.dto.userShoppingCart.ShoppingCartDTO; @@ -69,15 +66,24 @@ public class ShoppingCartController extends XktBaseController { } /** - * 用户进货车列表点击编辑 + * 用户进货车列表点击编辑获取数据 */ @PreAuthorize("@ss.hasPermi('system:cart:list')") - @ApiOperation(value = "用户进货车列表点击编辑", httpMethod = "GET", response = R.class) + @ApiOperation(value = "用户进货车列表点击编辑获取数据", httpMethod = "GET", response = R.class) @GetMapping("/{shoppingCartId}") public R getInfo(@PathVariable Long shoppingCartId) { return R.ok(BeanUtil.toBean(shopCartService.getInfo(shoppingCartId), ShopCartDetailResVO.class)); } + /** + * 根据storeProdId获取进货车详情 + */ + @ApiOperation(value = "根据storeProdId获取进货车详情", httpMethod = "GET", response = R.class) + @GetMapping("/storeProdId/{storeProdId}") + public R getByStoreProdId(@PathVariable Long storeProdId) { + return R.ok(BeanUtil.toBean(shopCartService.getByStoreProdId(storeProdId), ShopCartResVO.class)); + } + /** * 用户删除进货车商品 @@ -91,4 +97,5 @@ public class ShoppingCartController extends XktBaseController { } + } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/StoreProductController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/StoreProductController.java index 2f3f320e1..0269ae6aa 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/StoreProductController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/StoreProductController.java @@ -91,10 +91,28 @@ public class StoreProductController extends XktBaseController { return R.ok(BeanUtil.toBean(storeProdService.selectStoreProductByStoreProdId(storeProdId), StoreProdResVO.class)); } + /** + * APP获取档口商品详细信息 + */ + @ApiOperation(value = "APP获取档口商品详细信息", httpMethod = "GET", response = R.class) + @GetMapping(value = "/app/detail/{storeProdId}") + public R getAppInfo(@PathVariable("storeProdId") Long storeProdId) { + return R.ok(BeanUtil.toBean(storeProdService.getAppInfo(storeProdId), StoreProdAppResVO.class)); + } + + + /** + * 获取档口商品颜色及sku等 + */ + @ApiOperation(value = "获取档口商品颜色及sku等", httpMethod = "GET", response = R.class) + @GetMapping(value = "/sku/{storeProdId}") + public R getSkuList(@PathVariable("storeProdId") Long storeProdId) { + return R.ok(BeanUtil.toBean(storeProdService.getSkuList(storeProdId), StoreProdSkuResVO.class)); + } + /** * 新增档口商品 */ -// @PreAuthorize("@ss.hasPermi('system:product:add')") @Log(title = "档口商品", businessType = BusinessType.INSERT) @ApiOperation(value = "新增档口商品", httpMethod = "POST", response = R.class) @PostMapping diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/store/StoreAppResVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/store/StoreAppResVO.java index bcbbc111d..5ba8c59e4 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/store/StoreAppResVO.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/store/StoreAppResVO.java @@ -15,6 +15,8 @@ import java.util.List; @Data public class StoreAppResVO { + @ApiModelProperty(value = "档口头像") + private String storeLogo; @ApiModelProperty(value = "档口ID") private Long storeId; @ApiModelProperty(value = "档口名称") diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/storeProd/StoreProdAppResVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/storeProd/StoreProdAppResVO.java new file mode 100644 index 000000000..6637fc402 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/storeProd/StoreProdAppResVO.java @@ -0,0 +1,104 @@ +package com.ruoyi.web.controller.xkt.vo.storeProd; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("档口商品APP详情") +@Data +public class StoreProdAppResVO { + + @ApiModelProperty(value = "档口商品名称") + private Long storeProdId; + @ApiModelProperty(value = "档口ID") + private Long storeId; + @ApiModelProperty(value = "档口商品名称") + private String prodName; + @ApiModelProperty(value = "商品货号") + private String prodArtNum; + @ApiModelProperty(value = "商品标题") + private String prodTitle; + @ApiModelProperty(value = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date createTime; + @ApiModelProperty(value = "是否已收藏商品") + private Boolean collectProd; + @ApiModelProperty(value = "最低的商品价格") + private BigDecimal minPrice; + @ApiModelProperty(value = "规格") + private String specification; + @ApiModelProperty(value = "商品标签列表") + private List tagList; + @ApiModelProperty(value = "档口文件列表") + private List fileList; + @ApiModelProperty(value = "档口类目属性列表") + private List cateAttrList; + @ApiModelProperty(value = "档口服务承诺") + private StoreProdSvcVO svc; + @ApiModelProperty(value = "详情内容") + private StoreProdDetailVO detail; + + @Data + @ApiModel(value = "档口商品文件") + public static class StoreProdFileVO { + @ApiModelProperty(value = "文件名称") + private String fileName; + @ApiModelProperty(value = "文件路径") + private String fileUrl; + @ApiModelProperty(value = "文件大小") + private BigDecimal fileSize; + @ApiModelProperty(value = "文件类型 1商品主图 2商品主图视频 3下载图片包") + private Integer fileType; + @ApiModelProperty(value = "排序") + private Integer orderNum; + } + + @Data + @ApiModel(value = "档口商品类目属性") + public static class StoreProdCateAttrVO { + @ApiModelProperty(value = "系统设置类目") + private String dictType; + @ApiModelProperty(value = "系统设置类目值") + private String dictValue; + } + + @Data + @ApiModel(value = "档口商品颜色价格") + public static class StoreProdColorPriceVO { + @ApiModelProperty(value = "档口商品颜色ID") + private Long storeColorId; + @ApiModelProperty(value = "档口商品定价") + private BigDecimal price; + } + + @Data + @ApiModel(value = "档口商品服务") + public static class StoreProdSvcVO { + @ApiModelProperty(value = "大小码及定制款可退") + private String customRefund; + @ApiModelProperty(value = "30天包退") + private String thirtyDayRefund; + @ApiModelProperty(value = "一件起批") + private String oneBatchSale; + @ApiModelProperty(value = "退款72小时到账") + private String refundWithinThreeDay; + } + + @Data + @ApiModel(value = "档口商品详情") + public static class StoreProdDetailVO { + @ApiModelProperty(value = "详情内容") + private String detail; + } + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/storeProd/StoreProdResVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/storeProd/StoreProdResVO.java index 4c9876d48..7891a27e0 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/storeProd/StoreProdResVO.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/storeProd/StoreProdResVO.java @@ -88,17 +88,6 @@ public class StoreProdResVO { private String dictValue; } - @Data - @ApiModel(value = "档口商品颜色尺码") - public static class StoreProdColorSizeVO { - @ApiModelProperty(value = "档口颜色ID") - private Long storeColorId; - @ApiModelProperty(value = "商品尺码") - private Integer size; - @ApiModelProperty(value = "是否是标准尺码 1是 2不是") - private Integer standard; - } - @Data @ApiModel(value = "档口商品颜色价格") public static class StoreProdColorPriceVO { diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/storeProd/StoreProdSkuResVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/storeProd/StoreProdSkuResVO.java new file mode 100644 index 000000000..a705fcbc6 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/storeProd/StoreProdSkuResVO.java @@ -0,0 +1,54 @@ +package com.ruoyi.web.controller.xkt.vo.storeProd; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("档口商品SKU信息") +@Data +public class StoreProdSkuResVO { + + @ApiModelProperty(value = "档口商品名称") + private Long storeProdId; + @ApiModelProperty(value = "档口ID") + private Long storeId; + @ApiModelProperty(value = "档口商品名称") + private String prodName; + @ApiModelProperty(value = "商品货号") + private String prodArtNum; + @ApiModelProperty(value = "颜色列表") + private List colorList; + + @Data + @ApiModel(value = "档口商品SKU") + public static class SPColorVO { + @ApiModelProperty(value = "档口颜色ID") + private Long storeColorId; + @ApiModelProperty(value = "颜色名称") + private String colorName; + @ApiModelProperty(value = "排序") + private Integer orderNum; + @ApiModelProperty(value = "尺码库存列表") + List sizeStockList; + } + + + @Data + @ApiModel(value = "尺码库存") + public static class SPSizeStockVO { + @ApiModelProperty(value = "商品尺码") + private Integer size; + @ApiModelProperty(value = "是否是标准尺码") + private Integer standard; + @ApiModelProperty(value = "尺码库存") + private Integer stock; + } + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/userShoppingCart/ShopCartToOrderResVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/userShoppingCart/ShopCartToOrderResVO.java new file mode 100644 index 000000000..fe75f3f55 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/userShoppingCart/ShopCartToOrderResVO.java @@ -0,0 +1,75 @@ +package com.ruoyi.web.controller.xkt.vo.userShoppingCart; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.util.List; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("档口商品详情返回数据") +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ShopCartToOrderResVO { + + @ApiModelProperty("档口商品ID") + private Long storeProdId; + @ApiModelProperty(value = "商品货号") + private String prodArtNum; + @ApiModelProperty(value = "大小码加价") + private Integer overPrice; + @ApiModelProperty(value = "档口商品尺码库存列表") + private List colorList; + @ApiModelProperty(value = "标准尺码") + private List standardSizeList; + @ApiModelProperty(value = "进货车明细列表") + List detailList; + + @Data + @ApiModel(value = "档口商品基本信息") + @Accessors(chain = true) + public static class SCDDetailVO { + @ApiModelProperty(value = "档口商品颜色ID") + private Long storeProdColorId; + @ApiModelProperty(value = "尺码") + private Integer size; + @ApiModelProperty(value = "商品数量") + private Integer quantity; + } + + @Data + @ApiModel(value = "档口商品基本信息") + @Accessors(chain = true) + public static class StoreProdColorVO { + @ApiModelProperty(value = "档口商品颜色ID") + private Long storeProdColorId; + @ApiModelProperty(value = "档口颜色ID") + private Long storeColorId; + @ApiModelProperty(value = "颜色名称") + private String colorName; + @ApiModelProperty(value = "排序") + private Integer orderNum; + @ApiModelProperty(value = "档口商品定价") + private BigDecimal price; + @ApiModelProperty(value = "商品尺码及库存") + List sizeStockList; + } + + @Data + @ApiModel(value = "档口商品尺码及库存") + @Accessors(chain = true) + public static class StoreProdSizeStockVO { + @ApiModelProperty(value = "商品尺码") + private Integer size; + @ApiModelProperty(value = "尺码库存") + private Integer stock; + } + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/website/IndexSearchVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/website/IndexSearchVO.java index 0de36b9bf..8a5a0e3dc 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/website/IndexSearchVO.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/website/IndexSearchVO.java @@ -18,6 +18,8 @@ import java.util.List; @Data public class IndexSearchVO extends BasePageVO { + @ApiModelProperty(value = "档口ID") + private Long storeId; @ApiModelProperty(value = "搜索内容") private String search; @ApiModelProperty(value = "商品状态列表") diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/XktTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/XktTask.java index 38d9f5301..a0a27e29f 100644 --- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/XktTask.java +++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/XktTask.java @@ -398,6 +398,13 @@ public class XktTask { } } + /** + * 每晚11:30更新广告位轮次状态 将biddingTempStatus赋值给biddingStatus + */ + @Transactional + public void updateAdvertRoundBiddingStatus() throws ParseException { + this.advertRoundService.updateBiddingStatus(); + } /** * 通过定时任务(每天晚上9:00)往redis中放当前推广位 当前播放轮 或 即将播放轮 的截止时间; @@ -410,9 +417,22 @@ public class XktTask { */ public void saveAdvertDeadlineToRedis() throws ParseException { // 直接调service方法,若当时redis出了问题,也方便第一时间 通过业务流程弥补 两边都有一个补偿机制 - advertRoundService.saveAdvertDeadlineToRedis(); + this.advertRoundService.saveAdvertDeadlineToRedis(); } + /** + * 通过定时任务(每天晚上9:00)将store数据暂存到reidis中 + */ + public void saveStoreToRedis() { + List storeList = this.storeMapper.selectList(new LambdaQueryWrapper() + .eq(Store::getDelFlag, Constants.UNDELETED)); + if (CollectionUtils.isEmpty(storeList)) { + return; + } + storeList.forEach(store -> { + redisCache.setCacheObject(store.getId().toString(), store, 90, TimeUnit.MINUTES); + }); + } /** diff --git a/xkt/src/main/java/com/ruoyi/xkt/domain/Store.java b/xkt/src/main/java/com/ruoyi/xkt/domain/Store.java index 16153bbf4..1fea50e75 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/domain/Store.java +++ b/xkt/src/main/java/com/ruoyi/xkt/domain/Store.java @@ -42,6 +42,11 @@ public class Store extends XktBaseEntity { @Excel(name = "档口名称") private String storeName; + /** + * 档口LOGO + */ + private String storeLogo; + /** * 品牌名称 */ diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundStoreResDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundStoreResDTO.java index 144bc7f4e..1e988f020 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundStoreResDTO.java +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/AdRoundStoreResDTO.java @@ -1,9 +1,13 @@ package com.ruoyi.xkt.dto.advertRound; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; import lombok.Data; import lombok.experimental.Accessors; +import java.util.List; + /** * @author liujiang * @version v1.0 @@ -11,8 +15,79 @@ import lombok.experimental.Accessors; */ @ApiModel("当前类型档口营销推广数据") @Data +@Builder @Accessors(chain = true) public class AdRoundStoreResDTO { + @ApiModelProperty(value = "时间范围的广告轮次列表") + private List timeRangeList; + @ApiModelProperty(value = "位置枚举的广告轮次列表") + private List positionList; + @ApiModelProperty(value = "已订购的推广轮次记录") + private List recordList; + + @Data + @Builder + @Accessors(chain = true) + @ApiModel(value = "类型为时间范围的广告轮次") + public static class ADRSRoundTimeRangeDTO { + @ApiModelProperty(value = "广告ID") + private Long advertId; + @ApiModelProperty(value = "广告轮次ID") + private Integer roundId; + @ApiModelProperty(value = "typeId") + private Integer typeId; + @ApiModelProperty(value = "推广档口ID") + private Long storeId; + @ApiModelProperty(value = "对象锁符号") + private String symbol; + @ApiModelProperty(value = "竞价状态") + private Integer biddingStatus; + @ApiModelProperty(value = "竞价结果描述") + private String biddingStatusStr; + } + + @Data + @Builder + @Accessors(chain = true) + @ApiModel(value = "类型为位置枚举的广告轮次") + public static class ADRSRoundPositionDTO { + @ApiModelProperty(value = "广告ID") + private Long advertId; + @ApiModelProperty(value = "广告轮次ID") + private Long 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 String symbol; + } + + @Data + @Builder + @Accessors(chain = true) + @ApiModel(value = "已抢购的推广记录") + public static class ADRSRoundRecordDTO { + @ApiModelProperty(value = "广告ID") + private Long advertId; + @ApiModelProperty(value = "广告轮次ID") + private Long roundId; + @ApiModelProperty(value = "广告类型ID") + private Integer typeId; + @ApiModelProperty(value = "推广档口ID") + private Long storeId; + @ApiModelProperty(value = "对象锁符号") + private String symbol; + @ApiModelProperty(value = "广告类型名称") + private String typeName; + @ApiModelProperty(value = "广告位置 A B C D E") + private String position; + @ApiModelProperty(value = "竞价结果描述") + private String biddingStr; + } + } diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/store/StoreAppResDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/store/StoreAppResDTO.java index b465d793c..f35b6d2b7 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/dto/store/StoreAppResDTO.java +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/store/StoreAppResDTO.java @@ -17,6 +17,8 @@ import java.util.List; @Accessors(chain = true) public class StoreAppResDTO { + @ApiModelProperty(value = "档口头像") + private String storeLogo; @ApiModelProperty(value = "档口ID") private Long storeId; @ApiModelProperty(value = "档口名称") diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/storeProduct/StoreProdAppResDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/storeProduct/StoreProdAppResDTO.java new file mode 100644 index 000000000..4799d996f --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/storeProduct/StoreProdAppResDTO.java @@ -0,0 +1,59 @@ +package com.ruoyi.xkt.dto.storeProduct; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.ruoyi.xkt.dto.storeProdCateAttr.StoreProdCateAttrDTO; +import com.ruoyi.xkt.dto.storeProdColorPrice.StoreProdColorPriceDTO; +import com.ruoyi.xkt.dto.storeProdDetail.StoreProdDetailDTO; +import com.ruoyi.xkt.dto.storeProdSvc.StoreProdSvcDTO; +import com.ruoyi.xkt.dto.storeProductFile.StoreProdFileResDTO; +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; +import java.util.List; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("档口商品APP详情") +@Data +@Accessors(chain = true) +public class StoreProdAppResDTO { + + @ApiModelProperty(value = "档口商品名称") + private Long storeProdId; + @ApiModelProperty(value = "档口ID") + private Long storeId; + @ApiModelProperty(value = "档口商品名称") + private String prodName; + @ApiModelProperty(value = "商品货号") + private String prodArtNum; + @ApiModelProperty(value = "商品标题") + private String prodTitle; + @ApiModelProperty(value = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date createTime; + @ApiModelProperty(value = "是否已收藏商品") + private Boolean collectProd; + @ApiModelProperty(value = "最低的商品价格") + private BigDecimal minPrice; + @ApiModelProperty(value = "规格") + private String specification; + @ApiModelProperty(value = "标签列表") + private List tagList; + @ApiModelProperty(value = "档口文件列表") + private List fileList; + @ApiModelProperty(value = "档口类目属性列表") + private List cateAttrList; + @ApiModelProperty(value = "档口服务承诺") + private StoreProdSvcDTO svc; + @ApiModelProperty(value = "详情内容") + private StoreProdDetailDTO detail; + + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/storeProduct/StoreProdSkuDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/storeProduct/StoreProdSkuDTO.java new file mode 100644 index 000000000..a7e92cb41 --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/storeProduct/StoreProdSkuDTO.java @@ -0,0 +1,35 @@ +package com.ruoyi.xkt.dto.storeProduct; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("档口商品的sku信息") +@Data +public class StoreProdSkuDTO { + + @ApiModelProperty(value = "档口商品ID") + private Long storeProdId; + @ApiModelProperty(value = "档口商品颜色名称") + private String colorName; + @ApiModelProperty(value = "颜色排序") + private Integer orderNum; + @ApiModelProperty(value = "尺码") + private Integer size; + @ApiModelProperty(value = "是否是标准尺码") + private Integer standard; + @ApiModelProperty(value = "档口商品颜色ID") + private Long storeColorId; + @ApiModelProperty(value = "档口商品定价") + private BigDecimal price; + @ApiModelProperty(value = "档口商品颜色尺码ID") + private Long storeProdColorSizeId; + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/storeProduct/StoreProdSkuResDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/storeProduct/StoreProdSkuResDTO.java new file mode 100644 index 000000000..939f00cc5 --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/storeProduct/StoreProdSkuResDTO.java @@ -0,0 +1,61 @@ +package com.ruoyi.xkt.dto.storeProduct; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.util.List; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("档口商品SKU信息") +@Data +@Accessors(chain = true) +public class StoreProdSkuResDTO { + + @ApiModelProperty(value = "档口商品名称") + private Long storeProdId; + @ApiModelProperty(value = "档口ID") + private Long storeId; + @ApiModelProperty(value = "档口商品名称") + private String prodName; + @ApiModelProperty(value = "商品货号") + private String prodArtNum; + @ApiModelProperty(value = "颜色列表") + private List colorList; + + @Data + @ApiModel(value = "档口商品SKU") + public static class SPColorDTO { + @ApiModelProperty(value = "档口颜色ID") + private Long storeColorId; + @ApiModelProperty(value = "颜色名称") + private String colorName; + @ApiModelProperty(value = "排序") + private Integer orderNum; + @ApiModelProperty(value = "档口商品定价") + private BigDecimal price; + @ApiModelProperty(value = "尺码库存列表") + List sizeStockList; + } + + @Data + @ApiModel(value = "尺码库存") + @Accessors(chain = true) + public static class SPSizeStockDTO { + @ApiModelProperty(value = "档口商品颜色尺码ID") + private Long storeProdColorSizeId; + @ApiModelProperty(value = "商品尺码") + private Integer size; + @ApiModelProperty(value = "是否是标准尺码") + private Integer standard; + @ApiModelProperty(value = "尺码库存") + private Integer stock; + } + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/userShoppingCart/ShoppingCartDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/userShoppingCart/ShoppingCartDTO.java index 12f3b82de..885dda389 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/dto/userShoppingCart/ShoppingCartDTO.java +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/userShoppingCart/ShoppingCartDTO.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import lombok.experimental.Accessors; import java.util.List; @@ -14,6 +15,7 @@ import java.util.List; */ @ApiModel("电商卖家新增进货车") @Data +@Accessors(chain = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class ShoppingCartDTO { diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/website/IndexSearchDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/website/IndexSearchDTO.java index 6e0c235cf..aecd1e8e6 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/dto/website/IndexSearchDTO.java +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/website/IndexSearchDTO.java @@ -19,6 +19,8 @@ import java.util.List; @Data public class IndexSearchDTO extends BasePageDTO { + @ApiModelProperty(value = "档口ID") + private Long storeId; @ApiModelProperty(value = "搜索内容") private String search; @ApiModelProperty(value = "商品状态列表") diff --git a/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductColorMapper.java b/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductColorMapper.java index ba32984b1..b9e3e4a78 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductColorMapper.java +++ b/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductColorMapper.java @@ -17,58 +17,23 @@ import java.util.List; * @date 2025-03-26 */ public interface StoreProductColorMapper extends BaseMapper { - /** - * 查询档口当前商品颜色 - * - * @param id 档口当前商品颜色主键 - * @return 档口当前商品颜色 - */ - public StoreProductColor selectStoreProductColorByStoreProdColorId(Long id); - - /** - * 查询档口当前商品颜色列表 - * - * @param storeProductColor 档口当前商品颜色 - * @return 档口当前商品颜色集合 - */ - public List selectStoreProductColorList(StoreProductColor storeProductColor); - - /** - * 新增档口当前商品颜色 - * - * @param storeProductColor 档口当前商品颜色 - * @return 结果 - */ - public int insertStoreProductColor(StoreProductColor storeProductColor); - - /** - * 修改档口当前商品颜色 - * - * @param storeProductColor 档口当前商品颜色 - * @return 结果 - */ - public int updateStoreProductColor(StoreProductColor storeProductColor); - - /** - * 删除档口当前商品颜色 - * - * @param id 档口当前商品颜色主键 - * @return 结果 - */ - public int deleteStoreProductColorByStoreProdColorId(Long id); - - /** - * 批量删除档口当前商品颜色 - * - * @param storeProdColorIds 需要删除的数据主键集合 - * @return 结果 - */ - public int deleteStoreProductColorByStoreProdColorIds(Long[] storeProdColorIds); void updateDelFlagByStoreProdId(Long storeProdId); + /** + * 获取档口商品列表 + * + * @param storeProdId 档口商品ID + * @return List + */ List selectListByStoreProdId(Long storeProdId); + /** + * 获取档口商品颜色列表 + * + * @param pageDTO 入参 + * @return + */ List selectStoreProdColorPage(StoreProdPageDTO pageDTO); /** diff --git a/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductMapper.java b/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductMapper.java index a2bb990b2..08c3031c7 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductMapper.java +++ b/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductMapper.java @@ -5,6 +5,7 @@ import com.ruoyi.xkt.domain.StoreProduct; import com.ruoyi.xkt.dto.storeHomepage.StoreHomeResDTO; import com.ruoyi.xkt.dto.storeProduct.ProductESDTO; import com.ruoyi.xkt.dto.storeProduct.StoreProdFuzzyResPicDTO; +import com.ruoyi.xkt.dto.storeProduct.StoreProdSkuDTO; import com.ruoyi.xkt.dto.storeProduct.StoreProdStatusCountDTO; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; @@ -96,4 +97,12 @@ public interface StoreProductMapper extends BaseMapper { */ List getStyleList(); + /** + * 获取档口商品的sku列表 + * @param storeProdId 档口商品ID + * @return List + */ + List selectSkuList(Long storeProdId); + } + 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 e6085b439..160ba063e 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/IAdvertRoundService.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/IAdvertRoundService.java @@ -14,13 +14,14 @@ import java.text.ParseException; public interface IAdvertRoundService { /** - * 获取当前类型下档口的推广营销数据 + * 根据广告ID获取推广轮次列表,并返回当前档口在这些推广轮次的数据 * * @param storeId 档口ID - * @param typeId 推广类型ID + * @param advertId 广告ID + * @param typeId * @return AdRoundPlayStoreResDTO */ - AdRoundStoreResDTO getStoreAdInfo(Long storeId, Integer typeId); + AdRoundStoreResDTO getStoreAdInfo(Long storeId, Long advertId, Integer typeId); /** * 档口购买推广营销 @@ -44,4 +45,5 @@ public interface IAdvertRoundService { void test(); + void updateBiddingStatus() throws ParseException; } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/IShoppingCartService.java b/xkt/src/main/java/com/ruoyi/xkt/service/IShoppingCartService.java index a1f1b3db2..9c4614d17 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/IShoppingCartService.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/IShoppingCartService.java @@ -50,4 +50,13 @@ public interface IShoppingCartService { * @return */ Integer delete(Long shoppingCartId); + + /** + * 根据storeProdid获取进货车详情 + * + * @param storeProdId 商品ID + * @return ShoppingCartDTO + */ + ShoppingCartDTO getByStoreProdId(Long storeProdId); + } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/IStoreProductService.java b/xkt/src/main/java/com/ruoyi/xkt/service/IStoreProductService.java index 7c007515f..fbdaa960e 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/IStoreProductService.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/IStoreProductService.java @@ -100,7 +100,24 @@ public interface IStoreProductService { /** * 获取商品所有的风格 + * * @return */ List getStyleList(); + + /** + * APP获取档口商品详情 + * + * @param storeProdId 档口商品ID + * @return StoreProdAppResDTO + */ + StoreProdAppResDTO getAppInfo(Long storeProdId); + + /** + * 获取档口商品颜色及sku等 + * + * @param storeProdId 档口商品ID + * @return StoreProdSkuResDTO + */ + StoreProdSkuResDTO getSkuList(Long storeProdId); } 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 b00657746..84acf3367 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 @@ -16,6 +16,7 @@ import com.ruoyi.xkt.enums.AdLaunchStatus; import com.ruoyi.xkt.enums.AdRoundType; import com.ruoyi.xkt.mapper.AdvertRoundMapper; import com.ruoyi.xkt.mapper.AdvertRoundRecordMapper; +import com.ruoyi.xkt.mapper.StoreMapper; import com.ruoyi.xkt.service.IAdvertRoundService; import lombok.RequiredArgsConstructor; import org.apache.commons.collections4.CollectionUtils; @@ -47,6 +48,7 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { final AdvertRoundMapper advertRoundMapper; final AdvertRoundRecordMapper advertRoundRecordMapper; final RedisCache redisCache; + final StoreMapper storeMapper; // 推广营销位锁 key:symbol + roundId 或者 symbol + roundId + position 。value都是new Object() public static Map advertLockMap = new ConcurrentHashMap<>(); @@ -70,9 +72,7 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { .forEach((typeId, roundList) -> roundList // 初始化 锁资源对象 .forEach(round -> advertLockMap.putIfAbsent(round.getSymbol(), new Object()))); - System.err.println(advertLockMap); - } public void test() { @@ -80,23 +80,137 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { } + /** + * 更新广告位轮次的竞价状态 + * 此方法主要用于根据当前日期更新广告位轮次的竞价状态,以确保广告投放的正确性 + * 它首先查询符合条件的广告位轮次,然后根据当前时间与第一轮结束时间的比较,更新相应的竞价状态 + * 如果当前时间小于第一轮最后一天,则更新第一轮的竞价状态;如果等于第一轮最后一天,则更新第二轮的竞价状态 + * + * @throws ParseException 如果日期解析失败 + */ + @Override + @Transactional + public void updateBiddingStatus() throws ParseException { + List advertRoundList = this.advertRoundMapper.selectList(new LambdaQueryWrapper() + .eq(AdvertRound::getDelFlag, Constants.UNDELETED) + .in(AdvertRound::getRoundId, Arrays.asList(AdRoundType.PLAY_ROUND.getValue(), AdRoundType.SECOND_ROUND.getValue())) + .in(AdvertRound::getLaunchStatus, Arrays.asList(AdLaunchStatus.LAUNCHING.getValue(), AdLaunchStatus.UN_LAUNCH.getValue()))); + if (CollectionUtils.isEmpty(advertRoundList)) { + return; + } + // 待更新的推广位轮次 + List updateList = new ArrayList<>(); + // 如果当前时间小于第一轮最后一天则修改第一轮的竞价状态,若等于第一轮最后一天,则更新第二轮的竞价状态 + final Date now = DateUtils.parseDate(DateUtils.getDate(), DateUtils.YYYY_MM_DD); + advertRoundList.stream().collect(Collectors.groupingBy(AdvertRound::getAdvertId)) + .forEach((advertId, roundList) -> { + // 判断当前时间所处的阶段 小于第一轮播放时间(有可能新广告还未开播)、处于第一轮中间、处于第一轮最后一天 + final Date firstRoundEndTime = roundList.stream().filter(x -> x.getRoundId().equals(AdRoundType.PLAY_ROUND.getValue())) + .max(Comparator.comparing(AdvertRound::getEndTime)) + .orElseThrow(() -> new ServiceException("获取推广结束时间失败,请联系客服!", HttpStatus.ERROR)).getEndTime(); + // 判断当前时间是否为第一轮最后一天 + if (now.before(firstRoundEndTime)) { + // 将广告位第 一 轮,出价状态从已出价 改为 竞价成功 + roundList.stream().filter(x -> x.getRoundId().equals(AdRoundType.PLAY_ROUND.getValue())) + // 将出价状态和竞价状态不一致的播放轮次位置 筛选出来 + .filter(x -> ObjectUtils.isNotEmpty(x.getBiddingStatus()) && ObjectUtils.isNotEmpty(x.getBiddingTempStatus()) + && !Objects.equals(x.getBiddingStatus(), x.getBiddingTempStatus())) + .forEach(x -> updateList.add(x.setBiddingStatus(x.getBiddingTempStatus()))); + + } else if (now.equals(firstRoundEndTime)) { + // 广告第二轮 + List secondRoundList = roundList.stream().filter(x -> x.getRoundId().equals(AdRoundType.SECOND_ROUND.getValue())).collect(Collectors.toList()); + // 有可能广告下线,没有第二轮广告了 + if (CollectionUtils.isNotEmpty(secondRoundList)) { + // 将广告位第 二 轮,出价状态从已出价 改为 竞价成功 + secondRoundList.stream() + // 将出价状态和竞价状态不一致的播放轮次位置 筛选出来 + .filter(x -> ObjectUtils.isNotEmpty(x.getBiddingStatus()) && ObjectUtils.isNotEmpty(x.getBiddingTempStatus()) + && !Objects.equals(x.getBiddingStatus(), x.getBiddingTempStatus())) + .forEach(x -> updateList.add(x.setBiddingStatus(x.getBiddingTempStatus()))); + } + } + }); + if (CollectionUtils.isEmpty(updateList)) { + return; + } + this.advertRoundMapper.updateById(updateList); + } + /** - * 获取当前类型下档口的推广营销数据 + * 根据广告ID获取推广轮次列表,并返回当前档口在这些推广轮次的数据 * * @param storeId 档口ID - * @param typeId 推广类型ID + * @param advertId 推广ID + * @param typeId 类型ID + * @return AdRoundPlayStoreResDTO + */ + + /** + * 根据广告ID获取推广轮次列表,并返回当前档口在这些推广轮次的数据 + * + * @param storeId 档口ID + * @param advertId 广告ID + * @param typeId * @return AdRoundPlayStoreResDTO */ @Override @Transactional(readOnly = true) - public AdRoundStoreResDTO getStoreAdInfo(Long storeId, Integer typeId) { - // 先获取所有 投放中 待投放的营销推广 + public AdRoundStoreResDTO getStoreAdInfo(final Long storeId,final Long advertId,final Integer typeId) { + // 获取当前 正在播放 和 待播放的推广轮次 + List advertRoundList = this.advertRoundMapper.selectList(new LambdaQueryWrapper() + .eq(AdvertRound::getAdvertId, advertId) + .eq(AdvertRound::getDelFlag, Constants.UNDELETED) + .in(AdvertRound::getLaunchStatus, Arrays.asList(AdLaunchStatus.LAUNCHING.getValue(), AdLaunchStatus.UN_LAUNCH.getValue()))); + if (CollectionUtils.isEmpty(advertRoundList)) { + return AdRoundStoreResDTO.builder().build(); + } + + // 如果投放类型是:时间范围,则只需要返回每一轮的开始时间和结束时间;如果投放类型是:位置枚举,则需要返回每一个位置的详细情况 + if (!Constants.posEnumTypeList.contains(typeId)) { + List rangeList = new ArrayList<>(); + // 提取每一轮的广告数据 + Map> roundMap = advertRoundList.stream().collect(Collectors.groupingBy(AdvertRound::getRoundId)); + roundMap.forEach((roundId, roundList) -> { + AdvertRound targetRound = roundList.stream().filter(x -> Objects.equals(x.getStoreId(), storeId)).findFirst().orElse(null); + + final AdvertRound curRound = roundList.get(0); + AdRoundStoreResDTO.ADRSRoundTimeRangeDTO roundDTO = AdRoundStoreResDTO.ADRSRoundTimeRangeDTO.builder() + .roundId(roundId).advertId(advertId).symbol(curRound.getSymbol()).typeId(typeId).build(); + // 判断当前轮是否有该档口竞价的数据 + if (roundList.stream().anyMatch(x -> Objects.equals(x.getStoreId(), storeId))) { +// roundDTO.setStoreId(storeId).setBiddingStatus(0) + + } + }); + } else { + // 位置枚举 + } + + + + + + // 根据广告ID获取所有推广轮次列表,如果有其他档口的数据则 需要过滤 + + // 这里要返回两个部分的数据 1. 左边的档口广告列表 2. 右边的已购推广位竞价结果 + + // 如果左边某个推广位竞价失败,则失败的当天展示;第二天该推广位就不再展示竞价失败 字样了。但是右边的“已订购推广列表”,一直展示知道该推广位播放完毕 + + // 当天不是第一轮最后一天,类型位:时间范围,则显示前4轮推广位;类型为:位置枚举,则显示前1轮。是最后一天,类型为:时间范围,显示第2轮到第4轮;类型为:位置枚举,则显示第二轮 + + + + + + // 再判断当前当前与每一轮推广营销中的关系,已出价、竞价失败、竞价成功等 return null; } + /** * 档口购买推广营销 * 主要是两个场景:1. 某个广告位(advert_id)某个轮次(round_id)按照出价(pay_price)决定能否购买。[eg: A B C D E] @@ -115,26 +229,29 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { @Override @Transactional public Integer create(AdRoundStoreCreateDTO createDTO) { - // 截止时间都是当天 22:00:00,并且只会处理马上播放的这一轮。比如 5.1-5.3,当前为4.30,处理这一轮;当前为5.2,处理这一轮;当前为5.3(最后一天),处理下一轮。 if (DateUtils.getTime().compareTo(this.getDeadline(createDTO.getSymbol())) > 0) { throw new ServiceException("竞价结束,已经有档口出价更高了噢!", HttpStatus.ERROR); } - - // 校验position位置是否必传 - this.isPositionRequired(createDTO); - - // 判断当前推广位的这一轮每个档口可以买几个,不可超买 - boolean isOverBuy = this.advertRoundMapper.isStallOverBuy(createDTO.getAdvertId(), createDTO.getRoundId(), createDTO.getStoreId(), createDTO.getPosition()); - if (isOverBuy) { - throw new ServiceException("已购买过该推广位,不可超买哦!", HttpStatus.ERROR); + if (StringUtils.isEmpty(redisCache.getCacheObject(createDTO.getStoreId().toString()))) { + throw new ServiceException("档口不存在!", HttpStatus.ERROR); + } + // 如果是位置枚举的推广位,则需要传position + if (Constants.posEnumTypeList.contains(createDTO.getTypeId()) && StringUtils.isEmpty(createDTO.getPosition())) { + throw new ServiceException("当前推广类型position:必传!", HttpStatus.ERROR); + } + // 如果是时间范围的推广位,则不需要传position + if (!Constants.posEnumTypeList.contains(createDTO.getTypeId()) && StringUtils.isNotBlank(createDTO.getPosition())) { + throw new ServiceException("当前推广类型position:不传!", HttpStatus.ERROR); } - - // 当前营销推广位的锁 Object lockObj = Optional.ofNullable(advertLockMap.get(createDTO.getSymbol())).orElseThrow(() -> new ServiceException("symbol不存在!", HttpStatus.ERROR)); - // 锁当前推广营销位 synchronized (lockObj) { + // 判断当前推广位的这一轮每个档口可以买几个,不可超买 + boolean isOverBuy = this.advertRoundMapper.isStallOverBuy(createDTO.getAdvertId(), createDTO.getRoundId(), createDTO.getStoreId(), createDTO.getPosition()); + if (isOverBuy) { + throw new ServiceException("已购买过该推广位,不可超买哦!", HttpStatus.ERROR); + } LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() .eq(AdvertRound::getAdvertId, createDTO.getAdvertId()).eq(AdvertRound::getRoundId, createDTO.getRoundId()) .eq(AdvertRound::getDelFlag, Constants.UNDELETED).orderByAsc(AdvertRound::getPayPrice).last("LIMIT 1"); @@ -219,19 +336,6 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { }); } - /** - * 判断当前类型position是否必传 - * @param createDTO 购买广告位入参 - */ - private void isPositionRequired(AdRoundStoreCreateDTO createDTO) { - // 如果是位置枚举的推广位,则需要传position - if (Constants.posEnumTypeList.contains(createDTO.getTypeId()) && StringUtils.isEmpty(createDTO.getPosition())) { - throw new ServiceException("当前推广类型position:必传!", HttpStatus.ERROR); - } - if (!Constants.posEnumTypeList.contains(createDTO.getTypeId()) && StringUtils.isNotBlank(createDTO.getPosition())) { - throw new ServiceException("当前推广类型position:不传!", HttpStatus.ERROR); - } - } /** * 获取当前推广轮次的过期时间 @@ -243,10 +347,6 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { return StringUtils.isNotBlank(deadline) ? deadline : ""; } - // TODO 在每晚11:30起定时任务,重新梳理,每个广告位的大小顺序 - // TODO 在每晚11:30起定时任务,重新梳理,每个广告位的大小顺序 - - /** * 记录竞价失败档口推广营销 * @param failAdvert 竞价失败的推广营销 @@ -261,9 +361,4 @@ public class AdvertRoundServiceImpl implements IAdvertRoundService { this.advertRoundRecordMapper.insert(record); } - - // TODO 新增档口广告购买时,需要加锁,一定要锁住 - // TODO 新增档口广告购买时,需要加锁,一定要锁住 - // TODO 新增档口广告购买时,需要加锁,一定要锁住 - } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/IndexSearchServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/IndexSearchServiceImpl.java index 4f95d0876..f1211aa27 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/IndexSearchServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/IndexSearchServiceImpl.java @@ -77,6 +77,10 @@ public class IndexSearchServiceImpl implements IIndexSearchService { ); boolQuery.must(multiMatchQuery._toQuery()); } + // 档口ID 过滤条件 + if (ObjectUtils.isNotEmpty(searchDTO.getStoreId())) { + boolQuery.filter(f -> f.term(t -> t.field("storeId").value(searchDTO.getStoreId()))); + } // 添加prodStatus 过滤条件 if (CollectionUtils.isNotEmpty(searchDTO.getProdStatusList())) { TermsQueryField termsQueryField = new TermsQueryField.Builder() diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/ShoppingCartServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/ShoppingCartServiceImpl.java index 29e653aaa..0b0f95a09 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/ShoppingCartServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/ShoppingCartServiceImpl.java @@ -247,6 +247,25 @@ public class ShoppingCartServiceImpl implements IShoppingCartService { return count; } + /** + * 根据storeProdid获取进货车详情 + * + * @param storeProdId 商品ID + * @return ShoppingCartDTO + */ + @Override + @Transactional(readOnly = true) + public ShoppingCartDTO getByStoreProdId(Long storeProdId) { + ShoppingCart shoppingCart = this.shopCartMapper.selectOne(new LambdaQueryWrapper() + .eq(ShoppingCart::getStoreProdId, storeProdId).eq(ShoppingCart::getDelFlag, Constants.UNDELETED) + .eq(ShoppingCart::getUserId, SecurityUtils.getUserId())); + List detailList = this.shopCartDetailMapper.selectList(new LambdaQueryWrapper() + .eq(ShoppingCartDetail::getShoppingCartId, shoppingCart.getId()) + .eq(ShoppingCartDetail::getDelFlag, Constants.UNDELETED)); + return BeanUtil.toBean(shoppingCart, ShoppingCartDTO.class) + .setDetailList(BeanUtil.copyToList(detailList, ShoppingCartDTO.SCDetailDTO.class)); + } + /** * 获取档口商品颜色尺码的库存 * diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreProductServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreProductServiceImpl.java index 59b92705e..7587c46dc 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreProductServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreProductServiceImpl.java @@ -13,6 +13,7 @@ import com.ruoyi.common.constant.HttpStatus; import com.ruoyi.common.core.page.Page; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.framework.es.EsClientWrapper; import com.ruoyi.system.domain.dto.productCategory.ProdCateDTO; import com.ruoyi.system.mapper.SysProductCategoryMapper; @@ -45,9 +46,12 @@ import org.springframework.transaction.annotation.Transactional; import java.io.IOException; import java.math.BigDecimal; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.stream.Collectors; +import static com.ruoyi.common.constant.Constants.*; + /** * 档口商品Service业务层处理 * @@ -72,6 +76,9 @@ public class StoreProductServiceImpl implements IStoreProductService { final StoreMapper storeMapper; final EsClientWrapper esClientWrapper; final SysProductCategoryMapper prodCateMapper; + final UserFavoritesMapper userFavMapper; + final DailyProdTagMapper prodTagMapper; + final StoreProductStockMapper prodStockMapper; /** @@ -468,6 +475,116 @@ public class StoreProductServiceImpl implements IStoreProductService { return this.storeProdMapper.getStyleList(); } + /** + * APP获取档口商品详情 + * + * @param storeProdId 档口商品ID + * @return StoreProdAppResDTO + */ + @Override + @Transactional(readOnly = true) + public StoreProdAppResDTO getAppInfo(Long storeProdId) { + StoreProduct storeProd = Optional.ofNullable(this.storeProdMapper.selectOne(new LambdaQueryWrapper() + .eq(StoreProduct::getId, storeProdId).eq(StoreProduct::getDelFlag, Constants.UNDELETED))) + .orElseThrow(() -> new ServiceException("档口商品不存在!", HttpStatus.ERROR)); + StoreProdAppResDTO appResDTO = BeanUtil.toBean(storeProd, StoreProdAppResDTO.class).setStoreProdId(storeProd.getId()); + // 档口文件(商品主图、主图视频、下载的商品详情) + List fileResList = this.storeProdFileMapper.selectListByStoreProdId(storeProdId); + // 档口类目属性列表 + List cateAttrList = this.storeProdCateAttrMapper.selectListByStoreProdId(storeProdId); + // 档口当前商品颜色列表 + List colorList = this.storeProdColorMapper.selectListByStoreProdId(storeProdId); + // 档口商品颜色尺码列表 + List sizeList = this.storeProdColorSizeMapper.selectListByStoreProdId(storeProdId); + // 档口颜色价格列表 + List priceList = this.storeProdColorPriceMapper.selectListByStoreProdId(storeProdId); + // 档口商品详情 + StoreProductDetail prodDetail = this.storeProdDetailMapper.selectByStoreProdId(storeProdId); + // 档口服务承诺 + StoreProductService storeProductSvc = this.storeProdSvcMapper.selectByStoreProdId(storeProdId); + // 是否已收藏 + UserFavorites favorite = this.userFavMapper.selectOne(new LambdaQueryWrapper() + .eq(UserFavorites::getDelFlag, Constants.UNDELETED).eq(UserFavorites::getStoreProdId, storeProdId) + .eq(UserFavorites::getUserId, SecurityUtils.getUserId())); + // 获取商品标签 + List tagList = this.prodTagMapper.selectList(new LambdaQueryWrapper() + .eq(DailyProdTag::getDelFlag, Constants.UNDELETED).eq(DailyProdTag::getStoreProdId, storeProdId) + .orderByAsc(DailyProdTag::getType)); + return appResDTO.setFileList(fileResList).setCateAttrList(cateAttrList) + .setTagList(CollectionUtils.isNotEmpty(tagList) ? tagList.stream().map(DailyProdTag::getTag).distinct().collect(Collectors.toList()) : null) + .setCollectProd(ObjectUtils.isNotEmpty(favorite) ? Boolean.TRUE : Boolean.FALSE) + .setSpecification(colorList.size() + "色" + sizeList.stream().filter(x -> Objects.equals(x.getStandard(), ProductSizeStatus.STANDARD.getValue())).count() + "码") + .setMinPrice(priceList.stream().min(Comparator.comparing(StoreProdColorPriceDTO::getPrice)) + .orElseThrow(() -> new ServiceException("获取商品价格失败,请联系客服!", HttpStatus.ERROR)).getPrice()) + .setDetail(ObjectUtils.isEmpty(prodDetail) ? null : BeanUtil.toBean(prodDetail, StoreProdDetailDTO.class)) + .setSvc(ObjectUtils.isEmpty(storeProductSvc) ? null : BeanUtil.toBean(storeProductSvc, StoreProdSvcDTO.class)); + } + + /** + * 获取档口商品颜色及sku等 + * + * @param storeProdId 档口商品ID + * @return StoreProdSkuResDTO + */ + @Override + @Transactional(readOnly = true) + public StoreProdSkuResDTO getSkuList(Long storeProdId) { + StoreProduct storeProd = Optional.ofNullable(this.storeProdMapper.selectOne(new LambdaQueryWrapper() + .eq(StoreProduct::getId, storeProdId).eq(StoreProduct::getDelFlag, Constants.UNDELETED))) + .orElseThrow(() -> new ServiceException("档口商品不存在!", HttpStatus.ERROR)); + // 档口商品的sku列表 + List prodSkuList = this.storeProdMapper.selectSkuList(storeProdId); + if (CollectionUtils.isEmpty(prodSkuList)) { + return BeanUtil.toBean(storeProd, StoreProdSkuResDTO.class); + } + // 获取当前档口商品的sku列表 + Map colorSizeStockMap = this.getProdStockList(storeProdId); + // 组装所有的档口商品sku + List colorList = prodSkuList.stream().map(x -> BeanUtil.toBean(x, StoreProdSkuResDTO.SPColorDTO.class)).distinct().collect(Collectors.toList()); + // storeColorId的sku列表 + Map> colorSizeMap = prodSkuList.stream().collect(Collectors.groupingBy(StoreProdSkuDTO::getStoreColorId)); + colorList.forEach(color -> { + List sizeList = Optional.ofNullable(colorSizeMap.get(color.getStoreColorId())) + .orElseThrow(() -> new ServiceException("获取商品sku失败,请联系客服!", HttpStatus.ERROR)); + color.setSizeStockList(sizeList.stream().map(size -> new StoreProdSkuResDTO.SPSizeStockDTO() + .setStoreProdColorSizeId(size.getStoreProdColorSizeId()).setSize(size.getSize()).setStandard(size.getStandard()) + .setStock(colorSizeStockMap.get(color.getStoreColorId() + ":" + size.getSize()))) + .collect(Collectors.toList())); + }); + return BeanUtil.toBean(storeProd, StoreProdSkuResDTO.class).setStoreProdId(storeProdId).setColorList(colorList); + } + + /** + * 获取当前商品的sku列表 + * + * @param storeProdId 档口商品ID + * @return Map + */ + private Map getProdStockList(Long storeProdId) { + // 获取当前商品的库存列表 + List stockList = this.prodStockMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProductStock::getStoreProdId, storeProdId).eq(StoreProductStock::getDelFlag, Constants.UNDELETED)); + // 该商品storeColorId + size的库存maps + Map colorSizeStockMap = new ConcurrentHashMap<>(); + stockList.stream().collect(Collectors.groupingBy(StoreProductStock::getStoreColorId)).forEach((storeColorId, tempStockList) -> { + colorSizeStockMap.put(storeColorId + ":" + SIZE_30, tempStockList.stream().map(x -> ObjectUtils.defaultIfNull(x.getSize30(), 0)).reduce(0, Integer::sum)); + colorSizeStockMap.put(storeColorId + ":" + SIZE_31, tempStockList.stream().map(x -> ObjectUtils.defaultIfNull(x.getSize31(), 0)).reduce(0, Integer::sum)); + colorSizeStockMap.put(storeColorId + ":" + SIZE_32, tempStockList.stream().map(x -> ObjectUtils.defaultIfNull(x.getSize32(), 0)).reduce(0, Integer::sum)); + colorSizeStockMap.put(storeColorId + ":" + SIZE_33, tempStockList.stream().map(x -> ObjectUtils.defaultIfNull(x.getSize33(), 0)).reduce(0, Integer::sum)); + colorSizeStockMap.put(storeColorId + ":" + SIZE_34, tempStockList.stream().map(x -> ObjectUtils.defaultIfNull(x.getSize34(), 0)).reduce(0, Integer::sum)); + colorSizeStockMap.put(storeColorId + ":" + SIZE_35, tempStockList.stream().map(x -> ObjectUtils.defaultIfNull(x.getSize35(), 0)).reduce(0, Integer::sum)); + colorSizeStockMap.put(storeColorId + ":" + SIZE_36, tempStockList.stream().map(x -> ObjectUtils.defaultIfNull(x.getSize36(), 0)).reduce(0, Integer::sum)); + colorSizeStockMap.put(storeColorId + ":" + SIZE_37, tempStockList.stream().map(x -> ObjectUtils.defaultIfNull(x.getSize37(), 0)).reduce(0, Integer::sum)); + colorSizeStockMap.put(storeColorId + ":" + SIZE_38, tempStockList.stream().map(x -> ObjectUtils.defaultIfNull(x.getSize38(), 0)).reduce(0, Integer::sum)); + colorSizeStockMap.put(storeColorId + ":" + SIZE_39, tempStockList.stream().map(x -> ObjectUtils.defaultIfNull(x.getSize39(), 0)).reduce(0, Integer::sum)); + colorSizeStockMap.put(storeColorId + ":" + SIZE_40, tempStockList.stream().map(x -> ObjectUtils.defaultIfNull(x.getSize40(), 0)).reduce(0, Integer::sum)); + colorSizeStockMap.put(storeColorId + ":" + SIZE_41, tempStockList.stream().map(x -> ObjectUtils.defaultIfNull(x.getSize41(), 0)).reduce(0, Integer::sum)); + colorSizeStockMap.put(storeColorId + ":" + SIZE_42, tempStockList.stream().map(x -> ObjectUtils.defaultIfNull(x.getSize42(), 0)).reduce(0, Integer::sum)); + colorSizeStockMap.put(storeColorId + ":" + SIZE_43, tempStockList.stream().map(x -> ObjectUtils.defaultIfNull(x.getSize43(), 0)).reduce(0, Integer::sum)); + }); + return colorSizeStockMap; + } + /** * 处理档口商品属性 * @@ -620,7 +737,7 @@ public class StoreProductServiceImpl implements IStoreProductService { .setParCateId(esDTO.getParCateId()).setParCateName(esDTO.getParCateName()).setProdPrice(esDTO.getProdPrice()).setStoreName(esDTO.getStoreName()) .setSeason(esDTO.getSeason()).setStyle(esDTO.getStyle()).setCreateTime(createTime); return new BulkOperation.Builder().create(d -> d.document(esProductDTO).id(String.valueOf(x.getId())) - .index(Constants.ES_IDX_PRODUCT_INFO)).build(); + .index(Constants.ES_IDX_PRODUCT_INFO)).build(); }).collect(Collectors.toList()); // 调用bulk方法执行批量插入操作 BulkResponse bulkResponse = esClientWrapper.getEsClient().bulk(e -> e.index(Constants.ES_IDX_PRODUCT_INFO).operations(list)); diff --git a/xkt/src/main/resources/mapper/StoreProductColorMapper.xml b/xkt/src/main/resources/mapper/StoreProductColorMapper.xml index d5c17ba69..2304e944a 100644 --- a/xkt/src/main/resources/mapper/StoreProductColorMapper.xml +++ b/xkt/src/main/resources/mapper/StoreProductColorMapper.xml @@ -3,92 +3,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - - - - - - - - - - - - - - - - - select id, store_color_id, store_prod_id, store_id, color_name, version, del_flag, create_by, create_time, update_by, update_time from store_product_color - - - - - - - - insert into store_product_color - - store_color_id, - store_prod_id, - color_name, - version, - del_flag, - create_by, - create_time, - update_by, - update_time, - - - #{storeColorId}, - #{storeProdId}, - #{colorName}, - #{version}, - #{delFlag}, - #{createBy}, - #{createTime}, - #{updateBy}, - #{updateTime}, - - - - - update store_product_color - - store_color_id = #{storeColorId}, - store_prod_id = #{storeProdId}, - color_name = #{colorName}, - version = #{version}, - del_flag = #{delFlag}, - create_by = #{createBy}, - create_time = #{createTime}, - update_by = #{updateBy}, - update_time = #{updateTime}, - - where id = #{id} - - - - delete from store_product_color where id = #{id} - - - - delete from store_product_color where id in - - #{id} - - UPDATE store_product_color SET del_flag = 2 WHERE store_prod_id = #{storeProdId} diff --git a/xkt/src/main/resources/mapper/StoreProductMapper.xml b/xkt/src/main/resources/mapper/StoreProductMapper.xml index a5cd33e0a..9022a0a76 100644 --- a/xkt/src/main/resources/mapper/StoreProductMapper.xml +++ b/xkt/src/main/resources/mapper/StoreProductMapper.xml @@ -219,4 +219,29 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" AND del_flag = 0 + + + + + \ No newline at end of file