소스 검색

新志愿接口适配

mingfu 20 시간 전
부모
커밋
ef14277c86

+ 1 - 1
ie-admin/src/main/java/com/ruoyi/web/controller/front/FrontSyMajorRelationController.java

@@ -74,7 +74,7 @@ public class FrontSyMajorRelationController extends BaseController {
         UniversitiesCondDTO cond = new UniversitiesCondDTO();
         cond.setMajorCodes(code);
         //是否收藏
-        return universitiesController.getUniversitiesList(cond,VistorContextHolder.getLocation(),pageNum,pageSize);
+        return getDataTable(universitiesController.getUniversitiesList(cond,VistorContextHolder.getLocation(),pageNum,pageSize));
     }
 
     @GetMapping("getMajorOverviewByCode")

+ 56 - 15
ie-admin/src/main/java/com/ruoyi/web/controller/front/FrontUniversitiesController.java

@@ -1,7 +1,9 @@
 package com.ruoyi.web.controller.front;
 
 import com.alibaba.fastjson.JSONObject;
-import com.ruoyi.common.annotation.Anonymous;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.entity.SysDictData;
@@ -23,14 +25,14 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.math.NumberUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 @RestController
 @Api(tags = "前端-三库-院校库")
@@ -57,6 +59,16 @@ public class FrontUniversitiesController extends BaseController {
     private IBBusiWishUniversitySubmitRecruitPlanService wishUniversitySubmitRecruitPlanService;
     @Autowired
     private CommService commService;
+    private final Map<String, String> tierDescMap = Maps.newHashMap();
+
+    public FrontUniversitiesController() {
+        tierDescMap.put("1", "文化分280分以上");
+        tierDescMap.put("2", "文化分270分以上");
+        tierDescMap.put("3", "文化分260分以上");
+        tierDescMap.put("4", "文化分250分以上");
+        tierDescMap.put("5", "文化分240分以上");
+        tierDescMap.put("6", "文化分230分以上");
+    }
 
     @GetMapping("filters")
     @ApiOperation("00 院校列表数据筛选项")
@@ -75,6 +87,11 @@ public class FrontUniversitiesController extends BaseController {
         map.entrySet().stream().sorted(Map.Entry.comparingByKey());
 //                .forEachOrdered(x -> map.put(x.getKey(), x.getValue()));
         data.put("stars", map);
+        //梯次
+        Map<String,String> tierMap = dictTypeService.selectDictDataByType("tier_type")
+                .stream().collect(Collectors.toMap(t -> t.getDictValue(), SysDictData::getDictLabel));
+        map.entrySet().stream().sorted(Map.Entry.comparingByKey());
+        data.put("tiers", tierMap);
         return AjaxResult.success(data);
     }
 
@@ -112,7 +129,35 @@ public class FrontUniversitiesController extends BaseController {
     @ApiOperation("01 院校列表")
     public TableDataInfo listNoToken(UniversitiesCondDTO cond, @ApiParam(value = "页数", example = "1") @RequestParam Integer pageNum,
                                      @ApiParam(value = "页大小", example = "15") @RequestParam Integer pageSize) {
-        return getUniversitiesList(cond,null,  pageNum, pageSize);
+        return getDataTable(getUniversitiesList(cond,null,  pageNum, pageSize));
+    }
+
+    @GetMapping("listByTier")
+    @ApiOperation("01 分级院校列表")
+    public TableDataInfo listByTier(UniversitiesCondDTO cond) {
+        String location = VistorContextHolder.getLocation();
+        if(StringUtils.isNotBlank(location)){
+            location = location+",全国";
+        }
+        List<JSONObject> tierList = Lists.newArrayList();
+        List<BBusiWishUniversities> arr = getUniversitiesList(cond,location,  -1, 15);
+        Map<Integer, List<BBusiWishUniversities>> tierMap = arr.stream().filter(t -> null != t.getTier())
+                .collect(Collectors.groupingBy(BBusiWishUniversities::getTier, Collectors.toList()));
+        List<SysDictData> tierTypeList = dictTypeService.selectDictDataByType("tier_type");
+        Set<String> tierSet = Sets.newHashSet(Arrays.asList((StringUtils.isBlank(cond.getTiers()) ? "1,2,3,4" : cond.getTiers()).split(",")));
+        for(SysDictData dd : tierTypeList) {
+            if(!tierSet.contains(dd.getDictValue())) {
+                continue;
+            }
+            List<BBusiWishUniversities> uList = tierMap.get(NumberUtils.toInt(dd.getDictValue()));
+            JSONObject tierUniversities = new JSONObject();
+            tierUniversities.put("typeName", dd.getDictLabel());
+            tierUniversities.put("typeValue", dd.getDictValue());
+            tierUniversities.put("desc", tierDescMap.get(dd.getDictValue()));
+            tierUniversities.put("list", uList);
+            tierList.add(tierUniversities);
+        }
+        return getDataTable(tierList);
     }
 
     @GetMapping("list")
@@ -123,23 +168,19 @@ public class FrontUniversitiesController extends BaseController {
         if(StringUtils.isNotBlank(location)){
             location = location+",全国";
         }
-        return getUniversitiesList(cond,location,  pageNum, pageSize);
+        return getDataTable(getUniversitiesList(cond,location,  pageNum, pageSize));
     }
 
-    public TableDataInfo getUniversitiesList(UniversitiesCondDTO cond,String location, Integer pageNum,Integer pageSize){
+    public List<BBusiWishUniversities> getUniversitiesList(UniversitiesCondDTO cond,String location, Integer pageNum,Integer pageSize){
         if (StringUtils.isNumber(cond.getName())) {
             cond.setCode(cond.getName());
             cond.setName(null);
         }
-        if (null != cond.getFilterRank() && cond.getFilterRank()) {
-            cond.setOrderBy(" star desc, code");
-        } else {
-            cond.setFilterRank(null);
-            cond.setOrderBy(StringUtils.isNotBlank(cond.getOrderBy()) ? cond.getOrderBy() : "code");
-        }
         SysUser user = SecurityUtils.getLoginUser().getUser();
         cond.setEnrollLocation(user.getLocation());
-        startPage();
+        if (null != pageNum && pageNum >= 0) {
+            startPage();
+        }
         List<BBusiWishUniversities> arr;
         Integer planYear = voluntaryService.getPlanYear(user);
         if(Constant.EXAM_TYPE_ZG.equals(user.getExamType().title())) {
@@ -154,7 +195,7 @@ public class FrontUniversitiesController extends BaseController {
                 t.setStar(dictTypeService.getDictDataByType("university_stars",t.getStar()));
             }
         });
-        return getDataTable(arr);
+        return arr;
     }
 
     @GetMapping("detail")

+ 92 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/ie/VoluntaryController.java

@@ -1,7 +1,9 @@
 package com.ruoyi.web.controller.ie;
 
+import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
@@ -50,6 +52,96 @@ public class VoluntaryController extends BaseController {
         return voluntaryService.getAIRenderRules(req);
     }
 
+    @PostMapping("voluntary/getRenderRules")
+    @ApiOperation("查询志愿规则")
+    public R<List<VoluntaryDto.RenderRule>> getRenderRules(@RequestBody VoluntaryDto.RenderRequest req) {
+        req.setRenderType(0);
+        return voluntaryService.getRenderRules(req);
+    }
+
+    @PostMapping("voluntary/getSkillRules")
+    @ApiOperation("查询技能分规则")
+    public R<List<VoluntaryDto.RenderRule>> getSkillRules(@RequestBody VoluntaryDto.RenderRequest req) {
+        req.setRenderType(2);
+        return voluntaryService.getRenderRules(req);
+    }
+
+    @PostMapping("/voluntary/postRenderRules")
+    @ApiOperation("单院校专业结果")
+    public R<VoluntaryDto.RenderMajorResult> postRenderRules(@RequestBody String data) {
+        // commService.requireVip();
+
+        VoluntaryDto.SingleRequest req = new VoluntaryDto.SingleRequest();
+        JSONObject root = JSONObject.parseObject(data);
+        Map<String, String> form = req.getForm();
+        for(String key : root.keySet()) {
+            JSONObject sub = root.getJSONObject(key);
+            for (String field : sub.keySet()) {
+                form.put(field, sub.getString(field));
+            }
+        }
+        req.setUniversityCode(form.remove("universityId"));
+        req.setMajorEnrollCode(form.remove("majorId"));
+        return voluntaryService.postRenderResult(req, false);
+    }
+
+    @GetMapping("voluntary/getVoluntaryList")
+    @ApiOperation("查询志愿列表")
+    public TableDataInfo voluntaryList(@ApiParam @RequestParam Integer pageNum, @ApiParam @RequestParam Integer pageSize) { // 我的志愿表 // 后台填充快照缺省
+        List<VoluntaryDto.VoluntaryRecord> list = voluntaryService.getVoluntaryList2();
+        return getDataTable(list);
+    }
+
+    @PostMapping("voluntary/addVoluntary")
+    @ApiOperation("填报志愿")
+    public R<Long> addVoluntary(@RequestBody String body) { // 填报 // 前端+后台按需要剔除一些不需快照的信息(目前主要是院校信息)
+        JSONObject model = JSONObject.parseObject(body);
+        return voluntaryService.addVoluntary2(model);
+    }
+
+    @Log(title = "志愿删除院校", businessType = BusinessType.DELETE)
+    @DeleteMapping("voluntary/removeVoluntaryByUniversity/{universityId}")
+    public AjaxResult removeVoluntaryByUniversity(@PathVariable Long universityId)
+    {
+        return toAjax(voluntaryService.removeVoluntaryByUniversity(SecurityUtils.getLoginUser().getUserId(), universityId));
+    }
+
+    @Log(title = "志愿删除专业", businessType = BusinessType.DELETE)
+    @DeleteMapping("voluntary/removeVoluntaryByMajor/{majorId}")
+    public AjaxResult removeVoluntaryByMajor(@PathVariable Long majorId)
+    {
+        return toAjax(voluntaryService.removeVoluntaryByMajor(SecurityUtils.getLoginUser().getUserId(), majorId));
+    }
+
+    @PostMapping("voluntary/sortVoluntaryByMajor")
+    @ApiOperation("志愿专业排序")
+    public R sortVoluntaryByMajor(@RequestBody String body) { // 填报 // 前端+后台按需要剔除一些不需快照的信息(目前主要是院校信息)
+        JSONObject model = JSONObject.parseObject(body);
+        JSONArray list = model.getJSONArray("majorIdList");
+        Map<Long, Integer> majorRankMap = Maps.newHashMap();
+        for (int i = 0; i < list.size(); i++) {
+            majorRankMap.put(list.getLong(i), i);
+        }
+        voluntaryService.sortVoluntaryByMajor(SecurityUtils.getUserId(), model.getLong("universityId"), majorRankMap);
+        return R.ok();
+    }
+
+    @PostMapping("voluntary/sortVoluntaryByUniversity")
+    @ApiOperation("志愿院校排序")
+    public R sortVoluntaryByUniversity(@RequestBody String body) { // 填报 // 前端+后台按需要剔除一些不需快照的信息(目前主要是院校信息)
+        JSONObject model = JSONObject.parseObject(body);
+        JSONArray list = model.getJSONArray("universityIdList");
+        Map<Long, Integer> universityRankMap = Maps.newHashMap();
+        for (int i = 0; i < list.size(); i++) {
+            universityRankMap.put(list.getLong(i), i);
+        }
+        voluntaryService.sortVoluntaryByUniversity(SecurityUtils.getUserId(), universityRankMap);
+        return R.ok();
+    }
+
+
+
+
     @PostMapping("postSingleResultSample")
     @ApiOperation("单院校专业结果")
     public R<VoluntaryDto.SingleResponse> postSingleResultSample(@RequestBody VoluntaryDto.SingleRequest req) {

+ 105 - 0
ie-admin/src/main/java/com/ruoyi/web/domain/VoluntaryDto.java

@@ -9,7 +9,9 @@ import com.ruoyi.syzy.domain.BBusiWishUniversities;
 import com.ruoyi.web.service.EnrollRateCalculator;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 import org.apache.commons.compress.utils.Lists;
 import org.apache.commons.lang3.tuple.MutablePair;
 import org.apache.commons.lang3.tuple.Triple;
@@ -20,6 +22,108 @@ import java.util.Map;
 import java.util.Set;
 
 public class VoluntaryDto {
+
+    @Data
+    @ApiModel
+    public static class VoluntaryRecord extends RenderRequest {
+        Long id;
+        String universityLogo;
+        Long universityId;
+        String universityName;
+        Integer rank;
+        List<VoluntaryMajorRecord> majors = Lists.newArrayList();
+    }
+
+    @Data
+    @ApiModel
+    public static class VoluntaryMajorRecord extends RenderRequest {
+        Long majorId;
+        String majorName;
+        String majorAncestors;
+        String majorGroup;
+        Integer rank;
+    }
+
+    @Data
+    @ApiModel
+    public static class RenderRequest {
+        @ApiModelProperty("0 render; 2. Skill")
+        int renderType;
+        @ApiModelProperty("院校专业")
+        Long majorId;
+        @ApiModelProperty("院校ID")
+        Long universityId;
+    }
+
+    @Data
+    @ApiModel
+    @AllArgsConstructor
+    @NoArgsConstructor
+    public static class RenderRule {
+        @ApiModelProperty("类型")
+        String category;
+        @ApiModelProperty("描述")
+        String content;
+        @ApiModelProperty("规则列表")
+        List<AIRenderRule> details = Lists.newArrayList();
+    }
+
+    @Data
+    @ApiModel
+    public static class RenderMajorResult extends RenderRequest {
+        @ApiModelProperty
+        EnumPickType enumPickType;
+        @ApiModelProperty
+        Integer enrollRate; // 100进制,按原优志愿,为null表示无概率
+        @ApiModelProperty
+        String enrollRateText; // 概率描述,按原优志愿
+
+        @ApiModelProperty
+        List<RenderMajorHistory> histories = Lists.newArrayList();
+
+        @ApiModelProperty
+        RenderMajorSkill skill;
+    }
+
+    @Data
+    @ApiModel
+    public static class RenderMajorHistory {
+        @ApiModelProperty
+        Integer year; // 年份
+        @ApiModelProperty
+        String score; // 最低分
+        @ApiModelProperty
+        Integer plan; // 计划人数
+        @ApiModelProperty
+        Integer enroll; // 录取人数
+        @ApiModelProperty
+        Integer diff; // 负表示低于录取分;正数表示高于录取分
+        @ApiModelProperty
+        String ruleContent; // 完整的说明
+        @ApiModelProperty
+        String application; // 报名人数比值
+        @ApiModelProperty
+        String admission; // 计划人数比值
+    }
+
+    @Data
+    @ApiModel
+    public static class RenderMajorSkill {
+        @ApiModelProperty
+        Integer year; // 年份
+        @ApiModelProperty
+        String cultureScore; // 文化得分
+        @ApiModelProperty
+        String cultureRule; // 文化规则
+        @ApiModelProperty
+        String enrollScore; // 录取分
+        @ApiModelProperty
+        String skillScore; // 反向测技能分
+        @ApiModelProperty
+        String diff; // 负数表示低于skillScore,正数高于
+    }
+
+
     // dynamic render rules
     // TODO: 部分规则不需要向前端返回:比如性别与考生类别,此类信息直接在当前用户中获取
     // 只需要向前端返回需要收集信息的部分
@@ -57,6 +161,7 @@ public class VoluntaryDto {
         String defaultValue; // 缺省/初始化时的默认值
         Boolean dotDisable; // 数值输入时,是否带小数点,默认带
         String keyboardMode; // 当enumInputType==number时响应3种模式:number card car,默认number
+        Boolean readonly;
     }
 
     @Data

+ 1 - 0
ie-admin/src/main/java/com/ruoyi/web/service/PaperService.java

@@ -374,6 +374,7 @@ public class PaperService {
                 }
                 qg.getSubQuestions().add(qs);
             } else {
+                qs.setTypeTitle(lqs.getPaperTypeTitle());
                 paperQuestionList.add(qs);
             }
         }

+ 122 - 0
ie-admin/src/main/java/com/ruoyi/web/service/VoluntaryRuleHelper.java

@@ -0,0 +1,122 @@
+package com.ruoyi.web.service;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.ie.domain.AEnrollScore;
+import com.ruoyi.ie.domain.AMarjorPlan;
+import com.ruoyi.ie.domain.AMarjorSubmit;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class VoluntaryRuleHelper {
+
+
+    public boolean isMatchMajor(AEnrollScore r, String needMajor, String needDirect, String inclMajorDirection, String exclMajorDirection) {
+        if (StringUtils.isNotBlank(r.getMajorNames())) {
+            if (!r.getMajorNames().contains(needMajor)) {
+                return false;
+            }
+            if (StringUtils.isNotBlank(r.getMajorDirections())) { // 有单独的方向时,分开判断
+                if (StringUtils.isBlank(needDirect) || !r.getMajorDirections().contains(needDirect)) {
+                    return false;
+                }
+            } else if (StringUtils.isNotBlank(needDirect)) { // 有direct要求时,这里需要有 "<专业>(<方向>)
+                if (!r.getMajorNames().contains(inclMajorDirection)) {
+                    return false;
+                }
+            } else if (r.getMajorNames().contains(exclMajorDirection)) { // 当无direct要求时,这时不能有 "<专业>("
+                return false;
+            }
+        }
+        return true;
+    }
+    public Map<Boolean, List<AEnrollScore>> buildMajorEnrollScoresMap(List<AEnrollScore> scoreList, String needGroup) {
+        Map<Boolean, List<AEnrollScore>> majorEnrollScoresMap = scoreList.stream()
+                .filter(t -> needGroup.equals(StringUtils.trimToEmpty(t.getMajorGroups())))
+                .collect(Collectors.groupingBy(t -> StringUtils.isNotBlank(t.getMajorNames())));
+        if(majorEnrollScoresMap.isEmpty() && StringUtils.isNotBlank(needGroup)) {
+            majorEnrollScoresMap = scoreList.stream()
+                    .filter(t -> StringUtils.isBlank(t.getMajorGroups()))
+                    .collect(Collectors.groupingBy(t -> StringUtils.isNotBlank(t.getMajorNames())));
+
+        }
+        return majorEnrollScoresMap;
+    }
+
+    public List<AMarjorSubmit> filtValidSubmits(String needMajorDirect, List<AMarjorSubmit> submitList, Set<String> existSet) {
+        List<AMarjorSubmit> validSubmitList = Lists.newArrayList();
+        if (null != submitList) {
+            for (AMarjorSubmit s : submitList) { // 历年录取通过专业分来判断差别
+                String majorNameDirect = s.getMajorName() + StringUtils.trimToEmpty(s.getMajorDirection());
+                if (null != s.getScore() && needMajorDirect.equals(majorNameDirect) && existSet.add(needMajorDirect + s.getYear() + s.getEnrollType())) {
+                    validSubmitList.add(s);
+                }
+            }
+        }
+        return validSubmitList;
+    }
+
+    public List<AMarjorPlan> sortPlans(List<AMarjorPlan> historyPlanList) {
+        if (null != historyPlanList) {
+            Collections.sort(historyPlanList, new Comparator<AMarjorPlan>() {
+                @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();
+        }
+        return historyPlanList;
+    }
+    /**
+     *
+     * @param submitList
+     * @return
+     */
+    public List<AMarjorSubmit> sortSubmits(List<AMarjorSubmit> submitList) {
+        if (null != submitList) {
+            Collections.sort(submitList, new Comparator<AMarjorSubmit>() {
+                @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();
+        }
+        return submitList;
+    }
+}

+ 473 - 0
ie-admin/src/main/java/com/ruoyi/web/service/VoluntaryService.java

@@ -14,9 +14,12 @@ import com.ruoyi.common.core.content.VistorContextHolder;
 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.enums.ExamType;
+import com.ruoyi.common.enums.SubjectType;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.dz.SubjectScore;
 import com.ruoyi.ie.domain.*;
 import com.ruoyi.ie.mapper.*;
 import com.ruoyi.system.service.ISysConfigService;
@@ -29,6 +32,7 @@ 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.ApiModelProperty;
 import io.swagger.annotations.ApiParam;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.MapUtils;
@@ -43,6 +47,7 @@ import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 @Service
 public class VoluntaryService {
@@ -50,6 +55,7 @@ public class VoluntaryService {
     private static TypeReference<List<VoluntaryDto.SingleResponse>> wishDetailsTypeReference = new TypeReference<List<VoluntaryDto.SingleResponse>>() { };
     private static TypeReference<List<VoluntaryDto.AIResponse>> wishAiDetailsTypeReference = new TypeReference<List<VoluntaryDto.AIResponse>>() { };
     Set<String> NumberTypeSet = Sets.newHashSet(VoluntaryDto.EnumInputType.Number.name(), VoluntaryDto.EnumInputType.Eyesight.name(), VoluntaryDto.EnumInputType.Score.name());
+    private static VoluntaryRuleHelper voluntaryRuleHelper = new VoluntaryRuleHelper();
 
     private final AWishRecordMapper aWishRecordMapper;
     private final AEnrollScoreMapper aEnrollScoreMapper;
@@ -152,6 +158,255 @@ public class VoluntaryService {
         return 2025;
     }
 
+    public R<VoluntaryDto.RenderMajorResult> postRenderResult(VoluntaryDto.SingleRequest req, Boolean isScoreOnly) {
+        Integer planYear = getPlanYear(SecurityUtils.getLoginUser().getUser());
+        Integer submitYear = getSubmitYear();
+        String examType = VistorContextHolder.getExamType().title(); // TODO MF
+        String gender = "0".equals(SecurityUtils.getLoginUser().getUser().getSex()) ? "男生" : "女生";
+        Map cond = new HashMap();
+        cond.put("universityCode", req.getUniversityCode());
+        cond.put("examineeType", examType);
+        Map<Long, List<AMarjorPlan>> currUniversityMajorPlansMap = Maps.newHashMap();
+        Map<Long, List<AMarjorPlan>> historyUniversityMajorPlansMap = Maps.newHashMap();
+        List<Map<Long, List<AMarjorPlan>>> bothPlanList = Lists.newArrayList(currUniversityMajorPlansMap, historyUniversityMajorPlansMap);
+        Set<String> existSet = Sets.newHashSet();
+        Long planId = NumberUtils.toLong(req.getMajorEnrollCode(), 0L);
+        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<Long, List<AMarjorPlan>> tmpMap : bothPlanList) {
+                boolean isCurrYear = mp.getYear().equals(planYear);
+                if (tmpMap == currUniversityMajorPlansMap) {
+                    if(!isCurrYear || !mp.getId().equals(planId)) {
+                        continue;
+                    }
+                } else if(mp.getYear() > submitYear) {
+                    continue;
+                }
+                List<AMarjorPlan> tmpMpList = tmpMap.get(mp.getUniversityId());
+                if (null == tmpMpList) {
+                    tmpMpList = Lists.newArrayList(mp);
+                    tmpMap.put(mp.getUniversityId(), tmpMpList);
+                } else {
+                    tmpMpList.add(mp);
+                }
+            }
+        }
+        Map<Long, List<BBusiWishUniversitiesProfession>> universityMajorsMap = Maps.newHashMap();
+        // 有计划以计划为准的输出,无计划时则以所有专业输出为准
+        Map<Long, BBusiWishUniversities> universitiesMap = null;
+        if (MapUtils.isEmpty(currUniversityMajorPlansMap)) {
+            Map<String, List<BBusiWishUniversitiesProfession>> 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<String, List<BBusiWishUniversitiesProfession>> 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 R.fail("无计划院校专业");
+        }
+        // 查询涉及的规则
+        cond.put("year", planYear);
+        cond.put("universityIds", universitiesMap.keySet());
+        Map<Long, List<AEnrollScore>> universityScoreListMap = aEnrollScoreMapper.selectListByRuleCond(cond).stream().collect(Collectors.groupingBy(AEnrollScore::getUniversityId));
+        cond.remove("universityIds");
+        cond.remove("year");
+
+        Map<String, String> mutexOptionMap = getMutexOptionMap();
+        for (Long universityId : universitiesMap.keySet()) {
+            List<AEnrollScore> scoreList = universityScoreListMap.get(universityId); // 分数条件
+            List<AMarjorPlan> currPlanList = currUniversityMajorPlansMap.get(universityId);// 当年计划
+            List<AMarjorPlan> historyPlanList = historyUniversityMajorPlansMap.get(universityId);// 历年计划
+            BBusiWishUniversities u = universitiesMap.get(universityId);// 院校
+            List<BBusiWishUniversitiesProfession> professionList = universityMajorsMap.get(u.getId()); // 所有专业
+            // 院校变更标志
+            AEnrollUniversity euCond = new AEnrollUniversity();
+            euCond.setUniversityId(u.getId());
+            euCond.setYear(planYear);
+            List<AEnrollUniversity> enrollUniversityList = aEnrollUniversityMapper.selectAEnrollUniversityList(euCond);
+            // 院校历史情况
+            AMarjorSubmit submitCond = new AMarjorSubmit();
+            submitCond.setExamineeType(examType);
+            submitCond.setUniversityId(universityId);
+            List<AMarjorSubmit> submitList = aMarjorSubmitMapper.selectAMarjorSubmitList(submitCond);
+
+            VoluntaryDto.RenderMajorResult sr;
+            if (CollectionUtils.isNotEmpty(currPlanList)) {
+                Map<String, BBusiWishUniversitiesProfession> professionMap = null == professionList ? Maps.newHashMap() : professionList.stream().collect(Collectors.toMap(BBusiWishUniversitiesProfession::getName, Function.identity()));
+                for (AMarjorPlan mp : currPlanList) { // 只有一个
+                    if (null != (sr = buildRenderResponse(submitYear, planYear, gender, mp, professionMap.get(mp.getMajorName()), enrollUniversityList, req.getForm(), u,
+                            historyPlanList, submitList, scoreList, mutexOptionMap, isScoreOnly))) {
+                        sr.setUniversityId(universityId);
+                        sr.setMajorId(planId);
+                        return R.ok(sr);
+                    }
+                }
+            }
+        }
+        return R.fail("无计划院校专业");
+    }
+
+    private VoluntaryDto.RenderMajorResult buildRenderResponse(Integer submitYear, Integer planYear, String gender, AMarjorPlan currPlan, BBusiWishUniversitiesProfession prof,
+                                                            List<AEnrollUniversity> enrollUniversityList, Map<String, String> paramMap, BBusiWishUniversities u,
+                                                            List<AMarjorPlan> historyPlanList, List<AMarjorSubmit> submitList,
+                                                            List<AEnrollScore> scoreList, Map<String,String> mutexOptionMap, boolean isScoreOnly) {
+        submitList = voluntaryRuleHelper.sortSubmits(submitList);
+        historyPlanList = voluntaryRuleHelper.sortPlans(historyPlanList);
+
+        Boolean typeChange = false;
+        VoluntaryDto.FormulaScoreStat formulaScoreStat = new VoluntaryDto.FormulaScoreStat();
+        String needGroup = StringUtils.trimToEmpty(null != currPlan && null != currPlan.getMajorGroup() ? currPlan.getMajorGroup() : "");
+        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<AEnrollUniversity> validEuList = enrollUniversityList.stream()
+                .filter(t -> needGroup.equals(StringUtils.trimToEmpty(t.getMajorGroups())) && t.getMajorNames().contains(needMajor))
+                .collect(Collectors.toList());
+        typeChange = CollectionUtils.isNotEmpty(validEuList) && new Integer(1).equals(validEuList.get(0).getTypeChange());
+
+        Set<String> existSet = Sets.newHashSet();
+        List<AMarjorSubmit> validSubmitList = voluntaryRuleHelper.filtValidSubmits(needMajorDirect, submitList, existSet);
+
+        // 录取线
+        List<VoluntaryDto.RenderMajorHistory> histories = Lists.newArrayList(); // 历史录取情况
+        VoluntaryDto.RenderMajorResult sr = new VoluntaryDto.RenderMajorResult();
+        sr.setHistories(histories);
+
+        if (null == scoreList) {
+            throw new RuntimeException("无分数规则");
+        }
+        Map<Boolean, List<AEnrollScore>> majorEnrollScoresMap = voluntaryRuleHelper.buildMajorEnrollScoresMap(scoreList, needGroup);
+        existSet.clear();
+        List<AEnrollScore> fEnrollScoreList = Lists.newArrayList();
+        Double inputScoreRate = NumberUtils.toInt(paramMap.get("ScoreRate"), 0) / 100.0;
+        String inclMajorDirection = needMajor + "(" + needDirect + ")";
+        String exclMajorDirection = needMajor + "(";
+        List<AEnrollScore> tmpEnrollScoreList = majorEnrollScoresMap.get(Boolean.TRUE);
+        if (null != tmpEnrollScoreList) {
+            for (AEnrollScore r : tmpEnrollScoreList) {
+                if(!voluntaryRuleHelper.isMatchMajor(r, needMajor, needMajorDirect, inclMajorDirection, exclMajorDirection)) {
+                    continue;
+                }
+                Boolean isSkillScore = isScoreOnly && r.getItemType().equals("ScoreSkill");
+                appendScoreRule(formulaScoreStat, existSet, r, fEnrollScoreList, false, paramMap, inputScoreRate, isSkillScore);
+            }
+        }
+        if (fEnrollScoreList.size() == 0 && null != (tmpEnrollScoreList = majorEnrollScoresMap.get(Boolean.FALSE))) {
+            for (AEnrollScore r : tmpEnrollScoreList) {
+                Boolean isSkillScore = isScoreOnly && r.getItemType().equals("ScoreSkill");
+                appendScoreRule(formulaScoreStat, existSet, r, fEnrollScoreList, false, paramMap, inputScoreRate, isSkillScore);
+            }
+        }
+
+        Double currTotal = formulaScoreStat.getTypeValue("StatRateScore", "", false);
+        existSet.clear();
+        Map<String, AMarjorPlan> historyPlanMap = historyPlanList.stream().collect(Collectors.toMap(t -> t.getYear() + t.getMajorName() + StringUtils.trimToEmpty(t.getMajorDirection()), Function.identity()));
+        AMarjorSubmit lastSubmit1 = null, lastSubmit2 = null;
+        for (AMarjorSubmit s : validSubmitList) {
+            if (s.getYear().equals(submitYear)) {
+                if(s.getEnrollType().equals("初录")) {
+                    lastSubmit1 = s;
+                } else {
+                    lastSubmit2 = s;
+                }
+            }
+            VoluntaryDto.RenderMajorHistory h = new VoluntaryDto.RenderMajorHistory();
+            h.setYear(s.getYear());
+            AMarjorPlan p = historyPlanMap.get(s.getYear() + s.getMajorName() + StringUtils.trimToEmpty(s.getMajorDirection()));
+            if(null != p) {
+                h.setPlan(p.getPlanTotal());
+            } else {
+                // System.out.println(s.getId());
+            }
+            h.setEnroll(s.getEnrollTotal());
+            if(null != s.getScore()) {
+                h.setScore(String.valueOf(s.getScore()));
+                h.setDiff((int) Math.round(currTotal - s.getScore()));
+            } else {
+                h.setScore("");
+                h.setDiff(null);
+            }
+            h.setRuleContent(s.getEnrollFormula());
+            h.setApplication("");
+            h.setAdmission("");
+            histories.add(h);
+        }
+
+        AMarjorSubmit lastSubmit = null == lastSubmit1 ? lastSubmit2 : lastSubmit1;
+        Double cultureScore = formulaScoreStat.getTypeValue("StatCategoryScore", "ScoreBase", false);
+
+        VoluntaryDto.RenderMajorSkill skill = new VoluntaryDto.RenderMajorSkill();
+        skill.setYear(currPlan.getYear());
+        skill.setCultureScore(toString(cultureScore));
+        String[] formulas = fEnrollScoreList.get(0).getEnrollFormula().split("\\+职业技能");
+        if(formulas.length != 2) {
+            throw new RuntimeException("错误定义考试规则" + fEnrollScoreList.get(0).getEnrollFormula());
+        }
+        skill.setCultureRule(formulas[0]); // 拆分公式
+        skill.setEnrollScore(toString(lastSubmit.getScore()));
+
+        // 计算概念或反算技能分
+        boolean isSameYear = planYear.equals(submitYear);
+        Integer validScoreTotal = isSameYear ? formulaScoreStat.getAllTotal() : lastSubmit.getScoreTotal();
+        Double currScoreRate = isSameYear ? 1.0 : formulaScoreStat.getAllTotal() * 1.0 / lastSubmit.getScoreTotal();
+        Double needSkillScore = lastSubmit.getScore() * currScoreRate - cultureScore;
+        if(isScoreOnly) {
+            skill.setSkillScore(toString(needSkillScore));
+        } else {
+            Double skillScore = formulaScoreStat.getTypeValue("StatCategoryScore", "ScoreSkill", true);
+            skill.setSkillScore(toString(needSkillScore));
+            skill.setDiff(toString(skillScore - needSkillScore));
+            EnrollRateCalculator.RateLevel rl;
+            if (currTotal != null && null != (rl = enrollRateCalculator.calSchoolEnrollRate(validScoreTotal, lastSubmit.getScore(), currTotal / currScoreRate))) { // 按去年标准算概率
+                sr.setEnrollRate(rl.rate);
+                sr.setEnrollRateText(rl.typeLabel);
+                sr.setEnumPickType(rl.type);
+            }
+        }
+        sr.setSkill(skill);
+        return sr;
+    }
+
+    public String toString(Double v) {
+        return String.valueOf(v);
+    }
+
+    public R<List<VoluntaryDto.RenderRule>> getRenderRules(VoluntaryDto.RenderRequest req) {
+        Map cond = new HashMap();
+        Integer planYear = getPlanYear(SecurityUtils.getLoginUser().getUser());
+        cond.put("year", planYear);
+        AMarjorPlan plan = aMarjorPlanMapper.selectAMarjorPlanById(req.getMajorId());
+        cond.put("majorGroup", StringUtils.trimToEmpty(plan.getMajorGroup()));
+        cond.put("majorGroupCodes", plan.getMajorCode());
+        cond.put("universityCode", req.getUniversityId());
+        return R.ok(findMatchRenderRules(cond, req.getRenderType() == 2));
+    }
+
     public R<List<VoluntaryDto.AIRenderRule>> getAIRenderRules(VoluntaryDto.AIRenderRequest req) {
         Map cond = new HashMap();
         Integer planYear = getPlanYear(SecurityUtils.getLoginUser().getUser());
@@ -263,6 +518,70 @@ public class VoluntaryService {
         return tableDataInfo;
     }
 
+    private List<VoluntaryDto.RenderRule> findMatchRenderRules(Map cond, boolean isScore) {
+        String examType = VistorContextHolder.getExamType().title(); // TODO MF
+        // String gender = "0".equals(SecurityUtils.getLoginUser().getUser().getSex()) ? "男生" : "女生";
+        cond.put("examineeType", examType);
+
+        List<VoluntaryDto.AIRenderRule> cultureRuleList = Lists.newArrayList();
+        List<VoluntaryDto.AIRenderRule> skillRuleList = Lists.newArrayList();
+
+        List<AEnrollScore> enrollScoreList = aEnrollScoreMapper.selectListByRuleCond(cond);
+        if (CollectionUtils.isEmpty(enrollScoreList) && cond.containsKey("majorGroup")) {
+            cond.put("majorGroup", "");
+            enrollScoreList = aEnrollScoreMapper.selectListByRuleCond(cond);
+        }
+        Set<String> existItemSet  = Sets.newHashSet();
+        String vt;
+        SysUser sysUser = SecurityUtils.getLoginUser().getUser();;
+        boolean isOHS = ExamType.OHS.equals(sysUser.getExamType());
+        SubjectScore subjectScore = sysUser.getScores();
+        for (AEnrollScore s : enrollScoreList) { // 跳过统计类和提示类的规则
+            boolean isSkill = "职业技能测试".equals(s.getItemCategory());
+            if (null == (vt = s.getValueType()) || vt.startsWith("Stat") || vt.equals("Notice")) {
+                continue;
+            }
+            List<VoluntaryDto.AIRenderRule> ruleList = isSkill ? skillRuleList : cultureRuleList ;
+            if (!existItemSet.add(s.getItemField())) {
+                continue;
+            }
+            VoluntaryDto.AIRenderRule r = new VoluntaryDto.AIRenderRule();
+            r.setEnumRuleCategory(VoluntaryDto.EnumRuleCategory.Enroll);
+            if (isOHS && "Score".equals(s.getValueType()) && !isSkill) {
+                r.setReadonly(true);
+                Double score = subjectScore.getSelectScore(s.getItemField());
+                if (null == score && SubjectType.Foreign.name().equals(s.getItemField())) {
+                    score = subjectScore.getSelectScore(SubjectType.English.name());
+                }
+                r.setDefaultValue(null != score ? String.valueOf(score) : "0");
+            } else {
+                r.setReadonly(false);
+                r.setDefaultValue(s.getDefaultValue());
+            }
+            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.setDotDisable(null != s.getDotDisable() && s.getDotDisable() > 0);
+            r.setKeyboardMode(s.getKeyboardMode()); // number card car,默认number
+            ruleList.add(r);
+        }
+        if(CollectionUtils.isEmpty(enrollScoreList)) {
+            throw new RuntimeException("未定义考试规则" + StringUtils.join(cond.values(), ","));
+        }
+        String[] formulas = enrollScoreList.get(0).getEnrollFormula().split("\\+职业技能");
+        if(formulas.length != 2) {
+            throw new RuntimeException("错误定义考试规则" + enrollScoreList.get(0).getEnrollFormula());
+        }
+        List<VoluntaryDto.RenderRule> allRenderRuleList = Lists.newArrayList();
+        allRenderRuleList.add(new VoluntaryDto.RenderRule("文化素质", formulas[0], cultureRuleList));
+        allRenderRuleList.add(new VoluntaryDto.RenderRule("职业技能", "职业技能" + formulas[1], isScore ? null : skillRuleList));
+        return allRenderRuleList;
+    }
+
     private List<VoluntaryDto.AIRenderRule> findMatchRules(Map cond, boolean isAi, boolean isScore) {
         String examType = VistorContextHolder.getExamType().title(); // TODO MF
         String gender = "0".equals(SecurityUtils.getLoginUser().getUser().getSex()) ? "男生" : "女生";
@@ -1191,4 +1510,158 @@ public class VoluntaryService {
         }
         return VoluntaryDto.EnumRuleType.valueOf(itemType);
     }
+
+
+
+    public List<VoluntaryDto.VoluntaryRecord> getVoluntaryList2() { // 我的志愿表 // 后台填充快照缺省
+        AWishRecord cond = new AWishRecord();
+        cond.setUserId(SecurityUtils.getLoginUser().getUserId());
+        cond.setStatus(1);
+        List<AWishRecord> aWishRecordList = aWishRecordMapper.selectAWishRecordList(cond);
+        if(CollectionUtils.isEmpty(aWishRecordList)) {
+            return Collections.emptyList();
+        }
+        return JSONArray.parseArray(aWishRecordList.get(0).getDetails(), VoluntaryDto.VoluntaryRecord.class);
+    }
+
+    public R<Long> addVoluntary2(JSONObject model) { // 填报 // 前端+后台按需要剔除一些不需快照的信息(目前主要是院校信息)
+        SysUser user = SecurityUtils.getLoginUser().getUser();
+
+        AWishRecord wishRecord = getWishRecord(user.getUserId());
+        List<VoluntaryDto.VoluntaryRecord> voluntaryRecordList = (null == wishRecord.getId()) ? Lists.newArrayList()
+                : JSONArray.parseArray(wishRecord.getDetails(), VoluntaryDto.VoluntaryRecord.class);
+
+        Long universityId = model.getLong("universityId");
+        Long majorId = model.getLong("majorId");
+        Optional<VoluntaryDto.VoluntaryRecord> optionalVoluntary = voluntaryRecordList.stream().filter(t -> t.getUniversityId().equals(universityId)).findFirst();
+        VoluntaryDto.VoluntaryRecord voluntaryRecord;
+        if(optionalVoluntary.isPresent()) {
+            voluntaryRecord = optionalVoluntary.get();
+            if(null == voluntaryRecord.getMajors()) {
+                voluntaryRecord.setMajors(Lists.newArrayList());
+            }
+        } else {
+            BBusiWishUniversities u = bBusiWishUniversitiesMapper.selectBBusiWishUniversitiesById(universityId);
+            voluntaryRecord = new VoluntaryDto.VoluntaryRecord();
+            voluntaryRecord.setUniversityLogo(u.getLogo());
+            voluntaryRecord.setUniversityName(u.getName());
+            voluntaryRecord.setUniversityId(u.getId());
+            voluntaryRecord.setMajors(Lists.newArrayList());
+            voluntaryRecord.setRank(voluntaryRecordList.size() + 1);
+            voluntaryRecordList.add(voluntaryRecord);
+        }
+        Optional<VoluntaryDto.VoluntaryMajorRecord> optionalMajor = voluntaryRecord.getMajors().stream().filter( t -> t.getMajorId().equals(majorId)).findFirst();
+        if(!optionalMajor.isPresent()) {
+            AMarjorPlan p = aMarjorPlanMapper.selectAMarjorPlanById(majorId);
+            VoluntaryDto.VoluntaryMajorRecord major = new VoluntaryDto.VoluntaryMajorRecord();
+            major.setMajorId(p.getId());
+            major.setMajorGroup(p.getMajorGroup());
+            major.setMajorName(p.getMajorName());
+            major.setMajorAncestors("");
+            major.setRank(voluntaryRecord.getMajors().size() + 1);
+            voluntaryRecord.getMajors().add(major);
+        }
+
+        wishRecord.setDetails(JSONArray.toJSONString(voluntaryRecordList));
+
+        wishRecord.setYear(getPlanYear(user));
+        if (null != wishRecord.getId()) {
+            wishRecord.setUpdateTime(new Date());
+            wishRecord.setUpdateTime(new Date());
+            aWishRecordMapper.updateAWishRecord(wishRecord);
+        } else {
+            wishRecord.setCreateTime(new Date());
+            wishRecord.setUserId(user.getUserId());
+            wishRecord.setStatus(1);
+            aWishRecordMapper.insertAWishRecord(wishRecord);
+        }
+        return R.ok(wishRecord.getId());
+    }
+
+    public Boolean removeVoluntaryByUniversity(Long userId, Long universityId) {
+        AWishRecord wishRecord = getWishRecord(userId);
+        List<VoluntaryDto.VoluntaryRecord> voluntaryRecordList = JSONArray.parseArray(wishRecord.getDetails(), VoluntaryDto.VoluntaryRecord.class);
+
+        List<VoluntaryDto.VoluntaryRecord> newRecordList = Lists.newArrayList();
+        for(VoluntaryDto.VoluntaryRecord r : voluntaryRecordList) {
+            if(r.getUniversityId().equals(universityId)) {
+                continue;
+            }
+            r.setRank(newRecordList.size());
+            newRecordList.add(r);
+        }
+        updateWishRecord(wishRecord, newRecordList);
+        return true;
+    }
+
+    public Boolean removeVoluntaryByMajor(Long userId, Long majorId) {
+        AMarjorPlan plan = aMarjorPlanMapper.selectAMarjorPlanById(majorId);
+        if(null == plan) {
+            throw new RuntimeException("错误的专业计划ID");
+        }
+        AWishRecord wishRecord = getWishRecord(userId);
+        List<VoluntaryDto.VoluntaryRecord> voluntaryRecordList = JSONArray.parseArray(wishRecord.getDetails(), VoluntaryDto.VoluntaryRecord.class);
+        Optional<VoluntaryDto.VoluntaryRecord> optionalVoluntary = voluntaryRecordList.stream().filter(t -> t.getUniversityId().equals(plan.getUniversityId())).findFirst();
+        if(!optionalVoluntary.isPresent()) {
+            throw new RuntimeException("错误的院校ID");
+        }
+        VoluntaryDto.VoluntaryRecord voluntaryRecord = optionalVoluntary.get();
+        List<VoluntaryDto.VoluntaryMajorRecord> newRecordList = Lists.newArrayList();
+        voluntaryRecord.setMajors(newRecordList);
+        for(VoluntaryDto.VoluntaryMajorRecord r : voluntaryRecord.getMajors()) {
+            if(r.getMajorId().equals(majorId)) {
+               continue;
+            }
+            r.setRank(newRecordList.size());
+            newRecordList.add(r);
+        }
+        updateWishRecord(wishRecord, voluntaryRecordList);
+        return true;
+    }
+
+    public void sortVoluntaryByMajor(Long userId, Long universityId, Map<Long, Integer> majorRankMap) {
+        AWishRecord wishRecord = getWishRecord(userId);
+        List<VoluntaryDto.VoluntaryRecord> voluntaryRecordList = JSONArray.parseArray(wishRecord.getDetails(), VoluntaryDto.VoluntaryRecord.class);
+        Optional<VoluntaryDto.VoluntaryRecord> optionalVoluntary = voluntaryRecordList.stream().filter(t -> t.getUniversityId().equals(universityId)).findFirst();
+        VoluntaryDto.VoluntaryRecord voluntaryRecord;
+        if(!optionalVoluntary.isPresent()) {
+            throw new RuntimeException("错误的院校ID");
+        }
+        voluntaryRecord = optionalVoluntary.get();
+        Integer rank;
+        for(VoluntaryDto.VoluntaryMajorRecord record : voluntaryRecord.getMajors()) {
+            if(null == (rank = majorRankMap.remove(record.getUniversityId()))) {
+                throw new RuntimeException("错误的专业计划ID");
+            }
+            record.setRank(rank);
+        }
+        updateWishRecord(wishRecord, voluntaryRecordList);
+    }
+
+    public void sortVoluntaryByUniversity(Long userId, Map<Long, Integer> universityRankMap) {
+        AWishRecord wishRecord = getWishRecord(userId);
+        List<VoluntaryDto.VoluntaryRecord> voluntaryRecordList = JSONArray.parseArray(wishRecord.getDetails(), VoluntaryDto.VoluntaryRecord.class);
+        Integer rank;
+        for(VoluntaryDto.VoluntaryRecord record : voluntaryRecordList) {
+            if(null == (rank = universityRankMap.remove(record.getUniversityId()))) {
+                throw new RuntimeException("错误的院校ID");
+            }
+            record.setRank(rank);
+        }
+        updateWishRecord(wishRecord, voluntaryRecordList);
+    }
+
+    private void updateWishRecord(AWishRecord wishRecord, List<VoluntaryDto.VoluntaryRecord> voluntaryRecordList) {
+        wishRecord.setUpdateTime(new Date());
+        wishRecord.setUpdateTime(new Date());
+        wishRecord.setDetails(JSONArray.toJSONString(voluntaryRecordList));
+        aWishRecordMapper.updateAWishRecord(wishRecord);
+    }
+    private AWishRecord getWishRecord(Long userId) {
+        AWishRecord wrCond = new AWishRecord();
+        wrCond.setId(userId);
+        wrCond.setStatus(1);
+        List<AWishRecord> wishList = aWishRecordMapper.selectAWishRecordList(wrCond);
+        return wishList.isEmpty() ? new AWishRecord() : wishList.get(0);
+    }
 }

+ 2 - 0
ie-system/src/main/java/com/ruoyi/learn/domain/PaperVO.java

@@ -45,6 +45,8 @@ public class PaperVO {
         String qtpye;
         @ApiModelProperty("分数无用")
         Integer score;
+        @ApiModelProperty("原题型")
+        String typeTitle;
         @ApiModelProperty("总分数")
         Integer totalScore;
         @ApiModelProperty("选项数组")

+ 10 - 0
ie-system/src/main/java/com/ruoyi/syzy/domain/BBusiWishUniversities.java

@@ -48,6 +48,8 @@ public class BBusiWishUniversities extends BaseEntity {
     @Excel(name = "学历层次")
     private String level;
 
+    private Integer tier;
+
     /** 一流大学建设高校(1:不是,2:是) */
     @Excel(name = "一流大学建设高校(1:不是,2:是)")
     private Integer ylxx;
@@ -228,6 +230,14 @@ public class BBusiWishUniversities extends BaseEntity {
         return level;
     }
 
+    public Integer getTier() {
+        return tier;
+    }
+
+    public void setTier(Integer tier) {
+        this.tier = tier;
+    }
+
     public void setYlxx(Integer ylxx) {
         this.ylxx = ylxx;
     }

+ 1 - 0
ie-system/src/main/java/com/ruoyi/syzy/dto/UniversitiesCondDTO.java

@@ -51,6 +51,7 @@ public class UniversitiesCondDTO {
     private String majorCodes;
     private String codes;
     private String examMajor;
+    private String tiers;
 
     /** 状态(0:无效,1:有效) */
     @ApiModelProperty("状态(0:无效,1:有效)")

+ 4 - 2
ie-system/src/main/resources/mapper/syzy/BBusiWishUniversitiesMapper.xml

@@ -139,7 +139,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
   <select id="selectMajorWishUniversitiesListSimpleByMap" parameterType="map" resultMap="BBusiWishUniversitiesResult">
     SELECT DISTINCT u.id, u.code, u.name, logo, u.location, u.managerType, u.type, u.level, u.comScore,u.rankingOfEdu,u.ranking,u.cityName,
-    u.bxLevel,u.features,u.hits,u.natureTypeCN,u.bannerUrl,u.webSite,u.area,u.enrollLocation,u.collect,u.star,u.address
+    u.bxLevel,u.features,u.hits,u.natureTypeCN,u.bannerUrl,u.webSite,u.area,u.enrollLocation,u.collect,u.star,u.address,u.tier
     FROM `b_busi_wish_universities` u
     <where>
       u.status  >0
@@ -152,6 +152,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       <if test="entranceType != null "> and u.entranceType = #{entranceType}</if>
       <if test="types != null"> and <foreach item="o" collection="types" open="(" separator=" OR " close=")">u.type like concat('%', #{o}, '%')</foreach></if>
       <if test="levels != null"> and u.level in <foreach item="o" collection="levels" open="(" separator="," close=")">#{o}</foreach></if>
+      <if test="tiers != null"> and u.tier in <foreach item="o" collection="tiers" open="(" separator="," close=")">#{o}</foreach></if>
       <if test="natureTypeCNs != null"> and <foreach item="o" collection="natureTypeCNs" open="(" separator=" OR " close=")">u.natureTypeCN like concat('%', #{o}, '%')</foreach></if>
       <if test="featureses!= null"> and <foreach item="o" collection="featureses" open="(" separator=" OR " close=")">u.features like concat('%', #{o}, '%')</foreach></if>
       <if test="bxTypes!= null"> and <foreach item="o" collection="bxTypes" open="(" separator=" OR " close=")">u.bxType like concat('%', #{o}, '%')</foreach></if>
@@ -178,7 +179,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
   <select id="selectMajorWishUniversitiesListSimpleByMap2" parameterType="map" resultMap="BBusiWishUniversitiesResult">
     SELECT DISTINCT u.id, u.code, u.name, logo, u.location, u.managerType, u.type, u.level, u.comScore,u.rankingOfEdu,u.ranking,u.cityName,
-    u.bxLevel,u.features,u.hits,u.natureTypeCN,u.bannerUrl,u.webSite,u.area,u.enrollLocation,u.collect,u.star,u.address
+    u.bxLevel,u.features,u.hits,u.natureTypeCN,u.bannerUrl,u.webSite,u.area,u.enrollLocation,u.collect,u.star,u.address,u.tier
     FROM `b_busi_wish_university_submit_recruit_plan` p
     JOIN `b_busi_wish_universities` u ON p.`universityId` = u.`id`
     <if test="majorCategory != null and majorCategory != ''">
@@ -200,6 +201,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       <if test="examMajor != null "> and p.liberalScience = #{examMajor}</if>
       <if test="types != null"> and <foreach item="o" collection="types" open="(" separator=" OR " close=")">u.type like concat('%', #{o}, '%')</foreach></if>
       <if test="levels != null"> and u.level in <foreach item="o" collection="levels" open="(" separator="," close=")">#{o}</foreach></if>
+      <if test="tiers != null"> and u.tier in <foreach item="o" collection="tiers" open="(" separator="," close=")">#{o}</foreach></if>
       <if test="natureTypeCNs != null"> and <foreach item="o" collection="natureTypeCNs" open="(" separator=" OR " close=")">u.natureTypeCN like concat('%', #{o}, '%')</foreach></if>
       <if test="featureses!= null"> and <foreach item="o" collection="featureses" open="(" separator=" OR " close=")">u.features like concat('%', #{o}, '%')</foreach></if>
       <if test="bxTypes!= null"> and <foreach item="o" collection="bxTypes" open="(" separator=" OR " close=")">u.bxType like concat('%', #{o}, '%')</foreach></if>