Explorar o código

Merge branch 'release_buried-point_ph' into sit

lutong hai 2 meses
pai
achega
370b08a527

+ 15 - 0
alien-gateway/pom.xml

@@ -220,10 +220,25 @@
                     <target>1.8</target>
                     <source>1.8</source>
                     <encoding>UTF-8</encoding>
+                    <parameters>true</parameters>
                     <!-- <compilerArguments> <extdirs>lib</extdirs> </compilerArguments> -->
                 </configuration>
             </plugin>
             <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <mainClass>shop.alien.gateway.AlienGatewayApplication</mainClass>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-jar-plugin</artifactId>
                 <configuration>

+ 538 - 46
alien-store/src/main/java/shop/alien/store/service/impl/StoreOperationalStatisticsServiceImpl.java

@@ -114,8 +114,8 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
                 return new StoreOperationalStatisticsVo();
             }
             
-            // 累加所有统计数据
-            return aggregateStatistics(statisticsList);
+            // 聚合统计数据(优先取结束日期的数据,只累加新增访客数)
+            return aggregateStatistics(statisticsList, endDate);
             
         } catch (ParseException e) {
             log.error("StoreOperationalStatisticsServiceImpl.calculateStatistics - 时间解析错误", e);
@@ -128,65 +128,127 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
     }
     
     /**
-     * 累加统计数据
+     * 聚合统计数据(优先取结束日期的数据,只累加流量数据中的新增访客数,其他数据取结束日期的记录)
+     * 
+     * @param statisticsList 统计数据列表
+     * @param endDate 结束日期(用于优先选择该日期的数据)
      */
-    private StoreOperationalStatisticsVo aggregateStatistics(List<StoreTrackStatistics> statisticsList) {
+    private StoreOperationalStatisticsVo aggregateStatistics(List<StoreTrackStatistics> statisticsList, Date endDate) {
         StoreOperationalStatisticsVo result = new StoreOperationalStatisticsVo();
         
-        // 初始化累加器
-        Map<String, Long> trafficAccumulator = new HashMap<>();
-        Map<String, Long> interactionAccumulator = new HashMap<>();
-        Map<String, Object> couponAccumulator = new HashMap<>();
-        Map<String, Object> voucherAccumulator = new HashMap<>();
-        Map<String, Object> serviceAccumulator = new HashMap<>();
-        Map<Integer, Map<String, Long>> priceRankingAccumulator = new HashMap<>();
-        
-        // 用于计算平均值的计数器
-        int trafficCount = 0;
-        int serviceCount = 0;
-        
-        // 遍历所有统计数据并累加
+        // 优先查找结束日期的数据(比较日期部分,忽略时间)
+        StoreTrackStatistics endDateStat = null;
+        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
+        String endDateStr = sdf.format(endDate);
         for (StoreTrackStatistics stat : statisticsList) {
-            // 累加流量数据
-            if (stat.getTrafficData() != null && !stat.getTrafficData().isEmpty()) {
-                aggregateTrafficData(stat.getTrafficData(), trafficAccumulator);
-                trafficCount++;
+            if (stat.getStatDate() != null) {
+                String statDateStr = sdf.format(stat.getStatDate());
+                if (endDateStr.equals(statDateStr)) {
+                    endDateStat = stat;
+                    break;
+                }
             }
+        }
+        
+        // 判断结束日期的数据是否有效(不全为0)
+        boolean endDateStatValid = false;
+        if (endDateStat != null) {
+            endDateStatValid = isStatisticsValid(endDateStat);
+        }
+        
+        // 如果没有结束日期的数据,或者结束日期的数据全是0,则按日期排序,取有数据的最新日期
+        StoreTrackStatistics latestStat = null;
+        if (endDateStat != null && endDateStatValid) {
+            latestStat = endDateStat;
+        } else {
+            // 按日期排序,从最新到最旧
+            statisticsList.sort((a, b) -> {
+                if (a.getStatDate() == null && b.getStatDate() == null) return 0;
+                if (a.getStatDate() == null) return 1;
+                if (b.getStatDate() == null) return -1;
+                return b.getStatDate().compareTo(a.getStatDate());
+            });
             
-            // 累加互动数据
-            if (stat.getInteractionData() != null && !stat.getInteractionData().isEmpty()) {
-                aggregateInteractionData(stat.getInteractionData(), interactionAccumulator);
+            // 查找第一个有数据的记录
+            for (StoreTrackStatistics stat : statisticsList) {
+                if (isStatisticsValid(stat)) {
+                    latestStat = stat;
+                    break;
+                }
             }
             
-            // 累加优惠券数据
-            if (stat.getCouponData() != null && !stat.getCouponData().isEmpty()) {
-                aggregateCouponData(stat.getCouponData(), couponAccumulator);
+            // 如果所有记录都无效,使用最新的记录(即使全是0)
+            if (latestStat == null && !statisticsList.isEmpty()) {
+                latestStat = statisticsList.get(0);
             }
             
-            // 累加代金券数据
-            if (stat.getVoucherData() != null && !stat.getVoucherData().isEmpty()) {
-                aggregateVoucherData(stat.getVoucherData(), voucherAccumulator);
+            if (latestStat != null) {
+                if (endDateStat != null && !endDateStatValid) {
+                    log.info("结束日期{}的数据全是0,使用范围内有数据的最新日期{}的数据", 
+                            endDateStr,
+                            latestStat.getStatDate() != null ? sdf.format(latestStat.getStatDate()) : "未知");
+                } else {
+                    log.info("结束日期{}没有统计数据,使用范围内最新日期{}的数据", 
+                            endDateStr,
+                            latestStat.getStatDate() != null ? sdf.format(latestStat.getStatDate()) : "未知");
+                }
             }
-            
-            // 累加服务质量数据
-            if (stat.getServiceData() != null && !stat.getServiceData().isEmpty()) {
-                aggregateServiceData(stat.getServiceData(), serviceAccumulator);
-                serviceCount++;
+        }
+        
+        // 如果找不到有效数据,返回空结果
+        if (latestStat == null) {
+            log.warn("未找到有效的统计数据,返回空结果");
+            return result;
+        }
+        
+        // 只累加流量数据中的新增访客数
+        long newVisitorCountSum = 0L;
+        for (StoreTrackStatistics stat : statisticsList) {
+            if (stat.getTrafficData() != null && !stat.getTrafficData().isEmpty()) {
+                try {
+                    Map<String, Object> trafficData = (Map<String, Object>) JSON.parseObject(stat.getTrafficData(), Map.class);
+                    if (trafficData != null && trafficData.containsKey("newVisitorCount")) {
+                        newVisitorCountSum += getLongValue(trafficData, "newVisitorCount");
+                    }
+                } catch (Exception e) {
+                    log.warn("解析流量数据失败: {}", stat.getTrafficData(), e);
+                }
             }
-            
-            // 累加价目表排名数据
-            if (stat.getPriceRankingData() != null && !stat.getPriceRankingData().isEmpty()) {
-                aggregatePriceRankingData(stat.getPriceRankingData(), priceRankingAccumulator);
+        }
+        
+        // 使用最新记录的数据,但替换新增访客数为累加值
+        if (latestStat.getTrafficData() != null && !latestStat.getTrafficData().isEmpty()) {
+            try {
+                Map<String, Object> latestTrafficData = (Map<String, Object>) JSON.parseObject(latestStat.getTrafficData(), Map.class);
+                if (latestTrafficData != null) {
+                    latestTrafficData.put("newVisitorCount", newVisitorCountSum);
+                    result.setTrafficData(convertToTrafficDataVoFromMap(latestTrafficData));
+                }
+            } catch (Exception e) {
+                log.warn("解析最新流量数据失败: {}", latestStat.getTrafficData(), e);
             }
         }
         
-        // 转换为VO对象
-        result.setTrafficData(convertToTrafficDataVo(trafficAccumulator, trafficCount));
-        result.setInteractionData(convertToInteractionDataVo(interactionAccumulator));
-        result.setCouponData(convertToCouponDataVo(couponAccumulator));
-        result.setVoucherData(convertToVoucherDataVo(voucherAccumulator));
-        result.setServiceQualityData(convertToServiceQualityDataVo(serviceAccumulator, serviceCount));
-        result.setPriceListRanking(convertToPriceListRankingVo(priceRankingAccumulator));
+        // 其他数据直接使用最新记录的值
+        if (latestStat.getInteractionData() != null && !latestStat.getInteractionData().isEmpty()) {
+            result.setInteractionData(convertToInteractionDataVoFromJson(latestStat.getInteractionData()));
+        }
+        
+        if (latestStat.getCouponData() != null && !latestStat.getCouponData().isEmpty()) {
+            result.setCouponData(convertToCouponDataVoFromJson(latestStat.getCouponData()));
+        }
+        
+        if (latestStat.getVoucherData() != null && !latestStat.getVoucherData().isEmpty()) {
+            result.setVoucherData(convertToVoucherDataVoFromJson(latestStat.getVoucherData()));
+        }
+        
+        if (latestStat.getServiceData() != null && !latestStat.getServiceData().isEmpty()) {
+            result.setServiceQualityData(convertToServiceQualityDataVoFromJson(latestStat.getServiceData()));
+        }
+        
+        if (latestStat.getPriceRankingData() != null && !latestStat.getPriceRankingData().isEmpty()) {
+            result.setPriceListRanking(convertToPriceListRankingVoFromJson(latestStat.getPriceRankingData()));
+        }
         
         return result;
     }
@@ -236,6 +298,9 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
         Integer historyId = saveStatisticsHistory(storeId, currentStartTime, currentEndTime, 
                 previousStartTime, previousEndTime, comparison, null);
 
+        // 将历史记录ID设置到返回对象中
+        comparison.setHistoryId(historyId);
+
         // 异步调用AI接口进行数据分析
         if (historyId != null) {
             try {
@@ -1655,6 +1720,121 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
     // ==================== 工具方法 ====================
     
     /**
+     * 判断统计数据是否有效(不全为0)
+     * 检查流量数据、互动数据、优惠券数据、代金券数据、服务质量数据、价目表排名数据中是否至少有一个字段不为0
+     */
+    @SuppressWarnings("unchecked")
+    private boolean isStatisticsValid(StoreTrackStatistics stat) {
+        if (stat == null) {
+            return false;
+        }
+        
+        try {
+            // 检查流量数据
+            if (stat.getTrafficData() != null && !stat.getTrafficData().isEmpty()) {
+                Map<String, Object> trafficData = (Map<String, Object>) JSON.parseObject(stat.getTrafficData(), Map.class);
+                if (trafficData != null) {
+                    long searchCount = getLongValue(trafficData, "searchCount");
+                    long viewCount = getLongValue(trafficData, "viewCount");
+                    long visitorCount = getLongValue(trafficData, "visitorCount");
+                    long newVisitorCount = getLongValue(trafficData, "newVisitorCount");
+                    long totalDuration = getLongValue(trafficData, "totalDuration");
+                    if (searchCount > 0 || viewCount > 0 || visitorCount > 0 || newVisitorCount > 0 || totalDuration > 0) {
+                        return true;
+                    }
+                }
+            }
+            
+            // 检查互动数据
+            if (stat.getInteractionData() != null && !stat.getInteractionData().isEmpty()) {
+                Map<String, Object> interactionData = (Map<String, Object>) JSON.parseObject(stat.getInteractionData(), Map.class);
+                if (interactionData != null) {
+                    long collectCount = getLongValue(interactionData, "collectCount");
+                    long shareCount = getLongValue(interactionData, "shareCount");
+                    long checkinCount = getLongValue(interactionData, "checkinCount");
+                    long consultCount = getLongValue(interactionData, "consultCount");
+                    long friendCount = getLongValue(interactionData, "friendCount");
+                    long followCount = getLongValue(interactionData, "followCount");
+                    long fansCount = getLongValue(interactionData, "fansCount");
+                    long postCount = getLongValue(interactionData, "postCount");
+                    long postLikeCount = getLongValue(interactionData, "postLikeCount");
+                    long postCommentCount = getLongValue(interactionData, "postCommentCount");
+                    long postRepostCount = getLongValue(interactionData, "postRepostCount");
+                    if (collectCount > 0 || shareCount > 0 || checkinCount > 0 || consultCount > 0 || 
+                        friendCount > 0 || followCount > 0 || fansCount > 0 || postCount > 0 || 
+                        postLikeCount > 0 || postCommentCount > 0 || postRepostCount > 0) {
+                        return true;
+                    }
+                }
+            }
+            
+            // 检查优惠券数据
+            if (stat.getCouponData() != null && !stat.getCouponData().isEmpty()) {
+                Map<String, Object> couponData = (Map<String, Object>) JSON.parseObject(stat.getCouponData(), Map.class);
+                if (couponData != null) {
+                    long giveToFriendCount = getLongValue(couponData, "giveToFriendCount");
+                    BigDecimal giveToFriendAmount = getBigDecimalValue(couponData, "giveToFriendAmount");
+                    long friendGiveCount = getLongValue(couponData, "friendGiveCount");
+                    BigDecimal friendGiveAmount = getBigDecimalValue(couponData, "friendGiveAmount");
+                    if (giveToFriendCount > 0 || giveToFriendAmount.compareTo(BigDecimal.ZERO) > 0 || 
+                        friendGiveCount > 0 || friendGiveAmount.compareTo(BigDecimal.ZERO) > 0) {
+                        return true;
+                    }
+                }
+            }
+            
+            // 检查代金券数据
+            if (stat.getVoucherData() != null && !stat.getVoucherData().isEmpty()) {
+                Map<String, Object> voucherData = (Map<String, Object>) JSON.parseObject(stat.getVoucherData(), Map.class);
+                if (voucherData != null) {
+                    long giveToFriendCount = getLongValue(voucherData, "giveToFriendCount");
+                    BigDecimal giveToFriendAmount = getBigDecimalValue(voucherData, "giveToFriendAmount");
+                    long friendGiveCount = getLongValue(voucherData, "friendGiveCount");
+                    BigDecimal friendGiveAmount = getBigDecimalValue(voucherData, "friendGiveAmount");
+                    if (giveToFriendCount > 0 || giveToFriendAmount.compareTo(BigDecimal.ZERO) > 0 || 
+                        friendGiveCount > 0 || friendGiveAmount.compareTo(BigDecimal.ZERO) > 0) {
+                        return true;
+                    }
+                }
+            }
+            
+            // 检查服务质量数据
+            if (stat.getServiceData() != null && !stat.getServiceData().isEmpty()) {
+                Map<String, Object> serviceData = (Map<String, Object>) JSON.parseObject(stat.getServiceData(), Map.class);
+                if (serviceData != null) {
+                    double storeScore = getBigDecimalValue(serviceData, "storeScore").doubleValue();
+                    long ratingCount = getLongValue(serviceData, "ratingCount");
+                    long appealCount = getLongValue(serviceData, "appealCount");
+                    if (storeScore > 0 || ratingCount > 0 || appealCount > 0) {
+                        return true;
+                    }
+                }
+            }
+            
+            // 检查价目表排名数据
+            if (stat.getPriceRankingData() != null && !stat.getPriceRankingData().isEmpty()) {
+                List<Map<String, Object>> priceRankingData = (List<Map<String, Object>>) (List<?>) JSON.parseArray(stat.getPriceRankingData());
+                if (priceRankingData != null && !priceRankingData.isEmpty()) {
+                    for (Map<String, Object> item : priceRankingData) {
+                        long viewCount = getLongValue(item, "viewCount");
+                        long visitorCount = getLongValue(item, "visitorCount");
+                        long shareCount = getLongValue(item, "shareCount");
+                        if (viewCount > 0 || visitorCount > 0 || shareCount > 0) {
+                            return true;
+                        }
+                    }
+                }
+            }
+            
+            return false;
+        } catch (Exception e) {
+            log.warn("判断统计数据有效性失败: {}", e.getMessage(), e);
+            // 如果解析失败,认为数据无效
+            return false;
+        }
+    }
+    
+    /**
      * 从Map中获取Long值
      */
     private Long getLongValue(Map<String, Object> map, String key) {
@@ -1698,6 +1878,318 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
             return BigDecimal.ZERO;
         }
     }
+    
+    // ==================== 从JSON/Map直接转换的方法 ====================
+    
+    /**
+     * 从Map转换为流量数据VO
+     */
+    private StoreOperationalStatisticsVo.TrafficData convertToTrafficDataVoFromMap(Map<String, Object> trafficDataMap) {
+        StoreOperationalStatisticsVo.TrafficData vo = new StoreOperationalStatisticsVo.TrafficData();
+        vo.setStoreSearchVolume(getLongValue(trafficDataMap, "searchCount"));
+        vo.setPageViews(getLongValue(trafficDataMap, "viewCount"));
+        vo.setVisitors(getLongValue(trafficDataMap, "visitorCount"));
+        vo.setNewVisitors(getLongValue(trafficDataMap, "newVisitorCount"));
+        // 访问时长从毫秒转换为秒
+        Long totalDuration = getLongValue(trafficDataMap, "totalDuration");
+        vo.setVisitDuration(totalDuration / 1000);
+        Long avgDuration = getLongValue(trafficDataMap, "avgDuration");
+        vo.setAvgVisitDuration(avgDuration / 1000);
+        return vo;
+    }
+    
+    /**
+     * 从JSON字符串转换为互动数据VO
+     */
+    @SuppressWarnings("unchecked")
+    private StoreOperationalStatisticsVo.InteractionData convertToInteractionDataVoFromJson(String interactionDataJson) {
+        try {
+            Map<String, Object> data = (Map<String, Object>) JSON.parseObject(interactionDataJson, Map.class);
+            if (data == null) return new StoreOperationalStatisticsVo.InteractionData();
+            
+            StoreOperationalStatisticsVo.InteractionData vo = new StoreOperationalStatisticsVo.InteractionData();
+            vo.setStoreCollectionCount(getLongValue(data, "collectCount"));
+            vo.setStoreShareCount(getLongValue(data, "shareCount"));
+            vo.setStoreCheckInCount(getLongValue(data, "checkinCount"));
+            vo.setConsultMerchantCount(getLongValue(data, "consultCount"));
+            vo.setFriendsCount(getLongValue(data, "friendCount"));
+            vo.setFollowCount(getLongValue(data, "followCount"));
+            vo.setFansCount(getLongValue(data, "fansCount"));
+            vo.setPostsPublishedCount(getLongValue(data, "postCount"));
+            vo.setPostLikesCount(getLongValue(data, "postLikeCount"));
+            vo.setPostCommentsCount(getLongValue(data, "postCommentCount"));
+            vo.setPostSharesCount(getLongValue(data, "postRepostCount"));
+            vo.setReportedCount(getLongValue(data, "reportCount"));
+            vo.setBlockedCount(getLongValue(data, "blockCount"));
+            return vo;
+        } catch (Exception e) {
+            log.warn("解析互动数据失败: {}", interactionDataJson, e);
+            return new StoreOperationalStatisticsVo.InteractionData();
+        }
+    }
+    
+    /**
+     * 从JSON字符串转换为优惠券数据VO
+     */
+    @SuppressWarnings("unchecked")
+    private StoreOperationalStatisticsVo.CouponData convertToCouponDataVoFromJson(String couponDataJson) {
+        try {
+            Map<String, Object> data = (Map<String, Object>) JSON.parseObject(couponDataJson, Map.class);
+            if (data == null) return new StoreOperationalStatisticsVo.CouponData();
+            
+            StoreOperationalStatisticsVo.CouponData vo = new StoreOperationalStatisticsVo.CouponData();
+            vo.setGiftToFriendsCount(getLongValue(data, "giveToFriendCount"));
+            vo.setGiftToFriendsAmount(getBigDecimalValue(data, "giveToFriendAmount"));
+            vo.setGiftToFriendsUsedCount(getLongValue(data, "giveToFriendUseCount"));
+            vo.setGiftToFriendsUsedAmount(getBigDecimalValue(data, "giveToFriendUseAmount"));
+            
+            // 使用金额占比
+            Object useAmountPercent = data.get("giveToFriendUseAmountPercent");
+            if (useAmountPercent != null) {
+                if (useAmountPercent instanceof Number) {
+                    vo.setGiftToFriendsUsedAmountRatio(BigDecimal.valueOf(((Number) useAmountPercent).doubleValue()));
+                } else {
+                    vo.setGiftToFriendsUsedAmountRatio(new BigDecimal(useAmountPercent.toString()));
+                }
+            } else {
+                vo.setGiftToFriendsUsedAmountRatio(BigDecimal.ZERO);
+            }
+            
+            vo.setFriendsGiftCount(getLongValue(data, "friendGiveCount"));
+            vo.setFriendsGiftAmount(getBigDecimalValue(data, "friendGiveAmount"));
+            vo.setFriendsGiftUsedCount(getLongValue(data, "friendGiveUseCount"));
+            vo.setFriendsGiftUsedAmount(getBigDecimalValue(data, "friendGiveUseAmount"));
+            
+            // 好友赠送使用金额占比
+            Object friendUseAmountPercent = data.get("friendGiveUseAmountPercent");
+            if (friendUseAmountPercent != null) {
+                if (friendUseAmountPercent instanceof Number) {
+                    vo.setFriendsGiftUsedAmountRatio(BigDecimal.valueOf(((Number) friendUseAmountPercent).doubleValue()));
+                } else {
+                    vo.setFriendsGiftUsedAmountRatio(new BigDecimal(friendUseAmountPercent.toString()));
+                }
+            } else {
+                vo.setFriendsGiftUsedAmountRatio(BigDecimal.ZERO);
+            }
+            
+            return vo;
+        } catch (Exception e) {
+            log.warn("解析优惠券数据失败: {}", couponDataJson, e);
+            return new StoreOperationalStatisticsVo.CouponData();
+        }
+    }
+    
+    /**
+     * 从JSON字符串转换为代金券数据VO
+     */
+    @SuppressWarnings("unchecked")
+    private StoreOperationalStatisticsVo.VoucherData convertToVoucherDataVoFromJson(String voucherDataJson) {
+        try {
+            Map<String, Object> data = (Map<String, Object>) JSON.parseObject(voucherDataJson, Map.class);
+            if (data == null) return new StoreOperationalStatisticsVo.VoucherData();
+            
+            StoreOperationalStatisticsVo.VoucherData vo = new StoreOperationalStatisticsVo.VoucherData();
+            vo.setGiftToFriendsCount(getLongValue(data, "giveToFriendCount"));
+            vo.setGiftToFriendsAmount(getBigDecimalValue(data, "giveToFriendAmount"));
+            vo.setGiftToFriendsUsedCount(getLongValue(data, "giveToFriendUseCount"));
+            vo.setGiftToFriendsUsedAmount(getBigDecimalValue(data, "giveToFriendUseAmount"));
+            
+            // 使用金额占比
+            Object useAmountPercent = data.get("giveToFriendUseAmountPercent");
+            if (useAmountPercent != null) {
+                if (useAmountPercent instanceof Number) {
+                    vo.setGiftToFriendsUsedAmountRatio(BigDecimal.valueOf(((Number) useAmountPercent).doubleValue()));
+                } else {
+                    vo.setGiftToFriendsUsedAmountRatio(new BigDecimal(useAmountPercent.toString()));
+                }
+            } else {
+                vo.setGiftToFriendsUsedAmountRatio(BigDecimal.ZERO);
+            }
+            
+            vo.setFriendsGiftCount(getLongValue(data, "friendGiveCount"));
+            vo.setFriendsGiftAmount(getBigDecimalValue(data, "friendGiveAmount"));
+            vo.setFriendsGiftUsedCount(getLongValue(data, "friendGiveUseCount"));
+            vo.setFriendsGiftUsedAmount(getBigDecimalValue(data, "friendGiveUseAmount"));
+            
+            // 好友赠送使用金额占比
+            Object friendUseAmountPercent = data.get("friendGiveUseAmountPercent");
+            if (friendUseAmountPercent != null) {
+                if (friendUseAmountPercent instanceof Number) {
+                    vo.setFriendsGiftUsedAmountRatio(BigDecimal.valueOf(((Number) friendUseAmountPercent).doubleValue()));
+                } else {
+                    vo.setFriendsGiftUsedAmountRatio(new BigDecimal(friendUseAmountPercent.toString()));
+                }
+            } else {
+                vo.setFriendsGiftUsedAmountRatio(BigDecimal.ZERO);
+            }
+            
+            return vo;
+        } catch (Exception e) {
+            log.warn("解析代金券数据失败: {}", voucherDataJson, e);
+            return new StoreOperationalStatisticsVo.VoucherData();
+        }
+    }
+    
+    /**
+     * 从JSON字符串转换为服务质量数据VO
+     */
+    @SuppressWarnings("unchecked")
+    private StoreOperationalStatisticsVo.ServiceQualityData convertToServiceQualityDataVoFromJson(String serviceDataJson) {
+        try {
+            Map<String, Object> data = (Map<String, Object>) JSON.parseObject(serviceDataJson, Map.class);
+            if (data == null) return new StoreOperationalStatisticsVo.ServiceQualityData();
+            
+            StoreOperationalStatisticsVo.ServiceQualityData vo = new StoreOperationalStatisticsVo.ServiceQualityData();
+            
+            // 评分字段
+            Object storeScore = data.get("storeScore");
+            if (storeScore != null) {
+                if (storeScore instanceof Number) {
+                    vo.setStoreRating(BigDecimal.valueOf(((Number) storeScore).doubleValue()).setScale(1, RoundingMode.HALF_UP));
+                } else {
+                    vo.setStoreRating(new BigDecimal(storeScore.toString()).setScale(1, RoundingMode.HALF_UP));
+                }
+            } else {
+                vo.setStoreRating(BigDecimal.ZERO);
+            }
+            
+            Object scoreOne = data.get("scoreOne");
+            if (scoreOne != null) {
+                if (scoreOne instanceof Number) {
+                    vo.setScoreOne(BigDecimal.valueOf(((Number) scoreOne).doubleValue()).setScale(1, RoundingMode.HALF_UP));
+                } else {
+                    vo.setScoreOne(new BigDecimal(scoreOne.toString()).setScale(1, RoundingMode.HALF_UP));
+                }
+            } else {
+                vo.setScoreOne(BigDecimal.ZERO);
+            }
+            
+            Object scoreTwo = data.get("scoreTwo");
+            if (scoreTwo != null) {
+                if (scoreTwo instanceof Number) {
+                    vo.setScoreTwo(BigDecimal.valueOf(((Number) scoreTwo).doubleValue()).setScale(1, RoundingMode.HALF_UP));
+                } else {
+                    vo.setScoreTwo(new BigDecimal(scoreTwo.toString()).setScale(1, RoundingMode.HALF_UP));
+                }
+            } else {
+                vo.setScoreTwo(BigDecimal.ZERO);
+            }
+            
+            Object scoreThree = data.get("scoreThree");
+            if (scoreThree != null) {
+                if (scoreThree instanceof Number) {
+                    vo.setScoreThree(BigDecimal.valueOf(((Number) scoreThree).doubleValue()).setScale(1, RoundingMode.HALF_UP));
+                } else {
+                    vo.setScoreThree(new BigDecimal(scoreThree.toString()).setScale(1, RoundingMode.HALF_UP));
+                }
+            } else {
+                vo.setScoreThree(BigDecimal.ZERO);
+            }
+            
+            vo.setTotalReviews(getLongValue(data, "ratingCount"));
+            vo.setPositiveReviews(getLongValue(data, "goodRatingCount"));
+            vo.setNeutralReviews(getLongValue(data, "midRatingCount"));
+            vo.setNegativeReviews(getLongValue(data, "badRatingCount"));
+            
+            // 差评占比
+            Object badRatingPercent = data.get("badRatingPercent");
+            if (badRatingPercent != null) {
+                if (badRatingPercent instanceof Number) {
+                    vo.setNegativeReviewRatio(BigDecimal.valueOf(((Number) badRatingPercent).doubleValue()).setScale(2, RoundingMode.HALF_UP));
+                } else {
+                    vo.setNegativeReviewRatio(new BigDecimal(badRatingPercent.toString()).setScale(2, RoundingMode.HALF_UP));
+                }
+            } else {
+                vo.setNegativeReviewRatio(BigDecimal.ZERO);
+            }
+            
+            vo.setNegativeReviewAppealsCount(getLongValue(data, "appealCount"));
+            vo.setNegativeReviewAppealsSuccessCount(getLongValue(data, "appealSuccessCount"));
+            
+            // 申诉成功占比
+            Object appealSuccessPercent = data.get("appealSuccessPercent");
+            if (appealSuccessPercent != null) {
+                if (appealSuccessPercent instanceof Number) {
+                    vo.setNegativeReviewAppealsSuccessRatio(BigDecimal.valueOf(((Number) appealSuccessPercent).doubleValue()).setScale(2, RoundingMode.HALF_UP));
+                } else {
+                    vo.setNegativeReviewAppealsSuccessRatio(new BigDecimal(appealSuccessPercent.toString()).setScale(2, RoundingMode.HALF_UP));
+                }
+            } else {
+                vo.setNegativeReviewAppealsSuccessRatio(BigDecimal.ZERO);
+            }
+            
+            return vo;
+        } catch (Exception e) {
+            log.warn("解析服务质量数据失败: {}", serviceDataJson, e);
+            return new StoreOperationalStatisticsVo.ServiceQualityData();
+        }
+    }
+    
+    /**
+     * 从JSON字符串转换为价目表排名数据VO
+     */
+    @SuppressWarnings("unchecked")
+    private List<StoreOperationalStatisticsVo.PriceListRanking> convertToPriceListRankingVoFromJson(String priceRankingDataJson) {
+        List<StoreOperationalStatisticsVo.PriceListRanking> result = new ArrayList<>();
+        
+        try {
+            List<Map<String, Object>> dataList = (List<Map<String, Object>>) (List<?>) JSON.parseArray(priceRankingDataJson);
+            if (dataList == null || dataList.isEmpty()) {
+                return result;
+            }
+            
+            // 批量查询价目表名称
+            List<Integer> priceIds = new ArrayList<>();
+            for (Map<String, Object> item : dataList) {
+                Integer priceId = getIntegerValue(item, "priceId");
+                if (priceId != null) {
+                    priceIds.add(priceId);
+                }
+            }
+            
+            Map<Integer, String> priceNameMap = new HashMap<>();
+            if (!priceIds.isEmpty()) {
+                LambdaQueryWrapper<StorePrice> priceWrapper = new LambdaQueryWrapper<>();
+                priceWrapper.in(StorePrice::getId, priceIds)
+                            .eq(StorePrice::getDeleteFlag, 0);
+                List<StorePrice> prices = storePriceMapper.selectList(priceWrapper);
+                for (StorePrice price : prices) {
+                    if (price.getId() != null && price.getName() != null) {
+                        priceNameMap.put(price.getId(), price.getName());
+                    }
+                }
+            }
+            
+            // 转换为VO列表
+            for (Map<String, Object> item : dataList) {
+                StoreOperationalStatisticsVo.PriceListRanking ranking = new StoreOperationalStatisticsVo.PriceListRanking();
+                Integer priceId = getIntegerValue(item, "priceId");
+                ranking.setPriceId(priceId);
+                ranking.setPageViews(getLongValue(item, "viewCount"));
+                ranking.setVisitors(getLongValue(item, "visitorCount"));
+                ranking.setShares(getLongValue(item, "shareCount"));
+                
+                if (priceId != null) {
+                    ranking.setPriceListItemName(priceNameMap.get(priceId));
+                }
+                
+                result.add(ranking);
+            }
+            
+            // 按浏览量降序排序
+            result.sort((a, b) -> Long.compare(b.getPageViews(), a.getPageViews()));
+            
+            // 设置排名
+            for (int i = 0; i < result.size(); i++) {
+                result.get(i).setRank(i + 1);
+            }
+            
+        } catch (Exception e) {
+            log.warn("解析价目表排名数据失败: {}", priceRankingDataJson, e);
+        }
+        
+        return result;
+    }
 
     @Override
     public String generateStatisticsComparisonPdf(Integer storeId, String currentStartTime, String currentEndTime,