|
@@ -0,0 +1,171 @@
|
|
|
|
|
+package com.mangoo.rating.recommend.service.impl;
|
|
|
|
|
+
|
|
|
|
|
+import com.mangoo.rating.recommend.AjaxResult;
|
|
|
|
|
+import com.mangoo.rating.recommend.config.RecommendProperties;
|
|
|
|
|
+import com.mangoo.rating.recommend.enums.EvaluateEfficiencyEnum;
|
|
|
|
|
+import com.mangoo.rating.recommend.enums.MatchLevelEnum;
|
|
|
|
|
+import com.mangoo.rating.recommend.manager.RatingRecommendRuleManager;
|
|
|
|
|
+import com.mangoo.rating.recommend.po.RatingRecommendRulePO;
|
|
|
|
|
+import com.mangoo.rating.recommend.request.recommend.RecommendCardDTO;
|
|
|
|
|
+import com.mangoo.rating.recommend.request.recommend.RecommendRequest;
|
|
|
|
|
+import com.mangoo.rating.recommend.response.recommend.OrderSuggestionVO;
|
|
|
|
|
+import com.mangoo.rating.recommend.response.recommend.RecommendCardVO;
|
|
|
|
|
+import com.mangoo.rating.recommend.response.recommend.RecommendResultVO;
|
|
|
|
|
+import com.mangoo.rating.recommend.service.RecommendService;
|
|
|
|
|
+import com.mangoo.rating.recommend.service.recommend.EfficiencyPriceProvider;
|
|
|
|
|
+import com.mangoo.rating.recommend.service.recommend.OrderGrouper;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+
|
|
|
|
|
+import javax.annotation.Resource;
|
|
|
|
|
+import java.math.BigDecimal;
|
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 评级时效推荐服务实现
|
|
|
|
|
+ *
|
|
|
|
|
+ * 流程:
|
|
|
|
|
+ * 1) 逐卡按"全等→L2→L3→兜底"降级匹配,得到 (recommendEfficiency, matchLevel)
|
|
|
|
|
+ * 2) 用纯类 OrderGrouper 按时效精确分组
|
|
|
|
|
+ * 3) 加载时效价格(取不到则全部降级"待计算")
|
|
|
|
|
+ * 4) 回填单价/总计/合计,组装响应
|
|
|
|
|
+ *
|
|
|
|
|
+ * @author gengjintao
|
|
|
|
|
+ * @date 2026/06/24
|
|
|
|
|
+ */
|
|
|
|
|
+@Slf4j
|
|
|
|
|
+@Service
|
|
|
|
|
+public class RecommendServiceImpl implements RecommendService {
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private RatingRecommendRuleManager ratingRecommendRuleManager;
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private EfficiencyPriceProvider efficiencyPriceProvider;
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private RecommendProperties recommendProperties;
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public AjaxResult recommendEfficiency(RecommendRequest request) {
|
|
|
|
|
+ // 入参校验
|
|
|
|
|
+ if (request == null || request.getCards() == null || request.getCards().isEmpty()) {
|
|
|
|
|
+ return AjaxResult.error("卡列表不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (request.getCards().size() > recommendProperties.getBatchMax()) {
|
|
|
|
|
+ return AjaxResult.error("单次卡数量超过上限:" + recommendProperties.getBatchMax());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 1) 逐卡推荐 → 转 VO
|
|
|
|
|
+ List<RecommendCardVO> cardVOs = new ArrayList<>(request.getCards().size());
|
|
|
|
|
+ for (RecommendCardDTO dto : request.getCards()) {
|
|
|
|
|
+ cardVOs.add(recommendOneCard(dto));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2) 按时效精确分组
|
|
|
|
|
+ List<OrderSuggestionVO> orders = OrderGrouper.group(cardVOs);
|
|
|
|
|
+
|
|
|
|
|
+ // 3) 报价(取不到则全部 null=待计算,不阻断)
|
|
|
|
|
+ Map<Integer, BigDecimal> priceMap = efficiencyPriceProvider.loadEfficiencyPrices();
|
|
|
|
|
+ BigDecimal grandTotal = applyPricing(orders, priceMap);
|
|
|
|
|
+
|
|
|
|
|
+ // 4) 组装响应
|
|
|
|
|
+ RecommendResultVO result = new RecommendResultVO();
|
|
|
|
|
+ result.setTotalCards(request.getCards().size());
|
|
|
|
|
+ result.setOrderCount(orders.size());
|
|
|
|
|
+ result.setGrandTotal(grandTotal);
|
|
|
|
|
+ result.setOrders(orders);
|
|
|
|
|
+ return AjaxResult.success("推荐成功", result);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 单卡降级匹配:EXACT → L2 → L3 → DEFAULT
|
|
|
|
|
+ */
|
|
|
|
|
+ private RecommendCardVO recommendOneCard(RecommendCardDTO dto) {
|
|
|
|
|
+ RecommendCardVO vo = new RecommendCardVO();
|
|
|
|
|
+ vo.setClientCardId(dto.getClientCardId());
|
|
|
|
|
+ vo.setPlayer(dto.getPlayer());
|
|
|
|
|
+ vo.setYear(dto.getYear());
|
|
|
|
|
+ vo.setSeries(dto.getSeries());
|
|
|
|
|
+ vo.setCardSet(dto.getCardSet());
|
|
|
|
|
+ vo.setFrontImageUrl(dto.getFrontImageUrl());
|
|
|
|
|
+ vo.setBackImageUrl(dto.getBackImageUrl());
|
|
|
|
|
+
|
|
|
|
|
+ // L1:四字段全等命中
|
|
|
|
|
+ RatingRecommendRulePO rule = ratingRecommendRuleManager.selectByExact(
|
|
|
|
|
+ dto.getPlayer(), dto.getYear(), dto.getSeries(), dto.getCardSet());
|
|
|
|
|
+ if (isLegalRule(rule)) {
|
|
|
|
|
+ vo.setRecommendEfficiency(rule.getRecommendEfficiency());
|
|
|
|
|
+ vo.setMatchLevel(MatchLevelEnum.EXACT.getCode());
|
|
|
|
|
+ return vo;
|
|
|
|
|
+ }
|
|
|
|
|
+ // L2:series + cardSet + year
|
|
|
|
|
+ rule = ratingRecommendRuleManager.selectBySeriesSetYear(dto.getSeries(), dto.getCardSet(), dto.getYear());
|
|
|
|
|
+ if (isLegalRule(rule)) {
|
|
|
|
|
+ vo.setRecommendEfficiency(rule.getRecommendEfficiency());
|
|
|
|
|
+ vo.setMatchLevel(MatchLevelEnum.L2.getCode());
|
|
|
|
|
+ return vo;
|
|
|
|
|
+ }
|
|
|
|
|
+ // L3:series + cardSet
|
|
|
|
|
+ rule = ratingRecommendRuleManager.selectBySeriesSet(dto.getSeries(), dto.getCardSet());
|
|
|
|
|
+ if (isLegalRule(rule)) {
|
|
|
|
|
+ vo.setRecommendEfficiency(rule.getRecommendEfficiency());
|
|
|
|
|
+ vo.setMatchLevel(MatchLevelEnum.L3.getCode());
|
|
|
|
|
+ return vo;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 兜底
|
|
|
|
|
+ vo.setRecommendEfficiency(recommendProperties.getDefaultEfficiency());
|
|
|
|
|
+ vo.setMatchLevel(MatchLevelEnum.DEFAULT.getCode());
|
|
|
|
|
+ return vo;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 校验规则及其时效值是否合法(非空 + 时效在 EvaluateEfficiencyEnum 范围内)
|
|
|
|
|
+ */
|
|
|
|
|
+ private boolean isLegalRule(RatingRecommendRulePO rule) {
|
|
|
|
|
+ return rule != null
|
|
|
|
|
+ && rule.getRecommendEfficiency() != null
|
|
|
|
|
+ && EvaluateEfficiencyEnum.getByCode(rule.getRecommendEfficiency()) != null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 给订单列表回填单价/总计,并返回所有订单合计。
|
|
|
|
|
+ * 价格 Map 为空或某档无价 → 该订单 unitPrice/totalAmount = null("待计算"),并将 grandTotal 置 null。
|
|
|
|
|
+ */
|
|
|
|
|
+ private BigDecimal applyPricing(List<OrderSuggestionVO> orders, Map<Integer, BigDecimal> priceMap) {
|
|
|
|
|
+ if (orders == null || orders.isEmpty()) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ BigDecimal grand = BigDecimal.ZERO;
|
|
|
|
|
+ boolean grandNull = false;
|
|
|
|
|
+
|
|
|
|
|
+ for (OrderSuggestionVO order : orders) {
|
|
|
|
|
+ BigDecimal unit = (priceMap == null) ? null : priceMap.get(order.getEfficiency());
|
|
|
|
|
+ if (unit == null) {
|
|
|
|
|
+ // 该档价格缺失 → 订单 unitPrice/totalAmount = null,整体合计同步置 null
|
|
|
|
|
+ order.setUnitPrice(null);
|
|
|
|
|
+ order.setTotalAmount(null);
|
|
|
|
|
+ grandNull = true;
|
|
|
|
|
+ // 卡级单价同步 null
|
|
|
|
|
+ if (order.getCards() != null) {
|
|
|
|
|
+ for (RecommendCardVO c : order.getCards()) {
|
|
|
|
|
+ c.setUnitPrice(null);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ BigDecimal total = unit.multiply(BigDecimal.valueOf(order.getCardCount()));
|
|
|
|
|
+ order.setUnitPrice(unit);
|
|
|
|
|
+ order.setTotalAmount(total);
|
|
|
|
|
+ if (order.getCards() != null) {
|
|
|
|
|
+ for (RecommendCardVO c : order.getCards()) {
|
|
|
|
|
+ c.setUnitPrice(unit);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ grand = grand.add(total);
|
|
|
|
|
+ }
|
|
|
|
|
+ return grandNull ? null : grand;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|