Quellcode durchsuchen

会员看课记录,未完课消息推送,一键发课

wangxy vor 1 Tag
Ursprung
Commit
88c039cdbd

+ 42 - 0
fs-admin/src/main/java/com/fs/his/task/FsCourseTask.java

@@ -1,6 +1,10 @@
 package com.fs.his.task;
 
+import com.fs.common.core.redis.RedisCache;
+import com.fs.course.domain.FsCourseWatchLog;
+import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.gtPush.service.uniPush2Service;
 import com.fs.qw.service.ICustomerTransferApprovalService;
 import com.fs.qw.service.IHyWorkTaskService;
 import com.fs.statis.service.FsStatisSalerWatchService;
@@ -8,6 +12,11 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
 /**
  * 后台统计相关 定时任务
  */
@@ -23,6 +32,12 @@ public class FsCourseTask {
     private FsStatisSalerWatchService fsStatisSalerWatchService;
     @Autowired
     private ICustomerTransferApprovalService customerTransferApprovalService;
+    @Autowired
+    private FsCourseWatchLogMapper courseWatchLogMapper;
+    @Autowired
+    private uniPush2Service uniPush2Service;
+    @Autowired
+    private RedisCache redisCache;
     /**
      * 添加会员观看日志
      * @throws Exception
@@ -58,4 +73,31 @@ public class FsCourseTask {
         customerTransferApprovalService.autoApprovePass();
     }
 
+    /**
+     * 当日未完课课程信息推送,只推送,不发送IM消息。
+     */
+    public void pushTodayUnfinishedCourse(){
+        log.info("当日未完课课程信息推送 - 任务开始");
+        List<FsCourseWatchLog> watchLogs = courseWatchLogMapper.selectTodayUnfinishedCoursePushList(1000);
+        if (watchLogs == null || watchLogs.isEmpty()) {
+            log.info("当日未完课课程信息推送 - 没有需要推送的用户");
+            return;
+        }
+
+        String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
+        int pushCount = 0;
+        for (FsCourseWatchLog watchLog : watchLogs) {
+            if (watchLog.getUserId() == null || watchLog.getVideoId() == null) {
+                continue;
+            }
+            String redisKey = "uniPush:unfinishedCourse:" + date + ":" + watchLog.getUserId() + ":" + watchLog.getVideoId();
+            if (!redisCache.setIfAbsent(redisKey, "1", 1, TimeUnit.DAYS)) {
+                continue;
+            }
+            uniPush2Service.pushUnfinishedCourse(watchLog.getUserId(), watchLog.getCourseId(), watchLog.getVideoId(), "");
+            pushCount++;
+        }
+        log.info("当日未完课课程信息推送 - 任务完成,待推送:{},实际触发:{}", watchLogs.size(), pushCount);
+    }
+
 }

+ 8 - 0
fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -2,6 +2,7 @@ package com.fs.app.controller;
 
 import cn.hutool.core.date.DateUtil;
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fs.course.dto.BatchUrgeCourseTaskDTO;
 import com.fs.course.utils.WechatErrorUtil;
 import com.fs.feishu.service.FeiShuService;
 import com.fs.app.annotation.Login;
@@ -477,4 +478,11 @@ public class FsUserCourseVideoController extends AppBaseController {
         return R.ok().put("data", feiShuService.getFeishuCourseLink(companyUserId, videoId, periodId));
     }
 
+    @ApiOperation("会员批量发送课程消息")
+    @PostMapping("/batchUrgeCourseTaskCreate")
+    public OpenImResponseDTO batchUrgeCourseTaskCreate(@RequestBody BatchUrgeCourseTaskDTO batchUrgeCourseTaskDTO) throws JsonProcessingException {
+        return openIMService.batchUrgeCourseTaskCreate(batchUrgeCourseTaskDTO);
+    }
+
+
 }

+ 74 - 0
fs-service/src/main/java/com/fs/course/dto/BatchUrgeCourseTaskDTO.java

@@ -0,0 +1,74 @@
+package com.fs.course.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 一键催课任务创建入参
+ */
+@Data
+public class BatchUrgeCourseTaskDTO implements Serializable {
+
+    @NotNull
+    @ApiModelProperty(value = "销售id", required = true)
+    private Long companyUserId;
+
+    @NotNull
+    @ApiModelProperty(value = "公司id", required = true)
+    private Long companyId;
+
+    @NotNull
+    @ApiModelProperty(value = "营期id", required = true)
+    private Long periodId;
+
+    @NotNull
+    @ApiModelProperty(value = "课程id", required = true)
+    private Long courseId;
+
+    @NotBlank
+    @ApiModelProperty(value = "课程名称", required = true)
+    private String courseName;
+
+    @NotNull
+    @ApiModelProperty(value = "视频id", required = true)
+    private Long videoId;
+
+    @NotBlank
+    @ApiModelProperty(value = "视频名称", required = true)
+    private String videoName;
+
+    @NotNull
+    @ApiModelProperty(value = "项目id", required = true)
+    private Long projectId;
+
+    @NotNull
+    @ApiModelProperty(value = "营期课程id", required = true)
+    private Long periodDaysId;
+
+    @NotNull
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "催课发送时间", required = true)
+    private Date urgeTime;
+
+    @NotBlank
+    @ApiModelProperty(value = "文案标题", required = true)
+    private String title;
+
+    @NotBlank
+    @ApiModelProperty(value = "文案", required = true)
+    private String urgeContent;
+
+    @NotNull
+    @ApiModelProperty(value = "是否发送课程链接", required = true)
+    private Boolean sendCourse;
+
+    @NotNull
+    @ApiModelProperty(value = "任务类型:1-未看课催课;2-未完课催课", required = true)
+    private Integer taskType;
+}

+ 28 - 10
fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java

@@ -806,36 +806,54 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
     /**
      * 从链接字符串中解析companyId
      * @param linkStr 链接字符串,格式如:/pages_course/videovip?course={"companyId":123,...}
+     *                链接还有格式会/pages_company/bindCompany?companyUserId=9417&companyId=291
+     *
      * @return companyId
      */
     private Long parseCompanyIdFromLink(String linkStr) {
         try {
             String decodedStr = URLDecoder.decode(linkStr, StandardCharsets.UTF_8.toString());
             log.info("解析linkStr,解码后:{}", decodedStr);
-            
-            int companyIdIndex = decodedStr.indexOf("companyId");
-            if (companyIdIndex == -1) {
+
+            int queryCompanyIdIndex = decodedStr.indexOf("companyId=");
+            if (queryCompanyIdIndex != -1) {
+                int valueStart = queryCompanyIdIndex + "companyId=".length();
+                StringBuilder numStr = new StringBuilder();
+                while (valueStart < decodedStr.length() && Character.isDigit(decodedStr.charAt(valueStart))) {
+                    numStr.append(decodedStr.charAt(valueStart));
+                    valueStart++;
+                }
+                if (numStr.length() > 0) {
+                    return Long.parseLong(numStr.toString());
+                }
+            }
+
+            int jsonCompanyIdIndex = decodedStr.indexOf("\"companyId\"");
+            if (jsonCompanyIdIndex == -1) {
+                jsonCompanyIdIndex = decodedStr.indexOf("companyId");
+            }
+            if (jsonCompanyIdIndex == -1) {
                 log.warn("linkStr中未找到companyId参数");
                 return null;
             }
-            
-            int valueStart = decodedStr.indexOf(":", companyIdIndex);
+
+            int valueStart = decodedStr.indexOf(":", jsonCompanyIdIndex);
             if (valueStart == -1) {
                 return null;
             }
             valueStart++;
-            
-            while (valueStart < decodedStr.length() && 
-                   (decodedStr.charAt(valueStart) == ' ' || decodedStr.charAt(valueStart) == '"')) {
+
+            while (valueStart < decodedStr.length() &&
+                    (decodedStr.charAt(valueStart) == ' ' || decodedStr.charAt(valueStart) == '"')) {
                 valueStart++;
             }
-            
+
             StringBuilder numStr = new StringBuilder();
             while (valueStart < decodedStr.length() && Character.isDigit(decodedStr.charAt(valueStart))) {
                 numStr.append(decodedStr.charAt(valueStart));
                 valueStart++;
             }
-            
+
             if (numStr.length() > 0) {
                 return Long.parseLong(numStr.toString());
             }

+ 10 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java

@@ -2641,4 +2641,14 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
         }
     }
 
+    @Override
+    public List<AppUserWatchLogVO> selectAppUserWatchLogList(Long userId) {
+        return fsCourseWatchLogMapper.selectAppUserWatchLogList(userId);
+    }
+
+    @Override
+    public List<TodayUnfinishedCourseVO> selectTodayUnfinishedCourseList(Long userId) {
+        return fsCourseWatchLogMapper.selectTodayUnfinishedCourseList(userId);
+    }
+
 }

+ 37 - 0
fs-service/src/main/java/com/fs/course/vo/AppUserWatchLogVO.java

@@ -0,0 +1,37 @@
+package com.fs.course.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class AppUserWatchLogVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long logId;
+
+    private Long courseId;
+
+    private String courseName;
+
+    private Long videoId;
+
+    private String videoName;
+
+    private Integer logType;
+
+    private Long duration;
+
+    private String durationFormat;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date finishTime;
+
+    private Integer watchType;
+}

+ 46 - 0
fs-service/src/main/java/com/fs/course/vo/TodayUnfinishedCourseVO.java

@@ -0,0 +1,46 @@
+package com.fs.course.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.util.Date;
+
+@Data
+public class TodayUnfinishedCourseVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long logId;
+
+    private Long courseId;
+
+    private String courseName;
+
+    private Long videoId;
+
+    private String videoName;
+
+
+    private Integer logType;
+
+    private Long duration;
+
+    private Long totalDuration;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    private Integer watchType;
+
+    private Long periodId;
+
+    private String periodName;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime startDateTime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime endDateTime;
+}

+ 59 - 0
fs-service/src/main/java/com/fs/gtPush/service/impl/uniPush2ServiceImpl.java

@@ -12,6 +12,10 @@ import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.config.im.IMSystemConfig;
 import com.fs.course.config.CourseConfig;
+import com.fs.course.domain.FsUserCourse;
+import com.fs.course.domain.FsUserCourseVideo;
+import com.fs.course.mapper.FsUserCourseMapper;
+import com.fs.course.mapper.FsUserCourseVideoMapper;
 import com.fs.gtPush.domain.PushReqBean;
 import com.fs.gtPush.domain.PushResult;
 import com.fs.gtPush.domain.UniPushLog;
@@ -24,6 +28,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import com.fs.gtPush.utils.PushUtils;
 import com.fs.his.domain.FsUser;
+import com.fs.his.enums.PushLogDesTypeEnum;
 import com.fs.his.service.IFsUserService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -53,6 +58,12 @@ public class uniPush2ServiceImpl implements uniPush2Service {
     @Autowired
     private ISysConfigService configService;
 
+    @Autowired
+    private FsUserCourseMapper fsUserCourseMapper;
+
+    @Autowired
+    private FsUserCourseVideoMapper fsUserCourseVideoMapper;
+
     @Override
     public PushResult pushMessage(PushReqBean push) {
         String result = HttpUtil.post(imConfig.getPushUrl(), JSON.toJSONString(push));
@@ -89,6 +100,47 @@ public class uniPush2ServiceImpl implements uniPush2Service {
         }
     }
 
+    @Override
+    public void pushUnfinishedCourse(Long userId, Long courseId, Long videoId, String purl) {
+        try {
+            FsUserCourse course = fsUserCourseMapper.selectFsUserCourseByCourseId(courseId);
+            FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
+            String courseName = course != null ? course.getCourseName() : "课程";
+            String videoName = video != null ? video.getTitle() : "课程小节";
+            String title = "课程学习提醒";
+            String content = limitPushText("你有未完课《" + courseName + "》,请继续学习", 50);
+
+            PushReqBean param = getImParam(userId, purl, title, content, 1f, PushLogDesTypeEnum.STUDY_COURSE.getValue(), "");
+            if (param == null) {
+                log.warn("未完课课程信息单推取消,用户无有效推送标识或参数非法 userId:{} courseId:{} videoId:{}", userId, courseId, videoId);
+                return;
+            }
+
+            param.setForce_notification(true);
+            if (param.getPayload() == null) {
+                param.setPayload(new HashMap<>());
+            }
+            param.getPayload().put("type", "unfinishedCourse");
+            param.getPayload().put("courseId", courseId);
+            param.getPayload().put("videoId", videoId);
+            param.getPayload().put("courseName", courseName);
+            param.getPayload().put("videoName", videoName);
+
+            PushResult pushResult = pushMessage(param);
+            UniPushLog pushLog = new UniPushLog();
+            pushLog.setJpushId(param.getPush_clientid().toString());
+            pushLog.setPushMsg(JSON.toJSONString(param));
+            pushLog.setType(1f);
+            pushLog.setDesType(PushLogDesTypeEnum.STUDY_COURSE.getValue());
+            pushLog.setUserId(userId);
+            pushLog.setBusinessId(videoId != null ? videoId : courseId);
+            pushLog.setCreateTime(DateUtils.getNowDate());
+            logService.insertUniPushLog(PushUtils.returnMsg(pushResult, pushLog));
+        } catch (Exception e) {
+            log.error("未完课课程信息单推异常 userId:{} courseId:{} videoId:{}", userId, courseId, videoId, e);
+        }
+    }
+
     @Override
     public PushReqBean getParam(Long userId,String purl,String title,String content,Float type,Integer desType,String imJsonString){
         if (userId !=null) {
@@ -393,5 +445,12 @@ public class uniPush2ServiceImpl implements uniPush2Service {
         return bean;
     }
 
+    private String limitPushText(String text, int maxLength) {
+        if (StringUtils.isBlank(text) || text.length() <= maxLength) {
+            return text;
+        }
+        return text.substring(0, Math.max(0, maxLength - 1)) + "…";
+    }
+
 
 }

+ 2 - 0
fs-service/src/main/java/com/fs/gtPush/service/uniPush2Service.java

@@ -10,6 +10,8 @@ public interface uniPush2Service {
 
     void pushOne(Long userId,Long businessId,String purl,String title,String content, Float type, Integer desType);
 
+    void pushUnfinishedCourse(Long userId, Long courseId, Long videoId, String purl);
+
     PushReqBean getParam(Long userId,String purl,String title,String content,Float type,Integer desType,String imJsonString);
     void pushIm(Long userId, Long businessId, String purl, String title, String content, Float type, Integer desType,String imJsonString);
     void pushSopAppLinkMsgByExternalIM(String cropId,String linkTile,String linkDescribe,String linkImageUrl,String link,Long companyUserId,Long fsUserId) throws JsonProcessingException;

+ 9 - 0
fs-service/src/main/java/com/fs/im/service/OpenIMService.java

@@ -5,6 +5,7 @@ import com.fs.common.core.domain.R;
 import com.fs.company.domain.CompanyUser;
 import com.fs.course.dto.BatchSendCourseDTO;
 import com.fs.course.dto.BatchUrgeCourseDTO;
+import com.fs.course.dto.BatchUrgeCourseTaskDTO;
 import com.fs.im.domain.FsImMsgSendDetail;
 import com.fs.im.domain.FsImMsgSendLog;
 import com.fs.im.dto.OpenImBatchMsgDTO;
@@ -81,6 +82,14 @@ public interface OpenIMService {
      */
     OpenImResponseDTO batchUrgeCourseTask(OpenImBatchMsgDTO openImBatchMsgDTO, List<FsImMsgSendDetail> imMsgSendDetailList);
 
+    /**
+     * 会员一键催课任务创建
+     * @param batchUrgeCourseTaskDTO
+     * @return
+     * @throws JsonProcessingException
+     */
+    OpenImResponseDTO batchUrgeCourseTaskCreate(BatchUrgeCourseTaskDTO batchUrgeCourseTaskDTO) throws JsonProcessingException;
+
     /**
      * 会员一键催课
      * @param batchUrgeCourseDTO

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

@@ -22,6 +22,7 @@ import com.fs.course.domain.FsUserCourse;
 import com.fs.course.dto.BatchSendCourseAllDTO;
 import com.fs.course.dto.BatchSendCourseDTO;
 import com.fs.course.dto.BatchUrgeCourseDTO;
+import com.fs.course.dto.BatchUrgeCourseTaskDTO;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.mapper.FsUserCompanyUserMapper;
 import com.fs.course.mapper.FsUserCourseMapper;
@@ -1341,6 +1342,123 @@ public class OpenIMServiceImpl implements OpenIMService {
         return openImResponseDTO;
     }
 
+    @Override
+    @Transactional
+    public OpenImResponseDTO batchUrgeCourseTaskCreate(BatchUrgeCourseTaskDTO batchUrgeCourseTaskDTO) throws JsonProcessingException {
+        ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+
+        Map<String, Object> param = new HashMap<>();
+        param.put("companyUserId", batchUrgeCourseTaskDTO.getCompanyUserId());
+        param.put("projectId", batchUrgeCourseTaskDTO.getProjectId());
+        List<FsUserCompanyUser> fsUserCompanyUsers = fsUserCompanyUserMapper.selectFsUserCompanyUserByIds(param);
+        if (CollectionUtils.isEmpty(fsUserCompanyUsers)) {
+            throw new ServiceException("没有消息接收人");
+        }
+
+        List<Long> rawUserIds = fsUserCompanyUsers.stream()
+                .map(FsUserCompanyUser::getUserId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+        if (CollectionUtils.isEmpty(rawUserIds)) {
+            throw new ServiceException("没有消息接收人");
+        }
+
+        List<FsCourseWatchLog> watchCourseByVideoList = fsCourseWatchLogMapper.getWatchCourseByVideoId(batchUrgeCourseTaskDTO.getVideoId(), rawUserIds);
+        Map<Long, List<FsCourseWatchLog>> watchLogMap = CollectionUtils.isEmpty(watchCourseByVideoList)
+                ? Collections.emptyMap()
+                : watchCourseByVideoList.stream()
+                .filter(Objects::nonNull)
+                .filter(v -> v.getUserId() != null)
+                .collect(Collectors.groupingBy(FsCourseWatchLog::getUserId));
+
+        List<String> userIds;
+        if (Objects.equals(batchUrgeCourseTaskDTO.getTaskType(), 1)) {
+            userIds = rawUserIds.stream()
+                    .filter(userId -> {
+                        List<FsCourseWatchLog> logs = watchLogMap.get(userId);
+                        return CollectionUtils.isEmpty(logs) || logs.stream()
+                                .map(FsCourseWatchLog::getLogType)
+                                .allMatch(logType -> logType == null || logType == 3);
+                    })
+                    .map(userId -> "U" + userId)
+                    .distinct()
+                    .collect(Collectors.toList());
+        } else if (Objects.equals(batchUrgeCourseTaskDTO.getTaskType(), 2)) {
+            userIds = rawUserIds.stream()
+                    .filter(userId -> {
+                        List<FsCourseWatchLog> logs = watchLogMap.get(userId);
+                        return CollectionUtils.isEmpty(logs) || logs.stream()
+                                .map(FsCourseWatchLog::getLogType)
+                                .noneMatch(logType -> logType != null && logType == 2);
+                    })
+                    .map(userId -> "U" + userId)
+                    .distinct()
+                    .collect(Collectors.toList());
+        } else {
+            throw new ServiceException("催课任务类型不正确");
+        }
+
+        if (CollectionUtils.isEmpty(userIds)) {
+            throw new ServiceException("没有符合条件的催课用户");
+        }
+
+        BatchSendCourseDTO batchSendCourseDTO = new BatchSendCourseDTO();
+        BeanUtils.copyProperties(batchUrgeCourseTaskDTO, batchSendCourseDTO);
+        batchSendCourseDTO.setId(batchUrgeCourseTaskDTO.getPeriodDaysId());
+        batchSendCourseDTO.setSendType(1);
+        batchSendCourseDTO.setIsUrgeCourse(true);
+        batchSendCourseDTO.setUrgeTime(batchUrgeCourseTaskDTO.getUrgeTime());
+        if (Boolean.TRUE.equals(batchUrgeCourseTaskDTO.getSendCourse())) {
+            batchSendCourseDTO.setTitle(batchUrgeCourseTaskDTO.getTitle());
+        } else {
+            batchSendCourseDTO.setTitle(batchUrgeCourseTaskDTO.getUrgeContent());
+        }
+
+        OpenImBatchMsgDTO openImBatchMsgDTO = makeOpenImBatchMsgDTO(
+                batchSendCourseDTO,
+                null,
+                objectMapper,
+                userIds,
+                batchUrgeCourseTaskDTO.getUrgeTime().getTime(),
+                "催课"
+        );
+
+        String sendUnionId = UUID.randomUUID().toString();
+        List<FsImMsgSendDetail> imMsgSendDetailList = createImMsgSendLog(
+                "催课",
+                batchSendCourseDTO,
+                batchUrgeCourseTaskDTO.getUrgeTime().getTime(),
+                1,
+                userIds,
+                sendUnionId
+        );
+
+        String redisKey = "openIm:batchSendMsg:urgeCourse";
+        Map<String, Object> redisMap = redisCache.getCacheMap(redisKey);
+        if (redisMap == null) {
+            redisMap = new HashMap<>();
+        }
+
+        BatchSendCourseAllDTO batchSendCourseAllDTO = new BatchSendCourseAllDTO();
+        batchSendCourseAllDTO.setBatchSendCourseDTO(batchSendCourseDTO)
+                .setOpenImBatchMsgDTO(openImBatchMsgDTO)
+                .setImMsgSendDetailList(imMsgSendDetailList);
+
+        String batchKey = batchUrgeCourseTaskDTO.getCourseId() + ":"
+                + batchUrgeCourseTaskDTO.getVideoId() + ":"
+                + batchUrgeCourseTaskDTO.getUrgeTime().getTime() + ":"
+                + imMsgSendDetailList.get(0).getLogId();
+        redisMap.put(batchKey, batchSendCourseAllDTO);
+        redisCache.setCacheMap(redisKey, redisMap);
+
+        OpenImResponseDTO responseDTO = new OpenImResponseDTO();
+        responseDTO.setErrCode(0);
+        responseDTO.setErrMsg("催课任务创建成功,待消息发送");
+        return responseDTO;
+    }
+
     @Override
     @Transactional
     public OpenImResponseDTO batchUrgeCourse(BatchUrgeCourseDTO batchUrgeCourseDTO, FsImMsgSendLog fsImMsgSendLog, String url) throws JsonProcessingException {

+ 18 - 0
fs-user-app/src/main/java/com/fs/app/controller/UserController.java

@@ -18,6 +18,8 @@ import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.course.service.IFsUserCourseVideoService;
+import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.course.vo.AppUserWatchLogVO;
 import com.fs.his.domain.FsDoctor;
 import com.fs.his.domain.FsPackage;
 import com.fs.his.domain.FsUser;
@@ -94,6 +96,10 @@ public class UserController extends  AppBaseController {
 
     @Autowired
     private IUserBehaviorService userBehaviorService;
+
+    @Autowired
+    private IFsCourseWatchLogService courseWatchLogService;
+
     @Login
     @ApiOperation("获取用户信息")
     @PostMapping("/friendsSearch")
@@ -458,4 +464,16 @@ public class UserController extends  AppBaseController {
         userBehaviorService.reportBehavior(dto);
         return AjaxResult.success();
     }
+
+    @Login
+    @ApiOperation("获取用户看课记录列表")
+    @GetMapping("/getWatchLogList")
+    public R getWatchLogList(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
+                             @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
+        Long userId = Long.parseLong(getUserId());
+        PageHelper.startPage(pageNum, pageSize);
+        List<AppUserWatchLogVO> list = courseWatchLogService.selectAppUserWatchLogList(userId);
+        PageInfo<AppUserWatchLogVO> pageInfo = new PageInfo<>(list);
+        return R.ok().put("data", pageInfo);
+    }
 }

+ 13 - 0
fs-user-app/src/main/java/com/fs/app/controller/course/CourseFsUserController.java

@@ -18,6 +18,7 @@ import com.fs.course.param.newfs.FsUserCourseVideoUParam;
 import com.fs.course.service.*;
 import com.fs.course.vo.CourseCheckinResultVO;
 import com.fs.course.vo.FsUserCourseVideoH5VO;
+import com.fs.course.vo.TodayUnfinishedCourseVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoLinkDetailsVO;
 import com.fs.his.domain.FsUser;
 import com.fs.his.dto.FsUserBindSalesParamDTO;
@@ -67,6 +68,9 @@ public class CourseFsUserController extends AppBaseController {
     @Autowired
     private IFsCourseCheckinReceiveService fsCourseCheckinReceiveService;
 
+    @Autowired
+    private IFsCourseWatchLogService courseWatchLogService;
+
 
     @Login
     @ApiOperation("判断是否添加客服(是否关联销售)")
@@ -270,4 +274,13 @@ public class CourseFsUserController extends AppBaseController {
         return fsCourseCheckinReceiveService.sendActiveReward(param);
     }
 
+    @Login
+    @ApiOperation("获取当日未完课课程列表")
+    @GetMapping("/getTodayUnfinishedCourse")
+    public R getTodayUnfinishedCourse() {
+        Long userId = Long.parseLong(getUserId());
+        List<TodayUnfinishedCourseVO> list = courseWatchLogService.selectTodayUnfinishedCourseList(userId);
+        return R.ok().put("data", list);
+    }
+
 }