|
|
@@ -2,10 +2,14 @@ package com.yimeng.okr.schedule;
|
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.yimeng.okr.entity.AssessmentPeriod;
|
|
|
+import com.yimeng.okr.entity.KrKeyResult;
|
|
|
+import com.yimeng.okr.entity.OkrObjective;
|
|
|
import com.yimeng.okr.entity.SysUser;
|
|
|
import com.yimeng.okr.enums.PeriodStatus;
|
|
|
import com.yimeng.okr.event.NotificationEvent;
|
|
|
import com.yimeng.okr.mapper.AssessmentPeriodMapper;
|
|
|
+import com.yimeng.okr.mapper.KrKeyResultMapper;
|
|
|
+import com.yimeng.okr.mapper.OkrObjectiveMapper;
|
|
|
import com.yimeng.okr.mapper.SysUserMapper;
|
|
|
import com.yimeng.okr.service.AssessmentPeriodService;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
@@ -15,7 +19,6 @@ import org.springframework.scheduling.annotation.Scheduled;
|
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
|
import java.time.LocalDate;
|
|
|
-import java.time.LocalDateTime;
|
|
|
import java.time.temporal.ChronoUnit;
|
|
|
import java.util.List;
|
|
|
|
|
|
@@ -27,6 +30,8 @@ public class PeriodScheduler {
|
|
|
private final AssessmentPeriodService periodService;
|
|
|
private final AssessmentPeriodMapper periodMapper;
|
|
|
private final SysUserMapper userMapper;
|
|
|
+ private final OkrObjectiveMapper objectiveMapper;
|
|
|
+ private final KrKeyResultMapper krMapper;
|
|
|
private final ApplicationEventPublisher publisher;
|
|
|
|
|
|
@Scheduled(cron = "0 0 2 * * ?")
|
|
|
@@ -58,4 +63,48 @@ public class PeriodScheduler {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ @Scheduled(cron = "0 7 10 * * ?")
|
|
|
+ public void checkKrLagging() {
|
|
|
+ log.info("Checking KR lagging...");
|
|
|
+ List<AssessmentPeriod> periods = periodMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<AssessmentPeriod>()
|
|
|
+ .eq(AssessmentPeriod::getStatus, PeriodStatus.EXECUTING));
|
|
|
+ LocalDate today = LocalDate.now();
|
|
|
+ for (AssessmentPeriod p : periods) {
|
|
|
+ try {
|
|
|
+ long totalDays = ChronoUnit.DAYS.between(p.getStartDate(), p.getEndDate());
|
|
|
+ if (totalDays <= 0) continue;
|
|
|
+ long elapsedDays = ChronoUnit.DAYS.between(p.getStartDate(), today);
|
|
|
+ if (elapsedDays < 3) continue; // ignore first 3 days
|
|
|
+ double elapsedRatio = Math.min(1.0, (double) elapsedDays / totalDays);
|
|
|
+ double expectedProgress = elapsedRatio * 100;
|
|
|
+
|
|
|
+ List<OkrObjective> objectives = objectiveMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<OkrObjective>()
|
|
|
+ .eq(OkrObjective::getPeriodId, p.getId())
|
|
|
+ .eq(OkrObjective::getStatus, "APPROVED"));
|
|
|
+ for (OkrObjective obj : objectives) {
|
|
|
+ List<KrKeyResult> krs = krMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<KrKeyResult>()
|
|
|
+ .eq(KrKeyResult::getObjectiveId, obj.getId()));
|
|
|
+ for (KrKeyResult kr : krs) {
|
|
|
+ if ("COMPLETED".equals(kr.getStatus())) continue;
|
|
|
+ double actualProgress = kr.getTargetValue() > 0
|
|
|
+ ? (kr.getCurrentValue() / kr.getTargetValue()) * 100 : 0;
|
|
|
+ if (actualProgress < expectedProgress - 20) {
|
|
|
+ publisher.publishEvent(new NotificationEvent(
|
|
|
+ this, obj.getUserId(), "KR_LAGGING",
|
|
|
+ "KR 进度滞后",
|
|
|
+ "「" + kr.getTitle() + "」进度落后于时间线(当前 "
|
|
|
+ + Math.round(actualProgress) + "%,预期 " + Math.round(expectedProgress) + "%),请及时更新",
|
|
|
+ "objective", obj.getId()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("Failed to check KR lagging for period {}: {}", p.getId(), e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|