Explorar el Código

Merge branch 'pre'

dzx hace 1 año
padre
commit
be79501592
Se han modificado 25 ficheros con 766 adiciones y 81 borrados
  1. 9 0
      src/main/java/com/xjrsoft/module/attendance/controller/TeacherAttendanceRecordController.java
  2. 4 3
      src/main/java/com/xjrsoft/module/attendance/controller/TeacherStatisticsController.java
  3. 25 0
      src/main/java/com/xjrsoft/module/attendance/dto/ResetTeacherAttendanceRecordDto.java
  4. 3 0
      src/main/java/com/xjrsoft/module/attendance/service/ITeacherAttendanceRecordService.java
  5. 42 0
      src/main/java/com/xjrsoft/module/attendance/service/impl/TeacherAttendanceRecordServiceImpl.java
  6. 6 0
      src/main/java/com/xjrsoft/module/courseTable/dto/ClassTeacherDto.java
  7. 2 0
      src/main/java/com/xjrsoft/module/courseTable/mapper/CourseTableMapper.java
  8. 5 0
      src/main/java/com/xjrsoft/module/courseTable/service/ICourseTableService.java
  9. 6 0
      src/main/java/com/xjrsoft/module/courseTable/service/impl/CourseTableServiceImpl.java
  10. 90 54
      src/main/java/com/xjrsoft/module/job/AttendanceRecordTask.java
  11. 8 1
      src/main/java/com/xjrsoft/module/job/JianyuekbScheduleTask.java
  12. 347 0
      src/main/java/com/xjrsoft/module/ledger/controller/LedgerStatisticsController.java
  13. 38 0
      src/main/java/com/xjrsoft/module/ledger/dto/LedgerStatisticsPageDto.java
  14. 21 0
      src/main/java/com/xjrsoft/module/ledger/vo/LedgerStatisticsLeaveVo.java
  15. 21 0
      src/main/java/com/xjrsoft/module/ledger/vo/LedgerStatisticsListenVo.java
  16. 21 0
      src/main/java/com/xjrsoft/module/ledger/vo/LedgerStatisticsOvertimeVo.java
  17. 36 0
      src/main/java/com/xjrsoft/module/ledger/vo/LedgerStatisticsPageVo.java
  18. 1 1
      src/main/java/com/xjrsoft/module/liteflow/node/StudentDropOutNode.java
  19. 0 2
      src/main/java/com/xjrsoft/module/outint/controller/TeacherOutInRecordController.java
  20. 36 15
      src/main/java/com/xjrsoft/module/outint/service/impl/TeacherOutInRecordServiceImpl.java
  21. 2 0
      src/main/java/com/xjrsoft/module/teacher/mapper/WfTeacherleaveMapper.java
  22. 3 0
      src/main/java/com/xjrsoft/module/teacher/service/IWfTeacherleaveService.java
  23. 9 0
      src/main/java/com/xjrsoft/module/teacher/service/impl/WfTeacherleaveServiceImpl.java
  24. 8 0
      src/main/resources/mapper/courseTable/CourseTable.xml
  25. 23 5
      src/main/resources/mapper/teacher/WfTeacherleaveMapper.xml

+ 9 - 0
src/main/java/com/xjrsoft/module/attendance/controller/TeacherAttendanceRecordController.java

@@ -12,6 +12,7 @@ import com.xjrsoft.common.page.ConventPage;
 import com.xjrsoft.common.page.PageOutput;
 import com.xjrsoft.common.utils.VoToColumnUtil;
 import com.xjrsoft.module.attendance.dto.AddTeacherAttendanceRecordDto;
+import com.xjrsoft.module.attendance.dto.ResetTeacherAttendanceRecordDto;
 import com.xjrsoft.module.attendance.dto.TeacherAttendanceRecordPageDto;
 import com.xjrsoft.module.attendance.dto.UpdateTeacherAttendanceRecordDto;
 import com.xjrsoft.module.attendance.entity.TeacherAttendanceRecord;
@@ -119,4 +120,12 @@ public class TeacherAttendanceRecordController {
         return RT.ok(teacherAttendanceRecordService.removeBatchByIds(ids));
     }
 
+    @PostMapping("reset-data")
+    @ApiOperation(value = "重置考勤数据")
+    @SaCheckPermission("teacherattendancerecord:reset-data")
+    public RT<Boolean> add(@Valid @RequestBody ResetTeacherAttendanceRecordDto dto){
+        Boolean aBoolean = teacherAttendanceRecordService.resetData(dto);
+        return RT.ok(aBoolean);
+    }
+
 }

+ 4 - 3
src/main/java/com/xjrsoft/module/attendance/controller/TeacherStatisticsController.java

@@ -88,6 +88,9 @@ public class TeacherStatisticsController {
         }else{
             MPJLambdaWrapper<User> queryUser = new MPJLambdaWrapper<>();
             queryUser.disableSubLogicDel().distinct()
+                    .select(" (SELECT GROUP_CONCAT(t1.name) FROM xjr_department t1" +
+                            " INNER JOIN xjr_user_dept_relation t2 ON t1.id = t2.dept_id" +
+                            " WHERE t1.delete_mark = 0 AND t2.user_id = t.id) as dept_name")
                     .eq(ObjectUtil.isNotNull(dto.getDeptId()), UserDeptRelation::getDeptId, dto.getDeptId())
                     .eq(StrUtil.isNotEmpty(dto.getAttendanceMode()), AttendanceUserRelation::getAttendanceMode, dto.getAttendanceMode())
                     .like(StrUtil.isNotEmpty(dto.getCarNumber()), AttendanceUserRelation::getCarNumber, dto.getCarNumber())
@@ -95,11 +98,9 @@ public class TeacherStatisticsController {
                     .selectAs(User::getName, TeacherStatisticsPageVo::getTeacherName)
                     .selectAs(User::getId, TeacherStatisticsPageVo::getUserId)
                     .selectAs(User::getMobile, TeacherStatisticsPageVo::getMobile)
-                    .selectAs(Department::getName, TeacherStatisticsPageVo::getDeptName)
                     .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, User::getId)
                     .innerJoin(UserDeptRelation.class, UserDeptRelation::getUserId, User::getId)
-                    .leftJoin(AttendanceUserRelation.class, AttendanceUserRelation::getUserId, User::getId)
-                    .leftJoin(Department.class, Department::getId, UserDeptRelation::getDeptId);
+                    .leftJoin(AttendanceUserRelation.class, AttendanceUserRelation::getUserId, User::getId);
             IPage<TeacherStatisticsPageVo> voIPage = xjrUserService.selectJoinListPage(ConventPage.getPage(dto), TeacherStatisticsPageVo.class, queryUser);
 
             if(dto.getDate() != null && !"".equals(dto.getDate())){

+ 25 - 0
src/main/java/com/xjrsoft/module/attendance/dto/ResetTeacherAttendanceRecordDto.java

@@ -0,0 +1,25 @@
+package com.xjrsoft.module.attendance.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+
+
+/**
+* @title: 教师考勤记录
+* @Author dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Data
+public class ResetTeacherAttendanceRecordDto{
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @ApiModelProperty("考勤日期")
+    private LocalDate attendanceDate;
+
+    @ApiModelProperty("时段(1:上午,2:下午,3:晚上)")
+    private Integer timeInterval;
+}

+ 3 - 0
src/main/java/com/xjrsoft/module/attendance/service/ITeacherAttendanceRecordService.java

@@ -2,6 +2,7 @@ package com.xjrsoft.module.attendance.service;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.yulichang.base.MPJBaseService;
+import com.xjrsoft.module.attendance.dto.ResetTeacherAttendanceRecordDto;
 import com.xjrsoft.module.attendance.dto.TeacherDetailsDto;
 import com.xjrsoft.module.attendance.entity.TeacherAttendanceRecord;
 import com.xjrsoft.module.attendance.vo.TeacherStatisticsPageVo;
@@ -21,4 +22,6 @@ public interface ITeacherAttendanceRecordService extends MPJBaseService<TeacherA
     Page<TeacherStatisticsPageVo> getPage(Page<TeacherStatisticsPageVo> page, TeacherDetailsDto dto);
 
     List<TeacherStatisticsPageVo> getList(TeacherDetailsDto dto);
+
+    Boolean resetData(ResetTeacherAttendanceRecordDto dto);
 }

+ 42 - 0
src/main/java/com/xjrsoft/module/attendance/service/impl/TeacherAttendanceRecordServiceImpl.java

@@ -2,14 +2,28 @@ package com.xjrsoft.module.attendance.service.impl;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.yulichang.base.MPJBaseServiceImpl;
+import com.xjrsoft.common.exception.MyException;
+import com.xjrsoft.common.mybatis.SqlRunnerAdapter;
+import com.xjrsoft.module.attendance.dto.ResetTeacherAttendanceRecordDto;
 import com.xjrsoft.module.attendance.dto.TeacherDetailsDto;
 import com.xjrsoft.module.attendance.entity.TeacherAttendanceRecord;
 import com.xjrsoft.module.attendance.mapper.TeacherAttendanceRecordMapper;
+import com.xjrsoft.module.attendance.service.IAttendanceRuleCategoryService;
 import com.xjrsoft.module.attendance.service.ITeacherAttendanceRecordService;
 import com.xjrsoft.module.attendance.vo.TeacherStatisticsPageVo;
+import com.xjrsoft.module.holiday.service.IHolidayDateService;
+import com.xjrsoft.module.job.AttendanceRecordTask;
+import com.xjrsoft.module.organization.service.IUserService;
+import com.xjrsoft.module.outint.service.ICarOutInRecordService;
+import com.xjrsoft.module.outint.service.ITeacherOutInRecordService;
+import com.xjrsoft.module.teacher.service.IWfTeacherleaveService;
 import lombok.AllArgsConstructor;
+import me.zhyd.oauth.log.Log;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.List;
 
 /**
@@ -21,6 +35,12 @@ import java.util.List;
 @Service
 @AllArgsConstructor
 public class TeacherAttendanceRecordServiceImpl extends MPJBaseServiceImpl<TeacherAttendanceRecordMapper, TeacherAttendanceRecord> implements ITeacherAttendanceRecordService {
+    private final IUserService userService;
+    private final IAttendanceRuleCategoryService ruleCategoryService;
+    private final IHolidayDateService holidayDateService;
+    private final IWfTeacherleaveService wfTeacherleaveService;
+    private final ITeacherOutInRecordService outInRecordService;
+    private final ICarOutInRecordService carOutInRecordService;
     @Override
     public Page<TeacherStatisticsPageVo> getPage(Page<TeacherStatisticsPageVo> page, TeacherDetailsDto dto) {
         return this.baseMapper.getPage(page, dto);
@@ -30,4 +50,26 @@ public class TeacherAttendanceRecordServiceImpl extends MPJBaseServiceImpl<Teach
     public List<TeacherStatisticsPageVo> getList(TeacherDetailsDto dto) {
         return this.baseMapper.getList(dto);
     }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean resetData(ResetTeacherAttendanceRecordDto dto) {
+        try {
+            LocalDateTime startDateTime = dto.getAttendanceDate().atTime(0,0,0);
+            AttendanceRecordTask recordTask = new AttendanceRecordTask();
+            recordTask.teacherAttendanceRecord(startDateTime, dto.getTimeInterval(),
+                    userService,
+                    ruleCategoryService,
+                    holidayDateService,
+                    wfTeacherleaveService,
+                    outInRecordService,
+                    carOutInRecordService,
+                    this
+            );
+        }catch (Exception e){
+            Log.error(e.getMessage(), e);
+            throw new MyException("同步出错,请联系管理员");
+        }
+        return true;
+    }
 }

+ 6 - 0
src/main/java/com/xjrsoft/module/courseTable/dto/ClassTeacherDto.java

@@ -30,4 +30,10 @@ public class ClassTeacherDto implements Serializable {
 
     @ApiModelProperty("结束日期")
     private LocalDate endDate;
+
+    @ApiModelProperty("调顶课申请id")
+    private Long wfCourseAdjustId;
+
+    @ApiModelProperty("顶课老师id")
+    private Long teacherId;
 }

+ 2 - 0
src/main/java/com/xjrsoft/module/courseTable/mapper/CourseTableMapper.java

@@ -38,4 +38,6 @@ public interface CourseTableMapper extends MPJBaseMapper<CourseTable> {
     List<ClassTeacherVo> getClassTeacherIds(@Param("dto") ClassTeacherDto dto);
 
     List<Long> getExceptCourseIds(@Param("userId") Long userId);
+
+    Integer getSubstituteTeacherCourseCountByParams(@Param("dto") ClassTeacherDto dto);
 }

+ 5 - 0
src/main/java/com/xjrsoft/module/courseTable/service/ICourseTableService.java

@@ -2,6 +2,7 @@ package com.xjrsoft.module.courseTable.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.xjrsoft.module.courseTable.dto.ClassListDto;
+import com.xjrsoft.module.courseTable.dto.ClassTeacherDto;
 import com.xjrsoft.module.courseTable.entity.CourseTable;
 import com.xjrsoft.module.courseTable.vo.ClassListVo;
 import com.xjrsoft.module.schedule.dto.ClassOptionDto;
@@ -11,6 +12,7 @@ import com.xjrsoft.module.schedule.entity.WfCourseAdjust;
 import com.xjrsoft.module.schedule.vo.ClassOptionVo;
 import com.xjrsoft.module.schedule.vo.CourseListVo;
 import com.xjrsoft.module.schedule.vo.CourseTableVo;
+import org.apache.ibatis.annotations.Param;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -55,4 +57,7 @@ public interface ICourseTableService extends IService<CourseTable> {
     ByteArrayOutputStream scheduleWeekExportQuery(CourseTableDto dto);
 
 
+    Integer getSubstituteTeacherCourseCountByParams(ClassTeacherDto dto);
+
+
 }

+ 6 - 0
src/main/java/com/xjrsoft/module/courseTable/service/impl/CourseTableServiceImpl.java

@@ -36,6 +36,7 @@ import com.xjrsoft.module.base.mapper.BaseSemesterMapper;
 import com.xjrsoft.module.base.service.IBaseClassService;
 import com.xjrsoft.module.base.service.IBaseSemesterService;
 import com.xjrsoft.module.courseTable.dto.ClassListDto;
+import com.xjrsoft.module.courseTable.dto.ClassTeacherDto;
 import com.xjrsoft.module.courseTable.dto.CourseTableParse;
 import com.xjrsoft.module.courseTable.entity.ClassTime;
 import com.xjrsoft.module.courseTable.entity.CourseTable;
@@ -65,6 +66,7 @@ import com.xjrsoft.module.teacher.entity.XjrUser;
 import com.xjrsoft.module.teacher.service.ITeacherbaseManagerService;
 import lombok.AllArgsConstructor;
 import me.zhyd.oauth.log.Log;
+import org.apache.ibatis.annotations.Param;
 import org.apache.poi.ss.usermodel.BorderStyle;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellStyle;
@@ -1249,4 +1251,8 @@ public class CourseTableServiceImpl extends ServiceImpl<CourseTableMapper, Cours
 //        sheet.setColumnWidth(0, 335 * 256);
     }
 
+    public Integer getSubstituteTeacherCourseCountByParams(ClassTeacherDto dto){
+        return this.baseMapper.getSubstituteTeacherCourseCountByParams(dto);
+    }
+
 }

+ 90 - 54
src/main/java/com/xjrsoft/module/job/AttendanceRecordTask.java

@@ -192,39 +192,57 @@ public class AttendanceRecordTask {
             outInDto.setStatus(OutInStatusEnum.enter.getCode());
             outInDto.setUserId(record.getUserId());
             List<TeacherOutInRecord> outInRecords = teacherOutInRecordService.getListByParam(outInDto);
-            if(!outInRecords.isEmpty()){
+
+            //查询该教师是否通过车辆进入
+            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 == 2, CarOutInRecord::getRecordTime, amEndTime)
+                            .eq(CarOutInRecord::getStatus, OutInStatusEnum.enter.getCode())
+                            .orderByAsc(CarOutInRecord::getRecordTime)
+            );
+            //最早进入方式:1人脸 2车辆
+            Integer inStatus = 0;
+            if(!outInRecords.isEmpty() && !list.isEmpty()){
+                TeacherOutInRecord teacherOutInRecord = outInRecords.get(0);
+                CarOutInRecord carOutInRecord = list.get(0);
+                int result = teacherOutInRecord.getRecordTime().compareTo(carOutInRecord.getRecordTime());
+                if(result < 0){//人脸进入
+                    inStatus = 1;
+                }else if(result == 0){//同时
+                    inStatus = 0;
+                }else{//车辆进入
+                    inStatus = 2;
+                }
+            }else if(!outInRecords.isEmpty()){
+                inStatus = 1;
+            }else if(!list.isEmpty()){
+                inStatus = 2;
+            }
+
+            if(inStatus == 1){
                 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());
-                    }
+            }else if(inStatus == 2){
+                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());
                 }
             }
 
@@ -349,39 +367,57 @@ public class AttendanceRecordTask {
             outInDto.setStatus(OutInStatusEnum.enter.getCode());
             outInDto.setUserId(record.getUserId());
             List<TeacherOutInRecord> outInRecords = teacherOutInRecordService.getListByParam(outInDto);
-            if(!outInRecords.isEmpty()){
+
+            //查询该教师是否通过车辆进入
+            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 == 2, CarOutInRecord::getRecordTime, amEndTime)
+                            .eq(CarOutInRecord::getStatus, OutInStatusEnum.enter.getCode())
+                            .orderByAsc(CarOutInRecord::getRecordTime)
+            );
+            //最早进入方式:1人脸 2车辆
+            Integer inStatus = 0;
+            if(!outInRecords.isEmpty() && !list.isEmpty()){
+                TeacherOutInRecord teacherOutInRecord = outInRecords.get(0);
+                CarOutInRecord carOutInRecord = list.get(0);
+                int result = teacherOutInRecord.getRecordTime().compareTo(carOutInRecord.getRecordTime());
+                if(result < 0){//人脸进入
+                    inStatus = 1;
+                }else if(result == 0){//同时
+                    inStatus = 0;
+                }else{//车辆进入
+                    inStatus = 2;
+                }
+            }else if(!outInRecords.isEmpty()){
+                inStatus = 1;
+            }else if(!list.isEmpty()){
+                inStatus = 2;
+            }
+
+            if(inStatus == 1){
                 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 == 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());
-                    }
+            }else if(inStatus == 2){
+                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());
                 }
             }
 

+ 8 - 1
src/main/java/com/xjrsoft/module/job/JianyuekbScheduleTask.java

@@ -19,6 +19,7 @@ import com.xjrsoft.common.utils.VoToColumnUtil;
 import com.xjrsoft.config.CommonPropertiesConfig;
 import com.xjrsoft.module.base.entity.BaseClass;
 import com.xjrsoft.module.base.service.IBaseClassService;
+import com.xjrsoft.module.courseTable.dto.ClassTeacherDto;
 import com.xjrsoft.module.courseTable.entity.CourseTable;
 import com.xjrsoft.module.courseTable.service.ICourseTableService;
 import com.xjrsoft.module.organization.dto.WeChatSendMessageDto;
@@ -297,6 +298,7 @@ public class JianyuekbScheduleTask {
      * 课程数据同步完之后,处理调课和顶课申请
      * 1、课程数据入库后,将新课表日期之后的的调课顶课数据再次更新到课表中
      * 2、筛选出课表变化了的调课和顶课申请,通知发起人
+     * 3、顶课数据,如果顶课日期那天那个老师没有课,但是新发布的课表又有课了,需要把原来的顶课数据作废
      */
     public void handleCourseAdjust(List<BaseClass> classList, String startDate, String endDate){
         List<Long> classIds = classList.stream().map(BaseClass::getId).collect(Collectors.toList());
@@ -348,7 +350,12 @@ public class JianyuekbScheduleTask {
                 exchangeCourseIds = courseAdjust.getExchangeCourseId().split(",");
                 courseCount += exchangeCourseIds.length;
             }
-            if(courseList.size() != courseCount){
+            //查询顶课老师在本条申请的课程中的节次是否包含课
+            Integer substituteTeacherCourseCount = courseTableService.getSubstituteTeacherCourseCountByParams(new ClassTeacherDto() {{
+                setWfCourseAdjustId(courseAdjust.getId());
+                setTeacherId(courseAdjust.getExchangeTeacherId());
+            }});
+            if(courseList.size() != courseCount || substituteTeacherCourseCount > 0){
                 //表明课程变化了,需要重新申请,需要将原来的申请作废并进行微信消息通知
                 courseAdjust.setEnabledMark(EnabledMark.DISABLED.getCode());
                 courseAdjust.setModifyDate(new Date());

+ 347 - 0
src/main/java/com/xjrsoft/module/ledger/controller/LedgerStatisticsController.java

@@ -0,0 +1,347 @@
+package com.xjrsoft.module.ledger.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.support.ExcelTypeEnum;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.xjrsoft.common.model.result.RT;
+import com.xjrsoft.common.mybatis.SqlRunnerAdapter;
+import com.xjrsoft.common.page.ConventPage;
+import com.xjrsoft.common.page.PageOutput;
+import com.xjrsoft.common.utils.VoToColumnUtil;
+import com.xjrsoft.module.ledger.dto.LedgerStatisticsPageDto;
+import com.xjrsoft.module.ledger.vo.LedgerStatisticsLeaveVo;
+import com.xjrsoft.module.ledger.vo.LedgerStatisticsListenVo;
+import com.xjrsoft.module.ledger.vo.LedgerStatisticsOvertimeVo;
+import com.xjrsoft.module.organization.entity.User;
+import com.xjrsoft.module.organization.service.IUserService;
+import com.xjrsoft.module.organization.vo.UserPageVo;
+import com.xjrsoft.module.teacher.entity.BaseTeacher;
+import com.xjrsoft.module.teacher.entity.WfTeacherleave;
+import com.xjrsoft.module.teacher.service.IWfTeacherleaveService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+import java.io.ByteArrayOutputStream;
+import java.text.DecimalFormat;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+* @title: 台账统计
+* @Author dzx
+* @Date: 2024年11月29日
+* @Version 1.0
+*/
+@RestController
+@RequestMapping("/ledger" + "/ledgerStatistics")
+@Api(value = "/ledger"  + "/ledgerStatistics",tags = "台账统计代码")
+@AllArgsConstructor
+public class LedgerStatisticsController {
+
+
+    private final IUserService userService;
+    private final IWfTeacherleaveService teacherleaveService;
+
+    @GetMapping(value = "/teacher-leave-page")
+    @ApiOperation(value="教师请假统计(分页)")
+    @SaCheckPermission("ledgerstatistics:detail")
+    public RT<PageOutput<LedgerStatisticsLeaveVo>> teacherLeavePage(@Valid LedgerStatisticsPageDto dto){
+        IPage<LedgerStatisticsLeaveVo> userPage = userService.selectJoinListPage(ConventPage.getPage(dto), LedgerStatisticsLeaveVo.class,
+                new MPJLambdaWrapper<User>()
+                        .disableSubLogicDel()
+                        .select(User::getId)
+                        .select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()))
+                        .select(" (SELECT GROUP_CONCAT(t1.name) FROM xjr_department t1" +
+                                " INNER JOIN xjr_user_dept_relation t2 ON t1.id = t2.dept_id" +
+                                " WHERE t1.delete_mark = 0 AND t2.user_id = t.id) as dept_name")
+                        .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, User::getId)
+                        .like(StrUtil.isNotEmpty(dto.getName()), User::getName, dto.getName())
+                        .orderByAsc(User::getId)
+        );
+        LocalDateTime startTime = null;
+        LocalDateTime endTime = null;
+        if(dto.getStartDate() != null && dto.getEndDate() != null){
+            startTime = dto.getStartDate().atTime(0,0,0);
+            endTime = dto.getEndDate().atTime(23,59,59);
+        }
+        Map<String, List<WfTeacherleave>> userLeaveMap = teacherleaveService.getUserLeaveList(startTime, endTime);
+
+        for (LedgerStatisticsLeaveVo record : userPage.getRecords()) {
+            List<WfTeacherleave> wfTeacherleaves = userLeaveMap.get(record.getId().toString());
+            if(wfTeacherleaves == null || wfTeacherleaves.isEmpty()){
+                continue;
+            }
+            double value = wfTeacherleaves.stream().mapToDouble(WfTeacherleave::getLeaveDays).sum();
+            boolean isInteger = (value % 1) == 0;
+            DecimalFormat df = new DecimalFormat(isInteger ? "0" : "#.##");
+            String formattedValue = df.format(value);
+            record.setLeaveDays(formattedValue);
+        }
+
+        PageOutput<LedgerStatisticsLeaveVo> pageOutput = ConventPage.getPageOutput(userPage, LedgerStatisticsLeaveVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @PostMapping(value = "/teacher-leave-export-query")
+    @ApiOperation(value="教师请假统计-导出")
+    @SaCheckPermission("ledgerstatistics:detail")
+    public ResponseEntity<byte[]> teacherLeaveExportQuery(@Valid @RequestBody LedgerStatisticsPageDto dto){
+        List<LedgerStatisticsLeaveVo> list = userService.selectJoinList(LedgerStatisticsLeaveVo.class,
+                new MPJLambdaWrapper<User>()
+                        .disableSubLogicDel()
+                        .select(User::getId)
+                        .select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()))
+                        .select(" (SELECT GROUP_CONCAT(t1.name) FROM xjr_department t1" +
+                                " INNER JOIN xjr_user_dept_relation t2 ON t1.id = t2.dept_id" +
+                                " WHERE t1.delete_mark = 0 AND t2.user_id = t.id) as dept_name")
+                        .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, User::getId)
+                        .like(StrUtil.isNotEmpty(dto.getName()), User::getName, dto.getName())
+                        .orderByAsc(User::getId)
+        );
+        LocalDateTime startTime = null;
+        LocalDateTime endTime = null;
+        if(dto.getStartDate() != null && dto.getEndDate() != null){
+            startTime = dto.getStartDate().atTime(0,0,0);
+            endTime = dto.getEndDate().atTime(23,59,59);
+        }
+        Map<String, List<WfTeacherleave>> userLeaveMap = teacherleaveService.getUserLeaveList(startTime, endTime);
+        int sortCode = 1;
+        for (LedgerStatisticsLeaveVo record : list) {
+            List<WfTeacherleave> wfTeacherleaves = userLeaveMap.get(record.getId().toString());
+            if(wfTeacherleaves == null || wfTeacherleaves.isEmpty()){
+                continue;
+            }
+            double value = wfTeacherleaves.stream().mapToDouble(WfTeacherleave::getLeaveDays).sum();
+            boolean isInteger = (value % 1) == 0;
+            DecimalFormat df = new DecimalFormat(isInteger ? "0" : "#.##");
+            String formattedValue = df.format(value);
+            record.setLeaveDays(formattedValue);
+            record.setSortCode(sortCode);
+            sortCode ++;
+        }
+
+        ByteArrayOutputStream bot = new ByteArrayOutputStream();
+        EasyExcel.write(bot, LedgerStatisticsLeaveVo.class).automaticMergeHead(false).excelType(ExcelTypeEnum.XLSX).sheet().doWrite(list);
+
+        return RT.fileStream(bot.toByteArray(), "teacher-leave" + ExcelTypeEnum.XLSX.getValue());
+    }
+
+    @GetMapping(value = "/teacher-overtime-page")
+    @ApiOperation(value="教师加班统计(分页)")
+    @SaCheckPermission("ledgerstatistics:detail")
+    public RT<PageOutput<LedgerStatisticsOvertimeVo>> teacherOvertimePage(@Valid LedgerStatisticsPageDto dto){
+        IPage<LedgerStatisticsOvertimeVo> userPage = userService.selectJoinListPage(ConventPage.getPage(dto), LedgerStatisticsOvertimeVo.class,
+                new MPJLambdaWrapper<User>()
+                        .disableSubLogicDel()
+                        .select(User::getId)
+                        .select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()))
+                        .select(" (SELECT GROUP_CONCAT(t1.name) FROM xjr_department t1" +
+                                " INNER JOIN xjr_user_dept_relation t2 ON t1.id = t2.dept_id" +
+                                " WHERE t1.delete_mark = 0 AND t2.user_id = t.id) as dept_name")
+                        .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, User::getId)
+                        .like(StrUtil.isNotEmpty(dto.getName()), User::getName, dto.getName())
+                        .orderByAsc(User::getId)
+        );
+        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        String sql = "SELECT t4.teacher_user_id,SUM(t.total_days) as total_days FROM wf_overtime t" +
+                " LEFT JOIN xjr_user t1 ON t1.id = t.user_id" +
+                " LEFT JOIN xjr_user t3 ON t3.id = t.leader_in_charge" +
+                " LEFT JOIN xjr_workflow_form_relation t2 ON t.id = t2.form_key_value" +
+                " LEFT JOIN wf_overtime_teacher t4 ON t.id = t4.wf_overtime_id" +
+                " WHERE t2.current_state = 'COMPLETED'";
+        if(dto.getStartDate() != null && dto.getEndDate() != null){
+            String startTime = dto.getStartDate().atTime(0,0,0).format(dtf);
+            String endTime = dto.getEndDate().atTime(23,59,59).format(dtf);
+            sql += " AND (" +
+                "   (t.overtime_start_time BETWEEN '" + startTime + "' and '" + endTime + "')" +
+                "   OR (t.overtime_end_time BETWEEN '" + startTime + "' and '" + endTime + "')" +
+                "   OR (t.overtime_start_time > '" + startTime + "' and '" + endTime + "' > t.overtime_end_time)" +
+                "   OR ('" + startTime + "' > t.overtime_start_time and t.overtime_end_time > '" + endTime + "')" +
+                ")";
+        }
+        sql += " GROUP BY t4.teacher_user_id";
+        List<Map<String, Object>> list = SqlRunnerAdapter.db().selectList(sql);
+        Map<Long, String> userLeaveMap = list.stream().collect(
+                Collectors.toMap(x -> Long.parseLong(x.get("teacher_user_id").toString()), x -> x.get("total_days").toString())
+        );
+        for (LedgerStatisticsOvertimeVo record : userPage.getRecords()) {
+            if(!userLeaveMap.containsKey(record.getId())){
+                continue;
+            }
+            double value = Double.parseDouble(userLeaveMap.get(record.getId()));
+            boolean isInteger = (value % 1) == 0;
+            DecimalFormat df = new DecimalFormat(isInteger ? "0" : "#.##");
+            String formattedValue = df.format(value);
+            record.setTotalDays(formattedValue);
+        }
+
+        PageOutput<LedgerStatisticsOvertimeVo> pageOutput = ConventPage.getPageOutput(userPage, LedgerStatisticsOvertimeVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @PostMapping(value = "/teacher-overtime-export-query")
+    @ApiOperation(value="教师加班统计-导出")
+    @SaCheckPermission("ledgerstatistics:detail")
+    public ResponseEntity<byte[]> teacherOvertimeExportQuery(@Valid @RequestBody LedgerStatisticsPageDto dto){
+        List<LedgerStatisticsOvertimeVo> userPage = userService.selectJoinList(LedgerStatisticsOvertimeVo.class,
+                new MPJLambdaWrapper<User>()
+                        .disableSubLogicDel()
+                        .select(User::getId)
+                        .select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()))
+                        .select(" (SELECT GROUP_CONCAT(t1.name) FROM xjr_department t1" +
+                                " INNER JOIN xjr_user_dept_relation t2 ON t1.id = t2.dept_id" +
+                                " WHERE t1.delete_mark = 0 AND t2.user_id = t.id) as dept_name")
+                        .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, User::getId)
+                        .like(StrUtil.isNotEmpty(dto.getName()), User::getName, dto.getName())
+                        .orderByAsc(User::getId)
+        );
+        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        String sql = "SELECT t4.teacher_user_id,SUM(t.total_days) as total_days FROM wf_overtime t" +
+                " LEFT JOIN xjr_user t1 ON t1.id = t.user_id" +
+                " LEFT JOIN xjr_user t3 ON t3.id = t.leader_in_charge" +
+                " LEFT JOIN xjr_workflow_form_relation t2 ON t.id = t2.form_key_value" +
+                " LEFT JOIN wf_overtime_teacher t4 ON t.id = t4.wf_overtime_id" +
+                " WHERE t2.current_state = 'COMPLETED'";
+        if(dto.getStartDate() != null && dto.getEndDate() != null){
+            String startTime = dto.getStartDate().atTime(0,0,0).format(dtf);
+            String endTime = dto.getEndDate().atTime(23,59,59).format(dtf);
+            sql += " AND (" +
+                    "   (t.overtime_start_time BETWEEN '" + startTime + "' and '" + endTime + "')" +
+                    "   OR (t.overtime_end_time BETWEEN '" + startTime + "' and '" + endTime + "')" +
+                    "   OR (t.overtime_start_time > '" + startTime + "' and '" + endTime + "' > t.overtime_end_time)" +
+                    "   OR ('" + startTime + "' > t.overtime_start_time and t.overtime_end_time > '" + endTime + "')" +
+                    ")";
+        }
+        sql += " GROUP BY t4.teacher_user_id";
+        List<Map<String, Object>> list = SqlRunnerAdapter.db().selectList(sql);
+        Map<Long, String> userLeaveMap = list.stream().collect(
+                Collectors.toMap(x -> Long.parseLong(x.get("teacher_user_id").toString()), x -> x.get("total_days").toString())
+        );
+        for (LedgerStatisticsOvertimeVo record : userPage) {
+            if(!userLeaveMap.containsKey(record.getId())){
+                continue;
+            }
+            double value = Double.parseDouble(userLeaveMap.get(record.getId()));
+            boolean isInteger = (value % 1) == 0;
+            DecimalFormat df = new DecimalFormat(isInteger ? "0" : "#.##");
+            String formattedValue = df.format(value);
+            record.setTotalDays(formattedValue);
+        }
+
+        ByteArrayOutputStream bot = new ByteArrayOutputStream();
+        EasyExcel.write(bot, LedgerStatisticsOvertimeVo.class).automaticMergeHead(false).excelType(ExcelTypeEnum.XLSX).sheet().doWrite(list);
+
+        return RT.fileStream(bot.toByteArray(), "teacher-overtime" + ExcelTypeEnum.XLSX.getValue());
+    }
+
+    @GetMapping(value = "/teacher-listen-page")
+    @ApiOperation(value="教师听课统计(分页)")
+    @SaCheckPermission("ledgerstatistics:detail")
+    public RT<PageOutput<LedgerStatisticsListenVo>> teacherListenPage(@Valid LedgerStatisticsPageDto dto){
+        IPage<LedgerStatisticsListenVo> userPage = userService.selectJoinListPage(ConventPage.getPage(dto), LedgerStatisticsListenVo.class,
+                new MPJLambdaWrapper<User>()
+                        .disableSubLogicDel()
+                        .select(User::getId)
+                        .select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()))
+                        .select(" (SELECT GROUP_CONCAT(t1.name) FROM xjr_department t1" +
+                                " INNER JOIN xjr_user_dept_relation t2 ON t1.id = t2.dept_id" +
+                                " WHERE t1.delete_mark = 0 AND t2.user_id = t.id) as dept_name")
+                        .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, User::getId)
+                        .like(StrUtil.isNotEmpty(dto.getName()), User::getName, dto.getName())
+                        .orderByAsc(User::getId)
+        );
+        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+        String sql = "SELECT t1.user_id,count(t1.course_name) as course_count FROM wf_teacher_listen t1" +
+                " LEFT JOIN xjr_workflow_form_relation t2 ON t1.id = t2.form_key_value" +
+                " WHERE t2.current_state = 'COMPLETED'";
+        if(dto.getStartDate() != null && dto.getEndDate() != null){
+            String startTime = dto.getStartDate().format(dtf);
+            String endTime = dto.getEndDate().format(dtf);
+            sql += " AND t1.schedule_date BETWEEN '" + startTime + "' and '" + endTime + "'";
+        }
+        sql += " GROUP BY t1.user_id";
+        List<Map<String, Object>> list = SqlRunnerAdapter.db().selectList(sql);
+        Map<Long, String> userLeaveMap = list.stream().collect(
+                Collectors.toMap(x -> Long.parseLong(x.get("user_id").toString()), x -> x.get("course_count").toString())
+        );
+        for (LedgerStatisticsListenVo record : userPage.getRecords()) {
+            if(!userLeaveMap.containsKey(record.getId())){
+                continue;
+            }
+            double value = Double.parseDouble(userLeaveMap.get(record.getId()));
+            boolean isInteger = (value % 1) == 0;
+            DecimalFormat df = new DecimalFormat(isInteger ? "0" : "#.##");
+            String formattedValue = df.format(value);
+            record.setCourseCount(formattedValue);
+        }
+
+        PageOutput<LedgerStatisticsListenVo> pageOutput = ConventPage.getPageOutput(userPage, LedgerStatisticsListenVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @GetMapping(value = "/teacher-listen-export-query")
+    @ApiOperation(value="教师听课统计-导出")
+    @SaCheckPermission("ledgerstatistics:detail")
+    public ResponseEntity<byte[]> teacherListenExportQuery(@Valid @RequestBody LedgerStatisticsPageDto dto){
+        List<LedgerStatisticsListenVo> userPage = userService.selectJoinList(LedgerStatisticsListenVo.class,
+                new MPJLambdaWrapper<User>()
+                        .disableSubLogicDel()
+                        .select(User::getId)
+                        .select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()))
+                        .select(" (SELECT GROUP_CONCAT(t1.name) FROM xjr_department t1" +
+                                " INNER JOIN xjr_user_dept_relation t2 ON t1.id = t2.dept_id" +
+                                " WHERE t1.delete_mark = 0 AND t2.user_id = t.id) as dept_name")
+                        .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, User::getId)
+                        .like(StrUtil.isNotEmpty(dto.getName()), User::getName, dto.getName())
+                        .orderByAsc(User::getId)
+        );
+        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+        String sql = "SELECT t1.user_id,count(t1.course_name) as course_count FROM wf_teacher_listen t1" +
+                " LEFT JOIN xjr_workflow_form_relation t2 ON t1.id = t2.form_key_value" +
+                " WHERE t2.current_state = 'COMPLETED'";
+        if(dto.getStartDate() != null && dto.getEndDate() != null){
+            String startTime = dto.getStartDate().format(dtf);
+            String endTime = dto.getEndDate().format(dtf);
+            sql += " AND t1.schedule_date BETWEEN '" + startTime + "' and '" + endTime + "'";
+        }
+        sql += " GROUP BY t1.user_id";
+        List<Map<String, Object>> list = SqlRunnerAdapter.db().selectList(sql);
+        Map<Long, String> userLeaveMap = list.stream().collect(
+                Collectors.toMap(x -> Long.parseLong(x.get("user_id").toString()), x -> x.get("course_count").toString())
+        );
+        for (LedgerStatisticsListenVo record : userPage) {
+            if(!userLeaveMap.containsKey(record.getId())){
+                continue;
+            }
+            double value = Double.parseDouble(userLeaveMap.get(record.getId()));
+            boolean isInteger = (value % 1) == 0;
+            DecimalFormat df = new DecimalFormat(isInteger ? "0" : "#.##");
+            String formattedValue = df.format(value);
+            record.setCourseCount(formattedValue);
+        }
+
+        ByteArrayOutputStream bot = new ByteArrayOutputStream();
+        EasyExcel.write(bot, LedgerStatisticsListenVo.class).automaticMergeHead(false).excelType(ExcelTypeEnum.XLSX).sheet().doWrite(list);
+
+        return RT.fileStream(bot.toByteArray(), "teacher-listen" + ExcelTypeEnum.XLSX.getValue());
+    }
+
+}

+ 38 - 0
src/main/java/com/xjrsoft/module/ledger/dto/LedgerStatisticsPageDto.java

@@ -0,0 +1,38 @@
+package com.xjrsoft.module.ledger.dto;
+
+import com.xjrsoft.common.page.PageInput;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+
+
+/**
+* @title: 台账配置表分页查询入参
+* @Author dzx
+* @Date: 2024-03-06
+* @Version 1.0
+*/
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class LedgerStatisticsPageDto extends PageInput {
+
+    @ApiModelProperty("姓名")
+    private String name;
+
+    @ApiModelProperty("工号")
+    private String userName;
+
+    @ApiModelProperty("所属部门")
+    private String deptName;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @ApiModelProperty("请假开始日期")
+    private LocalDate startDate;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @ApiModelProperty("请假结束日期")
+    private LocalDate endDate;
+}

+ 21 - 0
src/main/java/com/xjrsoft/module/ledger/vo/LedgerStatisticsLeaveVo.java

@@ -0,0 +1,21 @@
+package com.xjrsoft.module.ledger.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+/**
+* @title: 台账配置表分页查询入参
+* @Author dzx
+* @Date: 2024-03-06
+* @Version 1.0
+*/
+@Data
+public class LedgerStatisticsLeaveVo extends LedgerStatisticsPageVo{
+
+    @ExcelProperty("请假天数")
+    @ApiModelProperty("请假天数")
+    private String leaveDays;
+
+}

+ 21 - 0
src/main/java/com/xjrsoft/module/ledger/vo/LedgerStatisticsListenVo.java

@@ -0,0 +1,21 @@
+package com.xjrsoft.module.ledger.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+/**
+* @title: 台账配置表分页查询入参
+* @Author dzx
+* @Date: 2024-03-06
+* @Version 1.0
+*/
+@Data
+public class LedgerStatisticsListenVo extends LedgerStatisticsPageVo{
+
+    @ExcelProperty("听课次数")
+    @ApiModelProperty("听课次数")
+    private String courseCount;
+
+}

+ 21 - 0
src/main/java/com/xjrsoft/module/ledger/vo/LedgerStatisticsOvertimeVo.java

@@ -0,0 +1,21 @@
+package com.xjrsoft.module.ledger.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+/**
+* @title: 台账配置表分页查询入参
+* @Author dzx
+* @Date: 2024-03-06
+* @Version 1.0
+*/
+@Data
+public class LedgerStatisticsOvertimeVo extends LedgerStatisticsPageVo{
+
+    @ExcelProperty("加班天数")
+    @ApiModelProperty("加班天数")
+    private String totalDays;
+
+}

+ 36 - 0
src/main/java/com/xjrsoft/module/ledger/vo/LedgerStatisticsPageVo.java

@@ -0,0 +1,36 @@
+package com.xjrsoft.module.ledger.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+/**
+* @title: 台账配置表分页查询入参
+* @Author dzx
+* @Date: 2024-03-06
+* @Version 1.0
+*/
+@Data
+public class LedgerStatisticsPageVo {
+
+    @ApiModelProperty("主键id")
+    private Long id;
+
+    @ExcelProperty("序号")
+    @ApiModelProperty("序号")
+    private Integer sortCode;
+
+    @ExcelProperty("请假人")
+    @ApiModelProperty("请假人")
+    private String name;
+
+    @ExcelProperty("工号")
+    @ApiModelProperty("工号")
+    private String userName;
+
+    @ExcelProperty("所属部门")
+    @ApiModelProperty("所属部门")
+    private String deptName;
+
+}

+ 1 - 1
src/main/java/com/xjrsoft/module/liteflow/node/StudentDropOutNode.java

@@ -106,7 +106,7 @@ public class StudentDropOutNode extends NodeComponent {
                         studentSchoolRollService.updateById(schoolRoll);
 
                         //删除海康出入权限
-                        String hikvisionId = hikvisionDataMapper.getStudentHikvisionId(studentDropOut.getClassId());
+                        String hikvisionId = hikvisionDataMapper.getStudentHikvisionId(studentDropOut.getStudentUserId());
                         ApiUtil apiUtil = new ApiUtil();
                         String apiPath = "/api/pmas/v1/person/batch/delete";
                         JsonObject paramJson = new JsonObject();

+ 0 - 2
src/main/java/com/xjrsoft/module/outint/controller/TeacherOutInRecordController.java

@@ -128,8 +128,6 @@ public class TeacherOutInRecordController {
     @ApiOperation(value = "同步教师出入记录")
     @SaCheckPermission("teacheroutinrecord:add")
     public RT<Boolean> syncHikvisionData(@Valid @RequestBody SyncHikvsionDataDto dto){
-
-
         return RT.ok(teacherOutInRecordService.syncHikvisionData(dto));
     }
 

+ 36 - 15
src/main/java/com/xjrsoft/module/outint/service/impl/TeacherOutInRecordServiceImpl.java

@@ -1,12 +1,17 @@
 package com.xjrsoft.module.outint.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.github.yulichang.base.MPJBaseServiceImpl;
 import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 import com.xjrsoft.common.exception.MyException;
+import com.xjrsoft.module.hikvision.entity.HikvisionData;
+import com.xjrsoft.module.hikvision.service.IHikvisionDataService;
 import com.xjrsoft.module.hikvision.util.ApiUtil;
 import com.xjrsoft.module.hikvision.util.OutInRecordUtil;
+import com.xjrsoft.module.organization.service.IUserService;
 import com.xjrsoft.module.outint.dto.SyncHikvsionDataDto;
 import com.xjrsoft.module.outint.dto.TeacherOutInRecordDto;
 import com.xjrsoft.module.outint.entity.TeacherOutInRecord;
@@ -33,6 +38,8 @@ import java.util.List;
 public class TeacherOutInRecordServiceImpl extends MPJBaseServiceImpl<TeacherOutInRecordMapper, TeacherOutInRecord> implements ITeacherOutInRecordService {
 
     private final FaceImportMapper faceImportMapper;
+    private final IHikvisionDataService hikvisionDataService;
+
 
     @Override
     public List<TeacherOutInRecord> getListByParam(TeacherOutInRecordDto dto) {
@@ -48,23 +55,37 @@ public class TeacherOutInRecordServiceImpl extends MPJBaseServiceImpl<TeacherOut
             ApiUtil apiUtil = new ApiUtil();
             String apiPath = "/api/acs/v2/door/events";
 
-            JsonObject paramJson = new JsonObject();
-            JsonArray eventList = new JsonArray();
-            eventList.add(196893); // 只获取人脸通过的
-            paramJson.addProperty("pageNo", limit);
-            paramJson.addProperty("pageSize", size);
-            paramJson.add("eventTypes", eventList);
+            List<HikvisionData> dataList = hikvisionDataService.list(
+                    new QueryWrapper<HikvisionData>().lambda()
+                            .eq(HikvisionData::getTableName, "base_teacher")
+            );
+
+            for (HikvisionData hikvisionData : dataList) {
+                JsonObject paramJson = new JsonObject();
+                JsonArray eventList = new JsonArray();
+                eventList.add(196893); // 只获取人脸通过的
+                paramJson.addProperty("pageNo", limit);
+                paramJson.addProperty("pageSize", size);
+                paramJson.add("eventTypes", eventList);
+                JsonArray personIds = new JsonArray();
+                personIds.add(hikvisionData.getHikvisionId());
+                if("14954816214342".equals(hikvisionData.getSourceId())){
+                    System.out.println(hikvisionData.getHikvisionId());
+                }
+
+                paramJson.add("personIds", personIds);
 
-            paramJson.addProperty("sort", "eventTime");
-            paramJson.addProperty("order", "desc");
-            paramJson.addProperty("startTime", dto.getStartTime().atOffset(ZoneOffset.ofHours(8)).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
-            paramJson.addProperty("endTime", dto.getEndTime().atOffset(ZoneOffset.ofHours(8)).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
+                paramJson.addProperty("sort", "eventTime");
+                paramJson.addProperty("order", "desc");
+                paramJson.addProperty("startTime", dto.getStartTime().atOffset(ZoneOffset.ofHours(8)).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
+                paramJson.addProperty("endTime", dto.getEndTime().atOffset(ZoneOffset.ofHours(8)).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
 
-            String doPost = apiUtil.doPost(apiPath, paramJson.toString(), null);
-            JsonParser parser = new JsonParser();
-            JsonObject data = parser.parse(doPost).getAsJsonObject().get("data").getAsJsonObject();
-            JsonArray list = data.get("list").getAsJsonArray();
-            new OutInRecordUtil().InsertTeacherStudentRecords(list, faceImportMapper);
+                String doPost = apiUtil.doPost(apiPath, paramJson.toString(), null);
+                JsonParser parser = new JsonParser();
+                JsonObject data = parser.parse(doPost).getAsJsonObject().get("data").getAsJsonObject();
+                JsonArray list = data.get("list").getAsJsonArray();
+                new OutInRecordUtil().InsertTeacherStudentRecords(list, faceImportMapper);
+            }
         }catch (Exception e){
             Log.error(e.getMessage(), e);
             throw new MyException("同步报错,请联系管理员");

+ 2 - 0
src/main/java/com/xjrsoft/module/teacher/mapper/WfTeacherleaveMapper.java

@@ -22,4 +22,6 @@ public interface WfTeacherleaveMapper extends MPJBaseMapper<WfTeacherleave> {
     List<WfTeacherleave> getLeaveList(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);
 
     WfTeacherleave getLeaveByUserId(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime, @Param("userId")Long userId);
+
+    List<WfTeacherleave> getUserLeaveList(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);
 }

+ 3 - 0
src/main/java/com/xjrsoft/module/teacher/service/IWfTeacherleaveService.java

@@ -4,6 +4,7 @@ import com.github.yulichang.base.MPJBaseService;
 import com.xjrsoft.module.teacher.entity.WfTeacherleave;
 
 import java.time.LocalDateTime;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -30,4 +31,6 @@ public interface IWfTeacherleaveService extends MPJBaseService<WfTeacherleave> {
     WfTeacherleave getLeaveByUserId(LocalDateTime startTime, LocalDateTime endTime, Long userId);
 
     void updateAttendancestatus(Long id);
+
+    Map<String, List<WfTeacherleave>> getUserLeaveList(LocalDateTime startTime, LocalDateTime endTime);
 }

+ 9 - 0
src/main/java/com/xjrsoft/module/teacher/service/impl/WfTeacherleaveServiceImpl.java

@@ -35,6 +35,7 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * @title: 教职工请假流程
@@ -319,4 +320,12 @@ public class WfTeacherleaveServiceImpl extends MPJBaseServiceImpl<WfTeacherleave
          */
         private Long turnNum;
     }
+
+    @Override
+    public Map<String, List<WfTeacherleave>> getUserLeaveList(LocalDateTime startTime, LocalDateTime endTime) {
+        List<WfTeacherleave> leaveList = wfTeacherleaveMapper.getUserLeaveList(startTime, endTime);
+        Map<String, List<WfTeacherleave>> result = leaveList.stream().collect(Collectors.groupingBy(WfTeacherleave::getUserId));
+
+        return result;
+    }
 }

+ 8 - 0
src/main/resources/mapper/courseTable/CourseTable.xml

@@ -102,6 +102,14 @@
         AND t1.schedule_date BETWEEN #{dto.startDate} AND #{dto.endDate}
         AND (t1.adjust_type = 'course_exchange' OR t1.adjust_type = 'course_replace' OR t1.adjust_type IS NULL)
     </select>
+    <select id="getSubstituteTeacherCourseCountByParams" parameterType="com.xjrsoft.module.courseTable.dto.ClassTeacherDto" resultType="java.lang.Integer">
+        SELECT COUNT(t1.*) FROM course_table t1
+        INNER JOIN course_table_bak t2 ON t1.schedule_date = t2.schedule_date
+        AND t1.time_number = t2.time_number
+        AND t1.time_period = t2.time_number
+        WHERE t1.wf_course_adjust_id = #{dto.wfCourseAdjustId}
+        AND t1.teacher_id LIKE concat('', #{dto.teacherId},'') AND t1.adjust_type IS NULL;
+    </select>
 
 
 </mapper>

+ 23 - 5
src/main/resources/mapper/teacher/WfTeacherleaveMapper.xml

@@ -6,7 +6,8 @@
     <select id="getLeaveCount" resultType="java.lang.Long">
         SELECT COUNT(*) FROM wf_teacherleave t1
         INNER JOIN xjr_user t2 ON t1.user_id = t2.id
-        WHERE t1.status = 1 AND t2.delete_mark = 0
+        inner JOIN xjr_workflow_form_relation t3 ON t3.form_key_value = t1.id
+        WHERE t3.current_state = 'COMPLETED' AND t2.delete_mark = 0
         AND (
         (leave_start_time BETWEEN #{startTime} and #{endTime})
         OR (leave_end_time BETWEEN #{startTime} and #{endTime})
@@ -17,8 +18,9 @@
 
     <select id="getLeaveList" resultType="com.xjrsoft.module.teacher.entity.WfTeacherleave">
         SELECT * FROM wf_teacherleave t1
-                                 INNER JOIN xjr_user t2 ON t1.user_id = t2.id
-        WHERE t1.status = 1 AND t2.delete_mark = 0
+        INNER JOIN xjr_user t2 ON t1.user_id = t2.id
+        inner JOIN xjr_workflow_form_relation t3 ON t3.form_key_value = t1.id
+        WHERE t3.current_state = 'COMPLETED' AND t2.delete_mark = 0
           AND (
                 (leave_start_time BETWEEN #{startTime} and #{endTime})
                 OR (leave_end_time BETWEEN #{startTime} and #{endTime})
@@ -28,8 +30,9 @@
     </select>
     <select id="getLeaveByUserId" resultType="com.xjrsoft.module.teacher.entity.WfTeacherleave">
         SELECT * FROM wf_teacherleave t1
-                          INNER JOIN xjr_user t2 ON t1.user_id = t2.id
-        WHERE t1.status = 1 AND t2.delete_mark = 0
+        INNER JOIN xjr_user t2 ON t1.user_id = t2.id
+        inner JOIN xjr_workflow_form_relation t3 ON t3.form_key_value = t1.id
+        WHERE t3.current_state = 'COMPLETED' AND t2.delete_mark = 0
           AND (
                 (leave_start_time BETWEEN #{startTime} and #{endTime})
                 OR (leave_end_time BETWEEN #{startTime} and #{endTime})
@@ -38,4 +41,19 @@
             )
         and t2.id = #{userId}
     </select>
+
+    <select id="getUserLeaveList" resultType="com.xjrsoft.module.teacher.entity.WfTeacherleave">
+        SELECT * FROM wf_teacherleave t1
+        INNER JOIN xjr_user t2 ON t1.user_id = t2.id
+        inner JOIN xjr_workflow_form_relation t3 ON t3.form_key_value = t1.id
+        WHERE t3.current_state = 'COMPLETED' AND t2.delete_mark = 0
+        <if test="startTime != null and endTime != null">
+            AND (
+                (leave_start_time BETWEEN #{startTime} and #{endTime})
+                OR (leave_end_time BETWEEN #{startTime} and #{endTime})
+                OR (leave_start_time > #{startTime} and #{endTime} > leave_end_time)
+                OR (#{startTime} > leave_start_time and leave_end_time > #{endTime})
+            )
+        </if>
+    </select>
 </mapper>