From 97a2fb84b78d2eef4e9b1f5c43830c1b052cb71c Mon Sep 17 00:00:00 2001 From: liujiang <569804566@qq.com> Date: Mon, 6 Oct 2025 20:23:55 +0800 Subject: [PATCH] =?UTF-8?q?master=EF=BC=9A=E5=95=86=E5=9F=8E=E6=A1=A3?= =?UTF-8?q?=E5=8F=A3=E9=A6=96=E9=A1=B5=E8=BF=94=E5=9B=9E=E5=90=84=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E6=95=B0=E6=8D=AE=E8=B0=83=E4=BC=98=EF=BC=8C=E6=A1=A3?= =?UTF-8?q?=E5=8F=A3=E8=B4=AD=E4=B9=B0=E4=BC=9A=E5=91=98=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=AE=8C=E5=96=84=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StoreHomeTemplateTwoResVO.java | 13 +- .../mapper/quartz/DailySaleProductMapper.xml | 29 -- .../StoreHomeTemplateTwoResDTO.java | 11 +- .../storeProdColorSize/StoreStorageSnDTO.java | 1 - .../xkt/mapper/DailySaleProductMapper.java | 9 - .../ruoyi/xkt/mapper/StoreProductMapper.java | 12 +- .../impl/AdminAdvertRoundServiceImpl.java | 2 +- .../impl/StoreHomepageServiceImpl.java | 401 ++++++++++++++---- .../service/impl/StoreMemberServiceImpl.java | 8 +- .../resources/mapper/StoreProductMapper.xml | 23 + 10 files changed, 377 insertions(+), 132 deletions(-) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/storeHomepage/StoreHomeTemplateTwoResVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/storeHomepage/StoreHomeTemplateTwoResVO.java index 10243a8fd..78cccb495 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/storeHomepage/StoreHomeTemplateTwoResVO.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/storeHomepage/StoreHomeTemplateTwoResVO.java @@ -18,13 +18,15 @@ public class StoreHomeTemplateTwoResVO { @ApiModelProperty(value = "顶部左侧轮播图") List topLeftList; @ApiModelProperty(value = "右侧店铺公告") - String notice; + SHTTNoticeVO notice; @ApiModelProperty(value = "店家推荐") List recommendList; @ApiModelProperty(value = "人气爆款") List popularSaleList; @ApiModelProperty(value = "当季新品") List newProdList; + @ApiModelProperty(value = "销量排行") + List saleRankList; @Data @ApiModel @@ -39,4 +41,13 @@ public class StoreHomeTemplateTwoResVO { private Integer orderNum; } + @Data + @ApiModel + public static class SHTTNoticeVO { + @ApiModelProperty(value = "标题") + private String noticeTitle; + @ApiModelProperty(value = "内容") + private String noticeContent; + } + } diff --git a/ruoyi-quartz/src/main/resources/mapper/quartz/DailySaleProductMapper.xml b/ruoyi-quartz/src/main/resources/mapper/quartz/DailySaleProductMapper.xml index b1605b729..5e2989abc 100644 --- a/ruoyi-quartz/src/main/resources/mapper/quartz/DailySaleProductMapper.xml +++ b/ruoyi-quartz/src/main/resources/mapper/quartz/DailySaleProductMapper.xml @@ -184,34 +184,5 @@ count DESC; - - - - \ No newline at end of file diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/storeHomepage/StoreHomeTemplateTwoResDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/storeHomepage/StoreHomeTemplateTwoResDTO.java index 2cf1121e3..85513140e 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/dto/storeHomepage/StoreHomeTemplateTwoResDTO.java +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/storeHomepage/StoreHomeTemplateTwoResDTO.java @@ -20,7 +20,7 @@ public class StoreHomeTemplateTwoResDTO { @ApiModelProperty(value = "顶部左侧轮播图") List topLeftList; @ApiModelProperty(value = "右侧店铺公告") - String notice; + SHTTNoticeDTO notice; @ApiModelProperty(value = "店家推荐") List recommendList; @ApiModelProperty(value = "人气爆款") @@ -30,4 +30,13 @@ public class StoreHomeTemplateTwoResDTO { @ApiModelProperty(value = "销量排行") List saleRankList; + @Data + @ApiModel + public static class SHTTNoticeDTO { + @ApiModelProperty(value = "标题") + private String noticeTitle; + @ApiModelProperty(value = "内容") + private String noticeContent; + } + } diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/storeProdColorSize/StoreStorageSnDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/storeProdColorSize/StoreStorageSnDTO.java index a038fec38..1f2671cc2 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/dto/storeProdColorSize/StoreStorageSnDTO.java +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/storeProdColorSize/StoreStorageSnDTO.java @@ -25,7 +25,6 @@ public class StoreStorageSnDTO { @Data @Accessors(chain = true) public static class SSSDetailDTO { - @ApiModelProperty(value = "档口商品颜色尺码ID") private Long storeProdColorId; @ApiModelProperty(value = "档口商品ID") diff --git a/xkt/src/main/java/com/ruoyi/xkt/mapper/DailySaleProductMapper.java b/xkt/src/main/java/com/ruoyi/xkt/mapper/DailySaleProductMapper.java index f09ddb8b7..21ea1d756 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/mapper/DailySaleProductMapper.java +++ b/xkt/src/main/java/com/ruoyi/xkt/mapper/DailySaleProductMapper.java @@ -94,13 +94,4 @@ public interface DailySaleProductMapper extends BaseMapper { */ List prodCateSaleTop50List(@Param("oneMonthAgo") Date oneMonthAgo, @Param("yesterday") Date yesterday); - /** - * 获取当前档口销量最好的10件商品作为默认的推荐商品 - * - * @param storeId 档口ID - * @param fiveDaysAgo 5天前 - * @param yesterday 昨天 - * @return - */ - List selectStoreDefaultRecommendList(@Param("storeId") Long storeId, @Param("fiveDaysAgo") Date fiveDaysAgo, @Param("yesterday") Date yesterday); } 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 945356058..85f04ee77 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductMapper.java +++ b/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductMapper.java @@ -3,6 +3,7 @@ package com.ruoyi.xkt.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.xkt.domain.StoreProduct; import com.ruoyi.xkt.dto.dailyStoreTag.DailyStoreTagDTO; +import com.ruoyi.xkt.dto.storeHomepage.StoreRecommendResDTO; import com.ruoyi.xkt.dto.storeProduct.*; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; @@ -124,9 +125,18 @@ public interface StoreProductMapper extends BaseMapper { /** * 获取档口各个状态的数量 * - * @param storeId 档口ID + * @param storeId 档口ID * @return StoreProdStatusCountResDTO */ StoreProdStatusCountResDTO getStatusNum(@Param("storeId") Long storeId); + + /** + * 获取档口最新的10个商品 + * + * @param storeId 档口ID + * @return List + */ + List selectLatest10List(@Param("storeId") Long storeId); + } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/AdminAdvertRoundServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/AdminAdvertRoundServiceImpl.java index ef566ac9c..f7967c504 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/AdminAdvertRoundServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/AdminAdvertRoundServiceImpl.java @@ -62,7 +62,7 @@ public class AdminAdvertRoundServiceImpl implements IAdminAdvertRoundService { @Override @Transactional(readOnly = true) public Page page(AdminAdRoundPageDTO pageDTO) { - // 用户是否为档口管理者或子账户 + // 用户是否为管理员 if (!SecurityUtils.isAdmin()) { throw new ServiceException("当前用户非管理员账号,无权限操作!", HttpStatus.ERROR); } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreHomepageServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreHomepageServiceImpl.java index 0bedad2fa..621413c9b 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreHomepageServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreHomepageServiceImpl.java @@ -1,6 +1,7 @@ package com.ruoyi.xkt.service.impl; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.HttpStatus; @@ -10,10 +11,7 @@ import com.ruoyi.xkt.domain.*; import com.ruoyi.xkt.dto.storeHomepage.*; import com.ruoyi.xkt.dto.storeProduct.StoreProdPriceAndMainPicAndTagDTO; import com.ruoyi.xkt.dto.storeProductFile.StoreProdMainPicDTO; -import com.ruoyi.xkt.enums.AdDisplayType; -import com.ruoyi.xkt.enums.FileType; -import com.ruoyi.xkt.enums.HomepageJumpType; -import com.ruoyi.xkt.enums.HomepageType; +import com.ruoyi.xkt.enums.*; import com.ruoyi.xkt.mapper.*; import com.ruoyi.xkt.service.IStoreHomepageService; import lombok.RequiredArgsConstructor; @@ -23,7 +21,6 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.time.LocalDate; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -50,6 +47,7 @@ public class StoreHomepageServiceImpl implements IStoreHomepageService { final StoreCertificateMapper storeCertMapper; final DailySaleProductMapper dailySaleProdMapper; final DailyProdTagMapper dailyProdTagMapper; + final NoticeMapper noticeMapper; /** * 获取档口首页各个部分的图信息 @@ -167,26 +165,9 @@ public class StoreHomepageServiceImpl implements IStoreHomepageService { .eq(StoreHomepage::getStoreId, storeId).eq(StoreHomepage::getDelFlag, Constants.UNDELETED) .eq(StoreHomepage::getFileType, HomepageType.STORE_RECOMMENDED.getValue())); if (CollectionUtils.isEmpty(recommendList)) { - final Date yesterday = java.sql.Date.valueOf(LocalDate.now().minusDays(1)); - final Date fiveDaysAgo = java.sql.Date.valueOf(LocalDate.now().minusDays(6)); - - - // TODO 推荐商品逻辑修改,要确保档口从一入驻,整个档口首页就能正常显示数据 - // TODO 推荐商品逻辑修改,要确保档口从一入驻,整个档口首页就能正常显示数据 - // TODO 推荐商品逻辑修改,要确保档口从一入驻,整个档口首页就能正常显示数据 - // TODO 推荐商品逻辑修改,要确保档口从一入驻,整个档口首页就能正常显示数据 - // TODO 推荐商品逻辑修改,要确保档口从一入驻,整个档口首页就能正常显示数据 - // TODO 推荐商品逻辑修改,要确保档口从一入驻,整个档口首页就能正常显示数据 - - - // 如果档口未设置推荐商品,则筛选销量最好的10条商品 - List dailySaleTop10ProdList = this.dailySaleProdMapper.selectStoreDefaultRecommendList(storeId, fiveDaysAgo, yesterday); + // 未设置推荐的商品,则获取档口最新上传的10个商品 + List dailySaleTop10ProdList = this.storeProdMapper.selectLatest10List(storeId); return CollectionUtils.isEmpty(dailySaleTop10ProdList) ? Collections.emptyList() : this.getDefaultRecommendList(storeId, dailySaleTop10ProdList); - - - - - } // 商品价格、主图、标签等 List attrList = this.storeProdMapper.selectPriceAndMainPicAndTagList(recommendList.stream() @@ -205,41 +186,7 @@ public class StoreHomepageServiceImpl implements IStoreHomepageService { .collect(Collectors.toList()); } - /** - * 获取默认的推荐推荐商品 - * - * @param storeId 档口ID - * @param dailySaleTop10ProdList 近5日销量排名前10的商品 - * @return List - */ - private List getDefaultRecommendList(Long storeId, List dailySaleTop10ProdList) { - // 获取商品标签 - List prodTagList = this.dailyProdTagMapper.selectList(new LambdaQueryWrapper() - .eq(DailyProdTag::getStoreId, storeId).eq(DailyProdTag::getDelFlag, Constants.UNDELETED) - .in(DailyProdTag::getStoreProdId, dailySaleTop10ProdList.stream().map(StoreRecommendResDTO::getStoreProdId).collect(Collectors.toList()))); - Map> tagMap = CollectionUtils.isEmpty(prodTagList) ? new HashMap<>() - : prodTagList.stream().collect(Collectors.groupingBy(x -> x.getStoreProdId().toString(), Collectors.mapping(DailyProdTag::getTag, Collectors.toList()))); - // 获取商品主图及视频等 - List prodFileList = this.prodFileMapper.selectList(new LambdaQueryWrapper() - .eq(StoreProductFile::getStoreId, storeId).eq(StoreProductFile::getDelFlag, Constants.UNDELETED).eq(StoreProductFile::getOrderNum, ORDER_NUM_1) - .in(StoreProductFile::getStoreProdId, dailySaleTop10ProdList.stream().map(StoreRecommendResDTO::getStoreProdId).collect(Collectors.toList())) - .in(StoreProductFile::getFileType, Arrays.asList(FileType.MAIN_PIC.getValue(), FileType.MAIN_PIC_VIDEO.getValue()))); - // 档口商品主图map - Map mainPicMap = prodFileList.stream().filter(x -> Objects.equals(x.getFileType(), FileType.MAIN_PIC.getValue())) - .collect(Collectors.toMap(x -> x.getStoreProdId().toString(), StoreProductFile::getFileId)); - // 档口商品视频map - Map videoMap = prodFileList.stream().filter(x -> Objects.equals(x.getFileType(), FileType.MAIN_PIC_VIDEO.getValue())) - .collect(Collectors.toMap(x -> x.getStoreProdId().toString(), StoreProductFile::getFileId)); - List fileList = this.fileMapper.selectList(new LambdaQueryWrapper().eq(SysFile::getDelFlag, Constants.UNDELETED) - .in(SysFile::getId, prodFileList.stream().map(StoreProductFile::getFileId).collect(Collectors.toList()))); - Map fileMap = CollectionUtils.isEmpty(fileList) ? new HashMap<>() : fileList.stream().collect(Collectors.toMap(SysFile::getId, SysFile::getFileUrl)); - dailySaleTop10ProdList.forEach(x -> { - x.setTags(tagMap.getOrDefault(x.getStoreProdId(), new ArrayList<>())); - x.setMainPicUrl(fileMap.get(mainPicMap.get(x.getStoreProdId()))); - x.setHasVideo(videoMap.containsKey(x.getStoreProdId())); - }); - return dailySaleTop10ProdList; - } + /** * 档口首页模板一返回数据 @@ -251,27 +198,147 @@ public class StoreHomepageServiceImpl implements IStoreHomepageService { @Transactional(readOnly = true) public StoreHomeTemplateOneResDTO getTemplateOne(Long storeId) { // 顶部轮播大图 - StoreHomeTemplateOneResDTO templateTwo = new StoreHomeTemplateOneResDTO().setTopLeftList(this.storeHomeMapper.selectTopLeftList(storeId)); + StoreHomeTemplateOneResDTO templateOne = new StoreHomeTemplateOneResDTO().setTopLeftList(this.storeHomeMapper.selectTopLeftList(storeId)); // 其他区域 - List otherList = this.storeHomeMapper.selectList(new LambdaQueryWrapper() + List otherList = ObjectUtils.defaultIfNull(this.storeHomeMapper.selectList(new LambdaQueryWrapper() .eq(StoreHomepage::getStoreId, storeId).eq(StoreHomepage::getDelFlag, Constants.UNDELETED) .in(StoreHomepage::getFileType, Arrays.asList(HomepageType.POPULAR_SALES.getValue(), HomepageType.SLIDING_PICTURE_SMALL.getValue(), HomepageType.SEASON_NEW_PRODUCTS.getValue(), - HomepageType.STORE_RECOMMENDED.getValue(), HomepageType.SALES_RANKING.getValue()))); - if (CollectionUtils.isEmpty(otherList)) { - return templateTwo; + HomepageType.STORE_RECOMMENDED.getValue(), HomepageType.SALES_RANKING.getValue()))), new ArrayList<>()); + // 商品ID列表 + List prodIdList = CollectionUtils.isEmpty(otherList) ? new ArrayList<>() : otherList.stream().map(StoreHomepage::getBizId).collect(Collectors.toList()); + // 筛选商品最新的50条数据 + List latest50ProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProduct::getStoreId, storeId).eq(StoreProduct::getDelFlag, Constants.UNDELETED) + .orderByDesc(StoreProduct::getCreateTime).last("LIMIT 50")); + CollectionUtils.addAll(prodIdList, latest50ProdList.stream().map(StoreProduct::getId).collect(Collectors.toList())); + if (CollectionUtils.isEmpty(latest50ProdList)) { + return templateOne; } - final List storeProdIdList = otherList.stream().map(StoreHomepage::getBizId).collect(Collectors.toList()); - List attrList = storeProdMapper.selectPriceAndMainPicAndTagList(storeProdIdList); - Map attrMap = attrList.stream().collect(Collectors.toMap(StoreProdPriceAndMainPicAndTagDTO::getStoreProdId, x -> x)); - return templateTwo - .setTopRightList(this.getTemplateTypeList(otherList, attrMap, HomepageType.SLIDING_PICTURE_SMALL.getValue(), 2)) - .setRecommendList(this.getTemplateTypeList(otherList, attrMap, HomepageType.STORE_RECOMMENDED.getValue(), 5)) - .setPopularSaleList(this.getTemplateTypeList(otherList, attrMap, HomepageType.POPULAR_SALES.getValue(), 5)) - .setNewProdList(this.getTemplateTypeList(otherList, attrMap, HomepageType.SEASON_NEW_PRODUCTS.getValue(), 5)) - .setSaleRankList(this.getTemplateTypeList(otherList, attrMap, HomepageType.SALES_RANKING.getValue(), 10)); + // 商品价格、主图、标签等 + List attrList = this.storeProdMapper.selectPriceAndMainPicAndTagList(prodIdList); + Map attrMap = attrList.stream() + .collect(Collectors.toMap(StoreProdPriceAndMainPicAndTagDTO::getStoreProdId, Function.identity())); + + // 顶部右侧商品2条 + List topRightList = otherList.stream().filter(x -> Objects.equals(x.getFileType(), HomepageType.SLIDING_PICTURE_SMALL.getValue())).collect(Collectors.toList()); + List topRightRecommendList; + if (CollectionUtils.isEmpty(topRightList)) { + // 从latest50ProdList中随机选取最多2条数据 + List randomProductList = getRandomElements(latest50ProdList, 2); + topRightRecommendList = randomProductList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } else { + topRightRecommendList = topRightList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } + // 顶部右侧推荐商品 + templateOne.setTopRightList(topRightRecommendList); + + // 店家推荐 5条 + List storeRecommendList = otherList.stream().filter(x -> Objects.equals(x.getFileType(), HomepageType.STORE_RECOMMENDED.getValue())).collect(Collectors.toList()); + List recommendList; + if (CollectionUtils.isEmpty(storeRecommendList)) { + // 从latest50ProdList中随机选取最多5条数据 + List randomProductList = getRandomElements(latest50ProdList, 5); + recommendList = randomProductList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } else { + recommendList = storeRecommendList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } + // 档口推荐列表 + templateOne.setRecommendList(recommendList); + + List popularRecommendList; + // 人气爆款 5条 + List popularSaleList = otherList.stream().filter(x -> Objects.equals(x.getFileType(), HomepageType.POPULAR_SALES.getValue())).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(popularSaleList)) { + // 从latest50ProdList中随机选取最多5条数据 + List randomProductList = getRandomElements(latest50ProdList, 5); + popularRecommendList = randomProductList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } else { + popularRecommendList = popularSaleList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } + // 人气爆款列表 + templateOne.setPopularSaleList(popularRecommendList); + + // 当季新品 5条 + List seasonNewProductsList = otherList.stream().filter(x -> Objects.equals(x.getFileType(), HomepageType.SEASON_NEW_PRODUCTS.getValue())).collect(Collectors.toList()); + List seasonNewRecommendList; + if (CollectionUtils.isEmpty(seasonNewProductsList)) { + // 从latest50ProdList中随机选取最多5条数据 + List randomProductList = getRandomElements(latest50ProdList, 5); + seasonNewRecommendList = randomProductList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } else { + seasonNewRecommendList = seasonNewProductsList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } + // 当季新品列表 + templateOne.setNewProdList(seasonNewRecommendList); + + List saleRankRecommendList; + // 销量排行 10条 + List salesRankingList = otherList.stream().filter(x -> Objects.equals(x.getFileType(), HomepageType.SALES_RANKING.getValue())).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(salesRankingList)) { + // 从latest50ProdList中随机选取最多10条数据 + List randomProductList = getRandomElements(latest50ProdList, 10); + saleRankRecommendList = randomProductList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } else { + saleRankRecommendList = salesRankingList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } + // 销量排行列表 + templateOne.setSaleRankList(saleRankRecommendList); + return templateOne; } + + /** * 档口首页模板二返回数据 * @@ -283,27 +350,131 @@ public class StoreHomepageServiceImpl implements IStoreHomepageService { public StoreHomeTemplateTwoResDTO getTemplateTwo(Long storeId) { // 顶部轮播大图 StoreHomeTemplateTwoResDTO templateTwo = new StoreHomeTemplateTwoResDTO().setTopLeftList(this.storeHomeMapper.selectTopLeftList(storeId)); - - // TODO 获取档口公告 - // TODO 获取档口公告 - // TODO 获取档口公告 - + // 获取档口发布的公告 + List storeNoticeList = this.noticeMapper.selectList(new LambdaQueryWrapper().eq(Notice::getStoreId, storeId) + .eq(Notice::getDelFlag, Constants.UNDELETED).eq(Notice::getNoticeType, NoticeType.ANNOUNCEMENT.getValue()) + .eq(Notice::getOwnerType, NoticeOwnerType.STORE.getValue()).orderByDesc(Notice::getCreateTime)); + if (CollectionUtils.isEmpty(storeNoticeList)) { + templateTwo.setNotice(null); + } else { + final Date now = new Date(); + Notice storeNotice = storeNoticeList.stream() + .filter(x -> Objects.equals(x.getPerpetuity(), 2) || (x.getEffectStart().before(now) && x.getEffectEnd().after(now))) + .findFirst().orElse(null); + templateTwo.setNotice(BeanUtil.toBean(storeNotice, StoreHomeTemplateTwoResDTO.SHTTNoticeDTO.class)); + } List otherList = this.storeHomeMapper.selectList(new LambdaQueryWrapper() .eq(StoreHomepage::getStoreId, storeId).eq(StoreHomepage::getDelFlag, Constants.UNDELETED) .in(StoreHomepage::getFileType, Arrays.asList(HomepageType.POPULAR_SALES.getValue(), HomepageType.SEASON_NEW_PRODUCTS.getValue(), HomepageType.STORE_RECOMMENDED.getValue(), HomepageType.SALES_RANKING.getValue()))); - if (CollectionUtils.isEmpty(otherList)) { + // 商品ID列表 + List prodIdList = CollectionUtils.isEmpty(otherList) ? new ArrayList<>() : otherList.stream().map(StoreHomepage::getBizId).collect(Collectors.toList()); + // 筛选商品最新的50条数据 + List latest50ProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProduct::getStoreId, storeId).eq(StoreProduct::getDelFlag, Constants.UNDELETED) + .orderByDesc(StoreProduct::getCreateTime).last("LIMIT 50")); + CollectionUtils.addAll(prodIdList, latest50ProdList.stream().map(StoreProduct::getId).collect(Collectors.toList())); + if (CollectionUtils.isEmpty(latest50ProdList)) { return templateTwo; } - final List storeProdIdList = otherList.stream().map(StoreHomepage::getBizId).collect(Collectors.toList()); - List attrList = storeProdMapper.selectPriceAndMainPicAndTagList(storeProdIdList); - Map attrMap = attrList.stream().collect(Collectors.toMap(StoreProdPriceAndMainPicAndTagDTO::getStoreProdId, x -> x)); - return templateTwo - .setRecommendList(this.getTemplateTypeList(otherList, attrMap, HomepageType.STORE_RECOMMENDED.getValue(), 5)) - .setPopularSaleList(this.getTemplateTypeList(otherList, attrMap, HomepageType.POPULAR_SALES.getValue(), 5)) - .setNewProdList(this.getTemplateTypeList(otherList, attrMap, HomepageType.SEASON_NEW_PRODUCTS.getValue(), 5)) - .setSaleRankList(this.getTemplateTypeList(otherList, attrMap, HomepageType.SALES_RANKING.getValue(), 10)); + // 商品价格、主图、标签等 + List attrList = this.storeProdMapper.selectPriceAndMainPicAndTagList(prodIdList); + Map attrMap = attrList.stream() + .collect(Collectors.toMap(StoreProdPriceAndMainPicAndTagDTO::getStoreProdId, Function.identity())); + + // 店家推荐 5条 + List storeRecommendList = otherList.stream().filter(x -> Objects.equals(x.getFileType(), HomepageType.STORE_RECOMMENDED.getValue())).collect(Collectors.toList()); + List recommendList; + if (CollectionUtils.isEmpty(storeRecommendList)) { + // 从latest50ProdList中随机选取最多5条数据 + List randomProductList = getRandomElements(latest50ProdList, 5); + recommendList = randomProductList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } else { + recommendList = storeRecommendList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } + // 档口推荐列表 + templateTwo.setRecommendList(recommendList); + + List popularRecommendList; + // 人气爆款 5条 + List popularSaleList = otherList.stream().filter(x -> Objects.equals(x.getFileType(), HomepageType.POPULAR_SALES.getValue())).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(popularSaleList)) { + // 从latest50ProdList中随机选取最多5条数据 + List randomProductList = getRandomElements(latest50ProdList, 5); + popularRecommendList = randomProductList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } else { + popularRecommendList = popularSaleList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } + // 人气爆款列表 + templateTwo.setPopularSaleList(popularRecommendList); + + // 当季新品 5条 + List seasonNewProductsList = otherList.stream().filter(x -> Objects.equals(x.getFileType(), HomepageType.SEASON_NEW_PRODUCTS.getValue())).collect(Collectors.toList()); + List seasonNewRecommendList; + if (CollectionUtils.isEmpty(seasonNewProductsList)) { + // 从latest50ProdList中随机选取最多5条数据 + List randomProductList = getRandomElements(latest50ProdList, 5); + seasonNewRecommendList = randomProductList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } else { + seasonNewRecommendList = seasonNewProductsList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } + // 当季新品列表 + templateTwo.setNewProdList(seasonNewRecommendList); + + List saleRankRecommendList; + // 销量排行 10条 + List salesRankingList = otherList.stream().filter(x -> Objects.equals(x.getFileType(), HomepageType.SALES_RANKING.getValue())).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(salesRankingList)) { + // 从latest50ProdList中随机选取最多10条数据 + List randomProductList = getRandomElements(latest50ProdList, 10); + saleRankRecommendList = randomProductList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } else { + saleRankRecommendList = salesRankingList.stream().map(x -> { + StoreProdPriceAndMainPicAndTagDTO dto = attrMap.get(x.getId()); + return BeanUtil.toBean(dto, StoreHomeTemplateItemResDTO.class) + .setDisplayType(AdDisplayType.PRODUCT.getValue()).setProdPrice(ObjectUtils.isNotEmpty(dto) ? dto.getMinPrice() : null) + .setTags(ObjectUtils.isNotEmpty(dto) && StringUtils.isNotBlank(dto.getTagStr()) ? StrUtil.split(dto.getTagStr(), ",") : null); + }).collect(Collectors.toList()); + } + // 销量排行列表 + templateTwo.setSaleRankList(saleRankRecommendList); + return templateTwo; } /** @@ -580,4 +751,60 @@ public class StoreHomepageServiceImpl implements IStoreHomepageService { } + /** + * 从列表中随机选择指定数量的元素 + * + * @param list 列表 + * @param count 需要选择的数量 + * @param 元素类型 + * @return 随机选择的元素列表 + */ + private List getRandomElements(List list, int count) { + if (CollectionUtils.isEmpty(list)) { + return new ArrayList<>(); + } + // 创建列表副本以避免修改原列表 + List copyList = new ArrayList<>(list); + Collections.shuffle(copyList); + // 返回不超过列表大小和所需数量的元素 + return copyList.stream().limit(Math.min(count, copyList.size())).collect(Collectors.toList()); + } + + /** + * 获取默认的推荐推荐商品 + * + * @param storeId 档口ID + * @param dailySaleTop10ProdList 近5日销量排名前10的商品 + * @return List + */ + private List getDefaultRecommendList(Long storeId, List dailySaleTop10ProdList) { + // 获取商品标签 + List prodTagList = this.dailyProdTagMapper.selectList(new LambdaQueryWrapper() + .eq(DailyProdTag::getStoreId, storeId).eq(DailyProdTag::getDelFlag, Constants.UNDELETED) + .in(DailyProdTag::getStoreProdId, dailySaleTop10ProdList.stream().map(StoreRecommendResDTO::getStoreProdId).collect(Collectors.toList()))); + Map> tagMap = CollectionUtils.isEmpty(prodTagList) ? new HashMap<>() + : prodTagList.stream().collect(Collectors.groupingBy(x -> x.getStoreProdId().toString(), Collectors.mapping(DailyProdTag::getTag, Collectors.toList()))); + // 获取商品主图及视频等 + List prodFileList = this.prodFileMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProductFile::getStoreId, storeId).eq(StoreProductFile::getDelFlag, Constants.UNDELETED).eq(StoreProductFile::getOrderNum, ORDER_NUM_1) + .in(StoreProductFile::getStoreProdId, dailySaleTop10ProdList.stream().map(StoreRecommendResDTO::getStoreProdId).collect(Collectors.toList())) + .in(StoreProductFile::getFileType, Arrays.asList(FileType.MAIN_PIC.getValue(), FileType.MAIN_PIC_VIDEO.getValue()))); + // 档口商品主图map + Map mainPicMap = prodFileList.stream().filter(x -> Objects.equals(x.getFileType(), FileType.MAIN_PIC.getValue())) + .collect(Collectors.toMap(x -> x.getStoreProdId().toString(), StoreProductFile::getFileId)); + // 档口商品视频map + Map videoMap = prodFileList.stream().filter(x -> Objects.equals(x.getFileType(), FileType.MAIN_PIC_VIDEO.getValue())) + .collect(Collectors.toMap(x -> x.getStoreProdId().toString(), StoreProductFile::getFileId)); + List fileList = this.fileMapper.selectList(new LambdaQueryWrapper().eq(SysFile::getDelFlag, Constants.UNDELETED) + .in(SysFile::getId, prodFileList.stream().map(StoreProductFile::getFileId).collect(Collectors.toList()))); + Map fileMap = CollectionUtils.isEmpty(fileList) ? new HashMap<>() : fileList.stream().collect(Collectors.toMap(SysFile::getId, SysFile::getFileUrl)); + dailySaleTop10ProdList.forEach(x -> { + x.setTags(tagMap.getOrDefault(x.getStoreProdId(), new ArrayList<>())); + x.setMainPicUrl(fileMap.get(mainPicMap.get(x.getStoreProdId()))); + x.setHasVideo(videoMap.containsKey(x.getStoreProdId())); + }); + return dailySaleTop10ProdList; + } + + } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreMemberServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreMemberServiceImpl.java index 3828ddb31..afd00ce4b 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreMemberServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreMemberServiceImpl.java @@ -62,7 +62,7 @@ public class StoreMemberServiceImpl implements IStoreMemberService { @Transactional public Integer create(StoreMemberCreateDTO createDTO) { // 用户是否为档口管理者或子账户 - if (!SecurityUtils.isAdmin()) { + if (!SecurityUtils.isAdmin() && !SecurityUtils.isStoreManagerOrSub(createDTO.getStoreId())) { throw new ServiceException("当前用户非管理员账号,无权限操作!", HttpStatus.ERROR); } //校验推广支付方式是否存在 @@ -125,7 +125,7 @@ public class StoreMemberServiceImpl implements IStoreMemberService { @Override @Transactional(readOnly = true) public Page page(StoreMemberPageDTO pageDTO) { - // 用户是否为档口管理者或子账户 + // 用户是否为超级管理员 if (!SecurityUtils.isAdmin()) { throw new ServiceException("当前用户非管理员账号,无权限操作!", HttpStatus.ERROR); } @@ -144,6 +144,10 @@ public class StoreMemberServiceImpl implements IStoreMemberService { @Override @Transactional(readOnly = true) public StoreMemberExpireResDTO expire(Long storeId) { + // 用户是否为档口管理者或子账户 + if (!SecurityUtils.isAdmin() && !SecurityUtils.isStoreManagerOrSub(storeId)) { + throw new ServiceException("当前用户非管理员账号,无权限操作!", HttpStatus.ERROR); + } StoreMember storeMember = this.storeMemberMapper.selectOne(new LambdaQueryWrapper() .eq(StoreMember::getStoreId, storeId).eq(StoreMember::getDelFlag, Constants.UNDELETED) .gt(StoreMember::getStartTime, new Date()).le(StoreMember::getEndTime, new Date())); diff --git a/xkt/src/main/resources/mapper/StoreProductMapper.xml b/xkt/src/main/resources/mapper/StoreProductMapper.xml index d8f68c303..12a892a08 100644 --- a/xkt/src/main/resources/mapper/StoreProductMapper.xml +++ b/xkt/src/main/resources/mapper/StoreProductMapper.xml @@ -309,5 +309,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" spd.detail + + \ No newline at end of file