ct 19 timmar sedan
förälder
incheckning
1b4bf785f0

+ 4 - 3
fs-service/src/main/java/com/fs/course/mapper/FsUserWatchStatisticsMapper.java

@@ -2,6 +2,7 @@ package com.fs.course.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.course.domain.FsUserWatchStatistics;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -61,10 +62,10 @@ public interface FsUserWatchStatisticsMapper extends BaseMapper<FsUserWatchStati
     int deleteFsUserWatchStatisticsByIds(Long[] ids);
 
     /**
-     * 获取看课统计-按营期统计
-     * @return
+     * 获取看课统计-按营期统计(限定营期 + 时间窗口,避免全表扫描)
      */
-    List<FsUserWatchStatistics> getCourseWatchStatistics();
+    List<FsUserWatchStatistics> getCourseWatchStatistics(@Param("periodIds") List<Long> periodIds,
+                                                         @Param("startTime") String startTime);
 
     /**
      * 插入看课统计数据

+ 13 - 2
fs-service/src/main/java/com/fs/course/service/impl/FsUserWatchStatisticsServiceImpl.java

@@ -21,8 +21,10 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.time.LocalDate;
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -134,8 +136,17 @@ public class FsUserWatchStatisticsServiceImpl extends ServiceImpl<FsUserWatchSta
         List<Company> companies = companyMapper.selectCompanyByIds2(companyIds);
         Map<Long, Company> companyMap = companies.stream().collect(Collectors.toMap(Company::getCompanyId, Function.identity()));
 
-        // 获取看课统计(按营期按公司)
-        List<FsUserWatchStatistics> courseWatchStatistics = baseMapper.getCourseWatchStatistics();
+        // 获取看课统计(按营期按公司):限定营期 + 近180天看课记录,避免全表扫描
+        List<Long> periodIds = fsUserCoursePeriods.stream()
+                .map(FsUserCoursePeriod::getPeriodId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+        String startTime = LocalDate.now().minusDays(180).atStartOfDay()
+                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+        List<FsUserWatchStatistics> courseWatchStatistics = periodIds.isEmpty()
+                ? Collections.emptyList()
+                : baseMapper.getCourseWatchStatistics(periodIds, startTime);
         Map<String, FsUserWatchStatistics> courseWatchStatisticsMap = courseWatchStatistics.stream().collect(Collectors.toMap(k -> String.format("%s-%s", k.getPeriodId(), k.getCompanyId()), v -> v));
 
         //获取公司的会员数量和今日新增会员数量

+ 3 - 1
fs-service/src/main/java/com/fs/statis/mapper/FsStatisSalerWatchMapper.java

@@ -99,7 +99,9 @@ public interface FsStatisSalerWatchMapper {
     @DataSource(DataSourceType.SLAVE)
     List<FsStatisEveryDayWatch> queryEveryDayListExport(StatsWatchLogPageListDTO param);
 
-    void generateData(@Param("date") String date);
+    void generateData(@Param("date") String date,
+                      @Param("startTime") String startTime,
+                      @Param("endTime") String endTime);
 
     List<FsStatisSalerWatch> generateSopData(@Param("date") String date);
 

+ 7 - 4
fs-service/src/main/java/com/fs/statis/service/impl/FsStatisSalerWatchServiceImpl.java

@@ -349,7 +349,8 @@ public class FsStatisSalerWatchServiceImpl implements FsStatisSalerWatchService
         fsStatisTempParamMapper.clear();
 
         // 删除之前的数据
-        fsStatisSalerWatchMapper.deleteDateData(date);
+        String dataDate = previousDay.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+        fsStatisSalerWatchMapper.deleteDateData(dataDate);
 
         // -------开始计算-------------
         fsStatisTempParamMapper.batchSave(list);
@@ -357,8 +358,10 @@ public class FsStatisSalerWatchServiceImpl implements FsStatisSalerWatchService
 
         log.info("list 大小{}",list.size());
 
-        // 根据临时表生成数据
-        fsStatisSalerWatchMapper.generateData(date);
+        // 根据临时表生成数据(时间范围走索引,避免 DATE(create_time))
+        String startTime = previousDay.atStartOfDay().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+        String endTime = previousDay.plusDays(1).atStartOfDay().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+        fsStatisSalerWatchMapper.generateData(dataDate, startTime, endTime);
 
         // 写入企微重粉数和看课重粉数临时表
         List<FsStatisTempFsuser> tempData = fsStatisSalerWatchMapper.querySopRepeatData(date);
@@ -366,7 +369,7 @@ public class FsStatisSalerWatchServiceImpl implements FsStatisSalerWatchService
             fsStatisTempFsuserMapper.insertBatch(tempData);
         }
         // 生成企微重粉数和看课重粉数
-        fsStatisSalerWatchMapper.generateSopData(date);
+        fsStatisSalerWatchMapper.generateSopData(dataDate);
         // 清空临时表
         fsStatisTempFsuserMapper.clear();
         fsStatisTempParamMapper.clear();

+ 135 - 0
fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml

@@ -192,6 +192,141 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                  order by l.finish_time desc,l.update_time desc,l.create_time desc
             </select>
 
+    <!-- PageHelper 自定义轻量 COUNT:去掉纯展示 JOIN,仅保留过滤所需关联 -->
+    <select id="selectFsCourseWatchLogListVO_COUNT" resultType="java.lang.Long">
+        select count(0)
+        from fs_course_watch_log l
+        <if test="(maps.companyUserName != null and maps.companyUserName != '')
+                or (maps.deptId != null and maps.deptId != '')
+                or (maps.cuDeptIdList != null and !maps.cuDeptIdList.isEmpty() and maps.userType != '00')
+                or (maps.userIds != null and !maps.userIds.isEmpty())">
+            left join company_user cu on cu.user_id = l.company_user_id
+        </if>
+        <if test="(maps.nickName != null and maps.nickName != '')">
+            left join fs_user u on u.user_id = l.user_id
+        </if>
+        <if test="(maps.externalUserName != null and maps.externalUserName != '')
+                or maps.qecSTime != null or maps.qecETime != null">
+            left join qw_external_contact qec on l.qw_external_contact_id = qec.id
+        </if>
+        <if test="maps.qwUserName != null and maps.qwUserName != ''">
+            left join qw_user qu on qu.id = l.qw_user_id
+        </if>
+        <where>
+            <if test ='maps.isVip != null and maps.isVip == 0'>
+                and (l.user_id = 0 or l.user_id is null)
+            </if>
+            <if test ='maps.isVip != null and maps.isVip == 1'>
+                and l.user_id != 0 and l.user_id is not null
+            </if>
+            <if test ='maps.sendType !=null'>
+                and l.send_type = #{maps.sendType}
+            </if>
+            <if test ='maps.userId !=null'>
+                and l.user_id = #{maps.userId}
+            </if>
+            <if test ='maps.logId !=null'>
+                and l.log_id = #{maps.logId}
+            </if>
+            <if test ='maps.project !=null'>
+                and l.project = #{maps.project}
+            </if>
+            <if test ='maps.qwExternalContactId !=null'>
+                and l.qw_external_contact_id = #{maps.qwExternalContactId}
+            </if>
+            <if test ='maps.qwUserId !=null'>
+                and l.qw_user_id = #{maps.qwUserId}
+            </if>
+            <if test ='maps.courseId !=null'>
+                and l.course_id = #{maps.courseId}
+            </if>
+            <if test ='maps.videoId !=null'>
+                and l.video_id = #{maps.videoId}
+            </if>
+            <if test ='maps.logType !=null'>
+                and l.log_type = #{maps.logType}
+            </if>
+            <if test ='maps.companyId !=null'>
+                and l.company_id = #{maps.companyId}
+            </if>
+            <if test ='maps.watchType !=null'>
+                and l.watch_type = #{maps.watchType}
+            </if>
+            <if test ='maps.companyUserId !=null'>
+                and l.company_user_id = #{maps.companyUserId}
+            </if>
+            <if test ='maps.companyUserName !=null and maps.companyUserName!=""'>
+                and cu.nick_name  like concat('%', #{maps.companyUserName}, '%')
+            </if>
+            <if test ='maps.nickName !=null and maps.nickName!=""'>
+                and u.nick_name  like concat('%', #{maps.nickName}, '%')
+            </if>
+            <if test ='maps.externalUserName !=null and maps.externalUserName!=""'>
+                and qec.name  like concat('%', #{maps.externalUserName}, '%')
+            </if>
+            <if test= 'maps.qecSTime != null '>
+                and DATE(qec.create_time) &gt;= DATE(#{maps.qecSTime})
+            </if>
+            <if test='maps.qecETime != null '>
+                and DATE(qec.create_time) &lt;= DATE(#{maps.qecETime})
+            </if>
+            <if test= 'maps.sTime != null '>
+                and l.create_time &gt;= #{maps.sTime}
+            </if>
+            <if test='maps.eTime != null '>
+                and l.create_time &lt;= #{maps.eTime}
+            </if>
+            <if test= 'maps.scheduleStartTime != null '>
+                and l.camp_period_time &gt;= #{maps.scheduleStartTime}
+            </if>
+            <if test='maps.scheduleEndTime != null '>
+                and l.camp_period_time &lt;= #{maps.scheduleEndTime}
+            </if>
+            <if test= 'maps.upSTime != null '>
+                and l.update_time &gt;= #{maps.upSTime}
+            </if>
+            <if test='maps.upETime != null '>
+                and l.update_time &lt;= #{maps.upETime}
+            </if>
+            <if test="maps.sopIds != null and maps.sopIds.size() > 0">
+                and l.sop_id in
+                <foreach item="sopId" index="index" collection="maps.sopIds" open="(" separator="," close=")">
+                    #{sopId}
+                </foreach>
+            </if>
+            <if test="maps.sopId != null  and maps.sopId != '' ">
+                and l.sop_id = #{maps.sopId}
+            </if>
+            <if test="maps.periodId != null">
+                and l.period_id = #{maps.periodId}
+            </if>
+            <if test="maps.periodIds != null and maps.periodIds.size() > 0">
+                and l.period_id in
+                <foreach item="periodId" index="index" collection="maps.periodIds" open="(" separator="," close=")">
+                    #{periodId}
+                </foreach>
+            </if>
+            <if test="maps.qwUserName != null  and maps.qwUserName != '' ">
+                and qu.qw_user_name = #{maps.qwUserName}
+            </if>
+            <if test="maps.deptId != null  and maps.deptId != '' ">
+                and cu.dept_id = #{maps.deptId}
+            </if>
+            <if test='maps.cuDeptIdList != null and !maps.cuDeptIdList.isEmpty() and  maps.userType != "00" '>
+                AND cu.dept_id IN
+                <foreach collection='maps.cuDeptIdList' item='item' open='(' separator=',' close=')'>
+                    #{item}
+                </foreach>
+            </if>
+            <if test="maps.userIds != null and !maps.userIds.isEmpty()">
+                AND cu.user_id IN
+                    <foreach collection='maps.userIds' item='item' open='(' separator=',' close=')'>
+                        #{item}
+                    </foreach>
+            </if>
+        </where>
+    </select>
+
             <select id="selectFsCourseWatchLogListByParam" resultType="com.fs.course.vo.FsCourseWatchLogListVO">
                 select l.log_id,l.user_id,uc.course_name,v.title as video_name,u.nick_name as fsNickName, u.avatar as fsAvatar,
                 l.log_type,SEC_TO_TIME(l.duration) as duration,c.company_name,l.camp_period_time,l.finish_time,

+ 10 - 2
fs-service/src/main/resources/mapper/course/FsUserWatchStatisticsMapper.xml

@@ -119,10 +119,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             fwl.company_id
         FROM
             fs_course_watch_log fwl
-                LEFT JOIN fs_user_company_user ON fs_user_company_user.user_id = fwl.user_id
+                INNER JOIN fs_user_company_user ON fs_user_company_user.user_id = fwl.user_id
+                    AND fs_user_company_user.`status` = 1
         WHERE
             fwl.send_type = 1
-            AND fs_user_company_user.`status` = 1
+            AND fwl.user_id IS NOT NULL
+            AND fwl.create_time &gt;= #{startTime}
+            <if test="periodIds != null and periodIds.size() > 0">
+                AND fwl.period_id IN
+                <foreach collection="periodIds" item="periodId" open="(" separator="," close=")">
+                    #{periodId}
+                </foreach>
+            </if>
         GROUP BY
             fwl.period_id, fwl.company_id
     </select>

+ 27 - 38
fs-service/src/main/resources/mapper/statis/FsStatisSalerWatchMapper.xml

@@ -480,6 +480,7 @@
         online_complete_playback = VALUES(online_complete_playback)
     </insert>
     <insert id="generateData">
+        <![CDATA[
         REPLACE INTO fs_statis_saler_watch (
             company_user_id,
             sop_id,
@@ -492,20 +493,7 @@
             interrupt_num,
             dept_id
         )
-        SELECT
-            temp.company_user_id,
-            temp.sop_id,
-            temp.period_id,
-            temp.this_date as data_date,
-            COALESCE(log_stats.send_count, 0) as send_num,
-            COALESCE(log_stats.period_count, 0) as train_camp_num,
-            COALESCE(log_stats.not_register_count, 0) as not_registered_num,
-            COALESCE(log_stats.completed_count, 0) as completed_num,
-            COALESCE(log_stats.interrupt_count, 0) as interrupt_num,
-            temp.dept_id
-        FROM fs_statis_temp_param temp
-                 LEFT JOIN (
-            -- 一次性统计所有指标,避免重复扫描
+        WITH log_stats AS (
             SELECT
                 company_user_id,
                 sop_id,
@@ -517,17 +505,31 @@
                 COUNT(DISTINCT CASE WHEN log_type = 2 THEN log_id END) as completed_count,
                 COUNT(DISTINCT CASE WHEN (log_type = 4 or log_type = 1) THEN log_id END) as interrupt_count
             FROM fs_course_watch_log
-            WHERE (DATE(create_time) = #{date})
+            WHERE create_time >= #{startTime}
+              AND create_time < #{endTime}
             GROUP BY company_user_id, sop_id, qw_user_id, camp_period_time
-        ) log_stats ON temp.company_user_id = log_stats.company_user_id
-            AND temp.sop_id = log_stats.sop_id
-            AND temp.start_time = log_stats.camp_period_time
-            AND temp.qw_user_id = log_stats.qw_user_id
+        )
+        SELECT
+            temp.company_user_id,
+            temp.sop_id,
+            temp.period_id,
+            temp.this_date as data_date,
+            COALESCE(log_stats.send_count, 0) as send_num,
+            COALESCE(log_stats.period_count, 0) as train_camp_num,
+            COALESCE(log_stats.not_register_count, 0) as not_registered_num,
+            COALESCE(log_stats.completed_count, 0) as completed_num,
+            COALESCE(log_stats.interrupt_count, 0) as interrupt_num,
+            temp.dept_id
+        FROM fs_statis_temp_param temp
+                 LEFT JOIN log_stats
+                           ON temp.company_user_id = log_stats.company_user_id
+                               AND temp.sop_id = log_stats.sop_id
+                               AND temp.start_time = log_stats.camp_period_time
+                               AND temp.qw_user_id = log_stats.qw_user_id
         WHERE temp.this_date IS NOT NULL
 
         UNION ALL
 
--- 孤立数据处理部分保持不变,但也进行了优化
         SELECT
             orphan_summary.company_user_id,
             orphan_summary.sop_id,
@@ -545,24 +547,10 @@
                      orphan_data.sop_id,
                      SUM(orphan_data.send_count) as send_num,
                      SUM(orphan_data.period_count) as train_camp_num,
-                     SUM(orphan_data.not_registered_num) as not_registered_num,
+                     SUM(orphan_data.not_register_count) as not_registered_num,
                      SUM(orphan_data.completed_count) as completed_num,
-                     SUM(orphan_data.interrupt_num) as interrupt_num
-                 FROM (
-                          SELECT
-                              log_data.company_user_id,
-                              log_data.sop_id,
-                              log_data.qw_user_id,
-                              log_data.camp_period_time,
-                              COUNT(DISTINCT log_data.log_id) as send_count,
-                              COUNT(DISTINCT log_data.qw_external_contact_id) as period_count,
-                              COUNT(DISTINCT CASE WHEN log_data.log_type = 3 THEN log_data.log_id END) as not_registered_num,
-                              COUNT(DISTINCT CASE WHEN log_data.log_type = 2 THEN log_data.log_id END) as completed_count,
-                              COUNT(DISTINCT CASE WHEN (log_data.log_type = 4 or log_type = 1) THEN log_data.log_id END) as interrupt_num
-                          FROM fs_course_watch_log log_data
-                          WHERE (DATE(log_data.create_time) = #{date})
-                          GROUP BY log_data.company_user_id, log_data.sop_id, log_data.qw_user_id, log_data.camp_period_time
-                      ) orphan_data
+                     SUM(orphan_data.interrupt_count) as interrupt_num
+                 FROM log_stats orphan_data
                  WHERE NOT EXISTS (
                      SELECT 1
                      FROM fs_statis_temp_param temp
@@ -574,7 +562,8 @@
                  GROUP BY orphan_data.company_user_id, orphan_data.sop_id
              ) orphan_summary
          LEFT JOIN company_user cu ON cu.user_id = orphan_summary.company_user_id
-        WHERE cu.dept_id IS NOT NULL AND cu.dept_id != 0  -- 过滤掉dept_id为NULL或0的记录
+        WHERE cu.dept_id IS NOT NULL AND cu.dept_id != 0
+        ]]>
     </insert>
 
 </mapper>