PlanActivationService.java 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package com.etotem.cfc.service;
  2. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  3. import com.etotem.cfc.entity.FamilyMember;
  4. import com.etotem.cfc.entity.Task;
  5. import com.etotem.cfc.entity.TaskPlanInstance;
  6. import com.etotem.cfc.entity.TaskTemplateItem;
  7. import com.etotem.cfc.entity.User;
  8. import com.etotem.cfc.mapper.FamilyMemberMapper;
  9. import com.etotem.cfc.mapper.TaskMapper;
  10. import com.etotem.cfc.mapper.TaskPlanInstanceMapper;
  11. import com.etotem.cfc.mapper.TaskTemplateItemMapper;
  12. import com.etotem.cfc.mapper.UserMapper;
  13. import org.slf4j.Logger;
  14. import org.slf4j.LoggerFactory;
  15. import org.springframework.stereotype.Service;
  16. import org.springframework.transaction.annotation.Transactional;
  17. import javax.annotation.Resource;
  18. import java.util.Calendar;
  19. import java.util.Date;
  20. import java.util.List;
  21. /**
  22. * 方案激活服务。
  23. * 将已审核通过的方案转为实际任务实例,进入执行阶段。
  24. */
  25. @Service
  26. public class PlanActivationService {
  27. private static final Logger log = LoggerFactory.getLogger(PlanActivationService.class);
  28. @Resource
  29. private TaskPlanInstanceMapper planMapper;
  30. @Resource
  31. private TaskMapper taskMapper;
  32. @Resource
  33. private UserMapper userMapper;
  34. @Resource
  35. private FamilyMemberMapper familyMemberMapper;
  36. @Resource
  37. private TaskTemplateItemMapper templateItemMapper;
  38. /**
  39. * 激活方案:
  40. * 1. 校验状态必须为 reviewed
  41. * 2. 生成一条引导性任务(方案概览/首日任务)
  42. * 3. 若方案关联了模板包(packageId),按模板项批量生成日常任务(任务分解)
  43. * 4. 标记方案为 active
  44. */
  45. @Transactional
  46. public void activate(Long planId, Long operatorId) {
  47. TaskPlanInstance plan = planMapper.selectById(planId);
  48. if (plan == null) throw new IllegalStateException("方案不存在");
  49. if (!"reviewed".equals(plan.getStatus())) {
  50. throw new IllegalStateException("方案状态异常,需要先审核通过");
  51. }
  52. // childId 兼容 user 或 family_members 两种 ID 域,任一存在即可激活
  53. boolean childExists = userMapper.selectById(plan.getChildId()) != null
  54. || familyMemberMapper.selectById(plan.getChildId()) != null;
  55. if (!childExists) throw new IllegalStateException("孩子不存在");
  56. // 生成首日引导任务
  57. Task guideTask = new Task();
  58. guideTask.setFamilyId(plan.getFamilyId());
  59. guideTask.setChildId(plan.getChildId());
  60. guideTask.setCreatorId(operatorId);
  61. guideTask.setExecutorType("child");
  62. guideTask.setExecutorId(plan.getChildId());
  63. guideTask.setTitle("方案启动: " + plan.getName());
  64. guideTask.setDescription("请阅读并开始执行测评方案");
  65. guideTask.setPoints(2);
  66. guideTask.setCategory("成长");
  67. guideTask.setStatus("pending");
  68. guideTask.setSourceType("plan");
  69. guideTask.setSourceId(plan.getId());
  70. guideTask.setNeedReview(0);
  71. guideTask.setIsTemplate(0);
  72. guideTask.setMemberOnly(1); // B20: 方案/套餐生成的任务为会员专属
  73. fillDeadline(guideTask);
  74. guideTask.setCreatedAt(new Date());
  75. guideTask.setUpdatedAt(new Date());
  76. taskMapper.insert(guideTask);
  77. // 按模板包任务项批量生成日常任务(任务分解)
  78. if (plan.getPackageId() != null) {
  79. List<TaskTemplateItem> items = templateItemMapper.selectList(
  80. new LambdaQueryWrapper<TaskTemplateItem>()
  81. .eq(TaskTemplateItem::getPackageId, plan.getPackageId())
  82. .orderByAsc(TaskTemplateItem::getSortOrder));
  83. int itemCount = 0;
  84. for (TaskTemplateItem item : items) {
  85. if (item.getTaskName() == null || item.getTaskName().isEmpty()) continue;
  86. Task t = new Task();
  87. t.setFamilyId(plan.getFamilyId());
  88. t.setChildId(plan.getChildId());
  89. t.setCreatorId(operatorId);
  90. t.setExecutorType("child");
  91. t.setExecutorId(plan.getChildId());
  92. t.setTitle(item.getTaskName());
  93. t.setDescription(item.getDescription());
  94. t.setPoints(item.getPoints() != null ? item.getPoints() : 2);
  95. t.setCategory("成长");
  96. t.setStatus("pending");
  97. t.setSourceType("plan");
  98. t.setSourceId(plan.getId());
  99. t.setNeedReview(0);
  100. t.setIsTemplate(0);
  101. t.setMemberOnly(1);
  102. t.setFrequency(item.getFrequency() != null ? item.getFrequency() : "daily");
  103. t.setDuration(item.getDuration());
  104. fillDeadline(t);
  105. t.setCreatedAt(new Date());
  106. t.setUpdatedAt(new Date());
  107. taskMapper.insert(t);
  108. itemCount++;
  109. }
  110. log.info("方案{}激活按模板包{}生成{}条任务", planId, plan.getPackageId(), itemCount);
  111. }
  112. // 标记方案已激活
  113. plan.setStatus("active");
  114. plan.setActivatedAt(new Date());
  115. plan.setTotalDays(plan.getTotalDays() != null ? plan.getTotalDays() : 14);
  116. plan.setCompletedDays(0);
  117. plan.setUpdatedAt(new Date());
  118. planMapper.updateById(plan);
  119. log.info("方案激活 planId={}, childId={}, taskId={}", planId, plan.getChildId(), guideTask.getId());
  120. }
  121. private void fillDeadline(Task task) {
  122. Calendar cal = Calendar.getInstance();
  123. cal.set(Calendar.HOUR_OF_DAY, 23);
  124. cal.set(Calendar.MINUTE, 59);
  125. cal.set(Calendar.SECOND, 59);
  126. task.setDeadline(cal.getTime());
  127. }
  128. }