Преглед на файлове

增加请求次数限制,防止请求氚云接口卡顿,拆分数据同步的定时任务。修改半年时间区间为90天。修改检验氚云每日工时时删除氚云日志的操作失效导致脏数据的问题。增加http接口指定天数校验工时。增加定时器线程池配置。修改上传工时日志时间。

Cyangbin преди 3 години
родител
ревизия
95d0c4b173

+ 2 - 0
.gitignore

@@ -33,3 +33,5 @@ build/
 ### log info ###
 log/**
 /logs/**.**
+
+/src/test/**

+ 33 - 0
src/main/java/com/galaxis/manatee/configuration/ScheduleConfig.java

@@ -0,0 +1,33 @@
+package com.galaxis.manatee.configuration;
+
+import com.galaxis.manatee.util.ThreadUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.SchedulingConfigurer;
+import org.springframework.scheduling.config.ScheduledTaskRegistrar;
+
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+
+@Configuration
+public class ScheduleConfig implements SchedulingConfigurer {
+    private static final Logger log = LoggerFactory.getLogger(ScheduleConfig.class);
+
+    @Value("${schedule.pool.core:32}")
+    public int corePoolSize;
+
+    @Override
+    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
+        log.info("任务调度线程池的核心线程数: {}", corePoolSize);
+        ThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(
+                corePoolSize
+                , new ThreadUtil.PrefixThreadFactory("schedule-service-")
+                , new ThreadPoolExecutor.DiscardOldestPolicy());
+        // 设置线程池处理
+        taskRegistrar.setScheduler(executor);
+    }
+}

+ 33 - 1
src/main/java/com/galaxis/manatee/controller/TestController.java

@@ -1,16 +1,36 @@
 package com.galaxis.manatee.controller;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.galaxis.manatee.constant.ChuanYunConstant;
+import com.galaxis.manatee.dao.ChuanyunMemberCostDao;
+import com.galaxis.manatee.dao.ChuanyunSelfWorkHourDao;
 import com.galaxis.manatee.dao.ChuanyunUserCompanyDao;
-import com.galaxis.manatee.entity.chuanyun.data.object.ChuanyunUserCompanyDO;
+import com.galaxis.manatee.entity.chuanyun.data.object.*;
+import com.galaxis.manatee.entity.chuanyun.dto.*;
+import com.galaxis.manatee.manager.ChuanYunManager;
 import com.galaxis.manatee.service.*;
 import com.galaxis.manatee.task.ChuanyunBasicDataScheduledTask;
+import com.galaxis.manatee.util.TimeUtil;
 import lombok.extern.slf4j.Slf4j;
+import net.sf.json.util.JSONUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
@@ -204,6 +224,18 @@ public class TestController {
     /**
      * 手动更新项目组成员
      */
+    @GetMapping("/test/api/manual/updateSaleProjectMember")
+    public void updateSaleProjectMember() {
+        try {
+            projectMemberService.updateSaleMember("bfc36277-b201-4a80-b61c-e632bc664d82");
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 手动更新项目组成员
+     */
     @GetMapping("/test/api/manual/getGroupProjectForSynchronizationManually")
     public void getGroupProjectForSynchronizationManually() {
 

+ 48 - 8
src/main/java/com/galaxis/manatee/controller/WorkHourController.java

@@ -1,30 +1,42 @@
 package com.galaxis.manatee.controller;
 
+import com.galaxis.manatee.dao.ChuanyunUserCompanyDao;
+import com.galaxis.manatee.entity.chuanyun.data.object.ChuanyunUserCompanyDO;
 import com.galaxis.manatee.service.LogCheckService;
 import com.galaxis.manatee.service.LogService;
 import com.galaxis.manatee.service.LogStandardService;
 import com.galaxis.manatee.service.LogUpdateService;
 import com.galaxis.manatee.task.WorkHourStatistics;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
+import java.util.stream.Collectors;
+
 /**
  * 日志工时controller
+ *
  * @author zcj
  * @version 0.1
  * @date 2021/3/4 3:56 上午
  */
+@Slf4j
 @RestController
 public class WorkHourController {
 
+    @Autowired
+    private ChuanyunUserCompanyDao userCompanyDao;
+
     private final LogCheckService logCheckService;
     private final LogStandardService logStandardService;
     private final LogUpdateService logUpdateService;
     private final WorkHourStatistics workHourStatistics;
     private final LogService logService;
 
-    public WorkHourController(LogCheckService logCheckService, WorkHourStatistics workHourStatistics,LogStandardService logStandardService,LogUpdateService logUpdateService,LogService logService) {
+    public WorkHourController(LogCheckService logCheckService, WorkHourStatistics workHourStatistics, LogStandardService logStandardService, LogUpdateService logUpdateService, LogService logService) {
         this.logCheckService = logCheckService;
         this.workHourStatistics = workHourStatistics;
         this.logStandardService = logStandardService;
@@ -34,10 +46,11 @@ public class WorkHourController {
 
     /**
      * 检查工时不一致数据
-     * @param userId    用户Id
+     *
+     * @param userId 用户Id
      */
     @GetMapping("/test/workHour/checkSelfWorkHour")
-    public void checkSelfWorkHour(@RequestParam("userId") String userId){
+    public void checkSelfWorkHour(@RequestParam("userId") String userId) {
         try {
             logCheckService.checkDayWorkHour(userId);
         } catch (Exception e) {
@@ -49,7 +62,7 @@ public class WorkHourController {
      * 标准化全部工时信息
      */
     @GetMapping("/test/workHour/standardDayWorkHourApi")
-    public void standardDayWorkHourApi(){
+    public void standardDayWorkHourApi() {
         workHourStatistics.standardDayWorkHour();
     }
 
@@ -57,25 +70,52 @@ public class WorkHourController {
      * 上传日工时至氚云数据库
      */
     @GetMapping("/test/workHour/pullDayWorkHourApi")
-    public void pullDayWorkHourApi(){
-        workHourStatistics.pullDayWorkHour();
+    public void pullDayWorkHourApi() {
+        workHourStatistics.pushDayWorkHour();
     }
 
     /**
      * 标准化半年内工时信息
      */
     @GetMapping("/test/workHour/standardHalfYearDayWorkHourApi")
-    public void standardHalfYearDayWorkHourApi(){
+    public void standardHalfYearDayWorkHourApi() {
         logStandardService.standardHalfYearWorkHour();
     }
 
     /**
+     * 标准化半年内工时信息
+     */
+    @GetMapping("/test/workHour/standardHalfYearDayWorkHourApiByUserId")
+    public void standardHalfYearDayWorkHourApiByUserId(@RequestParam("userId") String userId) {
+        logStandardService.standardHalfYearWorkHourByUserId(userId);
+    }
+
+    /**
      * 上传半年内日工时至氚云数据库
      */
     @GetMapping("/test/workHour/pullHalfYearDayWorkHourApi")
-    public void pullHalfYearDayWorkHourApi(){
+    public void pullHalfYearDayWorkHourApi() {
         logService.updateHalfYearChuanyunSelfWorkHour();
     }
 
+    /**
+     * 检验一个季度的工时日志
+     */
+    @GetMapping("/test/workHour/checkQuarterDayWorkHour")
+    public void checkQuarterDayWorkHour() {
+        List<String> userIdList = userCompanyDao.findAll().stream().map(ChuanyunUserCompanyDO::getUserId).collect(Collectors.toList());
+        logCheckService.checkDayWorkHourTimeAfter(userIdList, 90);
+    }
 
+    /**
+     * 校验指定日期氚云数据库的工时记录是否存在+8时区的数据
+     *
+     * @param year   年
+     * @param month  月
+     * @param maxDay 当月最后一天
+     */
+    @GetMapping("/test/api/checkAllMemberHour")
+    public void checkMemberHour(Integer year, Integer month, Integer maxDay) {
+        logCheckService.checkChuanYunAll(year, month, maxDay);
+    }
 }

+ 1 - 1
src/main/java/com/galaxis/manatee/dao/ChuanyunWorkHourDao.java

@@ -162,7 +162,7 @@ public interface ChuanyunWorkHourDao extends GalaxisRepository<ChuanyunWorkHourD
             "LEFT JOIN chuanyun_log ON chuanyun_day_log.parent_object_id = chuanyun_log.object_id " +
             " WHERE chuanyun_log.user_id = ? " +
             "and DATEDIFF(chuanyun_day_log.day_log_date,NOW()) <= 0 " +
-            "and DATEDIFF(chuanyun_day_log.day_log_date,NOW()) > -180 " +
+            "and DATEDIFF(chuanyun_day_log.day_log_date,NOW()) > -90 " +
             "GROUP BY chuanyun_day_log.project_id," +
             "chuanyun_log.user_id," +
             "chuanyun_day_log.project_type," +

+ 80 - 9
src/main/java/com/galaxis/manatee/service/LogCheckService.java

@@ -10,15 +10,16 @@ import com.galaxis.manatee.dao.ChuanyunWeekMemberHourDao;
 import com.galaxis.manatee.dao.ChuanyunWorkHourDao;
 import com.galaxis.manatee.entity.chuanyun.data.object.*;
 import com.galaxis.manatee.entity.chuanyun.dto.ChuanyunFindAllBizDTO;
+import com.galaxis.manatee.entity.chuanyun.dto.ChuanyunFindAllBizReturnData;
 import com.galaxis.manatee.entity.chuanyun.dto.ChuanyunSaveDTO;
 import com.galaxis.manatee.entity.chuanyun.dto.Filter;
 import com.galaxis.manatee.manager.ChuanYunManager;
+import com.galaxis.manatee.util.TimeUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
 
-import java.time.DayOfWeek;
 import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -205,15 +206,21 @@ public class LogCheckService {
                             matchers.add("F0000001_2," + chuanyunSelfWorkHourDO.getProjectId());
                         }
                         matchers.add("F0000002_2," + chuanyunSelfWorkHourDO.getUserId());
-                        matchers.add("F0000003_2," + chuanyunSelfWorkHourDO.getDayLogDate());
+                        matchers.add("F0000003_2," + TimeUtil.formatDateTime(chuanyunSelfWorkHourDO.getDayLogDate()));
 
-                        var filter = Filter.instance(0, 1, true, "And", matchers);
+                        var filter = Filter.instance(-1, 100, true, "And", matchers);
                         var chuanyunFindAllResponse = chuanYunManager.findAll(ChuanyunMemberHourDO.SCHEMA_CODE, filter);
-                        ChuanyunSaveDTO chuanyunSaveDTO;
+                        // 修改bug 删除氚云数据库不生效问题
+                        // 1.日期未按照氚云要求格式化。
+                        // 2.查询条件未从-1开始查,且只查了1条。
+                        // 3.转换json时对象的objectId为null,无法删除氚云数据库。父类中属性需要在转换时指定转换的结果类型
                         if (chuanyunFindAllResponse.getReturnData() != null) {
-                            List<ChuanyunMemberHourDO> result = objectMapper.convertValue(chuanyunFindAllResponse.getReturnData().getBizObjectArray(), new TypeReference<>() {
+                            List<Object> responses = chuanyunFindAllResponse.getReturnData().getBizObjectArray();
+                            ObjectMapper objectMapper = new ObjectMapper();
+                            responses.forEach(o -> {
+                                ChuanyunMemberHourDO chuanyunMemberHourDO = objectMapper.convertValue(o, ChuanyunMemberHourDO.class);
+                                chuanYunManager.delete(ChuanyunMemberHourDO.SCHEMA_CODE, chuanyunMemberHourDO.getObjectId());
                             });
-                            chuanyunSaveDTO = chuanYunManager.delete(ChuanyunMemberHourDO.SCHEMA_CODE, result.get(0).getObjectId());
                         }
                         log.info(chuanyunSelfWorkHourDO.getUserId() + "删除" + chuanyunSelfWorkHourDO.getDayLogDate() + "位于" + chuanyunSelfWorkHourDO.getProjectId() + "工时");
                     } catch (Exception e) {
@@ -226,12 +233,17 @@ public class LogCheckService {
         }
     }
 
+    /**
+     * 校验指定时间后的日工时记录
+     *
+     * @param allUserIdList 用户id集合
+     * @param afterDay      多少天后
+     */
     @Async
-    public void checkHalfYearDayWorkHour(List<String> allUserIdList) {
+    public void checkDayWorkHourTimeAfter(List<String> allUserIdList, Integer afterDay) {
         allUserIdList.parallelStream().forEach(userId -> {
-            // 获取半年期的工时
             List<ChuanyunWorkHourDO> halfYearSelfWorkHour = chuanyunWorkHourDao.getHalfYearSelfWorkHour(userId);
-            LocalDateTime localDateTime = LocalDateTime.now().minusDays(180);
+            LocalDateTime localDateTime = LocalDateTime.now().minusDays(afterDay);
             List<ChuanyunSelfWorkHourDO> chuanyunSelfWorkHourList = chuanyunSelfWorkHourDao.findByUserIdAndDayLogDateAfter(userId, localDateTime);
             compareDayWorkHour(halfYearSelfWorkHour, chuanyunSelfWorkHourList);
         });
@@ -292,4 +304,63 @@ public class LogCheckService {
         allUserIdList.parallelStream().forEach(userId -> {
         });
     }
+
+    /**
+     * 按照年月日检验是否存在时区问题的数据
+     *
+     * @param year   年
+     * @param month  月
+     * @param maxDay 当月最后一天
+     */
+    public void checkChuanYunAll(Integer year, Integer month, Integer maxDay) {
+        for (int i = 1; i <= maxDay; i++) {
+            List<String> matchers = new ArrayList<>();
+            LocalDateTime of = LocalDateTime.of(year, month, i, 8, 0, 0);
+            String dateTime = TimeUtil.formatDateTime(of);
+            log.info("dateTime: {}", dateTime);
+            matchers.add("F0000003_2," + dateTime);
+            boolean flag = true;
+            int start = -1;
+            int pageSize = 100;
+            while (flag) {
+                Filter filter = Filter.instance(start, start + pageSize, true, Filter.AND, matchers);
+                ChuanyunFindAllBizDTO<Object> all = null;
+                try {
+                    all = chuanYunManager.findAll(ChuanyunMemberHourDO.SCHEMA_CODE, filter);
+                } catch (JsonProcessingException e) {
+                    e.printStackTrace();
+                }
+                if (all.getReturnData() == null) {
+                    flag = false;
+                    continue;
+                }
+                if (all.getReturnData().getTotalCount() >= start + pageSize) {
+                    start += pageSize;
+                } else {
+                    flag = false;
+                }
+                ChuanyunFindAllBizReturnData<Object> returnData = all.getReturnData();
+
+                if (returnData != null) {
+                    List<Object> bizObjectArray = returnData.getBizObjectArray();
+                    ObjectMapper objectMapper = new ObjectMapper();
+                    for (Object o : bizObjectArray) {
+                        ChuanyunMemberHourDO chuanyunMemberHourDO = objectMapper.convertValue(o, ChuanyunMemberHourDO.class);
+
+                        ChuanyunSaveDTO delete = null;
+                        try {
+                            delete = chuanYunManager.delete(ChuanyunMemberHourDO.SCHEMA_CODE, chuanyunMemberHourDO.getObjectId());
+                        } catch (Exception e) {
+                            log.error("删除异常 e: {}", e.getMessage());
+                        }
+                        if (!delete.getSuccessful()) {
+                            log.info("删除失败");
+                        }
+                        log.info("userId: {}, objectId: {}, time: {}", chuanyunMemberHourDO.getUserId(), chuanyunMemberHourDO.getObjectId(), chuanyunMemberHourDO.getDayLogDate());
+                    }
+                }
+            }
+
+        }
+    }
 }

+ 2 - 0
src/main/java/com/galaxis/manatee/service/LogDownloadService.java

@@ -129,6 +129,8 @@ public class LogDownloadService {
             log.warn("异常数据");
         }else{
             //如果有重复就删除
+            // todo 保存判断是否无变更,无变更返回0则修改该条数据为没变化的数据。
+
             chuanyunLogDao.findById(chuanyunLogDO.getObjectId()).ifPresent(chuanyunLogDao::delete);
             //根据projectId获取code,如果是生产项目,则不用处理
             //针对前期测试数据,可能出现日志为空的情况,跳过不处理

+ 1 - 1
src/main/java/com/galaxis/manatee/service/LogService.java

@@ -57,7 +57,7 @@ public class LogService {
      */
     public void updateHalfYearChuanyunSelfWorkHour() {
         long startTime = Instant.now().getEpochSecond();
-        chuanyunUserCompanyDao.findAll().parallelStream().forEach(chuanyunUserCompanyDO -> logUpdateService.pullHalfYearDayWorkHour(chuanyunUserCompanyDO.getUserId()));
+        chuanyunUserCompanyDao.findAll().parallelStream().forEach(chuanyunUserCompanyDO -> logUpdateService.pushHalfYearDayWorkHour(chuanyunUserCompanyDO.getUserId()));
         log.info("更新所有每日工时花费" + (Instant.now().getEpochSecond() - startTime) + "秒");
     }
 

+ 4 - 0
src/main/java/com/galaxis/manatee/service/LogStandardService.java

@@ -328,6 +328,10 @@ public class LogStandardService {
         chuanyunUserCompanyDao.findAll().forEach(chuanyunUserCompanyDO -> this.standardHalfYearDayWorkHour(chuanyunUserCompanyDO.getUserId()));
     }
 
+    public void standardHalfYearWorkHourByUserId(String userId) {
+        this.standardHalfYearDayWorkHour(userId);
+    }
+
     /**
      * 标准化半年内日志
      *

+ 2 - 2
src/main/java/com/galaxis/manatee/service/LogUpdateService.java

@@ -77,9 +77,9 @@ public class LogUpdateService {
     /**
      * 更新至氚云半内内的数据
      */
-    public void pullHalfYearDayWorkHour(String userId) {
+    public void pushHalfYearDayWorkHour(String userId) {
         log.info("更新用户 userId: {} 日工时日志至氚云", userId);
-        LocalDateTime halfYearDateTime = LocalDateTime.now().minusDays(180);
+        LocalDateTime halfYearDateTime = LocalDateTime.now().minusDays(90);
         List<ChuanyunSelfWorkHourDO> halfYearUpdateList = chuanyunSelfWorkHourDao.findByUserIdAndDayLogDateAfter(userId, halfYearDateTime);
         this.updateChuanyunSelfWorkHourList(halfYearUpdateList);
     }

+ 131 - 10
src/main/java/com/galaxis/manatee/task/ChuanyunBasicDataScheduledTask.java

@@ -119,46 +119,159 @@ public class ChuanyunBasicDataScheduledTask {
         projectMemberListCheck(chuanyunGroupProjectDO);
     }
 
-    ;
-
 
     /**
      * 定时将氚云中的数据保存到manatee
      */
     @Scheduled(fixedDelay = 3600000L)
-    private void getDataFromChuanyun() {
+    private void scheduledUserCompany() {
         //获取人员-归属公司信息
         getUserCompany();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    // fixme 暂时屏蔽
+//    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledGroupProject() {
         //获取集团项目数据
         getGroupProject();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledSubProject() {
         //获取子项目数据
         getSubProject();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledUserList() {
         //获取用户数据
         getUserList();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledProjectType() {
         //支出档案类型
         getProjectType();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledAttachmentId() {
         //项目备件明细
         getAttachmentId();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledReimbursementSubject() {
         //获取报销科目
         getReimbursementSubject();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledCost() {
         //获取成本中心
         getCost();
+    }
+
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledCompany() {
         //获取公司信息
         getCompany();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledSupplier() {
         //获取供应商
         getSupplier();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledReimbursementItems() {
         //人员报销特殊项目
         getReimbursementItems();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledCostCollection() {
         //人工成本特殊项目
         getCostCollection();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledSpecialProcedure() {
+
         //专项费用分摊
         getSpecialProcedure();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledAskForLeave() {
         //钉钉请假
         saveAskForLeave();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledOutDepartment() {
         //更新受益部门名称
         getOutDepartment();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledBusinessEntertainment() {
         //更新业务招待申请
         updateBusinessEntertainment();
+    }
+
+    /**
+     * 定时将氚云中的数据保存到manatee
+     */
+    @Scheduled(fixedDelay = 3600000L)
+    private void scheduledProjectChange() {
         //项目实施变更
         saveProjectChange();
     }
@@ -298,20 +411,23 @@ public class ChuanyunBasicDataScheduledTask {
             }
             //保证项目成员信息更新成功
             boolean updateFlag = false;
+            int count = 0;
             while (!updateFlag) {
                 try {
-                    // 重新将项目组成员设置进去。
-                    groupProjectMemberListUpdateDTO.setProjectMemberList(chuanyunGroupProjectDO.getProjectMemberList());
-                    groupProjectMemberListUpdateDTO.add();
-                    var groupProjectMemberListUpdateString = objectMapper.writeValueAsString(groupProjectMemberListUpdateDTO);
+                    count++;
+                    if (count == 20){
+                        updateFlag = true;
+                    }
+                    // 再次将项目组成员设置进去。
+                    GroupProjectMemberListUpdateDTO againGroupProjectMemberListUpdateDTO = new GroupProjectMemberListUpdateDTO(chuanyunGroupProjectDO);
+                    var groupProjectMemberListUpdateString = objectMapper.writeValueAsString(againGroupProjectMemberListUpdateDTO);
                     ChuanyunSaveDTO chuanyunSaveDTO = chuanYunManager.update(ChuanyunGroupProjectDO.SCHEMA_CODE, chuanyunGroupProjectDO.getObjectId(), groupProjectMemberListUpdateString);
                     if (chuanyunSaveDTO.getSuccessful()) {
 //                        log.info("更新项目成员成功"+groupProjectMemberListUpdateString);
                         updateFlag = true;
                     } else {
-                        log.warn(chuanyunGroupProjectDO.getObjectId() + "更新项目成员失败" + groupProjectMemberListUpdateString);
-                        log.warn(chuanyunGroupProjectDO + "");
-                        Thread.sleep(5000L);
+                        log.warn(chuanyunGroupProjectDO.getObjectId() + "更新项目成员失败" + againGroupProjectMemberListUpdateDTO);
+                        log.warn("{}", chuanyunGroupProjectDO);
                     }
                 } catch (Exception e) {
                     e.printStackTrace();
@@ -401,8 +517,13 @@ public class ChuanyunBasicDataScheduledTask {
         groupProjectUpdateDTO = new GroupProjectUpdateDTO(chuanyunGroupProjectDO);
         //保证项目经理信息更新成功
         boolean updateFlag = false;
+        int count = 0;
         while (!updateFlag) {
             try {
+                count++;
+                if (count == 20){
+                    updateFlag = true;
+                }
                 var groupProjectUpdateString = objectMapper.writeValueAsString(groupProjectUpdateDTO);
                 ChuanyunSaveDTO chuanyunSaveDTO = chuanYunManager.update(ChuanyunGroupProjectDO.SCHEMA_CODE, chuanyunGroupProjectDO.getObjectId(), groupProjectUpdateString);
                 if (chuanyunSaveDTO.getSuccessful()) {

+ 4 - 5
src/main/java/com/galaxis/manatee/task/WorkHourStatistics.java

@@ -39,21 +39,20 @@ public class WorkHourStatistics {
     }
 
     /**
-     * 每天19点执行一次所有工时数据的标准化、上传操作。
+     * 每天19点执行一次三个月工时数据的标准化操作。
      */
     @Scheduled(cron = "0 0 19 * * ?")
     public void standardDayWorkHour(){
         //每日工时标准化
         log.info("开始每日工时标准化");
-//        standardWorkHour();
         logStandardService.standardHalfYearWorkHour();
     }
 
     /**
-     * 每天6点执行一次所有工时数据的标准化、上传操作。
+     * 每天凌晨2点执行一次三个月内工时数据的上传操作。
      */
-    @Scheduled(cron = "0 0 6 * * ?")
-    public void pullDayWorkHour(){
+    @Scheduled(cron = "0 0 2 * * ?")
+    public void pushDayWorkHour(){
         //每日工时标准化
         log.info("开始每日工时上传");
         logService.updateHalfYearChuanyunSelfWorkHour();

+ 84 - 0
src/main/java/com/galaxis/manatee/util/ThreadUtil.java

@@ -0,0 +1,84 @@
+package com.galaxis.manatee.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ThreadUtil {
+    private static final Logger log = LoggerFactory.getLogger(ThreadUtil.class);
+
+    private static ThreadFactory threadFactory = new SimpleThreadFactory();
+
+    public static final long SLEEP_SHORT = 1000;
+    public static final long SLEEP_MIDDLE = 5 * 1000;
+    public static final long SLEEP_LONG = 10 * 1000;
+
+    private static final int CORE_POOL_SIZE = 8;
+    private static final int MAX_POOL_SIZE = 64;
+
+    private static final ExecutorService POOL = new ThreadPoolExecutor(
+            CORE_POOL_SIZE, MAX_POOL_SIZE
+            , 60, TimeUnit.SECONDS
+            , new LinkedBlockingQueue<>(1024)
+            , new PrefixThreadFactory("oes-thread-pool-"));
+
+    public static void execute(Runnable task) {
+        POOL.execute(task);
+    }
+
+    public static <T> Future<T> submit(Callable<T> callable) {
+        return POOL.submit(callable);
+    }
+
+    public static Thread createThread(String name, Runnable runnable) {
+        Thread thread = threadFactory.newThread(runnable);
+        thread.setName(name);
+        return thread;
+    }
+
+    public static void sleepShort() {
+        sleep(SLEEP_SHORT);
+    }
+
+    public static void sleepMiddle() {
+        sleep(SLEEP_MIDDLE);
+    }
+
+    public static void sleepLong() {
+        sleep(SLEEP_LONG);
+    }
+
+    public static void sleep(long millis) {
+        try {
+            Thread.sleep(millis);
+        } catch (InterruptedException e) {
+            log.error("sleep exception: {}", e.getMessage(), e);
+        }
+    }
+
+    public static class SimpleThreadFactory implements ThreadFactory {
+
+        @Override
+        public Thread newThread(Runnable r) {
+            return new Thread(r);
+        }
+    }
+
+    public static class PrefixThreadFactory implements ThreadFactory {
+
+        private final String prefix;
+        private AtomicInteger atomic = new AtomicInteger(0);
+
+        public PrefixThreadFactory(String prefix) {
+            this.prefix = prefix;
+        }
+
+        @Override
+        public Thread newThread(Runnable r) {
+            return ThreadUtil.createThread(prefix + atomic.getAndIncrement(), r);
+        }
+    }
+
+}

+ 66 - 0
src/main/java/com/galaxis/manatee/util/TimeUtil.java

@@ -0,0 +1,66 @@
+package com.galaxis.manatee.util;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+public class TimeUtil {
+    /**
+     * 一般的日期格式 yyyy-MM-dd
+     */
+    public static final DateTimeFormatter DATE_SIMPLE = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+    /**
+     * 一般的时间格式 HH-mm-ss
+     */
+    public static final DateTimeFormatter TIME_SIMPLE = DateTimeFormatter.ofPattern("HH:mm:ss");
+
+    /**
+     * 预交日期格式 yyyyMMdd
+     */
+    public static final DateTimeFormatter DATE_ADVANCE = DateTimeFormatter.ofPattern("yyyyMMdd");
+
+    /**
+     * 预交时间格式 HHmmss
+     */
+    public static final DateTimeFormatter TIME_ADVANCE = DateTimeFormatter.ofPattern("HHmmss");
+
+    /**
+     * 预交时间格式 HHmmss
+     */
+    public static final DateTimeFormatter DATE_TIME_NOW = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+    public static String formatDate(LocalDateTime dateTime) {
+        return format(dateTime, DATE_SIMPLE);
+    }
+
+    public static String formatDateAdvance(LocalDateTime dateTime) {
+        return format(dateTime, DATE_ADVANCE);
+    }
+
+    public static String formatTime(LocalDateTime dateTime) {
+        return format(dateTime, TIME_SIMPLE);
+    }
+
+    public static String formatTimeAdvance(LocalDateTime dateTime) {
+        return format(dateTime, TIME_ADVANCE);
+    }
+
+    public static String formatDateTime(LocalDateTime dateTime) {
+        return format(dateTime, DATE_TIME_NOW);
+    }
+
+
+
+    public static String format(LocalDateTime dateTime, DateTimeFormatter dtf) {
+        return dtf.format(dateTime);
+    }
+
+    public static LocalDateTime parse(String date, String time) {
+        LocalDate d = LocalDate.parse(date, DATE_SIMPLE);
+        LocalTime t = LocalTime.parse(time, TIME_SIMPLE);
+        return LocalDateTime.of(d, t);
+    }
+
+}

+ 4 - 4
src/main/resources/application.yml

@@ -49,9 +49,9 @@ spring:
         size: 500
       thread-name-prefix: scheduled-task-
   datasource:
-    url: ${MYSQL_URL}
-    username: ${USER_NAME}
-    password: ${PASSWORD}
+    url: jdbc:mysql://localhost:3306/manatee?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
+    username: root
+    password: your_password
     hikari:
       maximum-pool-size: 128
   jpa:
@@ -59,7 +59,7 @@ spring:
     hibernate:
       ddl-auto: update
 claw:
-  url: ${CLAW_URL}
+  url: 127.0.0.1
 logging:
   file:
     name: "logs/manatee.log"