package com.xjrsoft.module.attendance.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.stp.StpUtil; 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.enums.DeleteMark; import com.xjrsoft.common.enums.OutInStatusEnum; import com.xjrsoft.common.enums.StudyStatusEnum; import com.xjrsoft.common.model.result.RT; import com.xjrsoft.common.page.ConventPage; import com.xjrsoft.common.page.PageOutput; import com.xjrsoft.common.utils.VoToColumnUtil; 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.attendance.vo.TimeRangeVo; 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.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; /** * @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; private final IBaseClassService baseClassService; @GetMapping(value = "/class-statistics") @ApiOperation(value="班级考勤统计") @SaCheckPermission("statistics:detail") public RT> classStatistics(@Valid AttendanceStatisticDto dto){ List roleList = StpUtil.getRoleList(); long teacherId = StpUtil.getLoginIdAsLong(); List classList = baseClassService.list( new QueryWrapper().lambda() .eq(BaseClass::getTeacherId, teacherId) .eq(BaseClass::getDeleteMark, DeleteMark.NODELETE.getCode()) ); if(roleList.size() == 2 && roleList.contains("CLASSTE") && roleList.contains("TEACHER")){ if(classList != null && !classList.isEmpty()){ dto.setClassId(classList.get(0).getId()); } } Page attendancePage = classService.getAttendancePage(new Page<>(dto.getLimit(), dto.getSize()), dto); List 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().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> notStayMap = studentOutInRecordService.getList(startTime, endTime, classIds); //查询各班的请假人数 Map 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; Set userIds = new HashSet<>(); Integer lateCount = 0, playTruantCount = 0; for (StudentOutInRecordVo outInRecordVo : notStayMap.get(record.getId())) { if(userIds.contains(outInRecordVo.getUserId())){ continue; } if("迟到".equals(outInRecordVo.getAttendanceStatus())){ lateCount ++; }else if("旷课".equals(outInRecordVo.getAttendanceStatus())){ playTruantCount ++; } actualCount ++; userIds.add(outInRecordVo.getUserId()); } record.setActualCount(actualCount); record.setPlayTruantCount(playTruantCount); record.setLateCount(lateCount); //最后通过总人数-实到人数-请假人数计算出缺勤人数 record.setAbsenteeismCount(record.getNotStayCount() - record.getLeaveCount() - record.getActualCount()); //计算出勤率 BigDecimal divide = BigDecimal.ZERO; if(record.getNotStayCount() != null && record.getNotStayCount() != 0){ divide = BigDecimal.valueOf(record.getActualCount()).divide(BigDecimal.valueOf(record.getNotStayCount()), 4, RoundingMode.HALF_UP); } record.setAttendanceRate(divide.doubleValue() + ""); } } PageOutput pageOutput = ConventPage.getPageOutput(attendancePage, ClassStatisticsVo.class); return RT.ok(pageOutput); } @GetMapping(value = "/student-details") @ApiOperation(value="学生考勤") @SaCheckPermission("statistics:detail") public RT> studentDetails(@Valid StudentDetailsDto dto){ List roleList = StpUtil.getRoleList(); long teacherId = StpUtil.getLoginIdAsLong(); List classList = baseClassService.list( new QueryWrapper().lambda().eq(BaseClass::getTeacherId, teacherId) ); if(roleList.size() == 2 && roleList.contains("CLASSTE") && roleList.contains("TEACHER")){ if(classList != null && !classList.isEmpty()){ dto.setClassId(classList.get(0).getId()); } } MPJLambdaWrapper 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 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); HolidayDate holidayDate = holidayDateService.getOne( new QueryWrapper().lambda() .eq(HolidayDate::getDate, queryDate) ); if(holidayDate != null && holidayDate.getWay() != null && holidayDate.getWay() != 0){ return RT.ok(new PageOutput<>()); } 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 leaveList = studentLeaveService.getLeaveList(startTime, endTime); //查询进入记录 List outInRecords = studentOutInRecordService.list( new MPJLambdaWrapper() .select(StudentOutInRecord.class, x -> VoToColumnUtil.fieldsToColumns(StudentOutInRecord.class).contains(x.getProperty())) .eq(StudentOutInRecord::getStatus, OutInStatusEnum.enter.getCode()) .le(StudentOutInRecord::getRecordTime, endTime) .eq("DATE_FORMAT(record_time, '%Y-%m-%d')", endTime.toLocalDate()) ); Map 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("缺勤"); } } if(StudyStatusEnum.InResidence.getValue().equals(record.getStduyStatusCn())){ record.setStatus("不考勤"); } } } PageOutput pageOutput = ConventPage.getPageOutput(voIPage, StudentStatisticsPageVo.class); return RT.ok(pageOutput); } @GetMapping(value = "/class-history") @ApiOperation(value="历史考勤") @SaCheckPermission("statistics:detail") public RT> classHistory(@Valid AttendanceStatisticDto dto){ Page attendancePage = classService.getAttendancePage(new Page<>(dto.getLimit(), dto.getSize()), dto); List classIds = attendancePage.getRecords().stream().map(ClassStatisticsVo::getId).collect(Collectors.toList()); 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); //如果查询天数只有一天 if(startTime.toLocalDate().isEqual(endTime.toLocalDate())){ HolidayDate holidayDate = holidayDateService.getOne( new QueryWrapper().lambda() .eq(HolidayDate::getDate, endTime.toLocalDate()) ); if(holidayDate != null && holidayDate.getWay() != null && holidayDate.getWay() != 0){ return RT.ok(ConventPage.getPageOutput(attendancePage, ClassStatisticsVo.class)); } } //查询每个班的走读生实到人数 Map> notStayMap = studentOutInRecordService.getNotStayList(startTime, endTime, classIds); //查询住校生的实到情况 // Map> stayMap = studentOutInRecordService.getStayList(startTime, endTime, classIds); //查询各班的请假人数 //Map classLeaveCount = studentLeaveService.getClassLeaveCount(startTime, endTime); //计算2个时间相差的天数 long days = ChronoUnit.DAYS.between(startTime.toLocalDate(), endTime.toLocalDate()); List dayOfWeeks = new ArrayList<>(); List timeRangeList = new ArrayList<>(); for (int i = 0; i <= days; i ++){ dayOfWeeks.add(startTime.plusDays(i).getDayOfWeek().name()); TimeRangeVo rangeVo = new TimeRangeVo(); rangeVo.setStartTime(startTime.plusDays(i)); rangeVo.setStartTime(startTime.plusDays(i).withHour(23).withMinute(59).withSecond(59)); timeRangeList.add(rangeVo); } for (ClassStatisticsVo record: attendancePage.getRecords()) { //查询班级的请假总人次 Integer allLeaveCount = 0; for (TimeRangeVo rangeVo : timeRangeList) { AttendanceStatisticDto statisticDto = new AttendanceStatisticDto(); statisticDto.setClassId(record.getId()); Long leaveCount = studentLeaveService.getLeaveCount(rangeVo.getStartTime(), rangeVo.getEndTime(), statisticDto); allLeaveCount += (leaveCount.intValue() * 3); } record.setLeaveCount(allLeaveCount); List collect = notStayMap.get(record.getId()).stream().map(StudentOutInRecordVo::getUserId).collect(Collectors.toList()); record.setActualCount(collect.size()); record.setStudentCount(record.getStudentCount() * dayOfWeeks.size() * 3); Integer lateCount = 0; for (StudentOutInRecordVo outInRecord : notStayMap.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 pageOutput = ConventPage.getPageOutput(attendancePage, ClassStatisticsVo.class); return RT.ok(pageOutput); } @GetMapping(value = "/leaving-school") @ApiOperation(value="离校统计") @SaCheckPermission("statistics:detail") public RT> leavingSchool(@Valid AttendanceStatisticDto dto){ Page attendancePage = classService.getAttendancePage(new Page<>(dto.getLimit(), dto.getSize()), dto); List 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> notStayMap = studentOutInRecordService.getNotStayList(startTime, endTime, classIds); //查询住校生的实到情况 Map> stayMap = studentOutInRecordService.getStayList(lastSundayStart, lastSundayEnd, classIds); //查询各班的请假人数 Map 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() == OutInStatusEnum.enter.getCode()){ continue; } if("迟到".equals(outInRecord.getAttendanceStatus())){ lateCount ++; } } for (StudentOutInRecordVo outInRecord : stayMap.get(record.getId())) { if(outInRecord.getStatus() == OutInStatusEnum.enter.getCode()){ 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 pageOutput = ConventPage.getPageOutput(attendancePage, ClassStatisticsVo.class); return RT.ok(pageOutput); } }