Browse Source

首页统计

xdd 1 tháng trước cách đây
mục cha
commit
c6fd7c0148

+ 19 - 10
fs-admin/src/main/java/com/fs/api/controller/IndexStatisticsController.java

@@ -3,10 +3,13 @@ package com.fs.api.controller;
 import com.fs.statis.cache.IStatisticsCacheService;
 import com.fs.statis.dto.*;
 import com.fs.statis.service.IStatisticsService;
+import com.hc.openapi.tool.util.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 import com.fs.common.core.domain.R;
 
+import java.util.List;
+
 /**
  * 首页-统计
  */
@@ -22,10 +25,13 @@ public class IndexStatisticsController {
      */
     @PostMapping("/analysisPreview")
     public R analysisPreview(@RequestBody AnalysisPreviewQueryDTO param){
-        AnalysisPreviewDTO analysisPreviewDTO = statisticsService.analysisPreview(param);
+        AnalysisPreviewDTO analysisPreviewDTO = statisticsService1.analysisPreview(param);
         return R.ok().put("data",analysisPreviewDTO);
     }
 
+    /**
+     * 消费余额
+     */
     @GetMapping("/rechargeComsumption")
     public R rechargeComsumption(){
         ConsumptionBalanceDataDTO consumptionBalanceDataDTO = statisticsService.rechargeConsumption();
@@ -35,17 +41,19 @@ public class IndexStatisticsController {
     /**
      * 观看趋势
      */
-    @GetMapping("/watchEndPlayTrend")
-    public void watchEndPlayTrend(){
-
+    @PostMapping("/watchEndPlayTrend")
+    public R watchEndPlayTrend(@RequestBody AnalysisPreviewQueryDTO param){
+        List<WatchEndPlayTrendDTO> watchEndPlayTrendDTOS = statisticsService.watchEndPlayTrend(param);
+        return R.ok().put("data", watchEndPlayTrendDTOS);
     }
 
     /**
      * 经销商会员观看
      */
-    @GetMapping("/deaMemberTopTen")
-    public void deaMemberTopTen(){
-
+    @PostMapping("/deaMemberTopTen")
+    public R deaMemberTopTen(@RequestBody AnalysisPreviewQueryDTO param){
+        List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = statisticsService.deaMemberTopTen(param);
+        return R.ok().put("data", deaMemberTopTenDTOS);
     }
 
     /**
@@ -67,9 +75,10 @@ public class IndexStatisticsController {
     /**
      * 课程观看top10
      */
-    @GetMapping("/watchCourseTopTen")
-    public void watchCourseTopTen(){
-
+    @PostMapping("/watchCourseTopTen")
+    public R watchCourseTopTen(@RequestBody AnalysisPreviewQueryDTO param){
+        List<CourseStatsDTO> courseStatsDTOS = statisticsService1.watchCourseTopTen(param);
+        return R.ok().put("data", courseStatsDTOS);
     }
 
     /**

+ 3 - 0
fs-service-system/src/main/java/com/fs/company/cache/impl/ICompanyCacheServiceImpl.java

@@ -32,6 +32,9 @@ public class ICompanyCacheServiceImpl implements ICompanyCacheService {
 
     @Override
     public String selectCompanyNameById(Long companyId) {
+        if(companyId == null){
+            return "未找到";
+        }
         return COMPANY_NAME_CACHE.get(companyId, e-> {
             Company company = companyService.selectCompanyById(companyId);
             if(company == null){

+ 18 - 4
fs-service-system/src/main/java/com/fs/statis/cache/IStatisticsCacheService.java

@@ -1,9 +1,8 @@
 package com.fs.statis.cache;
 
-import com.fs.statis.dto.AnalysisPreviewDTO;
-import com.fs.statis.dto.AnalysisPreviewQueryDTO;
-import com.fs.statis.dto.ConsumptionBalanceDataDTO;
-import com.fs.statis.dto.DealerAggregatedDTO;
+import com.fs.statis.dto.*;
+
+import java.util.List;
 
 public interface IStatisticsCacheService {
     /**
@@ -21,4 +20,19 @@ public interface IStatisticsCacheService {
      */
     AnalysisPreviewDTO analysisPreview(AnalysisPreviewQueryDTO param);
 
+
+    /**
+     * 会员观看、完播人数趋势图
+     * @param param 请求参数
+     * @return 会员观看、完播人数趋势图
+     */
+    List<WatchEndPlayTrendDTO> watchEndPlayTrend(AnalysisPreviewQueryDTO param);
+
+    /**
+     * 经销商会员观看TOP10
+     * @param param 请求参数
+     * @return TOP10
+     * @return
+     */
+    List<DeaMemberTopTenDTO> deaMemberTopTen(AnalysisPreviewQueryDTO param);
 }

+ 27 - 4
fs-service-system/src/main/java/com/fs/statis/cache/impl/StatisticsCacheServiceImpl.java

@@ -1,16 +1,15 @@
 package com.fs.statis.cache.impl;
 
 import com.fs.statis.cache.IStatisticsCacheService;
-import com.fs.statis.dto.AnalysisPreviewDTO;
-import com.fs.statis.dto.AnalysisPreviewQueryDTO;
-import com.fs.statis.dto.ConsumptionBalanceDataDTO;
-import com.fs.statis.dto.DealerAggregatedDTO;
+import com.fs.statis.dto.*;
 import com.fs.statis.service.IStatisticsService;
 import com.github.benmanes.caffeine.cache.Cache;
 import com.github.benmanes.caffeine.cache.Caffeine;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.Collections;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 @Service
@@ -33,6 +32,16 @@ public class StatisticsCacheServiceImpl implements IStatisticsCacheService {
             .expireAfterWrite(10, TimeUnit.MINUTES)
             .build();
 
+    private static final Cache<Integer, List<WatchEndPlayTrendDTO>> WATCH_END_PLAY_TREND = Caffeine.newBuilder()
+            .maximumSize(1000)
+            .expireAfterWrite(10, TimeUnit.MINUTES)
+            .build();
+
+    private static final Cache<Integer, List<DeaMemberTopTenDTO>> DEA_MEMBER_TOP_TEN = Caffeine.newBuilder()
+            .maximumSize(1000)
+            .expireAfterWrite(10, TimeUnit.MINUTES)
+            .build();
+
     @Override
     public DealerAggregatedDTO dealerAggregated() {
         return DEALER_AGGREGATED_DTO_CACHE.get(1,e->{
@@ -54,4 +63,18 @@ public class StatisticsCacheServiceImpl implements IStatisticsCacheService {
         });
     }
 
+    @Override
+    public List<WatchEndPlayTrendDTO> watchEndPlayTrend(AnalysisPreviewQueryDTO param) {
+        return WATCH_END_PLAY_TREND.get(param.getType(),e->{
+            return statisticsService.watchEndPlayTrend(param);
+        });
+    }
+
+    @Override
+    public List<DeaMemberTopTenDTO> deaMemberTopTen(AnalysisPreviewQueryDTO param) {
+        return DEA_MEMBER_TOP_TEN.get(param.getType(),e->{
+            return statisticsService.deaMemberTopTen(param);
+        });
+    }
+
 }

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

@@ -8,6 +8,16 @@ 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;
     /**
      * 开始时间
      */
@@ -16,4 +26,12 @@ public class AnalysisPreviewQueryDTO implements Serializable {
      * 结束时间
      */
     private String endTime;
+
+    /**
+     * 排序 DESC ASC
+     */
+    private String sort;
+
+    private Integer dateType;
+
 }

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

@@ -0,0 +1,63 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+
+import java.io.Serializable; // DTOs 通常建议实现 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-system/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;
+}

+ 29 - 0
fs-service-system/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;
+}

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

@@ -3,6 +3,7 @@ package com.fs.statis.mapper;
 import com.fs.statis.dto.*;
 
 import java.math.BigDecimal;
+import java.util.List;
 
 public interface ConsumptionBalanceMapper {
     /**
@@ -82,4 +83,25 @@ public interface ConsumptionBalanceMapper {
     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);
 }

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

@@ -2,6 +2,8 @@ package com.fs.statis.service;
 
 import com.fs.statis.dto.*;
 
+import java.util.List;
+
 /**
  * 统计接口
  */
@@ -33,4 +35,24 @@ public interface IStatisticsService {
      */
     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);
 }

+ 71 - 5
fs-service-system/src/main/java/com/fs/statis/service/impl/StatisticsServiceImpl.java

@@ -1,18 +1,31 @@
 package com.fs.statis.service.impl;
 
+import com.fs.company.cache.ICompanyCacheService;
 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.hc.openapi.tool.util.ObjectUtils;
+import com.hc.openapi.tool.util.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Collections;
+import java.util.List;
 
 @Service
 public class StatisticsServiceImpl implements IStatisticsService {
     @Autowired
     private ConsumptionBalanceMapper consumptionBalanceMapper;
+
+    @Autowired
+    private IFsUserCourseCacheService fsUserCourseCacheService;
+
+    @Autowired
+    private ICompanyCacheService companyCacheService;
     @Override
     public DealerAggregatedDTO dealerAggregated() {
         return consumptionBalanceMapper.dealerAggregated();
@@ -43,8 +56,10 @@ public class StatisticsServiceImpl implements IStatisticsService {
         dto.setCompletedUserCount(completedUserCount);
 
         // 完播率
-        if(!ObjectUtils.equals(completedUserCount,0L)){
-            dto.setCompletedRate((completedUserCount / watchUserCount) * 100 +"%");
+        if(!ObjectUtils.equals(watchUserCount,0L)){
+            BigDecimal multiply = (BigDecimal.valueOf(completedUserCount).divide(BigDecimal.valueOf(watchUserCount))).multiply(BigDecimal.valueOf(100));
+
+            dto.setCompletedRate(multiply.setScale(2,BigDecimal.ROUND_HALF_UP).toPlainString());
         } else {
             dto.setCompletedRate("0");
         }
@@ -64,8 +79,12 @@ public class StatisticsServiceImpl implements IStatisticsService {
         // 完播次数
         dto.setCompletedCount(completedCount);
         // 视频完播率
-        if(!ObjectUtils.equals(completedCount, 0L)){
-            dto.setCompletedRate((completedCount / watchCount) * 100 +"%");
+        if(!ObjectUtils.equals(watchCount, 0L)){
+            BigDecimal multiply = BigDecimal.valueOf(completedCount)
+                    .divide(BigDecimal.valueOf(watchCount))
+                    .multiply(BigDecimal.valueOf(100));
+
+            dto.setCompletedRate(multiply.setScale(2,BigDecimal.ROUND_HALF_UP).toPlainString());
         } else {
             dto.setCompletedRate("0");
         }
@@ -85,12 +104,20 @@ public class StatisticsServiceImpl implements IStatisticsService {
         dto.setCorrectUserCount(correctUserCount);
         // 正确比例
         if(!ObjectUtils.equals(answerMemberCount, 0L)){
-            dto.setCorrectRate((correctUserCount / answerMemberCount) * 100 +"%");
+            BigDecimal multiply = BigDecimal.valueOf(correctUserCount).divide(BigDecimal.valueOf(answerMemberCount)).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);
         // 答题红包金额
@@ -108,4 +135,43 @@ public class StatisticsServiceImpl implements IStatisticsService {
     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;
+    }
 }

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

@@ -0,0 +1,96 @@
+package com.fs.statis.service.utils;
+
+import com.fs.statis.dto.WatchEndPlayTrendDTO;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * 时序数据补全工具类
+ */
+public class TrendDataFiller {
+
+    /**
+     * 填充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;
+    }
+}

+ 100 - 10
fs-service-system/src/main/resources/mapper/statis/ConsumptionBalanceMapper.xml

@@ -31,34 +31,37 @@
 -- 答题人数
                (select count(*) from fs_course_answer_logs where create_time between #{startTime} and #{endTime}) as answer_member_count,
 -- 正确人数
-               (select count(*) from fs_course_answer_logs where create_time between #{startTime} and #{endTime}) as correct_user_count,
+               (select count(*) from fs_course_answer_logs where is_right=1 AND create_time between #{startTime} and #{endTime}) as correct_user_count,
 -- 答题红包个数
                (select 0) as reward_type,
-               (select 0) as reward_money;
+               (select 0) as reward_money
     </select>
     <select id="queryWatchCount" resultType="java.lang.Long">
-        select count(*) from fs_course_watch_log where create_time between #{startTime} and #{endTime}
+        select count(log_id) from fs_course_watch_log where create_time between #{startTime} and #{endTime}
     </select>
     <select id="queryCompletedUserCount" resultType="java.lang.Long">
-        select count(*) from fs_course_watch_log where finish_time is not null and create_time between #{startTime} and #{endTime} group by user_id
+        select count(DISTINCT user_id) from fs_course_watch_log where finish_time is not null and create_time between #{startTime} and #{endTime}
     </select>
     <select id="queryWatchUserCount" resultType="java.lang.Long">
-        select count(*) from fs_course_watch_log where create_time between #{startTime} and #{endTime} group by user_id
+        select count(distinct user_id) from fs_course_watch_log where create_time between #{startTime} and #{endTime}
     </select>
     <select id="queryCompletedCount" resultType="java.lang.Long">
-        select count(*) from fs_course_watch_log where create_time between #{startTime} and #{endTime}
+        SELECT COUNT(log_id) FROM fs_course_watch_log
+        WHERE finish_time IS NOT NULL AND create_time BETWEEN #{startTime} AND #{endTime}
     </select>
     <select id="queryAnswerMemberCount" resultType="java.lang.Long">
-        select count(*) from fs_course_answer_logs where create_time between #{startTime} and #{endTime}
+        SELECT COUNT(DISTINCT user_id) FROM fs_course_answer_logs
+        WHERE create_time BETWEEN #{startTime} AND #{endTime}
     </select>
     <select id="queryCorrectUserCount" resultType="java.lang.Long">
-        select count(*) from fs_course_answer_logs where create_time between #{startTime} and #{endTime}
+        SELECT COUNT(DISTINCT user_id) FROM fs_course_answer_logs
+        WHERE is_right = 1 AND create_time BETWEEN #{startTime} AND #{endTime}
     </select>
     <select id="queryRewardCount" resultType="java.lang.Long">
-        select 0
+        select count(*) from company_red_package_logs where operate_type=1
     </select>
     <select id="queryRewardMoney" resultType="java.math.BigDecimal">
-        select 0
+        select sum(up_money) from company_red_package_logs where operate_type=1
     </select>
     <select id="smsBalance" resultType="java.lang.Long">
         select sum(remain_sms_count) from company_sms
@@ -66,5 +69,92 @@
     <select id="authorizationInfo" resultType="com.fs.statis.dto.AuthorizationInfoDTO">
         select version_limit,today_watch_user_count from fs_statistics_index limit 1
     </select>
+    <select id="watchEndPlayTrend" resultType="com.fs.statis.dto.WatchEndPlayTrendDTO">
+        SELECT
+--             今日/昨日 小时
+            <if test="type == 0 or type == 1">
+                DATE_FORMAT(create_time, '%H') AS start_date,
+            </if>
+--                 本周/本月/上月 天
+            <if test="type == 2 or type == 3 or type == 4">
+                DATE_FORMAT(create_time, '%Y-%m-%d') AS start_date,
+            </if>
+        COUNT(DISTINCT user_id) AS watch_user_count,
+        COUNT(DISTINCT CASE WHEN log_type = 2 THEN user_id END) AS completed_user_count
+        FROM
+        fs_course_watch_log
+        <where>
+            <if test="startTime != null">
+                create_time <![CDATA[>=]]> #{startTime}
+            </if>
+            <if test="endTime != null">
+                AND create_time <![CDATA[<]]> #{endTime}
+            </if>
+        </where>
+        GROUP BY
+        start_date
+        ORDER BY
+        start_date
+    </select>
+    <select id="deaMemberTopTen" resultType="com.fs.statis.dto.DeaMemberTopTenDTO">
+        SELECT
+        company_id,
+        <if test="statisticalType == 0">
+            count(DISTINCT user_id) AS watch_user_count
+        </if>
+        <if test="statisticalType == 1">
+            COUNT(DISTINCT CASE WHEN log_type = 2 THEN user_id END) AS watch_user_count
+        </if>
+        FROM
+        fs_course_watch_log
+        <where>
+            <if test="startTime != null">
+                create_time <![CDATA[>=]]> #{startTime}
+            </if>
+            <if test="endTime != null">
+                AND create_time <![CDATA[<]]> #{endTime}
+            </if>
+        </where>
+        GROUP BY company_id
+        limit 10
+    </select>
+    <select id="watchCourseTopTen" resultType="com.fs.statis.dto.CourseStatsDTO">
+        SELECT
+        w.course_id AS course_id,
+        COUNT(DISTINCT w.user_id) AS watch_user_count,
+        COUNT(DISTINCT CASE WHEN w.log_type = 2 THEN w.user_id END) AS completed_user_count,
+        COUNT(DISTINCT a.user_id) AS answer_user_count,
+        COUNT(DISTINCT CASE WHEN a.is_right = 1 THEN a.user_id END) AS correct_user_count
+        FROM
+        fs_course_watch_log w
+        LEFT JOIN
+        fs_course_answer_logs a ON w.video_id = a.video_id AND w.user_id = a.user_id
+        <where>
+            <if test="startTime != null">
+                w.create_time <![CDATA[>=]]> #{startTime}
+            </if>
+            <if test="endTime != null">
+                AND w.create_time <![CDATA[<]]> #{endTime}
+            </if>
+        </where>
+        GROUP BY
+        w.course_id
+        ORDER BY
+            -- 观看人数
+            <if test="statisticalType == 0">
+                COUNT(DISTINCT w.user_id)
+            </if>
+            <if test="statisticalType == 1">
+                COUNT(DISTINCT CASE WHEN w.log_type = 2 THEN w.user_id END)
+            </if>
+            <if test="statisticalType == 2">
+                COUNT(DISTINCT a.user_id)
+            </if>
+            <if test="statisticalType == 3">
+                COUNT(DISTINCT CASE WHEN a.is_right = 1 THEN a.user_id END)
+            </if>
+        ${sort}
+        LIMIT 10
+    </select>
 
 </mapper>