From 47e4d57d589ad2d5d07518536b17fccd8d4e8852 Mon Sep 17 00:00:00 2001 From: liujiang <569804566@qq.com> Date: Fri, 23 May 2025 23:30:40 +0800 Subject: [PATCH] =?UTF-8?q?master=EF=BC=9A=E8=BF=94=E5=9B=9E=E5=90=84?= =?UTF-8?q?=E4=B8=AA=E4=BD=8D=E7=BD=AE=E8=90=A5=E9=94=80=E6=8E=A8=E5=B9=BF?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/controller/xkt/WebsiteController.java | 39 ++- .../ruoyi/common/constant/CacheConstants.java | 24 +- .../com/ruoyi/common/constant/Constants.java | 7 + .../java/com/ruoyi/common/core/page/Page.java | 15 +- .../java/com/ruoyi/quartz/task/XktTask.java | 2 +- .../app/index/APPIndexHotSaleDTO.java | 40 +++ .../app/index/APPIndexHotSalePageDTO.java | 37 +++ .../app/index/APPIndexNewProdDTO.java | 39 +++ .../app/index/APPIndexPopularSaleDTO.java | 39 +++ .../advertRound/app/index/APPSearchDTO.java | 39 +++ .../pc/index/PCIndexRecommendDTO.java | 39 +++ .../StoreProdPriceAndMainPicAndTagDTO.java | 38 +++ .../ruoyi/xkt/mapper/StoreProductMapper.java | 7 + .../ruoyi/xkt/service/IWebsiteService.java | 47 ++- .../xkt/service/impl/WebsiteServiceImpl.java | 275 ++++++++++++++++-- .../resources/mapper/StoreProductMapper.xml | 33 +++ 16 files changed, 681 insertions(+), 39 deletions(-) create mode 100644 xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexHotSaleDTO.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexHotSalePageDTO.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexNewProdDTO.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexPopularSaleDTO.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPSearchDTO.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/pc/index/PCIndexRecommendDTO.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/dto/storeProduct/StoreProdPriceAndMainPicAndTagDTO.java diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/WebsiteController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/WebsiteController.java index ec4914fd5..6dee01a66 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/WebsiteController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/WebsiteController.java @@ -16,6 +16,8 @@ import com.ruoyi.web.controller.xkt.vo.advertRound.pc.store.PCStoreMidBannerVO; import com.ruoyi.web.controller.xkt.vo.advertRound.pc.store.PCStoreTopBannerVO; import com.ruoyi.web.controller.xkt.vo.advertRound.picSearch.PicSearchAdvertVO; import com.ruoyi.web.controller.xkt.website.IndexSearchVO; +import com.ruoyi.xkt.dto.advertRound.app.index.*; +import com.ruoyi.xkt.dto.advertRound.pc.index.PCIndexRecommendDTO; import com.ruoyi.xkt.dto.es.ESProductDTO; import com.ruoyi.xkt.dto.website.IndexSearchDTO; import com.ruoyi.xkt.service.IWebsiteService; @@ -52,9 +54,44 @@ public class WebsiteController extends XktBaseController { return R.ok(websiteService.search(BeanUtil.toBean(searchVO, IndexSearchDTO.class))); } + + // PC 首页 新品馆 列表 // TODO APP 首页 热卖精选、人气爆品、新品榜 PC 首页 新品馆 列表 // TODO APP 首页 热卖精选、人气爆品、新品榜 PC 首页 新品馆 列表 - // TODO APP 首页 热卖精选、人气爆品、新品榜 PC 首页 新品馆 列表 + + @ApiOperation(value = "PC 首页 为你推荐", httpMethod = "POST", response = R.class) + @PostMapping("/pc/index/recommend") + public R> pcIndexRecommendPage(@Validated @RequestBody IndexSearchVO searchVO) throws IOException { + return R.ok(websiteService.pcIndexRecommendPage(BeanUtil.toBean(searchVO, IndexSearchDTO.class))); + } + + + + @ApiOperation(value = "APP 首页 精选热卖列表", httpMethod = "POST", response = R.class) + @PostMapping("/app/index/hot-sale") + public R> appIndexHotSalePage(@Validated @RequestBody IndexSearchVO searchVO) throws IOException { + return R.ok(websiteService.appIndexHotSalePage(BeanUtil.toBean(searchVO, IndexSearchDTO.class))); + } + + @ApiOperation(value = "APP 首页 人气爆品", httpMethod = "POST", response = R.class) + @PostMapping("/app/index/popular-sale") + public R> appIndexPopularSalePage(@Validated @RequestBody IndexSearchVO searchVO) throws IOException { + return R.ok(websiteService.appIndexPopularSalePage(BeanUtil.toBean(searchVO, IndexSearchDTO.class))); + } + + @ApiOperation(value = "APP 首页 新品榜", httpMethod = "POST", response = R.class) + @PostMapping("/app/index/new-prod") + public R> appIndexNewProdPage(@Validated @RequestBody IndexSearchVO searchVO) throws IOException { + return R.ok(websiteService.appIndexNewProdPage(BeanUtil.toBean(searchVO, IndexSearchDTO.class))); + } + + @ApiOperation(value = "APP 搜索", httpMethod = "POST", response = R.class) + @PostMapping("/app/index/search") + public R> appSearchPage(@Validated @RequestBody IndexSearchVO searchVO) throws IOException { + return R.ok(websiteService.appSearchPage(BeanUtil.toBean(searchVO, IndexSearchDTO.class))); + } + + @ApiOperation(value = "PC 首页 顶部横向轮播图", httpMethod = "GET", response = R.class) diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java index 0eed38840..87d378239 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java @@ -2,11 +2,10 @@ package com.ruoyi.common.constant; /** * 缓存的key 常量 - * + * * @author ruoyi */ -public class CacheConstants -{ +public class CacheConstants { /** * 登录用户 redis key */ @@ -132,7 +131,7 @@ public class CacheConstants */ public static final String PC_ADVERT_STORE_MID_BANNER = "pc_store_mid_banner"; /** - * 以图搜款 + * 以图搜款 */ public static final String PIC_SEARCH = "pic_search"; /** @@ -161,6 +160,22 @@ public class CacheConstants * APP 首页热卖精选 右侧固定位置 */ public static final String APP_INDEX_HOT_SALE_RIGHT_FIX = "app_index_hot_sale_right_fix"; + /** + * APP 首页精选热卖推广 + */ + public static final String APP_INDEX_HOT_SALE_ADVERT = "app_index_hot_sale_advert"; + /** + * APP 首页人气爆品推广 + */ + public static final String APP_INDEX_POPULAR_SALE_ADVERT = "app_index_popular_sale_advert"; + /** + * APP 首页 新品榜 + */ + public static final String APP_INDEX_NEW_PROD = "app_index_new_prod"; + /** + * APP 搜索 + */ + public static final String APP_SEARCH = "app_search"; /** * APP 分类页 */ @@ -169,7 +184,6 @@ public class CacheConstants * APP 我的猜你喜欢 */ public static final String APP_OWN_GUESS_LIKE = "app_own_guess_like"; - /** * 商品图搜次数统计 */ diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java index 75f05dbc5..57760e4df 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java @@ -2,7 +2,10 @@ package com.ruoyi.common.constant; import io.jsonwebtoken.Claims; +import java.util.Arrays; +import java.util.HashSet; import java.util.Locale; +import java.util.Set; /** * 通用常量信息 @@ -245,5 +248,9 @@ public class Constants * 以图搜图接口最大返回数 */ public static final int IMG_SEARCH_MAX_PAGE_NUM = 100; + /** + * APP 首页广告位置 插入广告的索引位置集合 获取精选热卖推广,将广告嵌入到列表中 每一页20条,5条广告嵌入到 3 7 11 15 19 + */ + public static final Set insertPositions = new HashSet<>(Arrays.asList(2, 6, 10, 14, 18)); } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/Page.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/page/Page.java index 0c5c0d0b6..8dacddc8a 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/Page.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/page/Page.java @@ -17,8 +17,8 @@ import java.util.List; * * @author ruoyi */ -@NoArgsConstructor -@AllArgsConstructor +//@NoArgsConstructor +//@AllArgsConstructor @Data @Accessors(chain = true) public class Page implements Serializable { @@ -47,6 +47,17 @@ public class Page implements Serializable { */ private List list; + public Page() { + } + + public Page(long pageNum, long pageSize, long pages, long total, List list) { + this.pageNum = pageNum; + this.pageSize = pageSize; + this.pages = pages; + this.total = total; + this.list = list; + } + public static Page convert(PageInfo pageInfo) { return BeanUtil.toBean(pageInfo, Page.class); } 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 7ba5955f1..067a63ef9 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 @@ -960,7 +960,7 @@ public class XktTask { // 构建部分文档更新请求 list.add(new BulkOperation.Builder().update(u -> u .action(a -> a.doc(new HashMap() {{ - put("tags", tags.stream().map(DailyProdTag::getTag).collect(Collectors.toList())); + put("tags", tags.stream().sorted(Comparator.comparing(x -> x.getType())).map(DailyProdTag::getTag).collect(Collectors.toList())); }})) .id(String.valueOf(storeProdId)) .index(Constants.ES_IDX_PRODUCT_INFO)) diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexHotSaleDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexHotSaleDTO.java new file mode 100644 index 000000000..379c18721 --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexHotSaleDTO.java @@ -0,0 +1,40 @@ +package com.ruoyi.xkt.dto.advertRound.app.index; + +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("APP首页热卖精选") +@Data +@Accessors(chain = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class APPIndexHotSaleDTO { + + @ApiModelProperty(value = "档口ID") + private String storeId; + @ApiModelProperty(value = "档口名称") + private String storeName; + @ApiModelProperty(value = "档口商品ID") + private String storeProdId; + @ApiModelProperty(value = "货号") + private String prodArtNum; + @ApiModelProperty(value = "主图") + private String mainPic; + @ApiModelProperty(value = "单价") + private String prodPrice; + @ApiModelProperty(value = "是否广告") + private Boolean advert; + @ApiModelProperty(value = "标签") + private List tags; + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexHotSalePageDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexHotSalePageDTO.java new file mode 100644 index 000000000..54e6cd37a --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexHotSalePageDTO.java @@ -0,0 +1,37 @@ +package com.ruoyi.xkt.dto.advertRound.app.index; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("APP精选热卖分页") +@Data +@Accessors(chain = true) +public class APPIndexHotSalePageDTO { + + @ApiModelProperty(value = "档口ID") + private String storeId; + @ApiModelProperty(value = "档口名称") + private String storeName; + @ApiModelProperty(value = "档口商品ID") + private String storeProdId; + @ApiModelProperty(value = "货号") + private String prodArtNum; + @ApiModelProperty(value = "主图") + private String mainPic; + @ApiModelProperty(value = "单价") + private String prodPrice; + @ApiModelProperty(value = "是否广告") + private Boolean advert; + @ApiModelProperty(value = "标签") + private List tags; + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexNewProdDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexNewProdDTO.java new file mode 100644 index 000000000..a0ec71910 --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexNewProdDTO.java @@ -0,0 +1,39 @@ +package com.ruoyi.xkt.dto.advertRound.app.index; + +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; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("APP首页新品榜列表") +@Data +@Accessors(chain = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class APPIndexNewProdDTO { + + @ApiModelProperty(value = "档口ID") + private String storeId; + @ApiModelProperty(value = "档口名称") + private String storeName; + @ApiModelProperty(value = "档口商品ID") + private String storeProdId; + @ApiModelProperty(value = "货号") + private String prodArtNum; + @ApiModelProperty(value = "主图") + private String mainPic; + @ApiModelProperty(value = "单价") + private String prodPrice; + @ApiModelProperty(value = "是否广告") + private Boolean advert; + @ApiModelProperty(value = "标签") + private List tags; + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexPopularSaleDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexPopularSaleDTO.java new file mode 100644 index 000000000..26d85040e --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPIndexPopularSaleDTO.java @@ -0,0 +1,39 @@ +package com.ruoyi.xkt.dto.advertRound.app.index; + +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; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("APP首页人气爆品列表") +@Data +@Accessors(chain = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class APPIndexPopularSaleDTO { + + @ApiModelProperty(value = "档口ID") + private String storeId; + @ApiModelProperty(value = "档口名称") + private String storeName; + @ApiModelProperty(value = "档口商品ID") + private String storeProdId; + @ApiModelProperty(value = "货号") + private String prodArtNum; + @ApiModelProperty(value = "主图") + private String mainPic; + @ApiModelProperty(value = "单价") + private String prodPrice; + @ApiModelProperty(value = "是否广告") + private Boolean advert; + @ApiModelProperty(value = "标签") + private List tags; + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPSearchDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPSearchDTO.java new file mode 100644 index 000000000..37fd2732c --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/app/index/APPSearchDTO.java @@ -0,0 +1,39 @@ +package com.ruoyi.xkt.dto.advertRound.app.index; + +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; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("APP 搜索 列表") +@Data +@Accessors(chain = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class APPSearchDTO { + + @ApiModelProperty(value = "档口ID") + private String storeId; + @ApiModelProperty(value = "档口名称") + private String storeName; + @ApiModelProperty(value = "档口商品ID") + private String storeProdId; + @ApiModelProperty(value = "货号") + private String prodArtNum; + @ApiModelProperty(value = "主图") + private String mainPic; + @ApiModelProperty(value = "单价") + private String prodPrice; + @ApiModelProperty(value = "是否广告") + private Boolean advert; + @ApiModelProperty(value = "标签") + private List tags; + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/pc/index/PCIndexRecommendDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/pc/index/PCIndexRecommendDTO.java new file mode 100644 index 000000000..a2e13cf3e --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/advertRound/pc/index/PCIndexRecommendDTO.java @@ -0,0 +1,39 @@ +package com.ruoyi.xkt.dto.advertRound.pc.index; + +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; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("PC首页为你推荐") +@Data +@Accessors(chain = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class PCIndexRecommendDTO { + + @ApiModelProperty(value = "档口ID") + private String storeId; + @ApiModelProperty(value = "档口名称") + private String storeName; + @ApiModelProperty(value = "档口商品ID") + private String storeProdId; + @ApiModelProperty(value = "货号") + private String prodArtNum; + @ApiModelProperty(value = "主图") + private String mainPic; + @ApiModelProperty(value = "单价") + private String prodPrice; + @ApiModelProperty(value = "是否广告") + private Boolean advert; + @ApiModelProperty(value = "标签") + private List tags; + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/storeProduct/StoreProdPriceAndMainPicAndTagDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/storeProduct/StoreProdPriceAndMainPicAndTagDTO.java new file mode 100644 index 000000000..426b9d46f --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/storeProduct/StoreProdPriceAndMainPicAndTagDTO.java @@ -0,0 +1,38 @@ +package com.ruoyi.xkt.dto.storeProduct; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@ApiModel("档口商品的价格及商品主图") +@Data +public class StoreProdPriceAndMainPicAndTagDTO { + + @ApiModelProperty(value = "档口商品ID") + private Long storeProdId; + @ApiModelProperty(value = "档口ID") + private Long storeId; + @ApiModelProperty(value = "档口名称") + private String storeName; + @ApiModelProperty(value = "商品标签字符串") + private String tagStr; + @ApiModelProperty(value = "商品标签") + private List tags; + @ApiModelProperty(value = "商品货号") + private String prodArtNum; + @ApiModelProperty(value = "档口商品定价") + private BigDecimal minPrice; + @ApiModelProperty(value = "档口商品主图") + private String mainPicUrl; + @ApiModelProperty(value = "商品标题") + private String prodTitle; + +} 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 8c3c00903..afd1cbaed 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductMapper.java +++ b/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductMapper.java @@ -72,5 +72,12 @@ public interface StoreProductMapper extends BaseMapper { */ List selectPriceAndMainPicList(@Param("storeProdIdList") List storeProdIdList); + /** + * 获取商品的价格主图及标签列表等 + * @param storeProdIdList 档口商品ID列表 + * @return List + */ + List selectPriceAndMainPicAndTagList(@Param("storeProdIdList") List storeProdIdList); + } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/IWebsiteService.java b/xkt/src/main/java/com/ruoyi/xkt/service/IWebsiteService.java index 30fb40f13..1648a79e0 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/IWebsiteService.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/IWebsiteService.java @@ -2,9 +2,7 @@ package com.ruoyi.xkt.service; import com.ruoyi.common.core.page.Page; import com.ruoyi.xkt.dto.advertRound.app.category.APPCateDTO; -import com.ruoyi.xkt.dto.advertRound.app.index.APPIndexHotSaleRightFixDTO; -import com.ruoyi.xkt.dto.advertRound.app.index.APPIndexMidBrandDTO; -import com.ruoyi.xkt.dto.advertRound.app.index.APPIndexTopBannerDTO; +import com.ruoyi.xkt.dto.advertRound.app.index.*; import com.ruoyi.xkt.dto.advertRound.app.own.APPOwnGuessLikeDTO; import com.ruoyi.xkt.dto.advertRound.pc.PCDownloadDTO; import com.ruoyi.xkt.dto.advertRound.pc.PCUserCenterDTO; @@ -20,7 +18,7 @@ import java.io.IOException; import java.util.List; /** - * 档口销售出库Service接口 + * 系统广告位置及搜索页 * * @author ruoyi * @date 2025-03-26 @@ -201,4 +199,45 @@ public interface IWebsiteService { * @return List */ List getAppOwnGuessLikeList(); + + /** + * APP 首页热卖精选列表 + * + * @param searchDTO 搜索入参 + * @return List + */ + Page appIndexHotSalePage(IndexSearchDTO searchDTO) throws IOException; + + /** + * APP 首页 人气爆品列表 + * + * @param searchDTO 搜索入参 + * @return Page + */ + Page appIndexPopularSalePage(IndexSearchDTO searchDTO) throws IOException; + + /** + * APP 首页 新品榜 + * + * @param searchDTO 搜索入参 + * @return Page + */ + Page appIndexNewProdPage(IndexSearchDTO searchDTO) throws IOException; + + /** + * APP 搜索列表 + * + * @param searchDTO 搜索入参 + * @return Page + */ + Page appSearchPage(IndexSearchDTO searchDTO) throws IOException; + + /** + * PC 首页 为你推荐 + * + * @param searchDTO 搜索入参 + * @return List + */ + Page pcIndexRecommendPage(IndexSearchDTO searchDTO); + } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/WebsiteServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/WebsiteServiceImpl.java index 4aabaf82b..09124e138 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/WebsiteServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/WebsiteServiceImpl.java @@ -1,11 +1,11 @@ package com.ruoyi.xkt.service.impl; +import cn.hutool.core.bean.BeanUtil; import co.elastic.clients.elasticsearch._types.FieldValue; import co.elastic.clients.elasticsearch._types.SortOrder; import co.elastic.clients.elasticsearch._types.query_dsl.*; import co.elastic.clients.elasticsearch.core.SearchResponse; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.github.pagehelper.PageInfo; import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.page.Page; @@ -15,9 +15,7 @@ import com.ruoyi.common.utils.DateUtils; import com.ruoyi.framework.es.EsClientWrapper; import com.ruoyi.xkt.domain.*; import com.ruoyi.xkt.dto.advertRound.app.category.APPCateDTO; -import com.ruoyi.xkt.dto.advertRound.app.index.APPIndexHotSaleRightFixDTO; -import com.ruoyi.xkt.dto.advertRound.app.index.APPIndexMidBrandDTO; -import com.ruoyi.xkt.dto.advertRound.app.index.APPIndexTopBannerDTO; +import com.ruoyi.xkt.dto.advertRound.app.index.*; import com.ruoyi.xkt.dto.advertRound.app.own.APPOwnGuessLikeDTO; import com.ruoyi.xkt.dto.advertRound.pc.PCDownloadDTO; import com.ruoyi.xkt.dto.advertRound.pc.PCUserCenterDTO; @@ -28,6 +26,7 @@ import com.ruoyi.xkt.dto.advertRound.pc.store.PCStoreTopBannerDTO; import com.ruoyi.xkt.dto.advertRound.picSearch.PicSearchAdvertDTO; import com.ruoyi.xkt.dto.dailySale.CateSaleRankDTO; import com.ruoyi.xkt.dto.es.ESProductDTO; +import com.ruoyi.xkt.dto.storeProduct.StoreProdPriceAndMainPicAndTagDTO; import com.ruoyi.xkt.dto.storeProduct.StoreProdPriceAndMainPicDTO; import com.ruoyi.xkt.dto.storeProductFile.StoreProdFileResDTO; import com.ruoyi.xkt.dto.website.IndexSearchDTO; @@ -74,6 +73,247 @@ public class WebsiteServiceImpl implements IWebsiteService { final StoreMapper storeMapper; final StoreProductStatisticsMapper prodStatsMapper; + /** + * APP 首页热卖精选列表 + * + * @param searchDTO 搜索入参 + * @return List + */ + @Override + @Transactional(readOnly = true) + public Page appIndexHotSalePage(IndexSearchDTO searchDTO) throws IOException { + Page page = this.search(searchDTO); + // 筛选出真实的数据 + List realDataList = page.getList().stream() + .map(esProduct -> BeanUtil.toBean(esProduct, APPIndexHotSaleDTO.class).setAdvert(Boolean.FALSE)).collect(Collectors.toList()); + // APP 只有第一页 有数据 其它页暂时没有广告 + if (searchDTO.getPageNum() > 1) { + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), realDataList); + } + // 从redis中获取广告 + List redisList = this.redisCache.getCacheObject(CacheConstants.APP_ADVERT + CacheConstants.APP_INDEX_HOT_SALE_ADVERT); + if (CollectionUtils.isNotEmpty(redisList)) { + // 添加广告的数据 + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), insertAdvertsIntoList(realDataList, redisList, Constants.insertPositions)); + } else { + // 从数据库查首页精选热卖推广(精准搜索是否存在推广,不存在从已过期的数据中拉数据来凑数) + List advertRoundList = this.advertRoundMapper.selectList(new LambdaQueryWrapper() + .isNotNull(AdvertRound::getStoreId).eq(AdvertRound::getDelFlag, Constants.UNDELETED) + .eq(AdvertRound::getTypeId, AdType.APP_HOME_HOT_RECOMMEND_PROD.getValue()) + .eq(AdvertRound::getLaunchStatus, AdLaunchStatus.LAUNCHING.getValue())); + if (CollectionUtils.isNotEmpty(advertRoundList)) { + List attrList = storeProdMapper.selectPriceAndMainPicAndTagList(advertRoundList.stream() + .map(x -> x.getProdIdStr()).map(Long::parseLong).collect(Collectors.toList())); + attrList = attrList.stream().peek(x -> x.setTags(StringUtils.isNotBlank(x.getTagStr()) ? Arrays.asList(x.getTagStr().split(",")) : null)).collect(Collectors.toList()); + Map attrMap = attrList.stream().collect(Collectors.toMap(StoreProdPriceAndMainPicAndTagDTO::getStoreProdId, x -> x)); + List hotSaleList = advertRoundList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO attrDto = attrMap.get(Long.parseLong(x.getProdIdStr())); + return new APPIndexHotSaleDTO().setAdvert(Boolean.TRUE).setStoreId(x.getStoreId().toString()) + .setStoreProdId(x.getProdIdStr()).setTags(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getTags() : null) + .setStoreName(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getStoreName() : "") + .setProdPrice(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMinPrice().toString() : null) + .setProdArtNum(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getProdArtNum() : "") + .setMainPic(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicUrl() : ""); + }).collect(Collectors.toList()); + // 放到redis中 有效期1天 + this.redisCache.setCacheObject(CacheConstants.APP_ADVERT + CacheConstants.APP_INDEX_HOT_SALE_ADVERT, hotSaleList, 1, TimeUnit.DAYS); + // 添加了广告的数据 + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), insertAdvertsIntoList(realDataList, hotSaleList, Constants.insertPositions)); + } + } + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), realDataList); + } + + /** + * APP 首页 人气爆品列表 + * + * @param searchDTO 搜索入参 + * @return Page + */ + @Override + @Transactional(readOnly = true) + public Page appIndexPopularSalePage(IndexSearchDTO searchDTO) throws IOException { + Page page = this.search(searchDTO); + // 筛选出真实的数据 + List realDataList = page.getList().stream() + .map(esProduct -> BeanUtil.toBean(esProduct, APPIndexPopularSaleDTO.class).setAdvert(Boolean.FALSE)).collect(Collectors.toList()); + // APP 只有第一页 有数据 其它页暂时没有广告 + if (searchDTO.getPageNum() > 1) { + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), realDataList); + } + // 从redis中获取数据 + List redisList = this.redisCache.getCacheObject(CacheConstants.APP_ADVERT + CacheConstants.APP_INDEX_POPULAR_SALE_ADVERT); + if (CollectionUtils.isNotEmpty(redisList)) { + // 添加广告的数据 + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), insertAdvertsIntoList(realDataList, redisList, Constants.insertPositions)); + } else { + // 从数据库查首页 人气爆品 推广(精准搜索是否存在推广,不存在从已过期的数据中拉数据来凑数) + List advertRoundList = this.advertRoundMapper.selectList(new LambdaQueryWrapper() + .isNotNull(AdvertRound::getStoreId).eq(AdvertRound::getDelFlag, Constants.UNDELETED) + .eq(AdvertRound::getTypeId, AdType.APP_HOME_POP_RECOMMEND_PROD.getValue()) + .eq(AdvertRound::getLaunchStatus, AdLaunchStatus.LAUNCHING.getValue())); + if (CollectionUtils.isNotEmpty(advertRoundList)) { + List attrList = storeProdMapper.selectPriceAndMainPicAndTagList(advertRoundList.stream() + .map(x -> x.getProdIdStr()).map(Long::parseLong).collect(Collectors.toList())); + attrList = attrList.stream().peek(x -> x.setTags(StringUtils.isNotBlank(x.getTagStr()) ? Arrays.asList(x.getTagStr().split(",")) : null)).collect(Collectors.toList()); + Map attrMap = attrList.stream().collect(Collectors.toMap(StoreProdPriceAndMainPicAndTagDTO::getStoreProdId, x -> x)); + List popularSaleList = advertRoundList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO attrDto = attrMap.get(Long.parseLong(x.getProdIdStr())); + return new APPIndexPopularSaleDTO().setAdvert(Boolean.TRUE).setStoreId(x.getStoreId().toString()) + .setStoreProdId(x.getProdIdStr()).setTags(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getTags() : null) + .setStoreName(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getStoreName() : "") + .setProdPrice(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMinPrice().toString() : null) + .setProdArtNum(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getProdArtNum() : "") + .setMainPic(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicUrl() : ""); + }).collect(Collectors.toList()); + // 放到redis中 有效期1天 + this.redisCache.setCacheObject(CacheConstants.APP_ADVERT + CacheConstants.APP_INDEX_POPULAR_SALE_ADVERT, popularSaleList, 1, TimeUnit.DAYS); + // 添加了广告的数据 + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), insertAdvertsIntoList(realDataList, popularSaleList, Constants.insertPositions)); + } + } + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), realDataList); + } + + /** + * APP 首页 新品榜 + * + * @param searchDTO 搜索入参 + * @return Page + */ + @Override + @Transactional(readOnly = true) + public Page appIndexNewProdPage(IndexSearchDTO searchDTO) throws IOException { + Page page = this.search(searchDTO); + // 筛选出真实的数据 + List realDataList = page.getList().stream() + .map(esProduct -> BeanUtil.toBean(esProduct, APPIndexNewProdDTO.class).setAdvert(Boolean.FALSE)).collect(Collectors.toList()); + // APP 只有第一页 有数据 其它页暂时没有广告 + if (searchDTO.getPageNum() > 1) { + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), realDataList); + } + // 从redis中获取数据 + List redisList = this.redisCache.getCacheObject(CacheConstants.APP_ADVERT + CacheConstants.APP_INDEX_NEW_PROD); + if (CollectionUtils.isNotEmpty(redisList)) { + // 添加广告的数据 + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), insertAdvertsIntoList(realDataList, redisList, Constants.insertPositions)); + } else { + // 从数据库查首页 新品榜 推广(精准搜索是否存在推广,不存在从已过期的数据中拉数据来凑数) + List advertRoundList = this.advertRoundMapper.selectList(new LambdaQueryWrapper() + .isNotNull(AdvertRound::getStoreId).eq(AdvertRound::getDelFlag, Constants.UNDELETED) + .eq(AdvertRound::getTypeId, AdType.APP_HOME_NEW_PROD_RECOMMEND_PROD.getValue()) + .eq(AdvertRound::getLaunchStatus, AdLaunchStatus.LAUNCHING.getValue())); + if (CollectionUtils.isNotEmpty(advertRoundList)) { + List attrList = storeProdMapper.selectPriceAndMainPicAndTagList(advertRoundList.stream() + .map(x -> x.getProdIdStr()).map(Long::parseLong).collect(Collectors.toList())); + attrList = attrList.stream().peek(x -> x.setTags(StringUtils.isNotBlank(x.getTagStr()) ? Arrays.asList(x.getTagStr().split(",")) : null)).collect(Collectors.toList()); + Map attrMap = attrList.stream().collect(Collectors.toMap(StoreProdPriceAndMainPicAndTagDTO::getStoreProdId, x -> x)); + List newProdList = advertRoundList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO attrDto = attrMap.get(Long.parseLong(x.getProdIdStr())); + return new APPIndexNewProdDTO().setAdvert(Boolean.TRUE).setStoreId(x.getStoreId().toString()) + .setStoreProdId(x.getProdIdStr()).setTags(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getTags() : null) + .setStoreName(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getStoreName() : "") + .setProdPrice(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMinPrice().toString() : null) + .setProdArtNum(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getProdArtNum() : "") + .setMainPic(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicUrl() : ""); + }).collect(Collectors.toList()); + // 放到redis中 有效期1天 + this.redisCache.setCacheObject(CacheConstants.APP_ADVERT + CacheConstants.APP_INDEX_NEW_PROD, newProdList, 1, TimeUnit.DAYS); + // 添加了广告的数据 + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), insertAdvertsIntoList(realDataList, newProdList, Constants.insertPositions)); + } + } + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), realDataList); + } + + /** + * APP 搜索列表 + * + * @param searchDTO 搜索入参 + * @return Page + */ + @Override + @Transactional(readOnly = true) + public Page appSearchPage(IndexSearchDTO searchDTO) throws IOException { + Page page = this.search(searchDTO); + // 筛选出真实的数据 + List realDataList = page.getList().stream() + .map(esProduct -> BeanUtil.toBean(esProduct, APPSearchDTO.class).setAdvert(Boolean.FALSE)).collect(Collectors.toList()); + // APP 只有第一页 有数据 其它页暂时没有广告 + if (searchDTO.getPageNum() > 1) { + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), realDataList); + } + // 从redis中获取数据 + List redisList = this.redisCache.getCacheObject(CacheConstants.APP_ADVERT + CacheConstants.APP_SEARCH); + if (CollectionUtils.isNotEmpty(redisList)) { + // 添加广告的数据 + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), insertAdvertsIntoList(realDataList, redisList, Constants.insertPositions)); + } else { + // 从数据库查首页 新品榜 推广(精准搜索是否存在推广,不存在从已过期的数据中拉数据来凑数) + List advertRoundList = this.advertRoundMapper.selectList(new LambdaQueryWrapper() + .isNotNull(AdvertRound::getStoreId).eq(AdvertRound::getDelFlag, Constants.UNDELETED) + .eq(AdvertRound::getTypeId, AdType.APP_SEARCH_RESULT.getValue()) + .eq(AdvertRound::getLaunchStatus, AdLaunchStatus.LAUNCHING.getValue())); + if (CollectionUtils.isNotEmpty(advertRoundList)) { + List attrList = storeProdMapper.selectPriceAndMainPicAndTagList(advertRoundList.stream() + .map(x -> x.getProdIdStr()).map(Long::parseLong).collect(Collectors.toList())); + attrList = attrList.stream().peek(x -> x.setTags(StringUtils.isNotBlank(x.getTagStr()) ? Arrays.asList(x.getTagStr().split(",")) : null)).collect(Collectors.toList()); + Map attrMap = attrList.stream().collect(Collectors.toMap(StoreProdPriceAndMainPicAndTagDTO::getStoreProdId, x -> x)); + List newProdList = advertRoundList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO attrDto = attrMap.get(Long.parseLong(x.getProdIdStr())); + return new APPSearchDTO().setAdvert(Boolean.TRUE).setStoreId(x.getStoreId().toString()) + .setStoreProdId(x.getProdIdStr()).setTags(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getTags() : null) + .setStoreName(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getStoreName() : "") + .setProdPrice(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMinPrice().toString() : null) + .setProdArtNum(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getProdArtNum() : "") + .setMainPic(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicUrl() : ""); + }).collect(Collectors.toList()); + // 放到redis中 有效期1天 + this.redisCache.setCacheObject(CacheConstants.APP_ADVERT + CacheConstants.APP_SEARCH, newProdList, 1, TimeUnit.DAYS); + // 添加了广告的数据 + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), insertAdvertsIntoList(realDataList, newProdList, Constants.insertPositions)); + } + } + return new Page<>(page.getPageNum(), page.getPageSize(), page.getPages(), page.getTotal(), realDataList); + } + + /** + * PC 首页 为你推荐 + * + * @param searchDTO 搜索入参 + * @return List + */ + @Override + @Transactional(readOnly = true) + public Page pcIndexRecommendPage(IndexSearchDTO searchDTO) { + + return null; + } + + /** + * 在指定位置插入广告数据到列表中 + * + * @param dataList 原始数据列表 + * @param adverts 广告数据列表 + * @param positions 插入广告的位置集合 + * @param 数据类型 + * @return 合并后的列表 + */ + public static List insertAdvertsIntoList(List dataList, List adverts, Set positions) { + List mergedList = new ArrayList<>(); + int dataIndex = 0; + int advertIndex = 0; + for (int i = 0; i < dataList.size() + positions.size(); i++) { + if (positions.contains(i) && advertIndex < adverts.size()) { + mergedList.add(adverts.get(advertIndex++)); + } else if (dataIndex < dataList.size()) { + mergedList.add(dataList.get(dataIndex++)); + } + } + return mergedList; + } + + /** * 网站首页搜索 * @@ -82,19 +322,6 @@ public class WebsiteServiceImpl implements IWebsiteService { @Override @Transactional(readOnly = true) public Page search(IndexSearchDTO searchDTO) throws IOException { - - /*// 查询索引 - GetIndexResponse res = esClientWrapper.getEsClient().indices().get(request -> request.index(indexName)); - System.err.println(res); - System.err.println(res.result()); - - Set all = esClientWrapper.getEsClient().indices().get(req -> req.index("*")).result().keySet(); - System.out.println("all = " + all); - - GetResponse response = esClientWrapper.getEsClient().get(g -> g.index(indexName).id("1"), ESProductInfo.class); - System.err.println(response);*/ - // 分页查询 - // 构建 bool 查询 BoolQuery.Builder boolQuery = new BoolQuery.Builder(); // 添加 price 范围查询 @@ -161,7 +388,6 @@ public class WebsiteServiceImpl implements IWebsiteService { .build(); boolQuery.filter(f -> f.terms(t -> t.field("season.keyword").terms(termsQueryField))); } - // 如果是按照时间过滤,则表明是“新品”,则限制 时间范围 20天前到现在 if (Objects.equals(searchDTO.getSort(), "createTime")) { // 当前时间 @@ -174,20 +400,16 @@ public class WebsiteServiceImpl implements IWebsiteService { builder.date(DateRangeQuery.of(d -> d.field("createTime").gte(agoStr).lte(nowStr))); boolQuery.filter(builder.build()._toQuery()); } - // 构建最终的查询 Query query = new Query.Builder().bool(boolQuery.build()).build(); // 执行搜索 SearchResponse resList = esClientWrapper.getEsClient().search(s -> s.index(Constants.ES_IDX_PRODUCT_INFO) - .query(query).from(searchDTO.getPageNum() - 1).size(searchDTO.getPageSize()) + .query(query).from((searchDTO.getPageNum() - 1) * searchDTO.getPageSize()).size(searchDTO.getPageSize()) .sort(sort -> sort.field(f -> f.field(searchDTO.getSort()).order(SortOrder.Desc))), ESProductDTO.class); - - System.err.println(resList); - - return CollectionUtils.isEmpty(resList.hits().hits()) ? Page.empty(searchDTO.getPageSize(), searchDTO.getPageNum()) - : Page.convert(new PageInfo<>(resList.hits().hits().stream().map(x -> x.source().setStoreProdId(x.id())).collect(Collectors.toList()))); -// : Page.convert(new PageInfo<>(resList.hits().hits().stream().map(Hit::source).collect(Collectors.toList()))); + final long total = resList.hits().total().value(); + final List esProdList = resList.hits().hits().stream().map(x -> x.source().setStoreProdId(x.id())).collect(Collectors.toList()); + return new Page<>(searchDTO.getPageNum(), searchDTO.getPageSize(), total / searchDTO.getPageSize() + 1, total, esProdList); } /** @@ -1444,6 +1666,7 @@ public class WebsiteServiceImpl implements IWebsiteService { } + /** * 获取PC 下载页数据 * diff --git a/xkt/src/main/resources/mapper/StoreProductMapper.xml b/xkt/src/main/resources/mapper/StoreProductMapper.xml index c68494b38..3fd5ad3e4 100644 --- a/xkt/src/main/resources/mapper/StoreProductMapper.xml +++ b/xkt/src/main/resources/mapper/StoreProductMapper.xml @@ -127,6 +127,39 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" sf.file_url + + + +