Ver Fonte

【feat】【v3】
1.正在开发打卡逻辑

ChenYL há 11 meses atrás
pai
commit
726b426ff9

+ 1 - 0
doc/sql/update-v3.sql

@@ -475,6 +475,7 @@ ADD COLUMN `repeat_category` varchar(10) DEFAULT NULL COMMENT '重复周期类
 ADD COLUMN `repeat_custom_day` varchar(13) DEFAULT NULL COMMENT '自定义重复日(周一-1,周二-2,周三-3,周四-4,周五-5,周六-6,周日-7)',
 ADD COLUMN `extra_method` varchar(10) DEFAULT NULL COMMENT '额外奖励方式(无-NONE,固定-FIXED,区间-INTERVAL)',
 ADD COLUMN `extra_time_step` int DEFAULT NULL COMMENT '额外的时间间隔(单位:分钟)',
+ADD COLUMN `extra_points` int DEFAULT NULL COMMENT '奖励的积分(额外)',
 ADD COLUMN `grace_status` varchar(10) DEFAULT NULL COMMENT '是否启用宽限期(ENABLED-启用,DISABLED-关闭)',
 ADD COLUMN `grace_day` int DEFAULT NULL COMMENT '宽限期(单位:天)',
 ADD COLUMN `interrupted_day` int DEFAULT NULL COMMENT '打卡中断天数(单位:天)',

+ 3 - 3
src/main/java/com/punchsettle/server/atomic/entity/PunchInMultiTask.java

@@ -8,7 +8,7 @@ import com.punchsettle.server.common.pojo.BaseEntity;
 
 import com.punchsettle.server.constant.ArchiveStatusEnum;
 import com.punchsettle.server.common.constant.CommonEnableStatusEnum;
-import com.punchsettle.server.constant.ExtraMethodEnum;
+import com.punchsettle.server.constant.PunchInExtraMethodEnum;
 import com.punchsettle.server.constant.PunchInMethodMultiEnum;
 import jakarta.persistence.Column;
 import jakarta.persistence.Table;
@@ -106,10 +106,10 @@ public class PunchInMultiTask extends BaseEntity implements Serializable {
 
     /**
      * 额外奖励方式(无-NONE,固定-FIXED,区间-INTERVAL)
-     * @see ExtraMethodEnum
+     * @see PunchInExtraMethodEnum
      */
     @Column(name = "extra_method")
-    private ExtraMethodEnum extraMethod;
+    private PunchInExtraMethodEnum extraMethod;
 
     /**
      * 奖励的积分(额外)

+ 9 - 1
src/main/java/com/punchsettle/server/atomic/entity/PunchInTask.java

@@ -9,6 +9,7 @@ import com.punchsettle.server.common.pojo.BaseEntity;
 import com.punchsettle.server.constant.ArchiveStatusEnum;
 import com.punchsettle.server.common.constant.CommonEnableStatusEnum;
 import com.punchsettle.server.constant.CompareRuleEnum;
+import com.punchsettle.server.constant.PunchInExtraMethodEnum;
 import com.punchsettle.server.constant.FullAttendancePeriodEnum;
 import com.punchsettle.server.constant.PunchInMethodEnum;
 import com.punchsettle.server.constant.RepeatCategoryEnum;
@@ -173,9 +174,10 @@ public class PunchInTask extends BaseEntity implements Serializable {
 
     /**
      * 额外奖励方式(无-NONE,固定-FIXED,区间-INTERVAL)
+     * @see PunchInExtraMethodEnum
      */
     @Column(name = "extra_method")
-    private String extraMethod;
+    private PunchInExtraMethodEnum extraMethod;
 
     /**
      * 额外的时间间隔(单位:分钟)
@@ -183,6 +185,12 @@ public class PunchInTask extends BaseEntity implements Serializable {
     @Column(name = "extra_time_step")
     private Integer extraTimeStep;
 
+    /**
+     * 奖励的积分(额外)
+     */
+    @Column(name = "extra_points")
+    private Integer extraPoints;
+
     /**
      * 是否启用宽限期(ENABLED-启用,DISABLED-关闭)
      * @see CommonEnableStatusEnum

+ 0 - 10
src/main/java/com/punchsettle/server/constant/ExtraMethodEnum.java

@@ -1,10 +0,0 @@
-package com.punchsettle.server.constant;
-
-/**
- * @author tyuio
- * @version 1.0.0
- * @date 2025/4/9 12:45
- * @description TODO
- */
-public enum ExtraMethodEnum {
-}

+ 24 - 0
src/main/java/com/punchsettle/server/constant/PunchInExtraMethodEnum.java

@@ -0,0 +1,24 @@
+package com.punchsettle.server.constant;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @date 2025/4/9 12:45
+ * @description 打卡额外奖励方式(无-NONE,固定-FIXED,区间-INTERVAL)
+ */
+@Getter
+@AllArgsConstructor
+public enum PunchInExtraMethodEnum {
+
+    NONE("无"),
+    FIXED("固定"),
+    INTERVAL("区间");
+
+    /**
+     * 名称
+     */
+    private String name;
+}

+ 2 - 2
src/main/java/com/punchsettle/server/service/manager/ICalendarManager.java

@@ -24,8 +24,8 @@ public interface ICalendarManager {
 
     /**
      * 判断指定日期是否节假日
-     * @param dateStr
+     * @param gregorianDate 日期格式:yyyy-MM-dd
      * @return
      */
-    boolean judgeHoliday(String dateStr);
+    boolean judgeHoliday(String gregorianDate);
 }

+ 2 - 2
src/main/java/com/punchsettle/server/service/manager/IPunchInManager.java

@@ -105,9 +105,9 @@ public interface IPunchInManager {
     /**
      * 计算积分
      * @param punchInTask 打卡任务
-     * @param punchInTaskExt 打卡任务拓展信息
+     * @param punchInTaskExtList 打卡任务拓展信息列表
      * @param punchInTaskHistory 打卡记录
      * @return
      */
-    int calculatePointsInTask(PunchInTask punchInTask, PunchInTaskExt punchInTaskExt, PunchInTaskHistory punchInTaskHistory);
+    int calculatePointsInTask(PunchInTask punchInTask, List<PunchInTaskExt> punchInTaskExtList, PunchInTaskHistory punchInTaskHistory);
 }

+ 94 - 18
src/main/java/com/punchsettle/server/service/manager/impl/PunchInManagerImpl.java

@@ -18,8 +18,11 @@ import java.util.stream.Collectors;
 
 import com.punchsettle.server.atomic.entity.PunchInMultiTask;
 import com.punchsettle.server.atomic.entity.PunchInTaskExt;
+import com.punchsettle.server.constant.FullAttendancePeriodEnum;
+import com.punchsettle.server.constant.PunchInExtraMethodEnum;
 import com.punchsettle.server.constant.PunchInMethodMultiEnum;
 import com.punchsettle.server.constant.RepeatCategoryEnum;
+import com.punchsettle.server.service.manager.ICalendarManager;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -441,13 +444,12 @@ public class PunchInManagerImpl implements IPunchInManager {
     }
 
     /**
-     * 判断是否是节假日
-     * @param date
-     * @return true:是节假日,false:不是节假日
+     * 默认打卡完成率
      */
-    private boolean judgeHoliday(String date) {
-        return false;
-    }
+    private static final BigDecimal DEFAULT_PUNCH_IN_DONE_RATE = new BigDecimal("101.00");
+
+    @Autowired
+    private ICalendarManager calendarManager;
 
     @Override
     public boolean judgeRepeat(PunchInTask punchInTask, String repeatDateStr) {
@@ -458,12 +460,12 @@ public class PunchInManagerImpl implements IPunchInManager {
 
         // 法定工作日
         if (RepeatCategoryEnum.WORKDAY.equals(punchInTask.getRepeatCategory())) {
-            return !judgeHoliday(repeatDateStr);
+            return !calendarManager.judgeHoliday(repeatDateStr);
         }
 
         // 法定节假日(含周末)
         if (RepeatCategoryEnum.HOLIDAY.equals(punchInTask.getRepeatCategory())) {
-            return !judgeHoliday(repeatDateStr);
+            return !calendarManager.judgeHoliday(repeatDateStr);
         }
 
         // 自定义
@@ -528,11 +530,6 @@ public class PunchInManagerImpl implements IPunchInManager {
         return PunchInStatusEnum.UNDONE;
     }
 
-    /**
-     * 默认打卡完成率
-     */
-    private static final BigDecimal DEFAULT_PUNCH_IN_DONE_RATE = new BigDecimal("101.00");
-
     @Override
     public PunchInStatusEnum judgePunchInStatusInMultiTask(PunchInMultiTask punchInMultiTask, List<PunchInTaskHistory> punchInTaskHistoryList, int multiTaskNum) {
         if (CollectionUtils.isEmpty(punchInTaskHistoryList) || multiTaskNum == 0) {
@@ -561,27 +558,106 @@ public class PunchInManagerImpl implements IPunchInManager {
         return PunchInStatusEnum.UNDONE;
     }
 
+    // TODO 考虑把结算过程记录下来(每个一个积分项、是否双倍结算、是否全勤结算
     @Override
-    public int calculatePointsInTask(PunchInTask punchInTask, PunchInTaskExt punchInTaskExt, PunchInTaskHistory punchInTaskHistory) {
+    public int calculatePointsInTask(PunchInTask punchInTask, List<PunchInTaskExt> punchInTaskExtList, PunchInTaskHistory punchInTaskHistory) {
         // 未完成打卡,积分为0
         if (PunchInStatusEnum.UNDONE.equals(punchInTaskHistory.getPunchInStatus())) {
             return 0;
         }
 
         // 单个任务积分=基本积分+(可选)额外积分+(可选)连续完成额外积分+法定节假日(含周末)双倍奖励+全勤双倍奖励
-        int points = Optional.ofNullable(punchInTask.getPoints()).orElse(0);
+        // 基本积分
+        int basicPoints = Optional.ofNullable(punchInTask.getPoints()).orElse(0);
+        basicPoints += calculateExtraPointsInTask(punchInTask, punchInTaskExtList, punchInTaskHistory, calendarManager.judgeHoliday(punchInTaskHistory.getPunchInDate()));
 
         // 启用了全勤奖励
+        int fullAttendancePoints = 0;
         if (CommonEnableStatusEnum.ENABLED.equals(punchInTask.getFullAttendanceStatus())) {
+            LocalDate punchInDate = LocalDate.parse(punchInTaskHistory.getPunchInDate());
+            // 结算周期:周,并且结算日是周末,则双倍奖励
+            if (FullAttendancePeriodEnum.WEEK.equals(punchInTask.getFullAttendancePeriod()) && punchInDate.getDayOfWeek().getValue() == 7) {
+                fullAttendancePoints = basicPoints;
+            }
 
+            // 结算周期:月,结算日是当月最后一天,则双倍奖励
+            if (FullAttendancePeriodEnum.MONTH.equals(punchInTask.getFullAttendancePeriod()) && punchInDate.lengthOfMonth() == punchInDate.getDayOfMonth()) {
+                fullAttendancePoints = basicPoints;
+            }
+
+            // TODO 无法判断容错率,要加一个专门的统计表才行,每周、每月的统计
         }
 
         // 启用了法定节假日(含周末)双倍奖励
-        if (CommonEnableStatusEnum.ENABLED.equals(punchInTask.getHolidayStatus()) && judgeHoliday(punchInTaskHistory.getPunchInDate())) {
-            points *= 2;
+        int holidayPoints = 0;
+        if (CommonEnableStatusEnum.ENABLED.equals(punchInTask.getHolidayStatus()) && calendarManager.judgeHoliday(punchInTaskHistory.getPunchInDate())) {
+            holidayPoints = basicPoints;
+        }
+
+        return basicPoints + fullAttendancePoints + holidayPoints;
+    }
+
+    /**
+     * 计算额外积分
+     * @param punchInTask
+     * @param punchInTaskExtList
+     * @return
+     */
+    private int calculateExtraPointsInTask(PunchInTask punchInTask, List<PunchInTaskExt> punchInTaskExtList, PunchInTaskHistory punchInTaskHistory, boolean holidayFlag) {
+        // 单次打卡或者没有启用额外积分计算则跳过
+        if (PunchInExtraMethodEnum.NONE.equals(punchInTask.getExtraMethod())
+            || PunchInMethodEnum.SINGLE.equals(punchInTask.getPunchInMethod())) {
+            return 0;
+        }
+
+        // 计算超出部分,
+        int extraCountTrack = 0;
+        // 计数打卡
+        if (PunchInMethodEnum.COUNT.equals(punchInTask.getPunchInMethod())) {
+            extraCountTrack = punchInTaskHistory.getCountTrack() - (holidayFlag ? punchInTask.getHolidayCountTrack() : punchInTask.getCountTrack());
+        }
+        // 计时打卡
+        if (PunchInMethodEnum.TIMING.equals(punchInTask.getPunchInMethod())) {
+            // 超出的时间按照时间间隔转换成次数
+            long timeTrack = punchInTaskHistory.getTimeTrack().until((holidayFlag ? punchInTask.getHolidayTimeTrack() : punchInTask.getTimeTrack()), ChronoUnit.MINUTES);
+            extraCountTrack = BigDecimal.valueOf(timeTrack).divide(BigDecimal.valueOf(punchInTask.getExtraTimeStep()), 0, RoundingMode.FLOOR).intValue();
+        }
+
+        // 如果等于0则没有超出部分,不用计算
+        if (extraCountTrack == 0) {
+            return 0;
+        }
+
+        // 固定计算
+        if (PunchInExtraMethodEnum.FIXED.equals(punchInTask.getExtraMethod())) {
+            Integer extraPoints = Optional.ofNullable(punchInTask.getExtraPoints()).orElse(0);
+            return extraCountTrack * extraPoints;
+        }
+
+        // 区间计算
+        if (PunchInExtraMethodEnum.INTERVAL.equals(punchInTask.getExtraMethod()) && !CollectionUtils.isEmpty(punchInTaskExtList)) {
+            int basicPoints = 0;
+            int prevInitialValue = 0;
+            for (PunchInTaskExt punchInTaskExt : punchInTaskExtList) {
+                Integer initialValue = Optional.ofNullable(punchInTaskExt.getInitialValue()).orElse(0);
+                // 第一轮:initialValue - extraCountTrack的值v1
+                // 如果v1≤0则超出initialValue范围,使用initialValue计算;
+                // 如果v1>0则在initialValue范围内 使用extraCountTrack
+                // 后续轮:本轮initialValue - extraCountTrack的值v1、
+                // 如果v1≤0则超出本轮initialValue范围,使用上一轮initialValue-本轮initialValue的值v2计算;
+                // 如果v1>0则在本轮initialValue范围内 使用extraCountTrack-上一轮initialValue的值v3计算
+                // 下面的代码不适合第一轮的计算
+                if (initialValue - extraCountTrack <= 0) {
+                    basicPoints = punchInTaskExt.getExtraPoints() * Math.abs(prevInitialValue - initialValue);
+                } else {
+                    basicPoints = punchInTaskExt.getExtraPoints() * (extraCountTrack - prevInitialValue);
+                }
+                prevInitialValue = initialValue;
+            }
+            return basicPoints;
         }
 
-        return points;
+        return 0;
     }
 
     // TODO 多任务结算