From 71bff8ea535d7eba6d1dbf20f20e4949e83d9bca Mon Sep 17 00:00:00 2001 From: JR <3573153686@qq.com> Date: Sat, 26 Jul 2025 11:16:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E4=BA=A7=E5=93=81?= =?UTF-8?q?=E7=83=AD=E5=BA=A6=E6=8E=92=E8=A1=8C=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WmsProductSalesScriptController.java | 39 +++---- .../klp/domain/vo/DashboardOverviewVO.java | 15 +-- ...otProductVO.java => ProductRankingVo.java} | 28 ++--- .../IWmsProductSalesScriptService.java | 12 +- .../WmsProductSalesScriptServiceImpl.java | 103 +++++++++++------- .../service/impl/WmsProductServiceImpl.java | 5 - 6 files changed, 103 insertions(+), 99 deletions(-) rename klp-wms/src/main/java/com/klp/domain/vo/{HotProductVO.java => ProductRankingVo.java} (68%) diff --git a/klp-wms/src/main/java/com/klp/controller/WmsProductSalesScriptController.java b/klp-wms/src/main/java/com/klp/controller/WmsProductSalesScriptController.java index 8e8a0eb5..e9b4a0c7 100644 --- a/klp-wms/src/main/java/com/klp/controller/WmsProductSalesScriptController.java +++ b/klp-wms/src/main/java/com/klp/controller/WmsProductSalesScriptController.java @@ -6,7 +6,7 @@ import java.util.Arrays; import lombok.RequiredArgsConstructor; import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.*; -import cn.dev33.satoken.annotation.SaCheckPermission; + import org.springframework.web.bind.annotation.*; import org.springframework.validation.annotation.Validated; import com.klp.common.annotation.RepeatSubmit; @@ -24,7 +24,7 @@ import com.klp.service.IWmsProductSalesScriptService; import com.klp.common.core.page.TableDataInfo; import com.klp.common.utils.redis.RedisUtils; import java.time.Duration; -import com.klp.domain.vo.HotProductVO; +import com.klp.domain.vo.ProductRankingVo; /** * 产品销售话术 @@ -66,7 +66,14 @@ public class WmsProductSalesScriptController extends BaseController { @GetMapping("/{scriptId}") public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long scriptId) { - return R.ok(iWmsProductSalesScriptService.queryById(scriptId)); + WmsProductSalesScriptVo vo = iWmsProductSalesScriptService.queryById(scriptId); + + // 记录产品访问次数到Redis + if (vo != null && vo.getProductId() != null) { + iWmsProductSalesScriptService.recordProductViewCount(vo.getProductId()); + } + + return R.ok(vo); } /** @@ -102,27 +109,11 @@ public class WmsProductSalesScriptController extends BaseController { } /** - * 记录话术访问频率 - * - * @param productId 产品ID + * 获取产品咨询热度排行 */ - @PostMapping("/recordVisit/{productId}") - public R recordVisit(@NotNull(message = "产品ID不能为空") @PathVariable Long productId) { - String key = "product:visit:frequency:" + productId; - // 原子递增访问次数,设置7天过期时间 - long count = RedisUtils.incrAtomicValue(key); - if (count == 1) { - // 第一次访问时设置过期时间 - RedisUtils.expire(key, Duration.ofDays(7)); - } - return R.ok(); - } - - /** - * 获取热门产品排行(基于访问频率) - */ - @GetMapping("/hotProducts") - public R> getHotProducts(@RequestParam(defaultValue = "10") Integer limit) { - return R.ok(iWmsProductSalesScriptService.getHotProducts(limit)); + @GetMapping("/dashboard/ranking") + public R> getProductRanking() { + List ranking = iWmsProductSalesScriptService.getProductRanking(); + return R.ok(ranking); } } diff --git a/klp-wms/src/main/java/com/klp/domain/vo/DashboardOverviewVO.java b/klp-wms/src/main/java/com/klp/domain/vo/DashboardOverviewVO.java index 85e90c0f..d7b4405a 100644 --- a/klp-wms/src/main/java/com/klp/domain/vo/DashboardOverviewVO.java +++ b/klp-wms/src/main/java/com/klp/domain/vo/DashboardOverviewVO.java @@ -11,34 +11,29 @@ import java.util.List; */ @Data public class DashboardOverviewVO { - + /** * 订单汇总 */ private OrderSummaryVO orderSummary; - + /** * 销售经理饼图 */ private List salesManagerPie; - + /** * 产品销量排行 */ private List productRank; - + /** * 订单物料分析 */ private List orderMaterial; - + /** * 客户分布 */ private List customerRegion; - - /** - * 热门产品排行(基于访问频率) - */ - private List hotProducts; } diff --git a/klp-wms/src/main/java/com/klp/domain/vo/HotProductVO.java b/klp-wms/src/main/java/com/klp/domain/vo/ProductRankingVo.java similarity index 68% rename from klp-wms/src/main/java/com/klp/domain/vo/HotProductVO.java rename to klp-wms/src/main/java/com/klp/domain/vo/ProductRankingVo.java index f6874003..02c45a54 100644 --- a/klp-wms/src/main/java/com/klp/domain/vo/HotProductVO.java +++ b/klp-wms/src/main/java/com/klp/domain/vo/ProductRankingVo.java @@ -3,36 +3,36 @@ package com.klp.domain.vo; import lombok.Data; /** - * 热门产品视图对象 + * 产品咨询热度排行视图对象 * * @author klp - * @date 2025-01-27 + * @date 2025-07-24 */ @Data -public class HotProductVO { - +public class ProductRankingVo { + /** * 产品ID */ private Long productId; - - /** - * 产品名称 - */ - private String productName; - + /** * 产品编号 */ private String productCode; - + + /** + * 产品名称 + */ + private String productName; + /** * 访问次数 */ - private Long visitCount; - + private Long viewCount; + /** * 排名 */ - private Integer rank; + private Integer ranking; } \ No newline at end of file diff --git a/klp-wms/src/main/java/com/klp/service/IWmsProductSalesScriptService.java b/klp-wms/src/main/java/com/klp/service/IWmsProductSalesScriptService.java index 42e446f8..4d47bf66 100644 --- a/klp-wms/src/main/java/com/klp/service/IWmsProductSalesScriptService.java +++ b/klp-wms/src/main/java/com/klp/service/IWmsProductSalesScriptService.java @@ -1,11 +1,10 @@ package com.klp.service; -import com.klp.domain.WmsProductSalesScript; import com.klp.domain.vo.WmsProductSalesScriptVo; import com.klp.domain.bo.WmsProductSalesScriptBo; import com.klp.common.core.page.TableDataInfo; import com.klp.common.core.domain.PageQuery; -import com.klp.domain.vo.HotProductVO; +import com.klp.domain.vo.ProductRankingVo; import java.util.Collection; import java.util.List; @@ -49,7 +48,12 @@ public interface IWmsProductSalesScriptService { Boolean deleteWithValidByIds(Collection ids, Boolean isValid); /** - * 获取热门产品排行(基于访问频率) + * 记录产品访问次数 */ - List getHotProducts(Integer limit); + void recordProductViewCount(Long productId); + + /** + * 获取产品咨询热度排行 + */ + List getProductRanking(); } diff --git a/klp-wms/src/main/java/com/klp/service/impl/WmsProductSalesScriptServiceImpl.java b/klp-wms/src/main/java/com/klp/service/impl/WmsProductSalesScriptServiceImpl.java index 542d82e4..84db4bff 100644 --- a/klp-wms/src/main/java/com/klp/service/impl/WmsProductSalesScriptServiceImpl.java +++ b/klp-wms/src/main/java/com/klp/service/impl/WmsProductSalesScriptServiceImpl.java @@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.klp.common.utils.StringUtils; +import com.klp.domain.WmsProduct; +import com.klp.mapper.WmsProductMapper; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import com.klp.domain.bo.WmsProductSalesScriptBo; @@ -14,16 +16,16 @@ import com.klp.domain.vo.WmsProductSalesScriptVo; import com.klp.domain.WmsProductSalesScript; import com.klp.mapper.WmsProductSalesScriptMapper; import com.klp.service.IWmsProductSalesScriptService; -import com.klp.domain.vo.HotProductVO; +import com.klp.domain.vo.ProductRankingVo; import com.klp.common.utils.redis.RedisUtils; -import java.util.stream.Collectors; -import java.util.Comparator; -import com.klp.domain.WmsProduct; -import com.klp.mapper.WmsProductMapper; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Collection; +import org.redisson.api.RScoredSortedSet; + +import javax.annotation.Resource; /** * 产品销售话术Service业务层处理 @@ -36,7 +38,9 @@ import java.util.Collection; public class WmsProductSalesScriptServiceImpl implements IWmsProductSalesScriptService { private final WmsProductSalesScriptMapper baseMapper; - private final WmsProductMapper wmsProductMapper; + + @Resource + private WmsProductMapper wmsProductMapper; /** * 查询产品销售话术 @@ -125,43 +129,58 @@ public class WmsProductSalesScriptServiceImpl implements IWmsProductSalesScriptS return baseMapper.deleteBatchIds(ids) > 0; } - /** - * 获取热门产品排行(基于访问频率) - */ @Override - public List getHotProducts(Integer limit) { - // 获取所有产品访问频率的key - Collection keys = RedisUtils.keys("product:visit:frequency:*"); - - List hotProducts = keys.stream() - .map(key -> { - String productIdStr = key.replace("product:visit:frequency:", ""); - Long productId = Long.valueOf(productIdStr); - Long visitCount = RedisUtils.getAtomicValue(key); - - // 查询产品信息 - WmsProduct product = wmsProductMapper.selectById(productId); - if (product == null) { - return null; - } - - HotProductVO vo = new HotProductVO(); - vo.setProductId(productId); - vo.setProductName(product.getProductName()); - vo.setProductCode(product.getProductCode()); - vo.setVisitCount(visitCount); - return vo; - }) - .filter(vo -> vo != null) - .sorted(Comparator.comparing(HotProductVO::getVisitCount).reversed()) - .limit(limit) - .collect(Collectors.toList()); - - // 设置排名 - for (int i = 0; i < hotProducts.size(); i++) { - hotProducts.get(i).setRank(i + 1); + public void recordProductViewCount(Long productId) { + String countKey = "product:view:count:" + productId; + String rankingKey = "product:view:ranking"; + + // 计数器+1(使用原子操作) + RedisUtils.incrAtomicValue(countKey); + + // 设置计数器过期时间为1天 + RedisUtils.expire(countKey, 24 * 60 * 60); + + // 更新排行榜(使用ZSet操作) + RScoredSortedSet zSet = RedisUtils.getClient().getScoredSortedSet(rankingKey); + zSet.addScore(productId.toString(), 1); + + // 设置排行榜过期时间为1天 + RedisUtils.expire(rankingKey, 24 * 60 * 60); + } + + @Override + public List getProductRanking() { + String rankingKey = "product:view:ranking"; + + // 获取排行榜前10名(按访问次数降序) + RScoredSortedSet zSet = RedisUtils.getClient().getScoredSortedSet(rankingKey); + + List rankingList = new ArrayList<>(); + int rank = 1; + + // 获取前10名的产品ID和分数 + Collection topProducts = zSet.valueRangeReversed(0, 9); + + for (String productIdStr : topProducts) { + Long productId = Long.valueOf(productIdStr); + Double score = zSet.getScore(productIdStr); + Long viewCount = score != null ? score.longValue() : 0L; + + ProductRankingVo vo = new ProductRankingVo(); + vo.setProductId(productId); + vo.setViewCount(viewCount); + vo.setRanking(rank++); + + //补充产品基础信息(这里需要注入ProductMapper) + WmsProduct product = wmsProductMapper.selectById(productId); + if (product != null) { + vo.setProductCode(product.getProductCode()); + vo.setProductName(product.getProductName()); + } + + rankingList.add(vo); } - - return hotProducts; + + return rankingList; } } diff --git a/klp-wms/src/main/java/com/klp/service/impl/WmsProductServiceImpl.java b/klp-wms/src/main/java/com/klp/service/impl/WmsProductServiceImpl.java index bc43cf99..9d276bc4 100644 --- a/klp-wms/src/main/java/com/klp/service/impl/WmsProductServiceImpl.java +++ b/klp-wms/src/main/java/com/klp/service/impl/WmsProductServiceImpl.java @@ -16,8 +16,6 @@ import com.klp.domain.WmsProduct; import com.klp.mapper.WmsProductMapper; import com.klp.service.IWmsProductService; import com.klp.domain.vo.OrderSummaryVO; -import com.klp.domain.vo.HotProductVO; -import com.klp.service.IWmsProductSalesScriptService; import java.util.List; import java.util.Map; @@ -34,7 +32,6 @@ import java.util.Collection; public class WmsProductServiceImpl implements IWmsProductService { private final WmsProductMapper baseMapper; - private final IWmsProductSalesScriptService iWmsProductSalesScriptService; /** * 查询产品 @@ -152,8 +149,6 @@ public class WmsProductServiceImpl implements IWmsProductService { vo.setProductRank(baseMapper.selectProductRank()); vo.setOrderMaterial(baseMapper.selectOrderMaterial()); vo.setCustomerRegion(baseMapper.selectCustomerRegion()); - // 添加热门产品数据 - vo.setHotProducts(iWmsProductSalesScriptService.getHotProducts(10)); return vo; } }