package com.punchsettle.server.service.manager.impl; import java.time.LocalDate; import java.time.LocalTime; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import com.punchsettle.server.atomic.entity.PiStatus; import com.punchsettle.server.constant.ContinueStageEnum; import com.punchsettle.server.utiis.DateUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import com.punchsettle.server.atomic.entity.PiMultiTask; import com.punchsettle.server.atomic.entity.PiTask; import com.punchsettle.server.atomic.entity.PiTaskHistory; import com.punchsettle.server.common.constant.CommonEnableStatusEnum; import com.punchsettle.server.common.exception.BusinessException; import com.punchsettle.server.common.utils.Assert; import com.punchsettle.server.constant.CompareRuleEnum; import com.punchsettle.server.constant.PunchInMethodEnum; import com.punchsettle.server.constant.PunchInResultEnum; import com.punchsettle.server.constant.RepeatCategoryEnum; import com.punchsettle.server.service.manager.ICalendarManager; import com.punchsettle.server.service.manager.IPunchInManager; import lombok.extern.slf4j.Slf4j; /** * @author tyuio * @version 1.0.0 * @date 2025/4/15 14:10 * @description 打卡服务类 */ @Slf4j @Component public class PunchInManagerImpl implements IPunchInManager { @Autowired private ICalendarManager calendarManager; @Override public boolean judgeRepeat(PiTask piTask, String repeatDateStr) { // 每天 if (RepeatCategoryEnum.EVERYDAY.equals(piTask.getRepeatCategory())) { return true; } // 法定工作日 if (RepeatCategoryEnum.WORKDAY.equals(piTask.getRepeatCategory())) { return !calendarManager.judgeHoliday(repeatDateStr); } // 法定节假日(含周末) if (RepeatCategoryEnum.HOLIDAY.equals(piTask.getRepeatCategory())) { return !calendarManager.judgeHoliday(repeatDateStr); } // 自定义 if (RepeatCategoryEnum.CUSTOM.equals(piTask.getRepeatCategory())) { if (!StringUtils.hasText(piTask.getRepeatCustomDay())) { BusinessException.throwFail(String.format("打卡任务ID:%s, 重复周期类型:自定义重复,没有设定自定义重复日期")); } LocalDate repeatDate = LocalDate.parse(repeatDateStr); int dayOfWeekValue = repeatDate.getDayOfWeek().getValue(); return piTask.getRepeatCustomDay().contains(String.valueOf(dayOfWeekValue)); } return false; } @Override public PunchInResultEnum judgePunchInResultInTask(PiTask piTask, PiTaskHistory piTaskHistory) { Assert.isNullInBusiness(piTask, "打卡任务不能为空 "); // 没有打卡记录,直接没完成 if (Objects.isNull(piTaskHistory)) { return PunchInResultEnum.UNDONE; } // 单次打卡,不区分是否节假日 if (PunchInMethodEnum.SINGLE.equals(piTask.getPunchInMethod())) { int countTrack = Optional.ofNullable(piTask.getCountTrack()).orElse(0); return countTrack > 0 ? PunchInResultEnum.DONE : PunchInResultEnum.UNDONE; } // 打卡任务的节假日启用配置 CommonEnableStatusEnum holidayStatus = Optional.ofNullable(piTask.getHolidayStatus()).orElse(CommonEnableStatusEnum.DISABLED); boolean enableHolidayFlag = CommonEnableStatusEnum.ENABLED.equals(holidayStatus) && calendarManager.judgeHoliday(piTaskHistory.getPunchInDate()); // 计数打卡,要区分是否节假日使用不同的判断标准 if (PunchInMethodEnum.COUNT.equals(piTask.getPunchInMethod())) { int countTrack = enableHolidayFlag ? piTask.getHolidayCountTrack() : piTask.getCountTrack(); int punchInCountTrack = Optional.ofNullable(piTaskHistory.getCountTrack()).orElse(0); if (CompareRuleEnum.GTE.equals(piTask.getCompareRule()) && punchInCountTrack >= countTrack) { return PunchInResultEnum.DONE; } if (CompareRuleEnum.LTE.equals(piTask.getCompareRule()) && punchInCountTrack <= countTrack) { return PunchInResultEnum.DONE; } return PunchInResultEnum.UNDONE; } // 计时打卡,要区分是否节假日使用不同的判断标准 if (PunchInMethodEnum.TIMING.equals(piTask.getPunchInMethod())) { LocalTime timeTrack = enableHolidayFlag ? piTask.getHolidayTimeTrack() : piTask.getTimeTrack(); LocalTime punchInTimeTrack = Optional.ofNullable(piTaskHistory.getTimeTrack()).orElse(LocalTime.parse("00:00:00.000")); if (CompareRuleEnum.GTE.equals(piTask.getCompareRule()) && punchInTimeTrack.compareTo(timeTrack) > -1) { return PunchInResultEnum.DONE; } if (CompareRuleEnum.LTE.equals(piTask.getCompareRule()) && punchInTimeTrack.compareTo(timeTrack) < 1) { return PunchInResultEnum.DONE; } return PunchInResultEnum.UNDONE; } return PunchInResultEnum.UNDONE; } @Override public PunchInResultEnum judgePunchInResultInMultiTask(PiMultiTask piMultiTask, List piTaskHistoryList) { if (CollectionUtils.isEmpty(piTaskHistoryList)) { return PunchInResultEnum.UNDONE; } // 完成的打卡数量 long punchInDoneCount = piTaskHistoryList.stream().filter(v -> PunchInResultEnum.DONE.equals(v.getPunchInResult())).count(); // 当天打卡次数大于等于设置的次数,则完成打卡 // 没有设置时默认设置一个较大的数,避免出现打卡次数为0的情况 Integer doneCount = Optional.ofNullable(piMultiTask.getPunchInDoneCount()).orElse(piTaskHistoryList.size() + 1); return punchInDoneCount >= doneCount ? PunchInResultEnum.DONE : PunchInResultEnum.UNDONE; } @Override public int getPunchInTotalCountInWeek(PiTask piTask, String specifiedDateStr) { Assert.isNullInBusiness(piTask, "打卡任务不能为空 "); Assert.isNull(specifiedDateStr, "指定日期不能为空 "); if (RepeatCategoryEnum.EVERYDAY.equals(piTask.getRepeatCategory())) { return 7; } if (RepeatCategoryEnum.CUSTOM.equals(piTask.getRepeatCategory())) { return piTask.getRepeatCustomDay().split(",").length; } // 指定日期 LocalDate specifiedDate = LocalDate.parse(specifiedDateStr); if (RepeatCategoryEnum.WORKDAY.equals(piTask.getRepeatCategory())) { List dateRange = DateUtils.getDateRangeInWeek(specifiedDate); return (int) dateRange.stream().map(v -> DateUtils.YYYY_MM_DD_FORMATTER.format(v)) .filter(v -> calendarManager.judgeWorkday(v)).count(); } if (RepeatCategoryEnum.HOLIDAY.equals(piTask.getRepeatCategory())) { List dateRange = DateUtils.getDateRangeInWeek(specifiedDate); return (int) dateRange.stream().map(v -> DateUtils.YYYY_MM_DD_FORMATTER.format(v)) .filter(v -> calendarManager.judgeHoliday(v)).count(); } return 0; } @Override public int getPunchInTotalCountInMonth(PiTask piTask, String specifiedDateStr) { Assert.isNullInBusiness(piTask, "打卡任务不能为空 "); Assert.isNull(specifiedDateStr, "指定日期不能为空 "); // 指定日期 LocalDate specifiedDate = LocalDate.parse(specifiedDateStr); if (RepeatCategoryEnum.EVERYDAY.equals(piTask.getRepeatCategory())) { return specifiedDate.lengthOfMonth(); } // 日期列表 List dateRange = DateUtils.getDateRangeInMonth(specifiedDate); if (RepeatCategoryEnum.CUSTOM.equals(piTask.getRepeatCategory())) { String[] split = piTask.getRepeatCustomDay().split(","); Set customDays = Arrays.stream(split).map(v -> Integer.valueOf(v)).collect(Collectors.toSet()); return (int) dateRange.stream().map(v -> v.getDayOfWeek().getValue()).filter(customDays::contains).count(); } if (RepeatCategoryEnum.WORKDAY.equals(piTask.getRepeatCategory())) { return (int) dateRange.stream().map(v -> DateUtils.YYYY_MM_DD_FORMATTER.format(v)) .filter(v -> calendarManager.judgeWorkday(v)).count(); } if (RepeatCategoryEnum.HOLIDAY.equals(piTask.getRepeatCategory())) { return (int) dateRange.stream().map(v -> DateUtils.YYYY_MM_DD_FORMATTER.format(v)) .filter(v -> calendarManager.judgeHoliday(v)).count(); } return 0; } @Override public ContinueStageEnum judgeContinueStageInTask(PiTask piTask, PiTaskHistory piTaskHistory, PiStatus piStatus, LocalDate punchInDate) { if (CommonEnableStatusEnum.DISABLED.equals(piTask.getContinueStatus())) { return ContinueStageEnum.NONE; } // TODO 启用/关闭连续打卡规则时要对状态表进行数据初始化 // 宽限期 if (ContinueStageEnum.GRACE_STAGE.equals(piStatus.getContinueStage())) { LocalDate graceDay = piStatus.getStageStartDate().plusDays(piTask.getGraceDay()); // 仍处于宽限期限内 if (punchInDate.compareTo(graceDay) <= 0) { return ContinueStageEnum.GRACE_STAGE; } // 已超过宽限期限,但是未完成打卡 if (PunchInResultEnum.UNDONE.equals(piTaskHistory.getPunchInResult())) { return ContinueStageEnum.GRACE_STAGE; } // 已超过宽限期限,且已完成打卡,进入正常打卡期 return ContinueStageEnum.NORMAL_STAGE; } // 正常打卡期 if (ContinueStageEnum.NORMAL_STAGE.equals(piStatus.getContinueStage())) { // 完成打卡则继续是正常打卡期,否则是惩罚期 if (PunchInResultEnum.DONE.equals(piTaskHistory.getPunchInResult())) { return ContinueStageEnum.NORMAL_STAGE; } // 连续中断次数大于等于设置的中断次数,重新进入宽限期 if (piStatus.getContinueInterruptedCount() + 1 > piTask.getContinueInterruptedCount()) { return ContinueStageEnum.GRACE_STAGE; } return ContinueStageEnum.PENALTY_STAGE; } // 惩罚期 if (ContinueStageEnum.PENALTY_STAGE.equals(piStatus.getContinueStage())) { // 仍处于惩罚期 if (punchInDate.compareTo(piStatus.getStageEndDate()) <= 0) { return ContinueStageEnum.GRACE_STAGE; } return ContinueStageEnum.NORMAL_STAGE; } return ContinueStageEnum.NONE; } }