zhangchen 2 mesi fa
parent
commit
3d8d29e57b

+ 56 - 0
alien-store/src/main/java/shop/alien/store/controller/StoreOperationalStatisticsController.java

@@ -125,6 +125,62 @@ public class StoreOperationalStatisticsController {
         return R.data(comparison);
     }
 
+    @ApiOperation("获取商家经营统计数据对比(新接口)")
+    @ApiOperationSupport(order = 21)
+    @ApiImplicitParams({
+            @ApiImplicitParam(
+                    name = "storeId",
+                    value = "店铺ID",
+                    dataType = "Integer",
+                    paramType = "query",
+                    required = true
+            ),
+            @ApiImplicitParam(
+                    name = "currentStartTime",
+                    value = "当期开始时间(格式:yyyy-MM-dd)",
+                    dataType = "String",
+                    paramType = "query",
+                    required = true
+            ),
+            @ApiImplicitParam(
+                    name = "currentEndTime",
+                    value = "当期结束时间(格式:yyyy-MM-dd)",
+                    dataType = "String",
+                    paramType = "query",
+                    required = true
+            ),
+            @ApiImplicitParam(
+                    name = "previousStartTime",
+                    value = "上期开始时间(格式:yyyy-MM-dd)",
+                    dataType = "String",
+                    paramType = "query",
+                    required = true
+            ),
+            @ApiImplicitParam(
+                    name = "previousEndTime",
+                    value = "上期结束时间(格式:yyyy-MM-dd)",
+                    dataType = "String",
+                    paramType = "query",
+                    required = true
+            )
+    })
+    @GetMapping("/getStatisticsComparisonNew")
+    public R<StoreOperationalStatisticsComparisonVo> getStatisticsComparisonNew(
+            @RequestParam("storeId") Integer storeId,
+            @RequestParam("currentStartTime") String currentStartTime,
+            @RequestParam("currentEndTime") String currentEndTime,
+            @RequestParam("previousStartTime") String previousStartTime,
+            @RequestParam("previousEndTime") String previousEndTime) {
+        log.info("StoreOperationalStatisticsController.getStatisticsComparisonNew - storeId={}, currentStartTime={}, currentEndTime={}, previousStartTime={}, previousEndTime={}",
+                storeId, currentStartTime, currentEndTime, previousStartTime, previousEndTime);
+        StoreOperationalStatisticsComparisonVo comparison = storeOperationalStatisticsService.getStatisticsComparisonNew(
+                storeId, currentStartTime, currentEndTime, previousStartTime, previousEndTime);
+        if (comparison == null) {
+            return R.fail("暂无对比数据");
+        }
+        return R.data(comparison);
+    }
+
     @ApiOperation("查询历史统计记录列表(分页)")
     @ApiOperationSupport(order = 3)
     @ApiImplicitParams({

+ 13 - 0
alien-store/src/main/java/shop/alien/store/service/StoreOperationalStatisticsService.java

@@ -40,6 +40,19 @@ public interface StoreOperationalStatisticsService {
                                                                     String previousStartTime, String previousEndTime);
 
     /**
+     * 获取商家经营统计数据对比(新接口)
+     *
+     * @param storeId           店铺ID
+     * @param currentStartTime  当期开始时间(格式:yyyy-MM-dd)
+     * @param currentEndTime    当期结束时间(格式:yyyy-MM-dd)
+     * @param previousStartTime 上期开始时间(格式:yyyy-MM-dd)
+     * @param previousEndTime   上期结束时间(格式:yyyy-MM-dd)
+     * @return 经营统计数据对比
+     */
+    StoreOperationalStatisticsComparisonVo getStatisticsComparisonNew(Integer storeId, String currentStartTime, String currentEndTime,
+                                                                      String previousStartTime, String previousEndTime);
+
+    /**
      * 查询历史统计记录列表(分页)
      *
      * @param storeId    店铺ID

+ 140 - 0
alien-store/src/main/java/shop/alien/store/service/impl/StoreOperationalStatisticsServiceImpl.java

@@ -317,6 +317,72 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
         return comparison;
     }
 
+    @Override
+    public StoreOperationalStatisticsComparisonVo getStatisticsComparisonNew(Integer storeId, String currentStartTime, String currentEndTime,
+                                                                            String previousStartTime, String previousEndTime) {
+
+        log.info("StoreOperationalStatisticsServiceImpl.getStatisticsComparison - storeId={}, currentStartTime={}, currentEndTime={}, previousStartTime={}, previousEndTime={}",
+                storeId, currentStartTime, currentEndTime, previousStartTime, previousEndTime);
+
+        // 参数校验
+        if (storeId == null || storeId <= 0) {
+            throw new IllegalArgumentException("店铺ID不能为空且必须大于0");
+        }
+        if (currentStartTime == null || currentStartTime.trim().isEmpty()) {
+            throw new IllegalArgumentException("当期开始时间不能为空");
+        }
+        if (currentEndTime == null || currentEndTime.trim().isEmpty()) {
+            throw new IllegalArgumentException("当期结束时间不能为空");
+        }
+        if (previousStartTime == null || previousStartTime.trim().isEmpty()) {
+            throw new IllegalArgumentException("上期开始时间不能为空");
+        }
+        if (previousEndTime == null || previousEndTime.trim().isEmpty()) {
+            throw new IllegalArgumentException("上期结束时间不能为空");
+        }
+
+        StoreOperationalStatisticsComparisonVo comparison = new StoreOperationalStatisticsComparisonVo();
+        comparison.setCurrentStartTime(currentStartTime);
+        comparison.setCurrentEndTime(currentEndTime);
+        comparison.setPreviousStartTime(previousStartTime);
+        comparison.setPreviousEndTime(previousEndTime);
+
+        // 获取当期和上期的统计数据
+        StoreOperationalStatisticsVo currentStatistics = calculateStatistics(storeId, currentStartTime, currentEndTime);
+        StoreOperationalStatisticsVo previousStatistics = calculateStatistics(storeId, previousStartTime, previousEndTime);
+
+        // 构建对比数据
+        comparison.setTrafficData(buildTrafficDataComparison(currentStatistics.getTrafficData(), previousStatistics.getTrafficData()));
+        comparison.setInteractionData(buildInteractionDataComparison(currentStatistics.getInteractionData(), previousStatistics.getInteractionData()));
+        comparison.setCouponData(buildCouponDataComparison(currentStatistics.getCouponData(), previousStatistics.getCouponData()));
+        comparison.setVoucherData(buildVoucherDataComparison(currentStatistics.getVoucherData(), previousStatistics.getVoucherData()));
+        comparison.setServiceQualityData(buildServiceQualityDataComparison(currentStatistics.getServiceQualityData(), previousStatistics.getServiceQualityData()));
+        comparison.setPriceListRanking(buildPriceListRankingComparison(currentStatistics.getPriceListRanking(), previousStatistics.getPriceListRanking(), storeId));
+
+        // 当comparison中所有对比数据的current和previous都为0或为空时,不抛异常,返回 null(由 Controller 返回失败提示)
+        if (!hasComparisonData(comparison)) {
+            return null;
+        }
+
+        // 保存历史记录(不包含PDF URL,PDF URL只在 generateStatisticsComparisonPdf 接口中保存)
+        Integer historyId = saveStatisticsHistory(storeId, currentStartTime, currentEndTime,
+                previousStartTime, previousEndTime, comparison, null);
+
+        // 将历史记录ID设置到返回对象中
+        comparison.setHistoryId(historyId);
+
+        // 异步调用AI接口进行数据分析
+        if (historyId != null) {
+            try {
+                callAiAnalysisAsync(historyId, storeId, comparison);
+            } catch (Exception e) {
+                log.error("调用AI分析接口失败 - historyId={}, error={}", historyId, e.getMessage(), e);
+                // AI分析失败不影响主流程,只记录日志
+            }
+        }
+
+        return comparison;
+    }
 
     /**
      * 将StoreOperationalStatisticsVo转换为符合埋点统计数据JSON格式
@@ -991,6 +1057,80 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
     }
 
     /**
+     * 判断 comparison 中是否至少有一项对比数据有效(current 或 previous 非 0 且非空)。
+     */
+    private boolean hasComparisonData(StoreOperationalStatisticsComparisonVo comparison) {
+        if (comparison == null) {
+            return false;
+        }
+        boolean hasData = hasAnyMeaningfulData(comparison.getTrafficData())
+                || hasAnyMeaningfulData(comparison.getInteractionData())
+                || hasAnyMeaningfulData(comparison.getCouponData())
+                || hasAnyMeaningfulData(comparison.getVoucherData())
+                || hasAnyMeaningfulData(comparison.getServiceQualityData());
+        if (!hasData && comparison.getPriceListRanking() != null) {
+            for (StoreOperationalStatisticsComparisonVo.PriceListRankingComparison pr : comparison.getPriceListRanking()) {
+                if (pr != null && (hasMeaningfulValue(pr.getPageViews()) || hasMeaningfulValue(pr.getVisitors()) || hasMeaningfulValue(pr.getShares()))) {
+                    hasData = true;
+                    break;
+                }
+            }
+        }
+        return hasData;
+    }
+
+    /**
+     * 校验 comparison 中是否至少有一项对比数据有效(current 或 previous 非 0 且非空)。
+     * 若所有对比数据的 current 和 previous 都为 0 或空,则抛出 IllegalArgumentException("暂无对比数据")。
+     */
+    private void validateComparisonHasData(StoreOperationalStatisticsComparisonVo comparison) {
+        if (!hasComparisonData(comparison)) {
+            throw new IllegalArgumentException("暂无对比数据");
+        }
+    }
+
+    private boolean hasAnyMeaningfulData(Object dataComparison) {
+        if (dataComparison == null) {
+            return false;
+        }
+        java.lang.reflect.Field[] fields = dataComparison.getClass().getDeclaredFields();
+        for (java.lang.reflect.Field f : fields) {
+            if (StoreOperationalStatisticsComparisonVo.BaseComparisonData.class.isAssignableFrom(f.getType())) {
+                try {
+                    f.setAccessible(true);
+                    StoreOperationalStatisticsComparisonVo.BaseComparisonData b = (StoreOperationalStatisticsComparisonVo.BaseComparisonData) f.get(dataComparison);
+                    if (hasMeaningfulValue(b)) {
+                        return true;
+                    }
+                } catch (Exception ignored) {
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean hasMeaningfulValue(StoreOperationalStatisticsComparisonVo.BaseComparisonData b) {
+        if (b == null) {
+            return false;
+        }
+        return !isNullOrZero(b.getCurrent()) || !isNullOrZero(b.getPrevious());
+    }
+
+    private boolean isNullOrZero(Object v) {
+        if (v == null) {
+            return true;
+        }
+        if (v instanceof Number) {
+            return ((Number) v).doubleValue() == 0;
+        }
+        if (v instanceof CharSequence) {
+            String s = v.toString().trim();
+            return s.isEmpty() || "0".equals(s) || "0.0".equals(s);
+        }
+        return false;
+    }
+
+    /**
      * 构建对比数据
      */
     private StoreOperationalStatisticsComparisonVo.BaseComparisonData buildComparisonData(Object current, Object previous) {