xdd hai 1 semana
pai
achega
9798fbaeea
Modificáronse 46 ficheiros con 4823 adicións e 0 borrados
  1. 197 0
      fs-admin/src/main/java/com/fs/api/controller/IndexStatisticsController.java
  2. 13 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseTrafficLogMapper.java
  3. 20 0
      fs-service/src/main/java/com/fs/his/mapper/FsStoreProductMapper.java
  4. 13 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java
  5. 4 0
      fs-service/src/main/java/com/fs/his/service/IFsStoreProductService.java
  6. 2 0
      fs-service/src/main/java/com/fs/his/service/IFsUserService.java
  7. 10 0
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreProductServiceImpl.java
  8. 5 0
      fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java
  9. 65 0
      fs-service/src/main/java/com/fs/statis/StatisticsRedisConstant.java
  10. 105 0
      fs-service/src/main/java/com/fs/statis/domain/FsStatisEveryDayWatch.java
  11. 108 0
      fs-service/src/main/java/com/fs/statis/domain/FsStatisPeriodWatch.java
  12. 112 0
      fs-service/src/main/java/com/fs/statis/domain/FsStatisSalerWatch.java
  13. 149 0
      fs-service/src/main/java/com/fs/statis/domain/FsStatsMemberDaily.java
  14. 91 0
      fs-service/src/main/java/com/fs/statis/dto/AnalysisPreviewDTO.java
  15. 50 0
      fs-service/src/main/java/com/fs/statis/dto/AnalysisPreviewQueryDTO.java
  16. 17 0
      fs-service/src/main/java/com/fs/statis/dto/AuthorizationInfoDTO.java
  17. 29 0
      fs-service/src/main/java/com/fs/statis/dto/ConsumptionBalanceDataDTO.java
  18. 63 0
      fs-service/src/main/java/com/fs/statis/dto/CourseStatsDTO.java
  19. 22 0
      fs-service/src/main/java/com/fs/statis/dto/DeaMemberTopTenDTO.java
  20. 70 0
      fs-service/src/main/java/com/fs/statis/dto/DealerAggregatedDTO.java
  21. 29 0
      fs-service/src/main/java/com/fs/statis/dto/ModifyMoreDTO.java
  22. 15 0
      fs-service/src/main/java/com/fs/statis/dto/RewardMoneyTopTenDTO.java
  23. 13 0
      fs-service/src/main/java/com/fs/statis/dto/RewardMoneyTrendDTO.java
  24. 30 0
      fs-service/src/main/java/com/fs/statis/dto/StatsWatchLogPageListDTO.java
  25. 25 0
      fs-service/src/main/java/com/fs/statis/dto/TrafficLogDTO.java
  26. 29 0
      fs-service/src/main/java/com/fs/statis/dto/WatchEndPlayTrendDTO.java
  27. 128 0
      fs-service/src/main/java/com/fs/statis/mapper/ConsumptionBalanceMapper.java
  28. 87 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisEveryDayWatchMapper.java
  29. 94 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisPeriodWatchMapper.java
  30. 80 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisSalerWatchMapper.java
  31. 26 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatsMemberDailyMapper.java
  32. 47 0
      fs-service/src/main/java/com/fs/statis/service/FsStatisEveryDayWatchService.java
  33. 56 0
      fs-service/src/main/java/com/fs/statis/service/FsStatisPeriodWatchService.java
  34. 59 0
      fs-service/src/main/java/com/fs/statis/service/FsStatisSalerWatchService.java
  35. 23 0
      fs-service/src/main/java/com/fs/statis/service/IFsStatsMemberDailyService.java
  36. 108 0
      fs-service/src/main/java/com/fs/statis/service/IStatisticsCompanyService.java
  37. 112 0
      fs-service/src/main/java/com/fs/statis/service/IStatisticsService.java
  38. 70 0
      fs-service/src/main/java/com/fs/statis/service/impl/FsStatisEveryDayWatchServiceImpl.java
  39. 81 0
      fs-service/src/main/java/com/fs/statis/service/impl/FsStatisPeriodWatchServiceImpl.java
  40. 173 0
      fs-service/src/main/java/com/fs/statis/service/impl/FsStatisSalerWatchServiceImpl.java
  41. 36 0
      fs-service/src/main/java/com/fs/statis/service/impl/FsStatsMemberDailyServiceImpl.java
  42. 1077 0
      fs-service/src/main/java/com/fs/statis/service/impl/StatisticsCompanyServiceImpl.java
  43. 968 0
      fs-service/src/main/java/com/fs/statis/service/impl/StatisticsServiceImpl.java
  44. 169 0
      fs-service/src/main/java/com/fs/statis/service/utils/TrendDataFiller.java
  45. 81 0
      fs-service/src/main/java/com/fs/statis/vo/FsStatsMemberDailyVO.java
  46. 62 0
      fs-service/src/main/resources/mapper/course/FsCourseTrafficLogMapper.xml

+ 197 - 0
fs-admin/src/main/java/com/fs/api/controller/IndexStatisticsController.java

@@ -0,0 +1,197 @@
+package com.fs.api.controller;
+
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.statis.StatisticsRedisConstant;
+import com.fs.statis.dto.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.fs.statis.StatisticsRedisConstant.*;
+
+/**
+ * 首页-统计
+ */
+@RestController
+@RequestMapping("/index/statistics")
+public class IndexStatisticsController {
+    @Autowired
+    private RedisCache redisCache;
+    /**
+     * 分析概览
+     */
+    @PostMapping("/analysisPreview")
+    public R analysisPreview(@RequestBody AnalysisPreviewQueryDTO param){
+        AnalysisPreviewDTO analysisPreviewDTO = null;
+        Integer type = param.getType();
+        Integer userType = param.getUserType();
+
+        if(type == null) {
+            type = 0;
+        }
+
+        if(userType == null) {
+            userType = 0;
+        }
+        analysisPreviewDTO = redisCache.getCacheObject(String.format("%s:%d:%d",DATA_OVERVIEW_DEALER_ANALYSISPREVIEW,type,userType));
+
+        return R.ok().put("data",analysisPreviewDTO);
+    }
+
+
+    /**
+     * 消费余额
+     */
+    @GetMapping("/rechargeComsumption")
+    public R rechargeComsumption(){
+        ConsumptionBalanceDataDTO consumptionBalanceDataDTO = redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_BALANCE);
+
+        return R.ok().put("data", consumptionBalanceDataDTO);
+    }
+
+    /**
+     * 获取统计流量
+     * @return
+     */
+    @GetMapping("/trafficLog")
+    public R getTrafficLog(){
+        TrafficLogDTO trafficLogDTO = redisCache.getCacheObject(DATA_OVERVIEW_TRAFFIC_LOG);
+        return R.ok().put("data",trafficLogDTO);
+    }
+
+    /**
+     * 观看趋势
+     */
+    @PostMapping("/watchEndPlayTrend")
+    public R watchEndPlayTrend(@RequestBody AnalysisPreviewQueryDTO param){
+        Integer type = param.getType();
+        Integer userType = param.getUserType();
+
+        if(type == null) {
+            type = 0;
+        }
+        if(userType == null){
+            userType = 0;
+        }
+        String key = String.format("%s:%d:%d", DATA_OVERVIEW_DEALER_CHARTS, type,userType);
+        List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = redisCache.getCacheObject(key);
+        return R.ok().put("data", deaMemberTopTenDTOS);
+    }
+
+    /**
+     * 经销商会员观看
+     */
+    @PostMapping("/deaMemberTopTen")
+    public R deaMemberTopTen(@RequestBody AnalysisPreviewQueryDTO param){
+        Integer type = param.getType();
+        Integer statisticalType = param.getStatisticalType();
+        Integer userType = param.getUserType();
+
+        if(type == null) {
+            type = 0;
+        }
+        if(userType == null){
+            userType = 0;
+        }
+
+        List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = redisCache.getCacheObject(String.format("%s:%d:%d:%d", CHARTS_MEMBER_TOP_TEN_WATCH, type, statisticalType,userType));
+        if(deaMemberTopTenDTOS == null){
+            deaMemberTopTenDTOS = new ArrayList<>();
+        }
+        return R.ok().put("data", deaMemberTopTenDTOS);
+    }
+
+    /**
+     * 奖励金额top10
+     */
+    @PostMapping("/rewardMoneyTopTen")
+    public R rewardMoneyTopTen(@RequestBody AnalysisPreviewQueryDTO param){
+        Integer type = param.getType();
+        Integer dataType = param.getDataType();
+        Integer userType = param.getUserType();
+
+        List<RewardMoneyTopTenDTO> rewardMoneyTopTenDTOS = redisCache.getCacheObject( String.format("%s:%d:%d:%d", CHARTS_REWARD_MONEY_TOP_TEN, type,dataType,userType));
+        return R.ok().put("data", rewardMoneyTopTenDTOS);
+    }
+
+    /**
+     * 答题红包金额趋势图
+     */
+    @PostMapping("/rewardMoneyTrend")
+    public R rewardMoneyTrend(@RequestBody AnalysisPreviewQueryDTO param){
+        Integer type = param.getType();
+        Integer userType = param.getUserType();
+        List<RewardMoneyTrendDTO> rewardMoneyTrendDTOS = redisCache.getCacheObject( String.format("%s:%d:%d", CHARTS_REWARD_MONEY_TREND, type,userType));
+        return R.ok().put("data", rewardMoneyTrendDTOS);
+    }
+
+    /**
+     * 课程观看top10
+     */
+    @PostMapping("/watchCourseTopTen")
+    public R watchCourseTopTen(@RequestBody AnalysisPreviewQueryDTO param){
+        Integer type = param.getType();
+        String sort = param.getSort();
+        Integer statisticalType = param.getStatisticalType();
+        Integer userType = param.getUserType();
+
+        List<CourseStatsDTO> courseStatsDTOS = redisCache.getCacheObject(String.format("%s:%d:%d:%d:%s", CHARTS_WATCH_TOP_TEN, type,statisticalType,userType,sort));
+        return R.ok().put("data", courseStatsDTOS);
+    }
+
+    /**
+     * 数据概览
+     */
+    @GetMapping("/dealerAggregated")
+    public R dealerAggregated(){
+        DealerAggregatedDTO dealerAggregatedDTO = redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_AGGREGATED);
+
+        return R.ok().put("data",dealerAggregatedDTO);
+    }
+
+    /**
+     * 短信余额
+     */
+    @GetMapping("/smsBalance")
+    public R smsBalance(){
+        Long smsBalance = redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_SMS_BALANCE);
+
+        return R.ok().put("data", smsBalance);
+    }
+
+
+    /**
+     * 授权信息
+     */
+    @GetMapping("/authorizationInfo")
+    public R authorizationInfo(){
+        AuthorizationInfoDTO authorizationInfoDTO = redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_AUTHORIZATION_INFO);
+
+        return R.ok().put("data", authorizationInfoDTO);
+    }
+
+
+    /**
+     * 当月订单数统计
+     * @return
+     */
+    @GetMapping("/thisMonthOrderCount")
+    public R thisMonthOrderCount(){
+        R result = redisCache.getCacheObject(StatisticsRedisConstant.THIS_MONTH_ORDER_COUNT);
+        return result;
+    }
+
+    /**
+     * 当月收益统计
+     * @return
+     */
+
+    @GetMapping("/thisMonthRecvCount")
+    public R thisMonthRecvCount(){
+        R result = redisCache.getCacheObject(StatisticsRedisConstant.THIS_MONTH_RECV_COUNT);
+        return result;
+    }
+}

+ 13 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseTrafficLogMapper.java

@@ -85,4 +85,17 @@ public interface FsCourseTrafficLogMapper
     FsCourseTrafficLog selectFsCourseTrafficLogByuuId(@Param("uuId") String uuId);
 
     void insertOrUpdateTrafficLog(FsCourseTrafficLog trafficLog);
+
+    Long getTodayTrafficLogCompanyId(@Param("companyId") Long companyId);
+
+    Long getYesterdayTrafficLogCompanyId(@Param("companyId") Long companyId);
+
+    Long getMonthTrafficLogCompanyId(@Param("companyId") Long companyId);
+
+    Long getTodayTrafficLog();
+
+    Long getYesterdayTrafficLog();
+
+    Long getMonthTrafficLog();
+
 }

+ 20 - 0
fs-service/src/main/java/com/fs/his/mapper/FsStoreProductMapper.java

@@ -227,4 +227,24 @@ public interface FsStoreProductMapper
     FsStoreProductAttrVO selectFsStoreProductAttrVOByProdId(Long productId);
 
     FsStoreProduct selectFsStoreProductById(Long productId);
+    @Select({"<script> " +
+            "select count(1) from fs_store_product  " +
+            "where 1=1 " +
+            "<if test = 'type != null and  type ==1  '> " +
+            "and  DATE_FORMAT(create_time, '%Y-%m-%d')  = DATE_FORMAT(NOW(), '%Y-%m-%d') " +
+            "</if>" +
+            "<if test = 'companyIds != null and companyIds != \"\" '> " +
+            "and find_in_set(#{companyIds}, company_ids) " +
+            "</if>" +
+            "</script>"})
+    Long selectFsStoreProductCompanyCount(@Param("type") int type,@Param("companyIds") Long companyIds);
+
+    @Select({"<script> " +
+            "select count(1) from fs_store_product  " +
+            "where 1=1 " +
+            "<if test = 'type != null and  type ==1  '> " +
+            "and  DATE_FORMAT(create_time, '%Y-%m-%d')  = DATE_FORMAT(NOW(), '%Y-%m-%d') " +
+            "</if>" +
+            "</script>"})
+    Long selectFsStoreProductCount(int type);
 }

+ 13 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java

@@ -256,4 +256,17 @@ public interface FsUserMapper
     List<FsUserPageListVO> selectFsUserPageListNew(FsUserPageListParam param);
 
     Long selectFsUserPageListCount(FsUserPageListParam param);
+
+    @Select({"<script> " +
+            "select count(1) from fs_user  " +
+            "where 1=1 " +
+            "<if test = 'type != null and  type ==1  '> " +
+            "and  DATE_FORMAT(create_time, '%Y-%m-%d')  = DATE_FORMAT(NOW(), '%Y-%m-%d') " +
+            "</if>" +
+            "<if test = 'companyId != null  '> " +
+            "and  company_id=#{companyId} " +
+            "</if>" +
+            "</script>"})
+    Long selectFsUserCount(@Param("type") int type,@Param("companyId") Long companyId);
+
 }

+ 4 - 0
fs-service/src/main/java/com/fs/his/service/IFsStoreProductService.java

@@ -90,4 +90,8 @@ public interface IFsStoreProductService
     List<FsStoreProductAttrValueVO> selectFsStoreProductAttrValueListVO(FsProductAttrValueParam param);
 
     FsStoreProduct selectFsStoreProductById(Long productId);
+
+    Long selectFsStoreProductCount(int type, Long companyId);
+    Long selectFsStoreProductCount(int type);
+
 }

+ 2 - 0
fs-service/src/main/java/com/fs/his/service/IFsUserService.java

@@ -134,4 +134,6 @@ public interface IFsUserService
     TableDataInfo selectFsUserPageListNew(FsUserPageListParam param);
 
     Long selectFsUserCount(FsUserPageListParam param);
+    Long selectFsUserCount(int type,Long companyId);
+
 }

+ 10 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsStoreProductServiceImpl.java

@@ -773,5 +773,15 @@ public class FsStoreProductServiceImpl implements IFsStoreProductService
         return fsStoreProductMapper.selectFsStoreProductById(productId);
     }
 
+    @Override
+    public Long selectFsStoreProductCount(int type, Long companyId) {
+        return fsStoreProductMapper.selectFsStoreProductCompanyCount(type,companyId);
+    }
+
+    @Override
+    public Long selectFsStoreProductCount(int type) {
+        return fsStoreProductMapper.selectFsStoreProductCount(type);
+    }
+
 
 }

+ 5 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java

@@ -610,4 +610,9 @@ public class FsUserServiceImpl implements IFsUserService
         return fsUserMapper.selectFsUserPageListCount(param);
     }
 
+    @Override
+    public Long selectFsUserCount(int type, Long companyId) {
+        return fsUserMapper.selectFsUserCount(type,companyId);
+    }
+
 }

+ 65 - 0
fs-service/src/main/java/com/fs/statis/StatisticsRedisConstant.java

@@ -0,0 +1,65 @@
+package com.fs.statis;
+
+/**
+ * 统计redis常量
+ */
+public class StatisticsRedisConstant {
+    /**
+     * 经销商统计
+     */
+    public static final String DATA_OVERVIEW_DEALER_AGGREGATED = "overview:dealerAggregated";
+    /**
+     * 短信余额
+     */
+    public static final String DATA_OVERVIEW_DEALER_SMS_BALANCE = "overview:sms:balance";
+    /**
+     * 流量统计
+     */
+    public static final String DATA_OVERVIEW_TRAFFIC_LOG = "overview:traffic_log";
+    /**
+     * 余额类
+     */
+    public static final String DATA_OVERVIEW_DEALER_BALANCE = "overview:balance";
+    /**
+     * 平台统计类信息
+     */
+    public static final String DATA_OVERVIEW_DEALER_AUTHORIZATION_INFO = "overview:authorizationInfo";
+
+    /**
+     * 分析概览-今日
+     */
+    public static final String DATA_OVERVIEW_DEALER_ANALYSISPREVIEW = "overview:AnalysisPreviewDTO";
+
+    /**
+     * 会员观看、完播人数趋势图
+     */
+    public static final String DATA_OVERVIEW_DEALER_CHARTS = "charts:dealer:charts";
+
+
+    /**
+     * 经销商会员观看TOP10 - 按观看人数
+     */
+    public static final String CHARTS_MEMBER_TOP_TEN_WATCH = "charts:memeber:top10:watch:user:count";
+    /**
+     * 课程观看TOP10
+     */
+    public static final String CHARTS_WATCH_TOP_TEN = "charts:watch:top10";
+    /**
+     * 答题红包金额TOP10
+     */
+    public static final String CHARTS_REWARD_MONEY_TOP_TEN = "charts:reward:money:top10";
+    /**
+     * 答题红包金额趋势图
+     */
+    public static final String CHARTS_REWARD_MONEY_TREND = "charts:reward:money:trend";
+
+    /**
+     * 本月订单数统计
+     */
+    public static final String THIS_MONTH_ORDER_COUNT = "charts:this:month:order:count";
+
+    /**
+     * 本月收款数统计
+     */
+    public static final String THIS_MONTH_RECV_COUNT = "charts:this:month:recv:count";
+}

+ 105 - 0
fs-service/src/main/java/com/fs/statis/domain/FsStatisEveryDayWatch.java

@@ -0,0 +1,105 @@
+package com.fs.statis.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * 每日统计数据实体类
+ * 对应表 fs_statis_every_day_watch
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class FsStatisEveryDayWatch {
+
+    /**
+     * 主键ID
+     */
+    private Integer id;
+
+    /**
+     * 数据日期
+     */
+    private LocalDateTime dataDate;
+
+    /**
+     * 训练营id
+     */
+    private Integer periodId;
+
+    /**
+     * 训练营人数
+     */
+    private Integer periodNum;
+
+    /**
+     * 未报名人数
+     */
+    private Integer notRegNum;
+
+    /**
+     * 已报名人数
+     */
+    private Integer registeredNum;
+
+    /**
+     * 报名率
+     */
+    private Float regRate;
+
+    /**
+     * 完课率
+     */
+    private Float completedRate;
+
+    /**
+     * 未上线-总数
+     */
+    private Integer offlineTotal;
+
+    /**
+     * 未上线-未参与
+     */
+    private Integer offlineNotRegNum;
+
+    /**
+     * 未上线-未观看
+     */
+    private Integer offlineNotWatchNum;
+
+    /**
+     * 已上线-总数
+     */
+    private Integer onlineTotal;
+
+    /**
+     * 已上线-上线率
+     */
+    private Float onlineRate;
+
+    /**
+     * 已上线-完播率
+     */
+    private Float onlineCompletedRate;
+
+    /**
+     * 已上线-未完播
+     */
+    private Integer onlineNotCompRateNum;
+
+    /**
+     * 已上线-已完播
+     */
+    private Integer onlineCompletedNum;
+
+    /**
+     * 销售id
+     */
+    private Integer companyUserId;
+
+}

+ 108 - 0
fs-service/src/main/java/com/fs/statis/domain/FsStatisPeriodWatch.java

@@ -0,0 +1,108 @@
+package com.fs.statis.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+/**
+ * fs_statis_period_watch表 实体类
+ *
+ * @author AutoGenerator
+ * @since now
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class FsStatisPeriodWatch {
+
+    /**
+     * 主键ID (虽然注释中没有,但通常id为主键)
+     */
+    private Integer id;
+
+    /**
+     * 训练营id
+     */
+    private Integer periodId;
+
+    /**
+     * 训练营人数
+     */
+    private Integer periodNum;
+
+    /**
+     * 未报名人数
+     */
+    private Integer notRegNum;
+
+    /**
+     * 已报名人数
+     */
+    private Integer registeredNum;
+
+    /**
+     * 报名率
+     */
+    private Float regRate;
+
+    /**
+     * 完课率
+     */
+    private Float watchCompletedRate;
+
+    /**
+     * 未上线-总数
+     */
+    private Integer offlineTotal;
+
+    /**
+     * 未上线-未参与
+     */
+    private Integer offlineNotRegNum;
+
+    /**
+     * 未上线-未观看
+     */
+    private Integer offlineNotWatchNum;
+
+    /**
+     * 已上线-总数
+     */
+    private Integer onlineTotal;
+
+    /**
+     * 已上线-上线率
+     */
+    private Float onlineRate;
+
+    /**
+     * 已上线-上线完播率
+     */
+    private Float onlineWatchCompletedRate;
+
+    /**
+     * 已上线-未完播
+     */
+    private Integer onlineWatchNotCompleted;
+
+    /**
+     * 已上线-已完播
+     */
+    private Integer onlineWatchCompleted;
+
+    /**
+     * 数据日期
+     */
+    private Date dataDate;
+
+
+    /**
+     * 销售id
+     */
+    private Long companyUserId;
+
+}

+ 112 - 0
fs-service/src/main/java/com/fs/statis/domain/FsStatisSalerWatch.java

@@ -0,0 +1,112 @@
+package com.fs.statis.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+
+/**
+ * 销售观看统计实体类
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class FsStatisSalerWatch {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 部门
+     */
+    private Long deptId;
+
+    /**
+     * 销售id
+     */
+    private Long companyUserId;
+
+    /**
+     * 训练营人数
+     */
+    private Long trainCampNum;
+
+    /**
+     * 未报名人数
+     */
+    private Long notRegisteredNum;
+
+    /**
+     * 已报名人数
+     */
+    private Long registeredNum;
+    /**
+     * 完课人数
+     */
+    private Long completedNum;
+
+    /**
+     * 报名率
+     */
+    private Float regRate;
+
+    /**
+     * 完课率
+     */
+    private Float finishedRate;
+
+    /**
+     * 未上线-总数
+     */
+    private Long offlineTotal;
+
+    /**
+     * 未上线-未参与
+     */
+    private Long offlineNotPart;
+
+    /**
+     * 未上线-未观看 (原SQL注释为'为观看',推测应为'未观看')
+     */
+    private Long offlineNotWatched;
+
+    /**
+     * 已上线-总数
+     */
+    private Long onlineTotal;
+
+    /**
+     * 已上线-上线率
+     */
+    private Float onlineOnlineRate;
+
+    /**
+     * 已上线-完播率
+     */
+    private Float onlinePlaybackCompleRate;
+
+    /**
+     * 已上线-未完播
+     */
+    private Long onlineIncompletePlayback;
+
+    /**
+     * 已上线-已完播
+     */
+    private Long onlineCompletePlayback;
+
+    /**
+     * 训练营id
+     */
+    private Long periodId;
+
+    /**
+     * 数据日期
+     */
+    private LocalDate dataDate;
+}

+ 149 - 0
fs-service/src/main/java/com/fs/statis/domain/FsStatsMemberDaily.java

@@ -0,0 +1,149 @@
+package com.fs.statis.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.time.LocalDate;
+
+@Data
+@TableName("fs_stats_member_daily")
+public class FsStatsMemberDaily {
+
+    /**
+     * 主键ID
+     */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 统计时间
+     */
+    private LocalDate statDate;
+
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+    /**
+     * 用户昵称
+     */
+    private String nickName;
+
+    /**
+     * 用户姓名
+     */
+    private String realName;
+
+    /**
+     * 用户手机号
+     */
+    private String phone;
+
+    /**
+     * 用户标签
+     */
+    private String tag;
+
+    /**
+     * 所属经销商分组
+     */
+    private Long companyGroupId;
+
+    /**
+     * 所属经销商
+     */
+    private Long companyId;
+
+    /**
+     * 所属经销商名称
+     */
+    private String companyName;
+
+    /**
+     * 所属群管
+     */
+    private Long companyUserId;
+
+    /**
+     * 所属群管名称
+     */
+    private String companyUserName;
+
+    /**
+     * 所属训练营
+     */
+    private Long trainCampId;
+
+    /**
+     * 所属训练营名称
+     */
+    private String trainCampName;
+
+    /**
+     * 所属营期
+     */
+    private Long periodId;
+
+    /**
+     * 所属营期名称
+     */
+    private String periodName;
+
+    /**
+     * 所属课程
+     */
+    private Long courseId;
+
+    /**
+     * 所属课程名称
+     */
+    private String courseName;
+
+    /**
+     * 所属小节
+     */
+    private Long videoId;
+
+    /**
+     * 所属小节名称
+     */
+    private String videoName;
+
+    /**
+     * 是否完课 0未完课 1已完课
+     */
+    private Integer isOver;
+
+    /**
+     * 观看次数
+     */
+    private Long watchCount;
+
+    /**
+     * 观看时长
+     */
+    private Long watchDuration;
+
+    /**
+     * 答题次数
+     */
+    private Long answerCount;
+
+    /**
+     * 正确次数
+     */
+    private Long answerCorrectCount;
+
+    /**
+     * 答题红包个数
+     */
+    private Long redPacketCount;
+
+    /**
+     * 答题红包金额
+     */
+    private Long redPacketAmount;
+}

+ 91 - 0
fs-service/src/main/java/com/fs/statis/dto/AnalysisPreviewDTO.java

@@ -0,0 +1,91 @@
+package com.fs.statis.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 用户活动统计数据传输对象
+ * <p>
+ * 该类用于封装和传输用户活动相关的统计数据,
+ * 包括观看人数、完成人数、完成率、观看次数、完成次数、
+ * 答题人数、答对人数、正确率、奖励次数和奖励金额等信息。
+ * </p>
+ *
+ * @author xdd
+ * @date 2025-02-27
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class AnalysisPreviewDTO implements Serializable {
+
+    /**
+     * 观看人数
+     * <p>统计周期内,观看了活动内容的不重复用户数量。</p>
+     */
+    private long watchUserCount;
+
+    /**
+     * 完播人数
+     * <p>统计周期内,完成了指定活动目标的不重复用户数量。</p>
+     */
+    private long completedUserCount;
+
+    /**
+     * 完播率
+     * <p>通常指 完成用户数 / 观看用户数 * 100%。注意:此处原始数据类型为字符串,可能需要业务层进行转换或特殊处理。</p>
+     */
+    private String completedRate;
+
+    /**
+     * 观看次数
+     * <p>统计周期内,活动内容被观看的总次数(可能包含重复观看)。</p>
+     */
+    private long watchCount;
+
+    /**
+     * 完播次数
+     * <p>统计周期内,活动目标被完成的总次数。</p>
+     */
+    private long completedCount;
+
+    /**
+     * 视频完播率
+     */
+    private String watchRate;
+
+    /**
+     * 答题人数 (或参与成员数)
+     * <p>统计周期内,参与了答题环节的不重复用户数量。</p>
+     */
+    private long answerMemberCount;
+
+    /**
+     * 正确人数
+     * <p>统计周期内,至少答对一题的不重复用户数量(具体定义需根据业务确认)。</p>
+     */
+    private long correctUserCount;
+
+    /**
+     * 正确率
+     * <p>通常指 答对题目总数 / 回答题目总数 * 100% 或其他业务定义。注意:此处原始数据类型为字符串,可能需要业务层进行转换或特殊处理。</p>
+     */
+    private String correctRate;
+
+    /**
+     * 答题红包个数
+     * <p>统计周期内,发放奖励的总次数或总数量。</p>
+     */
+    private long rewardCount;
+
+    /**
+     * 答题红包金额(元)
+     * <p>统计周期内,发放奖励的总金额。具体单位(如元、分)需根据业务确定。</p>
+     */
+    private BigDecimal rewardMoney;
+
+}

+ 50 - 0
fs-service/src/main/java/com/fs/statis/dto/AnalysisPreviewQueryDTO.java

@@ -0,0 +1,50 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+@Data
+@Setter
+public class AnalysisPreviewQueryDTO implements Serializable {
+
+    /**
+     * 0 今日,1昨日,2本周,3本月,4上月
+     */
+    private Integer type;
+
+    /**
+     * 0 观看人数,1 完播人数,2 答题人数,3 正确人数
+     */
+    private Integer statisticalType;
+    /**
+     * 开始时间
+     */
+    private String startTime;
+    /**
+     * 结束时间
+     */
+    private String endTime;
+
+    /**
+     * 排序 DESC ASC
+     */
+    private String sort;
+
+    /**
+     * 0 按公司统计 1 按课程统计
+     */
+    private Integer dataType;
+
+    /**
+     * 0 用户 1 企微
+     */
+    private Integer userType;
+
+    /**
+     * 公司id
+     */
+    private Long companyId;
+
+}

+ 17 - 0
fs-service/src/main/java/com/fs/statis/dto/AuthorizationInfoDTO.java

@@ -0,0 +1,17 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class AuthorizationInfoDTO implements Serializable {
+    /**
+     * 平台今日看课人数
+     */
+    private Long todayWatchUserCount;
+    /**
+     * 版本上限
+     */
+    private Long versionLimit;
+}

+ 29 - 0
fs-service/src/main/java/com/fs/statis/dto/ConsumptionBalanceDataDTO.java

@@ -0,0 +1,29 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 消费余额
+ */
+@Data
+public class ConsumptionBalanceDataDTO implements Serializable {
+    /**
+     * 当前账户余额。
+     * 数值表示,单位可能是分或其他约定单位。
+     */
+    private BigDecimal balance;
+    /**
+     * 今日消费金额。
+     * 当天的总消费数额。
+     */
+    private BigDecimal todayComsumption;
+    /**
+     * 昨日消费金额。
+     * 昨天的总消费数额。
+     */
+    private BigDecimal yesterdayComsumption;
+
+}

+ 63 - 0
fs-service/src/main/java/com/fs/statis/dto/CourseStatsDTO.java

@@ -0,0 +1,63 @@
+package com.fs.statis.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 课程统计数据传输对象 (DTO).
+ * <p>
+ * 用于封装课程相关的用户统计数据,如观看人数、完成人数等,以及课程的基本信息。
+ * </p>
+ *
+ * @author xdd
+ * @since 2025-02-27 // 通常使用 @since 标记版本或首次添加日期
+ * @version 1.0
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class CourseStatsDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L; // Serializable 建议添加 serialVersionUID
+
+    /**
+     * 观看用户数
+     * <p>统计有多少不同的用户观看了该课程(或其部分内容)。</p>
+     */
+    private Integer watchUserCount;
+
+    /**
+     * 完成用户数
+     * <p>统计有多少不同的用户完成了该课程的学习要求。</p>
+     */
+    private Integer completedUserCount;
+
+    /**
+     * 答题用户数
+     * <p>统计有多少不同的用户参与了该课程相关的答题活动。</p>
+     */
+    private Integer answerUserCount;
+
+    /**
+     * 答对用户数
+     * <p>统计有多少不同的用户在答题活动中至少答对了一定数量或比例的题目(具体定义取决于业务逻辑)。</p>
+     * <p><b>注意:</b>也可能指完全答对所有题目的用户数,需根据实际业务场景确认。</p>
+     */
+    private Integer correctUserCount;
+
+    /**
+     * 课程ID
+     * <p>课程的唯一标识符。</p>
+     */
+    private Long courseId; // 假设课程ID是长整型,如果可能是其他类型(如String),请修改
+
+    /**
+     * 课程名称
+     * <p>课程的标题或名称。</p>
+     */
+    private String courseName;
+
+}

+ 22 - 0
fs-service/src/main/java/com/fs/statis/dto/DeaMemberTopTenDTO.java

@@ -0,0 +1,22 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class DeaMemberTopTenDTO implements Serializable {
+    /**
+     * 公司id
+     */
+    private Long companyId;
+    /**
+     * 公司名称
+     */
+    private String companyName;
+
+    /**
+     * 观看人数
+     */
+    private Long watchUserCount;
+}

+ 70 - 0
fs-service/src/main/java/com/fs/statis/dto/DealerAggregatedDTO.java

@@ -0,0 +1,70 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class DealerAggregatedDTO implements Serializable {
+    /**
+     * 经销商数量
+     */
+    private Long dealderCount;
+    /**
+     * 群管数量
+     */
+    private Long groupMgrCount;
+    /**
+     * 会员总数量
+     */
+    private Long memberCount;
+    /**
+     * 正常会员数量
+     */
+    private Long normalNum;
+    /**
+     * 黑名单会员数量
+     */
+    private Long blackNum;
+
+    /**
+     * 企微用户数
+     */
+    private Long qwMemberNum;
+
+    /**
+     * 今日新增
+     */
+    private Long todayIncreaseUserNum;
+
+    /**
+     * 订单总数
+     */
+    private Long orderTotalNum;
+
+    /**
+     * 今日新增订单数
+     */
+    private Long todayOrderNum;
+
+    /**
+     * 收款总数
+     */
+    private Long recvTotalNum;
+
+    /**
+     * 今日收款总数
+     */
+    private Long recvTodayNum;
+
+    /**
+     * 商品总数
+     */
+    private Long goodsTotalNum;
+
+    /**
+     * 今日商品总数
+     */
+    private Long todayGoodsNum;
+
+}

+ 29 - 0
fs-service/src/main/java/com/fs/statis/dto/ModifyMoreDTO.java

@@ -0,0 +1,29 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 批量修改商品
+ */
+@Data
+public class ModifyMoreDTO implements Serializable {
+    /**
+     * 产品id
+     */
+    private List<Long> productId;
+    /**
+     * 产品状态
+     */
+    private Integer goodsStatus;
+    /**
+     * 是否显示
+     */
+    private Integer goodsIsShow;
+    /**
+     * 公司id
+     */
+    private String companyIds;
+}

+ 15 - 0
fs-service/src/main/java/com/fs/statis/dto/RewardMoneyTopTenDTO.java

@@ -0,0 +1,15 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class RewardMoneyTopTenDTO implements Serializable {
+    private Long courseId;
+    private String courseName;
+    private Long companyId;
+    private String companyName;
+    private BigDecimal rewardMoney;
+}

+ 13 - 0
fs-service/src/main/java/com/fs/statis/dto/RewardMoneyTrendDTO.java

@@ -0,0 +1,13 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class RewardMoneyTrendDTO implements Serializable {
+    private BigDecimal rewardMoney;
+    private String x;
+    private String startDate;
+}

+ 30 - 0
fs-service/src/main/java/com/fs/statis/dto/StatsWatchLogPageListDTO.java

@@ -0,0 +1,30 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class StatsWatchLogPageListDTO implements Serializable {
+
+    /**
+     * 员工列表
+     */
+    private List<String> userIds;
+
+    /**
+     * 开始时间
+     */
+    private String startDate;
+    /**
+     * 结束世界
+     */
+    private String endDate;
+
+    /**
+     * 营期列表
+     */
+    private List<String> periodList;
+
+}

+ 25 - 0
fs-service/src/main/java/com/fs/statis/dto/TrafficLogDTO.java

@@ -0,0 +1,25 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 获取统计流量
+ */
+@Data
+public class TrafficLogDTO implements Serializable {
+
+    /**
+     * 昨天
+     */
+    private Long yesterday;
+    /**
+     * 今日流量
+     */
+    private Long today;
+    /**
+     * 本月流量
+     */
+    private Long thisMonth;
+}

+ 29 - 0
fs-service/src/main/java/com/fs/statis/dto/WatchEndPlayTrendDTO.java

@@ -0,0 +1,29 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 会员观看、完播人数趋势图
+ */
+@Data
+public class WatchEndPlayTrendDTO implements Serializable {
+
+    /**
+     * 日期 如果是今日,昨日,都是小时
+     */
+    private String startDate;
+    /**
+     * x轴
+     */
+    private String x;
+    /**
+     * 总数
+     */
+    private Long watchUserCount;
+    /**
+     * 完播数
+     */
+    private Long completedUserCount;
+}

+ 128 - 0
fs-service/src/main/java/com/fs/statis/mapper/ConsumptionBalanceMapper.java

@@ -0,0 +1,128 @@
+package com.fs.statis.mapper;
+
+import com.fs.statis.dto.*;
+import org.apache.ibatis.annotations.Param;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+public interface ConsumptionBalanceMapper {
+    /**
+     * 分析概览 - 经销商统计
+     */
+    AnalysisPreviewDTO analysisPreview(AnalysisPreviewQueryDTO queryDTO);
+
+    /**
+     * 消费余额
+     */
+    ConsumptionBalanceDataDTO rechargeConsumption();
+
+    DealerAggregatedDTO dealerAggregated();
+    DealerAggregatedDTO dealerAggregatedCompanyId(@Param("companyId") Long companyId);
+
+    /**
+     * 观看人数
+     * @param queryDTO 请求参数
+     * @return 观看人数
+     */
+    Long queryWatchUserCount(AnalysisPreviewQueryDTO queryDTO);
+
+    /**
+     * 完播人数
+     * @param queryDTO 请求参数
+     * @return  完播人数
+     */
+    Long queryCompletedUserCount(AnalysisPreviewQueryDTO queryDTO);
+
+    /**
+     * 观看次数
+     * @param queryDTO 请求参数
+     * @return 观看次数
+     */
+    Long queryWatchCount(AnalysisPreviewQueryDTO queryDTO);
+
+    /**
+     * 完播次数
+     * @param queryDTO 请求参数
+     * @return 完播次数
+     */
+    Long queryCompletedCount(AnalysisPreviewQueryDTO queryDTO);
+
+    /**
+     * 答题人数
+     * @param queryDTO 请求参数
+     * @return 答题人数
+     */
+    Long queryAnswerMemberCount(AnalysisPreviewQueryDTO queryDTO);
+
+
+    /**
+     * 正确人数
+     * @param queryDTO 请求参数
+     * @return 正确人数
+     */
+    Long queryCorrectUserCount(AnalysisPreviewQueryDTO queryDTO);
+
+    /**
+     * 答题红包个数
+     * @param queryDTO 请求参数
+     * @return 奖励人数
+     * @return
+     */
+    Long queryRewardCount(AnalysisPreviewQueryDTO queryDTO);
+
+    /**
+     * 答题红包金额
+     * @param queryDTO 请求参数
+     * @return 奖励金额
+     */
+    BigDecimal queryRewardMoney(AnalysisPreviewQueryDTO queryDTO);
+
+    /**
+     * 短信余额
+     * @return 短信余额
+     */
+    Long smsBalance();
+
+    AuthorizationInfoDTO authorizationInfo();
+
+    /**
+     * 会员观看、完播人数趋势图
+     * @param param 请求参数
+     * @return 观看完播趋势
+     */
+    List<WatchEndPlayTrendDTO> watchEndPlayTrend(AnalysisPreviewQueryDTO param);
+
+    /**
+     * 经销商会员观看TOP10
+     * @param param 请求参数
+     * @return TOP10
+     */
+    List<DeaMemberTopTenDTO> deaMemberTopTen(AnalysisPreviewQueryDTO param);
+
+    /**
+     * 课程观看TOP10
+     * @param param 请求参数
+     * @return TOP10
+     */
+    List<CourseStatsDTO> watchCourseTopTen(AnalysisPreviewQueryDTO param);
+
+    /**
+     * 奖励金额TOP10
+     * @param param 请求参数
+     * @return TOP10
+     */
+    List<RewardMoneyTopTenDTO> rewardMoneyTopTen(AnalysisPreviewQueryDTO param);
+
+    /**
+     * 奖励金额趋势
+     * @param param 请求参数
+     * @return 趋势
+     */
+    List<RewardMoneyTrendDTO> rewardMoneyTrendDTO(AnalysisPreviewQueryDTO param);
+
+    BigDecimal getCurrentBalance();
+    BigDecimal getCurrentBalanceCompanyId(@Param("companyId") Long companyId);
+
+    Long smsBalanceCompany(@Param("companyId") Long companyId);
+}

+ 87 - 0
fs-service/src/main/java/com/fs/statis/mapper/FsStatisEveryDayWatchMapper.java

@@ -0,0 +1,87 @@
+package com.fs.statis.mapper;
+
+import com.fs.statis.domain.FsStatisEveryDayWatch;
+import com.fs.statis.domain.FsStatisSalerWatch;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+/**
+ * 每日统计数据Mapper接口
+ */
+@Mapper
+public interface FsStatisEveryDayWatchMapper {
+
+    /**
+     * 根据主键ID查询每日统计数据
+     * @param id 主键ID
+     * @return 每日统计数据对象,如果不存在则返回null
+     */
+    @Select("SELECT id, data_date AS dataDate, period_id AS periodId, period_num AS periodNum, " +
+            "not_reg_num AS notRegNum, registered_num AS registeredNum, reg_rate AS regRate, " +
+            "completed_rate AS completedRate, offline_total AS offlineTotal, " +
+            "offline_not_reg_num AS offlineNotRegNum, offline_not_watch_num AS offlineNotWatchNum, " +
+            "online_total AS onlineTotal, online_rate AS onlineRate, " +
+            "online_completed_rate AS onlineCompletedRate, online_not_comp_rate_num AS onlineNotCompRateNum, " +
+            "online_completed_num AS onlineCompletedNum, company_user_id AS companyUserId " +
+            "FROM fs_statis_every_day_watch WHERE id = #{id}")
+    FsStatisEveryDayWatch findById(@Param("id") Integer id);
+
+    /**
+     * 新增每日统计数据
+     * @param fsStatisEveryDayWatch 待插入的每日统计数据对象
+     * @return 影响的行数
+     */
+    @Insert("INSERT INTO fs_statis_every_day_watch (id, data_date, period_id, period_num, not_reg_num, " +
+            "registered_num, reg_rate, completed_rate, offline_total, offline_not_reg_num, " +
+            "offline_not_watch_num, online_total, online_rate, online_completed_rate, " +
+            "online_not_comp_rate_num, online_completed_num, company_user_id) " +
+            "VALUES (#{id}, #{dataDate}, #{periodId}, #{periodNum}, #{notRegNum}, #{registeredNum}, " +
+            "#{regRate}, #{completedRate}, #{offlineTotal}, #{offlineNotRegNum}, #{offlineNotWatchNum}, " +
+            "#{onlineTotal}, #{onlineRate}, #{onlineCompletedRate}, #{onlineNotCompRateNum}, " +
+            "#{onlineCompletedNum}, #{companyUserId})")
+    int insert(FsStatisEveryDayWatch fsStatisEveryDayWatch);
+
+    /**
+     * 更新每日统计数据
+     * @param fsStatisEveryDayWatch 待更新的每日统计数据对象 (必须包含ID)
+     * @return 影响的行数
+     */
+    @Update("UPDATE fs_statis_every_day_watch SET " +
+            "data_date = #{dataDate}, " +
+            "period_id = #{periodId}, " +
+            "period_num = #{periodNum}, " +
+            "not_reg_num = #{notRegNum}, " +
+            "registered_num = #{registeredNum}, " +
+            "reg_rate = #{regRate}, " +
+            "completed_rate = #{completedRate}, " +
+            "offline_total = #{offlineTotal}, " +
+            "offline_not_reg_num = #{offlineNotRegNum}, " +
+            "offline_not_watch_num = #{offlineNotWatchNum}, " +
+            "online_total = #{onlineTotal}, " +
+            "online_rate = #{onlineRate}, " +
+            "online_completed_rate = #{onlineCompletedRate}, " +
+            "online_not_comp_rate_num = #{onlineNotCompRateNum}, " +
+            "online_completed_num = #{onlineCompletedNum}, " +
+            "company_user_id = #{companyUserId} " +
+            "WHERE id = #{id}")
+    int update(FsStatisEveryDayWatch fsStatisEveryDayWatch);
+
+    /**
+     * 查询所有每日统计数据 (示例,根据需要添加更多查询方法)
+     * @return 每日统计数据列表
+     */
+    @Select("SELECT id, data_date AS dataDate, period_id AS periodId, period_num AS periodNum, " +
+            "not_reg_num AS notRegNum, registered_num AS registeredNum, reg_rate AS regRate, " +
+            "completed_rate AS completedRate, offline_total AS offlineTotal, " +
+            "offline_not_reg_num AS offlineNotRegNum, offline_not_watch_num AS offlineNotWatchNum, " +
+            "online_total AS onlineTotal, online_rate AS onlineRate, " +
+            "online_completed_rate AS onlineCompletedRate, online_not_comp_rate_num AS onlineNotCompRateNum, " +
+            "online_completed_num AS onlineCompletedNum, company_user_id AS companyUserId " +
+            "FROM fs_statis_every_day_watch")
+    List<FsStatisEveryDayWatch> findAll();
+
+    List<FsStatisSalerWatch> queryList(StatsWatchLogPageListDTO param);
+
+}

+ 94 - 0
fs-service/src/main/java/com/fs/statis/mapper/FsStatisPeriodWatchMapper.java

@@ -0,0 +1,94 @@
+package com.fs.statis.mapper;
+
+import com.fs.statis.domain.FsStatisPeriodWatch;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+/**
+ * fs_statis_period_watch表 Mapper 接口
+ *
+ * @author AutoGenerator
+ * @since now
+ */
+@Mapper
+public interface FsStatisPeriodWatchMapper {
+
+    /**
+     * 根据主键查询数据
+     *
+     * @param id 主键
+     * @return 实体对象
+     */
+    @Select("SELECT id, period_id, period_num, not_reg_num, registered_num, reg_rate, " +
+            "watch_completed_rate, offline_total, offline_not_reg_num, offline_not_watch_num, " +
+            "online_total, online_rate, online_watch_completed_rate, online_watch_not_completed, " +
+            "online_watch_completed, data_date " +
+            "FROM fs_statis_period_watch WHERE id = #{id}")
+    FsStatisPeriodWatch selectById(@Param("id") Integer id);
+
+    /**
+     * 新增数据
+     *
+     * @param fsStatisPeriodWatch 实体对象
+     * @return 影响行数
+     */
+    @Insert("INSERT INTO fs_statis_period_watch (id, period_id, period_num, not_reg_num, registered_num, " +
+            "reg_rate, watch_completed_rate, offline_total, offline_not_reg_num, offline_not_watch_num, " +
+            "online_total, online_rate, online_watch_completed_rate, online_watch_not_completed, " +
+            "online_watch_completed, data_date) " +
+            "VALUES (#{id}, #{periodId}, #{periodNum}, #{notRegNum}, #{registeredNum}, #{regRate}, " +
+            "#{watchCompletedRate}, #{offlineTotal}, #{offlineNotRegNum}, #{offlineNotWatchNum}, " +
+            "#{onlineTotal}, #{onlineRate}, #{onlineWatchCompletedRate}, #{onlineWatchNotCompleted}, " +
+            "#{onlineWatchCompleted}, #{dataDate})")
+    // 如果id是自增的,可以加上 @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn="id")
+    int insert(FsStatisPeriodWatch fsStatisPeriodWatch);
+
+    /**
+     * 根据主键更新数据
+     *
+     * @param fsStatisPeriodWatch 实体对象
+     * @return 影响行数
+     */
+    @Update("<script>" +
+            "UPDATE fs_statis_period_watch " +
+            "<set>" +
+            "  <if test='periodId != null'>period_id = #{periodId},</if>" +
+            "  <if test='periodNum != null'>period_num = #{periodNum},</if>" +
+            "  <if test='notRegNum != null'>not_reg_num = #{notRegNum},</if>" +
+            "  <if test='registeredNum != null'>registered_num = #{registeredNum},</if>" +
+            "  <if test='regRate != null'>reg_rate = #{regRate},</if>" +
+            "  <if test='watchCompletedRate != null'>watch_completed_rate = #{watchCompletedRate},</if>" +
+            "  <if test='offlineTotal != null'>offline_total = #{offlineTotal},</if>" +
+            "  <if test='offlineNotRegNum != null'>offline_not_reg_num = #{offlineNotRegNum},</if>" +
+            "  <if test='offlineNotWatchNum != null'>offline_not_watch_num = #{offlineNotWatchNum},</if>" +
+            "  <if test='onlineTotal != null'>online_total = #{onlineTotal},</if>" +
+            "  <if test='onlineRate != null'>online_rate = #{onlineRate},</if>" +
+            "  <if test='onlineWatchCompletedRate != null'>online_watch_completed_rate = #{onlineWatchCompletedRate},</if>" +
+            "  <if test='onlineWatchNotCompleted != null'>online_watch_not_completed = #{onlineWatchNotCompleted},</if>" +
+            "  <if test='onlineWatchCompleted != null'>online_watch_completed = #{onlineWatchCompleted},</if>" +
+            "  <if test='dataDate != null'>data_date = #{dataDate},</if>" +
+            "</set>" +
+            "WHERE id = #{id}" +
+            "</script>")
+    int updateById(FsStatisPeriodWatch fsStatisPeriodWatch);
+
+    /**
+     * 根据主键删除数据
+     *
+     * @param id 主键
+     * @return 影响行数
+     */
+    @Delete("DELETE FROM fs_statis_period_watch WHERE id = #{id}")
+    int deleteById(@Param("id") Integer id);
+
+    /**
+     * 查询所有数据
+     *
+     * @return 实体对象列表
+     */
+    List<FsStatisPeriodWatch> selectAll();
+
+    List<FsStatisPeriodWatch> queryList(StatsWatchLogPageListDTO param);
+}

+ 80 - 0
fs-service/src/main/java/com/fs/statis/mapper/FsStatisSalerWatchMapper.java

@@ -0,0 +1,80 @@
+package com.fs.statis.mapper;
+
+import com.fs.statis.domain.FsStatisSalerWatch;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+/**
+ * 销售观看统计Mapper接口
+ */
+@Mapper
+public interface FsStatisSalerWatchMapper {
+
+    /**
+     * 根据ID查询销售观看统计
+     * @param id 主键ID
+     * @return 销售观看统计对象
+     */
+    @Select("SELECT * FROM fs_statis_saler_watch WHERE id = #{id}")
+    FsStatisSalerWatch findById(@Param("id") Integer id);
+
+    /**
+     * 查询所有销售观看统计
+     * @return 销售观看统计列表
+     */
+    @Select("SELECT * FROM fs_statis_saler_watch")
+    List<FsStatisSalerWatch> findAll();
+
+    /**
+     * 新增销售观看统计
+     * @param fsStatisSalerWatch 销售观看统计对象
+     * @return 受影响的行数
+     */
+    @Insert("INSERT INTO fs_statis_saler_watch (dept_id, company_user_id, train_camp_num, not_registered_num, " +
+            "registered_num, reg_rate, finished_rate, offline_total, offline_not_part, offline_not_watched, " +
+            "online_total, online_online_rate, online_playback_comple_rate, online_incomplete_playback, " +
+            "online_complete_playback) " +
+            "VALUES (#{deptId}, #{companyUserId}, #{trainCampNum}, #{notRegisteredNum}, #{registeredNum}, " +
+            "#{regRate}, #{finishedRate}, #{offlineTotal}, #{offlineNotPart}, #{offlineNotWatched}, #{onlineTotal}, " +
+            "#{onlineOnlineRate}, #{onlinePlaybackCompleRate}, #{onlineIncompletePlayback}, #{onlineCompletePlayback})")
+    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
+    int insert(FsStatisSalerWatch fsStatisSalerWatch);
+
+    /**
+     * 更新销售观看统计
+     * @param fsStatisSalerWatch 销售观看统计对象
+     * @return 受影响的行数
+     */
+    @Update("UPDATE fs_statis_saler_watch SET " +
+            "dept_id = #{deptId}, " +
+            "company_user_id = #{companyUserId}, " +
+            "train_camp_num = #{trainCampNum}, " +
+            "not_registered_num = #{notRegisteredNum}, " +
+            "registered_num = #{registeredNum}, " +
+            "reg_rate = #{regRate}, " +
+            "finished_rate = #{finishedRate}, " +
+            "offline_total = #{offlineTotal}, " +
+            "offline_not_part = #{offlineNotPart}, " +
+            "offline_not_watched = #{offlineNotWatched}, " +
+            "online_total = #{onlineTotal}, " +
+            "online_online_rate = #{onlineOnlineRate}, " +
+            "online_playback_comple_rate = #{onlinePlaybackCompleRate}, " +
+            "online_incomplete_playback = #{onlineIncompletePlayback}, " +
+            "online_complete_playback = #{onlineCompletePlayback} " +
+            "WHERE id = #{id}")
+    int update(FsStatisSalerWatch fsStatisSalerWatch);
+
+    /**
+     * 根据ID删除销售观看统计
+     * @param id 主键ID
+     * @return 受影响的行数
+     */
+    @Delete("DELETE FROM fs_statis_saler_watch WHERE id = #{id}")
+    int deleteById(@Param("id") Integer id);
+
+    List<FsStatisSalerWatch> queryList(StatsWatchLogPageListDTO param);
+
+    void batchSave(@Param("list") List<FsStatisSalerWatch> writeData);
+}

+ 26 - 0
fs-service/src/main/java/com/fs/statis/mapper/FsStatsMemberDailyMapper.java

@@ -0,0 +1,26 @@
+package com.fs.statis.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.statis.domain.FsStatsMemberDaily;
+import com.fs.statis.vo.FsStatsMemberDailyVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Map;
+
+public interface FsStatsMemberDailyMapper extends BaseMapper<FsStatsMemberDaily> {
+
+    /**
+     * 查询会员统计数据
+     * @param params    参数
+     * @return  list
+     */
+    List<FsStatsMemberDailyVO> selectDailyData(@Param("params") Map<String, Object> params);
+
+    /**
+     * 更新统计数据
+     * @param date 日期
+     */
+    void refreshMemberDailyData(@Param("date") LocalDate date);
+}

+ 47 - 0
fs-service/src/main/java/com/fs/statis/service/FsStatisEveryDayWatchService.java

@@ -0,0 +1,47 @@
+package com.fs.statis.service;
+
+import com.fs.statis.domain.FsStatisEveryDayWatch;
+import com.fs.statis.domain.FsStatisSalerWatch;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
+
+import java.util.List;
+
+/**
+ * 每日统计数据服务接口
+ */
+public interface FsStatisEveryDayWatchService {
+
+    /**
+     * 根据主键ID查询每日统计数据
+     *
+     * @param id 主键ID
+     * @return 每日统计数据对象,如果不存在则返回null
+     */
+    FsStatisEveryDayWatch findById(Integer id);
+
+    /**
+     * 新增每日统计数据
+     *
+     * @param fsStatisEveryDayWatch 待插入的每日统计数据对象
+     * @return 影响的行数,通常是1表示成功
+     */
+    int create(FsStatisEveryDayWatch fsStatisEveryDayWatch);
+
+    /**
+     * 更新每日统计数据
+     *
+     * @param fsStatisEveryDayWatch 待更新的每日统计数据对象 (必须包含ID)
+     * @return 影响的行数,通常是1表示成功,0表示未找到对应记录
+     */
+    int update(FsStatisEveryDayWatch fsStatisEveryDayWatch);
+
+    /**
+     * 查询所有每日统计数据
+     *
+     * @return 每日统计数据列表
+     */
+    List<FsStatisEveryDayWatch> findAll();
+
+    List<FsStatisSalerWatch> queryList(StatsWatchLogPageListDTO param);
+
+}

+ 56 - 0
fs-service/src/main/java/com/fs/statis/service/FsStatisPeriodWatchService.java

@@ -0,0 +1,56 @@
+package com.fs.statis.service; // 假设Service接口放在此包下
+
+import com.fs.statis.domain.FsStatisPeriodWatch;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
+
+import java.util.List;
+
+/**
+ * 训练营周期统计数据服务接口
+ * 对应表 fs_statis_period_watch
+ */
+public interface FsStatisPeriodWatchService {
+
+    /**
+     * 根据主键ID查询训练营周期统计数据
+     *
+     * @param id 主键ID
+     * @return 训练营周期统计数据对象,如果不存在则返回null
+     */
+    FsStatisPeriodWatch findById(Integer id);
+
+    /**
+     * 新增训练营周期统计数据
+     *
+     * @param fsStatisPeriodWatch 待插入的训练营周期统计数据对象
+     * @return 影响的行数,通常是1表示成功
+     */
+    int create(FsStatisPeriodWatch fsStatisPeriodWatch);
+
+    /**
+     * 根据主键更新训练营周期统计数据
+     * (只会更新实体中非null的字段)
+     *
+     * @param fsStatisPeriodWatch 待更新的训练营周期统计数据对象 (必须包含ID)
+     * @return 影响的行数,通常是1表示成功,0表示未找到对应记录或未更新任何字段
+     */
+    int updateById(FsStatisPeriodWatch fsStatisPeriodWatch);
+
+    /**
+     * 根据主键ID删除训练营周期统计数据
+     *
+     * @param id 主键ID
+     * @return 影响的行数
+     */
+    int deleteById(Integer id);
+
+    /**
+     * 查询所有训练营周期统计数据
+     *
+     * @return 训练营周期统计数据列表
+     */
+    List<FsStatisPeriodWatch> findAll();
+
+    List<FsStatisPeriodWatch> queryList(StatsWatchLogPageListDTO param);
+
+}

+ 59 - 0
fs-service/src/main/java/com/fs/statis/service/FsStatisSalerWatchService.java

@@ -0,0 +1,59 @@
+package com.fs.statis.service;
+
+import com.fs.statis.domain.FsStatisSalerWatch;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
+
+import java.util.List;
+
+/**
+ * 销售观看统计服务接口
+ */
+public interface FsStatisSalerWatchService {
+
+    /**
+     * 根据ID查询销售观看统计
+     *
+     * @param id 主键ID
+     * @return 销售观看统计对象,如果不存在则返回null
+     */
+    FsStatisSalerWatch getById(Integer id);
+
+    /**
+     * 查询所有销售观看统计
+     *
+     * @return 销售观看统计列表
+     */
+    List<FsStatisSalerWatch> getAll();
+
+    /**
+     * 新增销售观看统计
+     *
+     * @param fsStatisSalerWatch 待新增的销售观看统计对象
+     * @return 返回带有生成ID的销售观看统计对象
+     */
+    FsStatisSalerWatch create(FsStatisSalerWatch fsStatisSalerWatch);
+
+    /**
+     * 更新销售观看统计
+     *
+     * @param fsStatisSalerWatch 待更新的销售观看统计对象 (ID必须存在)
+     * @return 返回更新后的销售观看统计对象,如果更新失败或对象不存在则可能返回null或抛出异常
+     */
+    FsStatisSalerWatch update(FsStatisSalerWatch fsStatisSalerWatch);
+
+    /**
+     * 根据ID删除销售观看统计
+     *
+     * @param id 主键ID
+     * @return 删除成功返回true,否则返回false
+     */
+    boolean deleteById(Integer id);
+
+    List<FsStatisSalerWatch> queryList(StatsWatchLogPageListDTO param);
+
+
+    /**
+     * 写入数据 写入前一天的数据
+     */
+    void writeData();
+}

+ 23 - 0
fs-service/src/main/java/com/fs/statis/service/IFsStatsMemberDailyService.java

@@ -0,0 +1,23 @@
+package com.fs.statis.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.statis.domain.FsStatsMemberDaily;
+import com.fs.statis.vo.FsStatsMemberDailyVO;
+
+import java.util.List;
+import java.util.Map;
+
+public interface IFsStatsMemberDailyService extends IService<FsStatsMemberDaily> {
+
+    /**
+     * 查询会员统计数据
+     * @param params    参数
+     * @return  list
+     */
+    List<FsStatsMemberDailyVO> selectDailyData(Map<String, Object> params);
+
+    /**
+     * 更新统计数据
+     */
+    void refreshMemberDailyData();
+}

+ 108 - 0
fs-service/src/main/java/com/fs/statis/service/IStatisticsCompanyService.java

@@ -0,0 +1,108 @@
+package com.fs.statis.service;
+
+import com.fs.statis.dto.*;
+
+import java.util.List;
+
+/**
+ * 公司统计接口
+ */
+public interface IStatisticsCompanyService {
+
+    /**
+     * 数据概览定时任务
+     */
+    void dataOverviewTask();
+
+    /**
+     * 分析概览定时任务
+     */
+    void analysisPreviewTask(Integer type,Integer userType,Long companyId);
+
+
+    /**
+     * 会员观看、完播人数趋势图
+     */
+    void watchEndPlayTrendTask(Integer type,Integer userType,Long companyId);
+
+
+    /**
+     * 经销商会员观看TOP10
+     */
+    void companyWatchCourseTopTenTask(Integer type,Integer statisticalType,Integer userType,Long companyId);
+
+    /**
+     * 课程观看TOP10
+     */
+    void watchCourseTopTenTask(Integer type,Integer statisticalType,Integer userType,String sort,Long companyId);
+
+    /**
+     * 答题红包金额TOP10
+     */
+    void rewardMoneyTopTenTask(Integer type,Integer dataType,Integer userType,Long companyId);
+    void rewardMoneyTradeTask(Integer type,Integer userType,Long companyId);
+
+
+
+    DealerAggregatedDTO dealerAggregated(Long companyId);
+
+    /**
+     * 消费余额
+     */
+
+    ConsumptionBalanceDataDTO rechargeConsumption(Long companyId);
+
+    /**
+     * 分析概览
+     */
+    AnalysisPreviewDTO analysisPreview(AnalysisPreviewQueryDTO param);
+
+    Long smsBalance(Long companyId);
+
+    /**
+     * 授权信息
+     * @return
+     */
+    AuthorizationInfoDTO authorizationInfo();
+
+    /**
+     * 会员观看、完播人数趋势图
+     * @param param 请求参数
+     * @return 观看完播趋势
+     */
+    List<WatchEndPlayTrendDTO> watchEndPlayTrend(AnalysisPreviewQueryDTO param);
+
+    /**
+     * 经销商会员观看TOP10
+     * @param param
+     * @return
+     */
+    List<DeaMemberTopTenDTO> deaMemberTopTen(AnalysisPreviewQueryDTO param);
+
+    /**
+     * 课程观看TOP10
+     * @param param
+     * @return
+     */
+    List<CourseStatsDTO> watchCourseTopTen(AnalysisPreviewQueryDTO param);
+
+    List<RewardMoneyTopTenDTO> rewardMoneyTopTen(AnalysisPreviewQueryDTO param);
+
+    List<RewardMoneyTrendDTO> rewardMoneyTrendDTO(AnalysisPreviewQueryDTO param);
+
+    /**
+     * 获取统计流量
+     * @return TrafficLogDTO
+     */
+    TrafficLogDTO getTrafficLog(Long companyId);
+
+    /**
+     * 本月订单数
+     */
+    void thisMonthOrderCount(Long companyId);
+
+    /**
+     * 本月收款数
+     */
+    void thisMonthRecvCount(Long companyId);
+}

+ 112 - 0
fs-service/src/main/java/com/fs/statis/service/IStatisticsService.java

@@ -0,0 +1,112 @@
+package com.fs.statis.service;
+
+import com.fs.statis.dto.*;
+
+import java.util.List;
+
+/**
+ * 统计接口
+ */
+public interface IStatisticsService {
+
+    /**
+     * 数据概览定时任务
+     */
+    void dataOverviewTask();
+
+    /**
+     * 分析概览定时任务
+     */
+    void analysisPreviewTask(Integer type,Integer userType);
+
+
+    /**
+     * 会员观看、完播人数趋势图
+     */
+    void watchEndPlayTrendTask(Integer type,Integer userType);
+
+
+    /**
+     * 经销商会员观看TOP10
+     */
+    void companyWatchCourseTopTenTask(Integer type,Integer statisticalType,Integer userType);
+
+    /**
+     * 课程观看TOP10
+     */
+    void watchCourseTopTenTask(Integer type,Integer statisticalType,Integer userType,String sort);
+
+    /**
+     * 答题红包金额TOP10
+     */
+    void rewardMoneyTopTenTask(Integer type,Integer dataType,Integer userType);
+    void rewardMoneyTradeTask(Integer type,Integer userType);
+
+    /**
+     * 分析概览 - 经销商统计
+     */
+    DealerAggregatedDTO dealerAggregated();
+
+    /**
+     * 消费余额
+     */
+    ConsumptionBalanceDataDTO rechargeConsumption();
+
+    /**
+     * 分析概览
+     */
+    AnalysisPreviewDTO analysisPreview(AnalysisPreviewQueryDTO param);
+
+    /**
+     * 获取短信余额
+     * @return
+     */
+    Long smsBalance();
+
+    /**
+     * 授权信息
+     * @return
+     */
+    AuthorizationInfoDTO authorizationInfo();
+
+    /**
+     * 会员观看、完播人数趋势图
+     * @param param 请求参数
+     * @return 观看完播趋势
+     */
+    List<WatchEndPlayTrendDTO> watchEndPlayTrend(AnalysisPreviewQueryDTO param);
+
+    /**
+     * 经销商会员观看TOP10
+     * @param param
+     * @return
+     */
+    List<DeaMemberTopTenDTO> deaMemberTopTen(AnalysisPreviewQueryDTO param);
+
+    /**
+     * 课程观看TOP10
+     * @param param
+     * @return
+     */
+    List<CourseStatsDTO> watchCourseTopTen(AnalysisPreviewQueryDTO param);
+
+    List<RewardMoneyTopTenDTO> rewardMoneyTopTen(AnalysisPreviewQueryDTO param);
+
+    List<RewardMoneyTrendDTO> rewardMoneyTrendDTO(AnalysisPreviewQueryDTO param);
+
+    /**
+     * 获取统计流量
+     * @return TrafficLogDTO
+     */
+    TrafficLogDTO getTrafficLog();
+
+    /**
+     * 本月订单数
+     */
+    void thisMonthOrderCount();
+
+    /**
+     * 本月收款数
+     */
+    void thisMonthRecvCount();
+}

+ 70 - 0
fs-service/src/main/java/com/fs/statis/service/impl/FsStatisEveryDayWatchServiceImpl.java

@@ -0,0 +1,70 @@
+package com.fs.statis.service.impl;
+
+import com.fs.statis.domain.FsStatisEveryDayWatch;
+import com.fs.statis.domain.FsStatisSalerWatch;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
+import com.fs.statis.mapper.FsStatisEveryDayWatchMapper;
+import com.fs.statis.service.FsStatisEveryDayWatchService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * 每日统计数据服务实现类
+ */
+@Service
+public class FsStatisEveryDayWatchServiceImpl implements FsStatisEveryDayWatchService {
+
+    private final FsStatisEveryDayWatchMapper fsStatisEveryDayWatchMapper;
+
+    /**
+     * 通过构造函数注入Mapper
+     * @param fsStatisEveryDayWatchMapper 每日统计数据Mapper
+     */
+    @Autowired
+    public FsStatisEveryDayWatchServiceImpl(FsStatisEveryDayWatchMapper fsStatisEveryDayWatchMapper) {
+        this.fsStatisEveryDayWatchMapper = fsStatisEveryDayWatchMapper;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FsStatisEveryDayWatch findById(Integer id) {
+        return fsStatisEveryDayWatchMapper.findById(id);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    @Transactional
+    public int create(FsStatisEveryDayWatch fsStatisEveryDayWatch) {
+        return fsStatisEveryDayWatchMapper.insert(fsStatisEveryDayWatch);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    @Transactional
+    public int update(FsStatisEveryDayWatch fsStatisEveryDayWatch) {
+        return fsStatisEveryDayWatchMapper.update(fsStatisEveryDayWatch);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<FsStatisEveryDayWatch> findAll() {
+        return fsStatisEveryDayWatchMapper.findAll();
+    }
+
+    @Override
+    public List<FsStatisSalerWatch> queryList(StatsWatchLogPageListDTO param) {
+        return fsStatisEveryDayWatchMapper.queryList(param);
+    }
+
+}

+ 81 - 0
fs-service/src/main/java/com/fs/statis/service/impl/FsStatisPeriodWatchServiceImpl.java

@@ -0,0 +1,81 @@
+package com.fs.statis.service.impl; // 假设Service实现类放在此包下
+
+import com.fs.statis.domain.FsStatisPeriodWatch;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
+import com.fs.statis.mapper.FsStatisPeriodWatchMapper;
+import com.fs.statis.service.FsStatisPeriodWatchService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * 训练营周期统计数据服务实现类
+ */
+@Service
+public class FsStatisPeriodWatchServiceImpl implements FsStatisPeriodWatchService {
+
+    private final FsStatisPeriodWatchMapper fsStatisPeriodWatchMapper;
+
+    /**
+     * 通过构造函数注入Mapper
+     * @param fsStatisPeriodWatchMapper 训练营周期统计数据Mapper
+     */
+    @Autowired
+    public FsStatisPeriodWatchServiceImpl(FsStatisPeriodWatchMapper fsStatisPeriodWatchMapper) {
+        this.fsStatisPeriodWatchMapper = fsStatisPeriodWatchMapper;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FsStatisPeriodWatch findById(Integer id) {
+        return fsStatisPeriodWatchMapper.selectById(id);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    @Transactional // 标记此方法需要事务管理
+    public int create(FsStatisPeriodWatch fsStatisPeriodWatch) {
+        // 在这里可以添加业务逻辑,例如参数校验等
+        return fsStatisPeriodWatchMapper.insert(fsStatisPeriodWatch);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    @Transactional // 标记此方法需要事务管理
+    public int updateById(FsStatisPeriodWatch fsStatisPeriodWatch) {
+        // 在这里可以添加业务逻辑,例如检查记录是否存在,或在更新前进行特定校验
+        // 注意:Mapper中的updateById是动态SQL,只更新非null字段
+        return fsStatisPeriodWatchMapper.updateById(fsStatisPeriodWatch);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    @Transactional // 标记此方法需要事务管理
+    public int deleteById(Integer id) {
+        // 在这里可以添加业务逻辑,例如检查关联数据等
+        return fsStatisPeriodWatchMapper.deleteById(id);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<FsStatisPeriodWatch> findAll() {
+        return fsStatisPeriodWatchMapper.selectAll();
+    }
+
+    @Override
+    public List<FsStatisPeriodWatch> queryList(StatsWatchLogPageListDTO param) {
+        return fsStatisPeriodWatchMapper.queryList(param);
+    }
+}

+ 173 - 0
fs-service/src/main/java/com/fs/statis/service/impl/FsStatisSalerWatchServiceImpl.java

@@ -0,0 +1,173 @@
+package com.fs.statis.service.impl;
+
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.mapper.CompanyUserMapper;
+import com.fs.course.mapper.FsUserCoursePeriodMapper;
+import com.fs.qw.mapper.QwUserMapper;
+import com.fs.sop.mapper.QwSopLogsMapper;
+import com.fs.statis.domain.FsStatisSalerWatch;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
+import com.fs.statis.mapper.FsStatisSalerWatchMapper;
+import com.fs.statis.service.FsStatisSalerWatchService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 销售观看统计服务实现类
+ */
+@Service("fsStatisSalerWatchService")
+@Slf4j
+public class FsStatisSalerWatchServiceImpl implements FsStatisSalerWatchService {
+
+    private final FsStatisSalerWatchMapper fsStatisSalerWatchMapper;
+
+    private final CompanyUserMapper companyUserMapper;
+
+    private final QwUserMapper qwUserMapper;
+
+    private final QwSopLogsMapper qwSopLogsMapper;
+
+    private final FsUserCoursePeriodMapper fsUserCoursePeriodMapper;
+
+    @Autowired
+    public FsStatisSalerWatchServiceImpl(FsStatisSalerWatchMapper fsStatisSalerWatchMapper, CompanyUserMapper companyUserMapper, QwUserMapper qwUserMapper, QwSopLogsMapper qwSopLogsMapper, FsUserCoursePeriodMapper fsUserCoursePeriodMapper) {
+        this.fsStatisSalerWatchMapper = fsStatisSalerWatchMapper;
+        this.companyUserMapper = companyUserMapper;
+        this.qwUserMapper = qwUserMapper;
+        this.qwSopLogsMapper = qwSopLogsMapper;
+        this.fsUserCoursePeriodMapper = fsUserCoursePeriodMapper;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FsStatisSalerWatch getById(Integer id) {
+        if (id == null) {
+            return null;
+        }
+        return fsStatisSalerWatchMapper.findById(id);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<FsStatisSalerWatch> getAll() {
+        return fsStatisSalerWatchMapper.findAll();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FsStatisSalerWatch create(FsStatisSalerWatch fsStatisSalerWatch) {
+        if (fsStatisSalerWatch == null) {
+            return null;
+        }
+        fsStatisSalerWatch.setId(null);
+        fsStatisSalerWatchMapper.insert(fsStatisSalerWatch);
+        return fsStatisSalerWatch;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FsStatisSalerWatch update(FsStatisSalerWatch fsStatisSalerWatch) {
+        if (fsStatisSalerWatch == null || fsStatisSalerWatch.getId() == null) {
+            return null;
+        }
+        int affectedRows = fsStatisSalerWatchMapper.update(fsStatisSalerWatch);
+        if (affectedRows > 0) {
+            return fsStatisSalerWatch;
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean deleteById(Integer id) {
+        if (id == null) {
+            return false;
+        }
+        int affectedRows = fsStatisSalerWatchMapper.deleteById(id);
+        return affectedRows > 0;
+    }
+
+    @Override
+    public List<FsStatisSalerWatch> queryList(StatsWatchLogPageListDTO param) {
+        return fsStatisSalerWatchMapper.queryList(param);
+    }
+
+    @Override
+    public void writeData() {
+        // 统计销售看课情况
+        // 获取前一天的时间
+//        List<CompanyUser> companyUserList = this.companyUserMapper.selectAllCompanyUserList();
+//
+//
+//        List<FsStatisSalerWatch> writeData = new ArrayList<>();
+//
+//        LocalDate previousDay = LocalDate.now().minusDays(1);
+//        for (CompanyUser companyUser : companyUserList) {
+//
+//            if(companyUser.getCompanyId() == null) {
+//                log.info("销售{} 对应公司id {} 为空!",companyUser.getUserId(),companyUser.getCompanyId());
+//                continue;
+//            }
+//            // 确定当前销售对应的营期
+//            List<Long> periodList = fsUserCoursePeriodMapper.queryPeriod(companyUser.getCompanyId(),previousDay);
+//
+//            // 找到销售关联的企微账号
+//            List<String> qwUserIdList = qwUserMapper.findQwUserIdListByCompanyUserId(companyUser.getUserId());
+//
+//            for (Long periodId : periodList) {
+//                // 去sop记录表找对应的SOP发送记录,记录数作为营期人数
+//                Long periodCount = qwSopLogsMapper.selectQwSopLogsCountByQwUserId(qwUserIdList,periodId,previousDay);
+//                // 再去course_watch_log找对应的销售观看记录作为已报名数
+//                Long registerCount = companyUserMapper.queryCompanyUserWatchCount(companyUser.getUserId(),periodId);
+//                Long completedCount = companyUserMapper.queryCompanyUserWatchCountCompleted(companyUser.getUserId(),periodId);
+//
+//
+//                FsStatisSalerWatch fsStatisSalerWatch = new FsStatisSalerWatch();
+//                fsStatisSalerWatch.setDeptId(companyUser.getDeptId());
+//                fsStatisSalerWatch.setCompanyUserId(companyUser.getUserId());
+//                fsStatisSalerWatch.setTrainCampNum(periodCount);
+//                fsStatisSalerWatch.setNotRegisteredNum(periodCount - registerCount);
+//                fsStatisSalerWatch.setRegisteredNum(registerCount);
+//                fsStatisSalerWatch.setCompletedNum(completedCount);
+//
+//                float regRate = 0.0f;
+//                if(periodCount != 0) {
+//                    regRate = registerCount / periodCount;
+//                }
+//                float finishedRate = 0.0f;
+//                if(registerCount != 0) {
+//                    finishedRate = completedCount / registerCount;
+//                }
+//
+//
+//                fsStatisSalerWatch.setRegRate(regRate);
+//                fsStatisSalerWatch.setFinishedRate(finishedRate);
+//                fsStatisSalerWatch.setDataDate(previousDay);
+//
+//                fsStatisSalerWatch.setPeriodId(periodId);
+//
+//                writeData.add(fsStatisSalerWatch);
+//            }
+//        }
+//
+//        if(CollectionUtils.isNotEmpty(writeData)){
+//            fsStatisSalerWatchMapper.batchSave(writeData);
+//        }
+    }
+}

+ 36 - 0
fs-service/src/main/java/com/fs/statis/service/impl/FsStatsMemberDailyServiceImpl.java

@@ -0,0 +1,36 @@
+package com.fs.statis.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.statis.domain.FsStatsMemberDaily;
+import com.fs.statis.mapper.FsStatsMemberDailyMapper;
+import com.fs.statis.service.IFsStatsMemberDailyService;
+import com.fs.statis.vo.FsStatsMemberDailyVO;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class FsStatsMemberDailyServiceImpl extends ServiceImpl<FsStatsMemberDailyMapper, FsStatsMemberDaily> implements IFsStatsMemberDailyService {
+
+    /**
+     * 查询会员统计数据
+     * @param params    参数
+     * @return  list
+     */
+    @Override
+    public List<FsStatsMemberDailyVO> selectDailyData(Map<String, Object> params) {
+        return baseMapper.selectDailyData(params);
+    }
+
+    /**
+     * 更新统计数据
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void refreshMemberDailyData() {
+        baseMapper.refreshMemberDailyData(LocalDate.now());
+    }
+}

+ 1077 - 0
fs-service/src/main/java/com/fs/statis/service/impl/StatisticsCompanyServiceImpl.java

@@ -0,0 +1,1077 @@
+package com.fs.statis.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.TimeUtils;
+import com.fs.company.cache.ICompanyCacheService;
+import com.fs.company.service.ICompanyService;
+import com.fs.course.mapper.FsCourseTrafficLogMapper;
+import com.fs.his.service.IFsStoreOrderService;
+import com.fs.his.service.IFsStorePaymentService;
+import com.fs.his.service.IFsStoreProductService;
+import com.fs.his.service.IFsUserService;
+import com.fs.his.vo.OptionsVO;
+import com.fs.statis.StatisticsRedisConstant;
+import com.fs.statis.dto.*;
+import com.fs.statis.mapper.ConsumptionBalanceMapper;
+import com.fs.statis.service.IStatisticsCompanyService;
+import com.fs.statis.service.utils.TrendDataFiller;
+import com.fs.store.service.cache.IFsUserCourseCacheService;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.service.ISysConfigService;
+import com.hc.openapi.tool.util.ObjectUtils;
+import com.hc.openapi.tool.util.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.util.Asserts;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.DayOfWeek;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAdjusters;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.fs.statis.StatisticsRedisConstant.*;
+
+@Slf4j
+@Service("statisticsCompanyService")
+public class StatisticsCompanyServiceImpl implements IStatisticsCompanyService {
+    @Autowired
+    private ConsumptionBalanceMapper consumptionBalanceMapper;
+
+    @Autowired
+    private IFsUserCourseCacheService fsUserCourseCacheService;
+
+    @Autowired
+    private ICompanyCacheService companyCacheService;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @Autowired
+    private FsCourseTrafficLogMapper fsCourseTrafficLogMapper;
+    @Autowired
+    private IFsUserService userService;
+
+    @Autowired
+    private IFsStoreOrderService storeOrderService;
+
+    @Autowired
+    private IFsStorePaymentService paymentService;
+
+    @Autowired
+    private IFsStoreProductService productService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private ICompanyService companyService;
+    @Override
+    public void dataOverviewTask() {
+        List<OptionsVO> optionsVOS = companyService.selectAllCompanyList();
+        for (OptionsVO optionsVO : optionsVOS) {
+            Long companyId = optionsVO.getDictValue();
+            if(companyId == null){
+                continue;
+            }
+            dataOverviewTaskCompany(companyId);
+        }
+    }
+
+    private void dataOverviewTaskCompany(Long companyId){
+        DealerAggregatedDTO dealerAggregatedDTO = this.dealerAggregated(companyId);
+        ConsumptionBalanceDataDTO consumptionBalanceDataDTO = this.rechargeConsumption(companyId);
+        AuthorizationInfoDTO authorizationInfoDTO = authorizationInfo();
+        Long smsBalance = this.smsBalance(companyId);
+        TrafficLogDTO trafficLog = this.getTrafficLog(companyId);
+
+        redisCache.setCacheObject(String.format(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_AGGREGATED+":%d",companyId), dealerAggregatedDTO);
+        redisCache.setCacheObject(String.format(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_BALANCE+":%d",companyId), consumptionBalanceDataDTO);
+        redisCache.setCacheObject(String.format(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_AUTHORIZATION_INFO+":%d",companyId), authorizationInfoDTO);
+        redisCache.setCacheObject(String.format(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_SMS_BALANCE+":%d",companyId), smsBalance);
+        redisCache.setCacheObject(String.format(StatisticsRedisConstant.DATA_OVERVIEW_TRAFFIC_LOG+":%d",companyId),trafficLog);
+    }
+    public void analysisPreviewTask0(){
+        List<OptionsVO> optionsVOS = companyService.selectAllCompanyList();
+        for (OptionsVO optionsVO : optionsVOS) {
+            Long companyId = optionsVO.getDictValue();
+            if (companyId == null) {
+                continue;
+            }
+            analysisPreviewTask(0,1,companyId);
+            analysisPreviewTask(0,2,companyId);
+        }
+
+    }
+
+    public void analysisPreviewTask1(){
+        List<OptionsVO> optionsVOS = companyService.selectAllCompanyList();
+        for (OptionsVO optionsVO : optionsVOS) {
+            Long companyId = optionsVO.getDictValue();
+            if (companyId == null) {
+                continue;
+            }
+
+            analysisPreviewTask(0,1,companyId);
+            analysisPreviewTask(1,1,companyId);
+            analysisPreviewTask(2,1,companyId);
+            analysisPreviewTask(3,1,companyId);
+            analysisPreviewTask(4,1,companyId);
+
+            analysisPreviewTask(0,2,companyId);
+            analysisPreviewTask(1,2,companyId);
+            analysisPreviewTask(2,2,companyId);
+            analysisPreviewTask(3,2,companyId);
+            analysisPreviewTask(4,2,companyId);
+        }
+    }
+    @Override
+    public void analysisPreviewTask(Integer type, Integer userType,Long companyId) {
+        // 根据type计算出时间范围
+        String startDate = "";
+        String endDate = "";
+
+        LocalDateTime now = LocalDateTime.now();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        LocalTime startOfDayTime = LocalTime.MIN;
+        LocalTime endOfDayTime = LocalTime.of(23, 59, 59);
+
+        if(0 == type){
+            LocalDateTime startOfDay = now.with(startOfDayTime);
+            LocalDateTime endOfDay = now.with(endOfDayTime);
+            startDate = startOfDay.format(formatter);
+            endDate = endOfDay.format(formatter);
+        } else if(1 == type){
+            LocalDateTime yesterday = now.minusDays(1);
+            LocalDateTime startOfYesterday = yesterday.with(startOfDayTime);
+            LocalDateTime endOfYesterday = yesterday.with(endOfDayTime);
+            startDate = startOfYesterday.format(formatter);
+            endDate = endOfYesterday.format(formatter);
+        } else if(2 == type) {
+            LocalDateTime startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+            LocalDateTime startOfStartOfWeek = startOfWeek.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfWeek.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(3 == type) {
+            LocalDateTime startOfMonth = now.withDayOfMonth(1);
+            LocalDateTime startOfStartOfMonth = startOfMonth.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfMonth.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(4 == type) {
+            LocalDateTime firstDayOfPreviousMonth = now.minusMonths(1).withDayOfMonth(1);
+            LocalDateTime lastDayOfPreviousMonth = now.withDayOfMonth(1).minusDays(1);
+
+            LocalDateTime startOfPrevMonthStart = firstDayOfPreviousMonth.with(startOfDayTime);
+            LocalDateTime endOfPrevMonthEnd = lastDayOfPreviousMonth.with(endOfDayTime);
+
+            startDate = startOfPrevMonthStart.format(formatter);
+            endDate = endOfPrevMonthEnd.format(formatter);
+        }
+
+        AnalysisPreviewQueryDTO param = new AnalysisPreviewQueryDTO();
+        param.setStartTime(startDate);
+        param.setEndTime(endDate);
+        param.setType(type);
+        param.setUserType(userType);
+        param.setCompanyId(companyId);
+
+        AnalysisPreviewDTO analysisPreviewDTO = this.analysisPreview(param);
+
+        redisCache.setCacheObject(String.format("%s:%d:%d:%d",DATA_OVERVIEW_DEALER_ANALYSISPREVIEW,type,userType,companyId), analysisPreviewDTO);
+    }
+
+
+    public void watchEndPlayTrendTask0(){
+        List<OptionsVO> optionsVOS = companyService.selectAllCompanyList();
+        for (OptionsVO optionsVO : optionsVOS) {
+            Long companyId = optionsVO.getDictValue();
+            if(companyId == null){
+                continue;
+            }
+            this.watchEndPlayTrendTask(0,1,companyId);
+            this.watchEndPlayTrendTask(0,2,companyId);
+        }
+
+    }
+
+    public void watchEndPlayTrendTask1(){
+        List<OptionsVO> optionsVOS = companyService.selectAllCompanyList();
+        for (OptionsVO optionsVO : optionsVOS) {
+            Long companyId = optionsVO.getDictValue();
+            if(companyId == null){
+                continue;
+            }
+            this.watchEndPlayTrendTask(1,1,companyId);
+            this.watchEndPlayTrendTask(2,1,companyId);
+            this.watchEndPlayTrendTask(3,1,companyId);
+            this.watchEndPlayTrendTask(4,1,companyId);
+
+            this.watchEndPlayTrendTask(1,2,companyId);
+            this.watchEndPlayTrendTask(2,2,companyId);
+            this.watchEndPlayTrendTask(3,2,companyId);
+            this.watchEndPlayTrendTask(4,2,companyId);
+        }
+
+    }
+    @Override
+    public void watchEndPlayTrendTask(Integer type, Integer userType,Long companyId) {
+        // 根据type计算出时间范围
+        String startDate = "";
+        String endDate = "";
+
+        LocalDateTime now = LocalDateTime.now();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        LocalTime startOfDayTime = LocalTime.MIN;
+        LocalTime endOfDayTime = LocalTime.of(23, 59, 59);
+
+        if(0 == type){
+            LocalDateTime startOfDay = now.with(startOfDayTime);
+            LocalDateTime endOfDay = now.with(endOfDayTime);
+            startDate = startOfDay.format(formatter);
+            endDate = endOfDay.format(formatter);
+        } else if(1 == type){
+            LocalDateTime yesterday = now.minusDays(1);
+            LocalDateTime startOfYesterday = yesterday.with(startOfDayTime);
+            LocalDateTime endOfYesterday = yesterday.with(endOfDayTime);
+            startDate = startOfYesterday.format(formatter);
+            endDate = endOfYesterday.format(formatter);
+        } else if(2 == type) {
+            LocalDateTime startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+            LocalDateTime startOfStartOfWeek = startOfWeek.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfWeek.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(3 == type) {
+            LocalDateTime startOfMonth = now.withDayOfMonth(1);
+            LocalDateTime startOfStartOfMonth = startOfMonth.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfMonth.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(4 == type) {
+            LocalDateTime firstDayOfPreviousMonth = now.minusMonths(1).withDayOfMonth(1);
+            LocalDateTime lastDayOfPreviousMonth = now.withDayOfMonth(1).minusDays(1);
+
+            LocalDateTime startOfPrevMonthStart = firstDayOfPreviousMonth.with(startOfDayTime);
+            LocalDateTime endOfPrevMonthEnd = lastDayOfPreviousMonth.with(endOfDayTime);
+
+            startDate = startOfPrevMonthStart.format(formatter);
+            endDate = endOfPrevMonthEnd.format(formatter);
+        }
+
+        AnalysisPreviewQueryDTO param = new AnalysisPreviewQueryDTO();
+        param.setStartTime(startDate);
+        param.setEndTime(endDate);
+        param.setType(type);
+        param.setCompanyId(companyId);
+
+        param.setUserType(userType);
+        List<WatchEndPlayTrendDTO> watchEndPlayTrendDTOS = this.watchEndPlayTrend(param);
+
+        redisCache.setCacheObject(String.format("%s:%d:%d",DATA_OVERVIEW_DEALER_CHARTS,type,userType),watchEndPlayTrendDTOS);
+    }
+
+    @Override
+    public void companyWatchCourseTopTenTask(Integer type, Integer statisticalType, Integer userType,Long companyId) {
+
+        AnalysisPreviewQueryDTO dto = new AnalysisPreviewQueryDTO();
+        dto.setType(type);
+        dto.setStatisticalType(statisticalType);
+
+        String startDate = "";
+        String endDate = "";
+
+        LocalDateTime now = LocalDateTime.now();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        LocalTime startOfDayTime = LocalTime.MIN;
+        LocalTime endOfDayTime = LocalTime.of(23, 59, 59);
+
+        if(0 == type){
+            LocalDateTime startOfDay = now.with(startOfDayTime);
+            LocalDateTime endOfDay = now.with(endOfDayTime);
+            startDate = startOfDay.format(formatter);
+            endDate = endOfDay.format(formatter);
+        } else if(1 == type){
+            LocalDateTime yesterday = now.minusDays(1);
+            LocalDateTime startOfYesterday = yesterday.with(startOfDayTime);
+            LocalDateTime endOfYesterday = yesterday.with(endOfDayTime);
+            startDate = startOfYesterday.format(formatter);
+            endDate = endOfYesterday.format(formatter);
+        } else if(2 == type) {
+            LocalDateTime startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+            LocalDateTime startOfStartOfWeek = startOfWeek.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfWeek.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(3 == type) {
+            LocalDateTime startOfMonth = now.withDayOfMonth(1);
+            LocalDateTime startOfStartOfMonth = startOfMonth.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfMonth.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(4 == type) {
+            LocalDateTime firstDayOfPreviousMonth = now.minusMonths(1).withDayOfMonth(1);
+            LocalDateTime lastDayOfPreviousMonth = now.withDayOfMonth(1).minusDays(1);
+
+            LocalDateTime startOfPrevMonthStart = firstDayOfPreviousMonth.with(startOfDayTime);
+            LocalDateTime endOfPrevMonthEnd = lastDayOfPreviousMonth.with(endOfDayTime);
+
+            startDate = startOfPrevMonthStart.format(formatter);
+            endDate = endOfPrevMonthEnd.format(formatter);
+        }
+
+        dto.setStartTime(startDate);
+        dto.setEndTime(endDate);
+        dto.setUserType(userType);
+        dto.setCompanyId(companyId);
+
+        List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = deaMemberTopTen(dto);
+        redisCache.setCacheObject(String.format("%s:%d:%d:%d:%d", CHARTS_MEMBER_TOP_TEN_WATCH, type,statisticalType,userType,companyId), deaMemberTopTenDTOS);
+    }
+
+    public void companyWatchCourseTopTenTask0(){
+        List<OptionsVO> optionsVOS = companyService.selectAllCompanyList();
+        for (OptionsVO optionsVO : optionsVOS) {
+            Long companyId = optionsVO.getDictValue();
+            if (companyId == null) {
+                continue;
+            }
+            companyWatchCourseTopTenTask(0,0,1,companyId);
+            companyWatchCourseTopTenTask(0,1,1,companyId);
+
+
+            companyWatchCourseTopTenTask(0,0,2,companyId);
+            companyWatchCourseTopTenTask(0,1,2,companyId);
+        }
+
+    }
+
+    public void companyWatchCourseTopTenTask1(){
+        List<OptionsVO> optionsVOS = companyService.selectAllCompanyList();
+        for (OptionsVO optionsVO : optionsVOS) {
+            Long companyId = optionsVO.getDictValue();
+            if (companyId == null) {
+                continue;
+            }
+            companyWatchCourseTopTenTask(1,0,1,companyId);
+            companyWatchCourseTopTenTask(1,1,1,companyId);
+            companyWatchCourseTopTenTask(2,0,1,companyId);
+            companyWatchCourseTopTenTask(2,1,1,companyId);
+            companyWatchCourseTopTenTask(3,0,1,companyId);
+            companyWatchCourseTopTenTask(3,1,1,companyId);
+            companyWatchCourseTopTenTask(4,0,1,companyId);
+            companyWatchCourseTopTenTask(4,1,1,companyId);
+
+            companyWatchCourseTopTenTask(1,0,2,companyId);
+            companyWatchCourseTopTenTask(1,1,2,companyId);
+            companyWatchCourseTopTenTask(2,0,2,companyId);
+            companyWatchCourseTopTenTask(2,1,2,companyId);
+            companyWatchCourseTopTenTask(3,0,2,companyId);
+            companyWatchCourseTopTenTask(3,1,2,companyId);
+            companyWatchCourseTopTenTask(4,0,2,companyId);
+            companyWatchCourseTopTenTask(4,1,2,companyId);
+        }
+
+
+
+    }
+
+    @Override
+    public void watchCourseTopTenTask(Integer type, Integer statisticalType, Integer userType, String sort,Long companyId) {
+        AnalysisPreviewQueryDTO dto = new AnalysisPreviewQueryDTO();
+        dto.setType(type);
+        dto.setStatisticalType(statisticalType);
+        dto.setSort(sort);
+
+        String startDate = "";
+        String endDate = "";
+
+        LocalDateTime now = LocalDateTime.now();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        LocalTime startOfDayTime = LocalTime.MIN;
+        LocalTime endOfDayTime = LocalTime.of(23, 59, 59);
+
+        if(0 == type){
+            LocalDateTime startOfDay = now.with(startOfDayTime);
+            LocalDateTime endOfDay = now.with(endOfDayTime);
+            startDate = startOfDay.format(formatter);
+            endDate = endOfDay.format(formatter);
+        } else if(1 == type){
+            LocalDateTime yesterday = now.minusDays(1);
+            LocalDateTime startOfYesterday = yesterday.with(startOfDayTime);
+            LocalDateTime endOfYesterday = yesterday.with(endOfDayTime);
+            startDate = startOfYesterday.format(formatter);
+            endDate = endOfYesterday.format(formatter);
+        } else if(2 == type) {
+            LocalDateTime startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+            LocalDateTime startOfStartOfWeek = startOfWeek.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfWeek.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(3 == type) {
+            LocalDateTime startOfMonth = now.withDayOfMonth(1);
+            LocalDateTime startOfStartOfMonth = startOfMonth.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfMonth.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(4 == type) {
+            LocalDateTime firstDayOfPreviousMonth = now.minusMonths(1).withDayOfMonth(1);
+            LocalDateTime lastDayOfPreviousMonth = now.withDayOfMonth(1).minusDays(1);
+
+            LocalDateTime startOfPrevMonthStart = firstDayOfPreviousMonth.with(startOfDayTime);
+            LocalDateTime endOfPrevMonthEnd = lastDayOfPreviousMonth.with(endOfDayTime);
+
+            startDate = startOfPrevMonthStart.format(formatter);
+            endDate = endOfPrevMonthEnd.format(formatter);
+        }
+        dto.setStartTime(startDate);
+        dto.setEndTime(endDate);
+        dto.setUserType(userType);
+        dto.setCompanyId(companyId);
+        List<CourseStatsDTO> courseStatsDTOS = watchCourseTopTen(dto);
+
+        redisCache.setCacheObject( String.format("%s:%d:%d:%d:%s:%d", CHARTS_WATCH_TOP_TEN, type,statisticalType,userType,sort,companyId), courseStatsDTOS);
+
+    }
+
+
+    public void watchCourseTopTenTask0(){
+        List<OptionsVO> optionsVOS = companyService.selectAllCompanyList();
+        for (OptionsVO optionsVO : optionsVOS) {
+            Long companyId = optionsVO.getDictValue();
+            if (companyId == null) {
+                continue;
+            }
+
+            watchCourseTopTenTask(0,0,1,"DESC",companyId);
+            watchCourseTopTenTask(0,0,1,"ASC",companyId);
+            watchCourseTopTenTask(0,1,1,"DESC",companyId);
+            watchCourseTopTenTask(0,1,1,"ASC",companyId);
+            watchCourseTopTenTask(0,2,1,"DESC",companyId);
+            watchCourseTopTenTask(0,2,1,"ASC",companyId);
+            watchCourseTopTenTask(0,3,1,"DESC",companyId);
+            watchCourseTopTenTask(0,3,1,"ASC",companyId);
+
+            watchCourseTopTenTask(0,0,1,"DESC",companyId);
+            watchCourseTopTenTask(0,0,1,"ASC",companyId);
+            watchCourseTopTenTask(0,1,1,"DESC",companyId);
+            watchCourseTopTenTask(0,1,1,"ASC",companyId);
+            watchCourseTopTenTask(0,2,1,"DESC",companyId);
+            watchCourseTopTenTask(0,2,1,"ASC",companyId);
+            watchCourseTopTenTask(0,3,1,"DESC",companyId);
+            watchCourseTopTenTask(0,3,1,"ASC",companyId);
+
+        }
+
+    }
+
+    public void watchCourseTopTenTask1(){
+        List<OptionsVO> optionsVOS = companyService.selectAllCompanyList();
+        for (OptionsVO optionsVO : optionsVOS) {
+            Long companyId = optionsVO.getDictValue();
+            if (companyId == null) {
+                continue;
+            }
+
+            watchCourseTopTenTask(1,0,1,"DESC",companyId);
+            watchCourseTopTenTask(1,0,1,"ASC",companyId);
+
+            watchCourseTopTenTask(1,0,2,"DESC",companyId);
+            watchCourseTopTenTask(1,0,2,"ASC",companyId);
+
+
+            watchCourseTopTenTask(1,1,1,"DESC",companyId);
+            watchCourseTopTenTask(1,1,1,"ASC",companyId);
+
+            watchCourseTopTenTask(1,1,2,"DESC",companyId);
+            watchCourseTopTenTask(1,1,2,"ASC",companyId);
+
+            watchCourseTopTenTask(1,2,1,"DESC",companyId);
+            watchCourseTopTenTask(1,2,1,"ASC",companyId);
+
+            watchCourseTopTenTask(1,2,2,"DESC",companyId);
+            watchCourseTopTenTask(1,2,2,"ASC",companyId);
+
+
+            watchCourseTopTenTask(1,3,1,"DESC",companyId);
+            watchCourseTopTenTask(1,3,1,"ASC",companyId);
+
+            watchCourseTopTenTask(1,3,2,"DESC",companyId);
+            watchCourseTopTenTask(1,3,2,"ASC",companyId);
+
+            watchCourseTopTenTask(2,0,1,"DESC",companyId);
+            watchCourseTopTenTask(2,0,1,"ASC",companyId);
+
+            watchCourseTopTenTask(2,0,2,"DESC",companyId);
+            watchCourseTopTenTask(2,0,2,"ASC",companyId);
+
+            watchCourseTopTenTask(2,1,1,"DESC",companyId);
+            watchCourseTopTenTask(2,1,1,"ASC",companyId);
+
+            watchCourseTopTenTask(2,1,2,"DESC",companyId);
+            watchCourseTopTenTask(2,1,2,"ASC",companyId);
+
+            watchCourseTopTenTask(2,2,1,"DESC",companyId);
+            watchCourseTopTenTask(2,2,1,"ASC",companyId);
+
+            watchCourseTopTenTask(2,2,2,"DESC",companyId);
+            watchCourseTopTenTask(2,2,2,"ASC",companyId);
+
+
+            watchCourseTopTenTask(2,3,1,"DESC",companyId);
+            watchCourseTopTenTask(2,3,1,"ASC",companyId);
+
+            watchCourseTopTenTask(2,3,2,"DESC",companyId);
+            watchCourseTopTenTask(2,3,2,"ASC",companyId);
+
+            watchCourseTopTenTask(3,0,1,"DESC",companyId);
+            watchCourseTopTenTask(3,0,1,"ASC",companyId);
+
+            watchCourseTopTenTask(3,0,2,"DESC",companyId);
+            watchCourseTopTenTask(3,0,2,"ASC",companyId);
+
+            watchCourseTopTenTask(3,1,1,"DESC",companyId);
+            watchCourseTopTenTask(3,1,1,"ASC",companyId);
+
+            watchCourseTopTenTask(3,1,2,"DESC",companyId);
+            watchCourseTopTenTask(3,1,2,"ASC",companyId);
+
+            watchCourseTopTenTask(3,2,1,"DESC",companyId);
+            watchCourseTopTenTask(3,2,1,"ASC",companyId);
+
+            watchCourseTopTenTask(3,2,2,"DESC",companyId);
+            watchCourseTopTenTask(3,2,2,"ASC",companyId);
+
+            watchCourseTopTenTask(3,3,1,"DESC",companyId);
+            watchCourseTopTenTask(3,3,1,"ASC",companyId);
+
+            watchCourseTopTenTask(3,3,2,"DESC",companyId);
+            watchCourseTopTenTask(3,3,2,"ASC",companyId);
+
+            watchCourseTopTenTask(4,0,1,"DESC",companyId);
+            watchCourseTopTenTask(4,0,1,"ASC",companyId);
+
+            watchCourseTopTenTask(4,0,2,"DESC",companyId);
+            watchCourseTopTenTask(4,0,2,"ASC",companyId);
+
+            watchCourseTopTenTask(4,1,1,"DESC",companyId);
+            watchCourseTopTenTask(4,1,1,"ASC",companyId);
+            watchCourseTopTenTask(4,2,1,"DESC",companyId);
+            watchCourseTopTenTask(4,2,1,"ASC",companyId);
+            watchCourseTopTenTask(4,3,1,"DESC",companyId);
+            watchCourseTopTenTask(4,3,1,"ASC",companyId);
+
+            watchCourseTopTenTask(4,1,2,"DESC",companyId);
+            watchCourseTopTenTask(4,1,2,"ASC",companyId);
+            watchCourseTopTenTask(4,2,2,"DESC",companyId);
+            watchCourseTopTenTask(4,2,2,"ASC",companyId);
+            watchCourseTopTenTask(4,3,2,"DESC",companyId);
+            watchCourseTopTenTask(4,3,2,"ASC",companyId);
+        }
+
+    }
+
+
+    @Override
+    public void rewardMoneyTopTenTask(Integer type, Integer dataType, Integer userType,Long companyId) {
+        AnalysisPreviewQueryDTO dto = new AnalysisPreviewQueryDTO();
+        dto.setType(type);
+        dto.setDataType(dataType);
+
+        String startDate = "";
+        String endDate = "";
+
+        LocalDateTime now = LocalDateTime.now();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        LocalTime startOfDayTime = LocalTime.MIN;
+        LocalTime endOfDayTime = LocalTime.of(23, 59, 59);
+
+        if(0 == type){
+            LocalDateTime startOfDay = now.with(startOfDayTime);
+            LocalDateTime endOfDay = now.with(endOfDayTime);
+            startDate = startOfDay.format(formatter);
+            endDate = endOfDay.format(formatter);
+        } else if(1 == type){
+            LocalDateTime yesterday = now.minusDays(1);
+            LocalDateTime startOfYesterday = yesterday.with(startOfDayTime);
+            LocalDateTime endOfYesterday = yesterday.with(endOfDayTime);
+            startDate = startOfYesterday.format(formatter);
+            endDate = endOfYesterday.format(formatter);
+        } else if(2 == type) {
+            LocalDateTime startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+            LocalDateTime startOfStartOfWeek = startOfWeek.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfWeek.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(3 == type) {
+            LocalDateTime startOfMonth = now.withDayOfMonth(1);
+            LocalDateTime startOfStartOfMonth = startOfMonth.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfMonth.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(4 == type) {
+            LocalDateTime firstDayOfPreviousMonth = now.minusMonths(1).withDayOfMonth(1);
+            LocalDateTime lastDayOfPreviousMonth = now.withDayOfMonth(1).minusDays(1);
+
+            LocalDateTime startOfPrevMonthStart = firstDayOfPreviousMonth.with(startOfDayTime);
+            LocalDateTime endOfPrevMonthEnd = lastDayOfPreviousMonth.with(endOfDayTime);
+
+            startDate = startOfPrevMonthStart.format(formatter);
+            endDate = endOfPrevMonthEnd.format(formatter);
+        }
+
+        dto.setStartTime(startDate);
+        dto.setEndTime(endDate);
+        dto.setUserType(userType);
+        dto.setCompanyId(companyId);
+
+        List<RewardMoneyTopTenDTO> rewardMoneyTopTenDTOS = rewardMoneyTopTen(dto);
+
+        redisCache.setCacheObject( String.format("%s:%d:%d:%d:%d", CHARTS_REWARD_MONEY_TOP_TEN, type,dataType,userType,companyId), rewardMoneyTopTenDTOS);
+
+    }
+
+    @Override
+    public void rewardMoneyTradeTask(Integer type, Integer userType,Long companyId) {
+        AnalysisPreviewQueryDTO dto = new AnalysisPreviewQueryDTO();
+        dto.setType(type);
+
+        String startDate = "";
+        String endDate = "";
+
+        LocalDateTime now = LocalDateTime.now();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        LocalTime startOfDayTime = LocalTime.MIN;
+        LocalTime endOfDayTime = LocalTime.of(23, 59, 59);
+
+        if(0 == type){
+            LocalDateTime startOfDay = now.with(startOfDayTime);
+            LocalDateTime endOfDay = now.with(endOfDayTime);
+            startDate = startOfDay.format(formatter);
+            endDate = endOfDay.format(formatter);
+        } else if(1 == type){
+            LocalDateTime yesterday = now.minusDays(1);
+            LocalDateTime startOfYesterday = yesterday.with(startOfDayTime);
+            LocalDateTime endOfYesterday = yesterday.with(endOfDayTime);
+            startDate = startOfYesterday.format(formatter);
+            endDate = endOfYesterday.format(formatter);
+        } else if(2 == type) {
+            LocalDateTime startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+            LocalDateTime startOfStartOfWeek = startOfWeek.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfWeek.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(3 == type) {
+            LocalDateTime startOfMonth = now.withDayOfMonth(1);
+            LocalDateTime startOfStartOfMonth = startOfMonth.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfMonth.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(4 == type) {
+            LocalDateTime firstDayOfPreviousMonth = now.minusMonths(1).withDayOfMonth(1);
+            LocalDateTime lastDayOfPreviousMonth = now.withDayOfMonth(1).minusDays(1);
+
+            LocalDateTime startOfPrevMonthStart = firstDayOfPreviousMonth.with(startOfDayTime);
+            LocalDateTime endOfPrevMonthEnd = lastDayOfPreviousMonth.with(endOfDayTime);
+
+            startDate = startOfPrevMonthStart.format(formatter);
+            endDate = endOfPrevMonthEnd.format(formatter);
+        }
+
+        dto.setStartTime(startDate);
+        dto.setEndTime(endDate);
+        dto.setUserType(userType);
+        dto.setCompanyId(companyId);
+        List<RewardMoneyTrendDTO> rewardMoneyTrendDTOS = rewardMoneyTrendDTO(dto);
+        redisCache.setCacheObject( String.format("%s:%d:%d", CHARTS_REWARD_MONEY_TREND, type,userType), rewardMoneyTrendDTOS);
+
+    }
+
+
+    public void rewardMoneyTask15Minutes(){
+        List<OptionsVO> optionsVOS = companyService.selectAllCompanyList();
+        for (OptionsVO optionsVO : optionsVOS) {
+            Long companyId = optionsVO.getDictValue();
+            if (companyId == null) {
+                continue;
+            }
+            rewardMoneyTopTenTask(0,0,1,companyId);
+            rewardMoneyTopTenTask(0,1,1,companyId);
+
+            rewardMoneyTradeTask(0,1,companyId);
+
+            rewardMoneyTopTenTask(0,0,2,companyId);
+            rewardMoneyTopTenTask(0,1,2,companyId);
+
+            rewardMoneyTradeTask(0,2,companyId);
+        }
+
+    }
+
+
+    public void rewardMoneyTaskEveryday(){
+        List<OptionsVO> optionsVOS = companyService.selectAllCompanyList();
+        for (OptionsVO optionsVO : optionsVOS) {
+            Long companyId = optionsVO.getDictValue();
+            if (companyId == null) {
+                continue;
+            }
+
+            rewardMoneyTopTenTask(1,0,1,companyId);
+            rewardMoneyTopTenTask(1,1,1,companyId);
+
+
+            rewardMoneyTopTenTask(2,0,1,companyId);
+            rewardMoneyTopTenTask(2,1,1,companyId);
+
+            rewardMoneyTopTenTask(3,0,1,companyId);
+            rewardMoneyTopTenTask(3,1,1,companyId);
+
+            rewardMoneyTopTenTask(4,0,1,companyId);
+            rewardMoneyTopTenTask(4,1,1,companyId);
+
+
+            rewardMoneyTradeTask(1,1,companyId);
+            rewardMoneyTradeTask(2,1,companyId);
+            rewardMoneyTradeTask(3,1,companyId);
+            rewardMoneyTradeTask(4,1,companyId);
+
+
+            rewardMoneyTopTenTask(1,0,2,companyId);
+            rewardMoneyTopTenTask(1,1,2,companyId);
+            rewardMoneyTopTenTask(2,0,2,companyId);
+            rewardMoneyTopTenTask(2,1,2,companyId);
+            rewardMoneyTopTenTask(3,0,2,companyId);
+            rewardMoneyTopTenTask(3,1,2,companyId);
+            rewardMoneyTopTenTask(4,0,2,companyId);
+            rewardMoneyTopTenTask(4,1,2,companyId);
+
+            rewardMoneyTradeTask(1,2,companyId);
+            rewardMoneyTradeTask(2,2,companyId);
+            rewardMoneyTradeTask(3,2,companyId);
+            rewardMoneyTradeTask(4,2,companyId);
+        }
+
+    }
+
+    @Override
+    public DealerAggregatedDTO dealerAggregated(Long companyId) {
+        Long dayUserCount=userService.selectFsUserCount(1,companyId);
+        Long storeOrderCount=storeOrderService.selectFsStoreOrderTotalCount(0,companyId);
+        Long dayStoreOrderCount=storeOrderService.selectFsStoreOrderTotalCount(1,companyId);
+        Long paymentCount=paymentService.selectFsStorePaymentCount(0,companyId);
+        Long dayPaymentCount=paymentService.selectFsStorePaymentCount(1,companyId);
+        Long productCount=productService.selectFsStoreProductCount(0,companyId);
+        Long dayProductCount=productService.selectFsStoreProductCount(1,companyId);
+        DealerAggregatedDTO dealerAggregatedDTO = consumptionBalanceMapper.dealerAggregatedCompanyId(companyId);
+        dealerAggregatedDTO.setTodayIncreaseUserNum(dayUserCount);
+        dealerAggregatedDTO.setOrderTotalNum(storeOrderCount);
+        dealerAggregatedDTO.setTodayOrderNum(dayStoreOrderCount);
+        dealerAggregatedDTO.setRecvTodayNum(paymentCount);
+        dealerAggregatedDTO.setRecvTodayNum(dayPaymentCount);
+        dealerAggregatedDTO.setGoodsTotalNum(productCount);
+        dealerAggregatedDTO.setTodayGoodsNum(dayProductCount);
+        return dealerAggregatedDTO;
+    }
+
+    @Override
+    public ConsumptionBalanceDataDTO rechargeConsumption(Long companyId) {
+        // 获取流量统计数据
+        TrafficLogDTO trafficLog = this.getTrafficLog(companyId);
+
+        // 获取流量价格配置
+        SysConfig config = configService.selectConfigByConfigKey("statis.config");
+        Asserts.notNull(config, "流量价格配置不能为空!");
+        JSONObject jsonObject = JSONObject.parseObject(config.getConfigValue());
+        float trafficPrice = jsonObject.getFloatValue("trafficPrice");
+
+        // 创建消费余额数据对象
+        ConsumptionBalanceDataDTO consumptionBalanceData = new ConsumptionBalanceDataDTO();
+
+        // 计算消费金额(将流量从字节转换为GB,然后乘以每GB价格)
+        BigDecimal todayConsumption = calculateTrafficCost(trafficLog.getToday(), trafficPrice);
+        BigDecimal yesterdayConsumption = calculateTrafficCost(trafficLog.getYesterday(), trafficPrice);
+
+        // 设置消费数据
+        consumptionBalanceData.setTodayComsumption(todayConsumption);
+        consumptionBalanceData.setYesterdayComsumption(yesterdayConsumption);
+
+        // 从数据库获取当前余额
+        BigDecimal currentBalance = consumptionBalanceMapper.getCurrentBalanceCompanyId(companyId);
+        consumptionBalanceData.setBalance(currentBalance);
+
+        return consumptionBalanceData;
+    }
+    /**
+     * 计算流量消费金额
+     * @param trafficBytes 流量字节数
+     * @param pricePerGB 每GB价格
+     * @return 消费金额
+     */
+    private BigDecimal calculateTrafficCost(Long trafficBytes, float pricePerGB) {
+        if (trafficBytes == null || trafficBytes <= 0) {
+            return BigDecimal.ZERO;
+        }
+
+        // 将字节转换为GB (1GB = 1024^3 bytes)
+        BigDecimal trafficGB = new BigDecimal(trafficBytes)
+                .divide(new BigDecimal(1024 * 1024 * 1024), 6, BigDecimal.ROUND_HALF_UP);
+
+        // 计算消费金额
+        return trafficGB.multiply(new BigDecimal(pricePerGB)).setScale(2, BigDecimal.ROUND_HALF_UP);
+    }
+
+
+    @Override
+    public AnalysisPreviewDTO analysisPreview(AnalysisPreviewQueryDTO param) {
+        AnalysisPreviewDTO dto = new AnalysisPreviewDTO();
+
+        Long watchUserCount = consumptionBalanceMapper.queryWatchUserCount(param);
+        Long completedUserCount = consumptionBalanceMapper.queryCompletedUserCount(param);
+
+        if(watchUserCount == null){
+            watchUserCount = 0L;
+        }
+        if(completedUserCount == null){
+            completedUserCount = 0L;
+        }
+
+        // 观看人数
+        dto.setWatchUserCount(watchUserCount);
+        // 完播人数
+        dto.setCompletedUserCount(completedUserCount);
+
+        // 完播率
+        if(!ObjectUtils.equals(watchUserCount,0L)){
+            BigDecimal multiply = (BigDecimal.valueOf(completedUserCount)
+                    .divide(BigDecimal.valueOf(watchUserCount),4,BigDecimal.ROUND_HALF_UP))
+                    .multiply(BigDecimal.valueOf(100));
+
+            dto.setCompletedRate(multiply.setScale(2,BigDecimal.ROUND_HALF_UP).toPlainString());
+        } else {
+            dto.setCompletedRate("0");
+        }
+
+        Long watchCount = consumptionBalanceMapper.queryWatchCount(param);
+        Long completedCount = consumptionBalanceMapper.queryCompletedCount(param);
+
+        if(watchCount == null){
+            watchCount = 0L;
+        }
+        if(completedCount == null){
+            completedCount = 0L;
+        }
+
+        // 观看次数
+        dto.setWatchCount(watchCount);
+        // 完播次数
+        dto.setCompletedCount(completedCount);
+        // 视频完播率
+        if(!ObjectUtils.equals(watchCount, 0L)){
+            BigDecimal multiply = BigDecimal.valueOf(completedCount)
+                    .divide(BigDecimal.valueOf(watchCount),4,BigDecimal.ROUND_HALF_UP)
+                    .multiply(BigDecimal.valueOf(100));
+
+            dto.setWatchRate(multiply.setScale(2,BigDecimal.ROUND_HALF_UP).toPlainString());
+        } else {
+            dto.setWatchRate("0");
+        }
+
+        Long answerMemberCount = consumptionBalanceMapper.queryAnswerMemberCount(param);
+        Long correctUserCount = consumptionBalanceMapper.queryCorrectUserCount(param);
+
+        if(answerMemberCount == null){
+            answerMemberCount = 0L;
+        }
+        if(correctUserCount == null){
+            correctUserCount = 0L;
+        }
+        // 答题人数
+        dto.setAnswerMemberCount(answerMemberCount);
+        // 正确人数
+        dto.setCorrectUserCount(correctUserCount);
+        // 正确比例
+        if(!ObjectUtils.equals(answerMemberCount, 0L)){
+            BigDecimal multiply = BigDecimal.valueOf(correctUserCount)
+                    .divide(BigDecimal.valueOf(answerMemberCount),4,BigDecimal.ROUND_HALF_UP)
+                    .multiply(BigDecimal.valueOf(100));
+
+            dto.setCorrectRate(multiply.setScale(2, RoundingMode.HALF_UP).toPlainString());
+        } else {
+            dto.setCorrectRate("0");
+        }
+        Long rewardCount = consumptionBalanceMapper.queryRewardCount(param);
+        if(rewardCount == null) {
+            rewardCount = 0L;
+        }
+        BigDecimal rewardMoney = consumptionBalanceMapper.queryRewardMoney(param);
+        if(rewardMoney == null) {
+            rewardMoney = BigDecimal.ZERO;
+        }
+        // 答题红包个数
+        dto.setRewardCount(rewardCount);
+        // 答题红包金额
+        dto.setRewardMoney(rewardMoney);
+
+        return dto;
+    }
+
+
+    @Override
+    public Long smsBalance(Long companyId) {
+        Long smsBalance = consumptionBalanceMapper.smsBalanceCompany(companyId);
+        if(smsBalance != null) {
+            smsBalance = 0L;
+        }
+        return smsBalance;
+    }
+
+    @Override
+    public AuthorizationInfoDTO authorizationInfo() {
+        return consumptionBalanceMapper.authorizationInfo();
+    }
+
+    @Override
+    public List<WatchEndPlayTrendDTO> watchEndPlayTrend(AnalysisPreviewQueryDTO param) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<DeaMemberTopTenDTO> deaMemberTopTen(AnalysisPreviewQueryDTO param) {
+        List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = consumptionBalanceMapper.deaMemberTopTen(param);
+        for (DeaMemberTopTenDTO dto : deaMemberTopTenDTOS) {
+            Long companyId = dto.getCompanyId();
+            String companyName = companyCacheService.selectCompanyNameById(companyId);
+            if(StringUtils.isNotBlank(companyName)){
+                dto.setCompanyName(companyName);
+            }
+        }
+        return deaMemberTopTenDTOS;
+    }
+
+    @Override
+    public List<CourseStatsDTO> watchCourseTopTen(AnalysisPreviewQueryDTO param) {
+        List<CourseStatsDTO> courseStatsDTOS = consumptionBalanceMapper.watchCourseTopTen(param);
+        for (CourseStatsDTO courseStatsDTO : courseStatsDTOS) {
+            String courseName = fsUserCourseCacheService.selectCourseNameByCourseId(courseStatsDTO.getCourseId());
+            if(StringUtils.isNotBlank(courseName)){
+                courseStatsDTO.setCourseName(courseName);
+            }
+        }
+        return courseStatsDTOS;
+    }
+
+    @Override
+    public List<RewardMoneyTopTenDTO> rewardMoneyTopTen(AnalysisPreviewQueryDTO param) {
+        List<RewardMoneyTopTenDTO> rewardMoneyTopTenDTOS = consumptionBalanceMapper.rewardMoneyTopTen(param);
+        for (RewardMoneyTopTenDTO dto : rewardMoneyTopTenDTOS) {
+            if(dto.getCompanyId() != null) {
+                String companyName = companyCacheService.selectCompanyNameById(dto.getCompanyId());
+                dto.setCompanyName(companyName);
+            }
+            if(dto.getCourseId() != null){
+                String courseName = fsUserCourseCacheService.selectCourseNameByCourseId(dto.getCourseId());
+                dto.setCourseName(courseName);
+            }
+
+        }
+        return rewardMoneyTopTenDTOS;
+    }
+
+    @Override
+    public List<RewardMoneyTrendDTO> rewardMoneyTrendDTO(AnalysisPreviewQueryDTO param) {
+        List<RewardMoneyTrendDTO> rewardMoneyTrendDTOS = consumptionBalanceMapper.rewardMoneyTrendDTO(param);
+
+        // 今日,昨日 格式为24小时
+        if(ObjectUtils.equals(param.getType(),0) || ObjectUtils.equals(param.getType(),1)){
+            rewardMoneyTrendDTOS = TrendDataFiller.fillRewardHourData(rewardMoneyTrendDTOS);
+            // 否则都是按天为维度的时间范围
+        } else {
+            rewardMoneyTrendDTOS = TrendDataFiller.fillRewardDateSegmentData(rewardMoneyTrendDTOS, param.getStartTime(), param.getEndTime());
+        }
+
+
+        return rewardMoneyTrendDTOS;
+    }
+
+    @Override
+    public TrafficLogDTO getTrafficLog(Long companyId) {
+        TrafficLogDTO trafficLogDTO = new TrafficLogDTO();
+        Long todayTrafficLog = fsCourseTrafficLogMapper.getTodayTrafficLogCompanyId(companyId);
+        Long yesterdayTrafficLog = fsCourseTrafficLogMapper.getYesterdayTrafficLogCompanyId(companyId);
+        Long monthTrafficLog = fsCourseTrafficLogMapper.getMonthTrafficLogCompanyId(companyId);
+        trafficLogDTO.setToday(todayTrafficLog);
+        trafficLogDTO.setThisMonth(monthTrafficLog);
+        trafficLogDTO.setYesterday(yesterdayTrafficLog);
+        return trafficLogDTO;
+    }
+
+    public void companyThisMonthOrderCount(){
+        List<OptionsVO> optionsVOS = companyService.selectAllCompanyList();
+        for (OptionsVO optionsVO : optionsVOS) {
+            Long companyId = optionsVO.getDictValue();
+            if (companyId == null) {
+                continue;
+            }
+            this.thisMonthOrderCount(companyId);
+            this.thisMonthRecvCount(companyId);
+        }
+    }
+    @Override
+    public void thisMonthOrderCount(Long companyId) {
+        Long[] users=new Long[0];
+        TimeUtils.TimeEntity timeEntity=TimeUtils.parseTime("5",null,null);
+        timeEntity.setUserIds(users);
+        timeEntity.setCompanyId(companyId);
+        Integer cycleNum = timeEntity.getCycleNum();
+        Integer beginTime = timeEntity.getBeginTime();
+        List<Integer> timeList = new ArrayList<>();
+        for (int i = 1; i <= cycleNum; i++) {
+            timeList.add(beginTime);
+            beginTime = TimeUtils.formatTime(beginTime);
+        }
+        List<JSONObject> jsonObjectList = storeOrderService.selectFsStoreOrderCounts(timeEntity.toMap());
+        List<String> dates = jsonObjectList.stream().map(jsonObject -> jsonObject.getString("type")).collect(Collectors.toList());
+        List<Integer> orderCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("orderCount")).collect(Collectors.toList());
+        List<Integer> payPrice = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("payPrice")).collect(Collectors.toList());
+        R result = R.ok().put("dates", dates).put("orderCount", orderCount).put("payPrice", payPrice);
+        redisCache.setCacheObject(String.format(THIS_MONTH_ORDER_COUNT+":%d",companyId),result);
+    }
+
+    @Override
+    public void thisMonthRecvCount(Long companyId) {
+        Long[] users=new Long[0];
+        TimeUtils.TimeEntity timeEntity=TimeUtils.parseTime("5",null,null);
+        timeEntity.setUserIds(users);
+        timeEntity.setCompanyId(companyId);
+        Integer cycleNum = timeEntity.getCycleNum();
+        Integer beginTime = timeEntity.getBeginTime();
+        List<Integer> timeList = new ArrayList<>();
+        for (int i = 1; i <= cycleNum; i++) {
+            timeList.add(beginTime);
+            beginTime = TimeUtils.formatTime(beginTime);
+        }
+        List<JSONObject> jsonObjectList = paymentService.selectFsStorePaymentCounts(timeEntity.toMap());
+        List<String> dates = jsonObjectList.stream().map(jsonObject -> jsonObject.getString("type")).collect(Collectors.toList());
+        List<Integer> orderCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("orderCount")).collect(Collectors.toList());
+        List<Float> payMoney = jsonObjectList.stream().map(jsonObject -> jsonObject.getFloatValue("payMoney")).collect(Collectors.toList());
+        R result = R.ok().put("dates", dates).put("orderCount", orderCount).put("payMoney", payMoney);
+        redisCache.setCacheObject(String.format(THIS_MONTH_RECV_COUNT+":%d",companyId),result);
+    }
+}

+ 968 - 0
fs-service/src/main/java/com/fs/statis/service/impl/StatisticsServiceImpl.java

@@ -0,0 +1,968 @@
+package com.fs.statis.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.TimeUtils;
+import com.fs.company.cache.ICompanyCacheService;
+import com.fs.course.mapper.FsCourseTrafficLogMapper;
+import com.fs.his.service.IFsStoreOrderService;
+import com.fs.his.service.IFsStorePaymentService;
+import com.fs.his.service.IFsStoreProductService;
+import com.fs.his.service.IFsUserService;
+import com.fs.statis.StatisticsRedisConstant;
+import com.fs.statis.dto.*;
+import com.fs.statis.mapper.ConsumptionBalanceMapper;
+import com.fs.statis.service.IStatisticsService;
+import com.fs.statis.service.utils.TrendDataFiller;
+import com.fs.store.service.cache.IFsUserCourseCacheService;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.service.ISysConfigService;
+import com.hc.openapi.tool.util.ObjectUtils;
+import com.hc.openapi.tool.util.StringUtils;
+import org.apache.http.util.Asserts;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.DayOfWeek;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAdjusters;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.fs.statis.StatisticsRedisConstant.*;
+
+@Service("statisticsService")
+public class StatisticsServiceImpl implements IStatisticsService {
+    @Autowired
+    private ConsumptionBalanceMapper consumptionBalanceMapper;
+
+    @Autowired
+    private IFsUserCourseCacheService fsUserCourseCacheService;
+
+    @Autowired
+    private ICompanyCacheService companyCacheService;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @Autowired
+    private FsCourseTrafficLogMapper fsCourseTrafficLogMapper;
+    @Autowired
+    private IFsUserService userService;
+
+    @Autowired
+    private IFsStoreOrderService storeOrderService;
+
+    @Autowired
+    private IFsStorePaymentService paymentService;
+
+    @Autowired
+    private IFsStoreProductService productService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Override
+    public void dataOverviewTask() {
+        DealerAggregatedDTO dealerAggregatedDTO = this.dealerAggregated();
+        ConsumptionBalanceDataDTO consumptionBalanceDataDTO = this.rechargeConsumption();
+        AuthorizationInfoDTO authorizationInfoDTO = authorizationInfo();
+        Long smsBalance = this.smsBalance();
+        TrafficLogDTO trafficLog = this.getTrafficLog();
+
+        redisCache.setCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_AGGREGATED, dealerAggregatedDTO);
+        redisCache.setCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_BALANCE, consumptionBalanceDataDTO);
+        redisCache.setCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_AUTHORIZATION_INFO, authorizationInfoDTO);
+        redisCache.setCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_SMS_BALANCE, smsBalance);
+        redisCache.setCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_TRAFFIC_LOG,trafficLog);
+    }
+
+
+    public void analysisPreviewTask0(){
+        analysisPreviewTask(0,1);
+        analysisPreviewTask(0,2);
+    }
+
+    public void analysisPreviewTask1(){
+        analysisPreviewTask(0,1);
+        analysisPreviewTask(1,1);
+        analysisPreviewTask(2,1);
+        analysisPreviewTask(3,1);
+        analysisPreviewTask(4,1);
+
+        analysisPreviewTask(0,2);
+        analysisPreviewTask(1,2);
+        analysisPreviewTask(2,2);
+        analysisPreviewTask(3,2);
+        analysisPreviewTask(4,2);
+    }
+
+
+    @Override
+    public void analysisPreviewTask(Integer type,Integer userType) {
+        // 根据type计算出时间范围
+        String startDate = "";
+        String endDate = "";
+
+        LocalDateTime now = LocalDateTime.now();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        LocalTime startOfDayTime = LocalTime.MIN;
+        LocalTime endOfDayTime = LocalTime.of(23, 59, 59);
+
+        if(0 == type){
+            LocalDateTime startOfDay = now.with(startOfDayTime);
+            LocalDateTime endOfDay = now.with(endOfDayTime);
+            startDate = startOfDay.format(formatter);
+            endDate = endOfDay.format(formatter);
+        } else if(1 == type){
+            LocalDateTime yesterday = now.minusDays(1);
+            LocalDateTime startOfYesterday = yesterday.with(startOfDayTime);
+            LocalDateTime endOfYesterday = yesterday.with(endOfDayTime);
+            startDate = startOfYesterday.format(formatter);
+            endDate = endOfYesterday.format(formatter);
+        } else if(2 == type) {
+            LocalDateTime startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+            LocalDateTime startOfStartOfWeek = startOfWeek.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfWeek.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(3 == type) {
+            LocalDateTime startOfMonth = now.withDayOfMonth(1);
+            LocalDateTime startOfStartOfMonth = startOfMonth.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfMonth.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(4 == type) {
+            LocalDateTime firstDayOfPreviousMonth = now.minusMonths(1).withDayOfMonth(1);
+            LocalDateTime lastDayOfPreviousMonth = now.withDayOfMonth(1).minusDays(1);
+
+            LocalDateTime startOfPrevMonthStart = firstDayOfPreviousMonth.with(startOfDayTime);
+            LocalDateTime endOfPrevMonthEnd = lastDayOfPreviousMonth.with(endOfDayTime);
+
+            startDate = startOfPrevMonthStart.format(formatter);
+            endDate = endOfPrevMonthEnd.format(formatter);
+        }
+
+        AnalysisPreviewQueryDTO param = new AnalysisPreviewQueryDTO();
+        param.setStartTime(startDate);
+        param.setEndTime(endDate);
+        param.setType(type);
+        param.setUserType(userType);
+
+        AnalysisPreviewDTO analysisPreviewDTO = this.analysisPreview(param);
+
+        redisCache.setCacheObject(String.format("%s:%d:%d",DATA_OVERVIEW_DEALER_ANALYSISPREVIEW,type,userType), analysisPreviewDTO);
+    }
+
+    public void watchEndPlayTrendTask0(){
+        this.watchEndPlayTrendTask(0,1);
+        this.watchEndPlayTrendTask(0,2);
+    }
+
+    public void watchEndPlayTrendTask1(){
+        this.watchEndPlayTrendTask(1,1);
+        this.watchEndPlayTrendTask(2,1);
+        this.watchEndPlayTrendTask(3,1);
+        this.watchEndPlayTrendTask(4,1);
+
+        this.watchEndPlayTrendTask(1,2);
+        this.watchEndPlayTrendTask(2,2);
+        this.watchEndPlayTrendTask(3,2);
+        this.watchEndPlayTrendTask(4,2);
+    }
+
+
+    @Override
+    public void watchEndPlayTrendTask(Integer type,Integer userType) {
+        // 根据type计算出时间范围
+        String startDate = "";
+        String endDate = "";
+
+        LocalDateTime now = LocalDateTime.now();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        LocalTime startOfDayTime = LocalTime.MIN;
+        LocalTime endOfDayTime = LocalTime.of(23, 59, 59);
+
+        if(0 == type){
+            LocalDateTime startOfDay = now.with(startOfDayTime);
+            LocalDateTime endOfDay = now.with(endOfDayTime);
+            startDate = startOfDay.format(formatter);
+            endDate = endOfDay.format(formatter);
+        } else if(1 == type){
+            LocalDateTime yesterday = now.minusDays(1);
+            LocalDateTime startOfYesterday = yesterday.with(startOfDayTime);
+            LocalDateTime endOfYesterday = yesterday.with(endOfDayTime);
+            startDate = startOfYesterday.format(formatter);
+            endDate = endOfYesterday.format(formatter);
+        } else if(2 == type) {
+            LocalDateTime startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+            LocalDateTime startOfStartOfWeek = startOfWeek.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfWeek.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(3 == type) {
+            LocalDateTime startOfMonth = now.withDayOfMonth(1);
+            LocalDateTime startOfStartOfMonth = startOfMonth.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfMonth.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(4 == type) {
+            LocalDateTime firstDayOfPreviousMonth = now.minusMonths(1).withDayOfMonth(1);
+            LocalDateTime lastDayOfPreviousMonth = now.withDayOfMonth(1).minusDays(1);
+
+            LocalDateTime startOfPrevMonthStart = firstDayOfPreviousMonth.with(startOfDayTime);
+            LocalDateTime endOfPrevMonthEnd = lastDayOfPreviousMonth.with(endOfDayTime);
+
+            startDate = startOfPrevMonthStart.format(formatter);
+            endDate = endOfPrevMonthEnd.format(formatter);
+        }
+
+        AnalysisPreviewQueryDTO param = new AnalysisPreviewQueryDTO();
+        param.setStartTime(startDate);
+        param.setEndTime(endDate);
+        param.setType(type);
+
+        param.setUserType(userType);
+        List<WatchEndPlayTrendDTO> watchEndPlayTrendDTOS = this.watchEndPlayTrend(param);
+
+        redisCache.setCacheObject(String.format("%s:%d:%d",DATA_OVERVIEW_DEALER_CHARTS,type,userType),watchEndPlayTrendDTOS);
+
+    }
+
+
+    public void companyWatchCourseTopTenTask0(){
+        companyWatchCourseTopTenTask(0,0,1);
+        companyWatchCourseTopTenTask(0,1,1);
+
+
+        companyWatchCourseTopTenTask(0,0,2);
+        companyWatchCourseTopTenTask(0,1,2);
+    }
+
+    public void companyWatchCourseTopTenTask1(){
+        companyWatchCourseTopTenTask(1,0,1);
+        companyWatchCourseTopTenTask(1,1,1);
+        companyWatchCourseTopTenTask(2,0,1);
+        companyWatchCourseTopTenTask(2,1,1);
+        companyWatchCourseTopTenTask(3,0,1);
+        companyWatchCourseTopTenTask(3,1,1);
+        companyWatchCourseTopTenTask(4,0,1);
+        companyWatchCourseTopTenTask(4,1,1);
+
+        companyWatchCourseTopTenTask(1,0,2);
+        companyWatchCourseTopTenTask(1,1,2);
+        companyWatchCourseTopTenTask(2,0,2);
+        companyWatchCourseTopTenTask(2,1,2);
+        companyWatchCourseTopTenTask(3,0,2);
+        companyWatchCourseTopTenTask(3,1,2);
+        companyWatchCourseTopTenTask(4,0,2);
+        companyWatchCourseTopTenTask(4,1,2);
+
+
+    }
+
+    @Override
+    public void companyWatchCourseTopTenTask(Integer type,Integer statisticalType,Integer userType) {
+
+        AnalysisPreviewQueryDTO dto = new AnalysisPreviewQueryDTO();
+        dto.setType(type);
+        dto.setStatisticalType(statisticalType);
+
+        String startDate = "";
+        String endDate = "";
+
+        LocalDateTime now = LocalDateTime.now();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        LocalTime startOfDayTime = LocalTime.MIN;
+        LocalTime endOfDayTime = LocalTime.of(23, 59, 59);
+
+        if(0 == type){
+            LocalDateTime startOfDay = now.with(startOfDayTime);
+            LocalDateTime endOfDay = now.with(endOfDayTime);
+            startDate = startOfDay.format(formatter);
+            endDate = endOfDay.format(formatter);
+        } else if(1 == type){
+            LocalDateTime yesterday = now.minusDays(1);
+            LocalDateTime startOfYesterday = yesterday.with(startOfDayTime);
+            LocalDateTime endOfYesterday = yesterday.with(endOfDayTime);
+            startDate = startOfYesterday.format(formatter);
+            endDate = endOfYesterday.format(formatter);
+        } else if(2 == type) {
+            LocalDateTime startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+            LocalDateTime startOfStartOfWeek = startOfWeek.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfWeek.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(3 == type) {
+            LocalDateTime startOfMonth = now.withDayOfMonth(1);
+            LocalDateTime startOfStartOfMonth = startOfMonth.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfMonth.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(4 == type) {
+            LocalDateTime firstDayOfPreviousMonth = now.minusMonths(1).withDayOfMonth(1);
+            LocalDateTime lastDayOfPreviousMonth = now.withDayOfMonth(1).minusDays(1);
+
+            LocalDateTime startOfPrevMonthStart = firstDayOfPreviousMonth.with(startOfDayTime);
+            LocalDateTime endOfPrevMonthEnd = lastDayOfPreviousMonth.with(endOfDayTime);
+
+            startDate = startOfPrevMonthStart.format(formatter);
+            endDate = endOfPrevMonthEnd.format(formatter);
+        }
+
+        dto.setStartTime(startDate);
+        dto.setEndTime(endDate);
+        dto.setUserType(userType);
+
+        List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = deaMemberTopTen(dto);
+        redisCache.setCacheObject(String.format("%s:%d:%d:%d", CHARTS_MEMBER_TOP_TEN_WATCH, type,statisticalType,userType), deaMemberTopTenDTOS);
+    }
+
+    @Override
+    public void watchCourseTopTenTask(Integer type,Integer statisticalType,Integer userType,String sort) {
+        AnalysisPreviewQueryDTO dto = new AnalysisPreviewQueryDTO();
+        dto.setType(type);
+        dto.setStatisticalType(statisticalType);
+        dto.setSort(sort);
+
+        String startDate = "";
+        String endDate = "";
+
+        LocalDateTime now = LocalDateTime.now();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        LocalTime startOfDayTime = LocalTime.MIN;
+        LocalTime endOfDayTime = LocalTime.of(23, 59, 59);
+
+        if(0 == type){
+            LocalDateTime startOfDay = now.with(startOfDayTime);
+            LocalDateTime endOfDay = now.with(endOfDayTime);
+            startDate = startOfDay.format(formatter);
+            endDate = endOfDay.format(formatter);
+        } else if(1 == type){
+            LocalDateTime yesterday = now.minusDays(1);
+            LocalDateTime startOfYesterday = yesterday.with(startOfDayTime);
+            LocalDateTime endOfYesterday = yesterday.with(endOfDayTime);
+            startDate = startOfYesterday.format(formatter);
+            endDate = endOfYesterday.format(formatter);
+        } else if(2 == type) {
+            LocalDateTime startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+            LocalDateTime startOfStartOfWeek = startOfWeek.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfWeek.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(3 == type) {
+            LocalDateTime startOfMonth = now.withDayOfMonth(1);
+            LocalDateTime startOfStartOfMonth = startOfMonth.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfMonth.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(4 == type) {
+            LocalDateTime firstDayOfPreviousMonth = now.minusMonths(1).withDayOfMonth(1);
+            LocalDateTime lastDayOfPreviousMonth = now.withDayOfMonth(1).minusDays(1);
+
+            LocalDateTime startOfPrevMonthStart = firstDayOfPreviousMonth.with(startOfDayTime);
+            LocalDateTime endOfPrevMonthEnd = lastDayOfPreviousMonth.with(endOfDayTime);
+
+            startDate = startOfPrevMonthStart.format(formatter);
+            endDate = endOfPrevMonthEnd.format(formatter);
+        }
+        dto.setStartTime(startDate);
+        dto.setEndTime(endDate);
+        dto.setUserType(userType);
+        List<CourseStatsDTO> courseStatsDTOS = watchCourseTopTen(dto);
+
+        redisCache.setCacheObject( String.format("%s:%d:%d:%d:%s", CHARTS_WATCH_TOP_TEN, type,statisticalType,userType,sort), courseStatsDTOS);
+    }
+
+    public void watchCourseTopTenTask0(){
+        watchCourseTopTenTask(0,0,1,"DESC");
+        watchCourseTopTenTask(0,0,1,"ASC");
+        watchCourseTopTenTask(0,1,1,"DESC");
+        watchCourseTopTenTask(0,1,1,"ASC");
+        watchCourseTopTenTask(0,2,1,"DESC");
+        watchCourseTopTenTask(0,2,1,"ASC");
+        watchCourseTopTenTask(0,3,1,"DESC");
+        watchCourseTopTenTask(0,3,1,"ASC");
+
+        watchCourseTopTenTask(0,0,1,"DESC");
+        watchCourseTopTenTask(0,0,1,"ASC");
+        watchCourseTopTenTask(0,1,1,"DESC");
+        watchCourseTopTenTask(0,1,1,"ASC");
+        watchCourseTopTenTask(0,2,1,"DESC");
+        watchCourseTopTenTask(0,2,1,"ASC");
+        watchCourseTopTenTask(0,3,1,"DESC");
+        watchCourseTopTenTask(0,3,1,"ASC");
+    }
+
+    public void watchCourseTopTenTask1(){
+        watchCourseTopTenTask(1,0,1,"DESC");
+        watchCourseTopTenTask(1,0,1,"ASC");
+
+        watchCourseTopTenTask(1,0,2,"DESC");
+        watchCourseTopTenTask(1,0,2,"ASC");
+
+
+        watchCourseTopTenTask(1,1,1,"DESC");
+        watchCourseTopTenTask(1,1,1,"ASC");
+
+        watchCourseTopTenTask(1,1,2,"DESC");
+        watchCourseTopTenTask(1,1,2,"ASC");
+
+        watchCourseTopTenTask(1,2,1,"DESC");
+        watchCourseTopTenTask(1,2,1,"ASC");
+
+        watchCourseTopTenTask(1,2,2,"DESC");
+        watchCourseTopTenTask(1,2,2,"ASC");
+
+
+        watchCourseTopTenTask(1,3,1,"DESC");
+        watchCourseTopTenTask(1,3,1,"ASC");
+
+        watchCourseTopTenTask(1,3,2,"DESC");
+        watchCourseTopTenTask(1,3,2,"ASC");
+
+        watchCourseTopTenTask(2,0,1,"DESC");
+        watchCourseTopTenTask(2,0,1,"ASC");
+
+        watchCourseTopTenTask(2,0,2,"DESC");
+        watchCourseTopTenTask(2,0,2,"ASC");
+
+        watchCourseTopTenTask(2,1,1,"DESC");
+        watchCourseTopTenTask(2,1,1,"ASC");
+
+        watchCourseTopTenTask(2,1,2,"DESC");
+        watchCourseTopTenTask(2,1,2,"ASC");
+
+        watchCourseTopTenTask(2,2,1,"DESC");
+        watchCourseTopTenTask(2,2,1,"ASC");
+
+        watchCourseTopTenTask(2,2,2,"DESC");
+        watchCourseTopTenTask(2,2,2,"ASC");
+
+
+        watchCourseTopTenTask(2,3,1,"DESC");
+        watchCourseTopTenTask(2,3,1,"ASC");
+
+        watchCourseTopTenTask(2,3,2,"DESC");
+        watchCourseTopTenTask(2,3,2,"ASC");
+
+        watchCourseTopTenTask(3,0,1,"DESC");
+        watchCourseTopTenTask(3,0,1,"ASC");
+
+        watchCourseTopTenTask(3,0,2,"DESC");
+        watchCourseTopTenTask(3,0,2,"ASC");
+
+        watchCourseTopTenTask(3,1,1,"DESC");
+        watchCourseTopTenTask(3,1,1,"ASC");
+
+        watchCourseTopTenTask(3,1,2,"DESC");
+        watchCourseTopTenTask(3,1,2,"ASC");
+
+        watchCourseTopTenTask(3,2,1,"DESC");
+        watchCourseTopTenTask(3,2,1,"ASC");
+
+        watchCourseTopTenTask(3,2,2,"DESC");
+        watchCourseTopTenTask(3,2,2,"ASC");
+
+        watchCourseTopTenTask(3,3,1,"DESC");
+        watchCourseTopTenTask(3,3,1,"ASC");
+
+        watchCourseTopTenTask(3,3,2,"DESC");
+        watchCourseTopTenTask(3,3,2,"ASC");
+
+        watchCourseTopTenTask(4,0,1,"DESC");
+        watchCourseTopTenTask(4,0,1,"ASC");
+
+        watchCourseTopTenTask(4,0,2,"DESC");
+        watchCourseTopTenTask(4,0,2,"ASC");
+
+        watchCourseTopTenTask(4,1,1,"DESC");
+        watchCourseTopTenTask(4,1,1,"ASC");
+        watchCourseTopTenTask(4,2,1,"DESC");
+        watchCourseTopTenTask(4,2,1,"ASC");
+        watchCourseTopTenTask(4,3,1,"DESC");
+        watchCourseTopTenTask(4,3,1,"ASC");
+
+        watchCourseTopTenTask(4,1,2,"DESC");
+        watchCourseTopTenTask(4,1,2,"ASC");
+        watchCourseTopTenTask(4,2,2,"DESC");
+        watchCourseTopTenTask(4,2,2,"ASC");
+        watchCourseTopTenTask(4,3,2,"DESC");
+        watchCourseTopTenTask(4,3,2,"ASC");
+    }
+
+
+    public void rewardMoneyTask15Minutes(){
+        rewardMoneyTopTenTask(0,0,1);
+        rewardMoneyTopTenTask(0,1,1);
+
+        rewardMoneyTradeTask(0,1);
+
+        rewardMoneyTopTenTask(0,0,2);
+        rewardMoneyTopTenTask(0,1,2);
+
+        rewardMoneyTradeTask(0,2);
+    }
+
+
+    public void rewardMoneyTaskEveryday(){
+        rewardMoneyTopTenTask(1,0,1);
+        rewardMoneyTopTenTask(1,1,1);
+
+
+        rewardMoneyTopTenTask(2,0,1);
+        rewardMoneyTopTenTask(2,1,1);
+
+        rewardMoneyTopTenTask(3,0,1);
+        rewardMoneyTopTenTask(3,1,1);
+
+        rewardMoneyTopTenTask(4,0,1);
+        rewardMoneyTopTenTask(4,1,1);
+
+
+        rewardMoneyTradeTask(1,1);
+        rewardMoneyTradeTask(2,1);
+        rewardMoneyTradeTask(3,1);
+        rewardMoneyTradeTask(4,1);
+
+
+        rewardMoneyTopTenTask(1,0,2);
+        rewardMoneyTopTenTask(1,1,2);
+        rewardMoneyTopTenTask(2,0,2);
+        rewardMoneyTopTenTask(2,1,2);
+        rewardMoneyTopTenTask(3,0,2);
+        rewardMoneyTopTenTask(3,1,2);
+        rewardMoneyTopTenTask(4,0,2);
+        rewardMoneyTopTenTask(4,1,2);
+
+        rewardMoneyTradeTask(1,2);
+        rewardMoneyTradeTask(2,2);
+        rewardMoneyTradeTask(3,2);
+        rewardMoneyTradeTask(4,2);
+    }
+
+    @Override
+    public void rewardMoneyTopTenTask(Integer type,Integer dataType,Integer userType) {
+        AnalysisPreviewQueryDTO dto = new AnalysisPreviewQueryDTO();
+        dto.setType(type);
+        dto.setDataType(dataType);
+
+        String startDate = "";
+        String endDate = "";
+
+        LocalDateTime now = LocalDateTime.now();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        LocalTime startOfDayTime = LocalTime.MIN;
+        LocalTime endOfDayTime = LocalTime.of(23, 59, 59);
+
+        if(0 == type){
+            LocalDateTime startOfDay = now.with(startOfDayTime);
+            LocalDateTime endOfDay = now.with(endOfDayTime);
+            startDate = startOfDay.format(formatter);
+            endDate = endOfDay.format(formatter);
+        } else if(1 == type){
+            LocalDateTime yesterday = now.minusDays(1);
+            LocalDateTime startOfYesterday = yesterday.with(startOfDayTime);
+            LocalDateTime endOfYesterday = yesterday.with(endOfDayTime);
+            startDate = startOfYesterday.format(formatter);
+            endDate = endOfYesterday.format(formatter);
+        } else if(2 == type) {
+            LocalDateTime startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+            LocalDateTime startOfStartOfWeek = startOfWeek.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfWeek.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(3 == type) {
+            LocalDateTime startOfMonth = now.withDayOfMonth(1);
+            LocalDateTime startOfStartOfMonth = startOfMonth.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfMonth.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(4 == type) {
+            LocalDateTime firstDayOfPreviousMonth = now.minusMonths(1).withDayOfMonth(1);
+            LocalDateTime lastDayOfPreviousMonth = now.withDayOfMonth(1).minusDays(1);
+
+            LocalDateTime startOfPrevMonthStart = firstDayOfPreviousMonth.with(startOfDayTime);
+            LocalDateTime endOfPrevMonthEnd = lastDayOfPreviousMonth.with(endOfDayTime);
+
+            startDate = startOfPrevMonthStart.format(formatter);
+            endDate = endOfPrevMonthEnd.format(formatter);
+        }
+
+        dto.setStartTime(startDate);
+        dto.setEndTime(endDate);
+        dto.setUserType(userType);
+
+        List<RewardMoneyTopTenDTO> rewardMoneyTopTenDTOS = rewardMoneyTopTen(dto);
+
+        redisCache.setCacheObject( String.format("%s:%d:%d:%d", CHARTS_REWARD_MONEY_TOP_TEN, type,dataType,userType), rewardMoneyTopTenDTOS);
+
+    }
+
+    @Override
+    public void rewardMoneyTradeTask(Integer type,Integer userType) {
+        AnalysisPreviewQueryDTO dto = new AnalysisPreviewQueryDTO();
+        dto.setType(type);
+
+        String startDate = "";
+        String endDate = "";
+
+        LocalDateTime now = LocalDateTime.now();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        LocalTime startOfDayTime = LocalTime.MIN;
+        LocalTime endOfDayTime = LocalTime.of(23, 59, 59);
+
+        if(0 == type){
+            LocalDateTime startOfDay = now.with(startOfDayTime);
+            LocalDateTime endOfDay = now.with(endOfDayTime);
+            startDate = startOfDay.format(formatter);
+            endDate = endOfDay.format(formatter);
+        } else if(1 == type){
+            LocalDateTime yesterday = now.minusDays(1);
+            LocalDateTime startOfYesterday = yesterday.with(startOfDayTime);
+            LocalDateTime endOfYesterday = yesterday.with(endOfDayTime);
+            startDate = startOfYesterday.format(formatter);
+            endDate = endOfYesterday.format(formatter);
+        } else if(2 == type) {
+            LocalDateTime startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+            LocalDateTime startOfStartOfWeek = startOfWeek.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfWeek.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(3 == type) {
+            LocalDateTime startOfMonth = now.withDayOfMonth(1);
+            LocalDateTime startOfStartOfMonth = startOfMonth.with(startOfDayTime);
+            LocalDateTime endOfToday = now.with(endOfDayTime);
+            startDate = startOfStartOfMonth.format(formatter);
+            endDate = endOfToday.format(formatter);
+        } else if(4 == type) {
+            LocalDateTime firstDayOfPreviousMonth = now.minusMonths(1).withDayOfMonth(1);
+            LocalDateTime lastDayOfPreviousMonth = now.withDayOfMonth(1).minusDays(1);
+
+            LocalDateTime startOfPrevMonthStart = firstDayOfPreviousMonth.with(startOfDayTime);
+            LocalDateTime endOfPrevMonthEnd = lastDayOfPreviousMonth.with(endOfDayTime);
+
+            startDate = startOfPrevMonthStart.format(formatter);
+            endDate = endOfPrevMonthEnd.format(formatter);
+        }
+
+        dto.setStartTime(startDate);
+        dto.setEndTime(endDate);
+        dto.setUserType(userType);
+        List<RewardMoneyTrendDTO> rewardMoneyTrendDTOS = rewardMoneyTrendDTO(dto);
+        redisCache.setCacheObject( String.format("%s:%d:%d", CHARTS_REWARD_MONEY_TREND, type,userType), rewardMoneyTrendDTOS);
+
+    }
+
+
+
+    @Override
+    public DealerAggregatedDTO dealerAggregated() {
+        Long dayUserCount=userService.selectFsUserCount(1,null);
+        Long storeOrderCount=storeOrderService.selectFsStoreOrderTotalCount(0,null);
+        Long dayStoreOrderCount=storeOrderService.selectFsStoreOrderTotalCount(1,null);
+        Long paymentCount=paymentService.selectFsStorePaymentCount(0,null);
+        Long dayPaymentCount=paymentService.selectFsStorePaymentCount(1,null);
+        Long productCount=productService.selectFsStoreProductCount(0);
+        Long dayProductCount=productService.selectFsStoreProductCount(1);
+        DealerAggregatedDTO dealerAggregatedDTO = consumptionBalanceMapper.dealerAggregated();
+        dealerAggregatedDTO.setTodayIncreaseUserNum(dayUserCount);
+        dealerAggregatedDTO.setOrderTotalNum(storeOrderCount);
+        dealerAggregatedDTO.setTodayOrderNum(dayStoreOrderCount);
+        dealerAggregatedDTO.setRecvTodayNum(paymentCount);
+        dealerAggregatedDTO.setRecvTodayNum(dayPaymentCount);
+        dealerAggregatedDTO.setGoodsTotalNum(productCount);
+        dealerAggregatedDTO.setTodayGoodsNum(dayProductCount);
+        return dealerAggregatedDTO;
+    }
+
+    @Override
+    public ConsumptionBalanceDataDTO rechargeConsumption() {
+        // 获取流量统计数据
+        TrafficLogDTO trafficLog = this.getTrafficLog();
+
+        // 获取流量价格配置
+        SysConfig config = configService.selectConfigByConfigKey("statis.config");
+        Asserts.notNull(config, "流量价格配置不能为空!");
+        JSONObject jsonObject = JSONObject.parseObject(config.getConfigValue());
+        float trafficPrice = jsonObject.getFloatValue("trafficPrice");
+
+        // 创建消费余额数据对象
+        ConsumptionBalanceDataDTO consumptionBalanceData = new ConsumptionBalanceDataDTO();
+
+        // 计算消费金额(将流量从字节转换为GB,然后乘以每GB价格)
+        BigDecimal todayConsumption = calculateTrafficCost(trafficLog.getToday(), trafficPrice);
+        BigDecimal yesterdayConsumption = calculateTrafficCost(trafficLog.getYesterday(), trafficPrice);
+
+        // 设置消费数据
+        consumptionBalanceData.setTodayComsumption(todayConsumption);
+        consumptionBalanceData.setYesterdayComsumption(yesterdayConsumption);
+
+        // 从数据库获取当前余额
+        BigDecimal currentBalance = consumptionBalanceMapper.getCurrentBalance();
+        consumptionBalanceData.setBalance(currentBalance);
+
+        return consumptionBalanceData;
+    }
+    /**
+     * 计算流量消费金额
+     * @param trafficBytes 流量字节数
+     * @param pricePerGB 每GB价格
+     * @return 消费金额
+     */
+    private BigDecimal calculateTrafficCost(Long trafficBytes, float pricePerGB) {
+        if (trafficBytes == null || trafficBytes <= 0) {
+            return BigDecimal.ZERO;
+        }
+
+        // 将字节转换为GB (1GB = 1024^3 bytes)
+        BigDecimal trafficGB = new BigDecimal(trafficBytes)
+                .divide(new BigDecimal(1024 * 1024 * 1024), 6, BigDecimal.ROUND_HALF_UP);
+
+        // 计算消费金额
+        return trafficGB.multiply(new BigDecimal(pricePerGB)).setScale(2, BigDecimal.ROUND_HALF_UP);
+    }
+    @Override
+    public AnalysisPreviewDTO analysisPreview(AnalysisPreviewQueryDTO param) {
+        AnalysisPreviewDTO dto = new AnalysisPreviewDTO();
+
+        Long watchUserCount = consumptionBalanceMapper.queryWatchUserCount(param);
+        Long completedUserCount = consumptionBalanceMapper.queryCompletedUserCount(param);
+
+        if(watchUserCount == null){
+            watchUserCount = 0L;
+        }
+        if(completedUserCount == null){
+            completedUserCount = 0L;
+        }
+
+        // 观看人数
+        dto.setWatchUserCount(watchUserCount);
+        // 完播人数
+        dto.setCompletedUserCount(completedUserCount);
+
+        // 完播率
+        if(!ObjectUtils.equals(watchUserCount,0L)){
+            BigDecimal multiply = (BigDecimal.valueOf(completedUserCount)
+                    .divide(BigDecimal.valueOf(watchUserCount),4,BigDecimal.ROUND_HALF_UP))
+                    .multiply(BigDecimal.valueOf(100));
+
+            dto.setCompletedRate(multiply.setScale(2,BigDecimal.ROUND_HALF_UP).toPlainString());
+        } else {
+            dto.setCompletedRate("0");
+        }
+
+        Long watchCount = consumptionBalanceMapper.queryWatchCount(param);
+        Long completedCount = consumptionBalanceMapper.queryCompletedCount(param);
+
+        if(watchCount == null){
+            watchCount = 0L;
+        }
+        if(completedCount == null){
+            completedCount = 0L;
+        }
+
+        // 观看次数
+        dto.setWatchCount(watchCount);
+        // 完播次数
+        dto.setCompletedCount(completedCount);
+        // 视频完播率
+        if(!ObjectUtils.equals(watchCount, 0L)){
+            BigDecimal multiply = BigDecimal.valueOf(completedCount)
+                    .divide(BigDecimal.valueOf(watchCount),4,BigDecimal.ROUND_HALF_UP)
+                    .multiply(BigDecimal.valueOf(100));
+
+            dto.setWatchRate(multiply.setScale(2,BigDecimal.ROUND_HALF_UP).toPlainString());
+        } else {
+            dto.setWatchRate("0");
+        }
+
+        Long answerMemberCount = consumptionBalanceMapper.queryAnswerMemberCount(param);
+        Long correctUserCount = consumptionBalanceMapper.queryCorrectUserCount(param);
+
+        if(answerMemberCount == null){
+            answerMemberCount = 0L;
+        }
+        if(correctUserCount == null){
+            correctUserCount = 0L;
+        }
+        // 答题人数
+        dto.setAnswerMemberCount(answerMemberCount);
+        // 正确人数
+        dto.setCorrectUserCount(correctUserCount);
+        // 正确比例
+        if(!ObjectUtils.equals(answerMemberCount, 0L)){
+            BigDecimal multiply = BigDecimal.valueOf(correctUserCount)
+                    .divide(BigDecimal.valueOf(answerMemberCount),4,BigDecimal.ROUND_HALF_UP)
+                    .multiply(BigDecimal.valueOf(100));
+
+            dto.setCorrectRate(multiply.setScale(2, RoundingMode.HALF_UP).toPlainString());
+        } else {
+            dto.setCorrectRate("0");
+        }
+        Long rewardCount = consumptionBalanceMapper.queryRewardCount(param);
+        if(rewardCount == null) {
+            rewardCount = 0L;
+        }
+        BigDecimal rewardMoney = consumptionBalanceMapper.queryRewardMoney(param);
+        if(rewardMoney == null) {
+            rewardMoney = BigDecimal.ZERO;
+        }
+        // 答题红包个数
+        dto.setRewardCount(rewardCount);
+        // 答题红包金额
+        dto.setRewardMoney(rewardMoney);
+
+        return dto;
+    }
+
+    @Override
+    public Long smsBalance() {
+        Long smsBalance = consumptionBalanceMapper.smsBalance();
+        if(smsBalance != null) {
+            smsBalance = 0L;
+        }
+        return smsBalance;
+    }
+
+    @Override
+    public AuthorizationInfoDTO authorizationInfo() {
+        return consumptionBalanceMapper.authorizationInfo();
+    }
+
+    @Override
+    public List<WatchEndPlayTrendDTO> watchEndPlayTrend(AnalysisPreviewQueryDTO param) {
+        List<WatchEndPlayTrendDTO> watchEndPlayTrendDTOS = consumptionBalanceMapper.watchEndPlayTrend(param);
+        // 今日,昨日 格式为24小时
+        if(ObjectUtils.equals(param.getType(),0) || ObjectUtils.equals(param.getType(),1)){
+            watchEndPlayTrendDTOS = TrendDataFiller.fillHourData(watchEndPlayTrendDTOS);
+            // 否则都是按天为维度的时间范围
+        } else {
+            watchEndPlayTrendDTOS = TrendDataFiller.fillDateSegmentData(watchEndPlayTrendDTOS, param.getStartTime(), param.getEndTime());
+        }
+
+        return watchEndPlayTrendDTOS;
+    }
+
+    @Override
+    public List<DeaMemberTopTenDTO> deaMemberTopTen(AnalysisPreviewQueryDTO param) {
+        List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = consumptionBalanceMapper.deaMemberTopTen(param);
+        for (DeaMemberTopTenDTO dto : deaMemberTopTenDTOS) {
+            Long companyId = dto.getCompanyId();
+            String companyName = companyCacheService.selectCompanyNameById(companyId);
+            if(StringUtils.isNotBlank(companyName)){
+                dto.setCompanyName(companyName);
+            }
+        }
+        return deaMemberTopTenDTOS;
+    }
+
+    @Override
+    public List<CourseStatsDTO> watchCourseTopTen(AnalysisPreviewQueryDTO param) {
+        List<CourseStatsDTO> courseStatsDTOS = consumptionBalanceMapper.watchCourseTopTen(param);
+        for (CourseStatsDTO courseStatsDTO : courseStatsDTOS) {
+            String courseName = fsUserCourseCacheService.selectCourseNameByCourseId(courseStatsDTO.getCourseId());
+            if(StringUtils.isNotBlank(courseName)){
+                courseStatsDTO.setCourseName(courseName);
+            }
+        }
+        return courseStatsDTOS;
+    }
+
+    @Override
+    public List<RewardMoneyTopTenDTO> rewardMoneyTopTen(AnalysisPreviewQueryDTO param) {
+        List<RewardMoneyTopTenDTO> rewardMoneyTopTenDTOS = consumptionBalanceMapper.rewardMoneyTopTen(param);
+        for (RewardMoneyTopTenDTO dto : rewardMoneyTopTenDTOS) {
+            if(dto.getCompanyId() != null) {
+                String companyName = companyCacheService.selectCompanyNameById(dto.getCompanyId());
+                dto.setCompanyName(companyName);
+            }
+            if(dto.getCourseId() != null){
+                String courseName = fsUserCourseCacheService.selectCourseNameByCourseId(dto.getCourseId());
+                dto.setCourseName(courseName);
+            }
+
+        }
+        return rewardMoneyTopTenDTOS;
+    }
+
+    @Override
+    public List<RewardMoneyTrendDTO> rewardMoneyTrendDTO(AnalysisPreviewQueryDTO param) {
+        List<RewardMoneyTrendDTO> rewardMoneyTrendDTOS = consumptionBalanceMapper.rewardMoneyTrendDTO(param);
+
+        // 今日,昨日 格式为24小时
+        if(ObjectUtils.equals(param.getType(),0) || ObjectUtils.equals(param.getType(),1)){
+            rewardMoneyTrendDTOS = TrendDataFiller.fillRewardHourData(rewardMoneyTrendDTOS);
+            // 否则都是按天为维度的时间范围
+        } else {
+            rewardMoneyTrendDTOS = TrendDataFiller.fillRewardDateSegmentData(rewardMoneyTrendDTOS, param.getStartTime(), param.getEndTime());
+        }
+
+
+        return rewardMoneyTrendDTOS;
+    }
+
+    @Override
+    public TrafficLogDTO getTrafficLog() {
+        TrafficLogDTO trafficLogDTO = new TrafficLogDTO();
+        Long todayTrafficLog = fsCourseTrafficLogMapper.getTodayTrafficLog();
+        Long yesterdayTrafficLog = fsCourseTrafficLogMapper.getYesterdayTrafficLog();
+        Long monthTrafficLog = fsCourseTrafficLogMapper.getMonthTrafficLog();
+        trafficLogDTO.setToday(todayTrafficLog);
+        trafficLogDTO.setThisMonth(monthTrafficLog);
+        trafficLogDTO.setYesterday(yesterdayTrafficLog);
+        return trafficLogDTO;
+    }
+
+    @Override
+    public void thisMonthOrderCount() {
+        Long[] users=new Long[0];
+        TimeUtils.TimeEntity timeEntity=TimeUtils.parseTime("5",null,null);
+        timeEntity.setUserIds(users);
+        Integer cycleNum = timeEntity.getCycleNum();
+        Integer beginTime = timeEntity.getBeginTime();
+        List<Integer> timeList = new ArrayList<>();
+        for (int i = 1; i <= cycleNum; i++) {
+            timeList.add(beginTime);
+            beginTime = TimeUtils.formatTime(beginTime);
+        }
+        List<JSONObject> jsonObjectList = storeOrderService.selectFsStoreOrderCounts(timeEntity.toMap());
+        List<String> dates = jsonObjectList.stream().map(jsonObject -> jsonObject.getString("type")).collect(Collectors.toList());
+        List<Integer> orderCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("orderCount")).collect(Collectors.toList());
+        List<Integer> payPrice = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("payPrice")).collect(Collectors.toList());
+        R result = R.ok().put("dates", dates).put("orderCount", orderCount).put("payPrice", payPrice);
+        redisCache.setCacheObject(THIS_MONTH_ORDER_COUNT,result);
+    }
+
+    @Override
+    public void thisMonthRecvCount() {
+        Long[] users=new Long[0];
+        TimeUtils.TimeEntity timeEntity=TimeUtils.parseTime("5",null,null);
+        timeEntity.setUserIds(users);
+        Integer cycleNum = timeEntity.getCycleNum();
+        Integer beginTime = timeEntity.getBeginTime();
+        List<Integer> timeList = new ArrayList<>();
+        for (int i = 1; i <= cycleNum; i++) {
+            timeList.add(beginTime);
+            beginTime = TimeUtils.formatTime(beginTime);
+        }
+        List<JSONObject> jsonObjectList = paymentService.selectFsStorePaymentCounts(timeEntity.toMap());
+        List<String> dates = jsonObjectList.stream().map(jsonObject -> jsonObject.getString("type")).collect(Collectors.toList());
+        List<Integer> orderCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("orderCount")).collect(Collectors.toList());
+        List<Float> payMoney = jsonObjectList.stream().map(jsonObject -> jsonObject.getFloatValue("payMoney")).collect(Collectors.toList());
+        R result = R.ok().put("dates", dates).put("orderCount", orderCount).put("payMoney", payMoney);
+        redisCache.setCacheObject(THIS_MONTH_RECV_COUNT,result);
+    }
+}

+ 169 - 0
fs-service/src/main/java/com/fs/statis/service/utils/TrendDataFiller.java

@@ -0,0 +1,169 @@
+package com.fs.statis.service.utils;
+
+import com.fs.statis.dto.RewardMoneyTrendDTO;
+import com.fs.statis.dto.WatchEndPlayTrendDTO;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+
+/**
+ * 时序数据补全工具类
+ */
+public class TrendDataFiller {
+    public static List<RewardMoneyTrendDTO> fillRewardHourData(List<RewardMoneyTrendDTO> data){
+
+        boolean[] hourExists = new boolean[24];
+
+        for (RewardMoneyTrendDTO dto : data) {
+            int hour = Integer.parseInt(dto.getStartDate());
+            if (hour >= 0 && hour < 24) {
+                hourExists[hour] = true;
+                dto.setX(String.valueOf(hour));
+            }
+        }
+
+        // 填充不存在的小时数据
+        for (int i = 0; i < 24; i++) {
+            if (!hourExists[i]) {
+                RewardMoneyTrendDTO dto = new RewardMoneyTrendDTO();
+                dto.setX(String.valueOf(i));
+                dto.setRewardMoney(BigDecimal.ZERO);
+                data.add(dto);
+            }
+        }
+
+        data.sort((a, b) -> {
+            int intA = Integer.parseInt(a.getX());
+            int intB = Integer.parseInt(b.getX());
+            return Integer.compare(intA, intB);
+        });
+        return data;
+    }
+
+    /**
+     * 填充日期段数据
+     * @param data
+     * @return
+     */
+    public static List<RewardMoneyTrendDTO> fillRewardDateSegmentData(List<RewardMoneyTrendDTO> data,String startDate,String endDate){
+        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        LocalDate start = LocalDate.parse(startDate, dateTimeFormatter);
+        LocalDate end = LocalDate.parse(endDate, dateTimeFormatter);
+
+        LocalDate current = start;
+        while (!current.isAfter(end)) {
+            String dateStr = current.format(dateFormatter);
+            boolean found = false;
+
+            for (RewardMoneyTrendDTO dto : data) {
+                if (dateStr.equals(dto.getStartDate())) {
+                    found = true;
+                    dto.setX(dateStr);
+                    break;
+                }
+            }
+
+            if (!found) {
+                RewardMoneyTrendDTO dto = new RewardMoneyTrendDTO();
+                dto.setStartDate(dateStr);
+                dto.setX(dateStr);
+                dto.setRewardMoney(BigDecimal.ZERO);
+                data.add(dto);
+            }
+
+            current = current.plusDays(1);
+        }
+
+        data.sort((a, b) -> {
+            LocalDate dateA = LocalDate.parse(a.getX(), dateFormatter);
+            LocalDate dateB = LocalDate.parse(b.getX(), dateFormatter);
+            return dateA.compareTo(dateB);
+        });
+
+        return data;
+    }
+
+    /**
+     * 填充24小时类数据
+     * @param data
+     * @return
+     */
+    public static List<WatchEndPlayTrendDTO> fillHourData(List<WatchEndPlayTrendDTO> data){
+
+        boolean[] hourExists = new boolean[24];
+
+        for (WatchEndPlayTrendDTO dto : data) {
+            int hour = Integer.parseInt(dto.getStartDate());
+            if (hour >= 0 && hour < 24) {
+                hourExists[hour] = true;
+                dto.setX(String.valueOf(hour));
+            }
+        }
+
+        // 填充不存在的小时数据
+        for (int i = 0; i < 24; i++) {
+            if (!hourExists[i]) {
+                WatchEndPlayTrendDTO dto = new WatchEndPlayTrendDTO();
+                dto.setX(String.valueOf(i));
+                dto.setWatchUserCount(0L);
+                dto.setCompletedUserCount(0L);
+                data.add(dto);
+            }
+        }
+
+        data.sort((a, b) -> {
+            int intA = Integer.parseInt(a.getX());
+            int intB = Integer.parseInt(b.getX());
+            return Integer.compare(intA, intB);
+        });
+        return data;
+    }
+
+    /**
+     * 填充日期段数据
+     * @param data
+     * @return
+     */
+    public static List<WatchEndPlayTrendDTO> fillDateSegmentData(List<WatchEndPlayTrendDTO> data,String startDate,String endDate){
+        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        LocalDate start = LocalDate.parse(startDate, dateTimeFormatter);
+        LocalDate end = LocalDate.parse(endDate, dateTimeFormatter);
+
+        LocalDate current = start;
+        while (!current.isAfter(end)) {
+            String dateStr = current.format(dateFormatter);
+            boolean found = false;
+
+            for (WatchEndPlayTrendDTO dto : data) {
+                if (dateStr.equals(dto.getStartDate())) {
+                    found = true;
+                    dto.setX(dateStr);
+                    break;
+                }
+            }
+
+            if (!found) {
+                WatchEndPlayTrendDTO dto = new WatchEndPlayTrendDTO();
+                dto.setStartDate(dateStr);
+                dto.setX(dateStr);
+                dto.setWatchUserCount(0L);
+                dto.setCompletedUserCount(0L);
+                data.add(dto);
+            }
+
+            current = current.plusDays(1);
+        }
+
+        data.sort((a, b) -> {
+            LocalDate dateA = LocalDate.parse(a.getX(), dateFormatter);
+            LocalDate dateB = LocalDate.parse(b.getX(), dateFormatter);
+            return dateA.compareTo(dateB);
+        });
+
+        return data;
+    }
+}

+ 81 - 0
fs-service/src/main/java/com/fs/statis/vo/FsStatsMemberDailyVO.java

@@ -0,0 +1,81 @@
+package com.fs.statis.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class FsStatsMemberDailyVO {
+    /**
+     * 统计日期
+     */
+    private String statDate;
+    /**
+     * 用户ID
+     */
+    private Long userId;
+    /**
+     * 用户昵称
+     */
+    private String nickName;
+    /**
+     * 用户姓名
+     */
+    private String realName;
+    /**
+     * 电话号码
+     */
+    private String phone;
+    /**
+     * 标签
+     */
+    private String tag;
+    /**
+     * 公司ID
+     */
+    private Long companyId;
+    /**
+     * 公司名称
+     */
+    private String companyName;
+    /**
+     * 销售ID
+     */
+    private Long companyUserId;
+    /**
+     * 销售名称
+     */
+    private String companyUserName;
+    /**
+     * 课程数量
+     */
+    private Long count;
+    /**
+     * 完课数量
+     */
+    private Long overCount;
+    /**
+     * 观看次数
+     */
+    private Long watchCount;
+    /**
+     * 观看时长
+     */
+    private Long watchDuration;
+    /**
+     * 答题次数
+     */
+    private Long answerCount;
+    /**
+     * 正确次数
+     */
+    private Long answerCorrectCount;
+    /**
+     * 红包个数
+     */
+    private Long redPacketCount;
+    /**
+     * 红包金额
+     */
+    private BigDecimal redPacketAmount;
+}

+ 62 - 0
fs-service/src/main/resources/mapper/course/FsCourseTrafficLogMapper.xml

@@ -40,6 +40,68 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <include refid="selectFsCourseTrafficLogVo"/>
         where log_id = #{logId}
     </select>
+    <select id="getTodayTrafficLogCompanyId" resultType="java.lang.Long">
+        SELECT
+        COALESCE(SUM(internet_traffic), 0) AS today_traffic_bytes
+        FROM
+        fs_course_traffic_log
+        <where>
+            DATE(create_time) = CURDATE()
+            <if test="companyId != null">
+                AND company_id = ${companyId}
+            </if>
+        </where>
+    </select>
+    <select id="getYesterdayTrafficLogCompanyId" resultType="java.lang.Long">
+        SELECT
+        COALESCE(SUM(internet_traffic), 0) AS yesterday_traffic_bytes
+        FROM
+        fs_course_traffic_log
+        <where>
+            DATE(create_time) = CURDATE() - INTERVAL 1 DAY
+            <if test="companyId != null">
+                AND company_id = ${companyId}
+            </if>
+        </where>
+    </select>
+    <select id="getMonthTrafficLogCompanyId" resultType="java.lang.Long">
+        SELECT
+        COALESCE(SUM(internet_traffic), 0) AS month_traffic_bytes
+        FROM
+        fs_course_traffic_log
+        <where>
+            YEAR(create_time) = YEAR(CURDATE())
+            AND MONTH(create_time) = MONTH(CURDATE())
+            <if test="companyId != null">
+                AND company_id = ${companyId}
+            </if>
+        </where>
+    </select>
+    <select id="getTodayTrafficLog" resultType="java.lang.Long">
+        SELECT
+            COALESCE(SUM(internet_traffic), 0) AS today_traffic_bytes
+        FROM
+            fs_course_traffic_log
+        WHERE
+            DATE(create_time) = CURDATE()
+    </select>
+    <select id="getYesterdayTrafficLog" resultType="java.lang.Long">
+        SELECT
+            COALESCE(SUM(internet_traffic), 0) AS yesterday_traffic_bytes
+        FROM
+            fs_course_traffic_log
+        WHERE
+            DATE(create_time) = CURDATE() - INTERVAL 1 DAY
+    </select>
+    <select id="getMonthTrafficLog" resultType="java.lang.Long">
+        SELECT
+            COALESCE(SUM(internet_traffic), 0) AS month_traffic_bytes
+        FROM
+            fs_course_traffic_log
+        WHERE
+            YEAR(create_time) = YEAR(CURDATE())
+          AND MONTH(create_time) = MONTH(CURDATE())
+    </select>
 
     <insert id="insertFsCourseTrafficLog" parameterType="FsCourseTrafficLog" useGeneratedKeys="true" keyProperty="logId">
         insert into fs_course_traffic_log