VoluntaryService.java 93 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685
  1. package com.ruoyi.web.service;
  2. import com.alibaba.fastjson2.JSONArray;
  3. import com.alibaba.fastjson2.JSONException;
  4. import com.alibaba.fastjson2.JSONObject;
  5. import com.fasterxml.jackson.core.JsonProcessingException;
  6. import com.fasterxml.jackson.core.type.TypeReference;
  7. import com.fasterxml.jackson.databind.DeserializationFeature;
  8. import com.fasterxml.jackson.databind.ObjectMapper;
  9. import com.google.common.collect.Lists;
  10. import com.google.common.collect.Maps;
  11. import com.google.common.collect.Sets;
  12. import com.ruoyi.common.core.content.VistorContextHolder;
  13. import com.ruoyi.common.core.domain.R;
  14. import com.ruoyi.common.core.domain.entity.SysUser;
  15. import com.ruoyi.common.core.page.TableDataInfo;
  16. import com.ruoyi.common.enums.ExamType;
  17. import com.ruoyi.common.enums.SubjectType;
  18. import com.ruoyi.common.exception.ServiceException;
  19. import com.ruoyi.common.utils.SecurityUtils;
  20. import com.ruoyi.common.utils.StringUtils;
  21. import com.ruoyi.common.utils.dz.SubjectScore;
  22. import com.ruoyi.ie.domain.*;
  23. import com.ruoyi.ie.mapper.*;
  24. import com.ruoyi.system.service.ISysConfigService;
  25. import com.ruoyi.syzy.domain.BBusiWishUniversities;
  26. import com.ruoyi.syzy.domain.BBusiWishUniversitiesProfession;
  27. import com.ruoyi.syzy.dto.UniversityDetailDTO;
  28. import com.ruoyi.syzy.mapper.BBusiWishRecordsMapper;
  29. import com.ruoyi.syzy.mapper.BBusiWishUniversitiesMapper;
  30. import com.ruoyi.syzy.mapper.BBusiWishUniversitiesProfessionMapper;
  31. import com.ruoyi.util.PageUtil;
  32. import com.ruoyi.web.domain.Constant;
  33. import com.ruoyi.web.domain.VoluntaryDto;
  34. import io.swagger.annotations.ApiModelProperty;
  35. import io.swagger.annotations.ApiParam;
  36. import org.apache.commons.collections.CollectionUtils;
  37. import org.apache.commons.collections.MapUtils;
  38. import org.apache.commons.lang3.ArrayUtils;
  39. import org.apache.commons.lang3.math.NumberUtils;
  40. import org.apache.commons.lang3.tuple.MutablePair;
  41. import org.apache.commons.lang3.tuple.Pair;
  42. import org.springframework.stereotype.Service;
  43. import org.springframework.web.bind.annotation.RequestParam;
  44. import java.text.SimpleDateFormat;
  45. import java.util.*;
  46. import java.util.function.Function;
  47. import java.util.stream.Collectors;
  48. import java.util.stream.Stream;
  49. @Service
  50. public class VoluntaryService {
  51. private ObjectMapper mapper = new ObjectMapper();
  52. private static TypeReference<List<VoluntaryDto.SingleResponse>> wishDetailsTypeReference = new TypeReference<List<VoluntaryDto.SingleResponse>>() { };
  53. private static TypeReference<List<VoluntaryDto.AIResponse>> wishAiDetailsTypeReference = new TypeReference<List<VoluntaryDto.AIResponse>>() { };
  54. Set<String> NumberTypeSet = Sets.newHashSet(VoluntaryDto.EnumInputType.Number.name(), VoluntaryDto.EnumInputType.Eyesight.name(), VoluntaryDto.EnumInputType.Score.name());
  55. private static VoluntaryRuleHelper voluntaryRuleHelper = new VoluntaryRuleHelper();
  56. private final AWishRecordMapper aWishRecordMapper;
  57. private final AEnrollScoreMapper aEnrollScoreMapper;
  58. private final AEnrollSpecialMapper aEnrollSpecialMapper;
  59. private final AMarjorPlanMapper aMarjorPlanMapper;
  60. private final AMarjorSubmitMapper aMarjorSubmitMapper;
  61. private final AEnrollUniversityMapper aEnrollUniversityMapper;
  62. private final BBusiWishUniversitiesMapper bBusiWishUniversitiesMapper;
  63. private final BBusiWishUniversitiesProfessionMapper bBusiWishUniversitiesProfessionMapper;
  64. private final ISysConfigService sysConfigService;
  65. private final EnrollRateCalculator enrollRateCalculator;
  66. private final BBusiWishRecordsMapper busiWishRecordsMapper;
  67. public VoluntaryService(AWishRecordMapper aWishRecordMapper, AEnrollScoreMapper aEnrollScoreMapper, AEnrollSpecialMapper aEnrollSpecialMapper, AMarjorPlanMapper aMarjorPlanMapper, AMarjorSubmitMapper aMarjorSubmitMapper, AEnrollUniversityMapper aEnrollUniversityMapper, BBusiWishUniversitiesMapper bBusiWishUniversitiesMapper, BBusiWishUniversitiesProfessionMapper bBusiWishUniversitiesProfessionMapper, ISysConfigService sysConfigService, EnrollRateCalculator enrollRateCalculator, BBusiWishRecordsMapper busiWishRecordsMapper) {
  68. this.aWishRecordMapper = aWishRecordMapper;
  69. this.aEnrollScoreMapper = aEnrollScoreMapper;
  70. this.aEnrollSpecialMapper = aEnrollSpecialMapper;
  71. this.aMarjorPlanMapper = aMarjorPlanMapper;
  72. this.aMarjorSubmitMapper = aMarjorSubmitMapper;
  73. this.aEnrollUniversityMapper = aEnrollUniversityMapper;
  74. this.bBusiWishUniversitiesMapper = bBusiWishUniversitiesMapper;
  75. this.bBusiWishUniversitiesProfessionMapper = bBusiWishUniversitiesProfessionMapper;
  76. this.sysConfigService = sysConfigService;
  77. this.enrollRateCalculator = enrollRateCalculator;
  78. this.busiWishRecordsMapper = busiWishRecordsMapper;
  79. // mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
  80. mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
  81. }
  82. public Pair<List<UniversityDetailDTO.WishPlan>, List<UniversityDetailDTO.WishSubmit>> getUniversityHistory(Long universityId, String province, String examineType) {
  83. AMarjorPlan planCond = new AMarjorPlan();
  84. planCond.setUniversityId(universityId);
  85. planCond.setExamineeType(examineType);
  86. List<UniversityDetailDTO.WishPlan> planList = aMarjorPlanMapper.selectAMarjorPlanList(planCond).stream().map(t -> {
  87. UniversityDetailDTO.WishPlan p = new UniversityDetailDTO.WishPlan();
  88. p.setId(t.getId());
  89. p.setCollegeCode(t.getEnrollCode());
  90. p.setYear(String.valueOf(t.getYear()));
  91. p.setLevel(t.getLevel());
  92. p.setType("");
  93. p.setMarjorCode(t.getMajorCode());
  94. p.setMarjorName(t.getMajorName());
  95. p.setMarjorBelongs(t.getMajorEnrollCode());
  96. p.setMarjorDirection(t.getMajorDirection());
  97. p.setSpecialProject("");
  98. p.setPlanCount(t.getPlanTotal());
  99. p.setXuefei(String.valueOf(t.getXuefei()));
  100. p.setXuezhi(String.valueOf(t.getLengthOfSchooling()));
  101. p.setEnrollFormula(t.getEnrollFormula());
  102. p.setGroupsName(t.getMajorGroup());
  103. p.setAcceptanceRate(t.getAcceptanceRate());
  104. p.setEnrollCount(t.getEnrollCount());
  105. return p;
  106. }).collect(Collectors.toList());
  107. AMarjorSubmit submitCond = new AMarjorSubmit();
  108. submitCond.setUniversityId(universityId);
  109. submitCond.setEnrollType("初录");
  110. submitCond.setExamineeType(examineType);
  111. List<UniversityDetailDTO.WishSubmit> submitList = aMarjorSubmitMapper.selectAMarjorSubmitList(submitCond).stream().map(t -> {
  112. UniversityDetailDTO.WishSubmit s = new UniversityDetailDTO.WishSubmit();
  113. s.setId(t.getId());
  114. s.setYear(String.valueOf(t.getYear()));
  115. s.setLevel(t.getLevel());
  116. s.setType("");
  117. s.setMarjorCode("");
  118. s.setMarjorName(t.getMajorName());
  119. s.setMarjorBelongs("");
  120. s.setMarjorDirection(t.getMajorDirection());
  121. s.setSpecialProject("");
  122. s.setScore(null != t.getScore() ? t.getScore().longValue() : null);
  123. s.setSeat(null);
  124. s.setNumReal(null != t.getEnrollTotal() ? t.getEnrollTotal().longValue() : null);
  125. s.setEnrollFormula(t.getEnrollFormula());
  126. s.setGroupsName(t.getMajorGroup());
  127. return s;
  128. }).collect(Collectors.toList());
  129. return Pair.of(planList, submitList);
  130. }
  131. private void setOptionValue(VoluntaryDto.AIRenderRule r, String valueType, String valueRule, String options, Integer correctType, String correctValue, Integer scoreTotal) {
  132. r.setEnumInputType(VoluntaryDto.EnumInputType.valueOf(valueType));
  133. if (VoluntaryDto.EnumInputType.Score.equals(r.getEnumInputType())) {
  134. r.setOptions(new String[]{null == scoreTotal ? "0" : String.valueOf(scoreTotal.intValue())});
  135. } else if (StringUtils.isNotBlank(options) && (VoluntaryDto.EnumInputType.Checkbox.equals(r.getEnumInputType())
  136. || VoluntaryDto.EnumInputType.Radio.equals(r.getEnumInputType()) || VoluntaryDto.EnumInputType.Picker.equals(r.getEnumInputType()))) {
  137. r.setOptions(options.split(","));
  138. }
  139. // r.setRequired();
  140. // 词典选项类选项 // 词典类选项的优先级最高
  141. // String dictOptions;
  142. // 非词典选项 // 分制类规则,将多分制在此options中返回
  143. // String[] options;
  144. }
  145. public Integer getPlanYear(SysUser u) {
  146. return 2025;
  147. }
  148. public Integer getSubmitYear() {
  149. return 2025;
  150. }
  151. public R<VoluntaryDto.RenderMajorResult> postRenderResult(VoluntaryDto.SingleRequest req, Boolean isScoreOnly) {
  152. Integer planYear = getPlanYear(SecurityUtils.getLoginUser().getUser());
  153. Integer submitYear = getSubmitYear();
  154. String examType = VistorContextHolder.getExamType().title(); // TODO MF
  155. String gender = "0".equals(SecurityUtils.getLoginUser().getUser().getSex()) ? "男生" : "女生";
  156. Map cond = new HashMap();
  157. cond.put("universityCode", req.getUniversityCode());
  158. cond.put("examineeType", examType);
  159. Map<Long, List<AMarjorPlan>> currUniversityMajorPlansMap = Maps.newHashMap();
  160. Map<Long, List<AMarjorPlan>> historyUniversityMajorPlansMap = Maps.newHashMap();
  161. List<Map<Long, List<AMarjorPlan>>> bothPlanList = Lists.newArrayList(currUniversityMajorPlansMap, historyUniversityMajorPlansMap);
  162. Set<String> existSet = Sets.newHashSet();
  163. Long planId = NumberUtils.toLong(req.getMajorEnrollCode(), 0L);
  164. for (AMarjorPlan mp : aMarjorPlanMapper.selectListByRuleCond(cond)) {
  165. String key = mp.getUniversityId() + mp.getMajorName() + StringUtils.trimToEmpty(mp.getMajorDirection()) + mp.getYear(); // TODO 考虑为什么会重的问题 examType ?
  166. if (!existSet.add(key)) {
  167. continue;
  168. }
  169. for(Map<Long, List<AMarjorPlan>> tmpMap : bothPlanList) {
  170. boolean isCurrYear = mp.getYear().equals(planYear);
  171. if (tmpMap == currUniversityMajorPlansMap) {
  172. if(!isCurrYear || !mp.getId().equals(planId)) {
  173. continue;
  174. }
  175. } else if(mp.getYear() > submitYear) {
  176. continue;
  177. }
  178. List<AMarjorPlan> tmpMpList = tmpMap.get(mp.getUniversityId());
  179. if (null == tmpMpList) {
  180. tmpMpList = Lists.newArrayList(mp);
  181. tmpMap.put(mp.getUniversityId(), tmpMpList);
  182. } else {
  183. tmpMpList.add(mp);
  184. }
  185. }
  186. }
  187. Map<Long, List<BBusiWishUniversitiesProfession>> universityMajorsMap = Maps.newHashMap();
  188. // 有计划以计划为准的输出,无计划时则以所有专业输出为准
  189. Map<Long, BBusiWishUniversities> universitiesMap = null;
  190. if (MapUtils.isEmpty(currUniversityMajorPlansMap)) {
  191. Map<String, List<BBusiWishUniversitiesProfession>> tmpUniversityMajorsMap = bBusiWishUniversitiesProfessionMapper.selectListByRuleCond(cond).stream().collect(Collectors.groupingBy(BBusiWishUniversitiesProfession::getCollegeCode));
  192. if (MapUtils.isNotEmpty(tmpUniversityMajorsMap)) {
  193. Map uCond = Maps.newHashMap();
  194. uCond.put("codes", tmpUniversityMajorsMap.keySet());
  195. universitiesMap = Maps.newHashMap();
  196. for (BBusiWishUniversities u : bBusiWishUniversitiesMapper.selectBBusiWishUniversitiesListSimpleByMap(uCond)) {
  197. universitiesMap.put(u.getId(), u);
  198. universityMajorsMap.put(u.getId(), tmpUniversityMajorsMap.get(u.getCode()));
  199. }
  200. }
  201. } else {
  202. cond.put("universityIds", currUniversityMajorPlansMap.keySet());
  203. cond.put("examType", Constant.EXAM_TYPE_PG);
  204. Map<String, List<BBusiWishUniversitiesProfession>> tmpUniversityMajorsMap = bBusiWishUniversitiesProfessionMapper.selectListByRuleCond(cond).stream().collect(Collectors.groupingBy(BBusiWishUniversitiesProfession::getCollegeCode));
  205. cond.remove("universityIds");
  206. if (MapUtils.isNotEmpty(tmpUniversityMajorsMap)) {
  207. Map uCond = new HashMap();
  208. uCond.put("ids", currUniversityMajorPlansMap.keySet());
  209. universitiesMap = Maps.newHashMap();
  210. for (BBusiWishUniversities u : bBusiWishUniversitiesMapper.selectBBusiWishUniversitiesListSimpleByIds(uCond)) {
  211. universitiesMap.put(u.getId(), u);
  212. universityMajorsMap.put(u.getId(), tmpUniversityMajorsMap.get(u.getCode()));
  213. }
  214. }
  215. }
  216. // 无计划,也无院校专业
  217. if(MapUtils.isEmpty(universitiesMap)) {
  218. return R.fail("无计划院校专业");
  219. }
  220. // 查询涉及的规则
  221. cond.put("year", planYear);
  222. cond.put("universityIds", universitiesMap.keySet());
  223. Map<Long, List<AEnrollScore>> universityScoreListMap = aEnrollScoreMapper.selectListByRuleCond(cond).stream().collect(Collectors.groupingBy(AEnrollScore::getUniversityId));
  224. cond.remove("universityIds");
  225. cond.remove("year");
  226. Map<String, String> mutexOptionMap = getMutexOptionMap();
  227. for (Long universityId : universitiesMap.keySet()) {
  228. List<AEnrollScore> scoreList = universityScoreListMap.get(universityId); // 分数条件
  229. List<AMarjorPlan> currPlanList = currUniversityMajorPlansMap.get(universityId);// 当年计划
  230. List<AMarjorPlan> historyPlanList = historyUniversityMajorPlansMap.get(universityId);// 历年计划
  231. BBusiWishUniversities u = universitiesMap.get(universityId);// 院校
  232. List<BBusiWishUniversitiesProfession> professionList = universityMajorsMap.get(u.getId()); // 所有专业
  233. // 院校变更标志
  234. AEnrollUniversity euCond = new AEnrollUniversity();
  235. euCond.setUniversityId(u.getId());
  236. euCond.setYear(planYear);
  237. List<AEnrollUniversity> enrollUniversityList = aEnrollUniversityMapper.selectAEnrollUniversityList(euCond);
  238. // 院校历史情况
  239. AMarjorSubmit submitCond = new AMarjorSubmit();
  240. submitCond.setExamineeType(examType);
  241. submitCond.setUniversityId(universityId);
  242. List<AMarjorSubmit> submitList = aMarjorSubmitMapper.selectAMarjorSubmitList(submitCond);
  243. VoluntaryDto.RenderMajorResult sr;
  244. if (CollectionUtils.isNotEmpty(currPlanList)) {
  245. Map<String, BBusiWishUniversitiesProfession> professionMap = null == professionList ? Maps.newHashMap() : professionList.stream().collect(Collectors.toMap(BBusiWishUniversitiesProfession::getName, Function.identity()));
  246. for (AMarjorPlan mp : currPlanList) { // 只有一个
  247. if (null != (sr = buildRenderResponse(submitYear, planYear, gender, mp, professionMap.get(mp.getMajorName()), enrollUniversityList, req.getForm(), u,
  248. historyPlanList, submitList, scoreList, mutexOptionMap, isScoreOnly))) {
  249. sr.setUniversityId(universityId);
  250. sr.setMajorId(planId);
  251. return R.ok(sr);
  252. }
  253. }
  254. }
  255. }
  256. return R.fail("无计划院校专业");
  257. }
  258. private VoluntaryDto.RenderMajorResult buildRenderResponse(Integer submitYear, Integer planYear, String gender, AMarjorPlan currPlan, BBusiWishUniversitiesProfession prof,
  259. List<AEnrollUniversity> enrollUniversityList, Map<String, String> paramMap, BBusiWishUniversities u,
  260. List<AMarjorPlan> historyPlanList, List<AMarjorSubmit> submitList,
  261. List<AEnrollScore> scoreList, Map<String,String> mutexOptionMap, boolean isScoreOnly) {
  262. submitList = voluntaryRuleHelper.sortSubmits(submitList);
  263. historyPlanList = voluntaryRuleHelper.sortPlans(historyPlanList);
  264. Boolean typeChange = false;
  265. VoluntaryDto.FormulaScoreStat formulaScoreStat = new VoluntaryDto.FormulaScoreStat();
  266. String needGroup = StringUtils.trimToEmpty(null != currPlan && null != currPlan.getMajorGroup() ? currPlan.getMajorGroup() : "");
  267. String needMajor = StringUtils.trimToEmpty(null != currPlan ? currPlan.getMajorName() : (null != prof ? prof.getName() : ""));
  268. String needDirect = StringUtils.trimToEmpty(null != currPlan ? currPlan.getMajorDirection() : "");
  269. String needMajorDirect = needMajor + needDirect;
  270. // 判断是否政策变化情况
  271. List<AEnrollUniversity> validEuList = enrollUniversityList.stream()
  272. .filter(t -> needGroup.equals(StringUtils.trimToEmpty(t.getMajorGroups())) && t.getMajorNames().contains(needMajor))
  273. .collect(Collectors.toList());
  274. typeChange = CollectionUtils.isNotEmpty(validEuList) && new Integer(1).equals(validEuList.get(0).getTypeChange());
  275. Set<String> existSet = Sets.newHashSet();
  276. List<AMarjorSubmit> validSubmitList = voluntaryRuleHelper.filtValidSubmits(needMajorDirect, submitList, existSet);
  277. // 录取线
  278. List<VoluntaryDto.RenderMajorHistory> histories = Lists.newArrayList(); // 历史录取情况
  279. VoluntaryDto.RenderMajorResult sr = new VoluntaryDto.RenderMajorResult();
  280. sr.setHistories(histories);
  281. if (null == scoreList) {
  282. throw new RuntimeException("无分数规则");
  283. }
  284. Map<Boolean, List<AEnrollScore>> majorEnrollScoresMap = voluntaryRuleHelper.buildMajorEnrollScoresMap(scoreList, needGroup);
  285. existSet.clear();
  286. List<AEnrollScore> fEnrollScoreList = Lists.newArrayList();
  287. Double inputScoreRate = NumberUtils.toInt(paramMap.get("ScoreRate"), 0) / 100.0;
  288. String inclMajorDirection = needMajor + "(" + needDirect + ")";
  289. String exclMajorDirection = needMajor + "(";
  290. List<AEnrollScore> tmpEnrollScoreList = majorEnrollScoresMap.get(Boolean.TRUE);
  291. if (null != tmpEnrollScoreList) {
  292. for (AEnrollScore r : tmpEnrollScoreList) {
  293. if(!voluntaryRuleHelper.isMatchMajor(r, needMajor, needMajorDirect, inclMajorDirection, exclMajorDirection)) {
  294. continue;
  295. }
  296. Boolean isSkillScore = isScoreOnly && r.getItemType().equals("ScoreSkill");
  297. appendScoreRule(formulaScoreStat, existSet, r, fEnrollScoreList, false, paramMap, inputScoreRate, isSkillScore);
  298. }
  299. }
  300. if (fEnrollScoreList.size() == 0 && null != (tmpEnrollScoreList = majorEnrollScoresMap.get(Boolean.FALSE))) {
  301. for (AEnrollScore r : tmpEnrollScoreList) {
  302. Boolean isSkillScore = isScoreOnly && r.getItemType().equals("ScoreSkill");
  303. appendScoreRule(formulaScoreStat, existSet, r, fEnrollScoreList, false, paramMap, inputScoreRate, isSkillScore);
  304. }
  305. }
  306. Double currTotal = formulaScoreStat.getTypeValue("StatRateScore", "", false);
  307. existSet.clear();
  308. Map<String, AMarjorPlan> historyPlanMap = historyPlanList.stream().collect(Collectors.toMap(t -> t.getYear() + t.getMajorName() + StringUtils.trimToEmpty(t.getMajorDirection()), Function.identity()));
  309. AMarjorSubmit lastSubmit1 = null, lastSubmit2 = null;
  310. for (AMarjorSubmit s : validSubmitList) {
  311. if (s.getYear().equals(submitYear)) {
  312. if(s.getEnrollType().equals("初录")) {
  313. lastSubmit1 = s;
  314. } else {
  315. lastSubmit2 = s;
  316. }
  317. }
  318. VoluntaryDto.RenderMajorHistory h = new VoluntaryDto.RenderMajorHistory();
  319. h.setYear(s.getYear());
  320. AMarjorPlan p = historyPlanMap.get(s.getYear() + s.getMajorName() + StringUtils.trimToEmpty(s.getMajorDirection()));
  321. if(null != p) {
  322. h.setPlan(p.getPlanTotal());
  323. } else {
  324. // System.out.println(s.getId());
  325. }
  326. h.setEnroll(s.getEnrollTotal());
  327. if(null != s.getScore()) {
  328. h.setScore(String.valueOf(s.getScore()));
  329. h.setDiff((int) Math.round(currTotal - s.getScore()));
  330. } else {
  331. h.setScore("");
  332. h.setDiff(null);
  333. }
  334. h.setRuleContent(s.getEnrollFormula());
  335. h.setApplication("");
  336. h.setAdmission("");
  337. histories.add(h);
  338. }
  339. AMarjorSubmit lastSubmit = null == lastSubmit1 ? lastSubmit2 : lastSubmit1;
  340. Double cultureScore = formulaScoreStat.getTypeValue("StatCategoryScore", "ScoreBase", false);
  341. VoluntaryDto.RenderMajorSkill skill = new VoluntaryDto.RenderMajorSkill();
  342. skill.setYear(currPlan.getYear());
  343. skill.setCultureScore(toString(cultureScore));
  344. String[] formulas = fEnrollScoreList.get(0).getEnrollFormula().split("\\+职业技能");
  345. if(formulas.length != 2) {
  346. throw new RuntimeException("错误定义考试规则" + fEnrollScoreList.get(0).getEnrollFormula());
  347. }
  348. skill.setCultureRule(formulas[0]); // 拆分公式
  349. skill.setEnrollScore(toString(lastSubmit.getScore()));
  350. // 计算概念或反算技能分
  351. boolean isSameYear = planYear.equals(submitYear);
  352. Integer validScoreTotal = isSameYear ? formulaScoreStat.getAllTotal() : lastSubmit.getScoreTotal();
  353. Double currScoreRate = isSameYear ? 1.0 : formulaScoreStat.getAllTotal() * 1.0 / lastSubmit.getScoreTotal();
  354. Double needSkillScore = lastSubmit.getScore() * currScoreRate - cultureScore;
  355. if(isScoreOnly) {
  356. skill.setSkillScore(toString(formulaScoreStat.getImproveSkillScore(needSkillScore)));
  357. } else {
  358. Double skillScore = formulaScoreStat.getTypeValue("StatCategoryScore", "ScoreSkill", true);
  359. skill.setSkillScore(toString(needSkillScore));
  360. skill.setDiff(toString(formulaScoreStat.getImproveSkillScore(skillScore - needSkillScore)));
  361. EnrollRateCalculator.RateLevel rl;
  362. if (currTotal != null && null != (rl = enrollRateCalculator.calSchoolEnrollRate(validScoreTotal, lastSubmit.getScore(), currTotal / currScoreRate))) { // 按去年标准算概率
  363. sr.setEnrollRate(rl.rate);
  364. sr.setEnrollRateText(rl.typeLabel);
  365. sr.setEnumPickType(rl.type);
  366. }
  367. }
  368. sr.setSkill(skill);
  369. return sr;
  370. }
  371. public String toString(Double v) {
  372. return String.valueOf(v);
  373. }
  374. public R<List<VoluntaryDto.RenderRule>> getRenderRules(VoluntaryDto.RenderRequest req) {
  375. Map cond = new HashMap();
  376. Integer planYear = getPlanYear(SecurityUtils.getLoginUser().getUser());
  377. cond.put("year", planYear);
  378. AMarjorPlan plan = aMarjorPlanMapper.selectAMarjorPlanById(req.getMajorId());
  379. cond.put("majorGroup", StringUtils.trimToEmpty(plan.getMajorGroup()));
  380. cond.put("majorGroupCodes", plan.getMajorCode());
  381. cond.put("universityCode", req.getUniversityId());
  382. return R.ok(findMatchRenderRules(cond, req.getRenderType() == 2));
  383. }
  384. public R<List<VoluntaryDto.AIRenderRule>> getAIRenderRules(VoluntaryDto.AIRenderRequest req) {
  385. Map cond = new HashMap();
  386. Integer planYear = getPlanYear(SecurityUtils.getLoginUser().getUser());
  387. cond.put("year", planYear);
  388. Set<String> majorCodeSet = null;
  389. String majorGroup = null;
  390. if (ArrayUtils.isNotEmpty(req.getMajorEnrollCodes()) && StringUtils.isNotBlank(req.getMajorEnrollCodes()[0])) {
  391. List<Long> majorEnrollCodes = Arrays.asList(req.getMajorEnrollCodes()).stream().map(t -> NumberUtils.toLong(t, 0L)).collect(Collectors.toList());
  392. for(AMarjorPlan plan : aMarjorPlanMapper.selectMajorCodesByIds(majorEnrollCodes.toArray(new Long[majorEnrollCodes.size()]), planYear)) {
  393. majorGroup = StringUtils.trimToEmpty(plan.getMajorGroup());
  394. majorCodeSet = Sets.newHashSet(plan.getMajorCode());
  395. }
  396. }
  397. if(CollectionUtils.isNotEmpty(majorCodeSet)) {
  398. cond.put("majorGroup", majorGroup);
  399. cond.put("majorGroupCodes", majorCodeSet.toArray(new String[majorCodeSet.size()]));
  400. } else if (ArrayUtils.isNotEmpty(req.getMajorCodes()) && StringUtils.isNotBlank(req.getMajorCodes()[0])) {
  401. cond.put("majorCodes", req.getMajorCodes());
  402. } else if (ArrayUtils.isNotEmpty(req.getMajorTypes()) && StringUtils.isNotBlank(req.getMajorTypes()[0])) {
  403. cond.put("majorTypes", req.getMajorTypes());
  404. } else if (StringUtils.isNotBlank(req.getMajorCategory())) {
  405. cond.put("majorCategory", req.getMajorCategory());
  406. }
  407. cond.put("universityCode", req.getUniversityCode());
  408. return R.ok(findMatchRules(cond, req.getRenderType() == 1, req.getRenderType() == 2));
  409. }
  410. public R<VoluntaryDto.SingleResponse> postSingleResult(VoluntaryDto.SingleRequest req, Boolean isScoreOnly) {
  411. VoluntaryDto.MultipleRequest mr = new VoluntaryDto.MultipleRequest();
  412. VoluntaryDto.CollegeMajorDto collegeMajor = new VoluntaryDto.CollegeMajorDto();
  413. collegeMajor.setCode(req.getUniversityCode());
  414. if (StringUtils.isNotBlank(req.getMajorCode())) {
  415. collegeMajor.setMajorCodes(Lists.newArrayList(req.getMajorCode()));
  416. }
  417. if (StringUtils.isNotBlank(req.getMajorEnrollCode())) {
  418. collegeMajor.setMajorEnrollCodes(Lists.newArrayList(req.getMajorEnrollCode()));
  419. }
  420. collegeMajor.setForm(req.getForm());
  421. mr.setUniversities(Lists.newArrayList(collegeMajor));
  422. List<VoluntaryDto.SingleResponse> respList = postMultipleResult(mr, isScoreOnly).getData();
  423. if (respList.size() > 0) {
  424. Optional<VoluntaryDto.SingleResponse> optionalSingleResponse = respList.stream().filter(t -> StringUtils.isBlank(t.getMajorDirection())).findFirst();
  425. if (optionalSingleResponse.isPresent()) {
  426. return R.ok(optionalSingleResponse.get());
  427. }
  428. }
  429. return respList.size() > 0 ? R.ok(respList.get(0)) : null;
  430. }
  431. public R<List<VoluntaryDto.SingleResponse>> postMultipleResult(VoluntaryDto.MultipleRequest req, boolean isScoreOnly) {
  432. List<VoluntaryDto.SingleResponse> respList = Lists.newArrayList();
  433. for (VoluntaryDto.CollegeMajorDto cm : req.getUniversities()) {
  434. Map cond = new HashMap();
  435. if (CollectionUtils.isNotEmpty(cm.getMajorEnrollCodes()) && StringUtils.isNotBlank(cm.getMajorEnrollCodes().get(0))) {
  436. cond.put("majorEnrollCodes", cm.getMajorEnrollCodes()); // TODO 代替majorCodes更精准,只是现在没有,使用planId代替
  437. } else if (CollectionUtils.isNotEmpty(cm.getMajorCodes()) && StringUtils.isNotBlank(cm.getMajorCodes().get(0))) {
  438. cond.put("majorCodes", cm.getMajorCodes());
  439. } else if (StringUtils.isNotBlank(req.getMajorCategory())) {
  440. cond.put("majorCategory", req.getMajorCategory());
  441. }
  442. cond.put("universityCode", StringUtils.trimToEmpty(cm.getCode()));
  443. List<VoluntaryDto.AIResponse> responses = findMajorSuggest(getPlanYear(SecurityUtils.getLoginUser().getUser()), getSubmitYear(), cond, cm.getForm(), false, isScoreOnly);
  444. if(CollectionUtils.isNotEmpty(responses)) {
  445. responses.stream().forEach(t -> respList.addAll(t.getMajorDetails()));
  446. }
  447. }
  448. return R.ok(respList);
  449. }
  450. public TableDataInfo postAIResult(VoluntaryDto.AIRequest req) {
  451. VoluntaryDto.AIRequestFilter filter = req.getFilter();
  452. Map cond = new HashMap();
  453. if (CollectionUtils.isNotEmpty(filter.getMajorTypes()) && StringUtils.isNotBlank(filter.getMajorTypes().get(0))) {
  454. cond.put("majorTypes", filter.getMajorTypes());
  455. } else if (StringUtils.isNotBlank(req.getMajorCategory())) {
  456. cond.put("majorCategory", req.getMajorCategory());
  457. }
  458. cond.put("universityName", filter.getKeyword());// 院校名称
  459. if (CollectionUtils.isNotEmpty(filter.getLevel())) {
  460. cond.put("universityLevel", filter.getLevel());// 办学层次
  461. }
  462. if (CollectionUtils.isNotEmpty(filter.getType())) {
  463. cond.put("universityType", filter.getType());// 院校类型
  464. }
  465. if (CollectionUtils.isNotEmpty(filter.getNatureTypeCN())) {
  466. cond.put("universityNatureType", filter.getNatureTypeCN()); // 办学类型
  467. }
  468. if (CollectionUtils.isNotEmpty(filter.getLocation())) {
  469. cond.put("universityLocation", filter.getLocation()); // 院校省份
  470. }
  471. if (null != filter.getHasClearing()) {
  472. cond.put("hasClearing", filter.getHasClearing() ? "补录" : "初录");
  473. }
  474. List<VoluntaryDto.AIResponse> responses = findMajorSuggest(getPlanYear(SecurityUtils.getLoginUser().getUser()), getSubmitYear(), cond, req.getForm(), true, false);
  475. if (CollectionUtils.isEmpty(responses)) {
  476. return new TableDataInfo(Lists.newArrayList(), 0);
  477. }
  478. if (null != filter.getEnumPickEmpty()) {
  479. responses = responses.stream().filter(t -> filter.getEnumPickEmpty().equals(t.getEnumPickEmpty())).collect(Collectors.toList());
  480. } else if (null != filter.getEnumPickType() && !VoluntaryDto.EnumPickType.All.equals(filter.getEnumPickType())) {
  481. responses = responses.stream().filter(t -> filter.getEnumPickType().equals(t.getEnumPickType())).collect(Collectors.toList());
  482. }
  483. Integer start = null != req.getPageNum() ? (req.getPageNum() - 1) * req.getPageSize() : 0;
  484. List<VoluntaryDto.AIResponse> finalList = responses.subList(start, Math.min(start + (null == req.getPageSize() ? 10 : req.getPageSize()), responses.size()));
  485. TableDataInfo tableDataInfo = new TableDataInfo(finalList, responses.size());
  486. tableDataInfo.setCode(200);
  487. return tableDataInfo;
  488. }
  489. private List<VoluntaryDto.RenderRule> findMatchRenderRules(Map cond, boolean isScore) {
  490. String examType = VistorContextHolder.getExamType().title(); // TODO MF
  491. // String gender = "0".equals(SecurityUtils.getLoginUser().getUser().getSex()) ? "男生" : "女生";
  492. cond.put("examineeType", examType);
  493. List<VoluntaryDto.AIRenderRule> cultureRuleList = Lists.newArrayList();
  494. List<VoluntaryDto.AIRenderRule> skillRuleList = Lists.newArrayList();
  495. List<AEnrollScore> enrollScoreList = aEnrollScoreMapper.selectListByRuleCond(cond);
  496. if (CollectionUtils.isEmpty(enrollScoreList) && cond.containsKey("majorGroup")) {
  497. cond.put("majorGroup", "");
  498. enrollScoreList = aEnrollScoreMapper.selectListByRuleCond(cond);
  499. }
  500. Set<String> existItemSet = Sets.newHashSet();
  501. String vt;
  502. SysUser sysUser = SecurityUtils.getLoginUser().getUser();;
  503. boolean isOHS = ExamType.OHS.equals(sysUser.getExamType());
  504. SubjectScore subjectScore = sysUser.getScores();
  505. for (AEnrollScore s : enrollScoreList) { // 跳过统计类和提示类的规则
  506. boolean isSkill = "职业技能测试".equals(s.getItemCategory());
  507. if (null == (vt = s.getValueType()) || vt.startsWith("Stat") || vt.equals("Notice")) {
  508. continue;
  509. }
  510. List<VoluntaryDto.AIRenderRule> ruleList = isSkill ? skillRuleList : cultureRuleList ;
  511. if (!existItemSet.add(s.getItemField())) {
  512. continue;
  513. }
  514. VoluntaryDto.AIRenderRule r = new VoluntaryDto.AIRenderRule();
  515. r.setEnumRuleCategory(VoluntaryDto.EnumRuleCategory.Enroll);
  516. if (!isSkill && isOHS && !isScore && "Score".equals(s.getValueType())) {
  517. r.setReadonly(true);
  518. Double score = subjectScore.getSelectScore(s.getItemField());
  519. if (null == score && SubjectType.Foreign.name().equals(s.getItemField())) {
  520. score = subjectScore.getSelectScore(SubjectType.English.name());
  521. }
  522. r.setDefaultValue(null != score ? String.valueOf(score) : "0");
  523. } else {
  524. r.setReadonly(false);
  525. r.setDefaultValue(s.getDefaultValue());
  526. }
  527. r.setFieldName(s.getItemField());
  528. setOptionValue(r, vt, s.getValueRule(), s.getValueOptional(), s.getCorrectType(), s.getCorrectValue(), s.getScoreTotal());
  529. r.setRegex(s.getRegex());
  530. r.setLabel(s.getItemName());
  531. r.setDescription(s.getDescription());
  532. r.setPlaceholder(s.getPlaceholder());
  533. r.setTips(s.getTips());
  534. r.setDotDisable(null != s.getDotDisable() && s.getDotDisable() > 0);
  535. r.setKeyboardMode(s.getKeyboardMode()); // number card car,默认number
  536. ruleList.add(r);
  537. }
  538. if(CollectionUtils.isEmpty(enrollScoreList)) {
  539. throw new RuntimeException("未定义考试规则" + StringUtils.join(cond.values(), ","));
  540. }
  541. String[] formulas = enrollScoreList.get(0).getEnrollFormula().split("\\+职业技能");
  542. if(formulas.length != 2) {
  543. throw new RuntimeException("错误定义考试规则" + enrollScoreList.get(0).getEnrollFormula());
  544. }
  545. List<VoluntaryDto.RenderRule> allRenderRuleList = Lists.newArrayList();
  546. allRenderRuleList.add(new VoluntaryDto.RenderRule("文化素质", formulas[0], cultureRuleList));
  547. allRenderRuleList.add(new VoluntaryDto.RenderRule("职业技能", "职业技能" + formulas[1], isScore ? null : skillRuleList));
  548. return allRenderRuleList;
  549. }
  550. private List<VoluntaryDto.AIRenderRule> findMatchRules(Map cond, boolean isAi, boolean isScore) {
  551. String examType = VistorContextHolder.getExamType().title(); // TODO MF
  552. String gender = "0".equals(SecurityUtils.getLoginUser().getUser().getSex()) ? "男生" : "女生";
  553. cond.put("examineeType", examType);
  554. List<AEnrollScore> enrollScoreList = aEnrollScoreMapper.selectListByRuleCond(cond);
  555. if (CollectionUtils.isEmpty(enrollScoreList) && cond.containsKey("majorGroup")) {
  556. cond.put("majorGroup", "");
  557. enrollScoreList = aEnrollScoreMapper.selectListByRuleCond(cond);
  558. }
  559. List<VoluntaryDto.AIRenderRule> ruleList = Lists.newArrayList();
  560. Set<String> existItemSet = Sets.newHashSet();
  561. String vt;
  562. VoluntaryDto.AIRenderRule scoreRateRule = null;
  563. for (AEnrollScore s : enrollScoreList) { // 跳过统计类和提示类的规则
  564. if (null == (vt = s.getValueType()) || vt.startsWith("Stat") || vt.equals("Notice")) {
  565. continue;
  566. } else if(isScore && !"学考".equals(s.getItemCategory()) && !"校考".equals(s.getItemCategory())) {
  567. continue;
  568. } else if (vt.equals("ScoreRate")) {
  569. if (!isAi) {
  570. vt = "Score";
  571. } else if (existItemSet.add("ScoreRate")) {
  572. scoreRateRule = new VoluntaryDto.AIRenderRule();
  573. scoreRateRule.setEnumRuleCategory(VoluntaryDto.EnumRuleCategory.Enroll);
  574. scoreRateRule.setFieldName("ScoreRate");
  575. scoreRateRule.setEnumInputType(VoluntaryDto.EnumInputType.Number);
  576. scoreRateRule.setMin(0);
  577. scoreRateRule.setMax(100);
  578. scoreRateRule.setLabel("技能测试得分率");
  579. scoreRateRule.setDescription("%");
  580. continue;
  581. } else {
  582. continue;
  583. }
  584. }
  585. if (!existItemSet.add(s.getItemField())) {
  586. continue;
  587. }
  588. VoluntaryDto.AIRenderRule r = new VoluntaryDto.AIRenderRule();
  589. r.setEnumRuleCategory(VoluntaryDto.EnumRuleCategory.Enroll);
  590. r.setFieldName(s.getItemField());
  591. setOptionValue(r, vt, s.getValueRule(), s.getValueOptional(), s.getCorrectType(), s.getCorrectValue(), s.getScoreTotal());
  592. r.setRegex(s.getRegex());
  593. r.setLabel(s.getItemName());
  594. r.setDescription(s.getDescription());
  595. r.setPlaceholder(s.getPlaceholder());
  596. r.setTips(s.getTips());
  597. r.setDefaultValue(s.getDefaultValue());
  598. r.setDotDisable(null != s.getDotDisable() && s.getDotDisable() > 0);
  599. r.setKeyboardMode(s.getKeyboardMode()); // number card car,默认number
  600. ruleList.add(r);
  601. }
  602. if (null != scoreRateRule) {
  603. ruleList.add(scoreRateRule);
  604. }
  605. if(isScore) {
  606. return ruleList;
  607. }
  608. List<AEnrollSpecial> enrollSpecialList = Lists.newArrayList();
  609. Map<String, AEnrollSpecial> mergeEnrollSpecialMap = Maps.newHashMap();
  610. List<AEnrollSpecial> oriErollSpecialList = aEnrollSpecialMapper.selectListByRuleCond(cond);
  611. for (AEnrollSpecial s : oriErollSpecialList) {
  612. if (VoluntaryDto.EnumRuleType.Readonly.name().equals(s.getItemType()) || StringUtils.isNotBlank(s.getGender()) && !s.getGender().equals(gender)) {
  613. continue;
  614. }
  615. if (null == s.getItemGroup() || !"Checkbox".equals(s.getValueType())) {
  616. enrollSpecialList.add(s);
  617. continue;
  618. }
  619. //
  620. String key = s.getItemGroup(); // s.getUniversityId() + "_" + s.getMajorName() + "_" + StringUtils.trimToEmpty(s.getMajorDirection()) + "_" + StringUtils.trimToEmpty(s.getGender()) + "_" + s.getItemCategory() + "_" +
  621. AEnrollSpecial exist = mergeEnrollSpecialMap.get(key);
  622. if (null == exist) {
  623. // 修正分组后的名称及字段名
  624. String[] groupNameField = StringUtils.split(s.getItemGroup(), "_");
  625. s.setValueOptional(s.getItemName());
  626. s.setItemName(groupNameField[0]);
  627. s.setItemField(groupNameField[groupNameField.length > 1 ? 1 : 0]);
  628. mergeEnrollSpecialMap.put(key, s);
  629. enrollSpecialList.add(s);
  630. continue;
  631. }
  632. if(StringUtils.isBlank(exist.getValueOptional()) || !exist.getValueOptional().contains(s.getItemName())) {
  633. exist.setValueOptional(exist.getValueOptional() + "," + s.getItemName());
  634. }
  635. }
  636. Map<String,String> mutexOptionMap = getMutexOptionMap();
  637. for (AEnrollSpecial s : enrollSpecialList) {
  638. if (null == (vt = s.getValueType()) || vt.startsWith("Stat") || vt.equals("Notice") || !existItemSet.add(s.getItemField())) {
  639. continue;
  640. }
  641. VoluntaryDto.AIRenderRule r = new VoluntaryDto.AIRenderRule();
  642. r.setEnumRuleCategory(VoluntaryDto.EnumRuleCategory.Special);
  643. r.setFieldName(s.getItemField());
  644. setOptionValue(r, s.getValueType(), s.getValueRule(), s.getValueOptional(), s.getCorrectType(), s.getCorrectValue(), null);
  645. if (VoluntaryDto.EnumInputType.Checkbox.equals(r.getEnumInputType())) {
  646. r.setMutexOption(mutexOptionMap.get(r.getFieldName()));
  647. }
  648. r.setRegex(s.getRegex());
  649. r.setLabel(s.getItemName());
  650. r.setDescription(s.getDescription());
  651. r.setPlaceholder(s.getPlaceholder());
  652. r.setTips(s.getTips());
  653. r.setDefaultValue(s.getDefaultValue());
  654. r.setDotDisable(null != s.getDotDisable() && s.getDotDisable() > 0);
  655. r.setKeyboardMode(s.getKeyboardMode()); // number card car,默认number
  656. ruleList.add(r);
  657. }
  658. return ruleList;
  659. }
  660. private Map<String, String> getMutexOptionMap() {
  661. String mutexOptionConf = sysConfigService.selectConfigByKey("voluntary.rule.mutexOption");
  662. Map<String, String> mutexOptionMap = Maps.newHashMap();
  663. if (StringUtils.isNotBlank(mutexOptionConf)) {
  664. try {
  665. JSONArray.parseArray(mutexOptionConf).forEach(l -> {
  666. JSONObject lo = (JSONObject) l;
  667. mutexOptionMap.put(lo.getString("n"), lo.getString("m"));
  668. });
  669. } catch (JSONException e) {
  670. }
  671. }
  672. return mutexOptionMap;
  673. }
  674. // TODO 同一专业号有多个专业方向
  675. private List<VoluntaryDto.AIResponse> findMajorSuggest(Integer planYear, Integer submitYear, Map cond, Map<String, String> paramMap, boolean isAi, boolean isScoreOnly) {
  676. String examType = VistorContextHolder.getExamType().title(); // TODO MF
  677. String gender = "0".equals(SecurityUtils.getLoginUser().getUser().getSex()) ? "男生" : "女生";
  678. cond.remove("year");
  679. cond.put("examineeType", examType);
  680. Map<Long, List<AMarjorPlan>> currUniversityMajorPlansMap = Maps.newHashMap();
  681. Map<Long, List<AMarjorPlan>> historyUniversityMajorPlansMap = Maps.newHashMap();
  682. List<Map<Long, List<AMarjorPlan>>> bothPlanList = Lists.newArrayList(currUniversityMajorPlansMap, historyUniversityMajorPlansMap);
  683. Set<String> existSet = Sets.newHashSet();
  684. for (AMarjorPlan mp : aMarjorPlanMapper.selectListByRuleCond(cond)) {
  685. String key = mp.getUniversityId() + mp.getMajorName() + StringUtils.trimToEmpty(mp.getMajorDirection()) + mp.getYear(); // TODO 考虑为什么会重的问题 examType ?
  686. if (!existSet.add(key)) {
  687. continue;
  688. }
  689. for(Map<Long, List<AMarjorPlan>> tmpMap : bothPlanList) {
  690. if (!mp.getYear().equals(planYear) && tmpMap == currUniversityMajorPlansMap) {
  691. continue;
  692. }
  693. List<AMarjorPlan> tmpMpList = tmpMap.get(mp.getUniversityId());
  694. if (null == tmpMpList) {
  695. tmpMpList = Lists.newArrayList(mp);
  696. tmpMap.put(mp.getUniversityId(), tmpMpList);
  697. } else {
  698. tmpMpList.add(mp);
  699. }
  700. }
  701. }
  702. Map<Long, List<BBusiWishUniversitiesProfession>> universityMajorsMap = Maps.newHashMap();
  703. // 有计划以计划为准的输出,无计划时则以所有专业输出为准
  704. Map<Long, BBusiWishUniversities> universitiesMap = null;
  705. if (MapUtils.isEmpty(currUniversityMajorPlansMap)) {
  706. Map<String, List<BBusiWishUniversitiesProfession>> tmpUniversityMajorsMap = bBusiWishUniversitiesProfessionMapper.selectListByRuleCond(cond).stream().collect(Collectors.groupingBy(BBusiWishUniversitiesProfession::getCollegeCode));
  707. if (MapUtils.isNotEmpty(tmpUniversityMajorsMap)) {
  708. Map uCond = Maps.newHashMap();
  709. uCond.put("codes", tmpUniversityMajorsMap.keySet());
  710. universitiesMap = Maps.newHashMap();
  711. for (BBusiWishUniversities u : bBusiWishUniversitiesMapper.selectBBusiWishUniversitiesListSimpleByMap(uCond)) {
  712. universitiesMap.put(u.getId(), u);
  713. universityMajorsMap.put(u.getId(), tmpUniversityMajorsMap.get(u.getCode()));
  714. }
  715. }
  716. } else {
  717. cond.put("universityIds", currUniversityMajorPlansMap.keySet());
  718. cond.put("examType", Constant.EXAM_TYPE_PG);
  719. Map<String, List<BBusiWishUniversitiesProfession>> tmpUniversityMajorsMap = bBusiWishUniversitiesProfessionMapper.selectListByRuleCond(cond).stream().collect(Collectors.groupingBy(BBusiWishUniversitiesProfession::getCollegeCode));
  720. cond.remove("universityIds");
  721. if (MapUtils.isNotEmpty(tmpUniversityMajorsMap)) {
  722. Map uCond = new HashMap();
  723. uCond.put("ids", currUniversityMajorPlansMap.keySet());
  724. universitiesMap = Maps.newHashMap();
  725. for (BBusiWishUniversities u : bBusiWishUniversitiesMapper.selectBBusiWishUniversitiesListSimpleByIds(uCond)) {
  726. universitiesMap.put(u.getId(), u);
  727. universityMajorsMap.put(u.getId(), tmpUniversityMajorsMap.get(u.getCode()));
  728. }
  729. }
  730. }
  731. // 无计划,也无院校专业
  732. if(MapUtils.isEmpty(universitiesMap)) {
  733. return Lists.newArrayList();
  734. }
  735. // 查询涉及的规则
  736. cond.put("year", planYear);
  737. cond.put("universityIds", universitiesMap.keySet());
  738. Map<Long, List<AEnrollScore>> universityScoreListMap = aEnrollScoreMapper.selectListByRuleCond(cond).stream().collect(Collectors.groupingBy(AEnrollScore::getUniversityId));
  739. Map<Long, List<AEnrollSpecial>> universitySpecialListMap = aEnrollSpecialMapper.selectListByRuleCond(cond).stream().collect(Collectors.groupingBy(AEnrollSpecial::getUniversityId));
  740. cond.remove("universityIds");
  741. cond.remove("year");
  742. Map<String, String> mutexOptionMap = getMutexOptionMap();
  743. List<VoluntaryDto.AIResponse> aiRespList = Lists.newArrayList();
  744. for (Long universityId : universitiesMap.keySet()) {
  745. List<AEnrollScore> scoreList = universityScoreListMap.get(universityId); // 分数条件
  746. List<AEnrollSpecial> specialList = universitySpecialListMap.get(universityId);// 专项条件
  747. List<AMarjorPlan> currPlanList = currUniversityMajorPlansMap.get(universityId);// 当年计划
  748. List<AMarjorPlan> historyPlanList = historyUniversityMajorPlansMap.get(universityId);// 历年计划
  749. BBusiWishUniversities u = universitiesMap.get(universityId);// 院校
  750. List<BBusiWishUniversitiesProfession> professionList = universityMajorsMap.get(u.getId()); // 所有专业
  751. // 院校变更标志
  752. AEnrollUniversity euCond = new AEnrollUniversity();
  753. euCond.setUniversityId(u.getId());
  754. euCond.setYear(planYear);
  755. List<AEnrollUniversity> enrollUniversityList = aEnrollUniversityMapper.selectAEnrollUniversityList(euCond);
  756. // 院校历史情况
  757. AMarjorSubmit submitCond = new AMarjorSubmit();
  758. submitCond.setExamineeType(examType);
  759. submitCond.setUniversityId(universityId);
  760. List<AMarjorSubmit> submitList = aMarjorSubmitMapper.selectAMarjorSubmitList(submitCond);
  761. VoluntaryDto.AIResponse aiResp = new VoluntaryDto.AIResponse();
  762. aiResp.setUniversity(u);
  763. VoluntaryDto.SingleResponse sr;
  764. List<VoluntaryDto.SingleResponse> singleResponseList = Lists.newArrayList();
  765. if (CollectionUtils.isNotEmpty(currPlanList)) {
  766. aiResp.setEnrollCode(currPlanList.get(0).getEnrollCode());
  767. Map<String, BBusiWishUniversitiesProfession> professionMap = null == professionList ? Maps.newHashMap() : professionList.stream().collect(Collectors.toMap(BBusiWishUniversitiesProfession::getName, Function.identity()));
  768. for (AMarjorPlan mp : currPlanList) {
  769. if (null != (sr = buildSingleResponse(submitYear, planYear, gender, mp, professionMap.get(mp.getMajorName()), enrollUniversityList, paramMap, u,
  770. historyPlanList, submitList, scoreList, specialList, mutexOptionMap, isAi, isScoreOnly))) {
  771. singleResponseList.add(sr);
  772. }
  773. }
  774. } else {
  775. for (BBusiWishUniversitiesProfession prof : professionList) {
  776. if (null != (sr = buildSingleResponse(submitYear, planYear, gender, null, prof, enrollUniversityList, paramMap, u,
  777. historyPlanList, submitList, scoreList, specialList, mutexOptionMap, isAi, isScoreOnly))) {
  778. singleResponseList.add(sr);
  779. }
  780. }
  781. }
  782. aiResp.setMajorDetails(singleResponseList);
  783. sortAndExtractEnroll(singleResponseList, aiResp);
  784. aiRespList.add(aiResp);
  785. }
  786. Collections.sort(aiRespList, new Comparator<VoluntaryDto.AIResponse>() {
  787. @Override
  788. public int compare(VoluntaryDto.AIResponse o1, VoluntaryDto.AIResponse o2) {
  789. Integer d1 = o1.getEnrollRate();
  790. Integer d2 = o2.getEnrollRate();
  791. d1 = null == d1 ? 999 : (d1 == 0 ? 998 : d1);
  792. d2 = null == d2 ? 999 : (d2 == 0 ? 998 : d2);
  793. return d1.compareTo(d2);
  794. }
  795. });
  796. return aiRespList;
  797. }
  798. private VoluntaryDto.SingleResponse buildSingleResponse(Integer submitYear, Integer planYear, String gender, AMarjorPlan currPlan, BBusiWishUniversitiesProfession prof,
  799. List<AEnrollUniversity> enrollUniversityList, Map<String, String> paramMap, BBusiWishUniversities u,
  800. List<AMarjorPlan> historyPlanList, List<AMarjorSubmit> submitList,
  801. List<AEnrollScore> scoreList, List<AEnrollSpecial> specialList, Map<String,String> mutexOptionMap, boolean isAi, boolean isScoreOnly) {
  802. if (null != submitList) {
  803. Collections.sort(submitList, new Comparator<AMarjorSubmit>() {
  804. @Override
  805. public int compare(AMarjorSubmit o1, AMarjorSubmit o2) {
  806. int iRet;
  807. if (0 != (iRet = o1.getYear().compareTo(o2.getYear()))) {
  808. return -iRet;
  809. }
  810. if (0 != (iRet = o1.getMajorName().compareTo(o2.getMajorName()))) {
  811. return -iRet;
  812. }
  813. if (null == o1.getMajorDirection()) {
  814. if (null != o2.getMajorDirection()) {
  815. return 1;
  816. }
  817. return 0;
  818. } else if (null == o2.getMajorDirection()) {
  819. return -1;
  820. }
  821. return 0;
  822. }
  823. });
  824. } else {
  825. submitList = Lists.newArrayList();
  826. }
  827. if (null != historyPlanList) {
  828. Collections.sort(historyPlanList, new Comparator<AMarjorPlan>() {
  829. @Override
  830. public int compare(AMarjorPlan o1, AMarjorPlan o2) {
  831. int iRet;
  832. if (0 != (iRet = o1.getYear().compareTo(o2.getYear()))) {
  833. return -iRet;
  834. }
  835. if (0 != (iRet = o1.getMajorName().compareTo(o2.getMajorName()))) {
  836. return -iRet;
  837. }
  838. if (null == o1.getMajorDirection()) {
  839. if (null != o2.getMajorDirection()) {
  840. return 1;
  841. }
  842. return 0;
  843. } else if (null == o2.getMajorDirection()) {
  844. return -1;
  845. }
  846. return o1.getMajorDirection().compareTo(o2.getMajorDirection());
  847. }
  848. });
  849. } else {
  850. historyPlanList = Lists.newArrayList();
  851. }
  852. // 录取线
  853. List<VoluntaryDto.MajorClearingHistory> clearings = Lists.newArrayList(); // 补录情况
  854. List<VoluntaryDto.MajorEnrollHistory> histories = Lists.newArrayList(); // 初录情况
  855. List<VoluntaryDto.MajorEnrollRule> ruleMatchList = Lists.newArrayList();
  856. List<VoluntaryDto.MajorEnrollRule> improveList = Lists.newArrayList();
  857. Double tmpValue; // 总分,得分
  858. AMarjorSubmit lastSubmit = null;
  859. Boolean typeChange = false;
  860. VoluntaryDto.FormulaScoreStat formulaScoreStat = new VoluntaryDto.FormulaScoreStat();
  861. String needGroup = StringUtils.trimToEmpty(null != currPlan && null != currPlan.getMajorGroup() ? currPlan.getMajorGroup() : "");
  862. String needMajor = StringUtils.trimToEmpty(null != currPlan ? currPlan.getMajorName() : (null != prof ? prof.getName() : ""));
  863. String needDirect = StringUtils.trimToEmpty(null != currPlan ? currPlan.getMajorDirection() : "");
  864. String needMajorDirect = needMajor + needDirect;
  865. // 判断是否政策变化情况
  866. List<AEnrollUniversity> validEuList = enrollUniversityList.stream()
  867. .filter(t -> needGroup.equals(StringUtils.trimToEmpty(t.getMajorGroups())) && t.getMajorNames().contains(needMajor))
  868. .collect(Collectors.toList());
  869. typeChange = CollectionUtils.isNotEmpty(validEuList) && new Integer(1).equals(validEuList.get(0).getTypeChange());
  870. Set<String> existSet = Sets.newHashSet();
  871. existSet.clear();
  872. List<AMarjorSubmit> validSubmitList = Lists.newArrayList();
  873. if (null != submitList) {
  874. for (AMarjorSubmit s : submitList) { // 历年录取通过专业分来判断差别
  875. String majorNameDirect = s.getMajorName() + StringUtils.trimToEmpty(s.getMajorDirection());
  876. if (needMajorDirect.equals(majorNameDirect) && existSet.add(needMajorDirect + s.getYear() + s.getEnrollType())) {
  877. validSubmitList.add(s);
  878. if (s.getYear().equals(submitYear) && s.getEnrollType().equals("初录") ) {
  879. lastSubmit = s; // TODO 初录,补录与分数线的关系 要处理
  880. }
  881. }
  882. }
  883. }
  884. // 分项规则检查
  885. existSet.clear();
  886. Double currTotal = null;
  887. if (null != scoreList) {
  888. Double inputScoreRate = NumberUtils.toInt(paramMap.get("ScoreRate"), 0) / 100.0;
  889. List<AEnrollScore> fEnrollScoreList = Lists.newArrayList();
  890. String inclMajorDirection = needMajor + "(" + needDirect + ")";
  891. String exclMajorDirection = needMajor + "(";
  892. Map<Boolean, List<AEnrollScore>> majorEnrollScoresMap = scoreList.stream()
  893. .filter(t -> needGroup.equals(StringUtils.trimToEmpty(t.getMajorGroups())))
  894. .collect(Collectors.groupingBy(t -> StringUtils.isNotBlank(t.getMajorNames())));
  895. if(majorEnrollScoresMap.isEmpty() && StringUtils.isNotBlank(needGroup)) {
  896. majorEnrollScoresMap = scoreList.stream()
  897. .filter(t -> StringUtils.isBlank(t.getMajorGroups()))
  898. .collect(Collectors.groupingBy(t -> StringUtils.isNotBlank(t.getMajorNames())));
  899. }
  900. List<AEnrollScore> tmpEnrollScoreList = majorEnrollScoresMap.get(Boolean.TRUE);
  901. AEnrollScore skillEnrollScore = null;
  902. if (null != tmpEnrollScoreList) {
  903. for (AEnrollScore r : tmpEnrollScoreList) {
  904. if (StringUtils.isNotBlank(r.getMajorNames())) {
  905. if (!r.getMajorNames().contains(needMajor)) {
  906. continue;
  907. }
  908. if (StringUtils.isNotBlank(r.getMajorDirections())) { // 有单独的方向时,分开判断
  909. if (StringUtils.isBlank(needDirect) || !r.getMajorDirections().contains(needDirect)) {
  910. continue;
  911. }
  912. } else if (StringUtils.isNotBlank(needDirect)) { // 有direct要求时,这里需要有 "<专业>(<方向>)
  913. if (!r.getMajorNames().contains(inclMajorDirection)) {
  914. continue;
  915. }
  916. } else if (r.getMajorNames().contains(exclMajorDirection)) { // 当无direct要求时,这时不能有 "<专业>("
  917. continue;
  918. }
  919. }
  920. Boolean isSkillScore = isScoreOnly && r.getItemType().equals("ScoreSkill");
  921. if(isSkillScore) {
  922. skillEnrollScore = r;
  923. }
  924. appendScoreRule(formulaScoreStat, existSet, r, fEnrollScoreList, isAi, paramMap, inputScoreRate, isSkillScore);
  925. }
  926. }
  927. if (fEnrollScoreList.size() == 0 && null != (tmpEnrollScoreList = majorEnrollScoresMap.get(Boolean.FALSE))) {
  928. for (AEnrollScore r : tmpEnrollScoreList) {
  929. Boolean isSkillScore = isScoreOnly && r.getItemType().equals("ScoreSkill");
  930. if(isSkillScore) {
  931. skillEnrollScore = r;
  932. }
  933. appendScoreRule(formulaScoreStat, existSet, r, fEnrollScoreList, isAi, paramMap, inputScoreRate, isSkillScore);
  934. }
  935. }
  936. boolean isSameYear = null == lastSubmit || planYear.equals(lastSubmit.getYear());
  937. currTotal = formulaScoreStat.getTypeValue("StatRateScore", "", false);
  938. for (AEnrollScore r : fEnrollScoreList) {
  939. VoluntaryDto.MajorEnrollRule mr = buildEnrollRule(r);
  940. mr.setContent(StringUtils.isNotBlank(r.getEqualFormula()) ? r.getEqualFormula() : r.getEnrollFormula());
  941. if(isScoreOnly) {
  942. String vt;
  943. if (null != (vt = r.getValueType()) && vt.startsWith("Score")) {
  944. improveList.add(mr);
  945. mr.setCategory(VoluntaryDto.EnumRuleCategory.Enroll);
  946. mr.setType(VoluntaryDto.EnumRuleType.ScoreTotal);
  947. // mr.setValue(null != currTotal ? String.valueOf(currTotal.intValue()) : "");
  948. if (null == lastSubmit || null == lastSubmit.getScore() || null == lastSubmit.getScoreTotal() && !isSameYear) {
  949. mr.setFailedMessage("缺历史录取数据");
  950. continue;
  951. }
  952. mr.setYear(lastSubmit.getYear());
  953. if (typeChange) {
  954. mr.setFailedMessage("规则变更,无法计算");
  955. continue;
  956. } else if (!formulaScoreStat.isScoreValid() && (!isAi || inputScoreRate <= 0.0)) {
  957. mr.setFailedMessage("用户没有填写完整");
  958. continue;
  959. }
  960. Integer validScoreTotal = isSameYear ? formulaScoreStat.getAllTotal() : lastSubmit.getScoreTotal();
  961. Double currScoreRate = isSameYear ? 1.0 : formulaScoreStat.getAllTotal() * 1.0 / lastSubmit.getScoreTotal(); // 去年的分转成今年的分
  962. EnrollRateCalculator.RateLevel rl;
  963. if (null != lastSubmit.getScore() && currTotal != null && null != (rl = enrollRateCalculator.satisfy(validScoreTotal, lastSubmit.getScore(), currTotal / currScoreRate))) { // 按去年标准算概率
  964. Double skillRate = Double.parseDouble(skillEnrollScore.getValueRule());
  965. mr.setValue(String.valueOf(Math.round((lastSubmit.getScore() * currScoreRate - currTotal) * 10 / skillRate) / 10.0));
  966. mr.setValid(true);
  967. } else {
  968. mr.setFailedMessage("没有对应计算条件");
  969. continue;
  970. }
  971. } else {
  972. ruleMatchList.add(mr);
  973. mr.setValid(true);
  974. }
  975. continue;
  976. }
  977. ruleMatchList.add(mr);
  978. String vt;
  979. if (null == (vt = r.getValueType())) { // 无值时相当于直接通过
  980. mr.setValid(true);
  981. } else if (null != (vt = r.getValueType()) && vt.startsWith("Score")) {
  982. mr.setValue(null != currTotal ? String.valueOf(currTotal.intValue()) : "");
  983. if (null == lastSubmit || null == lastSubmit.getScore() || null == lastSubmit.getScoreTotal() && !isSameYear) {
  984. mr.setFailedMessage("缺历史录取数据");
  985. continue;
  986. } else if (typeChange) {
  987. mr.setFailedMessage("规则变更,无法计算");
  988. continue;
  989. } else if (!formulaScoreStat.isValid() && (!isAi || inputScoreRate <= 0.0)) {
  990. mr.setFailedMessage("用户没有填写完整");
  991. continue;
  992. }
  993. mr.setValid(true);
  994. Integer validScoreTotal = isSameYear ? formulaScoreStat.getAllTotal() : lastSubmit.getScoreTotal();
  995. Double currScoreRate = isSameYear ? 1.0 : formulaScoreStat.getAllTotal() * 1.0 / lastSubmit.getScoreTotal(); // 去年的分转成今年的分
  996. Double currScore = null;
  997. if (null != lastSubmit.getCulturalScore()) {
  998. if (null == (currScore = formulaScoreStat.getTypeValue("ScoreSingle", "", false))) {
  999. currScore = formulaScoreStat.getTypeValue("ScoreBase", "", false);
  1000. }
  1001. if (null != currScore && currScore < lastSubmit.getCulturalScore() * currScoreRate) {
  1002. // mr.setValid(false);
  1003. mr.setMissingValue(String.valueOf(Math.round(lastSubmit.getCulturalScore() * currScoreRate - currScore)));
  1004. mr.setFailedMessage("校考分低于分数线");
  1005. }
  1006. }
  1007. if (null != lastSubmit.getProfScore() && null != (currScore = formulaScoreStat.getTypeValue("ScoreSkill", "", false)) && currScore < lastSubmit.getProfScore() * currScoreRate) {
  1008. // mr.setValid(false);
  1009. mr.setMissingValue(String.valueOf(Math.round(lastSubmit.getProfScore() * currScoreRate - currScore)));
  1010. mr.setFailedMessage("技能测试分低于分数线");
  1011. }
  1012. // 检查总分,学考(文化),专业(技能)
  1013. EnrollRateCalculator.RateLevel rl;
  1014. if (null != lastSubmit.getScore() && currTotal != null && null != (rl = enrollRateCalculator.calSchoolEnrollRate(validScoreTotal, lastSubmit.getScore(), currTotal / currScoreRate))) { // 按去年标准算概率
  1015. mr.setRl(rl);
  1016. mr.setEnrollRate(rl.rate);
  1017. mr.setEnrollRateText(rl.typeLabel);
  1018. mr.setEnumPickType(rl.type);
  1019. if (mr.getValid() && currTotal < lastSubmit.getScore() * currScoreRate) {
  1020. // mr.setValid(false);
  1021. mr.setMissingValue(String.valueOf(Math.round(lastSubmit.getScore() * currScoreRate - currTotal))); // 按今年的算差值
  1022. mr.setFailedMessage("综合分低于分数线");
  1023. }
  1024. }
  1025. } else { // 专项符合型
  1026. mr.setValid(processPassCheck(paramMap, formulaScoreStat, r.getValueRule(), mr, r.getValueType(), r.getItemField(), r.getValuePassRule()));
  1027. }
  1028. }
  1029. }
  1030. if (null != specialList) {
  1031. existSet.clear();
  1032. List<AEnrollSpecial> validSpecialList = Lists.newArrayList();
  1033. Map<String, Pair<String, Set<String>>> groupMutexOptionsMap = Maps.newHashMap();
  1034. for (AEnrollSpecial r : specialList) {
  1035. if (StringUtils.isNotBlank(r.getGender()) && !r.getGender().equals(gender)
  1036. || StringUtils.isNotBlank(r.getMajorName()) && !Sets.newHashSet(r.getMajorName().split(",")).contains(needMajor)
  1037. || StringUtils.isNotBlank(r.getMajorDirection()) && !r.getMajorDirection().equals(needDirect)) {
  1038. continue;
  1039. }
  1040. if(r.getValueType().startsWith("StatBMI")) { // TODO 身高体重的名称需要是固定的
  1041. String height = paramMap.get("身高");
  1042. String weight = paramMap.get("体重");
  1043. Integer iHeight;
  1044. if (StringUtils.isNotBlank(height) && StringUtils.isNotBlank(weight) && (iHeight = NumberUtils.toInt(height, 0)) > 0) {
  1045. paramMap.put(r.getItemField(), String.valueOf(NumberUtils.toInt(height, 0) * 100 / iHeight));
  1046. }
  1047. } else if (null != r.getItemGroup() && "Checkbox".equals(r.getValueType())) {
  1048. Pair<String, Set<String>> p = getGroupOptions(groupMutexOptionsMap, mutexOptionMap, paramMap, r.getItemGroup());
  1049. if (p.getRight().size() == 0) { // 无值时
  1050. paramMap.put(r.getItemField(), null);
  1051. } else if (StringUtils.isNotBlank(p.getLeft()) && p.getRight().contains(p.getLeft())) { // 选中互斥时全是否
  1052. paramMap.put(r.getItemField(), !p.getLeft().contains("无") ? "[\"是\"]" : "[\"否\"]");
  1053. } else {
  1054. paramMap.put(r.getItemField(), p.getRight().contains(r.getItemName()) ? "[\"是\"]" : "[\"否\"]");
  1055. }
  1056. }
  1057. validSpecialList.add(r);
  1058. }
  1059. for (AEnrollSpecial r : validSpecialList) {
  1060. VoluntaryDto.MajorEnrollRule mr = new VoluntaryDto.MajorEnrollRule();
  1061. mr.setCategory(VoluntaryDto.EnumRuleCategory.Special);
  1062. mr.setContent(r.getEnrollFormula());
  1063. mr.setDescription(r.getComment());
  1064. ruleMatchList.add(mr);
  1065. if(isScoreOnly) {
  1066. mr.setType(VoluntaryDto.EnumRuleType.Readonly);
  1067. mr.setValid(true);
  1068. continue;
  1069. }
  1070. mr.setType(itemType2RuleType(r.getItemType(), r.getValueType(), false));
  1071. if (VoluntaryDto.EnumRuleType.Readonly.equals(mr.getType())) {
  1072. mr.setValid(true);
  1073. } else {
  1074. mr.setValid(processPassCheck(paramMap, formulaScoreStat, r.getValueRule(), mr, r.getValueType(), r.getItemField(), r.getValuePassRule()));
  1075. }
  1076. }
  1077. }
  1078. existSet.clear();
  1079. Map<String, AMarjorPlan> historyPlanMap = historyPlanList.stream().collect(Collectors.toMap(t -> t.getYear() + t.getMajorName() + StringUtils.trimToEmpty(t.getMajorDirection()), Function.identity()));
  1080. for (AMarjorSubmit s : validSubmitList) {
  1081. if ("初录".equals(s.getEnrollType())) {
  1082. VoluntaryDto.MajorEnrollHistory h = new VoluntaryDto.MajorEnrollHistory();
  1083. h.setYear(s.getYear());
  1084. h.setScore(null != s.getScore() ? String.valueOf(s.getScore()) : ""); // TODO 240301 直接输出录取分
  1085. /*if (null != currTotal && null != s.getScore()) {
  1086. Double diff = currTotal - s.getScore();
  1087. h.setScore(diff > 0 ? "+" + diff.intValue() : "" + diff.intValue()); // TODO 需要一个分来比较,综合分?
  1088. } else {
  1089. h.setScore("");
  1090. }*/
  1091. AMarjorPlan p = historyPlanMap.get(s.getYear() + s.getMajorName() + StringUtils.trimToEmpty(s.getMajorDirection()));
  1092. if(null != p) {
  1093. h.setPlan(p.getPlanTotal()); // TODO 估计输出录取人数 23.12.26 分开输入录取和计划 24.12.27
  1094. } else {
  1095. // System.out.println(s.getId());
  1096. }
  1097. h.setEnroll(s.getEnrollTotal());
  1098. histories.add(h);
  1099. } else {
  1100. /*VoluntaryDto.MajorClearingHistory c = new VoluntaryDto.MajorClearingHistory();
  1101. c.setYear(s.getYear());
  1102. if (null != currTotal && null != s.getScore()) {
  1103. Double diff = currTotal - s.getScore();
  1104. c.setScore(diff > 0 ? "+" + diff.intValue() : "" + diff.intValue()); // TODO 需要一个分来比较,综合分?
  1105. } else {
  1106. c.setScore("");
  1107. }
  1108. c.setRealNum(s.getEnrollTotal());
  1109. clearings.add(c);*/ // TODO 240301 关闭补录
  1110. }
  1111. }
  1112. VoluntaryDto.SingleResponse sr = new VoluntaryDto.SingleResponse();
  1113. sr.setUniversityCode(u.getCode());
  1114. sr.setMajorCode(null != prof ? prof.getCode() : "");
  1115. sr.setMajorName(needMajor);
  1116. sr.setMajorDirection(needDirect);
  1117. // 查找最高的专业 EnrollRule 为本专业的,理论上只有一个合并rule有此值
  1118. EnrollRateCalculator.RateLevel lastRl = null;
  1119. boolean specialValid = true, specialPass = true;
  1120. for (VoluntaryDto.MajorEnrollRule er : ruleMatchList) {
  1121. if (null != er.getRl() && (null == lastRl || er.getRl().getRate() < lastRl.getRate())) {
  1122. lastRl = er.getRl();
  1123. }
  1124. if ((specialPass || specialValid) && VoluntaryDto.EnumRuleType.Special.equals(er.getType())) {
  1125. if (null == er.getValid()) {
  1126. specialValid = false;
  1127. } else if (!er.getValid()) {
  1128. specialPass = false;
  1129. }
  1130. }
  1131. }
  1132. if (!specialPass) {
  1133. sr.setEnrollRate(0);
  1134. sr.setEnrollRateText("零概率");
  1135. sr.setEnumPickEmpty(VoluntaryDto.EnumPickEmpty.EnrollPass);
  1136. } else if (null != lastRl && specialValid) {
  1137. sr.setEnumPickType(lastRl.getType());
  1138. sr.setEnrollRate(lastRl.getRate());
  1139. sr.setEnrollRateText(lastRl.getTypeLabel());
  1140. } else {
  1141. sr.setEnrollRateText("无概率");
  1142. sr.setEnumPickEmpty(VoluntaryDto.EnumPickEmpty.New);
  1143. }
  1144. if (null != currPlan) {
  1145. sr.setMajorGroup(currPlan.getMajorGroup()); // 没有MajorEnrollId, 暂时用这个
  1146. sr.setMajorEnrollCode(StringUtils.isBlank(currPlan.getMajorEnrollCode()) ? String.valueOf(currPlan.getId()) : currPlan.getMajorEnrollCode());
  1147. sr.setTips(null != currPlan ? currPlan.getComment() : "");
  1148. }
  1149. sr.setHistories(histories);
  1150. sr.setClearings(clearings);
  1151. sr.setRules(ruleMatchList);
  1152. sr.setImproves(improveList);
  1153. sr.setScore(currTotal);
  1154. if (!isScoreOnly && null != lastSubmit && null != lastSubmit.getScore() && null != currTotal && currTotal < lastSubmit.getScore()) {
  1155. Double diffValue = lastSubmit.getScore() - currTotal;
  1156. sr.setImproves(formulaScoreStat.getImproveScore(diffValue));
  1157. }
  1158. return sr;
  1159. }
  1160. private void appendScoreRule(VoluntaryDto.FormulaScoreStat formulaScoreStat, Set<String> existSet, AEnrollScore r, List<AEnrollScore> fEnrollScoreList,
  1161. Boolean isAi, Map<String, String> paramMap, Double inputScoreRate, Boolean isSkillScore) {
  1162. String vt, iv;
  1163. Double currScore = null;
  1164. Double scoreRate = null;
  1165. Double tmpValue; // 总分,得分
  1166. if (null != (vt = r.getValueType()) && vt.startsWith("Score")) { //需要合并Score型(ScoreSingle, ScoreBase, ScoreSkill)的各类成绩, 其他为符合条件
  1167. if (existSet.add(r.getEnrollFormula())) { // 合并规则只留第一个
  1168. if (!existSet.add("_ScoreFormula_")) {
  1169. existSet.remove(r.getEnrollFormula());
  1170. return;
  1171. }
  1172. fEnrollScoreList.add(r);
  1173. }
  1174. if (null != r.getValueRule() && (scoreRate = Double.parseDouble(r.getValueRule())) <= 0.0) {
  1175. scoreRate = 1.0;
  1176. }
  1177. formulaScoreStat.addTypeTotal(r.getScoreTotal());
  1178. if (isAi && vt.equals("ScoreRate")) { // 根据得分率及总分计算分值
  1179. currScore = isSkillScore ? 0.0 : r.getScoreTotal() * inputScoreRate;
  1180. formulaScoreStat.addGroup(r.getItemGroup(), currScore, r.getScoreTotal().doubleValue(), scoreRate);
  1181. formulaScoreStat.addType(r.getItemType(), r.getItemField(), currScore, scoreRate);
  1182. } else {
  1183. currScore = (!isSkillScore && StringUtils.isNotBlank((iv = paramMap.get(r.getItemField())))) ? NumberUtils.toDouble(iv, 0.0) : 0.0;
  1184. formulaScoreStat.addGroup(r.getItemGroup(), currScore, r.getScoreTotal().doubleValue(), scoreRate);
  1185. formulaScoreStat.addType(r.getItemType(), r.getItemField(), currScore, scoreRate);
  1186. }
  1187. } else {
  1188. fEnrollScoreList.add(r);
  1189. }
  1190. }
  1191. private VoluntaryDto.MajorEnrollRule buildEnrollRule(AEnrollScore r) {
  1192. VoluntaryDto.MajorEnrollRule mr = new VoluntaryDto.MajorEnrollRule();
  1193. mr.setCategory(VoluntaryDto.EnumRuleCategory.Enroll);
  1194. mr.setType(itemType2RuleType(r.getItemType(), r.getValueType(), true)); // 学考 ScoreSingle 强转为 ScoreTotal, ScoreBase 校考, ScoreSkill 技能, Special 专项
  1195. mr.setContent(r.getEnrollFormula());
  1196. mr.setImproveType(r.getItemCategory());
  1197. mr.setDescription(r.getComment());
  1198. return mr;
  1199. }
  1200. private Pair<String, Set<String>> getGroupOptions(Map<String, Pair<String, Set<String>>> groupOptionsMap, Map<String, String> mutexOptionMap, Map<String, String> paramMap, String itemGroup) {
  1201. String[] groupNameField = StringUtils.split(itemGroup, "_");
  1202. String groupFieldName = groupNameField[groupNameField.length > 1 ? 1 : 0];
  1203. Pair<String, Set<String>> pair = groupOptionsMap.get(groupFieldName);
  1204. if(null == pair) {
  1205. String iv = paramMap.get(groupFieldName);
  1206. Set<String> options = StringUtils.isNotBlank(iv) ? JSONArray.parseArray(iv).stream().map(t -> (String) t).collect(Collectors.toSet()) : Sets.newHashSet();
  1207. pair = new MutablePair<>(mutexOptionMap.get(groupFieldName), options);
  1208. groupOptionsMap.put(groupFieldName, pair);
  1209. }
  1210. return pair;
  1211. }
  1212. private Boolean processPassCheck(Map<String, String> paramMap, VoluntaryDto.FormulaScoreStat stat, String valueRule,
  1213. VoluntaryDto.MajorEnrollRule mr, String valueType, String itemField, String passRule) {
  1214. Boolean matched = null;
  1215. Double tmpValue;
  1216. boolean isStat = null != valueType && valueType.startsWith("Stat");
  1217. if (isStat || NumberTypeSet.contains(valueType)) {
  1218. Double v = null;
  1219. String iv;
  1220. if (isStat) { // TODO 统计分
  1221. v = stat.getTypeValue(valueType, itemField, "0".equals(valueRule));
  1222. } else if(StringUtils.isNotBlank(passRule) && StringUtils.isNotBlank((iv = paramMap.get(itemField)))
  1223. && (tmpValue = NumberUtils.toDouble(iv, 0.0)) > 0.01) {
  1224. v = tmpValue;
  1225. }
  1226. if (v != null) {
  1227. String[] range = passRule.split("-");
  1228. if (StringUtils.isNotBlank(range[0]) && (tmpValue = NumberUtils.toDouble(range[0], 0.0)) > 0.01 && v < tmpValue) {
  1229. matched = false;
  1230. mr.setFailedMessage("小于最大值");
  1231. } else if (range.length > 1 && StringUtils.isNotBlank(range[1]) && (tmpValue = NumberUtils.toDouble(range[1], 0.0)) > 0.01 && v > tmpValue) {
  1232. matched = false;
  1233. mr.setFailedMessage("超过最大值");
  1234. } else {
  1235. matched = true;
  1236. }
  1237. } else {
  1238. mr.setFailedMessage("未输入参数");
  1239. }
  1240. } else if ("Radio".equals(valueType)) {
  1241. String iv = paramMap.get(itemField);
  1242. if (StringUtils.isNotBlank(iv)) {
  1243. if (!(matched = StringUtils.isNotBlank(passRule) && passRule.contains(iv))) {
  1244. mr.setFailedMessage("条件不满足");
  1245. }
  1246. } else {
  1247. mr.setFailedMessage("未输入参数");
  1248. }
  1249. } else if ("Checkbox".equals(valueType) || "Picker".equals(valueType)) {
  1250. String iv = paramMap.get(itemField);
  1251. if(StringUtils.isBlank(passRule)) {
  1252. if (!(matched = StringUtils.isBlank(iv))) {
  1253. mr.setFailedMessage("选择条件不满足1");
  1254. }
  1255. } else if (StringUtils.isNotBlank(iv)) {
  1256. List<String> valueList = Arrays.asList(passRule.split(","));
  1257. List<String> inputList = JSONArray.parseArray(iv).stream().map(t -> (String) t).collect(Collectors.toList());
  1258. if (!(matched = CollectionUtils.intersection(valueList, inputList).size() == valueList.size())) {
  1259. mr.setFailedMessage("选择条件不满足2");
  1260. }
  1261. }
  1262. }
  1263. return matched;
  1264. }
  1265. private void sortAndExtractEnroll(List<VoluntaryDto.SingleResponse> singleResponseList, VoluntaryDto.AIResponse aiResp) {
  1266. if (CollectionUtils.isEmpty(singleResponseList)) {
  1267. aiResp.setEnrollRate(null);
  1268. aiResp.setEnrollRateText("无概率");
  1269. aiResp.setEnumPickEmpty(VoluntaryDto.EnumPickEmpty.EnrollPass);
  1270. }
  1271. Collections.sort(singleResponseList, new Comparator<VoluntaryDto.SingleResponse>() {
  1272. @Override
  1273. public int compare(VoluntaryDto.SingleResponse o1, VoluntaryDto.SingleResponse o2) {
  1274. Integer d1 = o1.getEnrollRate();
  1275. Integer d2 = o2.getEnrollRate();
  1276. if (null == d1) {
  1277. if (null != d2) {
  1278. return 1;
  1279. }
  1280. return 0;
  1281. } else if (null == d2) {
  1282. return -1;
  1283. }
  1284. return -d1.compareTo(d2);
  1285. }
  1286. });
  1287. for (VoluntaryDto.SingleResponse sr : singleResponseList) {
  1288. aiResp.setEnrollRate(sr.getEnrollRate());
  1289. aiResp.setEnrollRateText(sr.getEnrollRateText());
  1290. aiResp.setEnumPickType(sr.getEnumPickType());
  1291. aiResp.setEnumPickEmpty(sr.getEnumPickEmpty());
  1292. break;
  1293. }
  1294. }
  1295. public R<VoluntaryDto.VoluntaryConfig> getVoluntaryConfig() { // 如果有填报配置相关,放在这里
  1296. VoluntaryDto.VoluntaryConfig resp = new VoluntaryDto.VoluntaryConfig();
  1297. return R.ok(resp);
  1298. }
  1299. public List<JSONObject> getVoluntaryList(@ApiParam @RequestParam VoluntaryDto.EnumVoluntaryType type) { // 我的志愿表 // 后台填充快照缺省
  1300. AWishRecord cond = new AWishRecord();
  1301. cond.setUserId(SecurityUtils.getLoginUser().getUserId());
  1302. if (null != type) {
  1303. cond.setType(type.name());
  1304. }
  1305. cond.setStatus(1);
  1306. List<AWishRecord> aWishRecordList = aWishRecordMapper.selectAWishRecordList(cond);
  1307. List<JSONObject> dtoList = Lists.newArrayList();
  1308. aWishRecordList.stream().forEach(t -> {
  1309. dtoList.add(toModel(t));
  1310. });
  1311. return PageUtil.getDtoListWithPageable(aWishRecordList, dtoList);
  1312. }
  1313. public R<Long> submitVoluntary(JSONObject model) { // 填报 // 前端+后台按需要剔除一些不需快照的信息(目前主要是院校信息)
  1314. SysUser user = SecurityUtils.getLoginUser().getUser();
  1315. AWishRecord wishRecord = new AWishRecord();
  1316. VoluntaryDto.User userSnapshot = new VoluntaryDto.User();
  1317. userSnapshot.setName(user.getNickName());
  1318. userSnapshot.setSex(user.getSex());
  1319. userSnapshot.setExamType(user.getExamType().title()); // TODO MF
  1320. userSnapshot.setProvinceName(user.getLocation());
  1321. Long modelId = null;
  1322. String modelName = null;
  1323. Integer year = null;
  1324. VoluntaryDto.EnumVoluntaryType type = null;
  1325. try {
  1326. modelId = model.getLong("id");
  1327. modelName = model.getString("name");
  1328. year = model.getInteger("year");
  1329. type = VoluntaryDto.EnumVoluntaryType.valueOf(model.getString("voluntaryType"));
  1330. wishRecord.setBatchName(model.getString("batchName"));
  1331. wishRecord.setRequest(model.getString("request"));
  1332. wishRecord.setDetails(model.getString("details"));
  1333. wishRecord.setUserSnapshot(mapper.writeValueAsString(userSnapshot));
  1334. } catch (JsonProcessingException e) {
  1335. return R.fail("格式错误: " + modelId);
  1336. }
  1337. wishRecord.setYear(null == year ? getPlanYear(user) : year);
  1338. wishRecord.setType(type.name());
  1339. if (null != modelId) {
  1340. wishRecord.setUpdateTime(new Date());
  1341. wishRecord.setId(modelId);
  1342. wishRecord.setName(modelName);
  1343. wishRecord.setUpdateTime(new Date());
  1344. aWishRecordMapper.updateAWishRecord(wishRecord);
  1345. } else {
  1346. wishRecord.setCreateTime(new Date());
  1347. wishRecord.setSeq(getWishSeq(wishRecord.getYear(), wishRecord.getType()));
  1348. wishRecord.setName(StringUtils.isNotBlank(modelName) ? modelName : ("AI".equals(wishRecord.getType()) ? "AI志愿" : "模拟志愿") + wishRecord.getSeq());
  1349. wishRecord.setUserId(user.getUserId());
  1350. wishRecord.setStatus(1);
  1351. aWishRecordMapper.insertAWishRecord(wishRecord);
  1352. }
  1353. return R.ok(wishRecord.getId());
  1354. }
  1355. private Integer getWishSeq(Integer year, String type) {
  1356. AWishRecord cond = new AWishRecord();
  1357. cond.setUserId(SecurityUtils.getLoginUser().getUserId());
  1358. cond.setYear(year);
  1359. cond.setType(type);
  1360. List<AWishRecord> aWishRecordList = aWishRecordMapper.selectAWishRecordList(cond);
  1361. Integer newSeq = CollectionUtils.isNotEmpty(aWishRecordList) ? aWishRecordList.get(0).getSeq() + 1 : 1;
  1362. return newSeq;
  1363. }
  1364. public void obsoleteWishRecord(Long userId) {
  1365. aWishRecordMapper.updateObsoleteByUser(userId);
  1366. busiWishRecordsMapper.updateObsoleteByUser(userId);
  1367. }
  1368. public R<JSONObject> getVoluntary(Long id) { // 志愿表详情 // 后台填充快照缺省
  1369. SysUser user = SecurityUtils.getLoginUser().getUser();
  1370. AWishRecord wishRecord = aWishRecordMapper.selectAWishRecordById(id);
  1371. if (null == wishRecord || !SecurityUtils.getUserId().equals(wishRecord.getUserId())) {
  1372. return R.fail("错误id");
  1373. }
  1374. if (null == wishRecord) {
  1375. throw new ServiceException("无此志愿id");
  1376. } else if (!user.getUserId().equals(wishRecord.getUserId())) {
  1377. throw new ServiceException("无此志愿id号");
  1378. }
  1379. JSONObject resp = toModel(wishRecord);
  1380. return R.ok(resp);
  1381. }
  1382. private JSONObject toModel(AWishRecord wishRecord) {
  1383. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  1384. JSONObject model = new JSONObject();
  1385. model.put("id", wishRecord.getId());
  1386. model.put("year", wishRecord.getYear());
  1387. model.put("voluntaryType", VoluntaryDto.EnumVoluntaryType.valueOf(wishRecord.getType()));
  1388. model.put("name", wishRecord.getName());
  1389. model.put("batchName", wishRecord.getBatchName());
  1390. model.put("createTime", sdf.format(wishRecord.getCreateTime()));
  1391. try {
  1392. model.put("userSnapshot", mapper.readValue(wishRecord.getUserSnapshot(), VoluntaryDto.User.class));
  1393. model.put("request", JSONObject.parseObject(wishRecord.getRequest()));
  1394. model.put("details", JSONArray.parseArray(wishRecord.getDetails()));
  1395. } catch (JsonProcessingException e) {
  1396. e.printStackTrace();
  1397. }
  1398. return model;
  1399. }
  1400. private VoluntaryDto.SingleResponse buildTestResp() {
  1401. String json = sysConfigService.selectConfigByKey("demo.voluntary.single");
  1402. if (StringUtils.isNotBlank(json)) {
  1403. try {
  1404. return mapper.readValue(json, VoluntaryDto.SingleResponse.class);
  1405. } catch (JsonProcessingException e) {
  1406. e.printStackTrace();
  1407. }
  1408. }
  1409. return new VoluntaryDto.SingleResponse();
  1410. }
  1411. private VoluntaryDto.AIResponse buildAiResp() {
  1412. String json = sysConfigService.selectConfigByKey("demo.voluntary.ai");
  1413. if (StringUtils.isNotBlank(json)) {
  1414. try {
  1415. VoluntaryDto.AIResponse resp = mapper.readValue(json, VoluntaryDto.AIResponse.class);
  1416. resp.setMajorDetails(Lists.newArrayList(buildTestResp()));
  1417. return resp;
  1418. } catch (JsonProcessingException e) {
  1419. e.printStackTrace();
  1420. }
  1421. }
  1422. return new VoluntaryDto.AIResponse();
  1423. }
  1424. private VoluntaryDto.VoluntaryModel buildModel() {
  1425. String json = sysConfigService.selectConfigByKey("demo.voluntary.model");
  1426. if(StringUtils.isNotBlank(json)) {
  1427. try {
  1428. VoluntaryDto.VoluntaryModel model = mapper.readValue(json, VoluntaryDto.VoluntaryModel.class);
  1429. model.setDetails(Lists.newArrayList(buildAiResp()));
  1430. return model;
  1431. } catch (JsonProcessingException e) {
  1432. e.printStackTrace();
  1433. }
  1434. }
  1435. return new VoluntaryDto.VoluntaryModel();
  1436. }
  1437. private VoluntaryDto.EnumRuleType itemType2RuleType(String itemType, String valueType, boolean foreSingleTotal) {
  1438. if ("Notice".equals(valueType)) {
  1439. return VoluntaryDto.EnumRuleType.Readonly;
  1440. } else if (foreSingleTotal && VoluntaryDto.EnumRuleType.ScoreSingle.name().equals(itemType)) {
  1441. return VoluntaryDto.EnumRuleType.ScoreTotal;
  1442. }
  1443. return VoluntaryDto.EnumRuleType.valueOf(itemType);
  1444. }
  1445. public List<VoluntaryDto.VoluntaryRecord> getVoluntaryList2() { // 我的志愿表 // 后台填充快照缺省
  1446. AWishRecord cond = new AWishRecord();
  1447. cond.setUserId(SecurityUtils.getLoginUser().getUserId());
  1448. cond.setStatus(1);
  1449. List<AWishRecord> aWishRecordList = aWishRecordMapper.selectAWishRecordList(cond);
  1450. if(CollectionUtils.isEmpty(aWishRecordList)) {
  1451. return Collections.emptyList();
  1452. }
  1453. return JSONArray.parseArray(aWishRecordList.get(0).getDetails(), VoluntaryDto.VoluntaryRecord.class);
  1454. }
  1455. public R<Long> addVoluntary2(JSONObject model) { // 填报 // 前端+后台按需要剔除一些不需快照的信息(目前主要是院校信息)
  1456. SysUser user = SecurityUtils.getLoginUser().getUser();
  1457. AWishRecord wishRecord = getWishRecord(user.getUserId());
  1458. List<VoluntaryDto.VoluntaryRecord> voluntaryRecordList = (null == wishRecord.getId()) ? Lists.newArrayList()
  1459. : JSONArray.parseArray(wishRecord.getDetails(), VoluntaryDto.VoluntaryRecord.class);
  1460. Long universityId = model.getLong("universityId");
  1461. Long majorId = model.getLong("majorId");
  1462. Optional<VoluntaryDto.VoluntaryRecord> optionalVoluntary = voluntaryRecordList.stream().filter(t -> t.getUniversityId().equals(universityId)).findFirst();
  1463. VoluntaryDto.VoluntaryRecord voluntaryRecord;
  1464. if(optionalVoluntary.isPresent()) {
  1465. voluntaryRecord = optionalVoluntary.get();
  1466. if(null == voluntaryRecord.getMajors()) {
  1467. voluntaryRecord.setMajors(Lists.newArrayList());
  1468. }
  1469. } else {
  1470. BBusiWishUniversities u = bBusiWishUniversitiesMapper.selectBBusiWishUniversitiesById(universityId);
  1471. voluntaryRecord = new VoluntaryDto.VoluntaryRecord();
  1472. voluntaryRecord.setUniversityLogo(u.getLogo());
  1473. voluntaryRecord.setUniversityName(u.getName());
  1474. voluntaryRecord.setUniversityId(u.getId());
  1475. voluntaryRecord.setMajors(Lists.newArrayList());
  1476. voluntaryRecord.setRank(voluntaryRecordList.size() + 1);
  1477. voluntaryRecordList.add(voluntaryRecord);
  1478. }
  1479. Optional<VoluntaryDto.VoluntaryMajorRecord> optionalMajor = voluntaryRecord.getMajors().stream().filter( t -> t.getMajorId().equals(majorId)).findFirst();
  1480. if(!optionalMajor.isPresent()) {
  1481. AMarjorPlan p = aMarjorPlanMapper.selectAMarjorPlanById(majorId);
  1482. VoluntaryDto.VoluntaryMajorRecord major = new VoluntaryDto.VoluntaryMajorRecord();
  1483. major.setMajorId(p.getId());
  1484. major.setMajorGroup(p.getMajorGroup());
  1485. major.setMajorName(p.getMajorName());
  1486. major.setMajorAncestors("");
  1487. major.setRank(voluntaryRecord.getMajors().size() + 1);
  1488. voluntaryRecord.getMajors().add(major);
  1489. }
  1490. wishRecord.setDetails(JSONArray.toJSONString(voluntaryRecordList));
  1491. wishRecord.setYear(getPlanYear(user));
  1492. if (null != wishRecord.getId()) {
  1493. wishRecord.setUpdateTime(new Date());
  1494. wishRecord.setUpdateTime(new Date());
  1495. aWishRecordMapper.updateAWishRecord(wishRecord);
  1496. } else {
  1497. wishRecord.setCreateTime(new Date());
  1498. wishRecord.setUserId(user.getUserId());
  1499. wishRecord.setStatus(1);
  1500. aWishRecordMapper.insertAWishRecord(wishRecord);
  1501. }
  1502. return R.ok(wishRecord.getId());
  1503. }
  1504. public Boolean removeVoluntaryByUniversity(Long userId, Long universityId) {
  1505. AWishRecord wishRecord = getWishRecord(userId);
  1506. List<VoluntaryDto.VoluntaryRecord> voluntaryRecordList = JSONArray.parseArray(wishRecord.getDetails(), VoluntaryDto.VoluntaryRecord.class);
  1507. List<VoluntaryDto.VoluntaryRecord> newRecordList = Lists.newArrayList();
  1508. for(VoluntaryDto.VoluntaryRecord r : voluntaryRecordList) {
  1509. if(r.getUniversityId().equals(universityId)) {
  1510. continue;
  1511. }
  1512. r.setRank(newRecordList.size());
  1513. newRecordList.add(r);
  1514. }
  1515. updateWishRecord(wishRecord, newRecordList);
  1516. return true;
  1517. }
  1518. public Boolean removeVoluntaryByMajor(Long userId, Long majorId) {
  1519. AMarjorPlan plan = aMarjorPlanMapper.selectAMarjorPlanById(majorId);
  1520. if(null == plan) {
  1521. throw new RuntimeException("错误的专业计划ID");
  1522. }
  1523. AWishRecord wishRecord = getWishRecord(userId);
  1524. List<VoluntaryDto.VoluntaryRecord> voluntaryRecordList = JSONArray.parseArray(wishRecord.getDetails(), VoluntaryDto.VoluntaryRecord.class);
  1525. Optional<VoluntaryDto.VoluntaryRecord> optionalVoluntary = voluntaryRecordList.stream().filter(t -> t.getUniversityId().equals(plan.getUniversityId())).findFirst();
  1526. if(!optionalVoluntary.isPresent()) {
  1527. throw new RuntimeException("错误的院校ID");
  1528. }
  1529. VoluntaryDto.VoluntaryRecord voluntaryRecord = optionalVoluntary.get();
  1530. List<VoluntaryDto.VoluntaryMajorRecord> newRecordList = Lists.newArrayList();
  1531. for(VoluntaryDto.VoluntaryMajorRecord r : voluntaryRecord.getMajors()) {
  1532. if(r.getMajorId().equals(majorId)) {
  1533. continue;
  1534. }
  1535. r.setRank(newRecordList.size());
  1536. newRecordList.add(r);
  1537. }
  1538. if(newRecordList.isEmpty()) {
  1539. updateWishRecord(wishRecord, voluntaryRecordList.stream().filter(t -> !t.getUniversityId().equals(plan.getUniversityId())).collect(Collectors.toList()));
  1540. } else {
  1541. voluntaryRecord.setMajors(newRecordList);
  1542. updateWishRecord(wishRecord, voluntaryRecordList);
  1543. }
  1544. return true;
  1545. }
  1546. public void sortVoluntaryByMajor(Long userId, Long universityId, Map<Long, Integer> majorRankMap) {
  1547. AWishRecord wishRecord = getWishRecord(userId);
  1548. List<VoluntaryDto.VoluntaryRecord> voluntaryRecordList = JSONArray.parseArray(wishRecord.getDetails(), VoluntaryDto.VoluntaryRecord.class);
  1549. Optional<VoluntaryDto.VoluntaryRecord> optionalVoluntary = voluntaryRecordList.stream().filter(t -> t.getUniversityId().equals(universityId)).findFirst();
  1550. VoluntaryDto.VoluntaryRecord voluntaryRecord;
  1551. if(!optionalVoluntary.isPresent()) {
  1552. throw new RuntimeException("错误的院校ID");
  1553. }
  1554. voluntaryRecord = optionalVoluntary.get();
  1555. Integer rank;
  1556. for(VoluntaryDto.VoluntaryMajorRecord record : voluntaryRecord.getMajors()) {
  1557. if(null == (rank = majorRankMap.remove(record.getMajorId()))) {
  1558. throw new RuntimeException("错误的专业计划ID");
  1559. }
  1560. record.setRank(rank);
  1561. }
  1562. Collections.sort(voluntaryRecord.getMajors(), new Comparator<VoluntaryDto.VoluntaryMajorRecord>() {
  1563. @Override
  1564. public int compare(VoluntaryDto.VoluntaryMajorRecord o1, VoluntaryDto.VoluntaryMajorRecord o2) {
  1565. return o1.getRank().compareTo(o2.getRank());
  1566. }
  1567. });
  1568. updateWishRecord(wishRecord, voluntaryRecordList);
  1569. }
  1570. public void sortVoluntaryByUniversity(Long userId, Map<Long, Integer> universityRankMap) {
  1571. AWishRecord wishRecord = getWishRecord(userId);
  1572. List<VoluntaryDto.VoluntaryRecord> voluntaryRecordList = JSONArray.parseArray(wishRecord.getDetails(), VoluntaryDto.VoluntaryRecord.class);
  1573. Integer rank;
  1574. for(VoluntaryDto.VoluntaryRecord record : voluntaryRecordList) {
  1575. if(null == (rank = universityRankMap.remove(record.getUniversityId()))) {
  1576. throw new RuntimeException("错误的院校ID");
  1577. }
  1578. record.setRank(rank);
  1579. }
  1580. Collections.sort(voluntaryRecordList, new Comparator<VoluntaryDto.VoluntaryRecord>() {
  1581. @Override
  1582. public int compare(VoluntaryDto.VoluntaryRecord o1, VoluntaryDto.VoluntaryRecord o2) {
  1583. return o1.getRank().compareTo(o2.getRank());
  1584. }
  1585. });
  1586. updateWishRecord(wishRecord, voluntaryRecordList);
  1587. }
  1588. private void updateWishRecord(AWishRecord wishRecord, List<VoluntaryDto.VoluntaryRecord> voluntaryRecordList) {
  1589. wishRecord.setUpdateTime(new Date());
  1590. wishRecord.setUpdateTime(new Date());
  1591. wishRecord.setDetails(JSONArray.toJSONString(voluntaryRecordList));
  1592. aWishRecordMapper.updateAWishRecord(wishRecord);
  1593. }
  1594. private AWishRecord getWishRecord(Long userId) {
  1595. AWishRecord wrCond = new AWishRecord();
  1596. wrCond.setUserId(userId);
  1597. wrCond.setStatus(1);
  1598. List<AWishRecord> wishList = aWishRecordMapper.selectAWishRecordList(wrCond);
  1599. return wishList.isEmpty() ? new AWishRecord() : wishList.get(0);
  1600. }
  1601. }