Browse Source

APP IM 看课修改

xgb 1 day ago
parent
commit
fd035b710b

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

@@ -189,11 +189,27 @@ public class FsUserCourseVideoController extends AppBaseController {
 
         R courseSortLink = fsUserCourseService.createCourseSortLink(fsCourseLinkCreateParam);
         String url = courseSortLink.get("url").toString();
+        String linkId=courseSortLink.get("linkId").toString();
+
         Map<String, Object> map = new HashMap<>();
         map.put("url", url);
+        map.put("linkId", linkId);
         return R.ok(map);
     }
 
+    /**
+     * @Description: 生成看课记录 中康APP 调取接口/courseSortLink 后发送后再生成看课记录
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2026/1/21 15:38
+     */
+    @Login
+    @PostMapping("/batchCreateCourseRecord")
+     public R batchCreateCourseRecord(@RequestBody BatchSendCourseDTO batchSendCourseDTO) {
+        return fsUserCourseService.batchCreateCourseRecord(batchSendCourseDTO);
+    }
+
     @Login
     @PostMapping("/courseImage")
     @ApiOperation("生成课程海报")
@@ -333,6 +349,7 @@ public class FsUserCourseVideoController extends AppBaseController {
         R courseSortLink = fsUserCourseService.createAppCourseSortLink(fsCourseLinkCreateParam);
         String url = courseSortLink.get("url").toString();
         batchSendCourseDTO.setUrl(url);
+        batchSendCourseDTO.setLinkId(Long.parseLong(courseSortLink.get("linkId").toString()));
         if(batchSendCourseDTO.getIsUrgeCourse()==null){
             batchSendCourseDTO.setIsUrgeCourse(false);
         }

+ 1 - 0
fs-company/src/main/java/com/fs/user/FsUserAdminController.java

@@ -189,6 +189,7 @@ public class FsUserAdminController extends BaseController {
         String url = courseSortLink.get("url").toString();
         batchSendCourseDTO.setUrl(url);
         batchSendCourseDTO.setIsUrgeCourse(false);
+        batchSendCourseDTO.setLinkId(Long.parseLong(courseSortLink.get("linkId").toString()));
         return openIMService.batchSendCourse(batchSendCourseDTO);
     }
 

+ 2 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseWatchLog.java

@@ -93,4 +93,6 @@ public class FsCourseWatchLog extends BaseEntity
 
     private Integer watchType;//看课方式:1 app  2 小程序
 
+    private Long linkId;
+
 }

+ 3 - 0
fs-service/src/main/java/com/fs/course/dto/BatchSendCourseDTO.java

@@ -78,4 +78,7 @@ public class BatchSendCourseDTO implements Serializable {
 
     @ApiModelProperty(value = "催课内容")
     private String urgeContent;
+
+    // 看课链接主键
+    private Long linkId;
 }

+ 4 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java

@@ -735,4 +735,8 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
 
 
     List<FsCourseWatchLog> selectWatchLogForDelete(@Param("createTime") String createTime,@Param("createTimeEnd") String createTimeEnd);
+
+    List<FsUserCourseAppListVO> selectCourseByUserIdForStatusFinish(Long userId);
+
+    List<FsUserCourseAppListVO> selectCourseByUserIdForStatusNotFinish(Long userId);
 }

+ 20 - 0
fs-service/src/main/java/com/fs/course/param/FsUserCourseAppListParam.java

@@ -0,0 +1,20 @@
+package com.fs.course.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class FsUserCourseAppListParam implements Serializable {
+    private Long userId;//用户id;
+
+    // 记录类型 1看课中 2完课 3待看课 4看课中断
+    private String logType;
+
+    @ApiModelProperty(value = "页码,默认为1")
+    private Integer pageNum =1;
+    @ApiModelProperty(value = "页大小,默认为10")
+    private Integer pageSize = 10;
+
+}

+ 3 - 0
fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseAddCompanyUserParam.java

@@ -37,4 +37,7 @@ public class FsUserCourseAddCompanyUserParam implements Serializable {
     @ApiModelProperty(value = "项目ID")
     private Long projectId;
     private Integer isOpenCourse;
+
+    // 1 app 2 小程序
+    private Integer watchType;
 }

+ 7 - 0
fs-service/src/main/java/com/fs/course/service/IFsUserCourseService.java

@@ -2,6 +2,7 @@ package com.fs.course.service;
 
 import com.fs.common.core.domain.R;
 import com.fs.course.domain.FsUserCourse;
+import com.fs.course.dto.BatchSendCourseDTO;
 import com.fs.course.param.*;
 import com.fs.course.param.newfs.FsUserCourseListParam;
 import com.fs.course.vo.*;
@@ -137,4 +138,10 @@ public interface IFsUserCourseService {
      * 修改课堂配置
      */
     void editConfig(Long id, String configJson);
+
+    R getAppCourseList(FsUserCourseAppListParam param);
+
+    R getLinkData(Long linkId);
+
+    R batchCreateCourseRecord(BatchSendCourseDTO batchSendCourseDTO);
 }

+ 92 - 5
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java

@@ -24,6 +24,7 @@ import com.fs.company.mapper.CompanyTagMapper;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.*;
+import com.fs.course.dto.BatchSendCourseDTO;
 import com.fs.course.mapper.*;
 import com.fs.course.param.*;
 import com.fs.course.param.newfs.FsUserCourseListParam;
@@ -41,6 +42,8 @@ import com.fs.his.param.FsUserAddIntegralTemplateParam;
 import com.fs.his.service.IFsUserIntegralLogsService;
 import com.fs.his.service.IFsUserNewTaskService;
 import com.fs.his.vo.OptionsVO;
+import com.fs.im.domain.FsImMsgSendDetail;
+import com.fs.im.dto.OpenImBatchResponseDataDTO;
 import com.fs.qw.domain.QwCompany;
 import com.fs.qw.service.IQwCompanyService;
 import com.fs.qw.service.impl.AsyncUploadQwCourseImageService;
@@ -56,7 +59,6 @@ import com.google.zxing.client.j2se.MatrixToImageWriter;
 import com.google.zxing.common.BitMatrix;
 import com.google.zxing.qrcode.QRCodeWriter;
 import lombok.extern.slf4j.Slf4j;
-import org.checkerframework.checker.units.qual.A;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
@@ -605,11 +607,11 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
                 String domainName = getDomainName(param.getCompanyUserId(), config);
                 String sortLink = domainName+ link.getRealLink().replace("/#","");
                 sortLink = sortLink.replaceAll("\\\\", "");
-                return R.ok().put("url", sortLink).put("link", random);
+                return R.ok().put("url", sortLink).put("link", random).put("linkId", link.getLinkId());
             }else {
                 String domainName = getDomainName(param.getCompanyUserId(), config);
                 String sortLink = domainName + shortLink + link.getLink();
-                return R.ok().put("url", sortLink).put("link", random);
+                return R.ok().put("url", sortLink).put("link", random).put("linkId", link.getLinkId());
             }
         }
         return R.error("生成链接失败!");
@@ -793,11 +795,11 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
             if (CloudHostUtils.hasCloudHostName("中康")){
                 String domainName = getDomainName(param.getCompanyUserId(), config);
                 String sortLink = domainName + link.getRealLink().replace("/#","");
-                return R.ok().put("url", sortLink).put("link", random);
+                return R.ok().put("url", sortLink).put("link", random).put("linkId", link.getLinkId());
             }
             String domainName = getDomainName(param.getCompanyUserId(), config);
             String sortLink = domainName + appShortLink + link.getLink();
-            return R.ok().put("url", sortLink).put("link", random);
+            return R.ok().put("url", sortLink).put("link", random).put("linkId", link.getLinkId());
         }
         return R.error("生成链接失败!");
     }
@@ -813,6 +815,91 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
         fsUserCourseMapper.editConfig(id, configJson);
     }
 
+    @Override
+    public R getAppCourseList(FsUserCourseAppListParam param) {
+        // 查询看课记录
+        List<FsUserCourseAppListVO> list;
+        if("2".equals(param.getLogType())){ // 完课
+             list=fsCourseWatchLogMapper.selectCourseByUserIdForStatusFinish(param.getUserId());
+        }else if("3".equals(param.getLogType())){ // 待看课
+             list=fsCourseWatchLogMapper.selectCourseByUserIdForStatusNotFinish(param.getUserId());
+        }else {
+            return R.error("参数错误!");
+        }
+        list.forEach(item -> {
+            String redisKey = "h5wxuser:watch:duration:" + item.getUserId() + ":" + item.getVideoId() + ":" + item.getCompanyUserId();
+            String durationCurrent = redisCache.getCacheObject(redisKey);
+            if(durationCurrent != null && !durationCurrent.isEmpty()){
+                item.setDuration(Long.parseLong(durationCurrent));
+            }
+            item.setVideoDuration(getFsUserVideoDuration(item.getVideoId()));
+        });
+
+        return R.ok().put("data", list);
+    }
+
+    public Long getFsUserVideoDuration(Long videoId){
+        //将视频时长也存到redis
+        String videoRedisKey = "h5wxuser:video:duration:" + videoId;
+        Long videoDuration=0L;
+        try {
+            videoDuration = redisCache.getCacheObject(videoRedisKey);
+        }catch (Exception e){
+            String string = redisCache.getCacheObject(videoRedisKey);
+            videoDuration=Long.parseLong(string);
+            log.error("key中id为S:{}", videoDuration);
+        }
+
+
+        if (videoDuration==null){
+            FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
+            videoDuration=video.getDuration();
+            redisCache.setCacheObject(videoRedisKey,video.getDuration());
+        }
+        return videoDuration;
+    }
+
+    @Override
+    public R getLinkData(Long linkId) {
+        FsCourseLink fsCourseLink = fsCourseLinkMapper.selectFsCourseLinkByLinkId(linkId);
+        if (fsCourseLink == null){
+            return R.error("视频已过期!");
+        }
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        String domainName = getDomainName(fsCourseLink.getCompanyUserId(), config);
+        String sortLink = domainName+ fsCourseLink.getRealLink().replace("/#","");
+
+        Map<String, Object> data = new HashMap<>();
+        data.put("url", sortLink);
+        return R.ok().put("data", data);
+    }
+
+    @Override
+    public R batchCreateCourseRecord(BatchSendCourseDTO batchSendCourseDTO) {
+        if(batchSendCourseDTO.getUserIds()== null|| batchSendCourseDTO.getUserIds().isEmpty()){
+            return R.error("请选择用户!");
+        }
+        FsUserCourse fsUserCourse = fsUserCourseMapper.selectFsUserCourseByCourseId(batchSendCourseDTO.getCourseId());
+        Long project = fsUserCourse != null ? fsUserCourse.getProject() : null;
+        List<FsCourseWatchLog> watchLogsInsertList = new LinkedList<>();
+        for (Long userId : batchSendCourseDTO.getUserIds()) {
+            FsCourseWatchLog fsCourseWatchLog = new FsCourseWatchLog();
+            BeanUtils.copyProperties(batchSendCourseDTO, fsCourseWatchLog);
+            fsCourseWatchLog.setUserId(userId);
+            fsCourseWatchLog.setSendType(1);
+            fsCourseWatchLog.setDuration(0L);
+            fsCourseWatchLog.setCreateTime(new Date());
+            fsCourseWatchLog.setLogType(3);
+            fsCourseWatchLog.setProject(project);
+            fsCourseWatchLog.setWatchType(1); // app
+            fsCourseWatchLog.setLinkId(batchSendCourseDTO.getLinkId());
+            watchLogsInsertList.add(fsCourseWatchLog);
+        }
+        fsCourseWatchLogMapper.insertFsCourseWatchLogBatch(watchLogsInsertList);
+        return R.ok();
+    }
+
 
     private Graphics2D initializeGraphics(BufferedImage combined) {
         Graphics2D graphics = combined.createGraphics();

+ 3 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -2555,6 +2555,7 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
                 fsCourseWatchLog.setDuration(0L);
                 fsCourseWatchLog.setCreateTime(new Date());
                 fsCourseWatchLog.setLogType(1);
+                fsCourseWatchLog.setWatchType(param.getWatchType());
                 courseWatchLogMapper.insertFsCourseWatchLog(fsCourseWatchLog);
                 String redisKey = "h5wxuser:watch:heartbeat:" + param.getUserId() + ":" + param.getVideoId() + ":" + 0;
                 redisCache.setCacheObject(redisKey, LocalDateTime.now().toString());
@@ -2654,6 +2655,7 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
             updateLog.setPeriodId(param.getPeriodId());
             updateLog.setProject(courseProject);
             updateLog.setUpdateTime(new Date());
+            updateLog.setWatchType(param.getWatchType());
             courseWatchLogMapper.updateFsCourseWatchLog(updateLog);
         } else {
             FsCourseWatchLog fsCourseWatchLog = new FsCourseWatchLog();
@@ -2663,6 +2665,7 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
             fsCourseWatchLog.setCreateTime(new Date());
             fsCourseWatchLog.setLogType(1);
             fsCourseWatchLog.setProject(courseProject);
+            fsCourseWatchLog.setWatchType(param.getWatchType());
             courseWatchLogMapper.insertFsCourseWatchLog(fsCourseWatchLog);
 
             String redisKey = "h5wxuser:watch:heartbeat:" + param.getUserId() + ":" + param.getVideoId() + ":" + param.getCompanyUserId();

+ 43 - 0
fs-service/src/main/java/com/fs/course/vo/FsUserCourseAppListVO.java

@@ -0,0 +1,43 @@
+package com.fs.course.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 课程对象 fs_user_course
+ *
+ * @author fs
+ * @date 2024-05-15
+ */
+@Data
+public class FsUserCourseAppListVO extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+
+    /** 课程名称 */
+    private String courseName;
+
+    /** 课程封面 */
+    private String imgUrl;
+
+    private String videoName;
+
+    private Long linkId;
+
+    // 播放时长
+    private Long duration;
+
+    // 视频时长
+    private Long videoDuration;
+
+    private Long videoId;
+
+    private Long userId;
+
+    private Long companyUserId;
+
+}

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

@@ -1403,6 +1403,8 @@ public class OpenIMServiceImpl implements OpenIMService {
             fsCourseWatchLog.setLogType(3);
             fsCourseWatchLog.setProject(project);
             fsCourseWatchLog.setImMsgSendDetailId(map.get(Long.parseLong(userId)).getLogDetailId());
+            fsCourseWatchLog.setWatchType(1); // app
+            fsCourseWatchLog.setLinkId(batchSendCourseDTO.getLinkId());
             watchLogsInsertList.add(fsCourseWatchLog);
         }
         courseWatchLogMapper.insertFsCourseWatchLogBatch(watchLogsInsertList);

+ 25 - 4
fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml

@@ -376,7 +376,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 project,
                 period_id,
                 im_msg_send_detail_id,
-                watch_type
+                watch_type,
+                link_id
                 )
                 VALUES
                 <foreach collection="watchLogs" item="log" separator=",">
@@ -399,12 +400,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                     #{log.project},
                     #{log.periodId},
                     #{log.imMsgSendDetailId},
-                    #{log.watchType}
+                    #{log.watchType},
+                     #{log.linkId}
                     )
                 </foreach>
                 ON DUPLICATE KEY UPDATE
                 update_time = NOW(),
-                im_msg_send_detail_id = VALUES(im_msg_send_detail_id)
+                im_msg_send_detail_id = VALUES(im_msg_send_detail_id),
+                link_id = VALUES(link_id)
             </insert>
 
 
@@ -1146,7 +1149,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         where t1.create_time &gt;=#{createTime}  and t1.create_time &lt; #{createTimeEnd}
     </select>
 
-
     <insert id="batchInsert" parameterType="java.util.List">
         INSERT INTO fs_course_watch_log_1 (
         log_id,
@@ -1205,4 +1207,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{id}
         </foreach>
     </delete>
+
+
+    <select id="selectCourseByUserIdForStatusFinish" resultType="com.fs.course.vo.FsUserCourseAppListVO">
+        select c.course_name courseName,c.img_url imgUrl,r.title videoName,l.link_id linkId,l.duration,l.video_id videoId,l.user_id userId,l.company_user_id companyUserId  from fs_course_watch_log l
+        left join fs_user_course c on l.course_id =c.course_id
+        left join fs_user_course_video r on r.video_id=l.video_id
+        WHERE l.user_id = #{userId} and l.log_type = 2
+          and l.create_time &gt;= CONCAT(CURDATE(), ' 00:00:00')
+          and l.create_time &lt;= CONCAT(CURDATE(), ' 23:59:59')
+    </select>
+
+    <select id="selectCourseByUserIdForStatusNotFinish" resultType="com.fs.course.vo.FsUserCourseAppListVO">
+        select c.course_name courseName,c.img_url imgUrl,r.title videoName,l.link_id linkId,l.duration,l.video_id videoId,l.user_id userId,l.company_user_id  from fs_course_watch_log l
+        left join fs_user_course c on l.course_id =c.course_id
+        left join fs_user_course_video r on r.video_id=l.video_id
+        WHERE l.user_id = #{userId} and l.log_type != 2
+          and l.create_time &gt;= CONCAT(CURDATE(), ' 00:00:00')
+          and l.create_time &lt;= CONCAT(CURDATE(), ' 23:59:59')
+    </select>
 </mapper>

+ 33 - 0
fs-user-app/src/main/java/com/fs/app/controller/CourseController.java

@@ -355,4 +355,37 @@ public class CourseController extends  AppBaseController{
         log.info("zyp \n【发放APP奖励】:{}",param);
         return courseVideoService.sendAppReward(param);
     }
+
+    /**
+     * @Description: APP 用户获取课程列表
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2026/1/21 9:48
+     */
+    @ApiOperation("APP用户获取课程列表")
+    @Login
+    @GetMapping("/getAppCourseList")
+    public R getAppCourseList(FsUserCourseAppListParam param)
+    {
+        param.setUserId(Long.parseLong(getUserId()));
+        return courseService.getAppCourseList(param);
+    }
+
+    /**
+     * @Description: 获取链接数据
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2026/1/21 16:10
+     */
+    @ApiOperation("获取链接数据")
+    @GetMapping("/getLinkData")
+    public R getLinkData(Long linkId)
+    {
+        return courseService.getLinkData(linkId);
+    }
+
+
+
 }