BandingTaskServiceImpl.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. package com.xjrsoft.module.banding.service.impl;
  2. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  3. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  4. import com.github.yulichang.base.MPJBaseServiceImpl;
  5. import com.github.yulichang.wrapper.MPJLambdaWrapper;
  6. import com.xjrsoft.common.enums.GenderDictionaryEnum;
  7. import com.xjrsoft.common.exception.MyException;
  8. import com.xjrsoft.common.utils.VoToColumnUtil;
  9. import com.xjrsoft.module.banding.dto.AutomaticBandingTaskDto;
  10. import com.xjrsoft.module.banding.dto.BandingTaskClassConditionDto;
  11. import com.xjrsoft.module.banding.dto.SureBandingTaskDto;
  12. import com.xjrsoft.module.banding.entity.BandingRule;
  13. import com.xjrsoft.module.banding.entity.BandingTask;
  14. import com.xjrsoft.module.banding.entity.BandingTaskClass;
  15. import com.xjrsoft.module.banding.entity.BandingTaskClassStudent;
  16. import com.xjrsoft.module.banding.entity.BandingTaskRule;
  17. import com.xjrsoft.module.banding.mapper.BandingRuleMapper;
  18. import com.xjrsoft.module.banding.mapper.BandingTaskClassMapper;
  19. import com.xjrsoft.module.banding.mapper.BandingTaskMapper;
  20. import com.xjrsoft.module.banding.mapper.BandingTaskRuleMapper;
  21. import com.xjrsoft.module.banding.service.IBandingTaskClassStudentService;
  22. import com.xjrsoft.module.banding.service.IBandingTaskService;
  23. import com.xjrsoft.module.outint.vo.IdCountVo;
  24. import com.xjrsoft.module.student.entity.BaseNewStudent;
  25. import com.xjrsoft.module.student.entity.EnrollmentPlan;
  26. import com.xjrsoft.module.student.service.IBaseNewStudentService;
  27. import lombok.AllArgsConstructor;
  28. import org.springframework.stereotype.Service;
  29. import org.springframework.transaction.annotation.Transactional;
  30. import java.util.ArrayList;
  31. import java.util.Date;
  32. import java.util.HashMap;
  33. import java.util.List;
  34. import java.util.Map;
  35. import java.util.Random;
  36. import java.util.stream.Collectors;
  37. /**
  38. * @title: 新生分班任务
  39. * @Author dzx
  40. * @Date: 2024-07-01
  41. * @Version 1.0
  42. */
  43. @Service
  44. @AllArgsConstructor
  45. public class BandingTaskServiceImpl extends MPJBaseServiceImpl<BandingTaskMapper, BandingTask> implements IBandingTaskService {
  46. private final BandingTaskMapper bandingTaskMapper;
  47. private final BandingRuleMapper ruleMapper;
  48. private final BandingTaskRuleMapper taskRuleMapper;
  49. private final BandingTaskClassMapper taskClassMapper;
  50. private final IBaseNewStudentService newStudentService;
  51. private final IBandingTaskClassStudentService classStudentService;
  52. @Override
  53. @Transactional(rollbackFor = Exception.class)
  54. public Boolean add(BandingTask bandingTask) {
  55. bandingTask.setCreateDate(new Date());
  56. bandingTaskMapper.insert(bandingTask);
  57. return true;
  58. }
  59. @Override
  60. @Transactional(rollbackFor = Exception.class)
  61. public Boolean update(BandingTask bandingTask) {
  62. bandingTask.setModifyDate(new Date());
  63. bandingTaskMapper.updateById(bandingTask);
  64. return true;
  65. }
  66. @Override
  67. @Transactional(rollbackFor = Exception.class)
  68. public Boolean delete(List<Long> ids) {
  69. bandingTaskMapper.deleteBatchIds(ids);
  70. taskRuleMapper.delete(Wrappers.lambdaQuery(BandingTaskRule.class).in(BandingTaskRule::getBandingTaskId, ids));
  71. taskClassMapper.delete(Wrappers.lambdaQuery(BandingTaskClass.class).in(BandingTaskClass::getBandingTaskId, ids));
  72. return true;
  73. }
  74. /**
  75. * 自动分班
  76. * 1、根据分班任务的信息,查询出来需要分班的学生
  77. * 2、查询该任务下的班级信息
  78. * 3、查询该任务使用的规则
  79. * 4、执行自动分班
  80. * 5、完成后,将分好班的信息存到banding_task_class_student表中
  81. */
  82. @Override
  83. public Boolean automaticBanding(AutomaticBandingTaskDto dto) {
  84. BandingTask bandingTask = this.getById(dto.getBandingTaskId());
  85. if(bandingTask == null){
  86. throw new MyException("未能查询到该任务,无法自动分班");
  87. }
  88. //1、查询需要分班的学生信息
  89. List<String> orderColumn = new ArrayList();
  90. orderColumn.add("height");orderColumn.add("score");
  91. List<BaseNewStudent> baseNewStudents = newStudentService.selectJoinList(BaseNewStudent.class,
  92. new MPJLambdaWrapper<BaseNewStudent>()
  93. .select(BaseNewStudent::getId)
  94. .select(BaseNewStudent.class, x -> VoToColumnUtil.fieldsToColumns(BaseNewStudent.class).contains(x.getProperty()))
  95. .leftJoin(EnrollmentPlan.class, EnrollmentPlan::getId, BaseNewStudent::getEnrollmentPlanId)
  96. .eq(EnrollmentPlan::getGradeId, bandingTask.getGradeId())
  97. .eq(EnrollmentPlan::getEnrollType, bandingTask.getEnrollType())
  98. .eq(BaseNewStudent::getStatus, 0)
  99. .orderByDescStr(orderColumn)
  100. );
  101. //2、查询所有班级信息
  102. List<BandingTaskClass> classList = taskClassMapper.selectList(
  103. new QueryWrapper<BandingTaskClass>().lambda()
  104. .select(BandingTaskClass::getId)
  105. .select(BandingTaskClass.class, x -> VoToColumnUtil.fieldsToColumns(BandingTaskClass.class).contains(x.getProperty()))
  106. .eq(BandingTaskClass::getBandingTaskId, bandingTask.getId())
  107. .orderByAsc(BandingTaskClass::getSortCode)
  108. );
  109. //3、查询所用到的规则
  110. List<BandingRule> ruleList = ruleMapper.selectJoinList(BandingRule.class,
  111. new MPJLambdaWrapper<BandingRule>()
  112. .select(BandingRule::getId)
  113. .select(BandingRule.class, x -> VoToColumnUtil.fieldsToColumns(BandingRule.class).contains(x.getProperty()))
  114. .innerJoin(BandingTaskRule.class, BandingTaskRule::getBandingRuleId, BandingRule::getId)
  115. .eq(BandingTaskRule::getBandingTaskId, bandingTask.getId())
  116. );
  117. List<String> ruleCodes = ruleList.stream().map(BandingRule::getCode).collect(Collectors.toList());
  118. //包含下面个条件,则需要计算每个班级应该分配的人数
  119. Map<Long, Integer> classLimitMap = new HashMap<>();
  120. if(ruleCodes.contains("BR0004")){
  121. //查询每个专业下面的班级人数
  122. Map<Long, Integer> majorClassStudentCount = taskClassMapper.getMajorClassStudentCount(bandingTask.getId())
  123. .stream().collect(Collectors.toMap(IdCountVo::getId, IdCountVo::getCount));
  124. //查询每个专业下面有多少个班级
  125. Map<Long, Integer> majorClassCount = taskClassMapper.getMajorClassCount(bandingTask.getId())
  126. .stream().collect(Collectors.toMap(IdCountVo::getId, IdCountVo::getCount));
  127. //查询每个专业人数
  128. Map<Long, Integer> majorStudentCount = newStudentService.getMajorStudentCount()
  129. .stream().collect(Collectors.toMap(IdCountVo::getId, IdCountVo::getCount));
  130. Map<Long, Integer> majorLimitMap = new HashMap<>();
  131. for (Long majorSetId : majorClassStudentCount.keySet()) {
  132. Integer majorClassNumber = majorClassStudentCount.get(majorSetId);
  133. Integer majorStudentNumber = majorStudentCount.get(majorSetId);
  134. Integer classCount = majorClassCount.get(majorSetId);
  135. if(majorStudentNumber < majorClassNumber){//报名人数小于班级人数
  136. Integer classLimtCount = majorStudentNumber / classCount;
  137. majorLimitMap.put(majorSetId, classLimtCount);
  138. }else{
  139. Integer classLimtCount = majorClassNumber / classCount;
  140. majorLimitMap.put(majorSetId, classLimtCount);
  141. }
  142. }
  143. for (BandingTaskClass bandingTaskClass : classList) {
  144. classLimitMap.put(bandingTaskClass.getId(), majorLimitMap.get(bandingTaskClass.getMajorSetId()));
  145. }
  146. }
  147. Map<Long, BandingTaskClassConditionDto> classConditionMap = new HashMap<>();
  148. for (BandingTaskClassConditionDto classConditionDto : dto.getClassInfo()) {
  149. classConditionMap.put(classConditionDto.getBandingTaskCassId(), classConditionDto);
  150. }
  151. //存班级和学生的关系
  152. Map<Long, Long> studentClassMap = new HashMap<>();
  153. //4、开始分班
  154. for (BandingTaskClass taskClass : classList) {
  155. Integer number = taskClass.getNumber();//班级总人数
  156. if(classLimitMap.get(taskClass.getId()) != null){
  157. number = classLimitMap.get(taskClass.getId());
  158. }
  159. Integer maleCount = 0, femaleCount = 0;
  160. if(ruleCodes.contains("BR0001")){
  161. maleCount = number / 2;
  162. femaleCount = number / 2;
  163. //如果班级人数是奇数,随机分配一个名额
  164. if(number % 2 != 0){
  165. Random random = new Random();
  166. int randomIndex = random.nextInt(GenderDictionaryEnum.getCodes().length);
  167. String randomGender = GenderDictionaryEnum.getCodes()[randomIndex];
  168. if(GenderDictionaryEnum.MALE.getCode().equals(randomGender)){
  169. maleCount ++;
  170. }else if(GenderDictionaryEnum.FEMALE.getCode().equals(randomGender)){
  171. femaleCount ++ ;
  172. }
  173. }
  174. }
  175. List<String> nameList = new ArrayList<>();
  176. List<BaseNewStudent> maleList = new ArrayList();
  177. List<BaseNewStudent> femaleList = new ArrayList();
  178. for (BaseNewStudent newStudent : baseNewStudents) {
  179. //人数已满,进行下一个班级的的循环
  180. if(nameList.size() == number){
  181. break;
  182. }
  183. //该学生已被分配
  184. if(studentClassMap.containsKey(newStudent.getId())){
  185. continue;
  186. }
  187. if(ruleCodes.contains("BR0003") && nameList.contains(newStudent.getName())){
  188. continue;
  189. }
  190. //专业不匹配,直接跳过
  191. if(taskClass.getMajorSetId() != newStudent.getFirstAmbitionId() && taskClass.getMajorSetId() != newStudent.getSecondAmbitionId()){
  192. continue;
  193. }
  194. //判断该班性别是否已满
  195. if(ruleCodes.contains("BR0001")){
  196. if(GenderDictionaryEnum.MALE.getCode().equals(newStudent.getGender()) && maleList.size() == maleCount){
  197. continue;
  198. }else if(GenderDictionaryEnum.FEMALE.getCode().equals(newStudent.getGender()) && femaleList.size() == femaleCount){
  199. continue;
  200. }
  201. }
  202. List<Boolean> conditionList = new ArrayList<>();
  203. BandingTaskClassConditionDto condition = classConditionMap.get(taskClass.getId());
  204. if(condition.getHeight() !=null && newStudent.getHeight() != null && newStudent.getHeight().compareTo(condition.getHeight()) >= 0 ){
  205. conditionList.add(true);
  206. }else if(condition.getHeight() !=null && newStudent.getHeight() != null && newStudent.getHeight().compareTo(condition.getHeight()) < 0){
  207. conditionList.add(false);
  208. }else if(condition.getHeight() !=null && newStudent.getHeight() == null){
  209. conditionList.add(false);
  210. }
  211. if(condition.getScore() !=null && newStudent.getScore() != null && newStudent.getScore().compareTo(condition.getScore()) >= 0 ){
  212. conditionList.add(true);
  213. }else if(condition.getScore() !=null && newStudent.getScore() != null && newStudent.getScore().compareTo(condition.getScore()) < 0){
  214. conditionList.add(false);
  215. }else if(condition.getScore() !=null && newStudent.getScore() == null){
  216. conditionList.add(false);
  217. }
  218. //如果包含false,则表明不符合条件,这个学生跳过
  219. if(conditionList.contains(false)){
  220. continue;
  221. }
  222. studentClassMap.put(newStudent.getId(), taskClass.getId());
  223. if(GenderDictionaryEnum.MALE.getCode().equals(newStudent.getGender())){
  224. maleList.add(newStudent);
  225. }else if(GenderDictionaryEnum.FEMALE.getCode().equals(newStudent.getGender())){
  226. femaleList.add(newStudent);
  227. }
  228. nameList.add(newStudent.getName());
  229. //清除已经被分班的学生
  230. baseNewStudents.remove(newStudent);
  231. }
  232. }
  233. List<BandingTaskClassStudent> dataList = new ArrayList<>();
  234. Date createDate = new Date();
  235. for (Long studentId : studentClassMap.keySet()) {
  236. dataList.add(
  237. new BandingTaskClassStudent(){{
  238. setBandingTaskClassId(studentClassMap.get(studentId));
  239. setNewStudentId(studentId);
  240. setStatus(0);
  241. setCreateDate(createDate);
  242. }}
  243. );
  244. }
  245. if(!dataList.isEmpty()){
  246. classStudentService.saveBatch(dataList);
  247. }
  248. return true;
  249. }
  250. @Override
  251. public Boolean sure(SureBandingTaskDto dto) {
  252. List<BandingTaskClassStudent> classStudents = classStudentService.selectJoinList(BandingTaskClassStudent.class,
  253. new MPJLambdaWrapper<BandingTaskClassStudent>()
  254. .select(BandingTaskClassStudent::getId)
  255. .select(BandingTaskClassStudent.class, x -> VoToColumnUtil.fieldsToColumns(BandingTaskClassStudent.class).contains(x.getProperty()))
  256. .leftJoin(BandingTaskClass.class, BandingTaskClass::getId, BandingTaskClassStudent::getBandingTaskClassId)
  257. .eq(BandingTaskClass::getBandingTaskId, dto.getId())
  258. .eq(BandingTaskClassStudent::getStatus, 1)
  259. );
  260. List<Long> studentIds = classStudents.stream().map(BandingTaskClassStudent::getNewStudentId).collect(Collectors.toList());
  261. List<BaseNewStudent> list = newStudentService.list(
  262. new QueryWrapper<BaseNewStudent>().lambda()
  263. .in(BaseNewStudent::getId, studentIds)
  264. );
  265. List<BaseNewStudent> updateList = new ArrayList<>();
  266. for (BaseNewStudent student : list) {
  267. student.setStatus(1);
  268. updateList.add(student);
  269. }
  270. if(!updateList.isEmpty()){
  271. newStudentService.updateBatchById(updateList);
  272. }
  273. BandingTask bandingTask = this.getById(dto.getId());
  274. bandingTask.setStatus(1);
  275. bandingTask.setModifyDate(new Date());
  276. Boolean isSuccess = this.update(bandingTask);
  277. return isSuccess;
  278. }
  279. }