package com.xjrsoft.module.attendance.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.github.yulichang.wrapper.MPJLambdaWrapper; import com.xjrsoft.common.enums.ArchivesStatusEnum; import com.xjrsoft.common.model.result.RT; import com.xjrsoft.common.page.ConventPage; import com.xjrsoft.common.page.PageOutput; import com.xjrsoft.module.attendance.dto.AttendanceStatisticDto; import com.xjrsoft.module.attendance.dto.StudentDetailsDto; import com.xjrsoft.module.attendance.vo.ClassStatisticsVo; import com.xjrsoft.module.attendance.vo.StudentStatisticsPageVo; import com.xjrsoft.module.base.entity.BaseClass; import com.xjrsoft.module.base.service.IBaseClassService; import com.xjrsoft.module.holiday.entity.HolidayDate; import com.xjrsoft.module.holiday.service.IHolidayDateService; import com.xjrsoft.module.organization.entity.User; import com.xjrsoft.module.organization.service.IUserService; import com.xjrsoft.module.outint.entity.StudentOutInRecord; import com.xjrsoft.module.outint.service.IStudentOutInRecordService; import com.xjrsoft.module.outint.vo.StudentOutInRecordVo; import com.xjrsoft.module.student.entity.BaseStudentFamily; import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll; import com.xjrsoft.module.student.entity.StudentLeave; import com.xjrsoft.module.student.service.IStudentLeaveService; import com.xjrsoft.module.system.entity.DictionaryDetail; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.DayOfWeek; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalAdjusters; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @title: 考勤消息设置 * @Author dzx * @Date: 2024-05-21 * @Version 1.0 */ @RestController @RequestMapping("/studentStatistics") @Api(value = "/studentStatistics" ,tags = "学生考勤统计") @AllArgsConstructor public class StudentStatisticsController { private final IUserService xjrUserService; private final IStudentOutInRecordService studentOutInRecordService; private final IStudentLeaveService studentLeaveService; private final IBaseClassService classService; private final IHolidayDateService holidayDateService; @GetMapping(value = "/class-statistics") @ApiOperation(value="班级考勤统计") @SaCheckPermission("statistics:detail") public RT<PageOutput<ClassStatisticsVo>> classStatistics(@Valid AttendanceStatisticDto dto){ Page<ClassStatisticsVo> attendancePage = classService.getAttendancePage(new Page<>(dto.getLimit(), dto.getSize()), dto); List<Long> classIds = new ArrayList<>(); for (ClassStatisticsVo record : attendancePage.getRecords()) { classIds.add(record.getId()); } if(dto.getDate() != null && !"".equals(dto.getDate())){ DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE; LocalDate queryDate = LocalDate.parse(dto.getDate(), formatter); HolidayDate holidayDate = holidayDateService.getOne( new QueryWrapper<HolidayDate>().lambda() .eq(HolidayDate::getDate, queryDate) ); if(holidayDate != null && holidayDate.getWay() != null && holidayDate.getWay() != 0){ return RT.ok(ConventPage.getPageOutput(attendancePage, ClassStatisticsVo.class)); } LocalDateTime startTime, endTime; if(dto.getTimePeriod() != null && dto.getTimePeriod() == 1){ startTime = queryDate.atTime(5, 0, 0); endTime = queryDate.atTime(12, 0, 0); }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 2){ startTime = queryDate.atTime(12, 0, 0); endTime = queryDate.atTime(18, 0, 0); }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 3){ startTime = queryDate.atTime(18, 0, 0); endTime = queryDate.atTime(23, 59, 59); }else{ startTime = queryDate.atTime(0, 0, 0); endTime = queryDate.atTime(23, 59, 59); } //查询每个班的走读生实到人数 Map<Long, List<StudentOutInRecordVo>> notStayMap = studentOutInRecordService.getList(startTime, endTime, classIds); //查询各班的请假人数 Map<Long, Integer> classLeaveCount = studentLeaveService.getClassLeaveCount(startTime, endTime); for (ClassStatisticsVo record: attendancePage.getRecords()) { Integer leaveCount = 0; if(classLeaveCount.get(record.getId()) != null){ leaveCount = classLeaveCount.get(record.getId()); } record.setLeaveCount(leaveCount); int actualCount = 0; for (StudentOutInRecordVo outInRecordVo : notStayMap.get(record.getId())) { if(outInRecordVo.getStatus() == 1){ actualCount ++; } } record.setActualCount(actualCount); Integer lateCount = 0, playTruantCount = 0; for (StudentOutInRecordVo outInRecord : notStayMap.get(record.getId())) { if(outInRecord.getStatus() == 0){ continue; } if("迟到".equals(outInRecord.getAttendanceStatus())){ lateCount ++; }else if("旷课".equals(outInRecord.getAttendanceStatus())){ playTruantCount ++; } } record.setPlayTruantCount(playTruantCount); record.setLateCount(lateCount); //最后通过总人数-实到人数-请假人数计算出缺勤人数 record.setAbsenteeismCount(record.getStudentCount() - record.getLeaveCount() - record.getActualCount()); //计算出勤率 BigDecimal divide = BigDecimal.ZERO; if(record.getStudentCount() != null && record.getStudentCount() != 0){ divide = BigDecimal.valueOf(record.getActualCount()).divide(BigDecimal.valueOf(record.getStudentCount()), 4, RoundingMode.HALF_UP); } record.setAttendanceRate(divide.doubleValue()); } } PageOutput<ClassStatisticsVo> pageOutput = ConventPage.getPageOutput(attendancePage, ClassStatisticsVo.class); return RT.ok(pageOutput); } @GetMapping(value = "/student-details") @ApiOperation(value="学生考勤") @SaCheckPermission("statistics:detail") public RT<PageOutput<StudentStatisticsPageVo>> studentDetails(@Valid StudentDetailsDto dto){ MPJLambdaWrapper<User> queryUser = new MPJLambdaWrapper<>(); queryUser.disableSubLogicDel().distinct() .like(StrUtil.isNotEmpty(dto.getName()), User::getName, dto.getName()) .like(StrUtil.isNotEmpty(dto.getCredentialNumber()), User::getCredentialNumber, dto.getCredentialNumber()) .eq(StrUtil.isNotEmpty(dto.getStduyStatus()), BaseStudentSchoolRoll::getStduyStatus, dto.getStduyStatus()) .eq(ObjectUtil.isNotNull(dto.getClassId()), BaseStudentSchoolRoll::getClassId, dto.getClassId()) .eq(BaseStudentSchoolRoll::getArchivesStatus, ArchivesStatusEnum.FB2901.getCode()) .selectAs(BaseClass::getName, StudentStatisticsPageVo::getClassName) .select("t3.name", StudentStatisticsPageVo::getTeacherName) .selectAs(User::getName, StudentStatisticsPageVo::getStudentName) .selectAs(User::getMobile, StudentStatisticsPageVo::getMobile) .selectAs(User::getId, StudentStatisticsPageVo::getUserId) .selectAs(BaseStudentFamily::getTelephone, StudentStatisticsPageVo::getGuardianPhone) .selectAs(DictionaryDetail::getName, StudentStatisticsPageVo::getStduyStatusCn) .selectAs(User::getCredentialNumber, StudentStatisticsPageVo::getCredentialNumber) .innerJoin(BaseStudentSchoolRoll.class, BaseStudentSchoolRoll::getUserId, User::getId) .innerJoin(BaseClass.class, BaseClass::getId, BaseStudentSchoolRoll::getClassId) .leftJoin(User.class, User::getId, BaseClass::getTeacherId) .leftJoin(BaseStudentFamily.class, BaseStudentFamily::getUserId, User::getId) .leftJoin(DictionaryDetail.class, DictionaryDetail::getCode, BaseStudentSchoolRoll::getStduyStatus); IPage<StudentStatisticsPageVo> voIPage = xjrUserService.selectJoinListPage(ConventPage.getPage(dto), StudentStatisticsPageVo.class, queryUser); if(dto.getDate() != null && !"".equals(dto.getDate())){ DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE; LocalDate queryDate = LocalDate.parse(dto.getDate(), formatter); LocalDateTime startTime, endTime; if(dto.getTimePeriod() != null && dto.getTimePeriod() == 1){ startTime = queryDate.atTime(5, 0, 0); endTime = queryDate.atTime(12, 0, 0); }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 2){ startTime = queryDate.atTime(12, 0, 0); endTime = queryDate.atTime(18, 0, 0); }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 3){ startTime = queryDate.atTime(18, 0, 0); endTime = queryDate.atTime(23, 59, 59); }else{ startTime = queryDate.atTime(0, 0, 0); endTime = queryDate.atTime(23, 59, 59); } //查询当前时间段存在请假的学生 Map<Long, StudentLeave> leaveList = studentLeaveService.getLeaveList(startTime, endTime); //查询进入记录 List<StudentOutInRecord> outInRecords = studentOutInRecordService.list( new QueryWrapper<StudentOutInRecord>().lambda() .between(StudentOutInRecord::getRecordTime, startTime, endTime) .eq(StudentOutInRecord::getStatus, 1) ); Map<Long, StudentOutInRecord> outInMap = new HashMap<>(); for (StudentOutInRecord inRecord : outInRecords) { outInMap.put(inRecord.getUserId(), inRecord); } for (StudentStatisticsPageVo record : voIPage.getRecords()) { StudentLeave studentLeave = leaveList.get(record.getUserId()); if(studentLeave != null){ record.setStatus(studentLeave.getLeaveType()); }else{ StudentOutInRecord outInRecord = outInMap.get(record.getUserId()); if(outInRecord != null){ record.setRecordTime(outInRecord.getRecordTime()); record.setStatus(outInRecord.getAttendanceStatus()); }else{ record.setStatus("缺勤"); } } } } PageOutput<StudentStatisticsPageVo> pageOutput = ConventPage.getPageOutput(voIPage, StudentStatisticsPageVo.class); return RT.ok(pageOutput); } @GetMapping(value = "/class-history") @ApiOperation(value="历史考勤") @SaCheckPermission("statistics:detail") public RT<PageOutput<ClassStatisticsVo>> classHistory(@Valid AttendanceStatisticDto dto){ Page<ClassStatisticsVo> attendancePage = classService.getAttendancePage(new Page<>(dto.getLimit(), dto.getSize()), dto); List<Long> classIds = new ArrayList<>(); for (ClassStatisticsVo record : attendancePage.getRecords()) { classIds.add(record.getId()); } if(dto.getStartTime() != null && !"".equals(dto.getStartTime()) && dto.getEndTime() != null && !"".equals(dto.getEndTime())){ DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE; LocalDateTime startTime = LocalDate.parse(dto.getStartTime(), formatter).atTime(0, 0, 0); LocalDateTime endTime = LocalDate.parse(dto.getEndTime(), formatter).atTime(23, 59, 59); //查询每个班的走读生实到人数 Map<Long, List<StudentOutInRecordVo>> notStayMap = studentOutInRecordService.getNotStayList(startTime, endTime, classIds); //查询住校生的实到情况 Map<Long, List<StudentOutInRecordVo>> stayMap = studentOutInRecordService.getStayList(startTime, endTime, classIds); //查询各班的请假人数 Map<Long, Integer> classLeaveCount = studentLeaveService.getClassLeaveCount(startTime, endTime); //计算2个时间相差的天数 long days = ChronoUnit.DAYS.between(startTime.toLocalDate(), endTime.toLocalDate()); List<String> dayOfWeeks = new ArrayList<>(); for (int i = 0; i <= days; i ++){ dayOfWeeks.add(startTime.plusDays(i).getDayOfWeek().name()); } for (ClassStatisticsVo record: attendancePage.getRecords()) { record.setLeaveCount(classLeaveCount.get(record.getId()) == null ? 0:classLeaveCount.get(record.getId())); record.setActualCount(notStayMap.get(record.getId()).size() + stayMap.get(record.getId()).size()); record.setStudentCount(record.getStudentCount() * dayOfWeeks.size() * 3); Integer lateCount = 0; for (String dayOfWeek : dayOfWeeks) { for (StudentOutInRecordVo outInRecord : notStayMap.get(record.getId())) { if("迟到".equals(outInRecord.getAttendanceStatus())){ lateCount ++; } } for (StudentOutInRecordVo outInRecord : stayMap.get(record.getId())) { if("迟到".equals(outInRecord.getAttendanceStatus())){ lateCount ++; } } } record.setLateCount(lateCount); //最后通过总人数-实到人数-请假人数计算出缺勤人数 record.setAbsenteeismCount(record.getStudentCount() - record.getLeaveCount() - record.getActualCount()); //计算出勤率 BigDecimal divide = BigDecimal.ZERO; if(record.getStudentCount() != null && record.getStudentCount() != 0){ divide = BigDecimal.valueOf(record.getActualCount()).divide(BigDecimal.valueOf(record.getStudentCount()), 4, RoundingMode.HALF_UP); } record.setAttendanceRate(divide.doubleValue()); } } PageOutput<ClassStatisticsVo> pageOutput = ConventPage.getPageOutput(attendancePage, ClassStatisticsVo.class); return RT.ok(pageOutput); } @GetMapping(value = "/leaving-school") @ApiOperation(value="离校统计") @SaCheckPermission("statistics:detail") public RT<PageOutput<ClassStatisticsVo>> leavingSchool(@Valid AttendanceStatisticDto dto){ Page<ClassStatisticsVo> attendancePage = classService.getAttendancePage(new Page<>(dto.getLimit(), dto.getSize()), dto); List<Long> classIds = new ArrayList<>(); for (ClassStatisticsVo record : attendancePage.getRecords()) { classIds.add(record.getId()); } if(dto.getDate() != null && !"".equals(dto.getDate())){ DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE; LocalDate queryDate = LocalDate.parse(dto.getDate(), formatter); LocalDateTime startTime, endTime; if(dto.getTimePeriod() != null && dto.getTimePeriod() == 1){ startTime = queryDate.atTime(5, 0, 0); endTime = queryDate.atTime(12, 0, 0); }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 2){ startTime = queryDate.atTime(12, 0, 0); endTime = queryDate.atTime(18, 0, 0); }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 3){ startTime = queryDate.atTime(18, 0, 0); endTime = queryDate.atTime(23, 59, 59); }else{ startTime = queryDate.atTime(0, 0, 0); endTime = queryDate.atTime(23, 59, 59); } LocalDateTime lastSundayStart = startTime.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).plusDays(-1); LocalDateTime lastSundayEnd = endTime.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).plusDays(-1); //查询每个班的走读生实到人数 Map<Long, List<StudentOutInRecordVo>> notStayMap = studentOutInRecordService.getNotStayList(startTime, endTime, classIds); //查询住校生的实到情况 Map<Long, List<StudentOutInRecordVo>> stayMap = studentOutInRecordService.getStayList(lastSundayStart, lastSundayEnd, classIds); //查询各班的请假人数 Map<Long, Integer> classLeaveCount = studentLeaveService.getClassLeaveCount(startTime, endTime); for (ClassStatisticsVo record: attendancePage.getRecords()) { record.setLeaveCount(classLeaveCount.get(record.getId())); record.setActualCount(notStayMap.get(record.getId()).size() + stayMap.get(record.getId()).size()); Integer lateCount = 0; for (StudentOutInRecordVo outInRecord : notStayMap.get(record.getId())) { if(outInRecord.getStatus() == 1){ continue; } if("迟到".equals(outInRecord.getAttendanceStatus())){ lateCount ++; } } for (StudentOutInRecordVo outInRecord : stayMap.get(record.getId())) { if(outInRecord.getStatus() == 1){ continue; } if("迟到".equals(outInRecord.getAttendanceStatus())){ lateCount ++; } } record.setLateCount(lateCount); //最后通过总人数-实到人数-请假人数计算出缺勤人数 record.setAbsenteeismCount(record.getStudentCount() - record.getLeaveCount() - record.getActualCount()); //计算出勤率 BigDecimal divide = BigDecimal.valueOf(record.getActualCount()).divide(BigDecimal.valueOf(record.getStudentCount()), 4, RoundingMode.HALF_UP); record.setAttendanceRate(divide.doubleValue()); } } PageOutput<ClassStatisticsVo> pageOutput = ConventPage.getPageOutput(attendancePage, ClassStatisticsVo.class); return RT.ok(pageOutput); } }