Эх сурвалжийг харах

feat(recommend): 卡片详情/趋势查询接口(GET /api/recommend/card/detail)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jintao.geng 1 сар өмнө
parent
commit
1c22bfb142

+ 37 - 0
mango-application/src/main/java/com/mangoo/rating/recommend/app/controller/CardController.java

@@ -0,0 +1,37 @@
+package com.mangoo.rating.recommend.app.controller;
+
+import com.mangoo.rating.recommend.AjaxResult;
+import com.mangoo.rating.recommend.annotation.ApiLog;
+import com.mangoo.rating.recommend.enums.BusinessType;
+import com.mangoo.rating.recommend.service.CardDetailService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 小程序-卡片详情/趋势接口
+ *
+ * @author gengjintao
+ * @date 2026/06/25
+ */
+@Api(tags = "小程序-卡片详情趋势接口")
+@RestController
+@RequestMapping("/api/recommend/card")
+public class CardController {
+
+    @Resource
+    private CardDetailService cardDetailService;
+
+    @ApiOperation("查询卡片详情(身份+POP+行情+价格趋势)")
+    @GetMapping("/detail")
+    @ApiLog(title = "卡片详情趋势查询", businessType = BusinessType.SEARCH)
+    public AjaxResult detail(@RequestParam("cardId") String cardId,
+                             @RequestParam(value = "period", defaultValue = "30d") String period) {
+        return cardDetailService.getDetail(cardId, period);
+    }
+}

+ 32 - 0
mango-common/src/main/java/com/mangoo/rating/recommend/response/recommend/CardDetailVO.java

@@ -0,0 +1,32 @@
+package com.mangoo.rating.recommend.response.recommend;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.util.List;
+
+/** 卡片详情/趋势 VO(对齐前端详情页 UI) */
+@Data
+@ApiModel("卡片详情")
+public class CardDetailVO {
+    @ApiModelProperty(value = "数仓卡片唯一ID")
+    private String cardId;
+    @ApiModelProperty(value = "卡号")
+    private String cardNo;
+    @ApiModelProperty(value = "卡牌主体名")
+    private String name;
+    @ApiModelProperty(value = "年份")
+    private String year;
+    @ApiModelProperty(value = "系列")
+    private String series;
+    @ApiModelProperty(value = "卡种")
+    private String cardSet;
+    @ApiModelProperty(value = "卡图URL(本期可能为 null)")
+    private String imageUrl;
+    @ApiModelProperty(value = "POP 明细(三机构)")
+    private List<CardPopVO> pops;
+    @ApiModelProperty(value = "行情")
+    private CardValueVO value;
+    @ApiModelProperty(value = "价格趋势点(按日期升序)")
+    private List<TrendPointVO> trend;
+}

+ 20 - 0
mango-common/src/main/java/com/mangoo/rating/recommend/response/recommend/CardValueVO.java

@@ -0,0 +1,20 @@
+package com.mangoo.rating.recommend.response.recommend;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.math.BigDecimal;
+
+/** 卡片行情 VO */
+@Data
+@ApiModel("卡片行情")
+public class CardValueVO {
+    @ApiModelProperty(value = "当前价")
+    private BigDecimal current;
+    @ApiModelProperty(value = "涨跌幅(百分数)")
+    private BigDecimal changePct;
+    @ApiModelProperty(value = "区间下限")
+    private BigDecimal min;
+    @ApiModelProperty(value = "区间上限")
+    private BigDecimal max;
+}

+ 17 - 0
mango-common/src/main/java/com/mangoo/rating/recommend/response/recommend/TrendPointVO.java

@@ -0,0 +1,17 @@
+package com.mangoo.rating.recommend.response.recommend;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+/** 价格趋势点 VO */
+@Data
+@ApiModel("价格趋势点")
+public class TrendPointVO {
+    @ApiModelProperty(value = "日期")
+    private LocalDate date;
+    @ApiModelProperty(value = "价格")
+    private BigDecimal price;
+}

+ 18 - 0
mango-domain/src/main/java/com/mangoo/rating/recommend/service/CardDetailService.java

@@ -0,0 +1,18 @@
+package com.mangoo.rating.recommend.service;
+
+import com.mangoo.rating.recommend.AjaxResult;
+
+/**
+ * 卡片详情/趋势查询服务
+ *
+ * @author gengjintao
+ * @date 2026/06/25
+ */
+public interface CardDetailService {
+    /**
+     * 查卡片详情(身份+POP+行情+价格趋势)
+     * @param cardId 数仓卡片ID
+     * @param period 趋势时间窗:7d/30d/90d/all
+     */
+    AjaxResult getDetail(String cardId, String period);
+}

+ 123 - 0
mango-domain/src/main/java/com/mangoo/rating/recommend/service/impl/CardDetailServiceImpl.java

@@ -0,0 +1,123 @@
+package com.mangoo.rating.recommend.service.impl;
+
+import com.mangoo.rating.recommend.AjaxResult;
+import com.mangoo.rating.recommend.manager.ActiveBatchManager;
+import com.mangoo.rating.recommend.manager.CardPopManager;
+import com.mangoo.rating.recommend.manager.CardValueHistoryManager;
+import com.mangoo.rating.recommend.manager.RatingRecommendRuleManager;
+import com.mangoo.rating.recommend.po.CardPopPO;
+import com.mangoo.rating.recommend.po.CardValueHistoryPO;
+import com.mangoo.rating.recommend.po.RatingRecommendRulePO;
+import com.mangoo.rating.recommend.response.recommend.CardDetailVO;
+import com.mangoo.rating.recommend.response.recommend.CardPopVO;
+import com.mangoo.rating.recommend.response.recommend.CardValueVO;
+import com.mangoo.rating.recommend.response.recommend.TrendPointVO;
+import com.mangoo.rating.recommend.service.CardDetailService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 卡片详情/趋势查询服务实现
+ *
+ * @author gengjintao
+ * @date 2026/06/25
+ */
+@Slf4j
+@Service
+public class CardDetailServiceImpl implements CardDetailService {
+
+    @Resource
+    private RatingRecommendRuleManager ratingRecommendRuleManager;
+    @Resource
+    private CardPopManager cardPopManager;
+    @Resource
+    private CardValueHistoryManager cardValueHistoryManager;
+    @Resource
+    private ActiveBatchManager activeBatchManager;
+
+    @Override
+    public AjaxResult getDetail(String cardId, String period) {
+        if (cardId == null || cardId.trim().isEmpty()) {
+            return AjaxResult.error("cardId 不能为空");
+        }
+        String activeBatchNo = activeBatchManager.selectActiveBatchNo();
+        if (activeBatchNo == null) {
+            return AjaxResult.error("暂无生效规则数据");
+        }
+        RatingRecommendRulePO rule = ratingRecommendRuleManager.selectByCardId(cardId, activeBatchNo);
+        if (rule == null) {
+            return AjaxResult.error("卡片不存在或已失效");
+        }
+
+        CardDetailVO vo = new CardDetailVO();
+        vo.setCardId(rule.getCardId());
+        vo.setCardNo(rule.getCardNo());
+        vo.setName(rule.getPlayer());
+        vo.setYear(rule.getYear());
+        vo.setSeries(rule.getSeries());
+        vo.setCardSet(rule.getCardSet());
+        vo.setImageUrl(null); // 本期规则表未存卡图,留 null
+
+        // 行情
+        CardValueVO value = new CardValueVO();
+        value.setCurrent(rule.getCurrentValue());
+        value.setChangePct(rule.getValueChangePct());
+        value.setMin(rule.getValueMin());
+        value.setMax(rule.getValueMax());
+        vo.setValue(value);
+
+        // POP 明细
+        List<CardPopPO> pops = cardPopManager.selectByCardId(cardId, activeBatchNo);
+        List<CardPopVO> popVOs = new ArrayList<>();
+        for (CardPopPO p : pops) {
+            CardPopVO pv = new CardPopVO();
+            pv.setAgency(p.getAgency());
+            pv.setAll(p.getGradeAll());
+            pv.setG10(p.getGrade10());
+            pv.setG9(p.getGrade9());
+            pv.setG8(p.getGrade8());
+            pv.setG7(p.getGrade7());
+            popVOs.add(pv);
+        }
+        vo.setPops(popVOs);
+
+        // 价格趋势(period → 起始日期)
+        LocalDate startDate = resolveStartDate(period);
+        List<CardValueHistoryPO> history = cardValueHistoryManager.selectTrend(cardId, startDate);
+        List<TrendPointVO> trend = new ArrayList<>();
+        for (CardValueHistoryPO h : history) {
+            TrendPointVO tp = new TrendPointVO();
+            tp.setDate(h.getRecordDate());
+            tp.setPrice(h.getPrice());
+            trend.add(tp);
+        }
+        vo.setTrend(trend);
+
+        return AjaxResult.success("查询成功", vo);
+    }
+
+    /**
+     * 解析时间窗为起始日期;all 或非法值返回 null(查全部),默认 30d
+     */
+    private LocalDate resolveStartDate(String period) {
+        if (period == null) {
+            return LocalDate.now().minusDays(30);
+        }
+        switch (period.trim()) {
+            case "7d":
+                return LocalDate.now().minusDays(7);
+            case "90d":
+                return LocalDate.now().minusDays(90);
+            case "all":
+                return null;
+            case "30d":
+            default:
+                return LocalDate.now().minusDays(30);
+        }
+    }
+}

+ 5 - 0
mango-infrastructure/src/main/java/com/mangoo/rating/recommend/mapper/RatingRecommendRuleMapper.java

@@ -37,6 +37,11 @@ public interface RatingRecommendRuleMapper {
                                             @Param("cardSet") String cardSet,
                                             @Param("batchNo") String batchNo);
 
+    /**
+     * 按数仓卡片ID命中(限定生效批次,用于卡片详情查询)
+     */
+    RatingRecommendRulePO selectByCardId(@Param("cardId") String cardId, @Param("batchNo") String batchNo);
+
     /**
      * 数仓同步:批量插入规则(物理全量替换,del_flag 恒为 0)
      */

+ 8 - 0
mango-infrastructure/src/main/resources/mapper/RatingRecommendRuleMapper.xml

@@ -72,6 +72,14 @@
         LIMIT 1
     </select>
 
+    <!-- 按数仓卡片ID命中(限定生效批次,用于卡片详情查询) -->
+    <select id="selectByCardId" resultMap="BaseResultMap">
+        SELECT <include refid="baseColumnList"/>
+        FROM t_rating_recommend_rule
+        WHERE del_flag = 0 AND card_id = #{cardId} AND batch_no = #{batchNo}
+        LIMIT 1
+    </select>
+
     <!-- 数仓同步:批量插入规则(物理全量替换,del_flag 恒为 0) -->
     <insert id="batchInsert">
         INSERT INTO t_rating_recommend_rule

+ 5 - 0
mango-manager/src/main/java/com/mangoo/rating/recommend/manager/RatingRecommendRuleManager.java

@@ -25,6 +25,11 @@ public interface RatingRecommendRuleManager {
      */
     RatingRecommendRulePO selectBySeriesSet(String series, String cardSet, String batchNo);
 
+    /**
+     * 按数仓卡片ID命中(cardId 或 batchNo 为空返回 null;用于卡片详情查询)
+     */
+    RatingRecommendRulePO selectByCardId(String cardId, String batchNo);
+
     /**
      * 数仓同步:批量插入规则(物理全量替换)
      */

+ 9 - 0
mango-manager/src/main/java/com/mangoo/rating/recommend/manager/impl/RatingRecommendRuleManagerImpl.java

@@ -48,6 +48,15 @@ public class RatingRecommendRuleManagerImpl implements RatingRecommendRuleManage
         return ratingRecommendRuleMapper.selectBySeriesSet(series, cardSet, batchNo);
     }
 
+    @Override
+    public RatingRecommendRulePO selectByCardId(String cardId, String batchNo) {
+        // cardId 或 batchNo 为空直接返回 null(无生效批次或无卡片ID不查)
+        if (isBlank(cardId) || isBlank(batchNo)) {
+            return null;
+        }
+        return ratingRecommendRuleMapper.selectByCardId(cardId, batchNo);
+    }
+
     @Override
     public int batchInsert(java.util.List<RatingRecommendRulePO> list) {
         if (list == null || list.isEmpty()) {