瀏覽代碼

feat: 会员看课

caoliqin 4 天之前
父節點
當前提交
51940d5a63

+ 10 - 1
fs-admin/src/main/java/com/fs/course/controller/FsUserWatchCourseStatisticsController.java

@@ -1,6 +1,8 @@
 package com.fs.course.controller;
 
 import java.util.List;
+
+import io.swagger.annotations.ApiOperation;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -22,7 +24,7 @@ import com.fs.common.core.page.TableDataInfo;
 
 /**
  * 会员看课统计-按课程统计Controller
- * 
+ *
  * @author fs
  * @date 2025-06-16
  */
@@ -100,4 +102,11 @@ public class FsUserWatchCourseStatisticsController extends BaseController
     {
         return toAjax(fsUserWatchCourseStatisticsService.deleteFsUserWatchCourseStatisticsByIds(ids));
     }
+
+
+    @PostMapping("/test")
+    @ApiOperation("测试看课统计明细定时任务")
+    public void userCourseCountTask() {
+        fsUserWatchCourseStatisticsService.insertWatchCourseStatistics();
+    }
 }

+ 14 - 0
fs-admin/src/main/java/com/fs/task/StoreTask.java

@@ -7,6 +7,8 @@ import com.fs.common.core.redis.RedisCache;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.vo.RedPacketMoneyVO;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
+import com.fs.course.service.IFsUserWatchCourseStatisticsService;
+import com.fs.course.service.IFsUserWatchStatisticsService;
 import com.fs.erp.domain.ErpDeliverys;
 import com.fs.erp.domain.ErpGoods;
 import com.fs.erp.domain.ErpOrderQuery;
@@ -128,6 +130,12 @@ public class StoreTask
     @Autowired
     IErpOrderService erpOrderService;
 
+    @Autowired
+    private IFsUserWatchCourseStatisticsService fsUserWatchCourseStatisticsService;
+
+    @Autowired
+    private IFsUserWatchStatisticsService fsUserWatchStatisticsService;
+
     public void PushErp() throws ParseException {
         List<Long> ids;
         // 开启审核
@@ -447,6 +455,12 @@ public class StoreTask
     }
 
 
+    public void insertWatchStatistics(){
+        fsUserWatchStatisticsService.insertStatistics();
+    }
 
+    public void insertWatchCourseStatistics(){
+        fsUserWatchCourseStatisticsService.insertWatchCourseStatistics();
+    }
 
 }

+ 12 - 7
fs-service-system/src/main/java/com/fs/course/mapper/FsUserWatchCourseStatisticsMapper.java

@@ -6,14 +6,14 @@ import com.fs.course.domain.FsUserWatchCourseStatistics;
 
 /**
  * 会员看课统计-按课程统计Mapper接口
- * 
+ *
  * @author fs
  * @date 2025-06-17
  */
 public interface FsUserWatchCourseStatisticsMapper extends BaseMapper<FsUserWatchCourseStatistics>{
     /**
      * 查询会员看课统计-按课程统计
-     * 
+     *
      * @param id 会员看课统计-按课程统计主键
      * @return 会员看课统计-按课程统计
      */
@@ -21,7 +21,7 @@ public interface FsUserWatchCourseStatisticsMapper extends BaseMapper<FsUserWatc
 
     /**
      * 查询会员看课统计-按课程统计列表
-     * 
+     *
      * @param fsUserWatchCourseStatistics 会员看课统计-按课程统计
      * @return 会员看课统计-按课程统计集合
      */
@@ -29,7 +29,7 @@ public interface FsUserWatchCourseStatisticsMapper extends BaseMapper<FsUserWatc
 
     /**
      * 新增会员看课统计-按课程统计
-     * 
+     *
      * @param fsUserWatchCourseStatistics 会员看课统计-按课程统计
      * @return 结果
      */
@@ -37,7 +37,7 @@ public interface FsUserWatchCourseStatisticsMapper extends BaseMapper<FsUserWatc
 
     /**
      * 修改会员看课统计-按课程统计
-     * 
+     *
      * @param fsUserWatchCourseStatistics 会员看课统计-按课程统计
      * @return 结果
      */
@@ -45,7 +45,7 @@ public interface FsUserWatchCourseStatisticsMapper extends BaseMapper<FsUserWatc
 
     /**
      * 删除会员看课统计-按课程统计
-     * 
+     *
      * @param id 会员看课统计-按课程统计主键
      * @return 结果
      */
@@ -53,9 +53,14 @@ public interface FsUserWatchCourseStatisticsMapper extends BaseMapper<FsUserWatc
 
     /**
      * 批量删除会员看课统计-按课程统计
-     * 
+     *
      * @param ids 需要删除的数据主键集合
      * @return 结果
      */
     int deleteFsUserWatchCourseStatisticsByIds(Long[] ids);
+
+    /**
+     * 插入看课统计数据
+     */
+    void insertFsUserWatchCourseStatisticsTask(FsUserWatchCourseStatistics fsUserWatchCourseStatistics);
 }

+ 63 - 45
fs-service-system/src/main/java/com/fs/course/service/impl/FsUserWatchCourseStatisticsServiceImpl.java

@@ -1,19 +1,17 @@
 package com.fs.course.service.impl;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.fs.course.domain.FsUserCoursePeriodDays;
 import com.fs.course.mapper.FsUserCoursePeriodDaysMapper;
-import com.fs.course.vo.FsPeriodCountVO;
-import com.fs.course.vo.newfs.FsCourseAnalysisCountVO;
 import com.fs.store.mapper.FsUserMapper;
-import com.fs.store.param.h5.CourseAnalysisParam;
+import com.google.common.collect.Lists;
 import lombok.AllArgsConstructor;
+import org.apache.ibatis.session.ExecutorType;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -21,7 +19,6 @@ import com.fs.course.mapper.FsUserWatchCourseStatisticsMapper;
 import com.fs.course.domain.FsUserWatchCourseStatistics;
 import com.fs.course.service.IFsUserWatchCourseStatisticsService;
 
-import static org.apache.coyote.http11.Constants.a;
 
 /**
  * 会员看课统计-按课程统计Service业务层处理
@@ -37,6 +34,9 @@ public class FsUserWatchCourseStatisticsServiceImpl extends ServiceImpl<FsUserWa
 
     private FsUserMapper fsUserMapper;
 
+    @Autowired
+    private SqlSessionFactory sqlSessionFactory;
+
     /**
      * 查询会员看课统计-按课程统计
      *
@@ -115,60 +115,78 @@ public class FsUserWatchCourseStatisticsServiceImpl extends ServiceImpl<FsUserWa
         // 查询课程相关数据
         List<FsUserWatchCourseStatistics> fsUserWatchCourseStatistics = fsUserCoursePeriodDaysMapper.selectDaysCountList();
 
-        //2、查询统计数据
+        // 查询统计数据
         List<FsUserWatchCourseStatistics> watchLog = fsUserMapper.selectWatchLogCount();
         List<FsUserWatchCourseStatistics> redPacketLog = fsUserMapper.selectRedPacketLogCount();
         List<FsUserWatchCourseStatistics> answerLog = fsUserMapper.selectAnswerLogCount();
-//        List<FsCourseAnalysisCountVO> courseCountList = fsUserMapper.courseAnalysisWatchLog(courseAnalysisParam);
-//        List<FsCourseAnalysisCountVO> redPacketCountList = fsUserMapper.courseAnalysisRedPacketCount(courseAnalysisParam);
-//        List<FsCourseAnalysisCountVO> answerCountList = fsUserMapper.courseAnalysisAnswerCount(courseAnalysisParam);
-
-        //3、转化为自定义键的map
-//        Map<Long, FsCourseAnalysisCountVO> courseMap = courseCountList.stream()
-//                .collect(Collectors.toMap(
-//                        FsCourseAnalysisCountVO::getVideoId,
-//                        Function.identity()
-//                ));
-//        Map<Long, FsCourseAnalysisCountVO> redPacketMap = redPacketCountList.stream()
-//                .collect(Collectors.toMap(
-//                        FsCourseAnalysisCountVO::getVideoId,
-//                        Function.identity()
-//                ));
-//        Map<Long, FsCourseAnalysisCountVO> answerMap = answerCountList.stream()
-//                .collect(Collectors.toMap(
-//                        FsCourseAnalysisCountVO::getVideoId,
-//                        Function.identity()
-//                ));
+        List<FsUserWatchCourseStatistics> userTotal = fsUserMapper.selectFsUserDetail();
+
+        // 转化为自定义键的map
         Map<String, FsUserWatchCourseStatistics> watchLogMap = watchLog.stream().collect(Collectors.toMap(k -> String.format("%s-%s-%s", k.getPeriodId(), k.getVideoId(), k.getCompanyUserId()), v -> v));
         Map<String, FsUserWatchCourseStatistics> redPacketLogMap = redPacketLog.stream().collect(Collectors.toMap(k -> String.format("%s-%s-%s", k.getPeriodId(), k.getVideoId(), k.getCompanyUserId()), v -> v));
         Map<String, FsUserWatchCourseStatistics> answerLogMap = answerLog.stream().collect(Collectors.toMap(k -> String.format("%s-%s-%s", k.getPeriodId(), k.getVideoId(), k.getCompanyUserId()), v -> v));
+        Map<Long, FsUserWatchCourseStatistics> userTotalMap = userTotal.stream()
+                .collect(Collectors.toMap(
+                        FsUserWatchCourseStatistics::getCompanyUserId,
+                        Function.identity()
+                ));
 
 
-
-
-
-//        //4、处理数据
-//        return videoList.stream().map(v -> {
-//            FsPeriodCountVO allVO = new FsPeriodCountVO();
-//            BeanUtils.copyProperties(v, allVO);
-//            allVO.setTitle(v.getVideoName());
-//
-//            FsCourseAnalysisCountVO countVO = getCourseAnalysisCountVO(v, courseMap, redPacketMap, answerMap);
-//            allVO.setCountDetailsVO(countVO);
-//            return allVO;
-//        }).collect(Collectors.toList());
+        // 处理数据
+        List<FsUserWatchCourseStatistics> list = new ArrayList<>();
         for (FsUserWatchCourseStatistics data : fsUserWatchCourseStatistics) {
             FsUserWatchCourseStatistics vo = new FsUserWatchCourseStatistics();
             String key = String.format("%s-%s-%s", data.getPeriodId(), data.getVideoId(), data.getCompanyUserId());
             FsUserWatchCourseStatistics watchLogData = watchLogMap.get(key);
             FsUserWatchCourseStatistics redPacketLogData = redPacketLogMap.get(key);
             FsUserWatchCourseStatistics answerLogData = answerLogMap.get(key);
-//            BeanUtils.copyProperties();
+            FsUserWatchCourseStatistics userTotalData = userTotalMap.get(data.getCompanyUserId());
+            BeanUtils.copyProperties(data, vo);
+            if(userTotalData != null){
+                vo.setUserNum(userTotalData.getUserNum());
+                vo.setNewUserNum(userTotalData.getNewUserNum());
+            }
+
+            if(watchLogData != null) {
+                vo.setWatchNum(watchLogData.getWatchNum());
+                vo.setCompleteWatchNum(watchLogData.getCompleteWatchNum());
+                vo.setCompleteWatchRate(watchLogData.getCompleteWatchRate());
+            }
+
+            if(redPacketLogData != null) {
+                vo.setRedPacketNum(redPacketLogData.getRedPacketNum());
+                vo.setRedPacketAmount(redPacketLogData.getRedPacketAmount());
+            }
+
+            if(answerLogData != null) {
+                vo.setAnswerNum(answerLogData.getAnswerNum());
+                vo.setAnswerRightNum(answerLogData.getAnswerRightNum());
+                vo.setAnswerRightRate(answerLogData.getAnswerRightRate());
+            }
+
+            vo.setCreateTime(new Date());
+            vo.setUpdateTime(new Date());
+            list.add(vo);
         }
 
+        //2、分批次插入数据
+        this.batchInsert(list);
+
     }
 
-    private String buildKey(Long periodId, Long videoId, Long companyUserId) {
-        return periodId + "|" + videoId + "|" + companyUserId;  // 使用特殊字符分隔,确保唯一性
+    private void batchInsert(List<FsUserWatchCourseStatistics> list) {
+        // 分批次处理,一次提交500条
+        List<List<FsUserWatchCourseStatistics>> batches = Lists.partition(list, 500);
+        batches.forEach(batch -> {
+            SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
+            try {
+                FsUserWatchCourseStatisticsMapper mapper = sqlSession.getMapper(FsUserWatchCourseStatisticsMapper.class);
+                batch.forEach(mapper::insertFsUserWatchCourseStatisticsTask);
+                sqlSession.commit();
+            } finally {
+                sqlSession.close();
+            }
+        });
     }
+
 }

+ 1 - 7
fs-service-system/src/main/java/com/fs/course/service/impl/FsUserWatchStatisticsServiceImpl.java

@@ -7,19 +7,13 @@ import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.mapper.FsUserCoursePeriodMapper;
-import com.fs.course.vo.FsPeriodCountVO;
-import com.fs.course.vo.newfs.FsCourseAnalysisCountVO;
-import com.fs.store.domain.FsUserCourseCount;
-import com.fs.store.mapper.FsUserCourseCountMapper;
 import com.fs.store.mapper.FsUserMapper;
 import com.google.common.collect.Lists;
 import lombok.AllArgsConstructor;
 import org.apache.ibatis.session.ExecutorType;
 import org.apache.ibatis.session.SqlSession;
 import org.apache.ibatis.session.SqlSessionFactory;
-import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.course.mapper.FsUserWatchStatisticsMapper;
@@ -125,7 +119,7 @@ public class FsUserWatchStatisticsServiceImpl extends ServiceImpl<FsUserWatchSta
 //        List<FsUserCoursePeriod> fsUserCoursePeriods = fsUserCoursePeriodMapper.selectFsUserCoursePeriodList(periodParam);
 
         //获取会员数量和新增会员数量
-        List<FsUserWatchStatistics> userTotal = fsUserMapper.selectFsUserTotal(0);
+        List<FsUserWatchStatistics> userTotal = fsUserMapper.selectFsUserTotal();
         FsUserWatchStatistics userTotalStatistics = new FsUserWatchStatistics();
         if(!userTotal.isEmpty()){
             userTotalStatistics = userTotal.get(0);

+ 3 - 1
fs-service-system/src/main/java/com/fs/store/mapper/FsUserMapper.java

@@ -305,7 +305,7 @@ public interface FsUserMapper
      * 获取会员总数和新增总数-可以按营期/课程
      * @return
      */
-    List<FsUserWatchStatistics> selectFsUserTotal(@Param("isCourse") Integer isCourse);
+    List<FsUserWatchStatistics> selectFsUserTotal();
 
     List<FsUserWatchCourseStatistics> selectWatchLogCount();
 
@@ -313,4 +313,6 @@ public interface FsUserMapper
 
     List<FsUserWatchCourseStatistics> selectAnswerLogCount();
 
+    List<FsUserWatchCourseStatistics> selectFsUserDetail();
+
 }

+ 2 - 1
fs-service-system/src/main/resources/mapper/course/FsUserCoursePeriodDaysMapper.xml

@@ -182,7 +182,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              ,b.course_name
              ,c.title as videoTitle
              ,period.period_name,period.period_starting_time
-             ,company.company_id,company.company_name,company_user.nick_name
+             ,company.company_id,company.company_name
+             ,company_user.user_id as companyUserId, company_user.nick_name as companyUserName
         FROM
             fs_user_course_period_days a
                 INNER JOIN fs_user_course b ON a.course_id = b.course_id

+ 66 - 6
fs-service-system/src/main/resources/mapper/course/FsUserWatchCourseStatisticsMapper.xml

@@ -3,7 +3,7 @@
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.fs.course.mapper.FsUserWatchCourseStatisticsMapper">
-    
+
     <resultMap type="FsUserWatchCourseStatistics" id="FsUserWatchCourseStatisticsResult">
         <result property="id"    column="id"    />
         <result property="periodId"    column="period_id"    />
@@ -36,7 +36,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <select id="selectFsUserWatchCourseStatisticsList" parameterType="FsUserWatchCourseStatistics" resultMap="FsUserWatchCourseStatisticsResult">
         <include refid="selectFsUserWatchCourseStatisticsVo"/>
-        <where>  
+        <where>
             <if test="periodId != null "> and period_id = #{periodId}</if>
             <if test="periodName != null  and periodName != ''"> and period_name like concat('%', #{periodName}, '%')</if>
             <if test="courseId != null "> and course_id = #{courseId}</if>
@@ -61,12 +61,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="redPacketAmount != null "> and red_packet_amount = #{redPacketAmount}</if>
         </where>
     </select>
-    
+
     <select id="selectFsUserWatchCourseStatisticsById" parameterType="Long" resultMap="FsUserWatchCourseStatisticsResult">
         <include refid="selectFsUserWatchCourseStatisticsVo"/>
         where id = #{id}
     </select>
-        
+
     <insert id="insertFsUserWatchCourseStatistics" parameterType="FsUserWatchCourseStatistics" useGeneratedKeys="true" keyProperty="id">
         insert into fs_user_watch_course_statistics
         <trim prefix="(" suffix=")" suffixOverrides=",">
@@ -153,9 +153,69 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </delete>
 
     <delete id="deleteFsUserWatchCourseStatisticsByIds" parameterType="String">
-        delete from fs_user_watch_course_statistics where id in 
+        delete from fs_user_watch_course_statistics where id in
         <foreach item="id" collection="array" open="(" separator="," close=")">
             #{id}
         </foreach>
     </delete>
-</mapper>
+
+
+    <insert id="insertFsUserWatchCourseStatisticsTask" parameterType="FsUserWatchCourseStatistics" useGeneratedKeys="true" keyProperty="id">
+        insert into fs_user_watch_course_statistics
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="periodId != null">period_id,</if>
+            <if test="periodName != null">period_name,</if>
+            <if test="courseId != null">course_id,</if>
+            <if test="courseName != null">course_name,</if>
+            <if test="videoId != null">video_id,</if>
+            <if test="videoTitle != null">video_title,</if>
+            <if test="companyId != null">company_id,</if>
+            <if test="companyName != null">company_name,</if>
+            <if test="companyUserId != null">company_user_id,</if>
+            <if test="courseStartDateTime != null">course_start_date_time,</if>
+            <if test="companyUserName != null">company_user_name,</if>
+            <if test="periodStartingTime != null">period_starting_time,</if>
+            <if test="newUserNum != null">new_user_num,</if>
+            <if test="userNum != null">user_num,</if>
+            <if test="watchNum != null">watch_num,</if>
+            <if test="completeWatchNum != null">complete_watch_num,</if>
+            <if test="completeWatchRate != null">complete_watch_rate,</if>
+            <if test="answerNum != null">answer_num,</if>
+            <if test="answerRightNum != null">answer_right_num,</if>
+            <if test="answerRightRate != null">answer_right_rate,</if>
+            <if test="redPacketNum != null">red_packet_num,</if>
+            <if test="redPacketAmount != null">red_packet_amount,</if>
+            <if test="createTime != null">create_time,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="periodId != null">#{periodId},</if>
+            <if test="periodName != null">#{periodName},</if>
+            <if test="courseId != null">#{courseId},</if>
+            <if test="courseName != null">#{courseName},</if>
+            <if test="videoId != null">#{videoId},</if>
+            <if test="videoTitle != null">#{videoTitle},</if>
+            <if test="companyId != null">#{companyId},</if>
+            <if test="companyName != null">#{companyName},</if>
+            <if test="companyUserId != null">#{companyUserId},</if>
+            <if test="courseStartDateTime != null">#{courseStartDateTime},</if>
+            <if test="companyUserName != null">#{companyUserName},</if>
+            <if test="periodStartingTime != null">#{periodStartingTime},</if>
+            <if test="newUserNum != null">#{newUserNum},</if>
+            <if test="userNum != null">#{userNum},</if>
+            <if test="watchNum != null">#{watchNum},</if>
+            <if test="completeWatchNum != null">#{completeWatchNum},</if>
+            <if test="completeWatchRate != null">#{completeWatchRate},</if>
+            <if test="answerNum != null">#{answerNum},</if>
+            <if test="answerRightNum != null">#{answerRightNum},</if>
+            <if test="answerRightRate != null">#{answerRightRate},</if>
+            <if test="redPacketNum != null">#{redPacketNum},</if>
+            <if test="redPacketAmount != null">#{redPacketAmount},</if>
+            <if test="createTime != null">#{createTime},</if>
+        </trim>
+        on duplicate key update
+        <trim suffixOverrides=",">
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+    </insert>
+
+</mapper>

+ 21 - 10
fs-service-system/src/main/resources/mapper/store/FsUserMapper.xml

@@ -1451,12 +1451,6 @@
         SELECT
             count( fs_user.user_id ) as userNum,
             count( DISTINCT CASE WHEN to_days( fs_user.create_time ) = to_days( now()) THEN fs_user.user_id END ) as newUserNum
-        <if test="isCourse != null and isCourse == 1 ">
-            ,company.company_id,
-            company.company_name,
-            GROUP_CONCAT( DISTINCT company_user.user_id ) AS company_user_id,
-            GROUP_CONCAT( DISTINCT company_user.nick_name ) AS companyUserName
-        </if>
         FROM
             fs_user
             LEFT JOIN company_user ON company_user.user_id = fs_user.company_user_id
@@ -1464,10 +1458,6 @@
         WHERE
             fs_user.is_del = 0
           AND fs_user.`status` = 1
-        <if test="isCourse != null and isCourse == 1 ">
-        GROUP BY
-            fs_user.company_id
-        </if>
     </select>
 
 
@@ -1538,4 +1528,25 @@
             fs_course_answer_logs.company_user_id
     </select>
 
+    <select id="selectFsUserDetail" resultType="FsUserWatchCourseStatistics">
+        SELECT
+        count( fs_user.user_id ) as userNum,
+        count( DISTINCT CASE WHEN to_days( fs_user.create_time ) = to_days( now()) THEN fs_user.user_id END ) as newUserNum
+        ,company.company_id,
+        company.company_name,
+        fs_user.company_user_id,
+        GROUP_CONCAT( DISTINCT company_user.user_id ) AS company_user_id,
+        GROUP_CONCAT( DISTINCT company_user.nick_name ) AS companyUserName
+
+        FROM
+        fs_user
+        LEFT JOIN company_user ON company_user.user_id = fs_user.company_user_id
+        LEFT JOIN company ON company.company_id = fs_user.company_id
+        WHERE
+        fs_user.is_del = 0
+        AND fs_user.`status` = 1
+        GROUP BY
+        fs_user.company_user_id
+    </select>
+
 </mapper>