ClassTimeStatisticsServiceImpl.java 67 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297
  1. package com.xjrsoft.module.classtime.service.impl;
  2. import cn.hutool.core.bean.BeanUtil;
  3. import cn.hutool.core.util.StrUtil;
  4. import com.alibaba.excel.EasyExcel;
  5. import com.alibaba.excel.support.ExcelTypeEnum;
  6. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  7. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  8. import com.github.yulichang.base.MPJBaseServiceImpl;
  9. import com.github.yulichang.wrapper.MPJLambdaWrapper;
  10. import com.google.gson.Gson;
  11. import com.google.gson.JsonArray;
  12. import com.google.gson.JsonElement;
  13. import com.google.gson.JsonObject;
  14. import com.google.gson.JsonParser;
  15. import com.xjrsoft.common.enums.CourseAdjustTypeEnum;
  16. import com.xjrsoft.common.enums.CourseTimeTypeEnum;
  17. import com.xjrsoft.common.enums.DeleteMark;
  18. import com.xjrsoft.common.enums.EnabledMark;
  19. import com.xjrsoft.common.exception.MyException;
  20. import com.xjrsoft.common.mybatis.SqlRunnerAdapter;
  21. import com.xjrsoft.common.utils.VoToColumnUtil;
  22. import com.xjrsoft.module.classtime.dto.AddClassTimeStatisticsDto;
  23. import com.xjrsoft.module.classtime.dto.CourseRecordDto;
  24. import com.xjrsoft.module.classtime.entity.ClassTimeDelete;
  25. import com.xjrsoft.module.classtime.entity.ClassTimeStatistics;
  26. import com.xjrsoft.module.classtime.entity.ClassTimeStatisticsAdministration;
  27. import com.xjrsoft.module.classtime.entity.ClassTimeStatisticsRecord;
  28. import com.xjrsoft.module.classtime.entity.ClassTimeStatisticsSet;
  29. import com.xjrsoft.module.classtime.mapper.ClassTimeStatisticsAdministrationMapper;
  30. import com.xjrsoft.module.classtime.mapper.ClassTimeStatisticsMapper;
  31. import com.xjrsoft.module.classtime.mapper.ClassTimeStatisticsRecordMapper;
  32. import com.xjrsoft.module.classtime.service.IClassTimeDeleteService;
  33. import com.xjrsoft.module.classtime.service.IClassTimeStatisticsService;
  34. import com.xjrsoft.module.classtime.service.IClassTimeStatisticsSetService;
  35. import com.xjrsoft.module.classtime.vo.ClassTimeStatisticsAdministrationExcelVo;
  36. import com.xjrsoft.module.classtime.vo.ClassTimeStatisticsRecordVo;
  37. import com.xjrsoft.module.classtime.vo.CourseClassTimeStatisticsRecordVo;
  38. import com.xjrsoft.module.classtime.vo.CourseListVo;
  39. import com.xjrsoft.module.classtime.vo.TeacherListVo;
  40. import com.xjrsoft.module.classtime.vo.WeekTimeRangeVo;
  41. import com.xjrsoft.module.oa.entity.WfTeacherCourseTime;
  42. import com.xjrsoft.module.organization.entity.User;
  43. import com.xjrsoft.module.organization.service.IUserService;
  44. import com.xjrsoft.module.system.entity.DictionaryDetail;
  45. import com.xjrsoft.module.system.service.IDictionarydetailService;
  46. import com.xjrsoft.module.teacher.entity.BaseTeacher;
  47. import com.xjrsoft.module.teacher.entity.XjrUser;
  48. import lombok.AllArgsConstructor;
  49. import me.zhyd.oauth.log.Log;
  50. import org.apache.poi.ss.usermodel.Cell;
  51. import org.apache.poi.ss.usermodel.CellStyle;
  52. import org.apache.poi.ss.usermodel.Font;
  53. import org.apache.poi.ss.usermodel.HorizontalAlignment;
  54. import org.apache.poi.ss.usermodel.Row;
  55. import org.apache.poi.ss.usermodel.Sheet;
  56. import org.apache.poi.ss.usermodel.VerticalAlignment;
  57. import org.apache.poi.ss.usermodel.Workbook;
  58. import org.apache.poi.ss.util.CellRangeAddress;
  59. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  60. import org.springframework.stereotype.Service;
  61. import org.springframework.transaction.annotation.Transactional;
  62. import org.springframework.web.multipart.MultipartFile;
  63. import java.io.ByteArrayOutputStream;
  64. import java.math.BigDecimal;
  65. import java.math.RoundingMode;
  66. import java.time.DayOfWeek;
  67. import java.time.LocalDate;
  68. import java.time.format.DateTimeFormatter;
  69. import java.time.temporal.ChronoUnit;
  70. import java.util.ArrayList;
  71. import java.util.Arrays;
  72. import java.util.Date;
  73. import java.util.HashMap;
  74. import java.util.LinkedHashMap;
  75. import java.util.List;
  76. import java.util.Map;
  77. import java.util.concurrent.CompletableFuture;
  78. import java.util.stream.Collectors;
  79. /**
  80. * @title: 课时统计
  81. * @Author dzx
  82. * @Date: 2024-09-26
  83. * @Version 1.0
  84. */
  85. @Service
  86. @AllArgsConstructor
  87. public class ClassTimeStatisticsServiceImpl extends MPJBaseServiceImpl<ClassTimeStatisticsMapper, ClassTimeStatistics> implements IClassTimeStatisticsService {
  88. private final ClassTimeStatisticsMapper statisticsMapper;
  89. private final ClassTimeStatisticsRecordMapper recordMapper;
  90. private final IClassTimeStatisticsSetService statisticsSetService;
  91. private final IClassTimeDeleteService deleteService;
  92. private final IDictionarydetailService dictionaryService;
  93. private final ClassTimeStatisticsAdministrationMapper administrationMapper;
  94. private final IUserService userService;
  95. @Override
  96. @Transactional(rollbackFor = Exception.class)
  97. public Boolean add(ClassTimeStatistics classTimeStatistics) {
  98. statisticsMapper.insert(classTimeStatistics);
  99. return true;
  100. }
  101. @Override
  102. public Boolean addCourse(AddClassTimeStatisticsDto dto) {
  103. ClassTimeStatistics classTimeStatistics = BeanUtil.toBean(dto, ClassTimeStatistics.class);
  104. classTimeStatistics.setStatus(0);
  105. classTimeStatistics.setCategory(2);
  106. classTimeStatistics.setCreateDate(new Date());
  107. List<WeekTimeRangeVo> weekTimeRangeVos = calculateNaturalWeeks(classTimeStatistics.getStartDate(), classTimeStatistics.getEndDate());
  108. classTimeStatistics.setWeeks(weekTimeRangeVos.size());
  109. //查询最新权重并保存到统计中
  110. Integer category = 3;
  111. List<ClassTimeStatisticsSet> list = statisticsSetService.list(
  112. new QueryWrapper<ClassTimeStatisticsSet>().lambda()
  113. .eq(ClassTimeStatisticsSet::getCategory, category)
  114. .orderByDesc(ClassTimeStatisticsSet::getCreateDate)
  115. );
  116. if(list.isEmpty()){
  117. throw new MyException("请先设置权重并进行保存");
  118. }
  119. classTimeStatistics.setWeightSetJson(list.get(0).getJsonContent());
  120. this.save(classTimeStatistics);
  121. CompletableFuture.runAsync(() -> {
  122. refreshCourseRecord(classTimeStatistics);
  123. });
  124. return true;
  125. }
  126. @Override
  127. @Transactional(rollbackFor = Exception.class)
  128. public Boolean update(ClassTimeStatistics classTimeStatistics) {
  129. statisticsMapper.updateById(classTimeStatistics);
  130. return true;
  131. }
  132. @Override
  133. public Boolean updateCourse(ClassTimeStatistics classTimeStatistics) {
  134. List<WeekTimeRangeVo> weekTimeRangeVos = calculateNaturalWeeks(classTimeStatistics.getStartDate(), classTimeStatistics.getEndDate());
  135. classTimeStatistics.setWeeks(weekTimeRangeVos.size());
  136. statisticsMapper.updateById(classTimeStatistics);
  137. return true;
  138. }
  139. @Override
  140. @Transactional(rollbackFor = Exception.class)
  141. public Boolean delete(List<Long> ids) {
  142. statisticsMapper.deleteBatchIds(ids);
  143. recordMapper.delete(Wrappers.lambdaQuery(ClassTimeStatisticsRecord.class).in(ClassTimeStatisticsRecord::getClassTimeStatisticsId, ids));
  144. return true;
  145. }
  146. @Override
  147. @Transactional(rollbackFor = Exception.class)
  148. public Boolean add(AddClassTimeStatisticsDto dto) {
  149. ClassTimeStatistics classTimeStatistics = BeanUtil.toBean(dto, ClassTimeStatistics.class);
  150. classTimeStatistics.setStatus(0);
  151. classTimeStatistics.setCategory(1);
  152. classTimeStatistics.setCreateDate(new Date());
  153. //查询最新权重并保存到统计中
  154. Integer category = 1;
  155. List<ClassTimeStatisticsSet> list = statisticsSetService.list(
  156. new QueryWrapper<ClassTimeStatisticsSet>().lambda()
  157. .eq(ClassTimeStatisticsSet::getCategory, category)
  158. .orderByDesc(ClassTimeStatisticsSet::getCreateDate)
  159. );
  160. if(list.isEmpty()){
  161. throw new MyException("请先设置权重并进行保存");
  162. }
  163. classTimeStatistics.setWeightSetJson(list.get(0).getJsonContent());
  164. //查询最新费用并保存到统计中
  165. category = 2;
  166. list = statisticsSetService.list(
  167. new QueryWrapper<ClassTimeStatisticsSet>().lambda()
  168. .eq(ClassTimeStatisticsSet::getCategory, category)
  169. .orderByDesc(ClassTimeStatisticsSet::getCreateDate)
  170. );
  171. if(list.isEmpty()){
  172. throw new MyException("请先设置费用并进行保存");
  173. }
  174. classTimeStatistics.setCostSetJson(list.get(0).getJsonContent());
  175. this.save(classTimeStatistics);
  176. CompletableFuture.runAsync(() -> {
  177. refreshRecord(classTimeStatistics);
  178. });
  179. return true;
  180. }
  181. /**
  182. * 1、通过xjr_user和base_teacher查询所有教师,查询聘用类型为:正式聘用和外聘的
  183. * 2、根据统计的开始日期和结束日期查询课时补充(wf_teacher_course_time)中的教研会、督导听课、临近三年退休政策、出题、阅卷、周末培优
  184. * 3、根绝统计的开始日期和结束日期查询课程表(course_table)中的所有课程数据
  185. * 4、查询补班日期下的所有课程
  186. * 5、属于节假日的课程不查询
  187. */
  188. @Override
  189. @Transactional(rollbackFor = Exception.class)
  190. public Boolean refreshRecord(ClassTimeStatistics statistics) {
  191. try {
  192. // 1、查询教师
  193. List<TeacherListVo> teacherList = this.baseMapper.getTeacherList();
  194. // 2、查询补课课时
  195. List<DictionaryDetail> CourseTimeTypeList = dictionaryService.list(
  196. new QueryWrapper<DictionaryDetail>().lambda()
  197. .eq(DictionaryDetail::getItemId, 1833772737004875778L)
  198. .eq(DictionaryDetail::getDeleteMark, DeleteMark.NODELETE.getCode())
  199. .eq(DictionaryDetail::getEnabledMark, EnabledMark.ENABLED.getCode())
  200. .orderByAsc(DictionaryDetail::getCode)
  201. );
  202. Map<String, String> CourseTimeTypeMap = CourseTimeTypeList.stream().collect(Collectors.toMap(DictionaryDetail::getCode, DictionaryDetail::getName));
  203. List<WfTeacherCourseTime> courseTimeList = this.baseMapper.getWfTeacherCourseTimeList(statistics);
  204. //按照课时补充类型分类统计
  205. Map<String, List<WfTeacherCourseTime>> courseTimeMap = courseTimeList.stream().collect(Collectors.groupingBy(WfTeacherCourseTime::getCourseTimeType));
  206. JsonParser parser = new JsonParser();
  207. //费用设置jsonArray
  208. JsonArray costSetArray = parser.parse(statistics.getCostSetJson()).getAsJsonArray();
  209. Map<String, Double> costSetMap = new LinkedHashMap<>();
  210. for (JsonElement jsonElement : costSetArray) {
  211. JsonObject object = jsonElement.getAsJsonObject();
  212. costSetMap.put(object.get("field").getAsString(), object.get("value").getAsDouble());
  213. }
  214. //权重设置jsonArray
  215. JsonArray weightSetArray = parser.parse(statistics.getWeightSetJson()).getAsJsonArray();
  216. Map<String, Double> weightSetMap = new LinkedHashMap<>();
  217. for (JsonElement jsonElement : weightSetArray) {
  218. JsonObject object = jsonElement.getAsJsonObject();
  219. weightSetMap.put(object.get("label").getAsString(), object.get("value").getAsDouble());
  220. }
  221. //计算出这个时间段内一共多少周
  222. List<WeekTimeRangeVo> weekTimeRangeVos = calculateNaturalWeeks(statistics.getStartDate(), statistics.getEndDate());
  223. //取出所有的日期
  224. List<LocalDate> allDateList = getDatesBetween(statistics.getStartDate(), statistics.getEndDate());
  225. //查询课程数据,排除开节假日的数据
  226. List<CourseListVo> allCourseList = this.baseMapper.getCourseList(statistics);
  227. allCourseList.addAll(this.baseMapper.getHolidayReplaceCourseList(statistics));
  228. //查询删除课时的数据,将每个班删除的具体日期统计出来
  229. List<ClassTimeDelete> deleteList = deleteService.list(
  230. new QueryWrapper<ClassTimeDelete>().lambda()
  231. .ne(ClassTimeDelete::getStatus, 2)
  232. .eq(ClassTimeDelete::getEnabledMark, EnabledMark.ENABLED.getCode())
  233. .eq(ClassTimeDelete::getDeleteMark, DeleteMark.NODELETE.getCode())
  234. );
  235. Map<Long, List<ClassTimeDelete>> deleteDataMap = deleteList.stream().collect(Collectors.groupingBy(ClassTimeDelete::getClassId));
  236. Map<Long, Map<LocalDate, String>> deleteMap = new HashMap<>();//将每个班级计算出来所有被删除的日期存入map
  237. for (Long classId : deleteDataMap.keySet()) {
  238. Map<LocalDate, String> dateMap = new HashMap<>();
  239. for (ClassTimeDelete classTimeDelete : deleteDataMap.get(classId)) {
  240. LocalDate currentDate = classTimeDelete.getStartDate();
  241. while (!currentDate.isAfter(classTimeDelete.getEndDate())) {
  242. dateMap.put(currentDate, classTimeDelete.getTimePeriod());
  243. currentDate = currentDate.plusDays(1); // 增加一天
  244. }
  245. }
  246. //去重并存到map中
  247. deleteMap.put(classId, dateMap);
  248. }
  249. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
  250. //查询所有老师发起顶课通过的数量,也要分别计算早自习、晚自习、正课、如果日期出入课时删除中,也需要跳过
  251. List<CourseListVo> allSubstituteList = this.baseMapper.getSubstituteList(statistics);
  252. List<ClassTimeStatisticsRecord> insertList = new ArrayList<>();
  253. //循环教师,准备开始计算
  254. for (TeacherListVo teacher : teacherList) {
  255. ClassTimeStatisticsRecord record = new ClassTimeStatisticsRecord();
  256. record.setUserId(teacher.getId());
  257. record.setClassTimeStatisticsId(statistics.getId());
  258. record.setEmployType(teacher.getEmployType());
  259. JsonArray allClassTimeDataArray = new JsonArray();
  260. Double allClassTime = 0D;
  261. //计算补充课时,算作正课课时,但是计算超出课时时不计算这部分
  262. JsonObject courseTimeTypeJson = new JsonObject();
  263. Double courseTimeTypeTime = 0D;
  264. for (String courseTimeType : CourseTimeTypeMap.keySet()) {
  265. List<WfTeacherCourseTime> courseTimes = courseTimeMap.get(courseTimeType);
  266. if(courseTimes == null){
  267. courseTimeTypeJson.addProperty(CourseTimeTypeMap.get(courseTimeType), 0);
  268. continue;
  269. }
  270. double sum = courseTimes.stream()
  271. .filter(x -> x.getTeacherIds().contains(teacher.getId().toString()))
  272. .mapToDouble(WfTeacherCourseTime::getCourseTime).sum();
  273. allClassTime = allClassTime + sum;
  274. courseTimeTypeTime = courseTimeTypeTime + sum;
  275. courseTimeTypeJson.addProperty(CourseTimeTypeMap.get(courseTimeType), sum);
  276. for (LocalDate localDate : allDateList) {
  277. double sum1 = courseTimes.stream()
  278. .filter(x -> x.getTeacherIds().contains(teacher.getId().toString()) && localDate.equals(x.getScheduleDate()))
  279. .mapToDouble(WfTeacherCourseTime::getCourseTime).sum();
  280. JsonObject courseJson = new JsonObject();
  281. courseJson.addProperty("type", CourseTimeTypeMap.get(courseTimeType));
  282. courseJson.addProperty("scheduleDate", localDate.format(formatter));
  283. courseJson.addProperty("content", sum1);
  284. courseJson.addProperty("adjustType", "");
  285. allClassTimeDataArray.add(courseJson);
  286. }
  287. }
  288. record.setCourseTimeTypeData(courseTimeTypeJson.toString());
  289. //早自习、正课、晚辅
  290. Double classTime7 = 0D,classTime8 = 0D,classTime9 = 0D,classTime11 = 0D;
  291. List<String> zkList = Arrays.asList("上1","上2","上3","上4","下1","下2","下3","下4");
  292. List<String> wzxList = Arrays.asList("晚1","晚2","晚3");
  293. //查询出老师的课程
  294. List<CourseListVo> courseList = allCourseList.stream()
  295. .filter(x -> x.getTeacherId().contains(teacher.getId().toString()))
  296. .collect(Collectors.toList());
  297. //循环,统计出各项数据
  298. for (CourseListVo courseListVo : courseList) {
  299. //如果这个课程数据包含在被删除的课时中,跳过不计算
  300. Map<LocalDate, String> deleteDates = deleteMap.get(courseListVo.getClassId());
  301. JsonObject courseJson = new JsonObject();
  302. if(deleteDates != null && deleteDates.containsKey(courseListVo.getScheduleDate()) && deleteDates.get(courseListVo.getScheduleDate()) != null
  303. && deleteDates.get(courseListVo.getScheduleDate()).contains(courseListVo.getTimeNumber()) ){
  304. courseJson.addProperty("type", courseListVo.getShortName());
  305. courseJson.addProperty("scheduleDate", courseListVo.getScheduleDate().format(formatter));
  306. courseJson.addProperty("content", "");
  307. courseJson.addProperty("adjustType", "course_delete");
  308. allClassTimeDataArray.add(courseJson);
  309. continue;
  310. }
  311. if("早自习".equals(courseListVo.getShortName())){
  312. classTime7 += weightSetMap.get(courseListVo.getShortName()) == null ? 0d : weightSetMap.get(courseListVo.getShortName());
  313. }else if(zkList.contains(courseListVo.getShortName())){
  314. classTime8 += weightSetMap.get(courseListVo.getShortName()) == null ? 0d : weightSetMap.get(courseListVo.getShortName());
  315. }else if(wzxList.contains(courseListVo.getShortName())){
  316. classTime9 += weightSetMap.get(courseListVo.getShortName()) == null ? 0d : weightSetMap.get(courseListVo.getShortName());
  317. }
  318. if(courseListVo.getAdjustType() != null && !courseListVo.getAdjustType().isEmpty()){
  319. if(CourseAdjustTypeEnum.courseExchange.getCode().equals(courseListVo.getAdjustType())){
  320. classTime11 += weightSetMap.get(courseListVo.getShortName());
  321. }
  322. }
  323. courseJson.addProperty("type", courseListVo.getShortName());
  324. courseJson.addProperty("scheduleDate", courseListVo.getScheduleDate().format(formatter));
  325. courseJson.addProperty("content", courseListVo.getClassName() + "," + courseListVo.getCourseName());
  326. courseJson.addProperty("adjustType", courseListVo.getAdjustType() == null?"":courseListVo.getAdjustType());
  327. allClassTimeDataArray.add(courseJson);
  328. }
  329. record.setClassTime7(classTime7);
  330. record.setClassTime8(classTime8);
  331. record.setClassTime9(classTime9);
  332. record.setClassTime11(classTime11);
  333. JsonObject weekDataJson = new JsonObject();
  334. Double allTimes = 0d;
  335. Double allCcksTime = 0d;//总的超出课时,从每周的正课课时中计算
  336. BigDecimal ccksTime = BigDecimal.ZERO;//超出课时标准(每周)
  337. if("FB1601".equals(teacher.getEmployType())){
  338. ccksTime = BigDecimal.valueOf(costSetMap.get("cost7"));
  339. }else{//外聘FB1605、合作人员FB1609
  340. ccksTime = BigDecimal.valueOf(costSetMap.get("cost8"));
  341. }
  342. //存每周的数据
  343. for (WeekTimeRangeVo timeRangeVo : weekTimeRangeVos) {
  344. Double zkTimes = 0d;
  345. Double wzxTimes = 0d;
  346. Double tkTimes = 0d;
  347. for (CourseListVo courseListVo : courseList) {
  348. LocalDate scheduleDate = courseListVo.getScheduleDate();
  349. //如果这个课程数据包含在被删除的课时中,跳过不计算
  350. Map<LocalDate, String> deleteDates = deleteMap.get(courseListVo.getClassId());
  351. if(deleteDates != null && deleteDates.containsKey(scheduleDate) && deleteDates.get(courseListVo.getScheduleDate()) != null
  352. && deleteDates.get(courseListVo.getScheduleDate()).contains(courseListVo.getTimeNumber())){
  353. continue;
  354. }
  355. if(!( (scheduleDate.equals(timeRangeVo.getMondayDate()) || scheduleDate.isAfter(timeRangeVo.getMondayDate()))
  356. && (scheduleDate.equals(timeRangeVo.getSundayDate()) || scheduleDate.isBefore(timeRangeVo.getSundayDate())))){
  357. continue;
  358. }
  359. if("早自习".equals(courseListVo.getShortName())){
  360. zkTimes += weightSetMap.get(courseListVo.getShortName()) == null ? 0d : weightSetMap.get(courseListVo.getShortName());
  361. }else if(zkList.contains(courseListVo.getShortName())){
  362. zkTimes += weightSetMap.get(courseListVo.getShortName()) == null ? 0d : weightSetMap.get(courseListVo.getShortName());
  363. }else if(wzxList.contains(courseListVo.getShortName())){
  364. wzxTimes += weightSetMap.get(courseListVo.getShortName()) == null ? 0d : weightSetMap.get(courseListVo.getShortName());
  365. }
  366. if(courseListVo.getAdjustType() != null && !courseListVo.getAdjustType().isEmpty()){
  367. if(CourseAdjustTypeEnum.courseExchange.getCode().equals(courseListVo.getAdjustType())){
  368. tkTimes += weightSetMap.get(courseListVo.getShortName());
  369. }
  370. }
  371. }
  372. //计算该老师发起的事假、病假顶课数据
  373. List<CourseListVo> substituteList = allSubstituteList.stream().filter(x -> x.getExchangeTeacherId().equals(teacher.getId()))
  374. .collect(Collectors.toList());
  375. Double reduceTime = 0d;//顶课课时
  376. for (CourseListVo courseListVo : substituteList) {
  377. Map<LocalDate, String> deleteDates = deleteMap.get(courseListVo.getClassId());
  378. if(deleteDates != null && deleteDates.get(courseListVo.getScheduleDate()) != null && deleteDates.get(courseListVo.getScheduleDate()).contains(courseListVo.getTimeNumber())){
  379. continue;
  380. }
  381. if(!( (courseListVo.getScheduleDate().equals(timeRangeVo.getMondayDate()) || courseListVo.getScheduleDate().isAfter(timeRangeVo.getMondayDate()))
  382. && (courseListVo.getScheduleDate().equals(timeRangeVo.getSundayDate()) || courseListVo.getScheduleDate().isBefore(timeRangeVo.getSundayDate())))){
  383. continue;
  384. }
  385. reduceTime += weightSetMap.get(courseListVo.getShortName());
  386. }
  387. substituteList = allSubstituteList.stream().filter(x -> x.getTeacherId().equals(teacher.getId().toString()))
  388. .collect(Collectors.toList());
  389. for (CourseListVo courseListVo : substituteList) {
  390. Map<LocalDate, String> deleteDates = deleteMap.get(courseListVo.getClassId());
  391. if(deleteDates != null && deleteDates.get(courseListVo.getScheduleDate()) != null
  392. ){
  393. String timeNumbers = deleteDates.get(courseListVo.getScheduleDate());
  394. if(StrUtil.isNotEmpty(timeNumbers) && timeNumbers.contains(courseListVo.getTimeNumber())){
  395. continue;
  396. }
  397. }
  398. if(!( (courseListVo.getScheduleDate().equals(timeRangeVo.getMondayDate()) || courseListVo.getScheduleDate().isAfter(timeRangeVo.getMondayDate()))
  399. && (courseListVo.getScheduleDate().equals(timeRangeVo.getSundayDate()) || courseListVo.getScheduleDate().isBefore(timeRangeVo.getSundayDate())))){
  400. continue;
  401. }
  402. reduceTime = reduceTime - weightSetMap.get(courseListVo.getShortName());
  403. }
  404. timeRangeVo.setZkTimes(zkTimes);
  405. timeRangeVo.setWzxTimes(wzxTimes);
  406. timeRangeVo.setDkTimes(reduceTime);
  407. timeRangeVo.setTkTimes(tkTimes);
  408. allTimes += (zkTimes + wzxTimes);
  409. if(zkTimes > ccksTime.doubleValue()){
  410. allCcksTime += zkTimes - ccksTime.doubleValue();
  411. }
  412. }
  413. weekDataJson.add("weekData", new Gson().toJsonTree(weekTimeRangeVos));
  414. weekDataJson.addProperty("allTimes", allTimes);
  415. record.setWeekData(weekDataJson.toString());
  416. //计算总课时
  417. allClassTime = allClassTime + classTime7 + classTime8 + classTime9;
  418. record.setAllClassTime(allClassTime);
  419. //计算费用,根据聘用类型判断费用问题
  420. Double classTimeAmount = 0d;
  421. Double beyondClassTimeAmount = 0d;
  422. BigDecimal zzxCost = BigDecimal.ZERO;//早自习费用
  423. if("FB1601".equals(teacher.getEmployType())){
  424. zzxCost = BigDecimal.valueOf(costSetMap.get("cost1"));
  425. }else{//外聘FB1605、合作人员FB1609
  426. zzxCost = BigDecimal.valueOf(costSetMap.get("cost2"));
  427. }
  428. classTimeAmount += BigDecimal.valueOf(classTime7).multiply(zzxCost).doubleValue();
  429. BigDecimal zkCost = BigDecimal.ZERO;//正课费用
  430. if("FB1601".equals(teacher.getEmployType())){
  431. zkCost = BigDecimal.valueOf(costSetMap.get("cost3"));
  432. }else{//外聘FB1605、合作人员FB1609
  433. zkCost = BigDecimal.valueOf(costSetMap.get("cost4"));
  434. }
  435. double classTime = classTime8
  436. + courseTimeTypeTime;
  437. classTimeAmount += BigDecimal.valueOf(classTime).multiply(zkCost).doubleValue();
  438. BigDecimal wzxCost = BigDecimal.ZERO;//晚自习费用
  439. if("FB1601".equals(teacher.getEmployType())){
  440. wzxCost = BigDecimal.valueOf(costSetMap.get("cost5"));
  441. }else{//外聘FB1605、合作人员FB1609
  442. wzxCost = BigDecimal.valueOf(costSetMap.get("cost6"));
  443. }
  444. classTimeAmount += BigDecimal.valueOf(classTime9).multiply(wzxCost).doubleValue();
  445. /**
  446. * 顶课:
  447. * 1、流程发起人(被顶老师)的课被顶课老师上了,那么被顶老师的课时就会-1,顶课老师课时就会+1
  448. * 2、顶课老师会根据规则额外加一笔费用,根据设置1课时额外加4元
  449. * 3、顶课类型为事假和病假的时候会扣除被顶老师的费用,根据设置为扣除4元
  450. */
  451. BigDecimal reduceTimeAmount = BigDecimal.ZERO;
  452. {
  453. //计算该老师发起的事假、病假顶课数据
  454. List<CourseListVo> substituteList = allSubstituteList.stream().filter(x -> x.getExchangeTeacherId().equals(teacher.getId()))
  455. .collect(Collectors.toList());
  456. Double reduceTime = 0d;//顶课课时
  457. Double dkClassTime = 0d;//去顶课的数量,所有顶课数量
  458. for (CourseListVo courseListVo : substituteList) {
  459. Map<LocalDate, String> deleteDates = deleteMap.get(courseListVo.getClassId());
  460. if(deleteDates != null && deleteDates.get(courseListVo.getScheduleDate()) != null && deleteDates.get(courseListVo.getScheduleDate()).contains(courseListVo.getTimeNumber())){
  461. continue;
  462. }
  463. reduceTime += weightSetMap.get(courseListVo.getShortName());
  464. dkClassTime += weightSetMap.get(courseListVo.getShortName());
  465. }
  466. Double bdkClassTime = 0d;//发起顶课的数量,只统计事假和病假的数量
  467. substituteList = allSubstituteList.stream().filter(x -> x.getTeacherId().equals(teacher.getId().toString()))
  468. .collect(Collectors.toList());
  469. for (CourseListVo courseListVo : substituteList) {
  470. Map<LocalDate, String> deleteDates = deleteMap.get(courseListVo.getClassId());
  471. if(deleteDates != null && deleteDates.get(courseListVo.getScheduleDate()) != null && deleteDates.get(courseListVo.getScheduleDate()).contains(courseListVo.getTimeNumber())){
  472. continue;
  473. }
  474. reduceTime = reduceTime - weightSetMap.get(courseListVo.getShortName());
  475. if("sick _leave".equals(courseListVo.getReason()) || "leave_absence".equals(courseListVo.getReason())){
  476. bdkClassTime += weightSetMap.get(courseListVo.getShortName());
  477. }
  478. }
  479. record.setClassTime10(reduceTime);
  480. BigDecimal dkCost = BigDecimal.ZERO;//顶课费用,顶课老师加钱
  481. if("FB1601".equals(teacher.getEmployType())){
  482. dkCost = BigDecimal.valueOf(costSetMap.get("cost11"));
  483. }else{//外聘FB1605、合作人员FB1609
  484. dkCost = BigDecimal.valueOf(costSetMap.get("cost12"));
  485. }
  486. reduceTimeAmount = BigDecimal.valueOf(dkClassTime).multiply(dkCost);
  487. BigDecimal bdkCost = BigDecimal.ZERO;//顶课费用,被顶课老师扣钱
  488. if("FB1601".equals(teacher.getEmployType())){
  489. bdkCost = BigDecimal.valueOf(costSetMap.get("cost13")==null?0:costSetMap.get("cost13"));
  490. }else{//外聘FB1605、合作人员FB1609
  491. bdkCost = BigDecimal.valueOf(costSetMap.get("cost14")==null?0:costSetMap.get("cost14"));
  492. }
  493. //计算被扣除的费用
  494. reduceTimeAmount = reduceTimeAmount.subtract(bdkCost.multiply(BigDecimal.valueOf(bdkClassTime)));
  495. }
  496. record.setClassTimeAmount(classTimeAmount);
  497. //计算超出的课时,需要先计算出每个周的开始结束时间
  498. BigDecimal ccksCost = BigDecimal.ZERO;
  499. if("FB1601".equals(teacher.getEmployType())){
  500. ccksCost = BigDecimal.valueOf(costSetMap.get("cost9"));
  501. }else{//外聘FB1605、合作人员FB1609
  502. ccksCost = BigDecimal.valueOf(costSetMap.get("cost10"));
  503. }
  504. //计算出总的超出课时并计算超课时费
  505. beyondClassTimeAmount = BigDecimal.valueOf(allCcksTime).multiply(ccksCost).doubleValue();
  506. if(!"FB1601".equals(teacher.getEmployType())){
  507. record.setBeyondClassTimeAmount(beyondClassTimeAmount);
  508. }
  509. //计算总金额,课时费+超课时费
  510. Double totalAmount = classTimeAmount + beyondClassTimeAmount + reduceTimeAmount.doubleValue();
  511. record.setTotalAmount(totalAmount);
  512. record.setAllClassTimeData(calculateClassTime(allClassTimeDataArray, weightSetMap, allDateList));
  513. record.setCreateDate(new Date());
  514. insertList.add(record);
  515. }
  516. if(!insertList.isEmpty()){
  517. //先删除
  518. String sql = "delete from class_time_statistics_record where class_time_statistics_id = " + statistics.getId();
  519. SqlRunnerAdapter.db().delete(sql);
  520. for (ClassTimeStatisticsRecord record : insertList) {
  521. recordMapper.insert(record);
  522. }
  523. }
  524. statistics.setAllClassTime(insertList.stream().filter(x -> x.getAllClassTime() != null).mapToDouble(ClassTimeStatisticsRecord::getAllClassTime).sum());
  525. statistics.setTotalAmount(insertList.stream().filter(x -> x.getTotalAmount() != null).mapToDouble(ClassTimeStatisticsRecord::getTotalAmount).sum());
  526. statistics.setBeyondClassTimeAmount(insertList.stream().filter(x -> x.getBeyondClassTimeAmount() != null).mapToDouble(ClassTimeStatisticsRecord::getBeyondClassTimeAmount).sum());
  527. statistics.setClassTimeAmount(insertList.stream().filter(x -> x.getClassTimeAmount() != null).mapToDouble(ClassTimeStatisticsRecord::getClassTimeAmount).sum());
  528. }catch (Exception e){
  529. Log.error(e.getMessage(), e);
  530. throw new MyException("统计出错,请联系管理员");
  531. }finally {
  532. statistics.setStatus(1);
  533. this.updateById(statistics);
  534. }
  535. return true;
  536. }
  537. @Override
  538. public Boolean lockData(Long id) {
  539. ClassTimeStatistics statistics = this.getById(id);
  540. return null;
  541. }
  542. @Override
  543. public List<ClassTimeStatisticsRecordVo> getRecordList(Long id) {
  544. return this.baseMapper.getRecordList(id);
  545. }
  546. @Override
  547. public List<CourseClassTimeStatisticsRecordVo> getCourseRecordList(CourseRecordDto dto) {
  548. return this.baseMapper.getCourseRecordList(dto);
  549. }
  550. /**
  551. * 导出课时统计明细
  552. */
  553. @Override
  554. public byte[] recordExport(Long id) {
  555. try {
  556. //1、查询数据
  557. List<ClassTimeStatisticsRecordVo> recordList = this.baseMapper.getRecordList(id);
  558. //计算出一共有多少周
  559. ClassTimeStatistics statistics = this.getById(id);
  560. List<WeekTimeRangeVo> weekTimeRangeVos = calculateNaturalWeeks(statistics.getStartDate(), statistics.getEndDate());
  561. List<DictionaryDetail> CourseTimeTypeList = dictionaryService.list(
  562. new QueryWrapper<DictionaryDetail>().lambda()
  563. .eq(DictionaryDetail::getItemId, 1833772737004875778L)
  564. .eq(DictionaryDetail::getDeleteMark, DeleteMark.NODELETE.getCode())
  565. .orderByAsc(DictionaryDetail::getCode)
  566. );
  567. /**
  568. * 2、将查询出来的数据按照表头转换成二维数组
  569. * 前端固定表头:序号、工号、姓名、教研会、督导听课、临近三年退休政策、出题、阅卷、周末培优、早自习、正课(含调顶课时)、晚辅(含调顶课时)、顶课、调课
  570. * 中间动态表头:每周,总课时(含调顶课节)、顶课(节)、调课(节)、晚辅(节)......课时晚辅合计
  571. * 后端固定表头:总课时、课时费(元)、外聘教师超课时费(元)、总金额(元)
  572. */
  573. //计算一共多少列
  574. int column = 12 + CourseTimeTypeList.size() + (4 * weekTimeRangeVos.size());
  575. List<ArrayList<String>> dataList = new ArrayList<>();
  576. Integer sortCode = 1;
  577. JsonParser parser = new JsonParser();
  578. for (ClassTimeStatisticsRecordVo recordVo : recordList) {
  579. ArrayList<String> rowData = new ArrayList<>();
  580. rowData.add(sortCode.toString());//序号
  581. rowData.add(recordVo.getUserName());//工号
  582. rowData.add(recordVo.getName());//姓名
  583. JsonObject courseTimeTypeJson = parser.parse(recordVo.getCourseTimeTypeData()).getAsJsonObject();
  584. for (DictionaryDetail dictionaryDetail : CourseTimeTypeList) {
  585. if (courseTimeTypeJson.get(dictionaryDetail.getName()) == null) {
  586. continue;
  587. }
  588. Double courseTimeTypeTime = courseTimeTypeJson.get(dictionaryDetail.getName()).getAsDouble();
  589. rowData.add(courseTimeTypeTime.toString());//教研会
  590. }
  591. // rowData.add(recordVo.getClassTime1()==null?"":recordVo.getClassTime1().toString());//教研会
  592. // rowData.add(recordVo.getClassTime2()==null?"":recordVo.getClassTime2().toString());//督导听课
  593. // rowData.add(recordVo.getClassTime3()==null?"":recordVo.getClassTime3().toString());//临近三年退休政策
  594. // rowData.add(recordVo.getClassTime4()==null?"":recordVo.getClassTime4().toString());//出题
  595. // rowData.add(recordVo.getClassTime5()==null?"":recordVo.getClassTime5().toString());//阅卷
  596. // rowData.add(recordVo.getClassTime6()==null?"":recordVo.getClassTime6().toString());//周末培优
  597. rowData.add(recordVo.getClassTime7()==null?"":recordVo.getClassTime7().toString());//早自习
  598. rowData.add(recordVo.getClassTime8()==null?"":recordVo.getClassTime8().toString());//正课(含调顶课时)
  599. rowData.add(recordVo.getClassTime9()==null?"":recordVo.getClassTime9().toString());//晚辅(含调顶课时)
  600. rowData.add(recordVo.getClassTime10()==null?"":recordVo.getClassTime10().toString());//顶课
  601. rowData.add(recordVo.getClassTime11()==null?"":recordVo.getClassTime11().toString());//调课
  602. //每周数据
  603. JsonObject weekDataJson = parser.parse(recordVo.getWeekData()).getAsJsonObject();
  604. JsonArray weekDataArray = weekDataJson.getAsJsonArray("weekData");
  605. for (int i = 0; i < weekDataArray.size(); i ++){
  606. JsonObject jsonElement = weekDataArray.get(i).getAsJsonObject();
  607. rowData.add(jsonElement.get("zkTimes").getAsString());//总课时(含调顶课节)
  608. rowData.add(jsonElement.get("dkTimes").getAsString());//顶课(节)
  609. rowData.add(jsonElement.get("tkTimes").getAsString());//调课(节)
  610. rowData.add(jsonElement.get("wzxTimes").getAsString());//晚辅(节)
  611. }
  612. rowData.add(weekDataJson.get("allTimes").getAsString());//课时晚辅合计
  613. rowData.add(recordVo.getAllClassTime().toString());//总课时
  614. rowData.add(recordVo.getClassTimeAmount().toString());//课时费(元)
  615. rowData.add(recordVo.getBeyondClassTimeAmount()==null?"":recordVo.getBeyondClassTimeAmount().toString());//外聘教师超课时费(元)
  616. rowData.add(recordVo.getTotalAmount().toString());//总金额(元)
  617. dataList.add(rowData);
  618. sortCode ++;
  619. }
  620. // 创建一个新的工作簿
  621. Workbook workbook = new XSSFWorkbook();
  622. // 创建一个工作表(sheet)
  623. String sheetName = "数据";
  624. Sheet sheet = workbook.createSheet(sheetName);
  625. // 创建一个字体对象
  626. Font font = workbook.createFont();
  627. font.setBold(true);// 设置为粗体
  628. font.setFontName("宋体");
  629. //font.setColor(IndexedColors.RED.getIndex()); // 设置字体颜色为红色
  630. font.setFontHeightInPoints((short)24);
  631. // 创建一个单元格样式对象
  632. CellStyle cellStyle = workbook.createCellStyle();
  633. cellStyle.setFont(font); // 将字体应用到样式
  634. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  635. cellStyle.setAlignment(HorizontalAlignment.CENTER);
  636. // 第一行表头
  637. {
  638. Row row = sheet.createRow(0);
  639. //合并第一行的列
  640. sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, column - 1));
  641. //3、处理表头
  642. String title1 = statistics.getYear() + "年" + statistics.getMonth() + "月课时统计";
  643. // 创建单元格并设置值
  644. Cell cell = row.createCell(0);
  645. cell.setCellValue(title1);
  646. cell.setCellStyle(cellStyle);
  647. }
  648. //第二行表头
  649. createSecondTitle(workbook, sheet, statistics, weekTimeRangeVos.size() * 4 + 1, CourseTimeTypeList);
  650. //第三行表头
  651. createThirdTitle(workbook, sheet, statistics.getMonth(), weekTimeRangeVos, 7 + CourseTimeTypeList.size());
  652. //第四行表头
  653. createFourthTitle(workbook, sheet, weekTimeRangeVos, 7 + CourseTimeTypeList.size());
  654. int dataRowNumber = 4;
  655. //设置样式
  656. font = workbook.createFont();
  657. font.setBold(false);// 设置为粗体
  658. font.setFontName("宋体");
  659. //font.setColor(IndexedColors.RED.getIndex()); // 设置字体颜色为红色
  660. font.setFontHeightInPoints((short)12);
  661. // 创建一个单元格样式对象
  662. cellStyle = workbook.createCellStyle();
  663. cellStyle.setFont(font); // 将字体应用到样式
  664. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  665. cellStyle.setAlignment(HorizontalAlignment.CENTER);
  666. for (ArrayList<String> rowData : dataList) {
  667. Row dataRow = sheet.createRow(dataRowNumber);
  668. for (int i = 0; i < rowData.size(); i ++){
  669. Cell row1cell2 = dataRow.createCell(i);
  670. String value = rowData.get(i);
  671. if("0".equals(value) || "0.0".equals(value)){
  672. value = "";
  673. }
  674. row1cell2.setCellValue(value);
  675. row1cell2.setCellStyle(cellStyle);
  676. }
  677. dataRowNumber ++;
  678. }
  679. //写入文件
  680. ByteArrayOutputStream bot = new ByteArrayOutputStream();
  681. workbook.write(bot);
  682. return bot.toByteArray();
  683. }catch (Exception e){
  684. Log.error(e.getMessage(), e);
  685. throw new MyException("导出出错,请联系管理员");
  686. }
  687. }
  688. @Override
  689. public Boolean refreshCourseRecord(ClassTimeStatistics statistics) {
  690. try {
  691. // 1、查询教师
  692. List<TeacherListVo> teacherList = this.baseMapper.getTeacherList();
  693. //查询课程数据,排除开节假日的数据
  694. List<CourseListVo> allCourseList = this.baseMapper.getCourseList(statistics);
  695. allCourseList.addAll(this.baseMapper.getHolidayReplaceCourseList(statistics));
  696. //查询删除课时的数据,将每个班删除的具体日期统计出来
  697. List<ClassTimeDelete> deleteList = deleteService.list(
  698. new QueryWrapper<ClassTimeDelete>().lambda()
  699. .ne(ClassTimeDelete::getStatus, 2)
  700. .eq(ClassTimeDelete::getDeleteMark, DeleteMark.NODELETE.getCode())
  701. .eq(ClassTimeDelete::getEnabledMark, EnabledMark.ENABLED.getCode())
  702. );
  703. Map<Long, List<ClassTimeDelete>> deleteDataMap = deleteList.stream().collect(Collectors.groupingBy(ClassTimeDelete::getClassId));
  704. Map<Long, Map<LocalDate, String>> deleteMap = new HashMap<>();//将每个班级计算出来所有被删除的日期存入map
  705. for (Long classId : deleteDataMap.keySet()) {
  706. Map<LocalDate, String> dateMap = new HashMap<>();
  707. for (ClassTimeDelete classTimeDelete : deleteDataMap.get(classId)) {
  708. LocalDate currentDate = classTimeDelete.getStartDate();
  709. while (!currentDate.isAfter(classTimeDelete.getEndDate())) {
  710. dateMap.put(currentDate, classTimeDelete.getTimePeriod());
  711. currentDate = currentDate.plusDays(1); // 增加一天
  712. }
  713. }
  714. //去重并存到map中
  715. deleteMap.put(classId, dateMap);
  716. }
  717. JsonParser parser = new JsonParser();
  718. //权重设置jsonArray
  719. JsonArray weightSetArray = parser.parse(statistics.getWeightSetJson()).getAsJsonArray();
  720. Map<String, Double> weightLabelMap = new LinkedHashMap<>();
  721. Map<String, Double> weightFieldMap = new LinkedHashMap<>();
  722. for (JsonElement jsonElement : weightSetArray) {
  723. JsonObject object = jsonElement.getAsJsonObject();
  724. weightLabelMap.put(object.get("label").getAsString(), object.get("value").getAsDouble());
  725. weightFieldMap.put(object.get("field").getAsString(), object.get("value").getAsDouble());
  726. }
  727. //查询行政工作量并转成map
  728. List<ClassTimeStatisticsAdministration> administrationList = administrationMapper.selectList(
  729. new QueryWrapper<ClassTimeStatisticsAdministration>().lambda()
  730. .eq(ClassTimeStatisticsAdministration::getClassTimeStatisticsId, statistics.getId())
  731. .eq(ClassTimeStatisticsAdministration::getDeleteMark, DeleteMark.NODELETE.getCode())
  732. .eq(ClassTimeStatisticsAdministration::getEnabledMark, EnabledMark.ENABLED.getCode())
  733. );
  734. Map<Long, Double> administrationMap = administrationList.stream().collect(Collectors.toMap(ClassTimeStatisticsAdministration::getUserId, ClassTimeStatisticsAdministration::getWorkload));
  735. List<ClassTimeStatisticsRecord> insertList = new ArrayList<>();
  736. for (TeacherListVo teacher : teacherList) {
  737. ClassTimeStatisticsRecord record = new ClassTimeStatisticsRecord();
  738. record.setUserId(teacher.getId());
  739. record.setClassTimeStatisticsId(statistics.getId());
  740. record.setEmployType(teacher.getEmployType());
  741. record.setClassTime1(statistics.getWeeks());
  742. //早自习、正课、晚辅、顶课、调课
  743. Double classTime7 = 0D,classTime8 = 0D,classTime9 = 0D;
  744. List<String> zkList = Arrays.asList("上1","上2","上3","上4","下1","下2","下3","下4");
  745. List<String> wzxList = Arrays.asList("晚1","晚2","晚3");
  746. //查询出老师的课程
  747. List<CourseListVo> courseList = allCourseList.stream()
  748. .filter(x -> x.getTeacherId().contains(teacher.getId().toString()))
  749. .collect(Collectors.toList());
  750. //循环,统计出各项数据
  751. for (CourseListVo courseListVo : courseList) {
  752. if("早自习".equals(courseListVo.getShortName())){
  753. classTime8 += weightLabelMap.get(courseListVo.getShortName()) == null ? 0d : weightLabelMap.get(courseListVo.getShortName());
  754. }else if(zkList.contains(courseListVo.getShortName())){
  755. classTime8 += weightLabelMap.get(courseListVo.getShortName()) == null ? 0d : weightLabelMap.get(courseListVo.getShortName());
  756. }else if(wzxList.contains(courseListVo.getShortName())){
  757. classTime9 += weightLabelMap.get(courseListVo.getShortName()) == null ? 0d : weightLabelMap.get(courseListVo.getShortName());
  758. }
  759. }
  760. record.setClassTime7(classTime7);
  761. record.setClassTime8(classTime8);
  762. record.setClassTime9(classTime9);
  763. //计算总课时:正课课时+晚辅
  764. Double allTimes = classTime8 + classTime9;
  765. record.setAllClassTime(allTimes);
  766. //计算周平均课时:总课时÷总周次
  767. double classTime2 = BigDecimal.valueOf(allTimes).divide(BigDecimal.valueOf(record.getClassTime1()),2, RoundingMode.HALF_UP).doubleValue();
  768. record.setClassTime2(classTime2);
  769. //行政工作量
  770. record.setClassTime3(administrationMap.get(record.getUserId()));
  771. //总平均课时
  772. Double classTime4 = (record.getClassTime3()==null?0D:record.getClassTime3()) + (record.getClassTime2()==null?0D:record.getClassTime2());
  773. record.setClassTime4(classTime4);
  774. Double time13 = weightFieldMap.get("time13");
  775. if(classTime4 > time13){
  776. record.setClassTime5(time13);
  777. }else{
  778. record.setClassTime5(classTime4);
  779. }
  780. insertList.add(record);
  781. }
  782. if(!insertList.isEmpty()){
  783. Double overWorkloadNumber = statistics.getOverWorkloadNumber() == null ? 0D : statistics.getOverWorkloadNumber();
  784. Double time14 = weightFieldMap.get("time14");//工作量得分
  785. if(statistics.getOverWorkloadNumberStatus() != 1){
  786. //取出最大总平均课时
  787. Double maxClassTime4 = insertList.stream().mapToDouble(ClassTimeStatisticsRecord::getClassTime4).max().getAsDouble();
  788. //计算超工作量基数
  789. if(!maxClassTime4.equals(time14)){
  790. Double time13 = weightFieldMap.get("time13");//超工作量得分
  791. overWorkloadNumber = BigDecimal.valueOf(time13).divide((BigDecimal.valueOf(maxClassTime4).subtract(BigDecimal.valueOf(time14))),2, RoundingMode.HALF_UP).doubleValue();
  792. }
  793. }
  794. statistics.setOverWorkloadNumber(overWorkloadNumber);
  795. //先删除
  796. String sql = "delete from class_time_statistics_record where class_time_statistics_id = " + statistics.getId();
  797. SqlRunnerAdapter.db().delete(sql);
  798. for (ClassTimeStatisticsRecord record : insertList) {
  799. if(overWorkloadNumber != 0D){
  800. double classTime6 = BigDecimal.valueOf(record.getClassTime4())
  801. .subtract(BigDecimal.valueOf(time14))
  802. .multiply(BigDecimal.valueOf(overWorkloadNumber)).doubleValue();
  803. if(classTime6 < 0d){
  804. continue;
  805. }
  806. record.setClassTime6(classTime6);
  807. }
  808. recordMapper.insert(record);
  809. }
  810. }
  811. }catch (Exception e){
  812. Log.error(e.getMessage(), e);
  813. throw new MyException("刷新统计出错,请联系管理员");
  814. }finally {
  815. statistics.setStatus(1);
  816. this.updateById(statistics);
  817. }
  818. return true;
  819. }
  820. @Override
  821. public Boolean importAdministration(Long classTimeStatisticsId, MultipartFile file){
  822. try {
  823. List<Map<Integer, Object>> excelDataList = EasyExcel.read(file.getInputStream()).sheet().headRowNumber(2).doReadSync();
  824. List<User> teacherList = userService.list(
  825. new MPJLambdaWrapper<User>()
  826. .select(User::getId)
  827. .select(XjrUser.class, x -> VoToColumnUtil.fieldsToColumns(XjrUser.class).contains(x.getProperty()))
  828. .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, User::getId)
  829. );
  830. List<ClassTimeStatisticsAdministration> insertList = new ArrayList<>();
  831. Map<String, Long> userMap = teacherList.stream().collect(Collectors.toMap(User::getUserName, User::getId));
  832. for (Map<Integer, Object> rowData : excelDataList) {
  833. String userName = rowData.get(1).toString();
  834. ClassTimeStatisticsAdministration data = new ClassTimeStatisticsAdministration(){{
  835. setClassTimeStatisticsId(classTimeStatisticsId);
  836. setUserId(userMap.get(userName));
  837. setWorkload(Double.parseDouble(rowData.get(3).toString()));
  838. }};
  839. insertList.add(data);
  840. }
  841. if(!insertList.isEmpty()){
  842. String sql = "delete from class_time_statistics_administration where class_time_statistics_id = " + classTimeStatisticsId;
  843. SqlRunnerAdapter.db().delete(sql);
  844. for (ClassTimeStatisticsAdministration administration : insertList) {
  845. administrationMapper.insert(administration);
  846. }
  847. CompletableFuture.runAsync(() -> {
  848. ClassTimeStatistics statistics = this.getById(classTimeStatisticsId);
  849. refreshCourseRecord(statistics);
  850. });
  851. }
  852. return true;
  853. }catch (Exception e){
  854. Log.error(e.getMessage(), e);
  855. throw new MyException("导入行政工作量报错,请联系管理员");
  856. }
  857. }
  858. @Override
  859. public byte[] exportAdministration(Long classTimeStatisticsId) {
  860. CourseRecordDto dto = new CourseRecordDto() {{
  861. setId(classTimeStatisticsId);
  862. }};
  863. List<CourseClassTimeStatisticsRecordVo> recordList = this.getCourseRecordList(dto);
  864. List<ClassTimeStatisticsAdministrationExcelVo> list = BeanUtil.copyToList(recordList, ClassTimeStatisticsAdministrationExcelVo.class);
  865. ByteArrayOutputStream bot = new ByteArrayOutputStream();
  866. EasyExcel.write(bot, ClassTimeStatisticsAdministrationExcelVo.class).automaticMergeHead(false).excelType(ExcelTypeEnum.XLSX).sheet().doWrite(list);
  867. return bot.toByteArray();
  868. }
  869. /**
  870. * 生成第二行表头
  871. * 前端固定表头:序号、工号、姓名、教研会、督导听课、临近三年退休政策、出题、阅卷、周末培优、早自习、正课(含调顶课时)、晚辅(含调顶课时)、顶课、调课
  872. * 中间动态表头:每周,总课时(含调顶课节)、顶课(节)、调课(节)、晚辅(节)......课时晚辅合计
  873. * 后端固定表头:总课时、课时费(元)、外聘教师超课时费(元)、总金额(元)
  874. */
  875. void createSecondTitle(Workbook workbook, Sheet sheet, ClassTimeStatistics statistics, int mergeCoulmn, List<DictionaryDetail> CourseTimeTypeList){
  876. Font font = workbook.createFont();
  877. font.setFontName("宋体");
  878. font.setFontHeightInPoints((short)12);
  879. CellStyle cellStyle = workbook.createCellStyle();
  880. cellStyle.setFont(font); // 将字体应用到样式
  881. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  882. cellStyle.setAlignment(HorizontalAlignment.CENTER);
  883. Row row1 = sheet.createRow(1);
  884. int cellNumber = 0;
  885. Cell row1cell1 = row1.createCell(cellNumber);
  886. row1cell1.setCellValue("序号");
  887. row1cell1.setCellStyle(cellStyle);
  888. cellNumber ++;
  889. Cell row1cell2 = row1.createCell(cellNumber);
  890. row1cell2.setCellValue("工号");
  891. row1cell2.setCellStyle(cellStyle);
  892. cellNumber ++;
  893. Cell row1cell3 = row1.createCell(cellNumber);
  894. row1cell3.setCellValue("姓名");
  895. row1cell3.setCellStyle(cellStyle);
  896. cellNumber ++;
  897. for (DictionaryDetail detail : CourseTimeTypeList) {
  898. Cell row1cell4 = row1.createCell(cellNumber);
  899. row1cell4.setCellValue(detail.getName());
  900. row1cell4.setCellStyle(cellStyle);
  901. cellNumber ++;
  902. }
  903. Cell row1cell10 = row1.createCell(cellNumber);
  904. row1cell10.setCellValue("早自习");
  905. row1cell10.setCellStyle(cellStyle);
  906. cellNumber ++;
  907. Cell row1cell11 = row1.createCell(cellNumber);
  908. row1cell11.setCellValue("正课(含调顶课时)");
  909. row1cell11.setCellStyle(cellStyle);
  910. cellNumber ++;
  911. Cell row1cell12 = row1.createCell(cellNumber);
  912. row1cell12.setCellValue("晚辅(含调顶课时)");
  913. row1cell12.setCellStyle(cellStyle);
  914. cellNumber ++;
  915. Cell row1cell13 = row1.createCell(cellNumber);
  916. row1cell13.setCellValue("顶课");
  917. row1cell13.setCellStyle(cellStyle);
  918. cellNumber ++;
  919. Cell row1cell14 = row1.createCell(cellNumber);
  920. row1cell14.setCellValue("调课");
  921. row1cell14.setCellStyle(cellStyle);
  922. cellNumber ++;
  923. Cell row1cell15 = row1.createCell(cellNumber);
  924. row1cell15.setCellValue("正课课时数(平台导出" + statistics.getMonth() + "月)");
  925. row1cell15.setCellStyle(cellStyle);
  926. cellNumber ++;
  927. int index = cellNumber + mergeCoulmn - 1;
  928. Cell row1cell16 = row1.createCell(index);
  929. row1cell16.setCellValue("总课时");
  930. row1cell16.setCellStyle(cellStyle);
  931. Cell row1cell17 = row1.createCell(index + 1);
  932. row1cell17.setCellValue("课时费(元)");
  933. row1cell17.setCellStyle(cellStyle);
  934. Cell row1cell18 = row1.createCell(index + 2);
  935. row1cell18.setCellValue("外聘教师超课时费(元)");
  936. row1cell18.setCellStyle(cellStyle);
  937. Cell row1cell19 = row1.createCell(index + 3);
  938. row1cell19.setCellValue("总金额(元)");
  939. row1cell19.setCellStyle(cellStyle);
  940. //合并表头
  941. for(int i = 0; i < 8 + CourseTimeTypeList.size(); i ++){
  942. sheet.addMergedRegion(new CellRangeAddress(1, 3, i, i));
  943. }
  944. //合并中间动态表头
  945. sheet.addMergedRegion(new CellRangeAddress(1, 1, 8 + CourseTimeTypeList.size(), index - 1));
  946. //合并前端表头
  947. for(int i = index; i < index + 4; i ++){
  948. sheet.addMergedRegion(new CellRangeAddress(1, 3, i, i));
  949. }
  950. }
  951. /**
  952. * 生成第三行表头
  953. * 关于周的表头,周一日期到周二日期,第几周,最后拼接一个单独的月份
  954. *
  955. * @param month 月份
  956. * @param weekTimeRangeVos 周的数据,包含周一的日期周二的日期
  957. * @param lastIndex 前一个表头的单元格
  958. */
  959. void createThirdTitle(Workbook workbook, Sheet sheet, int month, List<WeekTimeRangeVo> weekTimeRangeVos, int lastIndex){
  960. Font font = workbook.createFont();
  961. font.setFontName("宋体");
  962. font.setFontHeightInPoints((short)12);
  963. CellStyle cellStyle = workbook.createCellStyle();
  964. cellStyle.setFont(font); // 将字体应用到样式
  965. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  966. cellStyle.setAlignment(HorizontalAlignment.CENTER);
  967. //设置内容
  968. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM.dd");
  969. int rowNumber = 2;
  970. Row row2 = sheet.createRow(rowNumber);
  971. for(int i = 0; i < weekTimeRangeVos.size(); i ++){
  972. WeekTimeRangeVo rangeVo = weekTimeRangeVos.get(i);
  973. String cellValue = rangeVo.getMondayDate().format(formatter) + "-"
  974. + rangeVo.getSundayDate().format(formatter) + "(第" + rangeVo.getWeeks() + "周)";
  975. Cell row1cell1 = row2.createCell(lastIndex + 1 + (i * 4));
  976. row1cell1.setCellValue(cellValue);
  977. row1cell1.setCellStyle(cellStyle);
  978. }
  979. //合并单元格
  980. int monthIndex = 0;
  981. for(int i = 0; i < weekTimeRangeVos.size(); i ++){
  982. int startCoulmn = lastIndex + 1 + (i * 4);
  983. int endCoulmn = startCoulmn + 3;
  984. sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber, startCoulmn, endCoulmn));
  985. monthIndex = endCoulmn;
  986. }
  987. Cell row1cell2 = row2.createCell(monthIndex + 1);
  988. row1cell2.setCellValue(month + "月");
  989. row1cell2.setCellStyle(cellStyle);
  990. }
  991. /**
  992. * 生成第四行表头
  993. * 表头内容:总课时(含调顶课节)、顶课(节)、调课(节)、晚辅(节)、课时晚辅合计
  994. *
  995. * @param weekTimeRangeVos 周的数据,包含周一的日期周二的日期
  996. * @param lastIndex 前一个表头的单元格
  997. */
  998. void createFourthTitle(Workbook workbook, Sheet sheet, List<WeekTimeRangeVo> weekTimeRangeVos, int lastIndex){
  999. Font font = workbook.createFont();
  1000. font.setFontName("宋体");
  1001. font.setFontHeightInPoints((short)12);
  1002. CellStyle cellStyle = workbook.createCellStyle();
  1003. cellStyle.setFont(font); // 将字体应用到样式
  1004. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  1005. cellStyle.setAlignment(HorizontalAlignment.CENTER);
  1006. int rowNumber = 3;
  1007. Row row2 = sheet.createRow(rowNumber);
  1008. int index = lastIndex + 1;
  1009. for(int i = 0; i < weekTimeRangeVos.size(); i ++){
  1010. Cell row1cell1 = row2.createCell(index);
  1011. row1cell1.setCellValue("总课时(含调顶课节)");
  1012. row1cell1.setCellStyle(cellStyle);
  1013. index ++;
  1014. Cell row1cell2 = row2.createCell(index);
  1015. row1cell2.setCellValue("顶课(节)");
  1016. row1cell2.setCellStyle(cellStyle);
  1017. index ++;
  1018. Cell row1cell3 = row2.createCell(index);
  1019. row1cell3.setCellValue("调课(节)");
  1020. row1cell3.setCellStyle(cellStyle);
  1021. index ++;
  1022. Cell row1cell4 = row2.createCell(index);
  1023. row1cell4.setCellValue("晚辅(节)");
  1024. row1cell4.setCellStyle(cellStyle);
  1025. index ++;
  1026. }
  1027. Cell row1cell5 = row2.createCell(index);
  1028. row1cell5.setCellValue("课时晚辅合计");
  1029. row1cell5.setCellStyle(cellStyle);
  1030. }
  1031. //计算日期内一共几个周,并返回每周的周一日期和周日日期
  1032. private static List<WeekTimeRangeVo> calculateNaturalWeeks(LocalDate startDate, LocalDate endDate) {
  1033. List<WeekTimeRangeVo> result = new ArrayList<>();
  1034. // 获取第一个周一
  1035. LocalDate currentMonday = startDate.with(DayOfWeek.MONDAY);
  1036. // 如果 startDate 不是周一,则用下一个周一
  1037. if (!startDate.isEqual(currentMonday) && startDate.isAfter(currentMonday)) {
  1038. currentMonday = currentMonday.plusWeeks(1);
  1039. }
  1040. int weeks = 1;
  1041. // 遍历每个周
  1042. while (!currentMonday.isAfter(endDate)) {
  1043. // 计算当前周的周日
  1044. LocalDate currentSunday = currentMonday.plusDays(6);
  1045. // 限制周日的范围
  1046. if (currentSunday.isAfter(endDate)) {
  1047. currentSunday = endDate;
  1048. }
  1049. // 添加结果
  1050. WeekTimeRangeVo timeRangeVo = new WeekTimeRangeVo();
  1051. timeRangeVo.setMondayDate(currentMonday);
  1052. timeRangeVo.setSundayDate(currentSunday);
  1053. timeRangeVo .setWeeks(weeks);
  1054. result.add(timeRangeVo);
  1055. // 移动到下一个周的周一
  1056. currentMonday = currentMonday.plusWeeks(1);
  1057. weeks ++;
  1058. }
  1059. return result;
  1060. }
  1061. /**
  1062. * 取出所有日期
  1063. * @param startDate 开始时间
  1064. * @param endDate 结束时间
  1065. * @return 返回所有日期的集合
  1066. */
  1067. private static List<LocalDate> getDatesBetween(LocalDate startDate, LocalDate endDate) {
  1068. List<LocalDate> dates = new ArrayList<>();
  1069. long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate) + 1; // +1 包含结束日期
  1070. for (long i = 0; i < numOfDaysBetween; i++) {
  1071. dates.add(startDate.plusDays(i));
  1072. }
  1073. return dates;
  1074. }
  1075. String calculateClassTime(JsonArray allClassTimeDataArray, Map<String, Double> weightSetMap, List<LocalDate> allDateList){
  1076. JsonObject result = new JsonObject();
  1077. //计算纵向的合计
  1078. Double allClassTime = 0d;
  1079. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM.dd");
  1080. JsonArray rowTitle = new JsonArray();
  1081. for (LocalDate localDate : allDateList) {
  1082. JsonObject rowTitleJson = new JsonObject();
  1083. rowTitleJson.addProperty("scheduleDate", localDate.format(formatter));
  1084. Double sum = 0d;
  1085. for (JsonElement jsonElement : allClassTimeDataArray) {
  1086. JsonObject object = jsonElement.getAsJsonObject();
  1087. LocalDate scheduleDate = LocalDate.parse(object.get("scheduleDate").getAsString());
  1088. if(!scheduleDate.equals(localDate)){
  1089. continue;
  1090. }
  1091. String adjustType = object.get("adjustType").getAsString();
  1092. if("course_delete".equals(adjustType)){
  1093. continue;
  1094. }
  1095. if(weightSetMap.get(object.get("type").getAsString()) == null){
  1096. sum += object.get("content").getAsDouble();
  1097. allClassTime += object.get("content").getAsDouble();
  1098. }else{
  1099. sum += weightSetMap.get(object.get("type").getAsString());
  1100. allClassTime += weightSetMap.get(object.get("type").getAsString());
  1101. }
  1102. }
  1103. rowTitleJson.addProperty("content", sum);
  1104. rowTitleJson.addProperty("type", "");
  1105. rowTitleJson.addProperty("adjustType", "");
  1106. rowTitle.add(rowTitleJson);
  1107. }
  1108. result.add("rowTitle", rowTitle);
  1109. //计算横向的合计
  1110. JsonArray columnTitle = new JsonArray();
  1111. for (String type : weightSetMap.keySet()) {
  1112. Double sum = 0d;
  1113. JsonObject columnTitleJson = new JsonObject();
  1114. for (JsonElement jsonElement : allClassTimeDataArray) {
  1115. JsonObject object = jsonElement.getAsJsonObject();
  1116. String typeStr = object.get("type").getAsString();
  1117. if(!type.equals(typeStr)){
  1118. continue;
  1119. }
  1120. String adjustType = object.get("adjustType").getAsString();
  1121. if("course_delete".equals(adjustType)){
  1122. continue;
  1123. }
  1124. sum += weightSetMap.get(typeStr);
  1125. }
  1126. columnTitleJson.addProperty("type", type);
  1127. columnTitleJson.addProperty("content", sum);
  1128. columnTitleJson.addProperty("scheduleDate", "");
  1129. columnTitleJson.addProperty("adjustType", "");
  1130. columnTitle.add(columnTitleJson);
  1131. }
  1132. String[] courseTimeTypes = CourseTimeTypeEnum.getValues();
  1133. for (String courseTimeType : courseTimeTypes) {
  1134. double sum = 0d;
  1135. JsonObject columnTitleJson = new JsonObject();
  1136. for (JsonElement jsonElement : allClassTimeDataArray) {
  1137. JsonObject object = jsonElement.getAsJsonObject();
  1138. String typeStr = object.get("type").getAsString();
  1139. if (!courseTimeType.equals(typeStr)) {
  1140. continue;
  1141. }
  1142. String adjustType = object.get("adjustType").getAsString();
  1143. if("course_delete".equals(adjustType)){
  1144. continue;
  1145. }
  1146. sum += object.get("content").getAsDouble();
  1147. }
  1148. columnTitleJson.addProperty("type", courseTimeType);
  1149. columnTitleJson.addProperty("content", sum);
  1150. columnTitleJson.addProperty("scheduleDate", "");
  1151. columnTitleJson.addProperty("adjustType", "");
  1152. columnTitle.add(columnTitleJson);
  1153. }
  1154. result.add("columnTitle", columnTitle);
  1155. result.add("data", allClassTimeDataArray);
  1156. result.addProperty("allClassTime", allClassTime);
  1157. return result.toString();
  1158. }
  1159. }