package com.xjrsoft.module.classtime.service.impl; import cn.hutool.core.bean.BeanUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.github.yulichang.base.MPJBaseServiceImpl; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.xjrsoft.common.enums.CourseAdjustTypeEnum; import com.xjrsoft.common.enums.CourseTimeTypeEnum; import com.xjrsoft.common.enums.EnabledMark; import com.xjrsoft.common.exception.MyException; import com.xjrsoft.module.classtime.dto.AddClassTimeStatisticsDto; import com.xjrsoft.module.classtime.entity.ClassTimeDelete; import com.xjrsoft.module.classtime.entity.ClassTimeStatistics; import com.xjrsoft.module.classtime.entity.ClassTimeStatisticsRecord; import com.xjrsoft.module.classtime.entity.ClassTimeStatisticsSet; import com.xjrsoft.module.classtime.mapper.ClassTimeStatisticsMapper; import com.xjrsoft.module.classtime.mapper.ClassTimeStatisticsRecordMapper; import com.xjrsoft.module.classtime.service.IClassTimeDeleteService; import com.xjrsoft.module.classtime.service.IClassTimeStatisticsService; import com.xjrsoft.module.classtime.service.IClassTimeStatisticsSetService; import com.xjrsoft.module.classtime.vo.ClassTimeStatisticsRecordVo; import com.xjrsoft.module.classtime.vo.CourseListVo; import com.xjrsoft.module.classtime.vo.TeacherListVo; import com.xjrsoft.module.classtime.vo.WeekTimeRangeVo; import com.xjrsoft.module.oa.entity.WfTeacherCourseTime; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.DayOfWeek; import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; /** * @title: 课时统计 * @Author dzx * @Date: 2024-09-26 * @Version 1.0 */ @Service @AllArgsConstructor public class ClassTimeStatisticsServiceImpl extends MPJBaseServiceImpl implements IClassTimeStatisticsService { private final ClassTimeStatisticsMapper statisticsMapper; private final ClassTimeStatisticsRecordMapper recordMapper; private final IClassTimeStatisticsSetService statisticsSetService; private final IClassTimeDeleteService deleteService; @Override @Transactional(rollbackFor = Exception.class) public Boolean add(ClassTimeStatistics classTimeStatistics) { statisticsMapper.insert(classTimeStatistics); return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean update(ClassTimeStatistics classTimeStatistics) { statisticsMapper.updateById(classTimeStatistics); return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean delete(List ids) { statisticsMapper.deleteBatchIds(ids); recordMapper.delete(Wrappers.lambdaQuery(ClassTimeStatisticsRecord.class).in(ClassTimeStatisticsRecord::getClassTimeStatisticsId, ids)); return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean add(AddClassTimeStatisticsDto dto) { ClassTimeStatistics classTimeStatistics = BeanUtil.toBean(dto, ClassTimeStatistics.class); classTimeStatistics.setStatus(0); classTimeStatistics.setCreateDate(new Date()); //查询最新权重并保存到统计中 Integer category = 1; List list = statisticsSetService.list( new QueryWrapper().lambda() .eq(ClassTimeStatisticsSet::getCategory, category) .orderByDesc(ClassTimeStatisticsSet::getCreateDate) ); if(list.isEmpty()){ throw new MyException("请先设置权重并进行保存"); } classTimeStatistics.setWeightSetJson(list.get(0).getJsonContent()); //查询最新费用并保存到统计中 category = 2; list = statisticsSetService.list( new QueryWrapper().lambda() .eq(ClassTimeStatisticsSet::getCategory, category) .orderByDesc(ClassTimeStatisticsSet::getCreateDate) ); if(list.isEmpty()){ throw new MyException("请先设置费用并进行保存"); } classTimeStatistics.setCostSetJson(list.get(0).getJsonContent()); this.save(classTimeStatistics); CompletableFuture.runAsync(() -> { refreshRecord(classTimeStatistics); }); return true; } /** * 1、通过xjr_user和base_teacher查询所有教师,查询聘用类型为:正式聘用和外聘的 * 2、根据统计的开始日期和结束日期查询课时补充(wf_teacher_course_time)中的教研会、督导听课、临近三年退休政策、出题、阅卷、周末培优 * 3、根绝统计的开始日期和结束日期查询课程表(course_table)中的所有课程数据 * 4、查询补班日期下的所有课程 * 5、属于节假日的课程不查询 * @param statistics * @return */ @Override @Transactional(rollbackFor = Exception.class) public Boolean refreshRecord(ClassTimeStatistics statistics) { try { // 1、查询教师 List teacherList = this.baseMapper.getTeacherList(); // 2、查询补课课时 List courseTimeList = this.baseMapper.getWfTeacherCourseTimeList(); //按照课时补充类型分类统计 Map> courseTimeMap = courseTimeList.stream().collect(Collectors.groupingBy(WfTeacherCourseTime::getCourseTimeType)); JsonParser parser = new JsonParser(); //费用设置jsonArray JsonArray costSetArray = parser.parse(statistics.getCostSetJson()).getAsJsonArray(); Map costSetMap = new HashMap<>(); for (JsonElement jsonElement : costSetArray) { JsonObject object = jsonElement.getAsJsonObject(); costSetMap.put(object.get("field").getAsString(), object.get("value").getAsDouble()); } //权重设置jsonArray JsonArray weightSetArray = parser.parse(statistics.getWeightSetJson()).getAsJsonArray(); Map weightSetMap = new HashMap<>(); for (JsonElement jsonElement : weightSetArray) { JsonObject object = jsonElement.getAsJsonObject(); weightSetMap.put(object.get("label").getAsString(), object.get("value").getAsDouble()); } //计算出这个时间段内一共多少周 List weekTimeRangeVos = calculateNaturalWeeks(statistics.getStartDate(), statistics.getEndDate()); //查询课程数据,排除开节假日的数据 List allCourseList = this.baseMapper.getCourseList(statistics); //查询删除课时的数据,将每个班删除的具体日期统计出来 List deleteList = deleteService.list( new QueryWrapper().lambda() .ne(ClassTimeDelete::getStatus, 2) ); Map> deleteDataMap = deleteList.stream().collect(Collectors.groupingBy(ClassTimeDelete::getClassId)); Map> deleteMap = new HashMap<>();//将每个班级计算出来所有被删除的日期存入map for (Long classId : deleteDataMap.keySet()) { List dateList = new ArrayList<>(); for (ClassTimeDelete classTimeDelete : deleteDataMap.get(classId)) { LocalDate currentDate = classTimeDelete.getStartDate(); while (!currentDate.isAfter(classTimeDelete.getEndDate())) { dateList.add(currentDate); currentDate = currentDate.plusDays(1); // 增加一天 } } //去重并存到map中 deleteMap.put(classId, new HashSet<>(dateList)); } //查询所有老师发起顶课通过的数量(只查询事假、病假),也要分别计算早自习、晚自习、正课、如果日期出入课时删除中,也需要跳过 List allSubstituteList = this.baseMapper.getSubstituteList(statistics); List insertList = new ArrayList<>(); //循环教师,准备开始计算 for (TeacherListVo teacher : teacherList) { ClassTimeStatisticsRecord record = new ClassTimeStatisticsRecord(); record.setUserId(teacher.getId()); record.setClassTimeStatisticsId(statistics.getId()); record.setEmployType(teacher.getEmployType()); JsonArray allClassTimeDataArray = new JsonArray(); Double allClassTime = 0D; //计算补充课时,算作正课课时,但是计算超出课时时不计算这部分 for (String courseTimeType : courseTimeMap.keySet()) { List courseTimes = courseTimeMap.get(courseTimeType); double sum = courseTimes.stream() .filter(x -> x.getTeacherIds().contains(teacher.getId().toString())) .mapToDouble(WfTeacherCourseTime::getCourseTime).sum(); allClassTime = allClassTime + sum; if(CourseTimeTypeEnum.CTT001.getCode().equals(courseTimeType)){ record.setClassTime1(sum); }else if(CourseTimeTypeEnum.CTT002.getCode().equals(courseTimeType)){ record.setClassTime2(sum); }else if(CourseTimeTypeEnum.CTT003.getCode().equals(courseTimeType)){ record.setClassTime3(sum); }else if(CourseTimeTypeEnum.CTT004.getCode().equals(courseTimeType)){ record.setClassTime4(sum); }else if(CourseTimeTypeEnum.CTT005.getCode().equals(courseTimeType)){ record.setClassTime5(sum); }else if(CourseTimeTypeEnum.CTT006.getCode().equals(courseTimeType)){ record.setClassTime6(sum); } } //早自习、正课、晚辅、顶课、调课 Double classTime7 = 0D,classTime8 = 0D,classTime9 = 0D,classTime10 = 0D,classTime11 = 0D; List zkList = Arrays.asList("上1","上2","上3","上4","下1","下2","下3","下4"); List wzxList = Arrays.asList("晚1","晚2","晚3"); //查询出老师的课程 List courseList = allCourseList.stream() .filter(x -> x.getTeacherId().contains(teacher.getId().toString())) .collect(Collectors.toList()); //循环,统计出各项数据 for (CourseListVo courseListVo : courseList) { //如果这个课程数据包含在被删除的课时中,跳过不计算 Set deleteDates = deleteMap.get(courseListVo.getClassId()); if(deleteDates != null && deleteDates.contains(courseListVo.getScheduleDate())){ continue; } if("早自习".equals(courseListVo.getShortName())){ classTime7 += weightSetMap.get(courseListVo.getShortName()); }else if(zkList.contains(courseListVo.getShortName())){ classTime8 += weightSetMap.get(courseListVo.getShortName()); }else if(wzxList.contains(courseListVo.getShortName())){ classTime9 += weightSetMap.get(courseListVo.getShortName()); } if(courseListVo.getAdjustType() != null && !courseListVo.getAdjustType().isEmpty()){ if(CourseAdjustTypeEnum.courseSubstitute.getCode().equals(courseListVo.getAdjustType())){ classTime10 += weightSetMap.get(courseListVo.getShortName()); }else if(CourseAdjustTypeEnum.courseExchange.getCode().equals(courseListVo.getAdjustType())){ classTime11 += weightSetMap.get(courseListVo.getShortName()); } } } record.setClassTime7(classTime7); record.setClassTime8(classTime8); record.setClassTime9(classTime9); record.setClassTime10(classTime10); record.setClassTime11(classTime11); JsonObject weekDataJson = new JsonObject(); Double allTimes = 0d; //存每周的数据 for (WeekTimeRangeVo timeRangeVo : weekTimeRangeVos) { Double zkTimes = 0d; Double wzxTimes = 0d; Double dkTimes = 0d; Double tkTimes = 0d; for (CourseListVo courseListVo : courseList) { LocalDate scheduleDate = courseListVo.getScheduleDate(); //如果这个课程数据包含在被删除的课时中,跳过不计算 Set deleteDates = deleteMap.get(courseListVo.getClassId()); if(deleteDates != null && deleteDates.contains(scheduleDate)){ continue; } if(!(scheduleDate.isAfter(timeRangeVo.getMondayDate()) && scheduleDate.isBefore(timeRangeVo.getSundayDate()))){ continue; } if("早自习".equals(courseListVo.getShortName())){ zkTimes += weightSetMap.get(courseListVo.getShortName()); }else if(zkList.contains(courseListVo.getShortName())){ zkTimes += weightSetMap.get(courseListVo.getShortName()); }else if(wzxList.contains(courseListVo.getShortName())){ wzxTimes += weightSetMap.get(courseListVo.getShortName()); } if(courseListVo.getAdjustType() != null && !courseListVo.getAdjustType().isEmpty()){ if(CourseAdjustTypeEnum.courseSubstitute.getCode().equals(courseListVo.getAdjustType())){ dkTimes += weightSetMap.get(courseListVo.getShortName()); }else if(CourseAdjustTypeEnum.courseExchange.getCode().equals(courseListVo.getAdjustType())){ tkTimes += weightSetMap.get(courseListVo.getShortName()); } } } timeRangeVo.setZkTimes(zkTimes); timeRangeVo.setWzxTimes(wzxTimes); timeRangeVo.setDkTimes(dkTimes); timeRangeVo.setTkTimes(tkTimes); allTimes += (zkTimes + wzxTimes); } weekDataJson.add("weekData", new Gson().toJsonTree(weekTimeRangeVos)); weekDataJson.addProperty("allTimes", allTimes); record.setWeekData(weekDataJson.toString()); //计算总课时 allClassTime = allClassTime + classTime7 + classTime8 + classTime9; record.setAllClassTime(allClassTime); //计算该老师发起的事假、病假顶课数据 List substituteList = allSubstituteList.stream().filter(x -> x.getTeacherId().equals(teacher.getId().toString())) .collect(Collectors.toList()); Double reduceTime = 0d; for (CourseListVo courseListVo : substituteList) { Set deleteDates = deleteMap.get(courseListVo.getClassId()); if(deleteDates !=null && deleteDates.contains(courseListVo.getScheduleDate())){ continue; } reduceTime += weightSetMap.get(courseListVo.getShortName()); } //计算费用,根据聘用类型判断费用问题 Double classTimeAmount = 0d; Double beyondClassTimeAmount = 0d; BigDecimal zzxCost = BigDecimal.ZERO;//早自习费用 if("FB1601".equals(teacher.getEmployType())){ zzxCost = BigDecimal.valueOf(costSetMap.get("cost1")); }else{//外聘FB1605、合作人员FB1609 zzxCost = BigDecimal.valueOf(costSetMap.get("cost2")); } classTimeAmount += BigDecimal.valueOf(classTime7).multiply(zzxCost).doubleValue(); BigDecimal zkCost = BigDecimal.ZERO;//正课费用 if("FB1601".equals(teacher.getEmployType())){ zkCost = BigDecimal.valueOf(costSetMap.get("cost3")); }else{//外聘FB1605、合作人员FB1609 zkCost = BigDecimal.valueOf(costSetMap.get("cost4")); } double classTime = classTime8 + (record.getClassTime1() == null ? 0d:record.getClassTime1()) + (record.getClassTime2() == null ? 0d:record.getClassTime2()) + (record.getClassTime3() == null ? 0d:record.getClassTime3()) + (record.getClassTime4() == null ? 0d:record.getClassTime4()) + (record.getClassTime5() == null ? 0d:record.getClassTime5()) + (record.getClassTime6() == null ? 0d:record.getClassTime6()); classTimeAmount += BigDecimal.valueOf(classTime).multiply(zkCost).doubleValue(); BigDecimal wzxCost = BigDecimal.ZERO;//晚自习费用 if("FB1601".equals(teacher.getEmployType())){ wzxCost = BigDecimal.valueOf(costSetMap.get("cost5")); }else{//外聘FB1605、合作人员FB1609 wzxCost = BigDecimal.valueOf(costSetMap.get("cost6")); } classTimeAmount += BigDecimal.valueOf(classTime9).multiply(wzxCost).doubleValue(); BigDecimal dkCost = BigDecimal.ZERO;//顶课费用,顶课老师加钱 if("FB1601".equals(teacher.getEmployType())){ dkCost = BigDecimal.valueOf(costSetMap.get("cost11")); }else{//外聘FB1605、合作人员FB1609 dkCost = BigDecimal.valueOf(costSetMap.get("cost12")); } classTimeAmount += BigDecimal.valueOf(classTime10).multiply(dkCost).doubleValue(); BigDecimal bdkCost = BigDecimal.ZERO;//顶课费用,被顶课老师扣钱 if("FB1601".equals(teacher.getEmployType())){ bdkCost = BigDecimal.valueOf(costSetMap.get("cost13")==null?0:costSetMap.get("cost13")); }else{//外聘FB1605、合作人员FB1609 bdkCost = BigDecimal.valueOf(costSetMap.get("cost14")==null?0:costSetMap.get("cost14")); } //计算被扣除的费用 BigDecimal reduceTimeAmount = bdkCost.multiply(BigDecimal.valueOf(reduceTime)); //计算总课时费用 classTimeAmount = BigDecimal.valueOf(classTimeAmount).subtract(reduceTimeAmount).doubleValue(); record.setClassTimeAmount(classTimeAmount); //计算超出的课时,需要先计算出每个周的开始结束时间 BigDecimal ccksTime = BigDecimal.ZERO;//超出课时标准(每周) if("FB1601".equals(teacher.getEmployType())){ ccksTime = BigDecimal.valueOf(costSetMap.get("cost7")); }else{//外聘FB1605、合作人员FB1609 ccksTime = BigDecimal.valueOf(costSetMap.get("cost8")); } BigDecimal ccksCost = BigDecimal.ZERO; if("FB1601".equals(teacher.getEmployType())){ ccksCost = BigDecimal.valueOf(costSetMap.get("cost9")); }else{//外聘FB1605、合作人员FB1609 ccksCost = BigDecimal.valueOf(costSetMap.get("cost10")); } //计算出总的超出课时并计算超课时费 BigDecimal allCcksTime = BigDecimal.ZERO; BigDecimal ccksTime2 = ccksTime.multiply(BigDecimal.valueOf(weekTimeRangeVos.size())); if(allClassTime > ccksTime2.doubleValue()){//如果总的课时超出规定课时 allCcksTime = BigDecimal.valueOf(allClassTime).subtract(ccksTime2); } beyondClassTimeAmount = allCcksTime.multiply(ccksCost).doubleValue(); if(!"FB1601".equals(teacher.getEmployType())){ record.setBeyondClassTimeAmount(beyondClassTimeAmount); } //计算总金额,课时费+超课时费 Double totalAmount = classTimeAmount + beyondClassTimeAmount - reduceTimeAmount.doubleValue(); record.setTotalAmount(totalAmount); insertList.add(record); } if(!insertList.isEmpty()){ //先删除 recordMapper.delete( new QueryWrapper().lambda() .eq(ClassTimeStatisticsRecord::getClassTimeStatisticsId, statistics.getId()) ); for (ClassTimeStatisticsRecord record : insertList) { recordMapper.insert(record); } } statistics.setAllClassTime(insertList.stream().filter(x -> x.getAllClassTime() != null).mapToDouble(ClassTimeStatisticsRecord::getAllClassTime).sum()); statistics.setTotalAmount(insertList.stream().filter(x -> x.getTotalAmount() != null).mapToDouble(ClassTimeStatisticsRecord::getTotalAmount).sum()); statistics.setBeyondClassTimeAmount(insertList.stream().filter(x -> x.getBeyondClassTimeAmount() != null).mapToDouble(ClassTimeStatisticsRecord::getBeyondClassTimeAmount).sum()); statistics.setClassTimeAmount(insertList.stream().filter(x -> x.getClassTimeAmount() != null).mapToDouble(ClassTimeStatisticsRecord::getClassTimeAmount).sum()); statistics.setStatus(1); this.updateById(statistics); return true; }catch (Exception e){ log.error(e.getMessage()); throw new MyException("统计出错,请联系管理员"); } } @Override public Boolean lockData(Long id) { ClassTimeStatistics statistics = this.getById(id); return null; } @Override public List getRecordList(Long id) { return this.baseMapper.getRecordList(id); } //计算日期内一共几个周,并返回每周的周一日期和周日日期 private static List calculateNaturalWeeks(LocalDate startDate, LocalDate endDate) { List result = new ArrayList<>(); // 获取第一个周一 LocalDate currentMonday = startDate.with(DayOfWeek.MONDAY); // 如果 startDate 不是周一,则用下一个周一 if (!startDate.isEqual(currentMonday) && startDate.isAfter(currentMonday)) { currentMonday = currentMonday.plusWeeks(1); } int weeks = 1; // 遍历每个周 while (!currentMonday.isAfter(endDate)) { // 计算当前周的周日 LocalDate currentSunday = currentMonday.plusDays(6); // 限制周日的范围 if (currentSunday.isAfter(endDate)) { currentSunday = endDate; } // 添加结果 WeekTimeRangeVo timeRangeVo = new WeekTimeRangeVo(); timeRangeVo.setMondayDate(currentMonday); timeRangeVo.setSundayDate(currentSunday); timeRangeVo .setWeeks(weeks); result.add(timeRangeVo); // 移动到下一个周的周一 currentMonday = currentMonday.plusWeeks(1); weeks ++; } return result; } }