xgb 1 日 前
コミット
77fd2f26f9

+ 6 - 0
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java

@@ -316,6 +316,12 @@ public interface FsUserCourseMapper
      */
     Integer selectTodayCourseWatchLogCountByUserIdAndProjectId(@Param("userId") Long userId, @Param("projectId") Long projectId);
 
+    /**
+     * 批量查询当天哪些用户在此项目已有不同视频的看课记录,返回已有的 userId 集合
+     * @param videoId 当前视频ID,重复发同一节课不拦截
+     */
+    List<Long> selectUserIdsWithTodayCourseWatchLog(@Param("userIds") List<Long> userIds, @Param("projectId") Long projectId, @Param("videoId") Long videoId);
+
     /**
      * 根据时间限制来进行处理
      *

+ 64 - 0
fs-service/src/main/java/com/fs/im/service/impl/OpenIMServiceImpl.java

@@ -1625,6 +1625,31 @@ public class OpenIMServiceImpl implements OpenIMService {
         //组装发课消息数据
         FsUserCourse fsUserCourse = fsUserCourseMapper.selectFsUserCourseByCourseId(batchSendCourseDTO.getCourseId());
         Long project = fsUserCourse != null ? fsUserCourse.getProject() : null;
+
+        // 相同项目一天内同一用户只能发一个课(同一节课重复发不拦截)
+        if (project != null && !userIds.isEmpty()) {
+            List<Long> rawUserIds = userIds.stream()
+                    .map(id -> Long.parseLong(id.substring(1)))
+                    .collect(Collectors.toList());
+            Set<Long> duplicateUserIds = new HashSet<>(
+                    fsUserCourseMapper.selectUserIdsWithTodayCourseWatchLog(rawUserIds, project, batchSendCourseDTO.getVideoId()));
+            if (!duplicateUserIds.isEmpty()) {
+                List<String> filtered = userIds.stream()
+                        .filter(uid -> duplicateUserIds.contains(Long.parseLong(uid.substring(1))))
+                        .collect(Collectors.toList());
+                userIds.removeAll(filtered);
+                createFailedCourseSendDetail(batchSendCourseDTO, filtered, "同一项目当天已发送过不同课程");
+            }
+        }
+
+        // 全部被过滤则直接返回
+        if (userIds.isEmpty()) {
+            OpenImResponseDTO emptyResponse = new OpenImResponseDTO();
+            emptyResponse.setErrCode(0);
+            emptyResponse.setErrMsg("所有用户当天已在此项目接收过课程,已记录失败明细");
+            return emptyResponse;
+        }
+
         long planSendTimeStamp;
         if(ObjectUtils.isNotEmpty(batchSendCourseDTO.getSendType())&&batchSendCourseDTO.getSendType() == 1 && batchSendCourseDTO.getSendTime() != null && batchSendCourseDTO.getSendTime().compareTo(new Date()) > 0){
             planSendTimeStamp = batchSendCourseDTO.getSendTime().getTime();
@@ -2528,4 +2553,43 @@ public class OpenIMServiceImpl implements OpenIMService {
         return 0;
     }
 
+    /**
+     * 为当天项目已有看课记录的用户创建失败明细(发课过滤后登记)
+     */
+    private void createFailedCourseSendDetail(BatchSendCourseDTO dto, List<String> filteredUserIds, String failReason) {
+        FsImMsgSendLog log = new FsImMsgSendLog();
+        BeanUtils.copyProperties(dto, log);
+        log.setIsUrgeCourse(dto.getIsUrgeCourse() != null && dto.getIsUrgeCourse() ? 1 : 0);
+        log.setCreateBy(dto.getCompanyUserId().toString());
+        log.setCreateTime(new Date());
+        log.setSendUnionId(UUID.randomUUID().toString());
+        log.setProjectId(dto.getProjectId());
+        log.setPeriodDaysId(dto.getId());
+        if (dto.getTagIds() != null && !dto.getTagIds().isEmpty()) {
+            log.setTagIds(Joiner.on(",").join(dto.getTagIds()));
+        }
+        if (dto.getTagNames() != null && !dto.getTagNames().isEmpty()) {
+            log.setTagNames(Joiner.on(",").join(dto.getTagNames()));
+        }
+        log.setSendStatus(3); // 发送失败
+        log.setPlanSendTime(dto.getSendTime() != null ? dto.getSendTime() : new Date());
+        log.setSendTitle(dto.getTitle());
+        log.setMsgType(1);
+        fsImMsgSendLogMapper.insert(log);
+
+        for (String uid : filteredUserIds) {
+            FsImMsgSendDetail detail = new FsImMsgSendDetail();
+            detail.setLogId(log.getLogId())
+                    .setCompanyUserId(dto.getCompanyUserId())
+                    .setUserId(Long.parseLong(uid.substring(1)))
+                    .setPlanSendTime(log.getPlanSendTime())
+                    .setSendStatus(3) // 发送失败
+                    .setStatus(1)
+                    .setResultMessage(failReason)
+                    .setExceptionInfo("当天该用户在此项目已有看课记录,自动过滤")
+                    .setCreateTime(new Date());
+            fsImMsgSendDetailMapper.insert(detail);
+        }
+    }
+
 }

+ 15 - 0
fs-service/src/main/resources/mapper/course/FsUserCourseMapper.xml

@@ -163,6 +163,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
           and cwl.create_time between curdate() and date_add(curdate(), interval 1 day) and cwl.send_type = 1
     </select>
 
+    <select id="selectUserIdsWithTodayCourseWatchLog" resultType="java.lang.Long">
+        select DISTINCT cwl.user_id
+        from fs_course_watch_log cwl
+        inner join fs_user_course_video ucv on ucv.video_id = cwl.video_id
+        inner join fs_user_course uc on uc.course_id = ucv.course_id
+        where cwl.user_id in
+        <foreach collection="userIds" item="uid" open="(" separator="," close=")">
+            #{uid}
+        </foreach>
+          and uc.project = #{projectId}
+          and cwl.video_id != #{videoId}
+          and cwl.create_time between curdate() and date_add(curdate(), interval 1 day)
+          and cwl.send_type = 1
+    </select>
+
     <select id="countDistinctVideoByUserAndProject" resultType="java.lang.Long">
         select count(distinct cwl.video_id)
         from fs_course_watch_log cwl