package com.ruoyi.web.service; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONException; import com.alibaba.fastjson2.JSONObject; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.ie.domain.*; import com.ruoyi.ie.mapper.*; import com.ruoyi.system.service.ISysConfigService; import com.ruoyi.syzy.domain.BBusiWishUniversities; import com.ruoyi.syzy.domain.BBusiWishUniversitiesProfession; import com.ruoyi.syzy.dto.UniversityDetailDTO; import com.ruoyi.syzy.mapper.BBusiWishRecordsMapper; import com.ruoyi.syzy.mapper.BBusiWishUniversitiesMapper; import com.ruoyi.syzy.mapper.BBusiWishUniversitiesProfessionMapper; import com.ruoyi.util.PageUtil; import com.ruoyi.web.domain.Constant; import com.ruoyi.web.domain.VoluntaryDto; import io.swagger.annotations.ApiParam; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.math.NumberUtils; import org.apache.commons.lang3.tuple.MutablePair; import org.apache.commons.lang3.tuple.Pair; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RequestParam; import java.text.SimpleDateFormat; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @Service public class VoluntaryService { private ObjectMapper mapper = new ObjectMapper(); private static TypeReference> wishDetailsTypeReference = new TypeReference>() { }; private static TypeReference> wishAiDetailsTypeReference = new TypeReference>() { }; Set NumberTypeSet = Sets.newHashSet(VoluntaryDto.EnumInputType.Number.name(), VoluntaryDto.EnumInputType.Eyesight.name(), VoluntaryDto.EnumInputType.Score.name()); private final AWishRecordMapper aWishRecordMapper; private final AEnrollScoreMapper aEnrollScoreMapper; private final AEnrollSpecialMapper aEnrollSpecialMapper; private final AMarjorPlanMapper aMarjorPlanMapper; private final AMarjorSubmitMapper aMarjorSubmitMapper; private final AEnrollUniversityMapper aEnrollUniversityMapper; private final BBusiWishUniversitiesMapper bBusiWishUniversitiesMapper; private final BBusiWishUniversitiesProfessionMapper bBusiWishUniversitiesProfessionMapper; private final ISysConfigService sysConfigService; private final EnrollRateCalculator enrollRateCalculator; private final BBusiWishRecordsMapper busiWishRecordsMapper; public VoluntaryService(AWishRecordMapper aWishRecordMapper, AEnrollScoreMapper aEnrollScoreMapper, AEnrollSpecialMapper aEnrollSpecialMapper, AMarjorPlanMapper aMarjorPlanMapper, AMarjorSubmitMapper aMarjorSubmitMapper, AEnrollUniversityMapper aEnrollUniversityMapper, BBusiWishUniversitiesMapper bBusiWishUniversitiesMapper, BBusiWishUniversitiesProfessionMapper bBusiWishUniversitiesProfessionMapper, ISysConfigService sysConfigService, EnrollRateCalculator enrollRateCalculator, BBusiWishRecordsMapper busiWishRecordsMapper) { this.aWishRecordMapper = aWishRecordMapper; this.aEnrollScoreMapper = aEnrollScoreMapper; this.aEnrollSpecialMapper = aEnrollSpecialMapper; this.aMarjorPlanMapper = aMarjorPlanMapper; this.aMarjorSubmitMapper = aMarjorSubmitMapper; this.aEnrollUniversityMapper = aEnrollUniversityMapper; this.bBusiWishUniversitiesMapper = bBusiWishUniversitiesMapper; this.bBusiWishUniversitiesProfessionMapper = bBusiWishUniversitiesProfessionMapper; this.sysConfigService = sysConfigService; this.enrollRateCalculator = enrollRateCalculator; this.busiWishRecordsMapper = busiWishRecordsMapper; // mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } public Pair, List> getUniversityHistory(Long universityId, String province, String examineType) { AMarjorPlan planCond = new AMarjorPlan(); planCond.setUniversityId(universityId); planCond.setExamineeType(examineType); List planList = aMarjorPlanMapper.selectAMarjorPlanList(planCond).stream().map(t -> { UniversityDetailDTO.WishPlan p = new UniversityDetailDTO.WishPlan(); p.setId(t.getId()); p.setCollegeCode(t.getEnrollCode()); p.setYear(String.valueOf(t.getYear())); p.setLevel(t.getLevel()); p.setType(""); p.setMarjorCode(t.getMajorCode()); p.setMarjorName(t.getMajorName()); p.setMarjorBelongs(t.getMajorEnrollCode()); p.setMarjorDirection(t.getMajorDirection()); p.setSpecialProject(""); p.setPlanCount(t.getPlanTotal()); p.setXuefei(String.valueOf(t.getXuefei())); p.setXuezhi(String.valueOf(t.getLengthOfSchooling())); p.setEnrollFormula(t.getEnrollFormula()); p.setGroupsName(t.getMajorGroup()); return p; }).collect(Collectors.toList()); AMarjorSubmit submitCond = new AMarjorSubmit(); submitCond.setUniversityId(universityId); submitCond.setEnrollType("初录"); submitCond.setExamineeType(examineType); List submitList = aMarjorSubmitMapper.selectAMarjorSubmitList(submitCond).stream().map(t -> { UniversityDetailDTO.WishSubmit s = new UniversityDetailDTO.WishSubmit(); s.setId(t.getId()); s.setYear(String.valueOf(t.getYear())); s.setLevel(t.getLevel()); s.setType(""); s.setMarjorCode(""); s.setMarjorName(t.getMajorName()); s.setMarjorBelongs(""); s.setMarjorDirection(t.getMajorDirection()); s.setSpecialProject(""); s.setScore(null != t.getScore() ? t.getScore().longValue() : null); s.setSeat(null); s.setNumReal(null != t.getEnrollTotal() ? t.getEnrollTotal().longValue() : null); s.setEnrollFormula(t.getEnrollFormula()); s.setGroupsName(t.getMajorGroup()); return s; }).collect(Collectors.toList()); return Pair.of(planList, submitList); } private void setOptionValue(VoluntaryDto.AIRenderRule r, String valueType, String valueRule, String options, Integer correctType, String correctValue, Integer scoreTotal) { r.setEnumInputType(VoluntaryDto.EnumInputType.valueOf(valueType)); if (VoluntaryDto.EnumInputType.Score.equals(r.getEnumInputType())) { r.setOptions(new String[]{null == scoreTotal ? "0" : String.valueOf(scoreTotal.intValue())}); } else if (StringUtils.isNotBlank(options) && (VoluntaryDto.EnumInputType.Checkbox.equals(r.getEnumInputType()) || VoluntaryDto.EnumInputType.Radio.equals(r.getEnumInputType()) || VoluntaryDto.EnumInputType.Picker.equals(r.getEnumInputType()))) { r.setOptions(options.split(",")); } // r.setRequired(); // 词典选项类选项 // 词典类选项的优先级最高 // String dictOptions; // 非词典选项 // 分制类规则,将多分制在此options中返回 // String[] options; } public Integer getPlanYear(SysUser u) { return 2025; } public Integer getSubmitYear() { return 2024; } public R> getAIRenderRules(VoluntaryDto.AIRenderRequest req) { Map cond = new HashMap(); cond.put("year", getPlanYear(SecurityUtils.getLoginUser().getUser())); Set majorCodeSet = null; if (ArrayUtils.isNotEmpty(req.getMajorEnrollCodes()) && StringUtils.isNotBlank(req.getMajorEnrollCodes()[0])) { List majorEnrollCodes = Arrays.asList(req.getMajorEnrollCodes()).stream().map(t -> NumberUtils.toLong(t, 0L)).collect(Collectors.toList()); majorCodeSet = aMarjorPlanMapper.selectMajorCodesByIds(majorEnrollCodes.toArray(new Long[majorEnrollCodes.size()])).stream().collect(Collectors.toSet()); } if(CollectionUtils.isNotEmpty(majorCodeSet)) { cond.put("majorCodes", majorCodeSet.toArray(new String[majorCodeSet.size()])); } else if (ArrayUtils.isNotEmpty(req.getMajorCodes()) && StringUtils.isNotBlank(req.getMajorCodes()[0])) { cond.put("majorCodes", req.getMajorCodes()); } else if (ArrayUtils.isNotEmpty(req.getMajorTypes()) && StringUtils.isNotBlank(req.getMajorTypes()[0])) { cond.put("majorTypes", req.getMajorTypes()); } else if (StringUtils.isNotBlank(req.getMajorCategory())) { cond.put("majorCategory", req.getMajorCategory()); } cond.put("universityCode", req.getUniversityCode()); return R.ok(findMatchRules(cond, req.getRenderType() == 1, req.getRenderType() == 2)); } public R postSingleResult(VoluntaryDto.SingleRequest req, Boolean isScoreOnly) { VoluntaryDto.MultipleRequest mr = new VoluntaryDto.MultipleRequest(); VoluntaryDto.CollegeMajorDto collegeMajor = new VoluntaryDto.CollegeMajorDto(); collegeMajor.setCode(req.getUniversityCode()); if (StringUtils.isNotBlank(req.getMajorCode())) { collegeMajor.setMajorCodes(Lists.newArrayList(req.getMajorCode())); } if (StringUtils.isNotBlank(req.getMajorEnrollCode())) { collegeMajor.setMajorEnrollCodes(Lists.newArrayList(req.getMajorEnrollCode())); } collegeMajor.setForm(req.getForm()); mr.setUniversities(Lists.newArrayList(collegeMajor)); List respList = postMultipleResult(mr, isScoreOnly).getData(); if (respList.size() > 0) { Optional optionalSingleResponse = respList.stream().filter(t -> StringUtils.isBlank(t.getMajorDirection())).findFirst(); if (optionalSingleResponse.isPresent()) { return R.ok(optionalSingleResponse.get()); } } return respList.size() > 0 ? R.ok(respList.get(0)) : null; } public R> postMultipleResult(VoluntaryDto.MultipleRequest req, boolean isScoreOnly) { List respList = Lists.newArrayList(); for (VoluntaryDto.CollegeMajorDto cm : req.getUniversities()) { Map cond = new HashMap(); if (CollectionUtils.isNotEmpty(cm.getMajorEnrollCodes()) && StringUtils.isNotBlank(cm.getMajorEnrollCodes().get(0))) { cond.put("majorEnrollCodes", cm.getMajorEnrollCodes()); // TODO 代替majorCodes更精准,只是现在没有,使用planId代替 } else if (CollectionUtils.isNotEmpty(cm.getMajorCodes()) && StringUtils.isNotBlank(cm.getMajorCodes().get(0))) { cond.put("majorCodes", cm.getMajorCodes()); } else if (StringUtils.isNotBlank(req.getMajorCategory())) { cond.put("majorCategory", req.getMajorCategory()); } cond.put("universityCode", StringUtils.trimToEmpty(cm.getCode())); List responses = findMajorSuggest(getPlanYear(SecurityUtils.getLoginUser().getUser()), getSubmitYear(), cond, cm.getForm(), false, isScoreOnly); if(CollectionUtils.isNotEmpty(responses)) { responses.stream().forEach(t -> respList.addAll(t.getMajorDetails())); } } return R.ok(respList); } public TableDataInfo postAIResult(VoluntaryDto.AIRequest req) { VoluntaryDto.AIRequestFilter filter = req.getFilter(); Map cond = new HashMap(); if (CollectionUtils.isNotEmpty(filter.getMajorTypes()) && StringUtils.isNotBlank(filter.getMajorTypes().get(0))) { cond.put("majorTypes", filter.getMajorTypes()); } else if (StringUtils.isNotBlank(req.getMajorCategory())) { cond.put("majorCategory", req.getMajorCategory()); } cond.put("universityName", filter.getKeyword());// 院校名称 if (CollectionUtils.isNotEmpty(filter.getLevel())) { cond.put("universityLevel", filter.getLevel());// 办学层次 } if (CollectionUtils.isNotEmpty(filter.getType())) { cond.put("universityType", filter.getType());// 院校类型 } if (CollectionUtils.isNotEmpty(filter.getNatureTypeCN())) { cond.put("universityNatureType", filter.getNatureTypeCN()); // 办学类型 } if (CollectionUtils.isNotEmpty(filter.getLocation())) { cond.put("universityLocation", filter.getLocation()); // 院校省份 } if (null != filter.getHasClearing()) { cond.put("hasClearing", filter.getHasClearing() ? "补录" : "初录"); } List responses = findMajorSuggest(getPlanYear(SecurityUtils.getLoginUser().getUser()), getSubmitYear(), cond, req.getForm(), true, false); if (CollectionUtils.isEmpty(responses)) { return new TableDataInfo(Lists.newArrayList(), 0); } if (null != filter.getEnumPickEmpty()) { responses = responses.stream().filter(t -> filter.getEnumPickEmpty().equals(t.getEnumPickEmpty())).collect(Collectors.toList()); } else if (null != filter.getEnumPickType() && !VoluntaryDto.EnumPickType.All.equals(filter.getEnumPickType())) { responses = responses.stream().filter(t -> filter.getEnumPickType().equals(t.getEnumPickType())).collect(Collectors.toList()); } Integer start = null != req.getPageNum() ? (req.getPageNum() - 1) * req.getPageSize() : 0; List finalList = responses.subList(start, Math.min(start + (null == req.getPageSize() ? 10 : req.getPageSize()), responses.size())); TableDataInfo tableDataInfo = new TableDataInfo(finalList, responses.size()); tableDataInfo.setCode(200); return tableDataInfo; } private List findMatchRules(Map cond, boolean isAi, boolean isScore) { String examType = SecurityUtils.getLoginUser().getUser().getExamType().title(); // TODO MF String gender = "0".equals(SecurityUtils.getLoginUser().getUser().getSex()) ? "男生" : "女生"; cond.put("examineeType", examType); List enrollScoreList = aEnrollScoreMapper.selectListByRuleCond(cond); List ruleList = Lists.newArrayList(); Set existItemSet = Sets.newHashSet(); String vt; VoluntaryDto.AIRenderRule scoreRateRule = null; for (AEnrollScore s : enrollScoreList) { // 跳过统计类和提示类的规则 if (null == (vt = s.getValueType()) || vt.startsWith("Stat") || vt.equals("Notice")) { continue; } else if(isScore && !"学考".equals(s.getItemCategory()) && !"校考".equals(s.getItemCategory())) { continue; } else if (vt.equals("ScoreRate")) { if (!isAi) { vt = "Score"; } else if (existItemSet.add("ScoreRate")) { scoreRateRule = new VoluntaryDto.AIRenderRule(); scoreRateRule.setEnumRuleCategory(VoluntaryDto.EnumRuleCategory.Enroll); scoreRateRule.setFieldName("ScoreRate"); scoreRateRule.setEnumInputType(VoluntaryDto.EnumInputType.Number); scoreRateRule.setMin(0); scoreRateRule.setMax(100); scoreRateRule.setLabel("技能测试得分率"); scoreRateRule.setDescription("%"); continue; } else { continue; } } if (!existItemSet.add(s.getItemField())) { continue; } VoluntaryDto.AIRenderRule r = new VoluntaryDto.AIRenderRule(); r.setEnumRuleCategory(VoluntaryDto.EnumRuleCategory.Enroll); r.setFieldName(s.getItemField()); setOptionValue(r, vt, s.getValueRule(), s.getValueOptional(), s.getCorrectType(), s.getCorrectValue(), s.getScoreTotal()); r.setRegex(s.getRegex()); r.setLabel(s.getItemName()); r.setDescription(s.getDescription()); r.setPlaceholder(s.getPlaceholder()); r.setTips(s.getTips()); r.setDefaultValue(s.getDefaultValue()); r.setDotDisable(null != s.getDotDisable() && s.getDotDisable() > 0); r.setKeyboardMode(s.getKeyboardMode()); // number card car,默认number ruleList.add(r); } if (null != scoreRateRule) { ruleList.add(scoreRateRule); } if(isScore) { return ruleList; } List enrollSpecialList = Lists.newArrayList(); Map mergeEnrollSpecialMap = Maps.newHashMap(); List oriErollSpecialList = aEnrollSpecialMapper.selectListByRuleCond(cond); for (AEnrollSpecial s : oriErollSpecialList) { if (VoluntaryDto.EnumRuleType.Readonly.name().equals(s.getItemType()) || StringUtils.isNotBlank(s.getGender()) && !s.getGender().equals(gender)) { continue; } if (null == s.getItemGroup() || !"Checkbox".equals(s.getValueType())) { enrollSpecialList.add(s); continue; } // String key = s.getItemGroup(); // s.getUniversityId() + "_" + s.getMajorName() + "_" + StringUtils.trimToEmpty(s.getMajorDirection()) + "_" + StringUtils.trimToEmpty(s.getGender()) + "_" + s.getItemCategory() + "_" + AEnrollSpecial exist = mergeEnrollSpecialMap.get(key); if (null == exist) { // 修正分组后的名称及字段名 String[] groupNameField = StringUtils.split(s.getItemGroup(), "_"); s.setValueOptional(s.getItemName()); s.setItemName(groupNameField[0]); s.setItemField(groupNameField[groupNameField.length > 1 ? 1 : 0]); mergeEnrollSpecialMap.put(key, s); enrollSpecialList.add(s); continue; } if(StringUtils.isBlank(exist.getValueOptional()) || !exist.getValueOptional().contains(s.getItemName())) { exist.setValueOptional(exist.getValueOptional() + "," + s.getItemName()); } } Map mutexOptionMap = getMutexOptionMap(); for (AEnrollSpecial s : enrollSpecialList) { if (null == (vt = s.getValueType()) || vt.startsWith("Stat") || vt.equals("Notice") || !existItemSet.add(s.getItemField())) { continue; } VoluntaryDto.AIRenderRule r = new VoluntaryDto.AIRenderRule(); r.setEnumRuleCategory(VoluntaryDto.EnumRuleCategory.Special); r.setFieldName(s.getItemField()); setOptionValue(r, s.getValueType(), s.getValueRule(), s.getValueOptional(), s.getCorrectType(), s.getCorrectValue(), null); if (VoluntaryDto.EnumInputType.Checkbox.equals(r.getEnumInputType())) { r.setMutexOption(mutexOptionMap.get(r.getFieldName())); } r.setRegex(s.getRegex()); r.setLabel(s.getItemName()); r.setDescription(s.getDescription()); r.setPlaceholder(s.getPlaceholder()); r.setTips(s.getTips()); r.setDefaultValue(s.getDefaultValue()); r.setDotDisable(null != s.getDotDisable() && s.getDotDisable() > 0); r.setKeyboardMode(s.getKeyboardMode()); // number card car,默认number ruleList.add(r); } return ruleList; } private Map getMutexOptionMap() { String mutexOptionConf = sysConfigService.selectConfigByKey("voluntary.rule.mutexOption"); Map mutexOptionMap = Maps.newHashMap(); if (StringUtils.isNotBlank(mutexOptionConf)) { try { JSONArray.parseArray(mutexOptionConf).forEach(l -> { JSONObject lo = (JSONObject) l; mutexOptionMap.put(lo.getString("n"), lo.getString("m")); }); } catch (JSONException e) { } } return mutexOptionMap; } // TODO 同一专业号有多个专业方向 private List findMajorSuggest(Integer planYear, Integer submitYear, Map cond, Map paramMap, boolean isAi, boolean isScoreOnly) { String examType = SecurityUtils.getLoginUser().getUser().getExamType().title(); // TODO MF String gender = "0".equals(SecurityUtils.getLoginUser().getUser().getSex()) ? "男生" : "女生"; cond.remove("year"); cond.put("examineeType", examType); Map> currUniversityMajorPlansMap = Maps.newHashMap(); Map> historyUniversityMajorPlansMap = Maps.newHashMap(); List>> bothPlanList = Lists.newArrayList(currUniversityMajorPlansMap, historyUniversityMajorPlansMap); Set existSet = Sets.newHashSet(); for (AMarjorPlan mp : aMarjorPlanMapper.selectListByRuleCond(cond)) { String key = mp.getUniversityId() + mp.getMajorName() + StringUtils.trimToEmpty(mp.getMajorDirection()) + mp.getYear(); // TODO 考虑为什么会重的问题 examType ? if (!existSet.add(key)) { continue; } for(Map> tmpMap : bothPlanList) { if (!mp.getYear().equals(planYear) && tmpMap == currUniversityMajorPlansMap) { continue; } List tmpMpList = tmpMap.get(mp.getUniversityId()); if (null == tmpMpList) { tmpMpList = Lists.newArrayList(mp); tmpMap.put(mp.getUniversityId(), tmpMpList); } else { tmpMpList.add(mp); } } } Map> universityMajorsMap = Maps.newHashMap(); // 有计划以计划为准的输出,无计划时则以所有专业输出为准 Map universitiesMap = null; if (MapUtils.isEmpty(currUniversityMajorPlansMap)) { Map> tmpUniversityMajorsMap = bBusiWishUniversitiesProfessionMapper.selectListByRuleCond(cond).stream().collect(Collectors.groupingBy(BBusiWishUniversitiesProfession::getCollegeCode)); if (MapUtils.isNotEmpty(tmpUniversityMajorsMap)) { Map uCond = Maps.newHashMap(); uCond.put("codes", tmpUniversityMajorsMap.keySet()); universitiesMap = Maps.newHashMap(); for (BBusiWishUniversities u : bBusiWishUniversitiesMapper.selectBBusiWishUniversitiesListSimpleByMap(uCond)) { universitiesMap.put(u.getId(), u); universityMajorsMap.put(u.getId(), tmpUniversityMajorsMap.get(u.getCode())); } } } else { cond.put("universityIds", currUniversityMajorPlansMap.keySet()); cond.put("examType", Constant.EXAM_TYPE_PG); Map> tmpUniversityMajorsMap = bBusiWishUniversitiesProfessionMapper.selectListByRuleCond(cond).stream().collect(Collectors.groupingBy(BBusiWishUniversitiesProfession::getCollegeCode)); cond.remove("universityIds"); if (MapUtils.isNotEmpty(tmpUniversityMajorsMap)) { Map uCond = new HashMap(); uCond.put("ids", currUniversityMajorPlansMap.keySet()); universitiesMap = Maps.newHashMap(); for (BBusiWishUniversities u : bBusiWishUniversitiesMapper.selectBBusiWishUniversitiesListSimpleByIds(uCond)) { universitiesMap.put(u.getId(), u); universityMajorsMap.put(u.getId(), tmpUniversityMajorsMap.get(u.getCode())); } } } // 无计划,也无院校专业 if(MapUtils.isEmpty(universitiesMap)) { return Lists.newArrayList(); } // 查询涉及的规则 cond.put("year", planYear); cond.put("universityIds", universitiesMap.keySet()); Map> universityScoreListMap = aEnrollScoreMapper.selectListByRuleCond(cond).stream().collect(Collectors.groupingBy(AEnrollScore::getUniversityId)); Map> universitySpecialListMap = aEnrollSpecialMapper.selectListByRuleCond(cond).stream().collect(Collectors.groupingBy(AEnrollSpecial::getUniversityId)); cond.remove("universityIds"); cond.remove("year"); Map mutexOptionMap = getMutexOptionMap(); List aiRespList = Lists.newArrayList(); for (Long universityId : universitiesMap.keySet()) { List scoreList = universityScoreListMap.get(universityId); // 分数条件 List specialList = universitySpecialListMap.get(universityId);// 专项条件 List currPlanList = currUniversityMajorPlansMap.get(universityId);// 当年计划 List historyPlanList = historyUniversityMajorPlansMap.get(universityId);// 历年计划 BBusiWishUniversities u = universitiesMap.get(universityId);// 院校 List professionList = universityMajorsMap.get(u.getId()); // 所有专业 // 院校变更标志 AEnrollUniversity euCond = new AEnrollUniversity(); euCond.setUniversityId(u.getId()); euCond.setYear(planYear); List enrollUniversityList = aEnrollUniversityMapper.selectAEnrollUniversityList(euCond); // 院校历史情况 AMarjorSubmit submitCond = new AMarjorSubmit(); submitCond.setExamineeType(examType); submitCond.setUniversityId(universityId); List submitList = aMarjorSubmitMapper.selectAMarjorSubmitList(submitCond); VoluntaryDto.AIResponse aiResp = new VoluntaryDto.AIResponse(); aiResp.setUniversity(u); VoluntaryDto.SingleResponse sr; List singleResponseList = Lists.newArrayList(); if (CollectionUtils.isNotEmpty(currPlanList)) { aiResp.setEnrollCode(currPlanList.get(0).getEnrollCode()); Map professionMap = null == professionList ? Maps.newHashMap() : professionList.stream().collect(Collectors.toMap(BBusiWishUniversitiesProfession::getName, Function.identity())); for (AMarjorPlan mp : currPlanList) { if (null != (sr = buildSingleResponse(submitYear, planYear, gender, mp, professionMap.get(mp.getMajorName()), enrollUniversityList, paramMap, u, historyPlanList, submitList, scoreList, specialList, mutexOptionMap, isAi, isScoreOnly))) { singleResponseList.add(sr); } } } else { for (BBusiWishUniversitiesProfession prof : professionList) { if (null != (sr = buildSingleResponse(submitYear, planYear, gender, null, prof, enrollUniversityList, paramMap, u, historyPlanList, submitList, scoreList, specialList, mutexOptionMap, isAi, isScoreOnly))) { singleResponseList.add(sr); } } } aiResp.setMajorDetails(singleResponseList); sortAndExtractEnroll(singleResponseList, aiResp); aiRespList.add(aiResp); } Collections.sort(aiRespList, new Comparator() { @Override public int compare(VoluntaryDto.AIResponse o1, VoluntaryDto.AIResponse o2) { Integer d1 = o1.getEnrollRate(); Integer d2 = o2.getEnrollRate(); d1 = null == d1 ? 999 : (d1 == 0 ? 998 : d1); d2 = null == d2 ? 999 : (d2 == 0 ? 998 : d2); return d1.compareTo(d2); } }); return aiRespList; } private VoluntaryDto.SingleResponse buildSingleResponse(Integer submitYear, Integer planYear, String gender, AMarjorPlan currPlan, BBusiWishUniversitiesProfession prof, List enrollUniversityList, Map paramMap, BBusiWishUniversities u, List historyPlanList, List submitList, List scoreList, List specialList, Map mutexOptionMap, boolean isAi, boolean isScoreOnly) { if (null != submitList) { Collections.sort(submitList, new Comparator() { @Override public int compare(AMarjorSubmit o1, AMarjorSubmit o2) { int iRet; if (0 != (iRet = o1.getYear().compareTo(o2.getYear()))) { return -iRet; } if (0 != (iRet = o1.getMajorName().compareTo(o2.getMajorName()))) { return -iRet; } if (null == o1.getMajorDirection()) { if (null != o2.getMajorDirection()) { return 1; } return 0; } else if (null == o2.getMajorDirection()) { return -1; } return 0; } }); } else { submitList = Lists.newArrayList(); } if (null != historyPlanList) { Collections.sort(historyPlanList, new Comparator() { @Override public int compare(AMarjorPlan o1, AMarjorPlan o2) { int iRet; if (0 != (iRet = o1.getYear().compareTo(o2.getYear()))) { return -iRet; } if (0 != (iRet = o1.getMajorName().compareTo(o2.getMajorName()))) { return -iRet; } if (null == o1.getMajorDirection()) { if (null != o2.getMajorDirection()) { return 1; } return 0; } else if (null == o2.getMajorDirection()) { return -1; } return o1.getMajorDirection().compareTo(o2.getMajorDirection()); } }); } else { historyPlanList = Lists.newArrayList(); } // 录取线 List clearings = Lists.newArrayList(); // 补录情况 List histories = Lists.newArrayList(); // 初录情况 List ruleMatchList = Lists.newArrayList(); List improveList = Lists.newArrayList(); Double tmpValue; // 总分,得分 AMarjorSubmit lastSubmit = null; Boolean typeChange = false; VoluntaryDto.FormulaScoreStat formulaScoreStat = new VoluntaryDto.FormulaScoreStat(); String needMajor = StringUtils.trimToEmpty(null != currPlan ? currPlan.getMajorName() : (null != prof ? prof.getName() : "")); String needDirect = StringUtils.trimToEmpty(null != currPlan ? currPlan.getMajorDirection() : ""); String needMajorDirect = needMajor + needDirect; // 判断是否政策变化情况 List validEuList = enrollUniversityList.stream().filter(t -> t.getMajorNames().contains(needMajor)).collect(Collectors.toList()); typeChange = CollectionUtils.isNotEmpty(validEuList) && new Integer(1).equals(validEuList.get(0).getTypeChange()); Set existSet = Sets.newHashSet(); existSet.clear(); List validSubmitList = Lists.newArrayList(); if (null != submitList) { for (AMarjorSubmit s : submitList) { // 历年录取通过专业分来判断差别 String majorNameDirect = s.getMajorName() + StringUtils.trimToEmpty(s.getMajorDirection()); if (needMajorDirect.equals(majorNameDirect) && existSet.add(needMajorDirect + s.getYear() + s.getEnrollType())) { validSubmitList.add(s); if (s.getYear().equals(submitYear) && s.getEnrollType().equals("初录") ) { lastSubmit = s; // TODO 初录,补录与分数线的关系 要处理 } } } } // 分项规则检查 existSet.clear(); Double currTotal = null; if (null != scoreList) { Double inputScoreRate = NumberUtils.toInt(paramMap.get("ScoreRate"), 0) / 100.0; List fEnrollScoreList = Lists.newArrayList(); String inclMajorDirection = needMajor + "(" + needDirect + ")"; String exclMajorDirection = needMajor + "("; Map> majorEnrollScoresMap = scoreList.stream().collect(Collectors.groupingBy(t -> StringUtils.isNotBlank(t.getMajorNames()))); List tmpEnrollScoreList = majorEnrollScoresMap.get(Boolean.TRUE); AEnrollScore skillEnrollScore = null; if (null != tmpEnrollScoreList) { for (AEnrollScore r : tmpEnrollScoreList) { if (StringUtils.isNotBlank(r.getMajorNames())) { if (!r.getMajorNames().contains(needMajor)) { continue; } if (StringUtils.isNotBlank(r.getMajorDirections())) { // 有单独的方向时,分开判断 if (StringUtils.isBlank(needDirect) || !r.getMajorDirections().contains(needDirect)) { continue; } } else if (StringUtils.isNotBlank(needDirect)) { // 有direct要求时,这里需要有 "<专业>(<方向>) if (!r.getMajorNames().contains(inclMajorDirection)) { continue; } } else if (r.getMajorNames().contains(exclMajorDirection)) { // 当无direct要求时,这时不能有 "<专业>(" continue; } } Boolean isSkillScore = isScoreOnly && r.getItemType().equals("ScoreSkill"); if(isSkillScore) { skillEnrollScore = r; } appendScoreRule(formulaScoreStat, existSet, r, fEnrollScoreList, isAi, paramMap, inputScoreRate, isSkillScore); } } if (fEnrollScoreList.size() == 0 && null != (tmpEnrollScoreList = majorEnrollScoresMap.get(Boolean.FALSE))) { for (AEnrollScore r : tmpEnrollScoreList) { Boolean isSkillScore = isScoreOnly && r.getItemType().equals("ScoreSkill"); if(isSkillScore) { skillEnrollScore = r; } appendScoreRule(formulaScoreStat, existSet, r, fEnrollScoreList, isAi, paramMap, inputScoreRate, isSkillScore); } } boolean isSameYear = null == lastSubmit || planYear.equals(lastSubmit.getYear()); currTotal = formulaScoreStat.getTypeValue("StatRateScore", "", false); for (AEnrollScore r : fEnrollScoreList) { VoluntaryDto.MajorEnrollRule mr = buildEnrollRule(r); mr.setContent(StringUtils.isNotBlank(r.getEqualFormula()) ? r.getEqualFormula() : r.getEnrollFormula()); if(isScoreOnly) { String vt; if (null != (vt = r.getValueType()) && vt.startsWith("Score")) { improveList.add(mr); mr.setCategory(VoluntaryDto.EnumRuleCategory.Enroll); mr.setType(VoluntaryDto.EnumRuleType.ScoreTotal); // mr.setValue(null != currTotal ? String.valueOf(currTotal.intValue()) : ""); if (null == lastSubmit || null == lastSubmit.getScore() || null == lastSubmit.getScoreTotal() && !isSameYear) { mr.setFailedMessage("缺历史录取数据"); continue; } mr.setYear(lastSubmit.getYear()); if (typeChange) { mr.setFailedMessage("规则变更,无法计算"); continue; } else if (!formulaScoreStat.isScoreValid() && (!isAi || inputScoreRate <= 0.0)) { mr.setFailedMessage("用户没有填写完整"); continue; } Integer validScoreTotal = isSameYear ? formulaScoreStat.getAllTotal() : lastSubmit.getScoreTotal(); Double currScoreRate = isSameYear ? 1.0 : formulaScoreStat.getAllTotal() * 1.0 / lastSubmit.getScoreTotal(); // 去年的分转成今年的分 EnrollRateCalculator.RateLevel rl; if (null != lastSubmit.getScore() && currTotal != null && null != (rl = enrollRateCalculator.satisfy(validScoreTotal, lastSubmit.getScore(), currTotal / currScoreRate))) { // 按去年标准算概率 Double skillRate = Double.parseDouble(skillEnrollScore.getValueRule()); mr.setValue(String.valueOf(Math.round(Math.round(lastSubmit.getScore() * currScoreRate) - currTotal) / skillRate)); mr.setValid(true); } else { mr.setFailedMessage("没有对应计算条件"); continue; } } else { ruleMatchList.add(mr); mr.setValid(true); } continue; } ruleMatchList.add(mr); String vt; if (null == (vt = r.getValueType())) { // 无值时相当于直接通过 mr.setValid(true); } else if (null != (vt = r.getValueType()) && vt.startsWith("Score")) { mr.setValue(null != currTotal ? String.valueOf(currTotal.intValue()) : ""); if (null == lastSubmit || null == lastSubmit.getScore() || null == lastSubmit.getScoreTotal() && !isSameYear) { mr.setFailedMessage("缺历史录取数据"); continue; } else if (typeChange) { mr.setFailedMessage("规则变更,无法计算"); continue; } else if (!formulaScoreStat.isValid() && (!isAi || inputScoreRate <= 0.0)) { mr.setFailedMessage("用户没有填写完整"); continue; } mr.setValid(true); Integer validScoreTotal = isSameYear ? formulaScoreStat.getAllTotal() : lastSubmit.getScoreTotal(); Double currScoreRate = isSameYear ? 1.0 : formulaScoreStat.getAllTotal() * 1.0 / lastSubmit.getScoreTotal(); // 去年的分转成今年的分 Double currScore = null; if (null != lastSubmit.getCulturalScore()) { if (null == (currScore = formulaScoreStat.getTypeValue("ScoreSingle", "", false))) { currScore = formulaScoreStat.getTypeValue("ScoreBase", "", false); } if (null != currScore && currScore < lastSubmit.getCulturalScore() * currScoreRate) { // mr.setValid(false); mr.setMissingValue(String.valueOf(Math.round(lastSubmit.getCulturalScore() * currScoreRate - currScore))); mr.setFailedMessage("校考分低于分数线"); } } if (null != lastSubmit.getProfScore() && null != (currScore = formulaScoreStat.getTypeValue("ScoreSkill", "", false)) && currScore < lastSubmit.getProfScore() * currScoreRate) { // mr.setValid(false); mr.setMissingValue(String.valueOf(Math.round(lastSubmit.getProfScore() * currScoreRate - currScore))); mr.setFailedMessage("技能测试分低于分数线"); } // 检查总分,学考(文化),专业(技能) EnrollRateCalculator.RateLevel rl; if (null != lastSubmit.getScore() && currTotal != null && null != (rl = enrollRateCalculator.calSchoolEnrollRate(validScoreTotal, lastSubmit.getScore(), currTotal / currScoreRate))) { // 按去年标准算概率 mr.setRl(rl); mr.setEnrollRate(rl.rate); mr.setEnrollRateText(rl.typeLabel); mr.setEnumPickType(rl.type); if (mr.getValid() && currTotal < lastSubmit.getScore() * currScoreRate) { // mr.setValid(false); mr.setMissingValue(String.valueOf(Math.round(lastSubmit.getScore() * currScoreRate - currTotal))); // 按今年的算差值 mr.setFailedMessage("综合分低于分数线"); } } } else { // 专项符合型 mr.setValid(processPassCheck(paramMap, formulaScoreStat, r.getValueRule(), mr, r.getValueType(), r.getItemField(), r.getValuePassRule())); } } } if (null != specialList) { existSet.clear(); List validSpecialList = Lists.newArrayList(); Map>> groupMutexOptionsMap = Maps.newHashMap(); for (AEnrollSpecial r : specialList) { if (StringUtils.isNotBlank(r.getGender()) && !r.getGender().equals(gender) || StringUtils.isNotBlank(r.getMajorName()) && !Sets.newHashSet(r.getMajorName().split(",")).contains(needMajor) || StringUtils.isNotBlank(r.getMajorDirection()) && !r.getMajorDirection().equals(needDirect)) { continue; } if(r.getValueType().startsWith("StatBMI")) { // TODO 身高体重的名称需要是固定的 String height = paramMap.get("身高"); String weight = paramMap.get("体重"); Integer iHeight; if (StringUtils.isNotBlank(height) && StringUtils.isNotBlank(weight) && (iHeight = NumberUtils.toInt(height, 0)) > 0) { paramMap.put(r.getItemField(), String.valueOf(NumberUtils.toInt(height, 0) * 100 / iHeight)); } } else if (null != r.getItemGroup() && "Checkbox".equals(r.getValueType())) { Pair> p = getGroupOptions(groupMutexOptionsMap, mutexOptionMap, paramMap, r.getItemGroup()); if (p.getRight().size() == 0) { // 无值时 paramMap.put(r.getItemField(), null); } else if (StringUtils.isNotBlank(p.getLeft()) && p.getRight().contains(p.getLeft())) { // 选中互斥时全是否 paramMap.put(r.getItemField(), !p.getLeft().contains("无") ? "[\"是\"]" : "[\"否\"]"); } else { paramMap.put(r.getItemField(), p.getRight().contains(r.getItemName()) ? "[\"是\"]" : "[\"否\"]"); } } validSpecialList.add(r); } for (AEnrollSpecial r : validSpecialList) { VoluntaryDto.MajorEnrollRule mr = new VoluntaryDto.MajorEnrollRule(); mr.setCategory(VoluntaryDto.EnumRuleCategory.Special); mr.setContent(r.getEnrollFormula()); mr.setDescription(r.getComment()); ruleMatchList.add(mr); if(isScoreOnly) { mr.setType(VoluntaryDto.EnumRuleType.Readonly); mr.setValid(true); continue; } mr.setType(itemType2RuleType(r.getItemType(), r.getValueType(), false)); if (VoluntaryDto.EnumRuleType.Readonly.equals(mr.getType())) { mr.setValid(true); } else { mr.setValid(processPassCheck(paramMap, formulaScoreStat, r.getValueRule(), mr, r.getValueType(), r.getItemField(), r.getValuePassRule())); } } } existSet.clear(); Map historyPlanMap = historyPlanList.stream().collect(Collectors.toMap(t -> t.getYear() + t.getMajorName() + StringUtils.trimToEmpty(t.getMajorDirection()), Function.identity())); for (AMarjorSubmit s : validSubmitList) { if ("初录".equals(s.getEnrollType())) { VoluntaryDto.MajorEnrollHistory h = new VoluntaryDto.MajorEnrollHistory(); h.setYear(s.getYear()); h.setScore(null != s.getScore() ? String.valueOf(s.getScore()) : ""); // TODO 240301 直接输出录取分 /*if (null != currTotal && null != s.getScore()) { Double diff = currTotal - s.getScore(); h.setScore(diff > 0 ? "+" + diff.intValue() : "" + diff.intValue()); // TODO 需要一个分来比较,综合分? } else { h.setScore(""); }*/ AMarjorPlan p = historyPlanMap.get(s.getYear() + s.getMajorName() + StringUtils.trimToEmpty(s.getMajorDirection())); if(null != p) { h.setPlan(p.getPlanTotal()); // TODO 估计输出录取人数 23.12.26 分开输入录取和计划 24.12.27 } else { // System.out.println(s.getId()); } h.setEnroll(s.getEnrollTotal()); histories.add(h); } else { /*VoluntaryDto.MajorClearingHistory c = new VoluntaryDto.MajorClearingHistory(); c.setYear(s.getYear()); if (null != currTotal && null != s.getScore()) { Double diff = currTotal - s.getScore(); c.setScore(diff > 0 ? "+" + diff.intValue() : "" + diff.intValue()); // TODO 需要一个分来比较,综合分? } else { c.setScore(""); } c.setRealNum(s.getEnrollTotal()); clearings.add(c);*/ // TODO 240301 关闭补录 } } VoluntaryDto.SingleResponse sr = new VoluntaryDto.SingleResponse(); sr.setUniversityCode(u.getCode()); sr.setMajorCode(null != prof ? prof.getCode() : ""); sr.setMajorName(needMajor); sr.setMajorDirection(needDirect); // 查找最高的专业 EnrollRule 为本专业的,理论上只有一个合并rule有此值 EnrollRateCalculator.RateLevel lastRl = null; boolean specialValid = true, specialPass = true; for (VoluntaryDto.MajorEnrollRule er : ruleMatchList) { if (null != er.getRl() && (null == lastRl || er.getRl().getRate() < lastRl.getRate())) { lastRl = er.getRl(); } if ((specialPass || specialValid) && VoluntaryDto.EnumRuleType.Special.equals(er.getType())) { if (null == er.getValid()) { specialValid = false; } else if (!er.getValid()) { specialPass = false; } } } if (!specialPass) { sr.setEnrollRate(0); sr.setEnrollRateText("零概率"); sr.setEnumPickEmpty(VoluntaryDto.EnumPickEmpty.EnrollPass); } else if (null != lastRl && specialValid) { sr.setEnumPickType(lastRl.getType()); sr.setEnrollRate(lastRl.getRate()); sr.setEnrollRateText(lastRl.getTypeLabel()); } else { sr.setEnrollRateText("无概率"); sr.setEnumPickEmpty(VoluntaryDto.EnumPickEmpty.New); } if (null != currPlan) { sr.setMajorGroup(currPlan.getMajorGroup()); // 没有MajorEnrollId, 暂时用这个 sr.setMajorEnrollCode(StringUtils.isBlank(currPlan.getMajorEnrollCode()) ? String.valueOf(currPlan.getId()) : currPlan.getMajorEnrollCode()); sr.setTips(null != currPlan ? currPlan.getComment() : ""); } sr.setHistories(histories); sr.setClearings(clearings); sr.setRules(ruleMatchList); sr.setImproves(improveList); sr.setScore(currTotal); if (!isScoreOnly && null != lastSubmit && null != lastSubmit.getScore() && null != currTotal && currTotal < lastSubmit.getScore()) { Double diffValue = lastSubmit.getScore() - currTotal; sr.setImproves(formulaScoreStat.getImproveScore(diffValue)); } return sr; } private void appendScoreRule(VoluntaryDto.FormulaScoreStat formulaScoreStat, Set existSet, AEnrollScore r, List fEnrollScoreList, Boolean isAi, Map paramMap, Double inputScoreRate, Boolean isSkillScore) { String vt, iv; Double currScore = null; Double scoreRate = null; Double tmpValue; // 总分,得分 if (null != (vt = r.getValueType()) && vt.startsWith("Score")) { //需要合并Score型(ScoreSingle, ScoreBase, ScoreSkill)的各类成绩, 其他为符合条件 if (existSet.add(r.getEnrollFormula())) { // 合并规则只留第一个 if (!existSet.add("_ScoreFormula_")) { existSet.remove(r.getEnrollFormula()); return; } fEnrollScoreList.add(r); } if (null != r.getValueRule() && (scoreRate = Double.parseDouble(r.getValueRule())) <= 0.0) { scoreRate = 1.0; } formulaScoreStat.addTypeTotal(r.getScoreTotal()); if (isAi && vt.equals("ScoreRate")) { // 根据得分率及总分计算分值 currScore = isSkillScore ? 0.0 : r.getScoreTotal() * inputScoreRate; formulaScoreStat.addGroup(r.getItemGroup(), currScore, r.getScoreTotal().doubleValue(), scoreRate); formulaScoreStat.addType(r.getItemType(), r.getItemField(), currScore, scoreRate); } else { currScore = (!isSkillScore && StringUtils.isNotBlank((iv = paramMap.get(r.getItemField())))) ? NumberUtils.toDouble(iv, 0.0) : 0.0; formulaScoreStat.addGroup(r.getItemGroup(), currScore, r.getScoreTotal().doubleValue(), scoreRate); formulaScoreStat.addType(r.getItemType(), r.getItemField(), currScore, scoreRate); } } else { fEnrollScoreList.add(r); } } private VoluntaryDto.MajorEnrollRule buildEnrollRule(AEnrollScore r) { VoluntaryDto.MajorEnrollRule mr = new VoluntaryDto.MajorEnrollRule(); mr.setCategory(VoluntaryDto.EnumRuleCategory.Enroll); mr.setType(itemType2RuleType(r.getItemType(), r.getValueType(), true)); // 学考 ScoreSingle 强转为 ScoreTotal, ScoreBase 校考, ScoreSkill 技能, Special 专项 mr.setContent(r.getEnrollFormula()); mr.setImproveType(r.getItemCategory()); mr.setDescription(r.getComment()); return mr; } private Pair> getGroupOptions(Map>> groupOptionsMap, Map mutexOptionMap, Map paramMap, String itemGroup) { String[] groupNameField = StringUtils.split(itemGroup, "_"); String groupFieldName = groupNameField[groupNameField.length > 1 ? 1 : 0]; Pair> pair = groupOptionsMap.get(groupFieldName); if(null == pair) { String iv = paramMap.get(groupFieldName); Set options = StringUtils.isNotBlank(iv) ? JSONArray.parseArray(iv).stream().map(t -> (String) t).collect(Collectors.toSet()) : Sets.newHashSet(); pair = new MutablePair<>(mutexOptionMap.get(groupFieldName), options); groupOptionsMap.put(groupFieldName, pair); } return pair; } private Boolean processPassCheck(Map paramMap, VoluntaryDto.FormulaScoreStat stat, String valueRule, VoluntaryDto.MajorEnrollRule mr, String valueType, String itemField, String passRule) { Boolean matched = null; Double tmpValue; boolean isStat = null != valueType && valueType.startsWith("Stat"); if (isStat || NumberTypeSet.contains(valueType)) { Double v = null; String iv; if (isStat) { // TODO 统计分 v = stat.getTypeValue(valueType, itemField, "0".equals(valueRule)); } else if(StringUtils.isNotBlank(passRule) && StringUtils.isNotBlank((iv = paramMap.get(itemField))) && (tmpValue = NumberUtils.toDouble(iv, 0.0)) > 0.01) { v = tmpValue; } if (v != null) { String[] range = passRule.split("-"); if (StringUtils.isNotBlank(range[0]) && (tmpValue = NumberUtils.toDouble(range[0], 0.0)) > 0.01 && v < tmpValue) { matched = false; mr.setFailedMessage("小于最大值"); } else if (range.length > 1 && StringUtils.isNotBlank(range[1]) && (tmpValue = NumberUtils.toDouble(range[1], 0.0)) > 0.01 && v > tmpValue) { matched = false; mr.setFailedMessage("超过最大值"); } else { matched = true; } } else { mr.setFailedMessage("未输入参数"); } } else if ("Radio".equals(valueType)) { String iv = paramMap.get(itemField); if (StringUtils.isNotBlank(iv)) { if (!(matched = StringUtils.isNotBlank(passRule) && passRule.contains(iv))) { mr.setFailedMessage("条件不满足"); } } else { mr.setFailedMessage("未输入参数"); } } else if ("Checkbox".equals(valueType) || "Picker".equals(valueType)) { String iv = paramMap.get(itemField); if(StringUtils.isBlank(passRule)) { if (!(matched = StringUtils.isBlank(iv))) { mr.setFailedMessage("选择条件不满足1"); } } else if (StringUtils.isNotBlank(iv)) { List valueList = Arrays.asList(passRule.split(",")); List inputList = JSONArray.parseArray(iv).stream().map(t -> (String) t).collect(Collectors.toList()); if (!(matched = CollectionUtils.intersection(valueList, inputList).size() == valueList.size())) { mr.setFailedMessage("选择条件不满足2"); } } } return matched; } private void sortAndExtractEnroll(List singleResponseList, VoluntaryDto.AIResponse aiResp) { if (CollectionUtils.isEmpty(singleResponseList)) { aiResp.setEnrollRate(null); aiResp.setEnrollRateText("无概率"); aiResp.setEnumPickEmpty(VoluntaryDto.EnumPickEmpty.EnrollPass); } Collections.sort(singleResponseList, new Comparator() { @Override public int compare(VoluntaryDto.SingleResponse o1, VoluntaryDto.SingleResponse o2) { Integer d1 = o1.getEnrollRate(); Integer d2 = o2.getEnrollRate(); if (null == d1) { if (null != d2) { return 1; } return 0; } else if (null == d2) { return -1; } return -d1.compareTo(d2); } }); for (VoluntaryDto.SingleResponse sr : singleResponseList) { aiResp.setEnrollRate(sr.getEnrollRate()); aiResp.setEnrollRateText(sr.getEnrollRateText()); aiResp.setEnumPickType(sr.getEnumPickType()); aiResp.setEnumPickEmpty(sr.getEnumPickEmpty()); break; } } public R getVoluntaryConfig() { // 如果有填报配置相关,放在这里 VoluntaryDto.VoluntaryConfig resp = new VoluntaryDto.VoluntaryConfig(); return R.ok(resp); } public List getVoluntaryList(@ApiParam @RequestParam VoluntaryDto.EnumVoluntaryType type) { // 我的志愿表 // 后台填充快照缺省 AWishRecord cond = new AWishRecord(); cond.setUserId(SecurityUtils.getLoginUser().getUserId()); if (null != type) { cond.setType(type.name()); } cond.setStatus(1); List aWishRecordList = aWishRecordMapper.selectAWishRecordList(cond); List dtoList = Lists.newArrayList(); aWishRecordList.stream().forEach(t -> { dtoList.add(toModel(t)); }); return PageUtil.getDtoListWithPageable(aWishRecordList, dtoList); } public R submitVoluntary(JSONObject model) { // 填报 // 前端+后台按需要剔除一些不需快照的信息(目前主要是院校信息) SysUser user = SecurityUtils.getLoginUser().getUser(); AWishRecord wishRecord = new AWishRecord(); VoluntaryDto.User userSnapshot = new VoluntaryDto.User(); userSnapshot.setName(user.getNickName()); userSnapshot.setSex(user.getSex()); userSnapshot.setExamType(user.getExamType().title()); // TODO MF userSnapshot.setProvinceName(user.getLocation()); Long modelId = null; String modelName = null; Integer year = null; VoluntaryDto.EnumVoluntaryType type = null; try { modelId = model.getLong("id"); modelName = model.getString("name"); year = model.getInteger("year"); type = VoluntaryDto.EnumVoluntaryType.valueOf(model.getString("voluntaryType")); wishRecord.setBatchName(model.getString("batchName")); wishRecord.setRequest(model.getString("request")); wishRecord.setDetails(model.getString("details")); wishRecord.setUserSnapshot(mapper.writeValueAsString(userSnapshot)); } catch (JsonProcessingException e) { return R.fail("格式错误: " + modelId); } wishRecord.setYear(null == year ? getPlanYear(user) : year); wishRecord.setType(type.name()); if (null != modelId) { wishRecord.setUpdateTime(new Date()); wishRecord.setId(modelId); wishRecord.setName(modelName); wishRecord.setUpdateTime(new Date()); aWishRecordMapper.updateAWishRecord(wishRecord); } else { wishRecord.setCreateTime(new Date()); wishRecord.setSeq(getWishSeq(wishRecord.getYear(), wishRecord.getType())); wishRecord.setName(StringUtils.isNotBlank(modelName) ? modelName : ("AI".equals(wishRecord.getType()) ? "AI志愿" : "模拟志愿") + wishRecord.getSeq()); wishRecord.setUserId(user.getUserId()); wishRecord.setStatus(1); aWishRecordMapper.insertAWishRecord(wishRecord); } return R.ok(wishRecord.getId()); } private Integer getWishSeq(Integer year, String type) { AWishRecord cond = new AWishRecord(); cond.setUserId(SecurityUtils.getLoginUser().getUserId()); cond.setYear(year); cond.setType(type); List aWishRecordList = aWishRecordMapper.selectAWishRecordList(cond); Integer newSeq = CollectionUtils.isNotEmpty(aWishRecordList) ? aWishRecordList.get(0).getSeq() + 1 : 1; return newSeq; } public void obsoleteWishRecord(Long userId) { aWishRecordMapper.updateObsoleteByUser(userId); busiWishRecordsMapper.updateObsoleteByUser(userId); } public R getVoluntary(Long id) { // 志愿表详情 // 后台填充快照缺省 SysUser user = SecurityUtils.getLoginUser().getUser(); AWishRecord wishRecord = aWishRecordMapper.selectAWishRecordById(id); if (null == wishRecord || !SecurityUtils.getUserId().equals(wishRecord.getUserId())) { return R.fail("错误id"); } if (null == wishRecord) { throw new ServiceException("无此志愿id"); } else if (!user.getUserId().equals(wishRecord.getUserId())) { throw new ServiceException("无此志愿id号"); } JSONObject resp = toModel(wishRecord); return R.ok(resp); } private JSONObject toModel(AWishRecord wishRecord) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); JSONObject model = new JSONObject(); model.put("id", wishRecord.getId()); model.put("year", wishRecord.getYear()); model.put("voluntaryType", VoluntaryDto.EnumVoluntaryType.valueOf(wishRecord.getType())); model.put("name", wishRecord.getName()); model.put("batchName", wishRecord.getBatchName()); model.put("createTime", sdf.format(wishRecord.getCreateTime())); try { model.put("userSnapshot", mapper.readValue(wishRecord.getUserSnapshot(), VoluntaryDto.User.class)); model.put("request", JSONObject.parseObject(wishRecord.getRequest())); model.put("details", JSONArray.parseArray(wishRecord.getDetails())); } catch (JsonProcessingException e) { e.printStackTrace(); } return model; } private VoluntaryDto.SingleResponse buildTestResp() { String json = sysConfigService.selectConfigByKey("demo.voluntary.single"); if (StringUtils.isNotBlank(json)) { try { return mapper.readValue(json, VoluntaryDto.SingleResponse.class); } catch (JsonProcessingException e) { e.printStackTrace(); } } return new VoluntaryDto.SingleResponse(); } private VoluntaryDto.AIResponse buildAiResp() { String json = sysConfigService.selectConfigByKey("demo.voluntary.ai"); if (StringUtils.isNotBlank(json)) { try { VoluntaryDto.AIResponse resp = mapper.readValue(json, VoluntaryDto.AIResponse.class); resp.setMajorDetails(Lists.newArrayList(buildTestResp())); return resp; } catch (JsonProcessingException e) { e.printStackTrace(); } } return new VoluntaryDto.AIResponse(); } private VoluntaryDto.VoluntaryModel buildModel() { String json = sysConfigService.selectConfigByKey("demo.voluntary.model"); if(StringUtils.isNotBlank(json)) { try { VoluntaryDto.VoluntaryModel model = mapper.readValue(json, VoluntaryDto.VoluntaryModel.class); model.setDetails(Lists.newArrayList(buildAiResp())); return model; } catch (JsonProcessingException e) { e.printStackTrace(); } } return new VoluntaryDto.VoluntaryModel(); } private VoluntaryDto.EnumRuleType itemType2RuleType(String itemType, String valueType, boolean foreSingleTotal) { if ("Notice".equals(valueType)) { return VoluntaryDto.EnumRuleType.Readonly; } else if (foreSingleTotal && VoluntaryDto.EnumRuleType.ScoreSingle.name().equals(itemType)) { return VoluntaryDto.EnumRuleType.ScoreTotal; } return VoluntaryDto.EnumRuleType.valueOf(itemType); } }