Bladeren bron

【feat】【v3】
1.增加定时任务

ChenYL 10 maanden geleden
bovenliggende
commit
ac7b957883

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

@@ -749,3 +749,8 @@ DROP TABLE IF EXISTS settlement_notify_task;
 DROP TABLE IF EXISTS settlement_task;
 DROP TABLE IF EXISTS user_claim_reward_record;
 
+ALTER TABLE punch_settle.`user` ADD user_category varchar(10) DEFAULT 'NORMAL' NOT NULL COMMENT '用户类型(普通-NORMAL,管理员-ADMIN)';
+ALTER TABLE punch_settle.`user` CHANGE user_category user_category varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT 'NORMAL' NOT NULL COMMENT '用户类型(普通-NORMAL,管理员-ADMIN)' AFTER open_id;
+
+
+

+ 17 - 16
doc/技术文档.md

@@ -574,22 +574,23 @@ ui设计工具:即时设计
 
 表名:user
 
-| 字段                 | 类型          | 描述                               |
-| -------------------- | ------------- | ---------------------------------- |
-| id                   | bigint        | 主键                               |
-| open_id              | varchar(128)  | 微信小程序openId                   |
-| nickname             | varchar(100)  | 昵称                               |
-| total_points         | int           | 总积分                             |
-| unused_points        | int           | 未使用积分                         |
-| used_points          | int           | 已使用积分                         |
-| total_consume_amount | decimal(10,2) | 总消费金额(元)                     |
-| total_win_amount     | decimal(10,2) | 总中奖金额(元)                     |
-| created_by           | bigint        | 创建人                             |
-| creation_time        | timestamp     | 创建时间                           |
-| last_updated_by      | bigint        | 最后更新人                         |
-| last_update_time     | timestamp     | 最后更新时间                       |
-| version              | bigint        | 版本号                             |
-| delete_flag          | tinyint       | 逻辑删除标志(0-未删除,1-已删除) |
+| 字段                 | 类型          | 描述                                  |
+| -------------------- | ------------- | ------------------------------------- |
+| id                   | bigint        | 主键                                  |
+| open_id              | varchar(128)  | 微信小程序openId                      |
+| user_category        | varchar(10)   | 用户类型(普通-NORMAL,管理员-ADMIN) |
+| nickname             | varchar(100)  | 昵称                                  |
+| total_points         | int           | 总积分                                |
+| unused_points        | int           | 未使用积分                            |
+| used_points          | int           | 已使用积分                            |
+| total_consume_amount | decimal(10,2) | 总消费金额(元)                        |
+| total_win_amount     | decimal(10,2) | 总中奖金额(元)                        |
+| created_by           | bigint        | 创建人                                |
+| creation_time        | timestamp     | 创建时间                              |
+| last_updated_by      | bigint        | 最后更新人                            |
+| last_update_time     | timestamp     | 最后更新时间                          |
+| version              | bigint        | 版本号                                |
+| delete_flag          | tinyint       | 逻辑删除标志(0-未删除,1-已删除)    |
 
 
 

+ 7 - 0
src/main/java/com/punchsettle/server/atomic/entity/User.java

@@ -6,6 +6,7 @@ import java.math.BigDecimal;
 
 import com.punchsettle.server.common.pojo.BaseEntity;
 
+import com.punchsettle.server.constant.UserCategoryEnum;
 import jakarta.persistence.Column;
 import jakarta.persistence.Table;
 import lombok.Data;
@@ -31,6 +32,12 @@ public class User extends BaseEntity implements Serializable {
     @Column(name = "open_id")
     private String openId;
 
+    /**
+     * 用户类型(普通-NORMAL,管理员-ADMIN)
+     */
+    @Column(name = "user_category")
+    private UserCategoryEnum userCategory;
+
     /**
      * 微信昵称
      */

+ 3 - 0
src/main/java/com/punchsettle/server/atomic/service/impl/PiTaskServiceImpl.java

@@ -50,6 +50,9 @@ public class PiTaskServiceImpl implements IPiTaskService {
         if (!CollectionUtils.isEmpty(piTaskQuery.getIds())) {
             criteria.andIn(PiTask::getId, piTaskQuery.getIds());
         }
+        if (Objects.nonNull(piTaskQuery.getEndDateLt())) {
+            criteria.andLessThan(PiTask::getEndDate, piTaskQuery.getEndDateLt());
+        }
 
         weekend.excludeProperties(BaseEntity::getLastUpdatedBy,
                 BaseEntity::getLastUpdateTime,

+ 3 - 0
src/main/java/com/punchsettle/server/atomic/service/impl/RewardServiceImpl.java

@@ -40,6 +40,9 @@ public class RewardServiceImpl implements IRewardService {
         if (Objects.nonNull(query.getUserId())) {
             criteria.andEqualTo(Reward::getUserId, query.getUserId());
         }
+        if (Objects.nonNull(query.getAutoStatus())) {
+            criteria.andEqualTo(Reward::getAutoStatus, query.getAutoStatus());
+        }
         return rewardMapper.selectByExample(weekend);
     }
 

+ 23 - 0
src/main/java/com/punchsettle/server/constant/UserCategoryEnum.java

@@ -0,0 +1,23 @@
+package com.punchsettle.server.constant;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @date 2025/5/7 15:38
+ * @description 用户类型枚举(普通-NORMAL,管理员-ADMIN)
+ */
+@Getter
+@AllArgsConstructor
+public enum UserCategoryEnum {
+
+    NORMAL("普通"),
+    ADMIN("管理员");
+
+    /**
+     * 名称
+     */
+    private String name;
+}

+ 14 - 0
src/main/java/com/punchsettle/server/pojo/punchIn/PiTaskQuery.java

@@ -1,9 +1,12 @@
 package com.punchsettle.server.pojo.punchIn;
 
+import java.time.LocalDate;
 import java.util.Collection;
 
+import com.punchsettle.server.common.constant.CommonEnableStatusEnum;
 import com.punchsettle.server.constant.ArchiveStatusEnum;
 import com.punchsettle.server.constant.VersionStatusEnum;
+
 import lombok.Data;
 
 /**
@@ -36,4 +39,15 @@ public class PiTaskQuery {
      * @see ArchiveStatusEnum
      */
     private ArchiveStatusEnum archiveStatus;
+
+    /**
+     * 结束日期(小于)
+     */
+    private LocalDate endDateLt;
+
+    /**
+     * 是否启用自动打卡(ENABLED-启用,DISABLED-关闭)
+     * @see CommonEnableStatusEnum
+     */
+    private CommonEnableStatusEnum autoStatus;
 }

+ 7 - 0
src/main/java/com/punchsettle/server/pojo/reward/RewardQuery.java

@@ -2,6 +2,7 @@ package com.punchsettle.server.pojo.reward;
 
 import java.util.Collection;
 
+import com.punchsettle.server.common.constant.CommonEnableStatusEnum;
 import com.punchsettle.server.constant.VersionStatusEnum;
 
 import lombok.Data;
@@ -30,4 +31,10 @@ public class RewardQuery {
      * 奖励ID列表
      */
     private Collection<Long> rewardIds;
+
+    /**
+     * 是否启用自动兑换
+     * @see CommonEnableStatusEnum
+     */
+    private CommonEnableStatusEnum autoStatus;
 }

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

@@ -57,6 +57,11 @@ public interface IPunchInManager {
      */
     void doPunchIn(PunchInRequest request);
 
+    /**
+     * 自动打卡
+     */
+    void autoPunchIn(PiTask piTask, String punchInDate);
+
     /**
      * 归档打卡任务
      * @param punchInId

+ 48 - 0
src/main/java/com/punchsettle/server/service/manager/impl/PunchInManagerImpl.java

@@ -477,6 +477,54 @@ public class PunchInManagerImpl implements IPunchInManager {
         cacheManager.getCache(CacheNameConstant.TASK_STAT).evict(String.format("%s_%s", currentUserId, punchInDate.substring(0, 4)));
     }
 
+    @Override
+    public void autoPunchIn(PiTask piTask, String punchInDate) {
+        // 当前用户ID
+        Long currentUserId = piTask.getCreatedBy();
+        // 是否节假日
+        boolean holidayFlag = calendarManager.judgeHoliday(punchInDate);
+
+        // 查询今天的打卡记录
+        PiTaskHistory oldPiTaskHistory = piTaskHistoryService.getByTaskUniqueIdAndPunchInDate(piTask.getUniqueId(), punchInDate);
+
+        // 新增的打卡记录
+        PiTaskHistory tempPiTaskHistory = new PiTaskHistory();
+        tempPiTaskHistory.setTaskId(piTask.getId());
+        tempPiTaskHistory.setTaskUniqueId(piTask.getUniqueId());
+        tempPiTaskHistory.setPunchInDate(punchInDate);
+        tempPiTaskHistory.setUserId(currentUserId);
+
+        // 打卡类型:单次打卡,
+        if (PunchInMethodEnum.SINGLE.equals(piTask.getPunchInMethod())) {
+            // 默认打卡次数是1,是计数打卡的特例
+            tempPiTaskHistory.setCountTrack(1);
+        }
+
+        // 打卡类型:计数,需要累加打卡次数
+        if (PunchInMethodEnum.COUNT.equals(piTask.getPunchInMethod())) {
+            tempPiTaskHistory.setCountTrack(holidayFlag ? piTask.getHolidayCountTrack() : piTask.getCountTrack());
+        }
+
+        // 打卡类型:计时,需要记录最新打卡时长
+        if (PunchInMethodEnum.TIMING.equals(piTask.getPunchInMethod())) {
+            tempPiTaskHistory.setTimeTrack(holidayFlag ? piTask.getHolidayTimeTrack() : piTask.getTimeTrack());
+        }
+
+        // 设置打卡结果
+        PunchInResultEnum punchInResult = punchInCoreManager.judgePunchInResultInTask(piTask, tempPiTaskHistory);
+        tempPiTaskHistory.setPunchInResult(punchInResult);
+
+        // 新增或更新
+        piTaskHistoryService.insert(tempPiTaskHistory);
+
+        // 清楚缓存
+        cacheManager.getCache(CacheNameConstant.TASK_LIST_VO).evict(currentUserId);
+        cacheManager.getCache(CacheNameConstant.TASK_PUNCH_IN_HISTORY).evict(String.format("%s_%s", currentUserId, punchInDate));
+        cacheManager.getCache(CacheNameConstant.TASK_HISTORY_LIST_FOR_USER).evict(String.format("%s_%s", currentUserId, punchInDate));
+        cacheManager.getCache(CacheNameConstant.TASK_STAT).evict(String.format("%s_%s", currentUserId, punchInDate.substring(0, 7)));
+        cacheManager.getCache(CacheNameConstant.TASK_STAT).evict(String.format("%s_%s", currentUserId, punchInDate.substring(0, 4)));
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void archiveTask(Long id) {

+ 11 - 0
src/main/java/com/punchsettle/server/service/manager/impl/StatManagerImpl.java

@@ -12,6 +12,9 @@ import java.util.Optional;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
+import com.punchsettle.server.atomic.entity.User;
+import com.punchsettle.server.constant.UserCategoryEnum;
+import com.punchsettle.server.service.manager.IUserManager;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Component;
@@ -85,6 +88,9 @@ public class StatManagerImpl implements IStatManager {
     @Autowired
     private IPiTaskService piTaskService;
 
+    @Autowired
+    private IUserManager userManager;
+
     @Override
     @Cacheable(cacheNames = CacheNameConstant.STAT_POINTS_LINE, key = "T(com.punchsettle.server.utiis.UserUtils).getCurrentUserId()")
     public LineVO queryStatPointsLine() {
@@ -141,6 +147,11 @@ public class StatManagerImpl implements IStatManager {
     @Override
     @Cacheable(cacheNames = CacheNameConstant.STAT_NEW_USER_LINE)
     public LineVO queryStatNewUserLine() {
+        User user = userManager.getByIdWithCache(UserUtils.getCurrentUserId());
+        if (UserCategoryEnum.NORMAL.equals(user.getUserCategory())) {
+            return null;
+        }
+
         LocalDate endDate = LocalDate.now();
         LocalDate startDate = endDate.minusDays(bizProperties.getLineItemCount());
 

+ 2 - 0
src/main/java/com/punchsettle/server/service/manager/impl/UserManagerImpl.java

@@ -2,6 +2,7 @@ package com.punchsettle.server.service.manager.impl;
 
 import java.util.Objects;
 
+import com.punchsettle.server.constant.UserCategoryEnum;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.CacheManager;
@@ -58,6 +59,7 @@ public class UserManagerImpl implements IUserManager {
             user = new User();
             user.setOpenId(wxMaJscode2SessionResult.getOpenid());
             user.setNickname(request.getNickname());
+            user.setUserCategory(UserCategoryEnum.NORMAL);
             userService.insert(user);
         } else {
             User updateUser = new User();

+ 57 - 0
src/main/java/com/punchsettle/server/task/PiTaskAutoArchiveTask.java

@@ -0,0 +1,57 @@
+package com.punchsettle.server.task;
+
+import com.punchsettle.server.atomic.entity.PiTask;
+import com.punchsettle.server.atomic.service.IPiTaskService;
+import com.punchsettle.server.constant.ArchiveStatusEnum;
+import com.punchsettle.server.constant.VersionStatusEnum;
+import com.punchsettle.server.pojo.punchIn.PiTaskQuery;
+import com.punchsettle.server.service.manager.IPunchInManager;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @date 2025/5/7 15:00
+ * @description 打卡任务自动归档 定时任务
+ */
+@Slf4j
+@Component
+public class PiTaskAutoArchiveTask {
+
+    @Autowired
+    private IPiTaskService piTaskService;
+
+    @Autowired
+    private IPunchInManager punchInManager;
+
+    public void execute() {
+        log.info("========== 打卡任务自动归档定时任务 开始执行 ==========");
+
+        PiTaskQuery piTaskQuery = new PiTaskQuery();
+        piTaskQuery.setTaskStatus(VersionStatusEnum.ACTIVE);
+        piTaskQuery.setArchiveStatus(ArchiveStatusEnum.ACTIVE);
+        piTaskQuery.setEndDateLt(LocalDate.now());
+        List<PiTask> piTasks = piTaskService.queryByCondition(piTaskQuery);
+
+        if (CollectionUtils.isEmpty(piTasks)) {
+            log.info("========== 打卡任务自动归档任务,没有需要自动归档的任务 结束执行 ==========");
+            return;
+        }
+
+        for (PiTask piTask : piTasks) {
+            try {
+                punchInManager.archiveTask(piTask.getId());
+            } catch (Exception e) {
+                log.error("自动归档发生异常", e);
+            }
+        }
+
+        log.info("========== 打卡任务自动归档任务 结束执行 ==========");
+    }
+}

+ 62 - 0
src/main/java/com/punchsettle/server/task/PiTaskAutoPunchInTask.java

@@ -0,0 +1,62 @@
+package com.punchsettle.server.task;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import com.punchsettle.server.atomic.entity.PiTask;
+import com.punchsettle.server.atomic.service.IPiTaskService;
+import com.punchsettle.server.common.constant.CommonEnableStatusEnum;
+import com.punchsettle.server.constant.ArchiveStatusEnum;
+import com.punchsettle.server.constant.VersionStatusEnum;
+import com.punchsettle.server.pojo.punchIn.PiTaskQuery;
+import com.punchsettle.server.service.manager.IPunchInManager;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @date 2025/5/7 15:15
+ * @description 打卡任务自动打卡定时任务
+ */
+@Slf4j
+@Component
+public class PiTaskAutoPunchInTask {
+
+    @Autowired
+    private IPiTaskService piTaskService;
+
+    @Autowired
+    private IPunchInManager punchInManager;
+
+    public void execute() {
+        log.info("========== 打卡任务自动打卡定时任务 开始执行 ==========");
+
+        PiTaskQuery piTaskQuery = new PiTaskQuery();
+        piTaskQuery.setTaskStatus(VersionStatusEnum.ACTIVE);
+        piTaskQuery.setArchiveStatus(ArchiveStatusEnum.ACTIVE);
+        piTaskQuery.setAutoStatus(CommonEnableStatusEnum.ENABLED);
+        List<PiTask> piTasks = piTaskService.queryByCondition(piTaskQuery);
+
+        if (CollectionUtils.isEmpty(piTasks)) {
+            log.info("========== 打卡任务自动打卡定时任务,没有需要自动打卡的任务 结束执行 ==========");
+            return;
+        }
+
+        LocalDate punchInDate = LocalDate.now();
+
+        for (PiTask piTask : piTasks) {
+            try {
+                punchInManager.autoPunchIn(piTask, punchInDate.toString());
+            } catch (Exception e) {
+                log.error("自动打卡发生异常", e);
+            }
+        }
+
+        log.info("========== 打卡任务自动打卡定时任务 结束执行 ==========");
+    }
+}

+ 81 - 0
src/main/java/com/punchsettle/server/task/RewardAutoExchangeTask.java

@@ -0,0 +1,81 @@
+package com.punchsettle.server.task;
+
+import com.punchsettle.server.atomic.entity.Account;
+import com.punchsettle.server.atomic.entity.Reward;
+import com.punchsettle.server.atomic.service.IAccountService;
+import com.punchsettle.server.atomic.service.IRewardService;
+import com.punchsettle.server.common.constant.CommonEnableStatusEnum;
+import com.punchsettle.server.constant.AccountCategoryEnum;
+import com.punchsettle.server.constant.VersionStatusEnum;
+import com.punchsettle.server.pojo.account.AccountQuery;
+import com.punchsettle.server.pojo.reward.RewardExchangeRequest;
+import com.punchsettle.server.pojo.reward.RewardQuery;
+import com.punchsettle.server.service.manager.IRewardManager;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @date 2025/5/7 14:45
+ * @description 奖励自动兑换 定时任务
+ */
+@Slf4j
+@Component
+public class RewardAutoExchangeTask {
+
+    @Autowired
+    private IRewardManager rewardManager;
+
+    @Autowired
+    private IRewardService rewardService;
+
+    @Autowired
+    private IAccountService accountService;
+
+    public void execute() {
+        log.info("========== 奖励自动兑换定时任务 开始执行 ==========");
+
+        RewardQuery rewardQuery = new RewardQuery();
+        rewardQuery.setRewardStatus(VersionStatusEnum.ACTIVE);
+        rewardQuery.setAutoStatus(CommonEnableStatusEnum.ENABLED);
+        List<Reward> rewards = rewardService.queryByCondition(rewardQuery);
+
+        if (CollectionUtils.isEmpty(rewards)) {
+            log.info("========== 奖励自动兑换定时任务,没有需要自动兑换的奖励 结束执行 ==========");
+            return;
+        }
+
+        // 获取账户信息
+        Set<Long> userIds = rewards.stream().map(Reward::getUserId).collect(Collectors.toSet());
+        AccountQuery accountQuery = new AccountQuery();
+        accountQuery.setUserIds(userIds);
+        accountQuery.setAccountCategory(AccountCategoryEnum.BASIC);
+        List<Account> accounts = accountService.getAccountByCondition(accountQuery);
+        Map<Long, Account> accountMap = accounts.stream().collect(Collectors.toMap(Account::getUserId, Function.identity(), (key1, key2) -> key1));
+
+        for (Reward reward : rewards) {
+            try {
+                Account account = accountMap.get(reward.getUserId());
+
+                RewardExchangeRequest rewardExchangeRequest = new RewardExchangeRequest();
+                rewardExchangeRequest.setRewardId(reward.getId());
+                rewardExchangeRequest.setAccountId(account.getId());
+                rewardExchangeRequest.setExchangeCount(reward.getAutoExchangeCount());
+                rewardManager.exchangeReward(rewardExchangeRequest);
+            } catch (Exception e) {
+                log.info("自动兑换异常");
+            }
+        }
+
+        log.info("========== 奖励自动兑换定时任务 结束执行 ==========");
+    }
+}