From 9e04aad75ce828f9c1a304bf80a932d64ab0830b Mon Sep 17 00:00:00 2001 From: liujiang <569804566@qq.com> Date: Mon, 21 Apr 2025 20:18:56 +0800 Subject: [PATCH] =?UTF-8?q?master=EF=BC=9A=E6=A1=A3=E5=8F=A3=E5=95=86?= =?UTF-8?q?=E5=93=81=E7=BB=9F=E8=AE=A1=E5=8A=9F=E8=83=BD=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DailySaleController.java | 12 + .../com/ruoyi/quartz/domain/DailyProdTag.java | 54 ++++ .../quartz/mapper/DailyProdTagMapper.java | 13 + .../java/com/ruoyi/quartz/task/XktTask.java | 283 +++++++++++++----- .../com/ruoyi/xkt/domain/StoreProduct.java | 19 ++ .../xkt/domain/StoreProductStatistics.java | 46 +++ .../com/ruoyi/xkt/domain/StoreSaleDetail.java | 4 + .../java/com/ruoyi/xkt/enums/ProdTagType.java | 41 +++ .../mapper/StoreProductStatisticsMapper.java | 12 + .../xkt/mapper/StoreSaleDetailMapper.java | 1 + .../service/impl/StoreSaleServiceImpl.java | 6 +- .../mapper/StoreSaleDetailMapper.xml | 13 +- 12 files changed, 426 insertions(+), 78 deletions(-) create mode 100644 ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/DailyProdTag.java create mode 100644 ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/DailyProdTagMapper.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/domain/StoreProductStatistics.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/enums/ProdTagType.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductStatisticsMapper.java diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/DailySaleController.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/DailySaleController.java index c00ea3627..356fc7355 100644 --- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/DailySaleController.java +++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/DailySaleController.java @@ -51,4 +51,16 @@ public class DailySaleController extends BaseController { return R.ok(); } + @PostMapping("/prod-tag") + public R dailyProdTag(SysJob sysJob) { + task.dailyProdTag(); + return R.ok(); + } + + @PostMapping("/prod-weight") + public R dailyProdWeight(SysJob sysJob) { + task.dailyProdWeight(); + return R.ok(); + } + } diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/DailyProdTag.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/DailyProdTag.java new file mode 100644 index 000000000..5f2796e73 --- /dev/null +++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/DailyProdTag.java @@ -0,0 +1,54 @@ +package com.ruoyi.quartz.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.ruoyi.common.core.domain.XktBaseEntity; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.util.Date; + +/** + * 档口商品每天的标签更新 daily_prod_tag + * + * @author ruoyi + * @date 2025-03-26 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@Accessors(chain = true) +@Builder +public class DailyProdTag extends XktBaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 每日标签统计ID + */ + @TableId + private Long id; + /** + * 档口ID + */ + private Long storeId; + /** + * 档口商品ID + */ + private Long storeProdId; + /** + * 标签类型 + */ + private Integer type; + /** + * 具体标签 + */ + private String tag; + /** + * 统计时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd") + private Date voucherDate; + +} diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/DailyProdTagMapper.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/DailyProdTagMapper.java new file mode 100644 index 000000000..38d9f85b5 --- /dev/null +++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/DailyProdTagMapper.java @@ -0,0 +1,13 @@ +package com.ruoyi.quartz.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.quartz.domain.DailyProdTag; + +/** + * 调度任务信息 数据层 + * + * @author ruoyi + */ +public interface DailyProdTagMapper extends BaseMapper { + +} 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 3a69d87b8..08fb18acc 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 @@ -6,25 +6,20 @@ import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.HttpStatus; import com.ruoyi.common.core.domain.entity.SysProductCategory; import com.ruoyi.common.exception.ServiceException; -import com.ruoyi.quartz.domain.DailySale; -import com.ruoyi.quartz.domain.DailySaleCustomer; -import com.ruoyi.quartz.domain.DailySaleProduct; -import com.ruoyi.quartz.domain.DailyStoreTag; +import com.ruoyi.quartz.domain.*; import com.ruoyi.quartz.dto.DailySaleCusDTO; import com.ruoyi.quartz.dto.DailySaleDTO; import com.ruoyi.quartz.dto.DailySaleProdDTO; import com.ruoyi.quartz.dto.WeekCateSaleDTO; import com.ruoyi.quartz.mapper.*; import com.ruoyi.system.mapper.SysProductCategoryMapper; -import com.ruoyi.xkt.domain.Store; -import com.ruoyi.xkt.domain.StoreProduct; +import com.ruoyi.xkt.domain.*; import com.ruoyi.xkt.dto.dailyStoreTag.DailyStoreTagDTO; -import com.ruoyi.xkt.enums.EProductStatus; -import com.ruoyi.xkt.enums.StoreStatus; -import com.ruoyi.xkt.enums.StoreTagType; +import com.ruoyi.xkt.enums.*; import com.ruoyi.xkt.mapper.*; import lombok.RequiredArgsConstructor; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.ObjectUtils; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -32,6 +27,7 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; import java.time.ZoneId; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; /** @@ -57,6 +53,9 @@ public class XktTask { final StoreProductStockMapper stockMapper; final StoreMapper storeMapper; final StoreProductMapper storeProdMapper; + final DailyProdTagMapper dailyProdTagMapper; + final StoreProductCategoryAttributeMapper cateAttrMapper; + final StoreProductStatisticsMapper prodStatMapper; /** * 每晚1点同步档口销售数据 @@ -183,11 +182,11 @@ public class XktTask { } List tagList = new ArrayList<>(); // 根据LocalDate 获取当前日期前一天 - final Date yesterday = Date.from(LocalDate.now().minusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant()); + final Date yesterday = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant()); // 使用LocalDate 获取当前日期前一天的前一周,并转为 Date 格式 - final Date oneWeekAgo = Date.from(LocalDate.now().minusDays(8).atStartOfDay(ZoneId.systemDefault()).toInstant()); + final Date oneWeekAgo = Date.from(LocalDate.now().minusWeeks(1).atStartOfDay(ZoneId.systemDefault()).toInstant()); // 使用LocalDate 获取当前日期前一天的前一个月 - final Date oneMonthAgo = Date.from(LocalDate.now().minusDays(1).minusMonths(1).atStartOfDay(ZoneId.systemDefault()).toInstant()); + final Date oneMonthAgo = Date.from(LocalDate.now().minusMonths(1).atStartOfDay(ZoneId.systemDefault()).toInstant()); // 1. 打 销量榜 标签,这个是最重要标签 this.tagSaleRank(yesterday, oneMonthAgo, tagList); // 2. 打 爆款频出 标签,根据销量前50的商品中 档口 先后顺序排列 @@ -208,16 +207,203 @@ public class XktTask { this.dailyStoreTagMapper.insert(tagList); } + /** + * 给商品打标 + */ + @Transactional + public void dailyProdTag() { + // 先删除所有的商品标签,保证数据唯一性 + List existList = this.dailyProdTagMapper.selectList(new LambdaQueryWrapper() + .eq(DailyProdTag::getDelFlag, Constants.UNDELETED)); + if (CollectionUtils.isNotEmpty(existList)) { + this.dailyProdTagMapper.deleteByIds(existList.stream().map(DailyProdTag::getId).collect(Collectors.toList())); + } + // 根据LocalDate 获取当前日期前一天 + final Date yesterday = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant()); + // 使用LocalDate 获取当前日期4天前,并转为 Date 格式 + final Date fourDaysAgo = Date.from(LocalDate.now().minusDays(3).atStartOfDay(ZoneId.systemDefault()).toInstant()); + // 使用LocalDate 获取当前日期前一天的前一周,并转为 Date 格式 + final Date oneWeekAgo = Date.from(LocalDate.now().minusWeeks(1).atStartOfDay(ZoneId.systemDefault()).toInstant()); + // 使用LocalDate 获取当前日期前一天的前一个月 + final Date oneMonthAgo = Date.from(LocalDate.now().minusMonths(1).atStartOfDay(ZoneId.systemDefault()).toInstant()); + List tagList = new ArrayList<>(); + // 1. 当月(近一月)爆款 + this.tagMonthHot(yesterday, oneMonthAgo, tagList); + // 2. 档口热卖 + this.tagStoreHot(yesterday, oneMonthAgo, tagList); + // 3. 三日上新 + this.tagThreeDayNew(yesterday, fourDaysAgo, tagList); + // 4. 七日上新 + this.tagSevenDayNew(yesterday, fourDaysAgo, oneWeekAgo, tagList); + // 5. 风格 + this.tagStyle(yesterday, tagList); + if (CollectionUtils.isEmpty(tagList)) { + return; + } + this.dailyProdTagMapper.insert(tagList); + } + + + /** + * 每日更新档口商品的各项权重数据 + */ + public void dailyProdWeight() { + List storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProduct::getDelFlag, Constants.UNDELETED)); + if (CollectionUtils.isEmpty(storeProdList)) { + return; + } + // 获取 商品销售、商品浏览量、商品收藏量、商品下载量 + List statisticsList = this.prodStatMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProductStatistics::getDelFlag, Constants.UNDELETED)); + // 商品浏览量、下载量 + Map prodStatMap = statisticsList.stream().collect(Collectors.toMap(StoreProductStatistics::getStoreProdId, Function.identity())); + // 商品收藏量 + List userFavList = this.userFavMapper.selectList(new LambdaQueryWrapper() + .eq(UserFavorites::getDelFlag, Constants.UNDELETED)); + Map userFavMap = userFavList.stream().collect(Collectors.groupingBy(UserFavorites::getStoreProdId, Collectors.summingLong(UserFavorites::getId))); + // 商品销售量 + List saleDetailList = this.saleDetailMapper.selectList(new LambdaQueryWrapper() + .eq(StoreSaleDetail::getDelFlag, Constants.UNDELETED).eq(StoreSaleDetail::getSaleType, SaleType.GENERAL_SALE.getValue())); + Map saleMap = saleDetailList.stream().collect(Collectors.groupingBy(StoreSaleDetail::getStoreProdId, + Collectors.summingLong(StoreSaleDetail::getQuantity))); + storeProdList.forEach(x -> { + final long viewCount = ObjectUtils.isEmpty(prodStatMap.get(x.getId())) ? 0L : prodStatMap.get(x.getId()).getViewCount(); + final long downloadCount = ObjectUtils.isEmpty(prodStatMap.get(x.getId())) ? 0L : prodStatMap.get(x.getId()).getDownloadCount(); + final long favCount = ObjectUtils.isEmpty(userFavMap.get(x.getId())) ? 0L : userFavMap.get(x.getId()); + final long saleCount = ObjectUtils.isEmpty(saleMap.get(x.getId())) ? 0L : saleMap.get(x.getId()); + // 计算推荐权重,权重计算公式为:(浏览次数 * 0.3 + 下载次数 + 收藏次数 + 销售量 * 0.3) + final long recommendWeight = (long) (viewCount * 0.3 + downloadCount + favCount + saleCount * 0.3); + // 根据销售数量计算销售权重,权重占销售数量的30% + final long saleWeight = (long) (saleCount * 0.3); + // 计算人气权重,权重计算公式为:(浏览次数 * 0.1 和 100 取最小值) + 下载次数 + 收藏次数 + final long popularityWeight = (long) (Math.min(viewCount * 0.1, 100) + downloadCount + favCount); + x.setRecommendWeight(recommendWeight).setSaleWeight(saleWeight).setPopularityWeight(popularityWeight); + }); + this.storeProdMapper.updateById(storeProdList); + } + + + /** + * 给商品打风格标签 + * + * @param yesterday 昨天 + * @param tagList 标签列表 + */ + private void tagStyle(Date yesterday, List tagList) { + List cateAttrList = this.cateAttrMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProductCategoryAttribute::getDelFlag, Constants.UNDELETED).eq(StoreProductCategoryAttribute::getDictType, "style")); + // 查询条件加上 + if (CollectionUtils.isEmpty(cateAttrList)) { + return; + } + // 根据storeProdId找到storeId + List storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProduct::getDelFlag, Constants.UNDELETED).in(StoreProduct::getId, cateAttrList.stream() + .map(StoreProductCategoryAttribute::getStoreProdId).collect(Collectors.toList()))); + Map prodStoreIdMap = storeProdList.stream().collect(Collectors.toMap(StoreProduct::getId, StoreProduct::getStoreId)); + tagList.addAll(cateAttrList.stream().map(x -> DailyProdTag.builder().storeId(prodStoreIdMap.get(x.getStoreProdId())).storeProdId(x.getStoreProdId()) + .tag(x.getDictValue()).type(ProdTagType.STYLE.getValue()).voucherDate(yesterday).build()).collect(Collectors.toList())); + } + + /** + * 给商品打标 七日上新 + * + * @param yesterday 昨天 + * @param fourDaysAgo 4天前 + * @param oneWeekAgo 一周前 + * @param tagList 标签列表 + */ + private void tagSevenDayNew(Date yesterday, Date fourDaysAgo, Date oneWeekAgo, List tagList) { + List storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProduct::getDelFlag, Constants.UNDELETED).between(StoreProduct::getCreateTime, oneWeekAgo, fourDaysAgo)); + if (CollectionUtils.isEmpty(storeProdList)) { + return; + } + tagList.addAll(storeProdList.stream().map(x -> DailyProdTag.builder().storeId(x.getStoreId()).storeProdId(x.getId()) + .type(ProdTagType.SEVEN_DAY_NEW.getValue()).tag("七日上新").voucherDate(yesterday).build()).collect(Collectors.toList())); + } + + /** + * 三日上新 + * + * @param yesterday 昨天 + * @param fourDaysAgo 3天前 + * @param tagList 标签列表 + */ + private void tagThreeDayNew(Date yesterday, Date fourDaysAgo, List tagList) { + List storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProduct::getDelFlag, Constants.UNDELETED).between(StoreProduct::getCreateTime, fourDaysAgo, yesterday)); + if (CollectionUtils.isEmpty(storeProdList)) { + return; + } + tagList.addAll(storeProdList.stream().map(x -> DailyProdTag.builder().storeId(x.getStoreId()).storeProdId(x.getId()) + .type(ProdTagType.THREE_DAY_NEW.getValue()).tag("三日上新").voucherDate(yesterday).build()).collect(Collectors.toList())); + } + + /** + * 筛选档口热卖商品 + * + * @param yesterday 昨天 + * @param oneMonthAgo 一月前 + * @param tagList 标签集合 + */ + private void tagStoreHot(Date yesterday, Date oneMonthAgo, List tagList) { + List detailList = this.saleDetailMapper.selectList(new LambdaQueryWrapper() + .eq(StoreSaleDetail::getDelFlag, Constants.UNDELETED).eq(StoreSaleDetail::getSaleType, SaleType.GENERAL_SALE.getValue()) + .between(StoreSaleDetail::getCreateTime, oneMonthAgo, yesterday)); + if (CollectionUtils.isEmpty(detailList)) { + return; + } + // 按照档口下商品的销量排序 + Map> storeSaleMap = detailList.stream().collect(Collectors.groupingBy(StoreSaleDetail::getStoreId, Collectors + .groupingBy(StoreSaleDetail::getStoreProdId, Collectors.summingInt(StoreSaleDetail::getQuantity)))); + storeSaleMap.forEach((storeId, prodSaleMap) -> { + // 按照销量倒序排, 如果超过20个商品,则取前20,没有20个就有多少个货品取多少个 + List> prodSaleList = prodSaleMap.entrySet().stream() + .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).limit(20).collect(Collectors.toList()); + // 将prodSaleList按照tagList返回 + prodSaleList.forEach(x -> tagList.add(DailyProdTag.builder().storeId(storeId).storeProdId(x.getKey()).tag("档口热卖") + .type(ProdTagType.STORE_HOT.getValue()).voucherDate(yesterday).build())); + }); + } + + /** + * 给商品打标 本月爆款 + * + * @param yesterday 昨天 + * @param oneMonthAgo 一月前 + * @param tagList 标签列表 + */ + private void tagMonthHot(Date yesterday, Date oneMonthAgo, List tagList) { + List top50List = this.saleDetailMapper.selectTop50List(yesterday, oneMonthAgo); + if (CollectionUtils.isEmpty(top50List)) { + return; + } + tagList.addAll(top50List.stream().map(x -> DailyProdTag.builder().storeId(x.getStoreId()).storeProdId(x.getStoreProdId()) + .tag("本月爆款").type(ProdTagType.MONTH_HOT.getValue()).voucherDate(yesterday).build()).collect(Collectors.toList())); + } + + + /** + * 档口基础标签 + * + * @param yesterday 昨日 + * @param oneWeekAgo 一周前 + * @param tagList 标签列表 + */ private void tagBasicTag(Date yesterday, Date oneWeekAgo, List tagList) { // 7. 打 经营年限 标签 List storeList = this.storeMapper.selectList(new LambdaQueryWrapper() .eq(Store::getDelFlag, Constants.UNDELETED) .in(Store::getStoreStatus, Arrays.asList(StoreStatus.TRIAL_PERIOD.getValue(), StoreStatus.FORMAL_USE.getValue()))); - storeList.forEach(x -> { - final Integer operateYears = ObjectUtils.defaultIfNull(x.getOperateYears(), 0); - tagList.add(DailyStoreTag.builder().storeId(x.getId()).type(StoreTagType.OPERATE_YEARS_RANK.getValue()) - .tag(operateYears < 3 ? operateYears + "年新店" : operateYears + "年老店").voucherDate(yesterday).build()); - }); + if (CollectionUtils.isNotEmpty(storeList)) { + storeList.forEach(x -> { + final Integer operateYears = ObjectUtils.defaultIfNull(x.getOperateYears(), 0); + tagList.add(DailyStoreTag.builder().storeId(x.getId()).type(StoreTagType.OPERATE_YEARS_RANK.getValue()) + .tag(operateYears < 3 ? operateYears + "年新店" : operateYears + "年老店").voucherDate(yesterday).build()); + }); + } // 8. 打 七日上新 标签 List newProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper() .eq(StoreProduct::getDelFlag, Constants.UNDELETED) @@ -232,6 +418,13 @@ public class XktTask { }); } + /** + * 给档口打库存标签 + * + * @param yesterday 昨天 + * @param oneMonthAgo 一月前 + * @param tagList 标签列表 + */ private void tagStockTag(Date yesterday, Date oneMonthAgo, List tagList) { List top10List = this.stockMapper.selectTop10List(yesterday, oneMonthAgo); if (CollectionUtils.isEmpty(top10List)) { @@ -241,6 +434,12 @@ public class XktTask { .tag("库存充足").voucherDate(yesterday).build()).collect(Collectors.toList())); } + /** + * 给档口打收藏标签 + * + * @param yesterday 昨天 + * @param tagList 标签列表 + */ private void tagCollectionRank(Date yesterday, List tagList) { List top10List = this.userFavMapper.selectTop10List(); if (CollectionUtils.isEmpty(top10List)) { @@ -268,32 +467,6 @@ public class XktTask { .build()); } } - - /* if (ObjectUtils.isNotEmpty(top10List.get(0))) { - tagList.add(DailyStoreTag.builder().storeId(top10List.get(0).getStoreId()).type(StoreTagType.COLLECTION_RANK.getValue()) - .tag("收藏榜第一").voucherDate(yesterday).build()); - } - if (ObjectUtils.isNotEmpty(top10List.get(1))) { - tagList.add(DailyStoreTag.builder().storeId(top10List.get(1).getStoreId()).type(StoreTagType.COLLECTION_RANK.getValue()) - .tag("收藏榜第二").voucherDate(yesterday).build()); - } - if (ObjectUtils.isNotEmpty(top10List.get(2))) { - tagList.add(DailyStoreTag.builder().storeId(top10List.get(2).getStoreId()).type(StoreTagType.COLLECTION_RANK.getValue()) - .tag("收藏榜前三").voucherDate(yesterday).build()); - } - if (ObjectUtils.isNotEmpty(top10List.get(3))) { - tagList.add(DailyStoreTag.builder().storeId(top10List.get(3).getStoreId()).type(StoreTagType.COLLECTION_RANK.getValue()) - .tag("收藏榜前五").voucherDate(yesterday).build()); - } - if (ObjectUtils.isNotEmpty(top10List.get(4))) { - tagList.add(DailyStoreTag.builder().storeId(top10List.get(4).getStoreId()).type(StoreTagType.COLLECTION_RANK.getValue()) - .tag("收藏榜前五").voucherDate(yesterday).build()); - } - if (CollectionUtils.isNotEmpty(top10List.stream().skip(5).collect(Collectors.toList()))) { - tagList.addAll(top10List.stream().skip(5).map(x -> DailyStoreTag.builder().storeId(x.getStoreId()) - .type(StoreTagType.COLLECTION_RANK.getValue()).tag("收藏榜前十").voucherDate(yesterday).build()) - .collect(Collectors.toList())); - }*/ } private void tagAttentionRank(Date yesterday, List tagList) { @@ -370,30 +543,6 @@ public class XktTask { .build()); } } - /*if (ObjectUtils.isNotEmpty(saleTop10List.get(0))) { - tagList.add(DailyStoreTag.builder().storeId(saleTop10List.get(0).getStoreId()).type(StoreTagType.SALES_RANK.getValue()) - .tag("销量第一").voucherDate(yesterday).build()); - } - if (ObjectUtils.isNotEmpty(saleTop10List.get(1))) { - tagList.add(DailyStoreTag.builder().storeId(saleTop10List.get(1).getStoreId()).type(StoreTagType.SALES_RANK.getValue()) - .tag("销量第二").voucherDate(yesterday).build()); - } - if (ObjectUtils.isNotEmpty(saleTop10List.get(2))) { - tagList.add(DailyStoreTag.builder().storeId(saleTop10List.get(2).getStoreId()).type(StoreTagType.SALES_RANK.getValue()) - .tag("销量前三").voucherDate(yesterday).build()); - } - if (ObjectUtils.isNotEmpty(saleTop10List.get(3))) { - tagList.add(DailyStoreTag.builder().storeId(saleTop10List.get(3).getStoreId()).type(StoreTagType.SALES_RANK.getValue()) - .tag("销量前五").voucherDate(yesterday).build()); - } - if (ObjectUtils.isNotEmpty(saleTop10List.get(4))) { - tagList.add(DailyStoreTag.builder().storeId(saleTop10List.get(4).getStoreId()).type(StoreTagType.SALES_RANK.getValue()) - .tag("销量前五").voucherDate(yesterday).build()); - } - if (CollectionUtils.isNotEmpty(saleTop10List.stream().skip(5).collect(Collectors.toList()))) { - tagList.addAll(saleTop10List.stream().skip(5).map(x -> DailyStoreTag.builder().storeId(x.getStoreId()).type(StoreTagType.SALES_RANK.getValue()) - .tag("销量前十").voucherDate(yesterday).build()).collect(Collectors.toList())); - }*/ } } diff --git a/xkt/src/main/java/com/ruoyi/xkt/domain/StoreProduct.java b/xkt/src/main/java/com/ruoyi/xkt/domain/StoreProduct.java index e77e53e3e..19e2ee3c2 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/domain/StoreProduct.java +++ b/xkt/src/main/java/com/ruoyi/xkt/domain/StoreProduct.java @@ -122,6 +122,25 @@ public class StoreProduct extends XktBaseEntity { @Excel(name = "商品状态") private Integer prodStatus; + /** + * 推荐数值 + * @return + */ + private Long recommendWeight; + + /** + * 销量数值 + * @return + */ + private Long saleWeight; + + /** + * 人气数值 + * @return + */ + private Long popularityWeight; + + @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) diff --git a/xkt/src/main/java/com/ruoyi/xkt/domain/StoreProductStatistics.java b/xkt/src/main/java/com/ruoyi/xkt/domain/StoreProductStatistics.java new file mode 100644 index 000000000..53f53327e --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/domain/StoreProductStatistics.java @@ -0,0 +1,46 @@ +package com.ruoyi.xkt.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.ruoyi.common.core.domain.XktBaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 档口商品统计数据 store_product_statistics + * + * @author ruoyi + * @date 2025-03-26 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@Accessors(chain = true) +public class StoreProductStatistics extends XktBaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 档口商品ID + */ + @TableId + private Long id; + + /** + * 档口ID + */ + private Long storeId; + + /** + * 档口商品ID + */ + private Long storeProdId; + /** + * 商品浏览量 + */ + private Long viewCount; + /** + * 商品下载量 + */ + private Long downloadCount; + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/domain/StoreSaleDetail.java b/xkt/src/main/java/com/ruoyi/xkt/domain/StoreSaleDetail.java index 3ac1b2b35..fa6d637ad 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/domain/StoreSaleDetail.java +++ b/xkt/src/main/java/com/ruoyi/xkt/domain/StoreSaleDetail.java @@ -35,6 +35,10 @@ public class StoreSaleDetail extends XktBaseEntity { */ @Excel(name = "档口商品销售ID") private Long storeSaleId; + /** + * 档口ID + */ + private Long storeId; /** * 档口商品ID */ diff --git a/xkt/src/main/java/com/ruoyi/xkt/enums/ProdTagType.java b/xkt/src/main/java/com/ruoyi/xkt/enums/ProdTagType.java new file mode 100644 index 000000000..fb5679c8c --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/enums/ProdTagType.java @@ -0,0 +1,41 @@ +package com.ruoyi.xkt.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 档口标签类型 + * @author liujiang + * @date 2025-04-02 23:42 + */ +@Getter +@AllArgsConstructor +public enum ProdTagType { + + // 当月爆款 + MONTH_HOT(1, "当月爆款"), + // 档口爆款 + STORE_HOT(2, "档口热卖"), + // 三日上新 + THREE_DAY_NEW(3, "三日上新"), + // 七日上新 + SEVEN_DAY_NEW(4, "七日上新"), + // 风格 + STYLE(5, "风格"), + + + ; + + + private final Integer value; + private final String label; + + public static ProdTagType of(Integer value) { + for (ProdTagType e : ProdTagType.values()) { + if (e.getValue().equals(value)) { + return e; + } + } + return null; + } +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductStatisticsMapper.java b/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductStatisticsMapper.java new file mode 100644 index 000000000..5527a643f --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreProductStatisticsMapper.java @@ -0,0 +1,12 @@ +package com.ruoyi.xkt.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.xkt.domain.StoreProductStatistics; + +/** + * @author ruoyi + * @date 2025-03-26 + */ +public interface StoreProductStatisticsMapper extends BaseMapper { + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreSaleDetailMapper.java b/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreSaleDetailMapper.java index 845babac5..fd979624c 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreSaleDetailMapper.java +++ b/xkt/src/main/java/com/ruoyi/xkt/mapper/StoreSaleDetailMapper.java @@ -88,4 +88,5 @@ public interface StoreSaleDetailMapper extends BaseMapper { */ List selectTop20List(@Param("yesterday") Date yesterday, @Param("oneWeekAgo") Date oneWeekAgo); + } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreSaleServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreSaleServiceImpl.java index 8c0cd0fe0..6bd1de481 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreSaleServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreSaleServiceImpl.java @@ -158,7 +158,8 @@ public class StoreSaleServiceImpl implements IStoreSaleService { int count = storeSaleMapper.insert(storeSale); // 处理订单明细 List saleDetailList = storeSaleDTO.getDetailList().stream().map(x -> BeanUtil.toBean(x, StoreSaleDetail.class) - .setSaleType(storeSaleDTO.getSaleType()).setStoreSaleId(storeSale.getId())).collect(Collectors.toList()); + .setSaleType(storeSaleDTO.getSaleType()).setStoreSaleId(storeSale.getId()).setStoreId(storeSale.getStoreId())) + .collect(Collectors.toList()); this.storeSaleDetailMapper.insert(saleDetailList); // 先汇总当前这笔订单商品明细的销售数量,包括销售及退货 key: prodArtNum + storeProdId + storeProdColorId + colorName, value: map(key:size,value:count) Map> saleCountMap = storeSaleDTO.getDetailList().stream().collect(Collectors @@ -211,7 +212,8 @@ public class StoreSaleServiceImpl implements IStoreSaleService { this.storeSaleDetailMapper.updateById(saleDetailList.stream().peek(x -> x.setDelFlag(Constants.DELETED)).collect(Collectors.toList())); // 再新增档口销售出库明细数据 List detailList = storeSaleDTO.getDetailList().stream().map(x -> BeanUtil.toBean(x, StoreSaleDetail.class) - .setSaleType(storeSaleDTO.getSaleType()).setStoreSaleId(storeSale.getId())).collect(Collectors.toList()); + .setSaleType(storeSaleDTO.getSaleType()).setStoreSaleId(storeSale.getId()).setStoreId(storeSale.getStoreId())) + .collect(Collectors.toList()); this.storeSaleDetailMapper.insert(detailList); // 汇总编辑的存货总数量 final List totalList = new ArrayList(saleDetailList) {{ diff --git a/xkt/src/main/resources/mapper/StoreSaleDetailMapper.xml b/xkt/src/main/resources/mapper/StoreSaleDetailMapper.xml index 522bc3a72..60cfb8c4f 100644 --- a/xkt/src/main/resources/mapper/StoreSaleDetailMapper.xml +++ b/xkt/src/main/resources/mapper/StoreSaleDetailMapper.xml @@ -121,17 +121,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" SELECT - ss.store_id, ssd.store_prod_id, + ssd.store_id, SUM(IFNULL( ssd.quantity, 0 )) AS count FROM store_sale_detail ssd - JOIN store_sale ss ON ssd.store_sale_id = ss.id WHERE ssd.del_flag = 0 AND ssd.sale_type = 1 AND ssd.voucher_date between #{oneMonthAgo} AND #{yesterday} GROUP BY - ss.store_id, + ssd.store_id, ssd.store_prod_id ORDER BY count DESC @@ -174,7 +172,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - - - \ No newline at end of file