ct 14 часов назад
Родитель
Сommit
5706e5142c

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

@@ -403,20 +403,6 @@ public class FsUserCourseVideoController extends AppBaseController {
         return imMsgSendLogService.deleteFsImMsgSendLogAndDetail(logId);
     }
 
-    @Login
-    @ApiOperation("获取看课使用小程序")
-    @GetMapping("/getLoginMiniAppId/{appId}")
-    public R getLoginMiniAppId(@PathVariable String appId) {
-        CompanyMiniapp params =  new CompanyMiniapp();
-        params.setCompanyId(getCompanyId());
-        List<CompanyMiniapp> miniApps = companyMiniAppService.selectCompanyMiniappList(params);
-        if (miniApps != null) {
-            appId = miniApps.stream().min(Comparator.comparing(CompanyMiniapp::getSortNum)).map(CompanyMiniapp::getAppId).orElse(appId);
-        }
-
-        return R.ok().put("data", appId);
-    }
-
     @Autowired
     private FeiShuService feiShuService;
 

+ 1 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseTrafficLog.java

@@ -67,6 +67,7 @@ public class FsCourseTrafficLog extends BaseEntity
     private Long periodId;
 
 
+    private Integer typeFlag;
 
 //    @JsonFormat(pattern = "yyyy-MM-dd")
 //    private Date time;

+ 56 - 0
fs-service/src/main/java/com/fs/course/domain/WatchLogBak.java

@@ -0,0 +1,56 @@
+package com.fs.course.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.Date;
+
+@Data
+public class WatchLogBak {
+
+    @TableId(type = IdType.AUTO)
+    private Long backupId;
+
+    // 原始数据字段
+    private Long originalLogId;
+    private Long userId;
+    private Long videoId;
+    private Integer logType;
+    private Date createTime;
+    private Date updateTime;
+    private Long qwExternalContactId;
+    private Long duration;
+    private Long qwUserId;
+    private Long companyUserId;
+    private Long companyId;
+    private Long courseId;
+    private Integer sendType;
+    private Integer rewardType;
+    private LocalDateTime lastHeartbeatTime;
+    private String sopId;
+    private Date finishTime;
+    private Integer sendFinishMsg;
+    private Date campPeriodTime;
+    private Long day;
+    private Long project;
+    private String createBy;
+    private String updateBy;
+    private Long periodId;
+    private Integer projectId;
+    private Long imMsgSendDetailId;
+    private Integer watchType;
+
+    // 删除相关字段
+    private Date deleteTime;
+    private Long  deleteBy;
+    private Integer deleteMethod = 1; // 1手动删除 2自动清理
+    private String originalData; // JSON格式的完整原始数据
+
+    // 备份相关字段
+    private String backupOperator;
+    private String backupBatchNo;
+    private String remark;
+}

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

@@ -2,6 +2,7 @@ package com.fs.course.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.course.domain.FsCourseWatchLog;
+import com.fs.course.domain.WatchLogBak;
 import com.fs.course.dto.WatchLogDTO;
 import com.fs.course.param.*;
 import com.fs.course.vo.*;
@@ -66,6 +67,16 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
      */
     public int insertFsCourseWatchLog(FsCourseWatchLog fsCourseWatchLog);
 
+    /**
+     * 新增短链课程看课记录备份
+     *
+     * @param watchLogBak 短链课程看课记录备份
+     * @return 结果
+     */
+    int insertBackup(WatchLogBak watchLogBak);
+
+
+
     public int insertOrUpdateFsCourseWatchLog(FsCourseWatchLog fsCourseWatchLog);
 
     /**
@@ -739,4 +750,12 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
             "and company_user_id = #{companyUserId} " +
             "and user_id = #{userId} order by create_time desc limit 1")
     FsCourseWatchLog getWatchCourseVideoByFsUser2(@Param("userId") Long userId, @Param("videoId") Long videoId, @Param("companyUserId") Long companyUserId);
+
+    /**
+     * 查询用户当天的看课记录
+     * @param userId
+     * @param projectId
+     */
+    @Select("select * from fs_course_watch_log where user_id = #{userId} and project = #{projectId} and create_time >= #{startTime}")
+    FsCourseWatchLog selectByUserIdAndProjectId(@Param("userId") Long userId, @Param("projectId") Long projectId, @Param("startTime") Date startTime);
 }

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

@@ -67,6 +67,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.text.SimpleDateFormat;
 import java.time.Duration;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
@@ -1310,6 +1311,31 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
         return fsCourseWatchLogMapper.selectQwFsCourseWatchLogStatisticsListVO(param);
     }
 
+    public static Date removeTime(Date date) {
+        if (date == null) {
+            return null;
+        }
+
+        try {
+            // 双重保障:先格式化成字符串,再解析回来
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+            String dateStr = sdf.format(date);
+            Date result = sdf.parse(dateStr);
+
+            // 再用Calendar确保清除
+            Calendar cal = Calendar.getInstance();
+            cal.setTime(result);
+            cal.set(Calendar.HOUR_OF_DAY, 0);
+            cal.set(Calendar.MINUTE, 0);
+            cal.set(Calendar.SECOND, 0);
+            cal.set(Calendar.MILLISECOND, 0);
+
+            return cal.getTime();
+        } catch (Exception e) {
+            // 备用方案
+            return new java.sql.Date(date.getTime());
+        }
+    }
     /**
      * 根据看课记录id获取所有的外部联系人ids
      * @param watchLogIds
@@ -1353,6 +1379,100 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
         return R.ok().put("data", data);
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public R clearUserWatchLog(Long userId, Long projectId) {
+        Date startTime = removeTime(new Date());
+        FsCourseWatchLog fsCourseWatchLog = fsCourseWatchLogMapper.selectByUserIdAndProjectId(userId, projectId, startTime);
+        if (fsCourseWatchLog != null) {
+            int i = fsCourseWatchLogMapper.deleteById(fsCourseWatchLog.getLogId());
+            if (i < 0) {
+                return R.error("清除失败");
+            }else {
+                //备份看课记录
+                WatchLogBak watchLogBak = convertToBackupWithDeleteInfo(fsCourseWatchLog, userId, 1);
+                int j = fsCourseWatchLogMapper.insertBackup(watchLogBak);
+                if (j < 0) {
+                    return R.error("备份失败");
+                }
+            }
+        }else {
+            return R.error("没有需要清除的记录");
+        }
+        return R.ok("清除成功");
+    }
+
+    public WatchLogBak convertToBackupWithDeleteInfo(FsCourseWatchLog original, Long deleteBy,
+                                                     Integer deleteMethod) {
+        WatchLogBak backup = convertToBackup(original);
+        if (backup != null) {
+            backup.setDeleteBy(deleteBy);
+            if (deleteMethod != null) {
+                backup.setDeleteMethod(deleteMethod);
+            }
+        }
+        return backup;
+    }
+
+    public WatchLogBak convertToBackup(FsCourseWatchLog original) {
+        if (original == null) {
+            return null;
+        }
+
+        WatchLogBak backup = new WatchLogBak();
+
+        // 复制原始数据字段
+        backup.setOriginalLogId(original.getLogId());
+        backup.setUserId(original.getUserId());
+        backup.setVideoId(original.getVideoId());
+        backup.setLogType(original.getLogType());
+        backup.setCreateTime(original.getCreateTime());
+        backup.setUpdateTime(original.getUpdateTime());
+        backup.setQwExternalContactId(original.getQwExternalContactId());
+        backup.setDuration(original.getDuration());
+        backup.setQwUserId(original.getQwUserId());
+        backup.setCompanyUserId(original.getCompanyUserId());
+        backup.setCompanyId(original.getCompanyId());
+        backup.setCourseId(original.getCourseId());
+        backup.setSendType(original.getSendType());
+        backup.setRewardType(original.getRewardType());
+        backup.setLastHeartbeatTime(original.getLastHeartbeatTime());
+        backup.setSopId(original.getSopId());
+        backup.setFinishTime(original.getFinishTime());
+        backup.setSendFinishMsg(original.getSendFinishMsg());
+        backup.setCampPeriodTime(original.getCampPeriodTime());
+        backup.setDay(original.getDay());
+        backup.setProject(original.getProject());
+        backup.setCreateBy(original.getCreateBy());
+        backup.setUpdateBy(original.getUpdateBy());
+        backup.setPeriodId(original.getPeriodId());
+        backup.setImMsgSendDetailId(original.getImMsgSendDetailId());
+        backup.setWatchType(original.getWatchType());
+
+        // 设置删除信息(调用时传入)
+        backup.setDeleteTime(new Date());
+
+        // 保存完整的原始数据为JSON
+        backup.setOriginalData(convertToJson(original));
+
+        return backup;
+    }
+
+    private String convertToJson(FsCourseWatchLog original) {
+        try {
+            // 使用 FastJSON 进行序列化,它对复杂对象有更好的处理
+            String jsonString = JSON.toJSONString(original);
+
+            // 验证 JSON 格式是否有效
+            if (isValidJson(jsonString)) {
+                return jsonString;
+            }
+        } catch (Exception e) {
+            log.error("转换JSON失败: {}, 原始对象ID: {}", e.getMessage(), original.getLogId());
+        }
+        return null;
+    }
+
     private boolean isValidJson(String jsonString) {
         try {
             JSON.parse(jsonString);

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

@@ -6,6 +6,7 @@ import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -14,6 +15,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fs.common.BeanCopyUtils;
+import com.fs.common.constant.FsConstants;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.core.domain.entity.SysDictData;

+ 1 - 1
fs-service/src/main/java/com/fs/feishu/service/FeiShuService.java

@@ -91,7 +91,7 @@ public class FeiShuService {
         // 生成安全令牌
         Long timestamp = System.currentTimeMillis() / 1000;
         String token = SecureTokenUtil.generateToken(companyUserId, videoId, periodId, timestamp);
-
+        config.setFeishuLinkDomainName("https://h5.jnmyunl.com");
         return config.getFeishuLinkDomainName() + String.format(COURSE_PATH, token);
     }
 

+ 5 - 1
fs-service/src/main/resources/application-druid-jnmy-test.yml

@@ -145,7 +145,7 @@ spring:
                 # 主库数据源
                 type: com.alibaba.druid.pool.DruidDataSource
                 driverClassName: com.mysql.cj.jdbc.Driver
-                url: jdbc:mysql://120.46.174.121:2345/fs_his_test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                url: jdbc:mysql://120.46.174.121:2345/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
                 username: root
                 password: Ylrztek250218!3@.
                 # 初始连接数
@@ -243,4 +243,8 @@ wechat:
 #        redirectUri: http://ta6d97ec.natappfree.cc/callback
 #    isNeedScan: true
 
+# 飞书
+feishu:
+    appId: "cli_aab0956445f89beb"
+    appSecret: "zPonwfW704MLe0YnCfpwzhRjDsFkk0nT"
 

+ 3 - 0
fs-service/src/main/resources/application-druid-jnmy.yml

@@ -246,5 +246,8 @@ wechat:
         secret: 70d3ed4f8eb68cca0cf525b8ce07405d
         redirectUri: https://admin.jnmyunl.com/prod-api/callback
         isNeedScan: true
+feishu:
+    appId: "cli_aab0956445f89beb"
+    appSecret: "zPonwfW704MLe0YnCfpwzhRjDsFkk0nT"
 
 

+ 73 - 1
fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml

@@ -404,7 +404,79 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 update_time = NOW(),
                 im_msg_send_detail_id = VALUES(im_msg_send_detail_id)
             </insert>
-
+    <insert id="insertBackup">
+        INSERT INTO fs_course_watch_log_bak (
+            original_log_id,
+            user_id,
+            video_id,
+            log_type,
+            create_time,
+            update_time,
+            qw_external_contact_id,
+            duration,
+            qw_user_id,
+            company_user_id,
+            company_id,
+            course_id,
+            send_type,
+            reward_type,
+            last_heartbeat_time,
+            sop_id,
+            finish_time,
+            send_finish_msg,
+            camp_period_time,
+            day,
+            project,
+            create_by,
+            update_by,
+            period_id,
+            project_id,
+            im_msg_send_detail_id,
+            watch_type,
+            delete_time,
+            delete_by,
+            delete_method,
+            original_data,
+            backup_operator,
+            backup_batch_no,
+            remark
+        ) VALUES (
+                     #{originalLogId},
+                     #{userId},
+                     #{videoId},
+                     #{logType},
+                     #{createTime},
+                     #{updateTime},
+                     #{qwExternalContactId},
+                     #{duration},
+                     #{qwUserId},
+                     #{companyUserId},
+                     #{companyId},
+                     #{courseId},
+                     #{sendType},
+                     #{rewardType},
+                     #{lastHeartbeatTime},
+                     #{sopId},
+                     #{finishTime},
+                     #{sendFinishMsg},
+                     #{campPeriodTime},
+                     #{day},
+                     #{project},
+                     #{createBy},
+                     #{updateBy},
+                     #{periodId},
+                     #{projectId},
+                     #{imMsgSendDetailId},
+                     #{watchType},
+                     #{deleteTime},
+                     #{deleteBy},
+                     #{deleteMethod},
+                     #{originalData},
+                     #{backupOperator},
+                     #{backupBatchNo},
+                     #{remark}
+                 )
+    </insert>
 
 
             <update id="updateFsCourseWatchLog" parameterType="FsCourseWatchLog">