|
|
@@ -385,24 +385,18 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
|
|
|
public void scheduleUpdateDurationToDatabase() {
|
|
|
log.info("WXH5-开始更新会员看课时长,检查完课>>>>>>");
|
|
|
Set<String> keys = h5WxUserWatchRedisUtil.listDurationKeys();
|
|
|
-
|
|
|
- //读取看课配置
|
|
|
- String json = configService.selectConfigByKey("course.config");
|
|
|
- CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
|
|
|
-
|
|
|
+ CourseConfig config = loadCourseConfig();
|
|
|
List<FsCourseWatchLog> logs = new ArrayList<>();
|
|
|
for (String key : keys) {
|
|
|
- //取key中数据
|
|
|
String[] parts = key.split(":");
|
|
|
- Long userId=null;
|
|
|
- Long videoId=null;
|
|
|
- Long companyUserId=null;
|
|
|
+ Long userId;
|
|
|
+ Long videoId;
|
|
|
+ Long companyUserId;
|
|
|
try {
|
|
|
userId = Long.parseLong(parts[3]);
|
|
|
videoId = Long.parseLong(parts[4]);
|
|
|
companyUserId = Long.parseLong(parts[5]);
|
|
|
-
|
|
|
- }catch (Exception e){
|
|
|
+ } catch (Exception e) {
|
|
|
log.error("key中id为null:{}", key);
|
|
|
continue;
|
|
|
}
|
|
|
@@ -410,45 +404,121 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
|
|
|
if (durationStr == null) {
|
|
|
log.error("key中数据为null:{}", key);
|
|
|
h5WxUserWatchRedisUtil.untrackDuration(key);
|
|
|
- continue; // 如果 Redis 中没有记录,跳过
|
|
|
+ continue;
|
|
|
}
|
|
|
Long duration = Long.valueOf(durationStr);
|
|
|
-
|
|
|
- FsCourseWatchLog watchLog = new FsCourseWatchLog();
|
|
|
- watchLog.setVideoId(videoId);
|
|
|
- watchLog.setUserId(userId);
|
|
|
- watchLog.setCompanyUserId(companyUserId);
|
|
|
- watchLog.setDuration(duration);
|
|
|
-
|
|
|
- //取对应视频的时长
|
|
|
- Long videoDuration = 0L;
|
|
|
- try {
|
|
|
- videoDuration = getFsUserVideoDuration(videoId);
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("视频时长识别错误:{}", key);
|
|
|
+ FsCourseWatchLog watchLog = buildH5WxDurationWatchLogUpdate(userId, videoId, companyUserId, duration, config, key);
|
|
|
+ if (watchLog == null) {
|
|
|
continue;
|
|
|
}
|
|
|
- if (videoDuration != null && videoDuration != 0) {
|
|
|
- //判断是否完课
|
|
|
- long percentage = (duration * 100 / videoDuration);
|
|
|
- if (percentage >= config.getAnswerRate()) {
|
|
|
- watchLog.setLogType(2); // 设置状态为“已完成”checkFsUserWatchStatus
|
|
|
- watchLog.setFinishTime(new Date());
|
|
|
- String heartbeatKey = H5WxUserWatchRedisUtil.heartbeatKey(userId, videoId, companyUserId);
|
|
|
- // 完课删除心跳记录
|
|
|
- redisCache.deleteObject(heartbeatKey);
|
|
|
- h5WxUserWatchRedisUtil.untrackHeartbeat(heartbeatKey);
|
|
|
- // 完课删除看课时长记录
|
|
|
- redisCache.deleteObject(key);
|
|
|
- h5WxUserWatchRedisUtil.untrackDuration(key);
|
|
|
- }
|
|
|
- }
|
|
|
- //集合中增加
|
|
|
logs.add(watchLog);
|
|
|
}
|
|
|
batchUpdateFsUserCourseWatchLog(logs, 100);
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public void syncH5WxUserWatchProgressOnFinish(Long userId, Long videoId, Long companyUserId, Long duration) {
|
|
|
+ if (userId == null || videoId == null || companyUserId == null || duration == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ CourseConfig config = loadCourseConfig();
|
|
|
+ String durationKey = H5WxUserWatchRedisUtil.durationKey(userId, videoId, companyUserId);
|
|
|
+ FsCourseWatchLog watchLog = buildH5WxDurationWatchLogUpdate(userId, videoId, companyUserId, duration, config, durationKey);
|
|
|
+ if (watchLog == null || watchLog.getLogType() == null || watchLog.getLogType() != 2) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ batchUpdateFsUserCourseWatchLog(Collections.singletonList(watchLog), 100);
|
|
|
+ log.info("H5微信看课已达完课阈值,已同步写库: userId={}, videoId={}, companyUserId={}, duration={}",
|
|
|
+ userId, videoId, companyUserId, duration);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void syncQwUserWatchProgressOnFinish(Long qwUserId, Long qwExternalContactId, Long videoId, Long duration) {
|
|
|
+ if (qwUserId == null || qwExternalContactId == null || videoId == null || duration == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ CourseConfig config = loadCourseConfig();
|
|
|
+ String durationKey = "h5user:watch:duration:" + qwUserId + ":" + qwExternalContactId + ":" + videoId;
|
|
|
+ FsCourseWatchLog watchLog = buildQwDurationWatchLogUpdate(
|
|
|
+ qwUserId, qwExternalContactId, videoId, duration, config, durationKey);
|
|
|
+ if (watchLog.getLogType() == null || watchLog.getLogType() != 2) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ batchUpdateFsCourseWatchLog(Collections.singletonList(watchLog), 100);
|
|
|
+ log.info("企微看课已达完课阈值,已同步写库: qwUserId={}, qwExternalContactId={}, videoId={}, duration={}",
|
|
|
+ qwUserId, qwExternalContactId, videoId, duration);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 与 scheduleBatchUpdateToDatabase / processKeyBatch(type=1) 单条处理逻辑一致
|
|
|
+ */
|
|
|
+ private FsCourseWatchLog buildQwDurationWatchLogUpdate(Long qwUserId, Long externalId, Long videoId,
|
|
|
+ Long duration, CourseConfig config, String durationRedisKey) {
|
|
|
+ FsCourseWatchLog watchLog = new FsCourseWatchLog();
|
|
|
+ watchLog.setVideoId(videoId);
|
|
|
+ watchLog.setQwUserId(qwUserId);
|
|
|
+ watchLog.setQwExternalContactId(externalId);
|
|
|
+ watchLog.setDuration(duration);
|
|
|
+
|
|
|
+ Long videoDuration;
|
|
|
+ try {
|
|
|
+ videoDuration = getVideoDuration(videoId);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("视频时长识别错误:{}", durationRedisKey);
|
|
|
+ return watchLog;
|
|
|
+ }
|
|
|
+ if (videoDuration != null && videoDuration != 0) {
|
|
|
+ long percentage = (duration * 100 / videoDuration);
|
|
|
+ if (percentage >= config.getAnswerRate()) {
|
|
|
+ watchLog.setLogType(2);
|
|
|
+ watchLog.setFinishTime(new Date());
|
|
|
+ String heartbeatKey = "h5user:watch:heartbeat:" + qwUserId + ":" + externalId + ":" + videoId;
|
|
|
+ redisCache.deleteObject(heartbeatKey);
|
|
|
+ redisCache.deleteObject(durationRedisKey);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return watchLog;
|
|
|
+ }
|
|
|
+
|
|
|
+ private CourseConfig loadCourseConfig() {
|
|
|
+ String json = configService.selectConfigByKey("course.config");
|
|
|
+ return JSONUtil.toBean(json, CourseConfig.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 与 scheduleUpdateDurationToDatabase 单条处理逻辑一致(百分比达标即完课并清理 Redis)
|
|
|
+ */
|
|
|
+ private FsCourseWatchLog buildH5WxDurationWatchLogUpdate(Long userId, Long videoId, Long companyUserId,
|
|
|
+ Long duration, CourseConfig config, String durationRedisKey) {
|
|
|
+ FsCourseWatchLog watchLog = new FsCourseWatchLog();
|
|
|
+ watchLog.setVideoId(videoId);
|
|
|
+ watchLog.setUserId(userId);
|
|
|
+ watchLog.setCompanyUserId(companyUserId);
|
|
|
+ watchLog.setDuration(duration);
|
|
|
+
|
|
|
+ Long videoDuration;
|
|
|
+ try {
|
|
|
+ videoDuration = getFsUserVideoDuration(videoId);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("视频时长识别错误:{}", durationRedisKey);
|
|
|
+ return watchLog;
|
|
|
+ }
|
|
|
+ if (videoDuration == null || videoDuration == 0 || config == null || config.getAnswerRate() == null) {
|
|
|
+ return watchLog;
|
|
|
+ }
|
|
|
+ long percentage = (duration * 100 / videoDuration);
|
|
|
+ if (percentage >= config.getAnswerRate()) {
|
|
|
+ watchLog.setLogType(2);
|
|
|
+ watchLog.setFinishTime(new Date());
|
|
|
+ String heartbeatKey = H5WxUserWatchRedisUtil.heartbeatKey(userId, videoId, companyUserId);
|
|
|
+ redisCache.deleteObject(heartbeatKey);
|
|
|
+ h5WxUserWatchRedisUtil.untrackHeartbeat(heartbeatKey);
|
|
|
+ redisCache.deleteObject(durationRedisKey);
|
|
|
+ h5WxUserWatchRedisUtil.untrackDuration(durationRedisKey);
|
|
|
+ }
|
|
|
+ return watchLog;
|
|
|
+ }
|
|
|
+
|
|
|
public Long getFsUserVideoDuration(Long videoId) {
|
|
|
//将视频时长也存到redis
|
|
|
String videoRedisKey = "h5wxuser:video:duration:" + videoId;
|
|
|
@@ -1106,32 +1176,7 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
|
|
|
continue; // 如果 Redis 中没有记录,跳过
|
|
|
}
|
|
|
Long duration = Long.valueOf(durationStr);
|
|
|
-
|
|
|
- watchLog.setDuration(duration);
|
|
|
-
|
|
|
- // 取对应视频的时长
|
|
|
- Long videoDuration;
|
|
|
- try {
|
|
|
- videoDuration = getVideoDuration(videoId);
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("视频时长识别错误:{}", key);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- if (videoDuration != null && videoDuration != 0) {
|
|
|
- // 判断是否完课
|
|
|
- long percentage = (duration * 100 / videoDuration);
|
|
|
- if (percentage >= config.getAnswerRate()) {
|
|
|
- watchLog.setLogType(2); // 设置状态为"已完成"
|
|
|
- watchLog.setFinishTime(new Date());
|
|
|
- String heartbeatKey = "h5user:watch:heartbeat:" + qwUserId + ":" + externalId + ":" + videoId;
|
|
|
- // 完课删除心跳记录
|
|
|
- redisCache.deleteObject(heartbeatKey);
|
|
|
- // 完课删除看课时长记录
|
|
|
- redisCache.deleteObject(key);
|
|
|
- }
|
|
|
- }
|
|
|
+ watchLog = buildQwDurationWatchLogUpdate(qwUserId, externalId, videoId, duration, config, key);
|
|
|
}else{
|
|
|
//检查看课中断
|
|
|
// 获取最后心跳时间
|