FollowUpTask.java 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. package com.train.service;
  2. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  3. import com.train.entity.TrainAuditLog;
  4. import com.train.entity.TrainPlan;
  5. import com.train.mapper.TrainAuditLogMapper;
  6. import com.train.mapper.TrainPlanMapper;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.springframework.scheduling.annotation.Scheduled;
  9. import org.springframework.stereotype.Component;
  10. import javax.annotation.Resource;
  11. import java.util.Date;
  12. import java.util.List;
  13. /**
  14. * T+ 跟进定时任务:每日定时扫描已提交 7 天行动计划的学员,
  15. * 相对计划提交日(T0)生成 T+1 / T+3 / T+7 提醒记录,落 audit_log(幂等)。
  16. * 骨架版本以落账为主,生产可在此处改为推送订阅消息(复用 SubscribeMessageService)。
  17. */
  18. @Slf4j
  19. @Component
  20. public class FollowUpTask {
  21. @Resource
  22. private TrainPlanMapper trainPlanMapper;
  23. @Resource
  24. private TrainAuditLogMapper trainAuditLogMapper;
  25. private static final long DAY_MILLIS = 24L * 60 * 60 * 1000;
  26. /** 每日 09:30 执行(课后跟进节奏:T+1 成果合集 / T+3 补齐 / T+7 回访) */
  27. @Scheduled(cron = "0 30 9 * * ?")
  28. public void runFollowUp() {
  29. List<TrainPlan> plans = trainPlanMapper.selectList(
  30. new LambdaQueryWrapper<TrainPlan>().orderByAsc(TrainPlan::getSubmittedAt));
  31. Date now = new Date();
  32. for (TrainPlan plan : plans) {
  33. if (plan.getUid() == null || plan.getSubmittedAt() == null) {
  34. continue;
  35. }
  36. long elapsedDays = (now.getTime() - plan.getSubmittedAt().getTime()) / DAY_MILLIS;
  37. if (elapsedDays >= 1) {
  38. ensureLog(plan.getUid(), "followup_t1", "T+1 跟进提醒:课堂成果合集与照片已同步,请查收");
  39. }
  40. if (elapsedDays >= 3) {
  41. ensureLog(plan.getUid(), "followup_t3", "T+3 跟进提醒:未完成项建议补齐(三本账/自动化)");
  42. }
  43. if (elapsedDays >= 7) {
  44. ensureLog(plan.getUid(), "followup_t7", "T+7 回访:7 天行动计划完成度自检,欢迎约 1v1");
  45. }
  46. }
  47. log.info("FollowUpTask 完成一轮 T+ 跟进扫描,共 {} 条计划", plans.size());
  48. }
  49. /** 幂等写入 audit_log:同 action + targetId 已存在则跳过 */
  50. private void ensureLog(Long uid, String action, String detail) {
  51. Long exists = trainAuditLogMapper.selectCount(
  52. new LambdaQueryWrapper<TrainAuditLog>()
  53. .eq(TrainAuditLog::getAction, action)
  54. .eq(TrainAuditLog::getTargetId, uid));
  55. if (exists != null && exists > 0) {
  56. return;
  57. }
  58. TrainAuditLog entry = new TrainAuditLog();
  59. entry.setAction(action);
  60. entry.setActorUid(null);
  61. entry.setTargetType("user");
  62. entry.setTargetId(uid);
  63. entry.setDetail(detail);
  64. entry.setTs(new Date());
  65. trainAuditLogMapper.insert(entry);
  66. }
  67. }