Browse Source

首页统计

xdd 1 month ago
parent
commit
18d285b708

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

@@ -0,0 +1,102 @@
+package com.fs.api.controller;
+
+import com.fs.statis.cache.IStatisticsCacheService;
+import com.fs.statis.dto.*;
+import com.fs.statis.service.IStatisticsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.fs.common.core.domain.R;
+
+/**
+ * 首页-统计
+ */
+@RestController
+@RequestMapping("/index/statistics")
+public class IndexStatisticsController {
+    @Autowired
+    private IStatisticsCacheService statisticsService;
+    @Autowired
+    private IStatisticsService statisticsService1;
+    /**
+     * 分析概览
+     */
+    @PostMapping("/analysisPreview")
+    public R analysisPreview(@RequestBody AnalysisPreviewQueryDTO param){
+        AnalysisPreviewDTO analysisPreviewDTO = statisticsService.analysisPreview(param);
+        return R.ok().put("data",analysisPreviewDTO);
+    }
+
+    @GetMapping("/rechargeComsumption")
+    public R rechargeComsumption(){
+        ConsumptionBalanceDataDTO consumptionBalanceDataDTO = statisticsService.rechargeConsumption();
+        return R.ok().put("data", consumptionBalanceDataDTO);
+    }
+
+    /**
+     * 观看趋势
+     */
+    @GetMapping("/watchEndPlayTrend")
+    public void watchEndPlayTrend(){
+
+    }
+
+    /**
+     * 经销商会员观看
+     */
+    @GetMapping("/deaMemberTopTen")
+    public void deaMemberTopTen(){
+
+    }
+
+    /**
+     * 奖励金额top10
+     */
+    @GetMapping("/rewardMoneyTopTen")
+    public void rewardMoneyTopTen(){
+
+    }
+
+    /**
+     * 答题红包金额趋势图
+     */
+    @GetMapping("/rewardMoneyTrend")
+    public void rewardMoneyTrend(){
+
+    }
+
+    /**
+     * 课程观看top10
+     */
+    @GetMapping("/watchCourseTopTen")
+    public void watchCourseTopTen(){
+
+    }
+
+    /**
+     * 数据概览
+     */
+    @GetMapping("/dealerAggregated")
+    public R dealerAggregated(){
+        DealerAggregatedDTO dealerAggregatedDTO = statisticsService.dealerAggregated();
+        return R.ok().put("data",dealerAggregatedDTO);
+    }
+
+    /**
+     * 短信余额
+     */
+    @GetMapping("/smsBalance")
+    public R smsBalance(){
+        Long smsBalance = statisticsService1.smsBalance();
+        return R.ok().put("data", smsBalance);
+    }
+
+
+    /**
+     * 授权信息
+     */
+    @GetMapping("/authorizationInfo")
+    public R authorizationInfo(){
+        AuthorizationInfoDTO authorizationInfoDTO = statisticsService1.authorizationInfo();
+        return R.ok().put("data", authorizationInfoDTO);
+    }
+}

+ 24 - 0
fs-service-system/src/main/java/com/fs/statis/cache/IStatisticsCacheService.java

@@ -0,0 +1,24 @@
+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;
+
+public interface IStatisticsCacheService {
+    /**
+     * 分析概览 - 经销商统计
+     */
+    DealerAggregatedDTO dealerAggregated();
+
+    /**
+     * 消费余额
+     */
+    ConsumptionBalanceDataDTO rechargeConsumption();
+
+    /**
+     * 分析概览
+     */
+    AnalysisPreviewDTO analysisPreview(AnalysisPreviewQueryDTO param);
+
+}

+ 57 - 0
fs-service-system/src/main/java/com/fs/statis/cache/impl/StatisticsCacheServiceImpl.java

@@ -0,0 +1,57 @@
+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.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.concurrent.TimeUnit;
+
+@Service
+public class StatisticsCacheServiceImpl implements IStatisticsCacheService {
+    @Autowired
+    private IStatisticsService statisticsService;
+
+    private static final Cache<Integer, DealerAggregatedDTO> DEALER_AGGREGATED_DTO_CACHE = Caffeine.newBuilder()
+            .maximumSize(1000)
+            .expireAfterWrite(10, TimeUnit.MINUTES)
+            .build();
+
+    private static final Cache<Integer, ConsumptionBalanceDataDTO> RECHARGE_CONSUMPTION = Caffeine.newBuilder()
+            .maximumSize(1000)
+            .expireAfterWrite(10, TimeUnit.MINUTES)
+            .build();
+
+    private static final Cache<Integer, AnalysisPreviewDTO> ANALYSIS_PREVIEW_CONSUMPTION = Caffeine.newBuilder()
+            .maximumSize(1000)
+            .expireAfterWrite(10, TimeUnit.MINUTES)
+            .build();
+
+    @Override
+    public DealerAggregatedDTO dealerAggregated() {
+        return DEALER_AGGREGATED_DTO_CACHE.get(1,e->{
+            return statisticsService.dealerAggregated();
+        });
+    }
+
+    @Override
+    public ConsumptionBalanceDataDTO rechargeConsumption() {
+        return RECHARGE_CONSUMPTION.get(1,e->{
+            return statisticsService.rechargeConsumption();
+        });
+    }
+
+    @Override
+    public AnalysisPreviewDTO analysisPreview(AnalysisPreviewQueryDTO param) {
+        return ANALYSIS_PREVIEW_CONSUMPTION.get(1,e->{
+            return statisticsService.analysisPreview(param);
+        });
+    }
+
+}

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

@@ -0,0 +1,91 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+
+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;
+
+}

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

@@ -0,0 +1,19 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+@Data
+@Setter
+public class AnalysisPreviewQueryDTO implements Serializable {
+    /**
+     * 开始时间
+     */
+    private String startTime;
+    /**
+     * 结束时间
+     */
+    private String endTime;
+}

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

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

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

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

@@ -0,0 +1,30 @@
+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;
+
+}

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

@@ -0,0 +1,85 @@
+package com.fs.statis.mapper;
+
+import com.fs.statis.dto.*;
+
+import java.math.BigDecimal;
+
+public interface ConsumptionBalanceMapper {
+    /**
+     * 分析概览 - 经销商统计
+     */
+    AnalysisPreviewDTO analysisPreview(AnalysisPreviewQueryDTO queryDTO);
+
+    /**
+     * 消费余额
+     */
+    ConsumptionBalanceDataDTO rechargeConsumption();
+
+    DealerAggregatedDTO dealerAggregated();
+
+    /**
+     * 观看人数
+     * @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();
+}

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

@@ -0,0 +1,36 @@
+package com.fs.statis.service;
+
+import com.fs.statis.dto.*;
+
+/**
+ * 统计接口
+ */
+public interface IStatisticsService {
+    /**
+     * 分析概览 - 经销商统计
+     */
+    DealerAggregatedDTO dealerAggregated();
+
+    /**
+     * 消费余额
+     */
+    ConsumptionBalanceDataDTO rechargeConsumption();
+
+    /**
+     * 分析概览
+     */
+    AnalysisPreviewDTO analysisPreview(AnalysisPreviewQueryDTO param);
+
+    /**
+     * 获取短信余额
+     * @return
+     */
+    Long smsBalance();
+
+    /**
+     * 授权信息
+     * @return
+     */
+    AuthorizationInfoDTO authorizationInfo();
+
+}

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

@@ -0,0 +1,111 @@
+package com.fs.statis.service.impl;
+
+import com.fs.statis.dto.*;
+import com.fs.statis.mapper.ConsumptionBalanceMapper;
+import com.fs.statis.service.IStatisticsService;
+import com.hc.openapi.tool.util.ObjectUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+
+@Service
+public class StatisticsServiceImpl implements IStatisticsService {
+    @Autowired
+    private ConsumptionBalanceMapper consumptionBalanceMapper;
+    @Override
+    public DealerAggregatedDTO dealerAggregated() {
+        return consumptionBalanceMapper.dealerAggregated();
+    }
+
+    @Override
+    public ConsumptionBalanceDataDTO rechargeConsumption() {
+        return consumptionBalanceMapper.rechargeConsumption();
+    }
+
+    @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(completedUserCount,0L)){
+            dto.setCompletedRate((completedUserCount / watchUserCount) * 100 +"%");
+        } else {
+            dto.setCompletedRate("0");
+        }
+
+        Long watchCount = consumptionBalanceMapper.queryWatchCount(param);
+        Long completedCount = consumptionBalanceMapper.queryCompletedCount(param);
+
+        if(watchCount == 0){
+            watchCount = 0L;
+        }
+        if(completedCount == 0){
+            completedCount = 0L;
+        }
+
+        // 观看次数
+        dto.setWatchCount(watchCount);
+        // 完播次数
+        dto.setCompletedCount(completedCount);
+        // 视频完播率
+        if(!ObjectUtils.equals(completedCount, 0L)){
+            dto.setCompletedRate((completedCount / watchCount) * 100 +"%");
+        } else {
+            dto.setCompletedRate("0");
+        }
+
+        Long answerMemberCount = consumptionBalanceMapper.queryAnswerMemberCount(param);
+        Long correctUserCount = consumptionBalanceMapper.queryCorrectUserCount(param);
+
+        if(answerMemberCount == 0){
+            answerMemberCount = 0L;
+        }
+        if(correctUserCount == 0){
+            correctUserCount = 0L;
+        }
+        // 答题人数
+        dto.setAnswerMemberCount(answerMemberCount);
+        // 正确人数
+        dto.setCorrectUserCount(correctUserCount);
+        // 正确比例
+        if(!ObjectUtils.equals(answerMemberCount, 0L)){
+            dto.setCorrectRate((correctUserCount / answerMemberCount) * 100 +"%");
+        } else {
+            dto.setCorrectRate("0");
+        }
+        Long rewardCount = consumptionBalanceMapper.queryRewardCount(param);
+        BigDecimal rewardMoney = consumptionBalanceMapper.queryRewardMoney(param);
+        // 答题红包个数
+        dto.setRewardCount(rewardCount);
+        // 答题红包金额
+        dto.setRewardMoney(rewardMoney);
+
+        return dto;
+    }
+
+    @Override
+    public Long smsBalance() {
+        return consumptionBalanceMapper.smsBalance();
+    }
+
+    @Override
+    public AuthorizationInfoDTO authorizationInfo() {
+        return consumptionBalanceMapper.authorizationInfo();
+    }
+}

+ 70 - 0
fs-service-system/src/main/resources/mapper/statis/ConsumptionBalanceMapper.xml

@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.statis.mapper.ConsumptionBalanceMapper">
+
+    <select id="rechargeConsumption" resultType="com.fs.statis.dto.ConsumptionBalanceDataDTO">
+        select
+            14371277 AS balance,
+            103100 AS today_comsumption,
+            195280 AS yesterday_comsumption
+    </select>
+    <select id="dealerAggregated" resultType="com.fs.statis.dto.DealerAggregatedDTO">
+        SELECT
+                (SELECT COUNT(*) FROM COMPANY) AS dealder_count,
+                (SELECT COUNT(*) FROM COMPANY_USER) AS group_mgr_count,
+                (SELECT COUNT(*) FROM FS_USER) AS member_count,
+                (SELECT COUNT(*) FROM FS_USER WHERE STATUS=1) AS normal_num,
+                (SELECT COUNT(*) FROM FS_USER WHERE STATUS=0) AS black_num
+    </select>
+    <select id="analysisPreview" resultType="com.fs.statis.dto.AnalysisPreviewDTO">
+        -- 观看人数
+        select (select count(*) from fs_course_watch_log where create_time between #{startTime} and #{endTime} group by user_id) as watch_count,
+-- 完播人数
+               (select count(*) from fs_course_watch_log where finish_time is not null and create_time between #{startTime} and #{endTime} group by user_id)
+                                                                                                                                                     as completed_user_count,
+-- 观看次数
+               (select count(*) from fs_course_watch_log where create_time between #{startTime} and #{endTime}) as watch_count,
+-- 完播次数
+               (select count(*) from fs_course_watch_log where create_time between #{startTime} and #{endTime}) as completed_count,
+-- 答题人数
+               (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 0) as reward_type,
+               (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>
+    <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>
+    <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>
+    <select id="queryCompletedCount" resultType="java.lang.Long">
+        select count(*) from fs_course_watch_log where 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>
+    <select id="queryCorrectUserCount" resultType="java.lang.Long">
+        select count(*) from fs_course_answer_logs where create_time between #{startTime} and #{endTime}
+    </select>
+    <select id="queryRewardCount" resultType="java.lang.Long">
+        select 0
+    </select>
+    <select id="queryRewardMoney" resultType="java.math.BigDecimal">
+        select 0
+    </select>
+    <select id="smsBalance" resultType="java.lang.Long">
+        select sum(remain_sms_count) from company_sms
+    </select>
+    <select id="authorizationInfo" resultType="com.fs.statis.dto.AuthorizationInfoDTO">
+        select version_limit,today_watch_user_count from fs_statistics_index limit 1
+    </select>
+
+</mapper>