浏览代码

维护商户头像,维护入参时间异常问题

lutong 2 月之前
父节点
当前提交
c54dc1baf5

+ 3 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/StoreRenovationRequirementDto.java

@@ -104,6 +104,9 @@ public class StoreRenovationRequirementDto {
     @ApiModelProperty(value = "商铺简介")
     private String storeBlurb;
 
+    @ApiModelProperty(value = "商铺头像")
+    private String storeAvatar;
+
     @ApiModelProperty(value = "是否已与发布商铺发生沟通(true:已沟通, false:未沟通)")
     private Boolean hasCommunicated;
 }

+ 3 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/StoreOperationalStatisticsVo.java

@@ -254,6 +254,9 @@ public class StoreOperationalStatisticsVo implements Serializable {
         @ApiModelProperty("排名")
         private Integer rank;
 
+        @ApiModelProperty("价目表ID")
+        private Integer priceId;
+
         @ApiModelProperty("价目表名称")
         private String priceListItemName;
 

+ 9 - 3
alien-store/src/main/java/shop/alien/store/controller/StoreOperationalStatisticsController.java

@@ -30,7 +30,7 @@ public class StoreOperationalStatisticsController {
 
     private final StoreOperationalStatisticsService storeOperationalStatisticsService;
 
-    @ApiOperation("获取商家经营统计数据")
+    @ApiOperation("获取商家经营统计数据(符合埋点统计数据JSON格式)")
     @ApiOperationSupport(order = 1)
     @ApiImplicitParams({
             @ApiImplicitParam(
@@ -61,8 +61,14 @@ public class StoreOperationalStatisticsController {
             @RequestParam("startTime") String startTime,
             @RequestParam("endTime") String endTime) {
         log.info("StoreOperationalStatisticsController.getStatistics - storeId={}, startTime={}, endTime={}", storeId, startTime, endTime);
-        StoreOperationalStatisticsVo statistics = storeOperationalStatisticsService.getStatistics(storeId, startTime, endTime);
-        return R.data(statistics);
+        try {
+            StoreOperationalStatisticsVo statistics = storeOperationalStatisticsService.getStatisticsInTrackFormat(storeId, startTime, endTime);
+            return R.data(statistics);
+        } catch (Exception e) {
+            log.error("获取商家经营统计数据失败 - storeId={}, startTime={}, endTime={}, error={}", 
+                    storeId, startTime, endTime, e.getMessage(), e);
+            return R.fail("获取统计数据失败: " + e.getMessage());
+        }
     }
 
     @ApiOperation("获取商家经营统计数据对比")

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

@@ -61,4 +61,14 @@ public interface StoreOperationalStatisticsService {
      * @return 是否成功
      */
     boolean batchDeleteHistory(List<Integer> ids);
+
+    /**
+     * 获取商家经营统计数据(符合埋点统计数据JSON格式)
+     *
+     * @param storeId   店铺ID
+     * @param startTime 开始时间(格式:yyyy-MM-dd)
+     * @param endTime   结束时间(格式:yyyy-MM-dd)
+     * @return 经营统计数据
+     */
+    StoreOperationalStatisticsVo getStatisticsInTrackFormat(Integer storeId, String startTime, String endTime);
 }

+ 765 - 60
alien-store/src/main/java/shop/alien/store/service/impl/StoreOperationalStatisticsServiceImpl.java

@@ -48,55 +48,116 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
     private final StorePriceMapper storePriceMapper;
     private final StoreUserMapper storeUserMapper;
     private final StoreOperationalStatisticsHistoryMapper statisticsHistoryMapper;
+    private final StoreTrackStatisticsMapper storeTrackStatisticsMapper;
 
     private static final String DATE_FORMAT = "yyyy-MM-dd";
+    private static final String STAT_TYPE_DAILY = "DAILY";
 
     @Override
     public StoreOperationalStatisticsVo getStatistics(Integer storeId, String startTime, String endTime) {
         log.info("StoreOperationalStatisticsServiceImpl.getStatistics - storeId={}, startTime={}, endTime={}", storeId, startTime, endTime);
+        return calculateStatistics(storeId, startTime, endTime);
+    }
 
-        StoreOperationalStatisticsVo statistics = new StoreOperationalStatisticsVo();
-
+    /**
+     * 计算统计数据(从store_track_statistics表查询并累加)
+     */
+    private StoreOperationalStatisticsVo calculateStatistics(Integer storeId, String startTime, String endTime) {
         try {
             // 解析时间范围
             SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
             Date startDate = sdf.parse(startTime);
             Date endDate = sdf.parse(endTime);
-            // 设置为当天的结束时间
-            Calendar endCal = Calendar.getInstance();
-            endCal.setTime(endDate);
-            endCal.set(Calendar.HOUR_OF_DAY, 23);
-            endCal.set(Calendar.MINUTE, 59);
-            endCal.set(Calendar.SECOND, 59);
-            endDate = endCal.getTime();
-
-            // 1. 流量数据统计
-            statistics.setTrafficData(getTrafficData(storeId, startDate, endDate));
-
-            // 2. 互动数据统计
-            statistics.setInteractionData(getInteractionData(storeId, startDate, endDate));
-
-            // 3. 优惠券数据统计
-            statistics.setCouponData(getCouponData(storeId, startDate, endDate));
-
-            // 4. 代金券数据统计(与优惠券类似,根据实际业务区分)
-            statistics.setVoucherData(getVoucherData(storeId, startDate, endDate));
-
-            // 5. 服务质量数据统计
-            statistics.setServiceQualityData(getServiceQualityData(storeId, startDate, endDate));
-
-            // 6. 价目表排名统计
-            statistics.setPriceListRanking(getPriceListRanking(storeId, startDate, endDate));
-
-            // 保存统计数据到历史表
-            saveStatisticsHistory(storeId, startTime, endTime, statistics);
-
+            
+            // 查询指定时间范围内的日统计数据
+            LambdaQueryWrapper<StoreTrackStatistics> wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(StoreTrackStatistics::getStoreId, storeId)
+                    .eq(StoreTrackStatistics::getStatType, STAT_TYPE_DAILY)
+                    .ge(StoreTrackStatistics::getStatDate, startDate)
+                    .le(StoreTrackStatistics::getStatDate, endDate);
+            
+            List<StoreTrackStatistics> statisticsList = storeTrackStatisticsMapper.selectList(wrapper);
+            
+            if (statisticsList == null || statisticsList.isEmpty()) {
+                log.warn("未查询到统计数据 - storeId={}, startTime={}, endTime={}", storeId, startTime, endTime);
+                return new StoreOperationalStatisticsVo();
+            }
+            
+            // 累加所有统计数据
+            return aggregateStatistics(statisticsList);
+            
         } catch (ParseException e) {
-            log.error("StoreOperationalStatisticsServiceImpl.getStatistics - 时间解析错误", e);
+            log.error("StoreOperationalStatisticsServiceImpl.calculateStatistics - 时间解析错误", e);
             throw new RuntimeException("时间格式错误: " + e.getMessage());
+        } catch (Exception e) {
+            log.error("计算统计数据失败 - storeId={}, startTime={}, endTime={}, error={}", 
+                    storeId, startTime, endTime, e.getMessage(), e);
+            throw new RuntimeException("计算统计数据失败: " + e.getMessage());
         }
-
-        return statistics;
+    }
+    
+    /**
+     * 累加统计数据
+     */
+    private StoreOperationalStatisticsVo aggregateStatistics(List<StoreTrackStatistics> statisticsList) {
+        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;
+        
+        // 遍历所有统计数据并累加
+        for (StoreTrackStatistics stat : statisticsList) {
+            // 累加流量数据
+            if (stat.getTrafficData() != null && !stat.getTrafficData().isEmpty()) {
+                aggregateTrafficData(stat.getTrafficData(), trafficAccumulator);
+                trafficCount++;
+            }
+            
+            // 累加互动数据
+            if (stat.getInteractionData() != null && !stat.getInteractionData().isEmpty()) {
+                aggregateInteractionData(stat.getInteractionData(), interactionAccumulator);
+            }
+            
+            // 累加优惠券数据
+            if (stat.getCouponData() != null && !stat.getCouponData().isEmpty()) {
+                aggregateCouponData(stat.getCouponData(), couponAccumulator);
+            }
+            
+            // 累加代金券数据
+            if (stat.getVoucherData() != null && !stat.getVoucherData().isEmpty()) {
+                aggregateVoucherData(stat.getVoucherData(), voucherAccumulator);
+            }
+            
+            // 累加服务质量数据
+            if (stat.getServiceData() != null && !stat.getServiceData().isEmpty()) {
+                aggregateServiceData(stat.getServiceData(), serviceAccumulator);
+                serviceCount++;
+            }
+            
+            // 累加价目表排名数据
+            if (stat.getPriceRankingData() != null && !stat.getPriceRankingData().isEmpty()) {
+                aggregatePriceRankingData(stat.getPriceRankingData(), priceRankingAccumulator);
+            }
+        }
+        
+        // 转换为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));
+        
+        return result;
     }
 
     @Override
@@ -111,9 +172,9 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
         comparison.setPreviousStartTime(previousStartTime);
         comparison.setPreviousEndTime(previousEndTime);
 
-        // 获取当期和上期的统计数据(getStatistics方法内部已经保存了历史记录
-        StoreOperationalStatisticsVo currentStatistics = getStatistics(storeId, currentStartTime, currentEndTime);
-        StoreOperationalStatisticsVo previousStatistics = getStatistics(storeId, previousStartTime, previousEndTime);
+        // 获取当期和上期的统计数据(不保存历史,对比接口不需要保存
+        StoreOperationalStatisticsVo currentStatistics = calculateStatistics(storeId, currentStartTime, currentEndTime);
+        StoreOperationalStatisticsVo previousStatistics = calculateStatistics(storeId, previousStartTime, previousEndTime);
 
         // 构建对比数据
         comparison.setTrafficData(buildTrafficDataComparison(currentStatistics.getTrafficData(), previousStatistics.getTrafficData()));
@@ -125,32 +186,142 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
         return comparison;
     }
 
+
     /**
-     * 保存统计数据到历史表
+     * 将StoreOperationalStatisticsVo转换为符合埋点统计数据JSON格式
      */
-    private void saveStatisticsHistory(Integer storeId, String startTime, String endTime, StoreOperationalStatisticsVo statistics) {
-        try {
-            SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
-            Date startDate = sdf.parse(startTime);
-            Date endDate = sdf.parse(endTime);
-
-            StoreOperationalStatisticsHistory history = new StoreOperationalStatisticsHistory();
-            history.setStoreId(storeId);
-            history.setStartTime(startDate);
-            history.setEndTime(endDate);
-            history.setQueryTime(new Date());
-            
-            // 将统计数据序列化为JSON字符串
-            String statisticsJson = JSON.toJSONString(statistics);
-            history.setStatisticsData(statisticsJson);
-
-            statisticsHistoryMapper.insert(history);
-            log.info("保存统计数据到历史表成功 - storeId={}, startTime={}, endTime={}", storeId, startTime, endTime);
-        } catch (Exception e) {
-            log.error("保存统计数据到历史表失败 - storeId={}, startTime={}, endTime={}, error={}", 
-                    storeId, startTime, endTime, e.getMessage(), e);
-            // 保存失败不影响主流程,只记录日志
+    private Map<String, Object> convertToTrackStatisticsFormat(StoreOperationalStatisticsVo statistics) {
+        Map<String, Object> result = new HashMap<>();
+        
+        // 1. 转换流量数据
+        if (statistics.getTrafficData() != null) {
+            StoreOperationalStatisticsVo.TrafficData traffic = statistics.getTrafficData();
+            Map<String, Object> trafficData = new HashMap<>();
+            trafficData.put("searchCount", traffic.getStoreSearchVolume() != null ? traffic.getStoreSearchVolume() : 0L);
+            trafficData.put("viewCount", traffic.getPageViews() != null ? traffic.getPageViews() : 0L);
+            trafficData.put("visitorCount", traffic.getVisitors() != null ? traffic.getVisitors() : 0L);
+            trafficData.put("newVisitorCount", traffic.getNewVisitors() != null ? traffic.getNewVisitors() : 0L);
+            // 访问时长从秒转换为毫秒
+            trafficData.put("totalDuration", traffic.getVisitDuration() != null ? traffic.getVisitDuration() * 1000 : 0L);
+            trafficData.put("avgDuration", traffic.getAvgVisitDuration() != null ? traffic.getAvgVisitDuration() * 1000 : 0L);
+            result.put("trafficData", trafficData);
+        }
+        
+        // 2. 转换互动数据
+        if (statistics.getInteractionData() != null) {
+            StoreOperationalStatisticsVo.InteractionData interaction = statistics.getInteractionData();
+            Map<String, Object> interactionData = new HashMap<>();
+            interactionData.put("collectCount", interaction.getStoreCollectionCount() != null ? interaction.getStoreCollectionCount() : 0L);
+            interactionData.put("shareCount", interaction.getStoreShareCount() != null ? interaction.getStoreShareCount() : 0L);
+            interactionData.put("checkinCount", interaction.getStoreCheckInCount() != null ? interaction.getStoreCheckInCount() : 0L);
+            interactionData.put("consultCount", interaction.getConsultMerchantCount() != null ? interaction.getConsultMerchantCount() : 0L);
+            interactionData.put("friendCount", interaction.getFriendsCount() != null ? interaction.getFriendsCount() : 0L);
+            interactionData.put("followCount", interaction.getFollowCount() != null ? interaction.getFollowCount() : 0L);
+            interactionData.put("fansCount", interaction.getFansCount() != null ? interaction.getFansCount() : 0L);
+            interactionData.put("postCount", interaction.getPostsPublishedCount() != null ? interaction.getPostsPublishedCount() : 0L);
+            interactionData.put("postLikeCount", interaction.getPostLikesCount() != null ? interaction.getPostLikesCount() : 0L);
+            interactionData.put("postCommentCount", interaction.getPostCommentsCount() != null ? interaction.getPostCommentsCount() : 0L);
+            interactionData.put("postRepostCount", interaction.getPostSharesCount() != null ? interaction.getPostSharesCount() : 0L);
+            interactionData.put("reportCount", interaction.getReportedCount() != null ? interaction.getReportedCount() : 0L);
+            interactionData.put("blockCount", interaction.getBlockedCount() != null ? interaction.getBlockedCount() : 0L);
+            result.put("interactionData", interactionData);
+        }
+        
+        // 3. 转换优惠券数据
+        if (statistics.getCouponData() != null) {
+            StoreOperationalStatisticsVo.CouponData coupon = statistics.getCouponData();
+            Map<String, Object> couponData = new HashMap<>();
+            couponData.put("giveToFriendCount", coupon.getGiftToFriendsCount() != null ? coupon.getGiftToFriendsCount() : 0L);
+            couponData.put("giveToFriendAmount", coupon.getGiftToFriendsAmount() != null ? coupon.getGiftToFriendsAmount() : BigDecimal.ZERO);
+            couponData.put("giveToFriendUseCount", coupon.getGiftToFriendsUsedCount() != null ? coupon.getGiftToFriendsUsedCount() : 0L);
+            couponData.put("giveToFriendUseAmount", coupon.getGiftToFriendsUsedAmount() != null ? coupon.getGiftToFriendsUsedAmount() : BigDecimal.ZERO);
+            // 百分比转换:BigDecimal -> Double
+            if (coupon.getGiftToFriendsUsedAmountRatio() != null) {
+                couponData.put("giveToFriendUseAmountPercent", coupon.getGiftToFriendsUsedAmountRatio().doubleValue());
+            } else {
+                couponData.put("giveToFriendUseAmountPercent", 0.0);
+            }
+            couponData.put("friendGiveCount", coupon.getFriendsGiftCount() != null ? coupon.getFriendsGiftCount() : 0L);
+            couponData.put("friendGiveAmount", coupon.getFriendsGiftAmount() != null ? coupon.getFriendsGiftAmount() : BigDecimal.ZERO);
+            couponData.put("friendGiveUseCount", coupon.getFriendsGiftUsedCount() != null ? coupon.getFriendsGiftUsedCount() : 0L);
+            couponData.put("friendGiveUseAmount", coupon.getFriendsGiftUsedAmount() != null ? coupon.getFriendsGiftUsedAmount() : BigDecimal.ZERO);
+            if (coupon.getFriendsGiftUsedAmountRatio() != null) {
+                couponData.put("friendGiveUseAmountPercent", coupon.getFriendsGiftUsedAmountRatio().doubleValue());
+            } else {
+                couponData.put("friendGiveUseAmountPercent", 0.0);
+            }
+            result.put("couponData", couponData);
         }
+        
+        // 4. 转换代金券数据
+        if (statistics.getVoucherData() != null) {
+            StoreOperationalStatisticsVo.VoucherData voucher = statistics.getVoucherData();
+            Map<String, Object> voucherData = new HashMap<>();
+            voucherData.put("giveToFriendCount", voucher.getGiftToFriendsCount() != null ? voucher.getGiftToFriendsCount() : 0L);
+            voucherData.put("giveToFriendAmount", voucher.getGiftToFriendsAmount() != null ? voucher.getGiftToFriendsAmount() : BigDecimal.ZERO);
+            voucherData.put("giveToFriendUseCount", voucher.getGiftToFriendsUsedCount() != null ? voucher.getGiftToFriendsUsedCount() : 0L);
+            voucherData.put("giveToFriendUseAmount", voucher.getGiftToFriendsUsedAmount() != null ? voucher.getGiftToFriendsUsedAmount() : BigDecimal.ZERO);
+            if (voucher.getGiftToFriendsUsedAmountRatio() != null) {
+                voucherData.put("giveToFriendUseAmountPercent", voucher.getGiftToFriendsUsedAmountRatio().doubleValue());
+            } else {
+                voucherData.put("giveToFriendUseAmountPercent", 0.0);
+            }
+            voucherData.put("friendGiveCount", voucher.getFriendsGiftCount() != null ? voucher.getFriendsGiftCount() : 0L);
+            voucherData.put("friendGiveAmount", voucher.getFriendsGiftAmount() != null ? voucher.getFriendsGiftAmount() : BigDecimal.ZERO);
+            voucherData.put("friendGiveUseCount", voucher.getFriendsGiftUsedCount() != null ? voucher.getFriendsGiftUsedCount() : 0L);
+            voucherData.put("friendGiveUseAmount", voucher.getFriendsGiftUsedAmount() != null ? voucher.getFriendsGiftUsedAmount() : BigDecimal.ZERO);
+            if (voucher.getFriendsGiftUsedAmountRatio() != null) {
+                voucherData.put("friendGiveUseAmountPercent", voucher.getFriendsGiftUsedAmountRatio().doubleValue());
+            } else {
+                voucherData.put("friendGiveUseAmountPercent", 0.0);
+            }
+            result.put("voucherData", voucherData);
+        }
+        
+        // 5. 转换服务质量数据
+        if (statistics.getServiceQualityData() != null) {
+            StoreOperationalStatisticsVo.ServiceQualityData service = statistics.getServiceQualityData();
+            Map<String, Object> serviceData = new HashMap<>();
+            serviceData.put("storeScore", service.getStoreRating() != null ? service.getStoreRating().doubleValue() : 0.0);
+            serviceData.put("tasteScore", service.getTasteRating() != null ? service.getTasteRating().doubleValue() : 0.0);
+            serviceData.put("environmentScore", service.getEnvironmentRating() != null ? service.getEnvironmentRating().doubleValue() : 0.0);
+            serviceData.put("serviceScore", service.getServiceRating() != null ? service.getServiceRating().doubleValue() : 0.0);
+            serviceData.put("ratingCount", service.getTotalReviews() != null ? service.getTotalReviews() : 0L);
+            serviceData.put("goodRatingCount", service.getPositiveReviews() != null ? service.getPositiveReviews() : 0L);
+            serviceData.put("midRatingCount", service.getNeutralReviews() != null ? service.getNeutralReviews() : 0L);
+            serviceData.put("badRatingCount", service.getNegativeReviews() != null ? service.getNegativeReviews() : 0L);
+            if (service.getNegativeReviewRatio() != null) {
+                serviceData.put("badRatingPercent", service.getNegativeReviewRatio().doubleValue());
+            } else {
+                serviceData.put("badRatingPercent", 0.0);
+            }
+            serviceData.put("appealCount", service.getNegativeReviewAppealsCount() != null ? service.getNegativeReviewAppealsCount() : 0L);
+            serviceData.put("appealSuccessCount", service.getNegativeReviewAppealsSuccessCount() != null ? service.getNegativeReviewAppealsSuccessCount() : 0L);
+            if (service.getNegativeReviewAppealsSuccessRatio() != null) {
+                serviceData.put("appealSuccessPercent", service.getNegativeReviewAppealsSuccessRatio().doubleValue());
+            } else {
+                serviceData.put("appealSuccessPercent", 0.0);
+            }
+            result.put("serviceData", serviceData);
+        }
+        
+        // 6. 转换价目表排名数据
+        if (statistics.getPriceListRanking() != null && !statistics.getPriceListRanking().isEmpty()) {
+            List<Map<String, Object>> priceRankingData = new ArrayList<>();
+            for (StoreOperationalStatisticsVo.PriceListRanking ranking : statistics.getPriceListRanking()) {
+                Map<String, Object> priceItem = new HashMap<>();
+                priceItem.put("priceId", ranking.getPriceId() != null ? ranking.getPriceId() : 0);
+                priceItem.put("viewCount", ranking.getPageViews() != null ? ranking.getPageViews().intValue() : 0);
+                priceItem.put("visitorCount", ranking.getVisitors() != null ? ranking.getVisitors().intValue() : 0);
+                priceItem.put("shareCount", ranking.getShares() != null ? ranking.getShares().intValue() : 0);
+                priceRankingData.add(priceItem);
+            }
+            result.put("priceRankingData", priceRankingData);
+        } else {
+            result.put("priceRankingData", new ArrayList<>());
+        }
+        
+        return result;
     }
 
     /**
@@ -439,6 +610,7 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
         for (StorePrice price : prices) {
             StoreOperationalStatisticsVo.PriceListRanking ranking = new StoreOperationalStatisticsVo.PriceListRanking();
             ranking.setRank(rank++);
+            ranking.setPriceId(price.getId());
             ranking.setPriceListItemName(price.getName());
             // TODO: 统计该价目表的浏览量、访客数、分享数
             ranking.setPageViews(0L);
@@ -456,6 +628,13 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
     private StoreOperationalStatisticsComparisonVo.TrafficDataComparison buildTrafficDataComparison(
             StoreOperationalStatisticsVo.TrafficData current, StoreOperationalStatisticsVo.TrafficData previous) {
         StoreOperationalStatisticsComparisonVo.TrafficDataComparison comparison = new StoreOperationalStatisticsComparisonVo.TrafficDataComparison();
+        // 如果 previous 为 null,创建空对象避免 NullPointerException
+        if (previous == null) {
+            previous = new StoreOperationalStatisticsVo.TrafficData();
+        }
+        if (current == null) {
+            current = new StoreOperationalStatisticsVo.TrafficData();
+        }
         comparison.setStoreSearchVolume(buildComparisonData(current.getStoreSearchVolume(), previous.getStoreSearchVolume()));
         comparison.setPageViews(buildComparisonData(current.getPageViews(), previous.getPageViews()));
         comparison.setVisitors(buildComparisonData(current.getVisitors(), previous.getVisitors()));
@@ -471,6 +650,13 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
     private StoreOperationalStatisticsComparisonVo.InteractionDataComparison buildInteractionDataComparison(
             StoreOperationalStatisticsVo.InteractionData current, StoreOperationalStatisticsVo.InteractionData previous) {
         StoreOperationalStatisticsComparisonVo.InteractionDataComparison comparison = new StoreOperationalStatisticsComparisonVo.InteractionDataComparison();
+        // 如果 previous 为 null,创建空对象避免 NullPointerException
+        if (previous == null) {
+            previous = new StoreOperationalStatisticsVo.InteractionData();
+        }
+        if (current == null) {
+            current = new StoreOperationalStatisticsVo.InteractionData();
+        }
         comparison.setStoreCollectionCount(buildComparisonData(current.getStoreCollectionCount(), previous.getStoreCollectionCount()));
         comparison.setStoreShareCount(buildComparisonData(current.getStoreShareCount(), previous.getStoreShareCount()));
         comparison.setStoreCheckInCount(buildComparisonData(current.getStoreCheckInCount(), previous.getStoreCheckInCount()));
@@ -493,6 +679,13 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
     private StoreOperationalStatisticsComparisonVo.CouponDataComparison buildCouponDataComparison(
             StoreOperationalStatisticsVo.CouponData current, StoreOperationalStatisticsVo.CouponData previous) {
         StoreOperationalStatisticsComparisonVo.CouponDataComparison comparison = new StoreOperationalStatisticsComparisonVo.CouponDataComparison();
+        // 如果 previous 为 null,创建空对象避免 NullPointerException
+        if (previous == null) {
+            previous = new StoreOperationalStatisticsVo.CouponData();
+        }
+        if (current == null) {
+            current = new StoreOperationalStatisticsVo.CouponData();
+        }
         comparison.setGiftToFriendsCount(buildComparisonData(current.getGiftToFriendsCount(), previous.getGiftToFriendsCount()));
         comparison.setGiftToFriendsAmount(buildComparisonData(current.getGiftToFriendsAmount(), previous.getGiftToFriendsAmount()));
         comparison.setGiftToFriendsUsedCount(buildComparisonData(current.getGiftToFriendsUsedCount(), previous.getGiftToFriendsUsedCount()));
@@ -512,6 +705,13 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
     private StoreOperationalStatisticsComparisonVo.VoucherDataComparison buildVoucherDataComparison(
             StoreOperationalStatisticsVo.VoucherData current, StoreOperationalStatisticsVo.VoucherData previous) {
         StoreOperationalStatisticsComparisonVo.VoucherDataComparison comparison = new StoreOperationalStatisticsComparisonVo.VoucherDataComparison();
+        // 如果 previous 为 null,创建空对象避免 NullPointerException
+        if (previous == null) {
+            previous = new StoreOperationalStatisticsVo.VoucherData();
+        }
+        if (current == null) {
+            current = new StoreOperationalStatisticsVo.VoucherData();
+        }
         comparison.setGiftToFriendsCount(buildComparisonData(current.getGiftToFriendsCount(), previous.getGiftToFriendsCount()));
         comparison.setGiftToFriendsAmount(buildComparisonData(current.getGiftToFriendsAmount(), previous.getGiftToFriendsAmount()));
         comparison.setGiftToFriendsUsedCount(buildComparisonData(current.getGiftToFriendsUsedCount(), previous.getGiftToFriendsUsedCount()));
@@ -531,6 +731,13 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
     private StoreOperationalStatisticsComparisonVo.ServiceQualityDataComparison buildServiceQualityDataComparison(
             StoreOperationalStatisticsVo.ServiceQualityData current, StoreOperationalStatisticsVo.ServiceQualityData previous) {
         StoreOperationalStatisticsComparisonVo.ServiceQualityDataComparison comparison = new StoreOperationalStatisticsComparisonVo.ServiceQualityDataComparison();
+        // 如果 previous 为 null,创建空对象避免 NullPointerException
+        if (previous == null) {
+            previous = new StoreOperationalStatisticsVo.ServiceQualityData();
+        }
+        if (current == null) {
+            current = new StoreOperationalStatisticsVo.ServiceQualityData();
+        }
         comparison.setStoreRating(buildComparisonData(current.getStoreRating(), previous.getStoreRating()));
         comparison.setTasteRating(buildComparisonData(current.getTasteRating(), previous.getTasteRating()));
         comparison.setEnvironmentRating(buildComparisonData(current.getEnvironmentRating(), previous.getEnvironmentRating()));
@@ -607,6 +814,48 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
     }
 
     @Override
+    public StoreOperationalStatisticsVo getStatisticsInTrackFormat(Integer storeId, String startTime, String endTime) {
+        log.info("StoreOperationalStatisticsServiceImpl.getStatisticsInTrackFormat - storeId={}, startTime={}, endTime={}", 
+                storeId, startTime, endTime);
+        
+        // 计算统计数据
+        StoreOperationalStatisticsVo statistics = calculateStatistics(storeId, startTime, endTime);
+        
+        // 保存统计数据到历史表
+        saveStatisticsHistory(storeId, startTime, endTime, statistics);
+        
+        return statistics;
+    }
+    
+    /**
+     * 保存统计数据到历史表
+     */
+    private void saveStatisticsHistory(Integer storeId, String startTime, String endTime, StoreOperationalStatisticsVo statistics) {
+        try {
+            SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
+            Date startDate = sdf.parse(startTime);
+            Date endDate = sdf.parse(endTime);
+
+            StoreOperationalStatisticsHistory history = new StoreOperationalStatisticsHistory();
+            history.setStoreId(storeId);
+            history.setStartTime(startDate);
+            history.setEndTime(endDate);
+            history.setQueryTime(new Date());
+            
+            // 将统计数据序列化为JSON字符串
+            String statisticsJson = JSON.toJSONString(statistics);
+            history.setStatisticsData(statisticsJson);
+
+            statisticsHistoryMapper.insert(history);
+            log.info("保存统计数据到历史表成功 - storeId={}, startTime={}, endTime={}", storeId, startTime, endTime);
+        } catch (Exception e) {
+            log.error("保存统计数据到历史表失败 - storeId={}, startTime={}, endTime={}, error={}", 
+                    storeId, startTime, endTime, e.getMessage(), e);
+            // 保存失败不影响主流程,只记录日志
+        }
+    }
+
+    @Override
     public List<StoreOperationalStatisticsHistory> getHistoryList(Integer storeId) {
         log.info("StoreOperationalStatisticsServiceImpl.getHistoryList - storeId={}", storeId);
         
@@ -660,4 +909,460 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
             return false;
         }
     }
+    
+    // ==================== 累加和转换方法 ====================
+    
+    /**
+     * 累加流量数据
+     */
+    @SuppressWarnings("unchecked")
+    private void aggregateTrafficData(String trafficDataJson, Map<String, Long> accumulator) {
+        try {
+            Map<String, Object> data = (Map<String, Object>) JSON.parseObject(trafficDataJson, Map.class);
+            if (data == null) return;
+            
+            // 累加各个字段
+            accumulator.put("searchCount", accumulator.getOrDefault("searchCount", 0L) + 
+                    getLongValue(data, "searchCount"));
+            accumulator.put("viewCount", accumulator.getOrDefault("viewCount", 0L) + 
+                    getLongValue(data, "viewCount"));
+            accumulator.put("visitorCount", accumulator.getOrDefault("visitorCount", 0L) + 
+                    getLongValue(data, "visitorCount"));
+            accumulator.put("newVisitorCount", accumulator.getOrDefault("newVisitorCount", 0L) + 
+                    getLongValue(data, "newVisitorCount"));
+            accumulator.put("totalDuration", accumulator.getOrDefault("totalDuration", 0L) + 
+                    getLongValue(data, "totalDuration"));
+            accumulator.put("avgDuration", accumulator.getOrDefault("avgDuration", 0L) + 
+                    getLongValue(data, "avgDuration"));
+        } catch (Exception e) {
+            log.warn("解析流量数据失败: {}", trafficDataJson, e);
+        }
+    }
+    
+    /**
+     * 累加互动数据
+     */
+    @SuppressWarnings("unchecked")
+    private void aggregateInteractionData(String interactionDataJson, Map<String, Long> accumulator) {
+        try {
+            Map<String, Object> data = (Map<String, Object>) JSON.parseObject(interactionDataJson, Map.class);
+            if (data == null) return;
+            
+            accumulator.put("collectCount", accumulator.getOrDefault("collectCount", 0L) + 
+                    getLongValue(data, "collectCount"));
+            accumulator.put("shareCount", accumulator.getOrDefault("shareCount", 0L) + 
+                    getLongValue(data, "shareCount"));
+            accumulator.put("checkinCount", accumulator.getOrDefault("checkinCount", 0L) + 
+                    getLongValue(data, "checkinCount"));
+            accumulator.put("consultCount", accumulator.getOrDefault("consultCount", 0L) + 
+                    getLongValue(data, "consultCount"));
+            accumulator.put("friendCount", accumulator.getOrDefault("friendCount", 0L) + 
+                    getLongValue(data, "friendCount"));
+            accumulator.put("followCount", accumulator.getOrDefault("followCount", 0L) + 
+                    getLongValue(data, "followCount"));
+            accumulator.put("fansCount", accumulator.getOrDefault("fansCount", 0L) + 
+                    getLongValue(data, "fansCount"));
+            accumulator.put("postCount", accumulator.getOrDefault("postCount", 0L) + 
+                    getLongValue(data, "postCount"));
+            accumulator.put("postLikeCount", accumulator.getOrDefault("postLikeCount", 0L) + 
+                    getLongValue(data, "postLikeCount"));
+            accumulator.put("postCommentCount", accumulator.getOrDefault("postCommentCount", 0L) + 
+                    getLongValue(data, "postCommentCount"));
+            accumulator.put("postRepostCount", accumulator.getOrDefault("postRepostCount", 0L) + 
+                    getLongValue(data, "postRepostCount"));
+            accumulator.put("reportCount", accumulator.getOrDefault("reportCount", 0L) + 
+                    getLongValue(data, "reportCount"));
+            accumulator.put("blockCount", accumulator.getOrDefault("blockCount", 0L) + 
+                    getLongValue(data, "blockCount"));
+        } catch (Exception e) {
+            log.warn("解析互动数据失败: {}", interactionDataJson, e);
+        }
+    }
+    
+    /**
+     * 累加优惠券数据
+     */
+    @SuppressWarnings("unchecked")
+    private void aggregateCouponData(String couponDataJson, Map<String, Object> accumulator) {
+        try {
+            Map<String, Object> data = (Map<String, Object>) JSON.parseObject(couponDataJson, Map.class);
+            if (data == null) return;
+            
+            // 累加Long类型字段
+            accumulator.put("giveToFriendCount", getLongValue(accumulator, "giveToFriendCount") + 
+                    getLongValue(data, "giveToFriendCount"));
+            accumulator.put("giveToFriendUseCount", getLongValue(accumulator, "giveToFriendUseCount") + 
+                    getLongValue(data, "giveToFriendUseCount"));
+            accumulator.put("friendGiveCount", getLongValue(accumulator, "friendGiveCount") + 
+                    getLongValue(data, "friendGiveCount"));
+            accumulator.put("friendGiveUseCount", getLongValue(accumulator, "friendGiveUseCount") + 
+                    getLongValue(data, "friendGiveUseCount"));
+            
+            // 累加BigDecimal类型字段
+            accumulator.put("giveToFriendAmount", getBigDecimalValue(accumulator, "giveToFriendAmount")
+                    .add(getBigDecimalValue(data, "giveToFriendAmount")));
+            accumulator.put("giveToFriendUseAmount", getBigDecimalValue(accumulator, "giveToFriendUseAmount")
+                    .add(getBigDecimalValue(data, "giveToFriendUseAmount")));
+            accumulator.put("friendGiveAmount", getBigDecimalValue(accumulator, "friendGiveAmount")
+                    .add(getBigDecimalValue(data, "friendGiveAmount")));
+            accumulator.put("friendGiveUseAmount", getBigDecimalValue(accumulator, "friendGiveUseAmount")
+                    .add(getBigDecimalValue(data, "friendGiveUseAmount")));
+        } catch (Exception e) {
+            log.warn("解析优惠券数据失败: {}", couponDataJson, e);
+        }
+    }
+    
+    /**
+     * 累加代金券数据
+     */
+    @SuppressWarnings("unchecked")
+    private void aggregateVoucherData(String voucherDataJson, Map<String, Object> accumulator) {
+        try {
+            Map<String, Object> data = (Map<String, Object>) JSON.parseObject(voucherDataJson, Map.class);
+            if (data == null) return;
+            
+            // 累加Long类型字段
+            accumulator.put("giveToFriendCount", getLongValue(accumulator, "giveToFriendCount") + 
+                    getLongValue(data, "giveToFriendCount"));
+            accumulator.put("giveToFriendUseCount", getLongValue(accumulator, "giveToFriendUseCount") + 
+                    getLongValue(data, "giveToFriendUseCount"));
+            accumulator.put("friendGiveCount", getLongValue(accumulator, "friendGiveCount") + 
+                    getLongValue(data, "friendGiveCount"));
+            accumulator.put("friendGiveUseCount", getLongValue(accumulator, "friendGiveUseCount") + 
+                    getLongValue(data, "friendGiveUseCount"));
+            
+            // 累加BigDecimal类型字段
+            accumulator.put("giveToFriendAmount", getBigDecimalValue(accumulator, "giveToFriendAmount")
+                    .add(getBigDecimalValue(data, "giveToFriendAmount")));
+            accumulator.put("giveToFriendUseAmount", getBigDecimalValue(accumulator, "giveToFriendUseAmount")
+                    .add(getBigDecimalValue(data, "giveToFriendUseAmount")));
+            accumulator.put("friendGiveAmount", getBigDecimalValue(accumulator, "friendGiveAmount")
+                    .add(getBigDecimalValue(data, "friendGiveAmount")));
+            accumulator.put("friendGiveUseAmount", getBigDecimalValue(accumulator, "friendGiveUseAmount")
+                    .add(getBigDecimalValue(data, "friendGiveUseAmount")));
+        } catch (Exception e) {
+            log.warn("解析代金券数据失败: {}", voucherDataJson, e);
+        }
+    }
+    
+    /**
+     * 累加服务质量数据
+     */
+    @SuppressWarnings("unchecked")
+    private void aggregateServiceData(String serviceDataJson, Map<String, Object> accumulator) {
+        try {
+            Map<String, Object> data = (Map<String, Object>) JSON.parseObject(serviceDataJson, Map.class);
+            if (data == null) return;
+            
+            // 累加评分(需要计算平均值)
+            accumulator.put("storeScoreSum", getBigDecimalValue(accumulator, "storeScoreSum")
+                    .add(getBigDecimalValue(data, "storeScore")));
+            accumulator.put("tasteScoreSum", getBigDecimalValue(accumulator, "tasteScoreSum")
+                    .add(getBigDecimalValue(data, "tasteScore")));
+            accumulator.put("environmentScoreSum", getBigDecimalValue(accumulator, "environmentScoreSum")
+                    .add(getBigDecimalValue(data, "environmentScore")));
+            accumulator.put("serviceScoreSum", getBigDecimalValue(accumulator, "serviceScoreSum")
+                    .add(getBigDecimalValue(data, "serviceScore")));
+            
+            // 累加Long类型字段
+            accumulator.put("ratingCount", getLongValue(accumulator, "ratingCount") + 
+                    getLongValue(data, "ratingCount"));
+            accumulator.put("goodRatingCount", getLongValue(accumulator, "goodRatingCount") + 
+                    getLongValue(data, "goodRatingCount"));
+            accumulator.put("midRatingCount", getLongValue(accumulator, "midRatingCount") + 
+                    getLongValue(data, "midRatingCount"));
+            accumulator.put("badRatingCount", getLongValue(accumulator, "badRatingCount") + 
+                    getLongValue(data, "badRatingCount"));
+            accumulator.put("appealCount", getLongValue(accumulator, "appealCount") + 
+                    getLongValue(data, "appealCount"));
+            accumulator.put("appealSuccessCount", getLongValue(accumulator, "appealSuccessCount") + 
+                    getLongValue(data, "appealSuccessCount"));
+        } catch (Exception e) {
+            log.warn("解析服务质量数据失败: {}", serviceDataJson, e);
+        }
+    }
+    
+    /**
+     * 累加价目表排名数据
+     */
+    @SuppressWarnings("unchecked")
+    private void aggregatePriceRankingData(String priceRankingDataJson, Map<Integer, Map<String, Long>> accumulator) {
+        try {
+            List<Map<String, Object>> dataList = (List<Map<String, Object>>) (List<?>) JSON.parseArray(priceRankingDataJson);
+            if (dataList == null) return;
+            
+            for (Map<String, Object> item : dataList) {
+                Integer priceId = getIntegerValue(item, "priceId");
+                if (priceId == null) continue;
+                
+                Map<String, Long> priceData = accumulator.computeIfAbsent(priceId, k -> new HashMap<>());
+                priceData.put("viewCount", priceData.getOrDefault("viewCount", 0L) + 
+                        getLongValue(item, "viewCount"));
+                priceData.put("visitorCount", priceData.getOrDefault("visitorCount", 0L) + 
+                        getLongValue(item, "visitorCount"));
+                priceData.put("shareCount", priceData.getOrDefault("shareCount", 0L) + 
+                        getLongValue(item, "shareCount"));
+            }
+        } catch (Exception e) {
+            log.warn("解析价目表排名数据失败: {}", priceRankingDataJson, e);
+        }
+    }
+    
+    /**
+     * 转换为流量数据VO
+     */
+    private StoreOperationalStatisticsVo.TrafficData convertToTrafficDataVo(Map<String, Long> accumulator, int count) {
+        StoreOperationalStatisticsVo.TrafficData vo = new StoreOperationalStatisticsVo.TrafficData();
+        vo.setStoreSearchVolume(accumulator.getOrDefault("searchCount", 0L));
+        vo.setPageViews(accumulator.getOrDefault("viewCount", 0L));
+        vo.setVisitors(accumulator.getOrDefault("visitorCount", 0L));
+        vo.setNewVisitors(accumulator.getOrDefault("newVisitorCount", 0L));
+        
+        // 访问时长转换为秒(原数据是毫秒)
+        Long totalDuration = accumulator.getOrDefault("totalDuration", 0L);
+        vo.setVisitDuration(totalDuration / 1000);
+        
+        // 平均访问时长:如果有多个统计记录,需要重新计算平均值
+        Long avgDuration = accumulator.getOrDefault("avgDuration", 0L);
+        if (count > 0 && avgDuration > 0) {
+            vo.setAvgVisitDuration(avgDuration / 1000); // 转换为秒
+        } else {
+            vo.setAvgVisitDuration(0L);
+        }
+        
+        return vo;
+    }
+    
+    /**
+     * 转换为互动数据VO
+     */
+    private StoreOperationalStatisticsVo.InteractionData convertToInteractionDataVo(Map<String, Long> accumulator) {
+        StoreOperationalStatisticsVo.InteractionData vo = new StoreOperationalStatisticsVo.InteractionData();
+        vo.setStoreCollectionCount(accumulator.getOrDefault("collectCount", 0L));
+        vo.setStoreShareCount(accumulator.getOrDefault("shareCount", 0L));
+        vo.setStoreCheckInCount(accumulator.getOrDefault("checkinCount", 0L));
+        vo.setConsultMerchantCount(accumulator.getOrDefault("consultCount", 0L));
+        vo.setFriendsCount(accumulator.getOrDefault("friendCount", 0L));
+        vo.setFollowCount(accumulator.getOrDefault("followCount", 0L));
+        vo.setFansCount(accumulator.getOrDefault("fansCount", 0L));
+        vo.setPostsPublishedCount(accumulator.getOrDefault("postCount", 0L));
+        vo.setPostLikesCount(accumulator.getOrDefault("postLikeCount", 0L));
+        vo.setPostCommentsCount(accumulator.getOrDefault("postCommentCount", 0L));
+        vo.setPostSharesCount(accumulator.getOrDefault("postRepostCount", 0L));
+        vo.setReportedCount(accumulator.getOrDefault("reportCount", 0L));
+        vo.setBlockedCount(accumulator.getOrDefault("blockCount", 0L));
+        return vo;
+    }
+    
+    /**
+     * 转换为优惠券数据VO
+     */
+    private StoreOperationalStatisticsVo.CouponData convertToCouponDataVo(Map<String, Object> accumulator) {
+        StoreOperationalStatisticsVo.CouponData vo = new StoreOperationalStatisticsVo.CouponData();
+        vo.setGiftToFriendsCount(getLongValue(accumulator, "giveToFriendCount"));
+        vo.setGiftToFriendsAmount(getBigDecimalValue(accumulator, "giveToFriendAmount"));
+        vo.setGiftToFriendsUsedCount(getLongValue(accumulator, "giveToFriendUseCount"));
+        vo.setGiftToFriendsUsedAmount(getBigDecimalValue(accumulator, "giveToFriendUseAmount"));
+        
+        // 计算使用金额占比
+        BigDecimal giftAmount = getBigDecimalValue(accumulator, "giveToFriendAmount");
+        BigDecimal giftUsedAmount = getBigDecimalValue(accumulator, "giveToFriendUseAmount");
+        if (giftAmount.compareTo(BigDecimal.ZERO) > 0) {
+            vo.setGiftToFriendsUsedAmountRatio(giftUsedAmount.divide(giftAmount, 4, RoundingMode.HALF_UP)
+                    .multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP));
+        } else {
+            vo.setGiftToFriendsUsedAmountRatio(BigDecimal.ZERO);
+        }
+        
+        vo.setFriendsGiftCount(getLongValue(accumulator, "friendGiveCount"));
+        vo.setFriendsGiftAmount(getBigDecimalValue(accumulator, "friendGiveAmount"));
+        vo.setFriendsGiftUsedCount(getLongValue(accumulator, "friendGiveUseCount"));
+        vo.setFriendsGiftUsedAmount(getBigDecimalValue(accumulator, "friendGiveUseAmount"));
+        
+        // 计算好友赠送使用金额占比
+        BigDecimal friendAmount = getBigDecimalValue(accumulator, "friendGiveAmount");
+        BigDecimal friendUsedAmount = getBigDecimalValue(accumulator, "friendGiveUseAmount");
+        if (friendAmount.compareTo(BigDecimal.ZERO) > 0) {
+            vo.setFriendsGiftUsedAmountRatio(friendUsedAmount.divide(friendAmount, 4, RoundingMode.HALF_UP)
+                    .multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP));
+        } else {
+            vo.setFriendsGiftUsedAmountRatio(BigDecimal.ZERO);
+        }
+        
+        return vo;
+    }
+    
+    /**
+     * 转换为代金券数据VO
+     */
+    private StoreOperationalStatisticsVo.VoucherData convertToVoucherDataVo(Map<String, Object> accumulator) {
+        StoreOperationalStatisticsVo.VoucherData vo = new StoreOperationalStatisticsVo.VoucherData();
+        vo.setGiftToFriendsCount(getLongValue(accumulator, "giveToFriendCount"));
+        vo.setGiftToFriendsAmount(getBigDecimalValue(accumulator, "giveToFriendAmount"));
+        vo.setGiftToFriendsUsedCount(getLongValue(accumulator, "giveToFriendUseCount"));
+        vo.setGiftToFriendsUsedAmount(getBigDecimalValue(accumulator, "giveToFriendUseAmount"));
+        
+        // 计算使用金额占比
+        BigDecimal giftAmount = getBigDecimalValue(accumulator, "giveToFriendAmount");
+        BigDecimal giftUsedAmount = getBigDecimalValue(accumulator, "giveToFriendUseAmount");
+        if (giftAmount.compareTo(BigDecimal.ZERO) > 0) {
+            vo.setGiftToFriendsUsedAmountRatio(giftUsedAmount.divide(giftAmount, 4, RoundingMode.HALF_UP)
+                    .multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP));
+        } else {
+            vo.setGiftToFriendsUsedAmountRatio(BigDecimal.ZERO);
+        }
+        
+        vo.setFriendsGiftCount(getLongValue(accumulator, "friendGiveCount"));
+        vo.setFriendsGiftAmount(getBigDecimalValue(accumulator, "friendGiveAmount"));
+        vo.setFriendsGiftUsedCount(getLongValue(accumulator, "friendGiveUseCount"));
+        vo.setFriendsGiftUsedAmount(getBigDecimalValue(accumulator, "friendGiveUseAmount"));
+        
+        // 计算好友赠送使用金额占比
+        BigDecimal friendAmount = getBigDecimalValue(accumulator, "friendGiveAmount");
+        BigDecimal friendUsedAmount = getBigDecimalValue(accumulator, "friendGiveUseAmount");
+        if (friendAmount.compareTo(BigDecimal.ZERO) > 0) {
+            vo.setFriendsGiftUsedAmountRatio(friendUsedAmount.divide(friendAmount, 4, RoundingMode.HALF_UP)
+                    .multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP));
+        } else {
+            vo.setFriendsGiftUsedAmountRatio(BigDecimal.ZERO);
+        }
+        
+        return vo;
+    }
+    
+    /**
+     * 转换为服务质量数据VO
+     */
+    private StoreOperationalStatisticsVo.ServiceQualityData convertToServiceQualityDataVo(Map<String, Object> accumulator, int count) {
+        StoreOperationalStatisticsVo.ServiceQualityData vo = new StoreOperationalStatisticsVo.ServiceQualityData();
+        
+        // 计算平均评分
+        if (count > 0) {
+            BigDecimal storeScoreSum = getBigDecimalValue(accumulator, "storeScoreSum");
+            BigDecimal tasteScoreSum = getBigDecimalValue(accumulator, "tasteScoreSum");
+            BigDecimal environmentScoreSum = getBigDecimalValue(accumulator, "environmentScoreSum");
+            BigDecimal serviceScoreSum = getBigDecimalValue(accumulator, "serviceScoreSum");
+            
+            vo.setStoreRating(storeScoreSum.divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_UP));
+            vo.setTasteRating(tasteScoreSum.divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_UP));
+            vo.setEnvironmentRating(environmentScoreSum.divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_UP));
+            vo.setServiceRating(serviceScoreSum.divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_UP));
+        } else {
+            vo.setStoreRating(BigDecimal.ZERO);
+            vo.setTasteRating(BigDecimal.ZERO);
+            vo.setEnvironmentRating(BigDecimal.ZERO);
+            vo.setServiceRating(BigDecimal.ZERO);
+        }
+        
+        vo.setTotalReviews(getLongValue(accumulator, "ratingCount"));
+        vo.setPositiveReviews(getLongValue(accumulator, "goodRatingCount"));
+        vo.setNeutralReviews(getLongValue(accumulator, "midRatingCount"));
+        vo.setNegativeReviews(getLongValue(accumulator, "badRatingCount"));
+        
+        // 计算差评占比
+        Long ratingCount = getLongValue(accumulator, "ratingCount");
+        Long badRatingCount = getLongValue(accumulator, "badRatingCount");
+        if (ratingCount > 0) {
+            vo.setNegativeReviewRatio(BigDecimal.valueOf(badRatingCount)
+                    .divide(BigDecimal.valueOf(ratingCount), 4, RoundingMode.HALF_UP)
+                    .multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP));
+        } else {
+            vo.setNegativeReviewRatio(BigDecimal.ZERO);
+        }
+        
+        vo.setNegativeReviewAppealsCount(getLongValue(accumulator, "appealCount"));
+        vo.setNegativeReviewAppealsSuccessCount(getLongValue(accumulator, "appealSuccessCount"));
+        
+        // 计算差评申诉成功占比
+        Long appealCount = getLongValue(accumulator, "appealCount");
+        Long appealSuccessCount = getLongValue(accumulator, "appealSuccessCount");
+        if (appealCount > 0) {
+            vo.setNegativeReviewAppealsSuccessRatio(BigDecimal.valueOf(appealSuccessCount)
+                    .divide(BigDecimal.valueOf(appealCount), 4, RoundingMode.HALF_UP)
+                    .multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP));
+        } else {
+            vo.setNegativeReviewAppealsSuccessRatio(BigDecimal.ZERO);
+        }
+        
+        return vo;
+    }
+    
+    /**
+     * 转换为价目表排名数据VO
+     */
+    private List<StoreOperationalStatisticsVo.PriceListRanking> convertToPriceListRankingVo(Map<Integer, Map<String, Long>> accumulator) {
+        List<StoreOperationalStatisticsVo.PriceListRanking> result = new ArrayList<>();
+        
+        // 转换为列表并按浏览量降序排序
+        for (Map.Entry<Integer, Map<String, Long>> entry : accumulator.entrySet()) {
+            StoreOperationalStatisticsVo.PriceListRanking ranking = new StoreOperationalStatisticsVo.PriceListRanking();
+            ranking.setPriceId(entry.getKey());
+            Map<String, Long> data = entry.getValue();
+            ranking.setPageViews(data.getOrDefault("viewCount", 0L));
+            ranking.setVisitors(data.getOrDefault("visitorCount", 0L));
+            ranking.setShares(data.getOrDefault("shareCount", 0L));
+            
+            // 获取价目表名称(如果需要)
+            // ranking.setPriceListItemName(...);
+            
+            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);
+        }
+        
+        return result;
+    }
+    
+    // ==================== 工具方法 ====================
+    
+    /**
+     * 从Map中获取Long值
+     */
+    private Long getLongValue(Map<String, Object> map, String key) {
+        Object value = map.get(key);
+        if (value == null) return 0L;
+        if (value instanceof Long) return (Long) value;
+        if (value instanceof Number) return ((Number) value).longValue();
+        try {
+            return Long.parseLong(value.toString());
+        } catch (Exception e) {
+            return 0L;
+        }
+    }
+    
+    /**
+     * 从Map中获取Integer值
+     */
+    private Integer getIntegerValue(Map<String, Object> map, String key) {
+        Object value = map.get(key);
+        if (value == null) return null;
+        if (value instanceof Integer) return (Integer) value;
+        if (value instanceof Number) return ((Number) value).intValue();
+        try {
+            return Integer.parseInt(value.toString());
+        } catch (Exception e) {
+            return null;
+        }
+    }
+    
+    /**
+     * 从Map中获取BigDecimal值
+     */
+    private BigDecimal getBigDecimalValue(Map<String, Object> map, String key) {
+        Object value = map.get(key);
+        if (value == null) return BigDecimal.ZERO;
+        if (value instanceof BigDecimal) return (BigDecimal) value;
+        if (value instanceof Number) return BigDecimal.valueOf(((Number) value).doubleValue());
+        try {
+            return new BigDecimal(value.toString());
+        } catch (Exception e) {
+            return BigDecimal.ZERO;
+        }
+    }
 }

+ 11 - 1
alien-store/src/main/java/shop/alien/store/service/impl/StoreRenovationRequirementServiceImpl.java

@@ -503,7 +503,16 @@ public class StoreRenovationRequirementServiceImpl extends ServiceImpl<StoreReno
                 Map<Integer, StoreInfo> storeInfoMap = storeInfoList.stream()
                         .collect(Collectors.toMap(StoreInfo::getId, storeInfo -> storeInfo, (v1, v2) -> v1));
 
-                // 填充商铺信息到DTO
+                // 批量查询商户头像(store_user.head_img)
+                LambdaQueryWrapper<StoreUser> userWrapper = new LambdaQueryWrapper<StoreUser>()
+                        .in(StoreUser::getStoreId, storeIds)
+                        .eq(StoreUser::getDeleteFlag, 0);
+                List<StoreUser> storeUserList = storeUserMapper.selectList(userWrapper);
+                Map<Integer, String> storeAvatarMap = storeUserList.stream()
+                        .filter(u -> u.getStoreId() != null && u.getHeadImg() != null)
+                        .collect(Collectors.toMap(StoreUser::getStoreId, StoreUser::getHeadImg, (v1, v2) -> v1));
+
+                // 填充商铺信息(含头像)到DTO
                 dtoPage.getRecords().forEach(dto -> {
                     StoreInfo storeInfo = storeInfoMap.get(dto.getStoreId());
                     if (storeInfo != null) {
@@ -512,6 +521,7 @@ public class StoreRenovationRequirementServiceImpl extends ServiceImpl<StoreReno
                         dto.setStoreAddress(storeInfo.getStoreAddress());
                         dto.setStoreBlurb(storeInfo.getStoreBlurb());
                     }
+                    dto.setStoreAvatar(storeAvatarMap.get(dto.getStoreId()));
                 });
             }