Browse Source

考勤统计

dzx 4 months ago
parent
commit
5dca3a14a2

+ 3 - 2
src/main/java/com/xjrsoft/module/attendance/entity/AttendanceStatistics.java

@@ -11,6 +11,7 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.time.LocalDate;
 import java.util.Date;
 import java.util.List;
 
@@ -90,12 +91,12 @@ public class AttendanceStatistics implements Serializable {
     * 开始日期
     */
     @ApiModelProperty("开始日期")
-    private Date startDate;
+    private LocalDate startDate;
     /**
     * 结束日期
     */
     @ApiModelProperty("结束日期")
-    private Date endDate;
+    private LocalDate endDate;
     /**
     * 关联考勤规则(attendance_rule_category)
     */

+ 3 - 3
src/main/java/com/xjrsoft/module/attendance/entity/AttendanceStatisticsRecord.java

@@ -83,17 +83,17 @@ public class AttendanceStatisticsRecord implements Serializable {
     * 正常考勤次数
     */
     @ApiModelProperty("正常考勤次数")
-    private Integer normalCount;
+    private Long normalCount;
     /**
     * 请假次数
     */
     @ApiModelProperty("请假次数")
-    private Integer leaveCount;
+    private Long leaveCount;
     /**
     * 旷工次数
     */
     @ApiModelProperty("旷工次数")
-    private Integer absenteeCount;
+    private Long absenteeCount;
     /**
     * 所在部门(存在多个,用“,”隔开)
     */

+ 5 - 1
src/main/java/com/xjrsoft/module/attendance/entity/TeacherAttendanceRecord.java

@@ -10,6 +10,7 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.time.LocalDateTime;
 import java.util.Date;
 
 
@@ -43,7 +44,7 @@ public class TeacherAttendanceRecord implements Serializable {
     */
     @ApiModelProperty("创建时间")
     @TableField(fill = FieldFill.INSERT)
-    private Date createDate;
+    private LocalDateTime createDate;
     /**
     * 修改人id
     */
@@ -95,4 +96,7 @@ public class TeacherAttendanceRecord implements Serializable {
     @ApiModelProperty("车牌号")
     private String carNumber;
 
+    @ApiModelProperty("考勤时间")
+    private LocalDateTime recordTime;
+
 }

+ 2 - 0
src/main/java/com/xjrsoft/module/attendance/service/IAttendanceRuleCategoryService.java

@@ -61,4 +61,6 @@ public interface IAttendanceRuleCategoryService extends MPJBaseService<Attendanc
 
     List<TimeRangeVo> getAllTimeRange(LocalDateTime startTime, LocalDateTime endTime);
 
+    List<AttendanceRuleDetails> getRules(Long id);
+
 }

+ 14 - 0
src/main/java/com/xjrsoft/module/attendance/service/IAttendanceStatisticsRecordService.java

@@ -0,0 +1,14 @@
+package com.xjrsoft.module.attendance.service;
+
+import com.github.yulichang.base.MPJBaseService;
+import com.xjrsoft.module.attendance.entity.AttendanceStatisticsRecord;
+
+/**
+* @title: 考勤统计
+* @Author dzx
+* @Date: 2024-10-19
+* @Version 1.0
+*/
+
+public interface IAttendanceStatisticsRecordService extends MPJBaseService<AttendanceStatisticsRecord> {
+}

+ 9 - 0
src/main/java/com/xjrsoft/module/attendance/service/impl/AttendanceRuleCategoryServiceImpl.java

@@ -520,4 +520,13 @@ public class AttendanceRuleCategoryServiceImpl extends MPJBaseServiceImpl<Attend
 
         return null;
     }
+
+    @Override
+    public List<AttendanceRuleDetails> getRules(Long id) {
+        List<AttendanceRuleDetails> list = detailsMapper.selectList(
+                new QueryWrapper<AttendanceRuleDetails>().lambda()
+                        .eq(AttendanceRuleDetails::getAttendanceRuleCategoryId, id)
+        );
+        return list;
+    }
 }

+ 57 - 0
src/main/java/com/xjrsoft/module/attendance/service/impl/AttendanceStatisticsRecordServiceImpl.java

@@ -0,0 +1,57 @@
+package com.xjrsoft.module.attendance.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.yulichang.base.MPJBaseServiceImpl;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.xjrsoft.common.exception.MyException;
+import com.xjrsoft.common.utils.VoToColumnUtil;
+import com.xjrsoft.module.attendance.dto.AddAttendanceStatisticsDto;
+import com.xjrsoft.module.attendance.dto.AttendanceStatisticsPageDto;
+import com.xjrsoft.module.attendance.dto.AttendanceStatisticsRecordDto;
+import com.xjrsoft.module.attendance.entity.AttendanceRuleDetails;
+import com.xjrsoft.module.attendance.entity.AttendanceStatistics;
+import com.xjrsoft.module.attendance.entity.AttendanceStatisticsRecord;
+import com.xjrsoft.module.attendance.entity.AttendanceUserRelation;
+import com.xjrsoft.module.attendance.entity.TeacherAttendanceRecord;
+import com.xjrsoft.module.attendance.mapper.AttendanceStatisticsMapper;
+import com.xjrsoft.module.attendance.mapper.AttendanceStatisticsRecordMapper;
+import com.xjrsoft.module.attendance.service.IAttendanceRuleCategoryService;
+import com.xjrsoft.module.attendance.service.IAttendanceStatisticsRecordService;
+import com.xjrsoft.module.attendance.service.IAttendanceStatisticsService;
+import com.xjrsoft.module.attendance.service.ITeacherAttendanceRecordService;
+import com.xjrsoft.module.attendance.vo.AttendanceStatisticsPageVo;
+import com.xjrsoft.module.attendance.vo.AttendanceStatisticsRecordVo;
+import com.xjrsoft.module.organization.entity.User;
+import com.xjrsoft.module.organization.service.IUserService;
+import lombok.AllArgsConstructor;
+import me.zhyd.oauth.log.Log;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+* @title: 考勤统计
+* @Author dzx
+* @Date: 2024-10-19
+* @Version 1.0
+*/
+@Service
+@AllArgsConstructor
+public class AttendanceStatisticsRecordServiceImpl extends MPJBaseServiceImpl<AttendanceStatisticsRecordMapper, AttendanceStatisticsRecord> implements IAttendanceStatisticsRecordService {
+}

+ 173 - 8
src/main/java/com/xjrsoft/module/attendance/service/impl/AttendanceStatisticsServiceImpl.java

@@ -1,28 +1,46 @@
 package com.xjrsoft.module.attendance.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.yulichang.base.MPJBaseServiceImpl;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
 import com.xjrsoft.common.exception.MyException;
+import com.xjrsoft.common.utils.VoToColumnUtil;
 import com.xjrsoft.module.attendance.dto.AddAttendanceStatisticsDto;
 import com.xjrsoft.module.attendance.dto.AttendanceStatisticsPageDto;
 import com.xjrsoft.module.attendance.dto.AttendanceStatisticsRecordDto;
+import com.xjrsoft.module.attendance.entity.AttendanceRuleDetails;
 import com.xjrsoft.module.attendance.entity.AttendanceStatistics;
 import com.xjrsoft.module.attendance.entity.AttendanceStatisticsRecord;
+import com.xjrsoft.module.attendance.entity.AttendanceUserRelation;
+import com.xjrsoft.module.attendance.entity.TeacherAttendanceRecord;
 import com.xjrsoft.module.attendance.mapper.AttendanceStatisticsMapper;
-import com.xjrsoft.module.attendance.mapper.AttendanceStatisticsRecordMapper;
+import com.xjrsoft.module.attendance.service.IAttendanceRuleCategoryService;
+import com.xjrsoft.module.attendance.service.IAttendanceStatisticsRecordService;
 import com.xjrsoft.module.attendance.service.IAttendanceStatisticsService;
+import com.xjrsoft.module.attendance.service.ITeacherAttendanceRecordService;
 import com.xjrsoft.module.attendance.vo.AttendanceStatisticsPageVo;
 import com.xjrsoft.module.attendance.vo.AttendanceStatisticsRecordVo;
+import com.xjrsoft.module.organization.entity.User;
+import com.xjrsoft.module.organization.service.IUserService;
 import lombok.AllArgsConstructor;
 import me.zhyd.oauth.log.Log;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.io.IOException;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
@@ -37,7 +55,13 @@ import java.util.stream.Collectors;
 public class AttendanceStatisticsServiceImpl extends MPJBaseServiceImpl<AttendanceStatisticsMapper, AttendanceStatistics> implements IAttendanceStatisticsService {
     private final AttendanceStatisticsMapper statisticsMapper;
 
-    private final AttendanceStatisticsRecordMapper recordMapper;
+    private final IAttendanceStatisticsRecordService statisticsRecordService;
+
+    private final ITeacherAttendanceRecordService recordService;
+
+    private final IUserService userService;
+
+    private final IAttendanceRuleCategoryService ruleCategoryService;
 
 
     @Override
@@ -57,7 +81,7 @@ public class AttendanceStatisticsServiceImpl extends MPJBaseServiceImpl<Attendan
         //********************************* AttendanceStatisticsRecord  增删改  开始 *******************************************/
         {
             // 查出所有子级的id
-            List<AttendanceStatisticsRecord> attendanceStatisticsRecordList = recordMapper.selectList(Wrappers.lambdaQuery(AttendanceStatisticsRecord.class).eq(AttendanceStatisticsRecord::getAttendanceStatisticsId, attendanceStatistics.getId()).select(AttendanceStatisticsRecord::getId));
+            List<AttendanceStatisticsRecord> attendanceStatisticsRecordList = statisticsRecordService.list(Wrappers.lambdaQuery(AttendanceStatisticsRecord.class).eq(AttendanceStatisticsRecord::getAttendanceStatisticsId, attendanceStatistics.getId()).select(AttendanceStatisticsRecord::getId));
             List<Long> attendanceStatisticsRecordIds = attendanceStatisticsRecordList.stream().map(AttendanceStatisticsRecord::getId).collect(Collectors.toList());
             //原有子表单 没有被删除的主键
             List<Long> attendanceStatisticsRecordOldIds = attendanceStatistics.getAttendanceStatisticsRecordList().stream().map(AttendanceStatisticsRecord::getId).filter(Objects::nonNull).collect(Collectors.toList());
@@ -67,18 +91,18 @@ public class AttendanceStatisticsServiceImpl extends MPJBaseServiceImpl<Attendan
             for (AttendanceStatisticsRecord attendanceStatisticsRecord : attendanceStatistics.getAttendanceStatisticsRecordList()) {
                 //如果不等于空则修改
                 if (attendanceStatisticsRecord.getId() != null) {
-                    recordMapper.updateById(attendanceStatisticsRecord);
+                    statisticsRecordService.updateById(attendanceStatisticsRecord);
                 }
                 //如果等于空 则新增
                 else {
                     //已经不存在的id 删除
                     attendanceStatisticsRecord.setAttendanceStatisticsId(attendanceStatistics.getId());
-                    recordMapper.insert(attendanceStatisticsRecord);
+                    statisticsRecordService.save(attendanceStatisticsRecord);
                 }
             }
             //已经不存在的id 删除
             if(attendanceStatisticsRecordRemoveIds.size() > 0){
-                recordMapper.deleteBatchIds(attendanceStatisticsRecordRemoveIds);
+                statisticsRecordService.removeBatchByIds(attendanceStatisticsRecordRemoveIds);
             }
         }
         //********************************* AttendanceStatisticsRecord  增删改  结束 *******************************************/
@@ -90,7 +114,7 @@ public class AttendanceStatisticsServiceImpl extends MPJBaseServiceImpl<Attendan
     @Transactional(rollbackFor = Exception.class)
     public Boolean delete(List<Long> ids) {
         statisticsMapper.deleteBatchIds(ids);
-        recordMapper.delete(Wrappers.lambdaQuery(AttendanceStatisticsRecord.class).in(AttendanceStatisticsRecord::getAttendanceStatisticsId, ids));
+        statisticsRecordService.remove(Wrappers.lambdaQuery(AttendanceStatisticsRecord.class).in(AttendanceStatisticsRecord::getAttendanceStatisticsId, ids));
 
         return true;
     }
@@ -117,18 +141,159 @@ public class AttendanceStatisticsServiceImpl extends MPJBaseServiceImpl<Attendan
     @Transactional(rollbackFor = Exception.class)
     public Boolean refreshRecord(Long id) {
         try {
+            //1、修改状态为统计中
             AttendanceStatistics statistics = this.getById(id);
             statistics.setStatus(0);
             statistics.setModifyDate(new Date());
             this.updateById(statistics);
+
+            //2、删除以前的数据
+            statisticsRecordService.remove(
+                    new QueryWrapper<AttendanceStatisticsRecord>().lambda()
+                            .eq(AttendanceStatisticsRecord::getAttendanceStatisticsId, id)
+            );
+
+            /**
+             * 3、重新计算数据并入库
+             */
+            //3.1、根据考勤规则和统计的时间段查询这个规则下面所涉及到的老师
+            List<User> userList = userService.list(
+                    new MPJLambdaWrapper<User>()
+                            .select(User::getId)
+                            .select(User.class, x -> VoToColumnUtil.fieldsToColumns(User.class).contains(x.getProperty()))
+                            .innerJoin(AttendanceUserRelation.class, AttendanceUserRelation::getUserId, User::getId)
+                            .eq(AttendanceUserRelation::getAttendanceRuleCategoryId, statistics.getAttendanceRuleCategoryId())
+            );
+            if(userList.isEmpty()){
+               throw new MyException("该规则下无考勤人员");
+            }
+            List<Long> userIds = userList.stream().map(User::getId).collect(Collectors.toList());
+
+            //查询固化的考勤数据
+            List<TeacherAttendanceRecord> attendanceRecords = recordService.list(
+                    new QueryWrapper<TeacherAttendanceRecord>().lambda()
+                            .eq(TeacherAttendanceRecord::getTimeInterval, statistics.getTimePeriod())
+                            .in(TeacherAttendanceRecord::getUserId, userIds)
+                            .between(TeacherAttendanceRecord::getCreateDate, statistics.getStartDate(), statistics.getEndDate())
+            );
+            //3.2、计算出所有的天数
+            List<LocalDate> dateList = getDatesBetween(statistics.getStartDate(), statistics.getEndDate());
+            //3.3、循环用户进行统计查询
+            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
+            DateTimeFormatter timeDtf = DateTimeFormatter.ofPattern("HH:mm");
+            Map<String, String> weekCnMap = initWeekCn();
+            Map<String, String> weekEnMap = initWeekEn();
+
+            //3.4、查询这个考勤规则下面的所有细则并转换成map
+            List<AttendanceRuleDetails> ruleList = ruleCategoryService.getRules(statistics.getAttendanceRuleCategoryId());
+            Map<String, AttendanceRuleDetails> ruleMap = ruleList.stream().collect(Collectors.toMap(AttendanceRuleDetails::getDateType, x -> x));
+            //3.5、循环计算,并存入insertList,方便后续批量入库
+            List<AttendanceStatisticsRecord> insertList = new ArrayList<>();
+            for (User user : userList) {
+                AttendanceStatisticsRecord record = new AttendanceStatisticsRecord();
+                record.setUserId(user.getId());
+                Long normalCount = 0L;
+                Long leaveCount = 0L;
+                Long absenteeCount = 0L;
+                JsonArray daysData = new JsonArray();
+                for (LocalDate localDate : dateList) {
+                    String dayOfWeekName = localDate.getDayOfWeek().name();
+                    AttendanceRuleDetails ruleDetails = ruleMap.get(weekEnMap.get(dayOfWeekName));
+                    JsonObject daysJson = new JsonObject();
+                    daysJson.addProperty("date", localDate.format(dtf));
+                    daysJson.addProperty("week", weekCnMap.get(dayOfWeekName));
+                    String content = "";
+                    if(statistics.getTimePeriod() == 1){
+                        content += "(" + ruleDetails.getAmStartTime().toLocalTime().format(timeDtf) + ")上班 ";
+                    }else if(statistics.getTimePeriod() == 2){
+                        content += "(" + ruleDetails.getPmStartTime().toLocalTime().format(timeDtf) + ")上班 ";
+                    }
+                    List<TeacherAttendanceRecord> collect = attendanceRecords.stream().filter(el -> el.getRecordTime().toLocalDate().equals(localDate)).collect(Collectors.toList());
+                    for (TeacherAttendanceRecord attendanceRecord : collect) {
+                        if("到校".equals(attendanceRecord.getAttendanceStatus())){
+                            normalCount ++;
+                            content += "正常(" + attendanceRecord.getRecordTime().toLocalTime().format(timeDtf) + ")";
+                        }else if("请假".equals(attendanceRecord.getAttendanceStatus())){
+                            leaveCount ++;
+                            content += "请假";
+                        }else{
+                            absenteeCount ++;
+                            content += "缺勤";
+                        }
+                    }
+                    daysJson.addProperty("content", content);
+                    daysData.add(daysJson);
+                }
+                record.setNormalCount(normalCount);
+                record.setLeaveCount(leaveCount);
+                record.setAbsenteeCount(absenteeCount);
+                record.setDaysData(daysData.toString());
+                insertList.add(record);
+            }
+
+            //3.6、插入数据
+            if(!insertList.isEmpty()){
+                statisticsRecordService.saveBatch(insertList);
+            }
+
+            //4、将状态改为统计完成
+            statistics = this.getById(id);
+            statistics.setStatus(1);
+            statistics.setModifyDate(new Date());
+            this.updateById(statistics);
         }catch (Exception e){
             Log.error(e.getMessage(), e);
-            throw new MyException("刷新出错,请联系管理员");
+            if(e.getClass().equals(MyException.class)){
+                throw new MyException(e.getMessage());
+            }else{
+                throw new MyException("刷新出错,请联系管理员");
+            }
         }
 
         return true;
     }
 
+
+
+    private List<LocalDate> getDatesBetween(LocalDate startDate, LocalDate endDate) {
+        List<LocalDate> dates = new ArrayList<>();
+
+        long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate) + 1; // +1 包含结束日期
+        for (long i = 0; i < numOfDaysBetween; i++) {
+            dates.add(startDate.plusDays(i));
+        }
+
+        return dates;
+    }
+
+    private Map<String, String> initWeekCn() {
+        Map<String, String> result = new HashMap<>();
+
+        result.put("MONDAY", "周一");
+        result.put("TUESDAY", "周一");
+        result.put("WEDNESDAY", "周一");
+        result.put("THURSDAY", "周一");
+        result.put("FRIDAY", "周一");
+        result.put("SATURDAY", "周一");
+        result.put("SUNDAY", "周日");
+
+        return result;
+    }
+
+    private Map<String, String> initWeekEn() {
+        Map<String, String> result = new HashMap<>();
+
+        result.put("MONDAY", "monday");
+        result.put("TUESDAY", "tuesday");
+        result.put("WEDNESDAY", "wednesday");
+        result.put("THURSDAY", "thursday");
+        result.put("FRIDAY", "friday");
+        result.put("SATURDAY", "saturday");
+        result.put("SUNDAY", "sunday");
+
+        return result;
+    }
+
     @Override
     public byte[] recordExport(Long id) throws IOException {
         return new byte[0];

+ 3 - 0
src/main/java/com/xjrsoft/module/attendance/vo/AttendanceStatisticsRecordVo.java

@@ -59,6 +59,9 @@ public class AttendanceStatisticsRecordVo {
     @ApiModelProperty("部门成")
     private String deptName;
 
+    @ApiModelProperty("姓名")
+    private String name;
+
 
 
 }

+ 225 - 0
src/main/java/com/xjrsoft/module/job/AttendanceRecordTask.java

@@ -0,0 +1,225 @@
+package com.xjrsoft.module.job;
+
+import cn.hutool.extra.spring.SpringUtil;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.xjrsoft.common.enums.OutInStatusEnum;
+import com.xjrsoft.common.utils.VoToColumnUtil;
+import com.xjrsoft.module.attendance.entity.TeacherAttendanceRecord;
+import com.xjrsoft.module.attendance.service.IAttendanceRuleCategoryService;
+import com.xjrsoft.module.attendance.service.ITeacherAttendanceRecordService;
+import com.xjrsoft.module.attendance.vo.AttendanceRuleDetailsUserVo;
+import com.xjrsoft.module.organization.entity.User;
+import com.xjrsoft.module.organization.service.IUserService;
+import com.xjrsoft.module.outint.dto.TeacherOutInRecordDto;
+import com.xjrsoft.module.outint.entity.CarOutInRecord;
+import com.xjrsoft.module.outint.entity.TeacherOutInRecord;
+import com.xjrsoft.module.outint.service.ICarOutInRecordService;
+import com.xjrsoft.module.outint.service.ITeacherOutInRecordService;
+import com.xjrsoft.module.personnel.entity.CarMessageApply;
+import com.xjrsoft.module.teacher.entity.BaseTeacher;
+import com.xjrsoft.module.teacher.entity.WfHeadTeacherLeave;
+import com.xjrsoft.module.teacher.entity.WfTeacherleave;
+import com.xjrsoft.module.teacher.entity.XjrUser;
+import com.xjrsoft.module.teacher.service.IWfHeadTeacherLeaveService;
+import com.xjrsoft.module.teacher.service.IWfTeacherleaveService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author dzx
+ * @date 2024/10/19
+ * 考勤数据固话,指定时间执行
+ */
+@Component
+@Slf4j
+public class AttendanceRecordTask {
+    
+    @Autowired
+    private IUserService userService;
+
+    @Autowired
+    private IAttendanceRuleCategoryService ruleCategoryService;
+
+    @Autowired
+    private IWfTeacherleaveService wfTeacherleaveService;
+
+    @Autowired
+    private IWfHeadTeacherLeaveService headTeacherLeaveService;
+
+    @Autowired
+    private ITeacherOutInRecordService teacherOutInRecordService;
+
+    @Autowired
+    private ICarOutInRecordService carOutInRecordService;
+
+    @Autowired
+    private ITeacherAttendanceRecordService recordService;
+
+
+    @Scheduled(cron = "0 0 1 * * ?")
+    public void execute() {
+        String active = SpringUtil.getActiveProfile();
+        if(!"prod".equals(active)){
+            log.info("非正式环境,无法执行数据推送");
+            return;
+        }
+        //获取时间,并计算出前一天的开始时间和结束时间
+        LocalDateTime now = LocalDateTime.now();
+        LocalDateTime startDateTime = now.plusDays(-1).withHour(0).withMinute(0).withSecond(0).withNano(0);
+        LocalDateTime endDateTime = startDateTime.plusDays(1).plusSeconds(-1);
+
+        //计算上午考勤
+        teacherAttendanceRecord(startDateTime, endDateTime, 1);
+
+        //计算上午考勤
+        teacherAttendanceRecord(startDateTime, endDateTime, 2);
+
+    }
+
+    /**
+     * 根据时间段,统计这个时间段内的考勤数据
+     * @param startDateTime 开始时间
+     * @param endDateTime 结束时间
+     */
+    public void teacherAttendanceRecord(LocalDateTime startDateTime, LocalDateTime endDateTime, Integer timePeriod){
+        List<User> teacherList = userService.list(
+                new MPJLambdaWrapper<User>()
+                        .select(User::getId)
+                        .select(User.class, x -> VoToColumnUtil.fieldsToColumns(User.class).contains(x.getProperty()))
+                        .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, User::getId)
+        );
+        List<Long> userIds = teacherList.stream().map(User::getId).collect(Collectors.toList());
+        Map<Long, AttendanceRuleDetailsUserVo> teacherTodyRuleByUserId = ruleCategoryService.getTeacherTodyRuleByUserId(userIds);
+
+        LocalDate queryDate = startDateTime.toLocalDate();
+        List<TeacherAttendanceRecord> insertList = new ArrayList<>();
+        for (User user : teacherList) {
+
+            TeacherAttendanceRecord record = new TeacherAttendanceRecord();
+            record.setCreateDate(LocalDateTime.now());
+            record.setUserId(user.getId());
+            record.setTimeInterval(timePeriod);
+            AttendanceRuleDetailsUserVo detailsUserVo = teacherTodyRuleByUserId.get(user.getId());
+            if(detailsUserVo == null){
+                record.setAttendanceStatus("不考勤");
+                insertList.add(record);
+                continue;
+            }
+
+            LocalDateTime startTime, endTime, amEndTime = null;
+
+            if(timePeriod == 1){
+                startTime = queryDate.atTime(5, 0, 0);
+                if(detailsUserVo != null && detailsUserVo.getAmStartTime() != null){
+                    startTime = queryDate.atTime(detailsUserVo.getAmStartTime());
+                }
+                endTime = queryDate.atTime(12, 0, 0);
+                if(detailsUserVo != null && detailsUserVo.getAmEndTime() != null){
+                    endTime = queryDate.atTime(detailsUserVo.getAmEndTime());
+                }
+            }else if(timePeriod == 2){
+                startTime = queryDate.atTime(12, 0, 0);
+                if(detailsUserVo != null && detailsUserVo.getPmStartTime() != null){
+                    startTime = queryDate.atTime(detailsUserVo.getPmStartTime());
+                }
+                endTime = queryDate.atTime(18, 0, 0);
+                if(detailsUserVo != null && detailsUserVo.getPmEndTime() != null){
+                    endTime = queryDate.atTime(detailsUserVo.getPmEndTime());
+                }
+                amEndTime  = queryDate.atTime(12, 0, 0);
+                if(detailsUserVo != null && detailsUserVo.getAmEndTime() != null){
+                    amEndTime = queryDate.atTime(detailsUserVo.getAmEndTime());
+                }
+            }else{
+                startTime = queryDate.atTime(0, 0, 0);
+                if(detailsUserVo != null && detailsUserVo.getEveningStartTime() != null){
+                    startTime = queryDate.atTime(detailsUserVo.getEveningStartTime());
+                }
+                endTime = queryDate.atTime(23, 59, 59);
+                if(detailsUserVo != null && detailsUserVo.getEveningEndTime() != null){
+                    endTime = queryDate.atTime(detailsUserVo.getEveningEndTime());
+                }
+            }
+
+            WfTeacherleave studentLeave = wfTeacherleaveService.getLeaveByUserId(startTime, endTime, user.getId());
+            if(studentLeave != null){
+                record.setAttendanceStatus(studentLeave.getLeaveType());
+                continue;
+            }
+
+            WfHeadTeacherLeave teacherLeave = headTeacherLeaveService.selectJoinOne(WfHeadTeacherLeave.class,
+                    new MPJLambdaWrapper<WfHeadTeacherLeave>()
+                            .select(WfHeadTeacherLeave.class, x -> VoToColumnUtil.fieldsToColumns(WfHeadTeacherLeave.class).contains(x.getProperty()))
+                            .innerJoin(XjrUser.class, XjrUser::getId, WfHeadTeacherLeave::getApplicantUserId)
+                            .eq(WfHeadTeacherLeave::getStatus, 1)
+                            .eq(WfHeadTeacherLeave::getApplicantUserId, record.getUserId())
+                            .between(WfHeadTeacherLeave::getStartTime, startTime, endTime)
+            );
+            if(teacherLeave != null){
+                record.setAttendanceStatus(teacherLeave.getLeaveReason());
+                continue;
+            }
+            TeacherOutInRecordDto outInDto = new TeacherOutInRecordDto();
+            outInDto.setQueryDate(startTime.toLocalDate());
+            outInDto.setRecordTime(endTime);
+            outInDto.setStatus(OutInStatusEnum.enter.getCode());
+            outInDto.setUserId(record.getUserId());
+            List<TeacherOutInRecord> outInRecords = teacherOutInRecordService.getListByParam(outInDto);
+            if(!outInRecords.isEmpty()){
+                TeacherOutInRecord outInRecord = outInRecords.get(0);
+                if(outInRecord != null){
+                    record.setRecordTime(outInRecord.getRecordTime());
+                    record.setAttendanceStatus(outInRecord.getAttendanceStatus());
+                    record.setAttendanceMode(1);
+                }
+            }else{
+                //查询该教师是否通过车辆进入
+                List<CarOutInRecord> list = carOutInRecordService.list(
+                        new MPJLambdaWrapper<CarOutInRecord>()
+                                .select(CarOutInRecord.class, x -> VoToColumnUtil.fieldsToColumns(CarOutInRecord.class).contains(x.getProperty()))
+                                .leftJoin(CarMessageApply.class, CarMessageApply::getId, CarOutInRecord::getCarMessageApplyId)
+                                .le(CarOutInRecord::getRecordTime, endTime)
+                                .eq("DATE_FORMAT(record_time, '%Y-%m-%d')", endTime.toLocalDate())
+                                .eq(CarMessageApply::getUserId, record.getUserId())
+                                .ge(timePeriod != null && timePeriod == 2 && amEndTime != null, CarOutInRecord::getRecordTime, amEndTime)
+                                .eq(CarOutInRecord::getStatus, OutInStatusEnum.enter.getCode())
+                                .orderByAsc(CarOutInRecord::getRecordTime)
+                );
+                if(!list.isEmpty()){
+                    CarOutInRecord outInRecord = list.get(0);
+                    if(outInRecord != null && outInRecord.getRecordTime().isBefore(startTime)){
+                        record.setRecordTime(outInRecord.getRecordTime());
+                        record.setAttendanceStatus("到校");
+                        record.setAttendanceMode(2);
+                        record.setCarNumber(outInRecord.getPlanNo());
+                    }else if(outInRecord != null && outInRecord.getRecordTime().isAfter(startTime)){
+                        record.setRecordTime(outInRecord.getRecordTime());
+                        record.setAttendanceStatus("迟到");
+                        record.setAttendanceMode(1);
+                        record.setCarNumber(outInRecord.getPlanNo());
+                    }
+                }
+            }
+
+            if(record.getAttendanceStatus() == null){
+                record.setAttendanceStatus("缺勤");
+            }
+
+            insertList.add(record);
+        }
+
+        if(!insertList.isEmpty()){
+            recordService.saveBatch(insertList);
+        }
+    }
+
+}

+ 3 - 3
src/main/java/com/xjrsoft/module/job/InsertOutInRecordTask.java

@@ -29,14 +29,14 @@ public class InsertOutInRecordTask {
 
     @Scheduled(cron = "0 30 0 * * ?")
     public void execute() {
-        RefreshConnectionPool();
-    }
-    public void RefreshConnectionPool() {
         String active = SpringUtil.getActiveProfile();
         if(!"prod".equals(active)){
             log.info("非正式环境,无法执行数据推送");
             return;
         }
+        RefreshConnectionPool();
+    }
+    public void RefreshConnectionPool() {
         log.info("开始拉取海康威视基础数据");
         try {
             //获取时间,并计算出前一天的开始时间和结束时间

+ 219 - 0
src/test/java/com/xjrsoft/module/job/AttendanceRecordTaskTest.java

@@ -0,0 +1,219 @@
+package com.xjrsoft.module.job;
+
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.xjrsoft.XjrSoftApplication;
+import com.xjrsoft.common.enums.OutInStatusEnum;
+import com.xjrsoft.common.utils.VoToColumnUtil;
+import com.xjrsoft.module.attendance.entity.TeacherAttendanceRecord;
+import com.xjrsoft.module.attendance.service.IAttendanceRuleCategoryService;
+import com.xjrsoft.module.attendance.service.ITeacherAttendanceRecordService;
+import com.xjrsoft.module.attendance.vo.AttendanceRuleDetailsUserVo;
+import com.xjrsoft.module.organization.entity.User;
+import com.xjrsoft.module.organization.service.IUserService;
+import com.xjrsoft.module.outint.dto.TeacherOutInRecordDto;
+import com.xjrsoft.module.outint.entity.CarOutInRecord;
+import com.xjrsoft.module.outint.entity.TeacherOutInRecord;
+import com.xjrsoft.module.outint.service.ICarOutInRecordService;
+import com.xjrsoft.module.outint.service.ITeacherOutInRecordService;
+import com.xjrsoft.module.personnel.entity.CarMessageApply;
+import com.xjrsoft.module.teacher.entity.BaseTeacher;
+import com.xjrsoft.module.teacher.entity.WfHeadTeacherLeave;
+import com.xjrsoft.module.teacher.entity.WfTeacherleave;
+import com.xjrsoft.module.teacher.entity.XjrUser;
+import com.xjrsoft.module.teacher.service.IWfHeadTeacherLeaveService;
+import com.xjrsoft.module.teacher.service.IWfTeacherleaveService;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author dzx
+ * @date 2024/10/19
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = XjrSoftApplication.class)
+class AttendanceRecordTaskTest {
+
+    @Autowired
+    private IUserService userService;
+
+    @Autowired
+    private IAttendanceRuleCategoryService ruleCategoryService;
+
+    @Autowired
+    private IWfTeacherleaveService wfTeacherleaveService;
+
+    @Autowired
+    private IWfHeadTeacherLeaveService headTeacherLeaveService;
+
+    @Autowired
+    private ITeacherOutInRecordService teacherOutInRecordService;
+
+    @Autowired
+    private ICarOutInRecordService carOutInRecordService;
+
+    @Autowired
+    private ITeacherAttendanceRecordService recordService;
+
+
+    @Test
+    public void execute() {
+        //获取时间,并计算出前一天的开始时间和结束时间
+        LocalDateTime now = LocalDateTime.now();
+        LocalDateTime startDateTime = now.plusDays(-1).withHour(0).withMinute(0).withSecond(0).withNano(0);
+        LocalDateTime endDateTime = startDateTime.plusDays(1).plusSeconds(-1);
+
+        //计算上午考勤
+        teacherAttendanceRecord(startDateTime, endDateTime, 1);
+
+        //计算上午考勤
+        //teacherAttendanceRecord(startDateTime, endDateTime, 2);
+
+    }
+
+    /**
+     * 根据时间段,统计这个时间段内的考勤数据
+     * @param startDateTime 开始时间
+     * @param endDateTime 结束时间
+     */
+    public void teacherAttendanceRecord(LocalDateTime startDateTime, LocalDateTime endDateTime, Integer timePeriod){
+        List<User> teacherList = userService.list(
+                new MPJLambdaWrapper<User>()
+                        .select(User::getId)
+                        .select(User.class, x -> VoToColumnUtil.fieldsToColumns(User.class).contains(x.getProperty()))
+                        .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, User::getId)
+        );
+        List<Long> userIds = teacherList.stream().map(User::getId).collect(Collectors.toList());
+        Map<Long, AttendanceRuleDetailsUserVo> teacherTodyRuleByUserId = ruleCategoryService.getTeacherTodyRuleByUserId(userIds);
+
+        LocalDate queryDate = startDateTime.toLocalDate();
+        List<TeacherAttendanceRecord> insertList = new ArrayList<>();
+        for (User user : teacherList) {
+
+            TeacherAttendanceRecord record = new TeacherAttendanceRecord();
+            record.setCreateDate(LocalDateTime.now());
+            record.setUserId(user.getId());
+            record.setTimeInterval(timePeriod);
+            AttendanceRuleDetailsUserVo detailsUserVo = teacherTodyRuleByUserId.get(user.getId());
+            if(detailsUserVo == null){
+                record.setAttendanceStatus("不考勤");
+                insertList.add(record);
+                continue;
+            }
+
+            LocalDateTime startTime, endTime, amEndTime = null;
+
+            if(timePeriod == 1){
+                startTime = queryDate.atTime(5, 0, 0);
+                if(detailsUserVo != null && detailsUserVo.getAmStartTime() != null){
+                    startTime = queryDate.atTime(detailsUserVo.getAmStartTime());
+                }
+                endTime = queryDate.atTime(12, 0, 0);
+                if(detailsUserVo != null && detailsUserVo.getAmEndTime() != null){
+                    endTime = queryDate.atTime(detailsUserVo.getAmEndTime());
+                }
+            }else if(timePeriod == 2){
+                startTime = queryDate.atTime(12, 0, 0);
+                if(detailsUserVo != null && detailsUserVo.getPmStartTime() != null){
+                    startTime = queryDate.atTime(detailsUserVo.getPmStartTime());
+                }
+                endTime = queryDate.atTime(18, 0, 0);
+                if(detailsUserVo != null && detailsUserVo.getPmEndTime() != null){
+                    endTime = queryDate.atTime(detailsUserVo.getPmEndTime());
+                }
+                amEndTime  = queryDate.atTime(12, 0, 0);
+                if(detailsUserVo != null && detailsUserVo.getAmEndTime() != null){
+                    amEndTime = queryDate.atTime(detailsUserVo.getAmEndTime());
+                }
+            }else{
+                startTime = queryDate.atTime(0, 0, 0);
+                if(detailsUserVo != null && detailsUserVo.getEveningStartTime() != null){
+                    startTime = queryDate.atTime(detailsUserVo.getEveningStartTime());
+                }
+                endTime = queryDate.atTime(23, 59, 59);
+                if(detailsUserVo != null && detailsUserVo.getEveningEndTime() != null){
+                    endTime = queryDate.atTime(detailsUserVo.getEveningEndTime());
+                }
+            }
+
+            WfTeacherleave studentLeave = wfTeacherleaveService.getLeaveByUserId(startTime, endTime, user.getId());
+            if(studentLeave != null){
+                record.setAttendanceStatus(studentLeave.getLeaveType());
+                continue;
+            }
+
+            WfHeadTeacherLeave teacherLeave = headTeacherLeaveService.selectJoinOne(WfHeadTeacherLeave.class,
+                    new MPJLambdaWrapper<WfHeadTeacherLeave>()
+                            .select(WfHeadTeacherLeave.class, x -> VoToColumnUtil.fieldsToColumns(WfHeadTeacherLeave.class).contains(x.getProperty()))
+                            .innerJoin(XjrUser.class, XjrUser::getId, WfHeadTeacherLeave::getApplicantUserId)
+                            .eq(WfHeadTeacherLeave::getStatus, 1)
+                            .eq(WfHeadTeacherLeave::getApplicantUserId, record.getUserId())
+                            .between(WfHeadTeacherLeave::getStartTime, startTime, endTime)
+            );
+            if(teacherLeave != null){
+                record.setAttendanceStatus(teacherLeave.getLeaveReason());
+                continue;
+            }
+            TeacherOutInRecordDto outInDto = new TeacherOutInRecordDto();
+            outInDto.setQueryDate(startTime.toLocalDate());
+            outInDto.setRecordTime(endTime);
+            outInDto.setStatus(OutInStatusEnum.enter.getCode());
+            outInDto.setUserId(record.getUserId());
+            List<TeacherOutInRecord> outInRecords = teacherOutInRecordService.getListByParam(outInDto);
+            if(!outInRecords.isEmpty()){
+                TeacherOutInRecord outInRecord = outInRecords.get(0);
+                if(outInRecord != null){
+                    record.setRecordTime(outInRecord.getRecordTime());
+                    record.setAttendanceStatus(outInRecord.getAttendanceStatus());
+                    record.setAttendanceMode(1);
+                }
+            }else{
+                //查询该教师是否通过车辆进入
+                List<CarOutInRecord> list = carOutInRecordService.list(
+                        new MPJLambdaWrapper<CarOutInRecord>()
+                                .select(CarOutInRecord.class, x -> VoToColumnUtil.fieldsToColumns(CarOutInRecord.class).contains(x.getProperty()))
+                                .leftJoin(CarMessageApply.class, CarMessageApply::getId, CarOutInRecord::getCarMessageApplyId)
+                                .le(CarOutInRecord::getRecordTime, endTime)
+                                .eq("DATE_FORMAT(record_time, '%Y-%m-%d')", endTime.toLocalDate())
+                                .eq(CarMessageApply::getUserId, record.getUserId())
+                                .ge(timePeriod != null && timePeriod == 2 && amEndTime != null, CarOutInRecord::getRecordTime, amEndTime)
+                                .eq(CarOutInRecord::getStatus, OutInStatusEnum.enter.getCode())
+                                .orderByAsc(CarOutInRecord::getRecordTime)
+                );
+                if(!list.isEmpty()){
+                    CarOutInRecord outInRecord = list.get(0);
+                    if(outInRecord != null && outInRecord.getRecordTime().isBefore(startTime)){
+                        record.setRecordTime(outInRecord.getRecordTime());
+                        record.setAttendanceStatus("到校");
+                        record.setAttendanceMode(2);
+                        record.setCarNumber(outInRecord.getPlanNo());
+                    }else if(outInRecord != null && outInRecord.getRecordTime().isAfter(startTime)){
+                        record.setRecordTime(outInRecord.getRecordTime());
+                        record.setAttendanceStatus("迟到");
+                        record.setAttendanceMode(1);
+                        record.setCarNumber(outInRecord.getPlanNo());
+                    }
+                }
+            }
+
+            if(record.getAttendanceStatus() == null){
+                record.setAttendanceStatus("缺勤");
+            }
+
+            insertList.add(record);
+        }
+
+        if(!insertList.isEmpty()){
+            recordService.saveBatch(insertList);
+        }
+    }
+}