ClassTimeStatisticsServiceImpl.java 67 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296
  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. record.setClassTime6(classTime6);
  805. }
  806. }
  807. recordMapper.insert(record);
  808. }
  809. }
  810. }catch (Exception e){
  811. Log.error(e.getMessage(), e);
  812. throw new MyException("刷新统计出错,请联系管理员");
  813. }finally {
  814. statistics.setStatus(1);
  815. this.updateById(statistics);
  816. }
  817. return true;
  818. }
  819. @Override
  820. public Boolean importAdministration(Long classTimeStatisticsId, MultipartFile file){
  821. try {
  822. List<Map<Integer, Object>> excelDataList = EasyExcel.read(file.getInputStream()).sheet().headRowNumber(2).doReadSync();
  823. List<User> teacherList = userService.list(
  824. new MPJLambdaWrapper<User>()
  825. .select(User::getId)
  826. .select(XjrUser.class, x -> VoToColumnUtil.fieldsToColumns(XjrUser.class).contains(x.getProperty()))
  827. .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, User::getId)
  828. );
  829. List<ClassTimeStatisticsAdministration> insertList = new ArrayList<>();
  830. Map<String, Long> userMap = teacherList.stream().collect(Collectors.toMap(User::getUserName, User::getId));
  831. for (Map<Integer, Object> rowData : excelDataList) {
  832. String userName = rowData.get(1).toString();
  833. ClassTimeStatisticsAdministration data = new ClassTimeStatisticsAdministration(){{
  834. setClassTimeStatisticsId(classTimeStatisticsId);
  835. setUserId(userMap.get(userName));
  836. setWorkload(Double.parseDouble(rowData.get(3).toString()));
  837. }};
  838. insertList.add(data);
  839. }
  840. if(!insertList.isEmpty()){
  841. String sql = "delete from class_time_statistics_administration where class_time_statistics_id = " + classTimeStatisticsId;
  842. SqlRunnerAdapter.db().delete(sql);
  843. for (ClassTimeStatisticsAdministration administration : insertList) {
  844. administrationMapper.insert(administration);
  845. }
  846. CompletableFuture.runAsync(() -> {
  847. ClassTimeStatistics statistics = this.getById(classTimeStatisticsId);
  848. refreshCourseRecord(statistics);
  849. });
  850. }
  851. return true;
  852. }catch (Exception e){
  853. Log.error(e.getMessage(), e);
  854. throw new MyException("导入行政工作量报错,请联系管理员");
  855. }
  856. }
  857. @Override
  858. public byte[] exportAdministration(Long classTimeStatisticsId) {
  859. CourseRecordDto dto = new CourseRecordDto() {{
  860. setId(classTimeStatisticsId);
  861. }};
  862. List<CourseClassTimeStatisticsRecordVo> recordList = this.getCourseRecordList(dto);
  863. List<ClassTimeStatisticsAdministrationExcelVo> list = BeanUtil.copyToList(recordList, ClassTimeStatisticsAdministrationExcelVo.class);
  864. ByteArrayOutputStream bot = new ByteArrayOutputStream();
  865. EasyExcel.write(bot, ClassTimeStatisticsAdministrationExcelVo.class).automaticMergeHead(false).excelType(ExcelTypeEnum.XLSX).sheet().doWrite(list);
  866. return bot.toByteArray();
  867. }
  868. /**
  869. * 生成第二行表头
  870. * 前端固定表头:序号、工号、姓名、教研会、督导听课、临近三年退休政策、出题、阅卷、周末培优、早自习、正课(含调顶课时)、晚辅(含调顶课时)、顶课、调课
  871. * 中间动态表头:每周,总课时(含调顶课节)、顶课(节)、调课(节)、晚辅(节)......课时晚辅合计
  872. * 后端固定表头:总课时、课时费(元)、外聘教师超课时费(元)、总金额(元)
  873. */
  874. void createSecondTitle(Workbook workbook, Sheet sheet, ClassTimeStatistics statistics, int mergeCoulmn, List<DictionaryDetail> CourseTimeTypeList){
  875. Font font = workbook.createFont();
  876. font.setFontName("宋体");
  877. font.setFontHeightInPoints((short)12);
  878. CellStyle cellStyle = workbook.createCellStyle();
  879. cellStyle.setFont(font); // 将字体应用到样式
  880. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  881. cellStyle.setAlignment(HorizontalAlignment.CENTER);
  882. Row row1 = sheet.createRow(1);
  883. int cellNumber = 0;
  884. Cell row1cell1 = row1.createCell(cellNumber);
  885. row1cell1.setCellValue("序号");
  886. row1cell1.setCellStyle(cellStyle);
  887. cellNumber ++;
  888. Cell row1cell2 = row1.createCell(cellNumber);
  889. row1cell2.setCellValue("工号");
  890. row1cell2.setCellStyle(cellStyle);
  891. cellNumber ++;
  892. Cell row1cell3 = row1.createCell(cellNumber);
  893. row1cell3.setCellValue("姓名");
  894. row1cell3.setCellStyle(cellStyle);
  895. cellNumber ++;
  896. for (DictionaryDetail detail : CourseTimeTypeList) {
  897. Cell row1cell4 = row1.createCell(cellNumber);
  898. row1cell4.setCellValue(detail.getName());
  899. row1cell4.setCellStyle(cellStyle);
  900. cellNumber ++;
  901. }
  902. Cell row1cell10 = row1.createCell(cellNumber);
  903. row1cell10.setCellValue("早自习");
  904. row1cell10.setCellStyle(cellStyle);
  905. cellNumber ++;
  906. Cell row1cell11 = row1.createCell(cellNumber);
  907. row1cell11.setCellValue("正课(含调顶课时)");
  908. row1cell11.setCellStyle(cellStyle);
  909. cellNumber ++;
  910. Cell row1cell12 = row1.createCell(cellNumber);
  911. row1cell12.setCellValue("晚辅(含调顶课时)");
  912. row1cell12.setCellStyle(cellStyle);
  913. cellNumber ++;
  914. Cell row1cell13 = row1.createCell(cellNumber);
  915. row1cell13.setCellValue("顶课");
  916. row1cell13.setCellStyle(cellStyle);
  917. cellNumber ++;
  918. Cell row1cell14 = row1.createCell(cellNumber);
  919. row1cell14.setCellValue("调课");
  920. row1cell14.setCellStyle(cellStyle);
  921. cellNumber ++;
  922. Cell row1cell15 = row1.createCell(cellNumber);
  923. row1cell15.setCellValue("正课课时数(平台导出" + statistics.getMonth() + "月)");
  924. row1cell15.setCellStyle(cellStyle);
  925. cellNumber ++;
  926. int index = cellNumber + mergeCoulmn - 1;
  927. Cell row1cell16 = row1.createCell(index);
  928. row1cell16.setCellValue("总课时");
  929. row1cell16.setCellStyle(cellStyle);
  930. Cell row1cell17 = row1.createCell(index + 1);
  931. row1cell17.setCellValue("课时费(元)");
  932. row1cell17.setCellStyle(cellStyle);
  933. Cell row1cell18 = row1.createCell(index + 2);
  934. row1cell18.setCellValue("外聘教师超课时费(元)");
  935. row1cell18.setCellStyle(cellStyle);
  936. Cell row1cell19 = row1.createCell(index + 3);
  937. row1cell19.setCellValue("总金额(元)");
  938. row1cell19.setCellStyle(cellStyle);
  939. //合并表头
  940. for(int i = 0; i < 8 + CourseTimeTypeList.size(); i ++){
  941. sheet.addMergedRegion(new CellRangeAddress(1, 3, i, i));
  942. }
  943. //合并中间动态表头
  944. sheet.addMergedRegion(new CellRangeAddress(1, 1, 8 + CourseTimeTypeList.size(), index - 1));
  945. //合并前端表头
  946. for(int i = index; i < index + 4; i ++){
  947. sheet.addMergedRegion(new CellRangeAddress(1, 3, i, i));
  948. }
  949. }
  950. /**
  951. * 生成第三行表头
  952. * 关于周的表头,周一日期到周二日期,第几周,最后拼接一个单独的月份
  953. *
  954. * @param month 月份
  955. * @param weekTimeRangeVos 周的数据,包含周一的日期周二的日期
  956. * @param lastIndex 前一个表头的单元格
  957. */
  958. void createThirdTitle(Workbook workbook, Sheet sheet, int month, List<WeekTimeRangeVo> weekTimeRangeVos, int lastIndex){
  959. Font font = workbook.createFont();
  960. font.setFontName("宋体");
  961. font.setFontHeightInPoints((short)12);
  962. CellStyle cellStyle = workbook.createCellStyle();
  963. cellStyle.setFont(font); // 将字体应用到样式
  964. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  965. cellStyle.setAlignment(HorizontalAlignment.CENTER);
  966. //设置内容
  967. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM.dd");
  968. int rowNumber = 2;
  969. Row row2 = sheet.createRow(rowNumber);
  970. for(int i = 0; i < weekTimeRangeVos.size(); i ++){
  971. WeekTimeRangeVo rangeVo = weekTimeRangeVos.get(i);
  972. String cellValue = rangeVo.getMondayDate().format(formatter) + "-"
  973. + rangeVo.getSundayDate().format(formatter) + "(第" + rangeVo.getWeeks() + "周)";
  974. Cell row1cell1 = row2.createCell(lastIndex + 1 + (i * 4));
  975. row1cell1.setCellValue(cellValue);
  976. row1cell1.setCellStyle(cellStyle);
  977. }
  978. //合并单元格
  979. int monthIndex = 0;
  980. for(int i = 0; i < weekTimeRangeVos.size(); i ++){
  981. int startCoulmn = lastIndex + 1 + (i * 4);
  982. int endCoulmn = startCoulmn + 3;
  983. sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber, startCoulmn, endCoulmn));
  984. monthIndex = endCoulmn;
  985. }
  986. Cell row1cell2 = row2.createCell(monthIndex + 1);
  987. row1cell2.setCellValue(month + "月");
  988. row1cell2.setCellStyle(cellStyle);
  989. }
  990. /**
  991. * 生成第四行表头
  992. * 表头内容:总课时(含调顶课节)、顶课(节)、调课(节)、晚辅(节)、课时晚辅合计
  993. *
  994. * @param weekTimeRangeVos 周的数据,包含周一的日期周二的日期
  995. * @param lastIndex 前一个表头的单元格
  996. */
  997. void createFourthTitle(Workbook workbook, Sheet sheet, List<WeekTimeRangeVo> weekTimeRangeVos, int lastIndex){
  998. Font font = workbook.createFont();
  999. font.setFontName("宋体");
  1000. font.setFontHeightInPoints((short)12);
  1001. CellStyle cellStyle = workbook.createCellStyle();
  1002. cellStyle.setFont(font); // 将字体应用到样式
  1003. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  1004. cellStyle.setAlignment(HorizontalAlignment.CENTER);
  1005. int rowNumber = 3;
  1006. Row row2 = sheet.createRow(rowNumber);
  1007. int index = lastIndex + 1;
  1008. for(int i = 0; i < weekTimeRangeVos.size(); i ++){
  1009. Cell row1cell1 = row2.createCell(index);
  1010. row1cell1.setCellValue("总课时(含调顶课节)");
  1011. row1cell1.setCellStyle(cellStyle);
  1012. index ++;
  1013. Cell row1cell2 = row2.createCell(index);
  1014. row1cell2.setCellValue("顶课(节)");
  1015. row1cell2.setCellStyle(cellStyle);
  1016. index ++;
  1017. Cell row1cell3 = row2.createCell(index);
  1018. row1cell3.setCellValue("调课(节)");
  1019. row1cell3.setCellStyle(cellStyle);
  1020. index ++;
  1021. Cell row1cell4 = row2.createCell(index);
  1022. row1cell4.setCellValue("晚辅(节)");
  1023. row1cell4.setCellStyle(cellStyle);
  1024. index ++;
  1025. }
  1026. Cell row1cell5 = row2.createCell(index);
  1027. row1cell5.setCellValue("课时晚辅合计");
  1028. row1cell5.setCellStyle(cellStyle);
  1029. }
  1030. //计算日期内一共几个周,并返回每周的周一日期和周日日期
  1031. private static List<WeekTimeRangeVo> calculateNaturalWeeks(LocalDate startDate, LocalDate endDate) {
  1032. List<WeekTimeRangeVo> result = new ArrayList<>();
  1033. // 获取第一个周一
  1034. LocalDate currentMonday = startDate.with(DayOfWeek.MONDAY);
  1035. // 如果 startDate 不是周一,则用下一个周一
  1036. if (!startDate.isEqual(currentMonday) && startDate.isAfter(currentMonday)) {
  1037. currentMonday = currentMonday.plusWeeks(1);
  1038. }
  1039. int weeks = 1;
  1040. // 遍历每个周
  1041. while (!currentMonday.isAfter(endDate)) {
  1042. // 计算当前周的周日
  1043. LocalDate currentSunday = currentMonday.plusDays(6);
  1044. // 限制周日的范围
  1045. if (currentSunday.isAfter(endDate)) {
  1046. currentSunday = endDate;
  1047. }
  1048. // 添加结果
  1049. WeekTimeRangeVo timeRangeVo = new WeekTimeRangeVo();
  1050. timeRangeVo.setMondayDate(currentMonday);
  1051. timeRangeVo.setSundayDate(currentSunday);
  1052. timeRangeVo .setWeeks(weeks);
  1053. result.add(timeRangeVo);
  1054. // 移动到下一个周的周一
  1055. currentMonday = currentMonday.plusWeeks(1);
  1056. weeks ++;
  1057. }
  1058. return result;
  1059. }
  1060. /**
  1061. * 取出所有日期
  1062. * @param startDate 开始时间
  1063. * @param endDate 结束时间
  1064. * @return 返回所有日期的集合
  1065. */
  1066. private static List<LocalDate> getDatesBetween(LocalDate startDate, LocalDate endDate) {
  1067. List<LocalDate> dates = new ArrayList<>();
  1068. long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate) + 1; // +1 包含结束日期
  1069. for (long i = 0; i < numOfDaysBetween; i++) {
  1070. dates.add(startDate.plusDays(i));
  1071. }
  1072. return dates;
  1073. }
  1074. String calculateClassTime(JsonArray allClassTimeDataArray, Map<String, Double> weightSetMap, List<LocalDate> allDateList){
  1075. JsonObject result = new JsonObject();
  1076. //计算纵向的合计
  1077. Double allClassTime = 0d;
  1078. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM.dd");
  1079. JsonArray rowTitle = new JsonArray();
  1080. for (LocalDate localDate : allDateList) {
  1081. JsonObject rowTitleJson = new JsonObject();
  1082. rowTitleJson.addProperty("scheduleDate", localDate.format(formatter));
  1083. Double sum = 0d;
  1084. for (JsonElement jsonElement : allClassTimeDataArray) {
  1085. JsonObject object = jsonElement.getAsJsonObject();
  1086. LocalDate scheduleDate = LocalDate.parse(object.get("scheduleDate").getAsString());
  1087. if(!scheduleDate.equals(localDate)){
  1088. continue;
  1089. }
  1090. String adjustType = object.get("adjustType").getAsString();
  1091. if("course_delete".equals(adjustType)){
  1092. continue;
  1093. }
  1094. if(weightSetMap.get(object.get("type").getAsString()) == null){
  1095. sum += object.get("content").getAsDouble();
  1096. allClassTime += object.get("content").getAsDouble();
  1097. }else{
  1098. sum += weightSetMap.get(object.get("type").getAsString());
  1099. allClassTime += weightSetMap.get(object.get("type").getAsString());
  1100. }
  1101. }
  1102. rowTitleJson.addProperty("content", sum);
  1103. rowTitleJson.addProperty("type", "");
  1104. rowTitleJson.addProperty("adjustType", "");
  1105. rowTitle.add(rowTitleJson);
  1106. }
  1107. result.add("rowTitle", rowTitle);
  1108. //计算横向的合计
  1109. JsonArray columnTitle = new JsonArray();
  1110. for (String type : weightSetMap.keySet()) {
  1111. Double sum = 0d;
  1112. JsonObject columnTitleJson = new JsonObject();
  1113. for (JsonElement jsonElement : allClassTimeDataArray) {
  1114. JsonObject object = jsonElement.getAsJsonObject();
  1115. String typeStr = object.get("type").getAsString();
  1116. if(!type.equals(typeStr)){
  1117. continue;
  1118. }
  1119. String adjustType = object.get("adjustType").getAsString();
  1120. if("course_delete".equals(adjustType)){
  1121. continue;
  1122. }
  1123. sum += weightSetMap.get(typeStr);
  1124. }
  1125. columnTitleJson.addProperty("type", type);
  1126. columnTitleJson.addProperty("content", sum);
  1127. columnTitleJson.addProperty("scheduleDate", "");
  1128. columnTitleJson.addProperty("adjustType", "");
  1129. columnTitle.add(columnTitleJson);
  1130. }
  1131. String[] courseTimeTypes = CourseTimeTypeEnum.getValues();
  1132. for (String courseTimeType : courseTimeTypes) {
  1133. double sum = 0d;
  1134. JsonObject columnTitleJson = new JsonObject();
  1135. for (JsonElement jsonElement : allClassTimeDataArray) {
  1136. JsonObject object = jsonElement.getAsJsonObject();
  1137. String typeStr = object.get("type").getAsString();
  1138. if (!courseTimeType.equals(typeStr)) {
  1139. continue;
  1140. }
  1141. String adjustType = object.get("adjustType").getAsString();
  1142. if("course_delete".equals(adjustType)){
  1143. continue;
  1144. }
  1145. sum += object.get("content").getAsDouble();
  1146. }
  1147. columnTitleJson.addProperty("type", courseTimeType);
  1148. columnTitleJson.addProperty("content", sum);
  1149. columnTitleJson.addProperty("scheduleDate", "");
  1150. columnTitleJson.addProperty("adjustType", "");
  1151. columnTitle.add(columnTitleJson);
  1152. }
  1153. result.add("columnTitle", columnTitle);
  1154. result.add("data", allClassTimeDataArray);
  1155. result.addProperty("allClassTime", allClassTime);
  1156. return result.toString();
  1157. }
  1158. }