فهرست منبع

河南职高对口升学

jinxia.mo 2 روز پیش
والد
کامیت
beea5bae6b

+ 99 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/front/FrontSyzyYfydController.java

@@ -0,0 +1,99 @@
+package com.ruoyi.web.controller.front;
+
+import com.google.common.collect.Maps;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.utils.CommonUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.syzy.domain.BBusiWishScoreGroups;
+import com.ruoyi.syzy.service.IBBusiWishScoreGroupsService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@RestController
+@Api(tags = "模拟志愿-一分一段")
+@RequestMapping("front/syzy/yfyd")
+public class FrontSyzyYfydController extends BaseController {
+    @Autowired
+    private IBBusiWishScoreGroupsService scoreGroupsService;
+
+    @GetMapping("locations")
+    @ApiOperation("01.地域")
+    public TableDataInfo locations() {
+        List<String> list = scoreGroupsService.locations();
+        CommonUtils.sortByChina(list);
+        return getDataTable(list);
+    }
+
+    @GetMapping("years")
+    @ApiOperation("02.录取年份")
+    public TableDataInfo years(@ApiParam("地域") @RequestParam String location) {
+        //此处显示使用时不限制status
+        List<Integer> list = scoreGroupsService.yearsNoStatus(location);
+        return getDataTable(list);
+    }
+
+    @GetMapping("modes")
+    @ApiOperation("03.科类")
+    public TableDataInfo modes(@ApiParam("地域") @RequestParam String location, @ApiParam("录取年份") @RequestParam String year) {
+        //此处显示使用时不限制status
+        List<Map> list = scoreGroupsService.modesNoStatus(location, year).stream().map(t -> {
+            Map d = new HashMap();
+            d.put("mode", t.getMode());
+            d.put("modeName", t.getModeName());
+            return d;
+        }).collect(Collectors.toList());
+        return getDataTable(list);
+    }
+
+    @GetMapping("list")
+    @ApiOperation("04.一分一段列表")
+    public TableDataInfo list(@ApiParam("地域") @RequestParam String location, @ApiParam("录取年份") @RequestParam(required = false) Integer year,
+        @ApiParam("科类") @RequestParam String mode, @ApiParam("分数或位次") Integer scoreRank,@ApiParam("type 1分数,2位次") Integer type,
+        @ApiParam(value = "页数", example = "1") @RequestParam Integer pageNum,
+        @ApiParam(value = "页大小", example = "15") @RequestParam Integer pageSize) {
+        BBusiWishScoreGroups query = new BBusiWishScoreGroups();
+        query.setLocation(location).setYear(year).setMode(mode).setScoreRank(scoreRank).setType(type);
+        startPage();
+        List<BBusiWishScoreGroups> list = scoreGroupsService.selectBBusiWishScoreGroupsList(query);
+        return getDataTable(list);
+    }
+
+    @GetMapping("getRankByScore")
+    @ApiOperation("05.根据分数找位次")
+    public AjaxResult getDataByRankOrScore(@ApiParam("地域") String location, @ApiParam("录取年份")  Integer year,
+                              @ApiParam("分数或位次") @RequestParam Integer scoreRank) {
+        if(StringUtils.isBlank(location)){
+            location= SecurityUtils.getLoginUser().getUser().getLocation();
+        }
+        if(null==year){
+            year = scoreGroupsService.years(location).stream().filter(e -> e != null).max(Comparator.naturalOrder()).orElse(0);
+        }
+
+        Map cond = Maps.newHashMap();
+        cond.put("score", scoreRank);
+        cond.put("location", location);
+        cond.put("year", year);
+        cond.put("mode", SecurityUtils.getLoginUser().getUser().getExamMajor()); // 物理/历史 或 文科/理课
+        List<BBusiWishScoreGroups> groupList = scoreGroupsService.selectBusiWishScoreGroupsByScore(cond);
+        if (CollectionUtils.isEmpty(groupList)) {
+            return AjaxResult.success(new BBusiWishScoreGroups());
+        }
+        return AjaxResult.success(groupList.get(0));
+    }
+}

+ 271 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/front/FrontSyzyZytbController.java

@@ -0,0 +1,271 @@
+package com.ruoyi.web.controller.front;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Maps;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BoolValues;
+import com.ruoyi.common.enums.UserRegStatus;
+import com.ruoyi.common.exception.base.BaseException;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.web.service.TokenService;
+import com.ruoyi.system.service.ISysConfigService;
+import com.ruoyi.system.service.ISysUserService;
+import com.ruoyi.syzy.criteria.ZytbMarjorCriteriaNew;
+import com.ruoyi.syzy.domain.BBusiWishRecords;
+import com.ruoyi.syzy.dto.SubmitWishRecordDTO;
+import com.ruoyi.syzy.dto.SubmitWishRecordDTO.SubmitWishRecordDetail;
+import com.ruoyi.syzy.dto.ZytbBatch;
+import com.ruoyi.syzy.service.IBBusiWishLocationSubmitsService;
+import com.ruoyi.syzy.service.IBBusiWishRecordsService;
+import com.ruoyi.web.domain.Constant;
+import com.ruoyi.web.domain.ZytbDto;
+import com.ruoyi.web.service.ZyService;
+import com.ruoyi.web.util.VolunteerExporter;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+@Api(tags = "生涯志愿-志愿填报")
+@RequestMapping("front/syzy/zytb")
+public class FrontSyzyZytbController extends BaseController {
+    @Autowired
+    private IBBusiWishLocationSubmitsService wishLocationSubmitsService;
+    @Autowired
+    private IBBusiWishRecordsService wishRecordsService;
+    @Autowired
+    private ISysConfigService configService;
+    @Autowired
+    private ZyService zyService;
+    @Autowired
+    ISysUserService sysUserService;
+    @Autowired
+    TokenService tokenService;
+
+    @GetMapping("batches")
+    @ApiOperation("01.填报批次")
+    public TableDataInfo batches(@ApiParam("总分") @RequestParam Float score) {
+        // 获取当前登录用户省份
+        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
+        String location = sysUser.getLocation();
+        List<ZytbBatch> batchs = wishLocationSubmitsService.batches(location, score, zyService.getExamMajor());
+        return getDataTable(batchs);
+    }
+
+    @PostMapping("save")
+    @ApiOperation("04.志愿保存")
+    public AjaxResult save(@RequestBody SubmitWishRecordDTO data) {
+        if (null == data.getDetail().getYear()) {
+            data.getDetail().setYear(DateUtils.getCurrentYear());
+        }
+        //体验卡在0615~0831之间不能使用
+        String msg = zyService.limitExperienceCard(SecurityUtils.getLoginUser().getUser());
+        if(StringUtils.isNotEmpty(msg)){
+            throw new BaseException(msg);
+        }
+        SysUser u = SecurityUtils.getLoginUser().getUser();
+        SubmitWishRecordDTO.User us = new SubmitWishRecordDTO.User();
+        us.setName(u.getNickName());
+        us.setSex(u.getSex());
+        us.setProvinceName(u.getLocation());
+        us.setExamType(u.getExamType().name());
+        us.setExamMajor(String.valueOf(u.getExamMajor()));
+        us.setExamMajorName(u.getExamMajorName());
+        data.setUserSnapshot(us);
+        if(StringUtils.isBlank(data.getDetail().getMode())) {
+            data.getDetail().setMode(us.getExamMajorName());
+        }
+        wishRecordsService.save(data);
+        return AjaxResult.success("保存成功", data.getId());
+    }
+
+    @GetMapping("recordDetail")
+    @ApiOperation("02.查询明细")
+    public AjaxResult recordDetail(@ApiParam(value = "志愿id", example = "1") @RequestParam Long wishResId) {
+        BBusiWishRecords wishRecords = wishRecordsService.selectBBusiWishRecordsById(wishResId);
+        if (null != wishRecords) {
+            SubmitWishRecordDetail detail = JSON.parseObject(wishRecords.getDetail(), SubmitWishRecordDetail.class);
+            List<String> summary = new ArrayList<String>();
+            detail.getBatch().getWishes().forEach(wish -> {
+                summary.add(String.format("[%s]%s", wish.getCode(), wish.getName()));
+            });
+            SubmitWishRecordDTO.User us = JSON.parseObject(wishRecords.getUserSnapshot(), SubmitWishRecordDTO.User.class);
+            wishRecords.setMode(us.getExamMajorName());
+            wishRecords.setScore(detail.getScore());
+            wishRecords.setSummary(summary);
+        }
+        return AjaxResult.success("查询成功", wishRecords);
+    }
+
+    @GetMapping("record")
+    @ApiOperation("05.我的志愿表")
+    public TableDataInfo record(@ApiParam(value = "页数", example = "1") @RequestParam Integer pageNum,
+        @ApiParam(value = "页大小", example = "15") @RequestParam Integer pageSize) {
+        startPage();
+        String customerCode = SecurityUtils.getLoginUser().getUser().getCode(); // TODO 标识
+        BBusiWishRecords exam = new BBusiWishRecords();
+        exam.setCustomerCode(customerCode);
+        exam.setStatus(1);
+        List<BBusiWishRecords> list = wishRecordsService.selectBBusiWishRecordsList(exam);
+        list.forEach(row -> {
+//            row.setBatchName(BatchUtil.getLabel(Integer.valueOf(row.getBatch())));
+            SubmitWishRecordDetail detail = JSON.parseObject(row.getDetail(), SubmitWishRecordDetail.class);
+            List<String> summary = new ArrayList<String>();
+            detail.getBatch().getWishes().forEach(wish -> {
+                summary.add(String.format("[%s]%s", wish.getCode(), wish.getName()));
+            });
+            SubmitWishRecordDTO.User us = JSON.parseObject(row.getUserSnapshot(), SubmitWishRecordDTO.User.class);
+            row.setMode(us.getExamMajorName());
+            row.setScore(detail.getScore());
+            row.setSummary(summary);
+        });
+        return getDataTable(list);
+    }
+
+    @GetMapping("record/del")
+    @ApiOperation("06.删除我的志愿表")
+    public AjaxResult removeRecord(@ApiParam(value = "页数", example = "1") @RequestParam Long id) {
+        wishRecordsService.deleteBBusiWishRecordsById(id);
+        return success("删除成功");
+    }
+
+
+    @ApiOperation("20.获取地区科目年度")
+    @RequestMapping(value = "/getVoluntaryHeaders", method = {RequestMethod.GET, RequestMethod.POST})
+    public AjaxResult getVoluntaryHeaders(@ApiParam(value = "年度") @RequestParam(required = false) Integer year, @ApiParam(value = "组合") @RequestParam String mode, Boolean isMock) {
+        if(null==isMock){
+            isMock = false;
+        }
+        AjaxResult ajaxResult = AjaxResult.success(zyService.getVoluntaryHeaders(isMock,year, mode.split(",")[0]));
+        ajaxResult.put("isMock", isMock);
+        return ajaxResult;
+    }
+
+    @ApiOperation("21.获取推荐志愿")
+    @RequestMapping(value = "/getRecommendVoluntary", method = {RequestMethod.POST})
+    public TableDataInfo getRecommendVoluntary(@RequestBody ZytbMarjorCriteriaNew query, HttpServletResponse response,
+                                               @ApiParam(value = "页数", example = "1") @RequestParam Integer pageNum,
+                                               @ApiParam(value = "页大小", example = "5") @RequestParam Integer pageSize) {
+        SysUser user = SecurityUtils.getLoginUser().getUser();
+        if (UserRegStatus.isNotVip()) {
+            pageNum = 1;
+            pageSize = 1;
+        }
+        if (!BoolValues.isFalse(user.getScoreLock())) {
+            //在锁分阶段,强行将分数及mode重置为用户所填写锁定的值
+            query.setScore(user.getScore());
+        }
+        query.setMode(String.valueOf(user.getExamMajor()));
+        if (null != query.getWishResId() && query.getWishResId() > 0) {
+            return getDataTable(zyService.filterResEmptyHistory(zyService.getRecommendVoluntaryRes(query.getWishResId(), pageNum, pageSize)));
+        }
+
+        //体验卡在0615~0831之间不能使用、非高三卡不能使用
+        String msg = zyService.limitExperienceCard(SecurityUtils.getLoginUser().getUser());
+        if(StringUtils.isNotEmpty(msg)){
+            throw new BaseException(msg);
+        }
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        SysUser sysUser = new SysUser();
+        if (null != query.getSeatInput() && !query.getSeatInput().equals(user.getSeatInput())) { // 更新最后的 SeatInput
+            sysUser.setUserId(user.getUserId());
+            sysUser.setSeatInput(query.getSeatInput());
+            loginUser.getUser().setSeatInput(query.getSeatInput());
+        }
+        if (!BoolValues.isTrue(user.getScoreLock()) && query.getScore() != null && !query.getScore().equals(user.getScore())) {
+            //-1(中间状态),0(非锁分状态)时可以修改
+            sysUser.setUserId(user.getUserId());
+            sysUser.setScore(query.getScore());
+            user.setScore(query.getScore());
+        }
+        if (null != sysUser.getUserId()) {
+            sysUserService.updateUserProfile(sysUser);
+            tokenService.setLoginUser(loginUser);
+        }
+        return getDataTable(zyService.filterResEmptyHistory(zyService.getRecommendVoluntary(query, pageNum, pageSize)));
+    }
+
+
+    @ApiOperation("22.获取推荐志愿明细")
+    @RequestMapping(value = "/getVoluntaryMarjors", method = {RequestMethod.POST})
+    public AjaxResult getVoluntaryMarjors(@RequestBody ZytbDto.ZytbVoluntaryMarjorCond query) {
+        if (null != query.getWishResId() && query.getWishResId() > 0) {
+            return AjaxResult.success(zyService.filterEmptyHistory(zyService.getVoluntaryMarjorsRes(query.getWishResId(), query.getCollegeCode(), query.getJCode())));
+        }
+        return AjaxResult.success(zyService.filterEmptyHistory(zyService.getVoluntaryMarjors(query)));
+    }
+
+
+    @ApiOperation("23.获取模拟志愿初始参数-分数区间、科类(物理历史、理科文科)")
+    @RequestMapping(value = "/getVoluntaryData", method = {RequestMethod.GET,RequestMethod.POST})
+    public AjaxResult getVoluntaryData(String provinceName,Integer year) {
+        Map<String,Object> resultMap = new HashMap<>();
+        try {
+//            JSONObject jsonObject= SecurityUtils.getLoginUser().getUser().getVoluntaryParam();
+            String voluntaryCount= configService.selectConfigByKey("voluntary.num");
+            if(StringUtils.isNotEmpty(voluntaryCount)){
+                JSONArray array = JSONArray.parseArray(voluntaryCount);
+                array.stream().forEach(item->{
+                    JSONObject jsonObject=(JSONObject) item;
+                    if(jsonObject.getString("location").trim().contains(SecurityUtils.getLoginUser().getUser().getLocation().trim())){
+                        jsonObject.entrySet().forEach(e->{
+                            resultMap.put(e.getKey(),e.getValue());
+                        });
+                        return;
+                    }
+                });
+            }
+        }catch (Exception e){
+            logger.debug("获取志愿参数失败",e);
+        }
+
+        String examMajor = zyService.getExamMajor();
+        Integer maxScore = getMaxScore(examMajor);
+        resultMap.put("maxScore",maxScore);
+        resultMap.put("minScore",0);
+        return AjaxResult.success(resultMap);
+    }
+
+    private Integer getMaxScore(String examMajor) {
+        String scores = configService.selectConfigByKey(Constant.CFG_MAJOR_SCORES);
+        if(StringUtils.isBlank(scores)) {
+            scores = "{'20': 300, '0': 750}";
+        }
+        JSONObject scoreObj = JSONObject.parseObject(scores);
+        Integer maxScore;
+        if(null == (maxScore = scoreObj.getInteger(examMajor)) && null == (maxScore = scoreObj.getInteger("0"))) {
+            maxScore = 750;
+        }
+        return maxScore;
+    }
+
+    @GetMapping("/export")
+    public void export(@RequestParam Long wishResId, HttpServletResponse response)
+    {
+        Map dataMap = Maps.newHashMap();
+        List<ZytbDto.ZytbVolunteerRes> volunteerResList = zyService.getRecommendVoluntaryRes(wishResId, 1, 100, dataMap);
+        SubmitWishRecordDetail detail = (SubmitWishRecordDetail) dataMap.get("detail");
+        BBusiWishRecords record = (BBusiWishRecords) dataMap.get("record");
+        String location = (String) dataMap.get("location");
+        Integer currYear = (Integer) dataMap.get("currYear");
+        Integer currSubmitYear = (Integer) dataMap.get("currSubmitYear");
+        Integer seat = (Integer) dataMap.get("seat");
+        VolunteerExporter.export(location, record, detail, currYear, currSubmitYear, seat, volunteerResList, response);
+    }
+}

+ 123 - 0
ie-admin/src/main/java/com/ruoyi/web/service/ScoreGroupCalculator.java

@@ -0,0 +1,123 @@
+package com.ruoyi.web.service;
+
+import com.ruoyi.syzy.domain.BBusiWishScoreGroups;
+import org.apache.commons.collections4.CollectionUtils;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class ScoreGroupCalculator {
+    private Map<String, List<BBusiWishScoreGroups>> yearScoreGroupsMap;
+    private Set<String> courseSet;
+
+    public ScoreGroupCalculator(List<BBusiWishScoreGroups> groupList) {
+        Collections.sort(groupList, new Comparator<BBusiWishScoreGroups>() {
+            @Override
+            public int compare(BBusiWishScoreGroups o1, BBusiWishScoreGroups o2) {
+                return o1.getScore().compareTo(o2.getScore());
+            }
+        });
+        courseSet = groupList.stream().map(t -> t.getMode()).collect(Collectors.toSet());
+        yearScoreGroupsMap = groupList.stream().collect(Collectors.groupingBy(t -> buildKey(t.getYear(), t.getMode())));
+        if(CollectionUtils.isEmpty(groupList)) {
+            return;
+        }
+    }
+
+    public Integer getRankIgnoreLow(Integer year, String mode, Integer score) {
+        return (null == score || score < 200) ? null : getRank2(year, mode, score);
+    }
+
+    public Integer getRank(Integer year, String mode, Integer score) {
+        return (null == score) ? null : getRank2(year, mode, score);
+    }
+
+    public Integer getRank2(Integer year, String mode, Integer score) {
+        BBusiWishScoreGroups scoreGroups = getScoreGroupByScore(year, mode, score);
+        return null != scoreGroups ? scoreGroups.getLowestRank() : null;
+    }
+
+    public Integer getScore(Integer year, String mode, Integer rank) {
+        List<BBusiWishScoreGroups> l = yearScoreGroupsMap.get(buildKey(year, mode));
+        if (null == l) {
+            return null;
+        }
+        Optional<BBusiWishScoreGroups> optionalBBusiWishScoreGroups = l.stream().filter(v -> rank <= v.getLowestRank() && rank >= v.getHighestRank()).findFirst();
+        /*int left = 0;
+        int right = l.size() - 1;
+        while (left <= right) {
+            int mid = left + (right - left) / 2;
+            BBusiWishScoreGroups v = l.get(mid);
+            if (rank <= v.getLowestRank() && rank >= v.getHighestRank()) {
+                return v.getScore(); // 找到目标,返回索引
+            } else if (v.getLowestRank() > rank) {
+                left = mid + 1; // 在右半区继续查找
+            } else {
+                right = mid - 1; // 在左半区继续查找
+            }
+        }*/
+        return optionalBBusiWishScoreGroups.isPresent() ? optionalBBusiWishScoreGroups.get().getScore() : null;
+    }
+
+    public BBusiWishScoreGroups getScoreGroupByScore(Integer year, String mode, Integer score) {
+        List<BBusiWishScoreGroups> l = yearScoreGroupsMap.get(buildKey(year, mode));
+        if (CollectionUtils.isEmpty(l) || null == score || score > l.get(l.size() - 1).getMaxScore()) {
+            return null;
+        }
+        Optional<BBusiWishScoreGroups> optionalBBusiWishScoreGroups = l.stream().filter(v -> score >= v.getScore() && score <= v.getMaxScore()).findFirst();
+        /*
+        int left = 0;
+        int right = l.size() - 1;
+        while (left <= right) {
+            int mid = left + (right - left) / 2;
+
+            BBusiWishScoreGroups v = l.get(mid);
+            if (score >= v.getScore() && score <= v.getMaxScore()) {
+                return v; // 找到目标,返回索引
+            } else if (v.getScore() < score) {
+                left = mid + 1; // 在右半区继续查找
+            } else {
+                right = mid - 1; // 在左半区继续查找
+            }
+        }*/
+        return optionalBBusiWishScoreGroups.isPresent() ? optionalBBusiWishScoreGroups.get() : null;
+    }
+
+    public BBusiWishScoreGroups getBatchRange(Map<String, List<BBusiWishScoreGroups>> yearBatchRangeMap, Integer year, Integer matchBatch) {
+        return getBatchRange(yearBatchRangeMap, year, null, matchBatch);
+    }
+
+    public BBusiWishScoreGroups getBatchRange(Map<String, List<BBusiWishScoreGroups>> yearBatchRangeMap, Integer year, Integer liberalScience, Integer matchBatch) {
+        List<BBusiWishScoreGroups> rangeList = yearBatchRangeMap.get(null != liberalScience ? year + "_" + liberalScience : year.toString());
+        if (null != rangeList) {
+            for (BBusiWishScoreGroups range : rangeList) {
+                if (range.getType().equals(matchBatch)) {
+                    return range;
+                }
+            }
+        }
+        return null;
+    }
+
+    public Integer getMaxScore(Integer year, String mode) {
+        List<BBusiWishScoreGroups> l = yearScoreGroupsMap.get(buildKey(year, mode));
+        return CollectionUtils.isNotEmpty(l) ? l.get(l.size() - 1).getMaxScore() : null;
+    }
+
+    public Boolean isMixCourse() {
+        return courseSet.size() > 2;
+    }
+
+    public static Integer getLiberalScience(String type) {
+        if("物理".equals(type) || "理科".equals(type)) {
+            return 1;
+        } else if("历史".equals(type) || "文科".equals(type)) {
+            return 0;
+        }
+        return 2;
+    }
+
+    private String buildKey(Integer year, String mode) {
+        return year + "_" + mode;
+    }
+}

+ 267 - 0
ie-admin/src/main/java/com/ruoyi/web/service/ScoreRankService.java

@@ -0,0 +1,267 @@
+package com.ruoyi.web.service;
+
+import com.google.common.collect.Maps;
+import com.ruoyi.syzy.domain.BBusiWishLocationSubmits;
+import com.ruoyi.syzy.domain.BBusiWishScoreGroups;
+import com.ruoyi.syzy.mapper.BBusiWishLocationSubmitsMapper;
+import com.ruoyi.syzy.mapper.BBusiWishScoreGroupsMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+public class ScoreRankService {
+    private BBusiWishScoreGroupsMapper wishScoreGroupsMapper;
+    private BBusiWishLocationSubmitsMapper wishLocationSubmitsMapper;
+    private Map<String, ScoreGroupCalculator> locationYearScoreGroupMapperMap = Maps.newHashMap(); // 一分一段
+    private Map<String, Map<Integer, List<BBusiWishScoreGroups>>> locationYearBatchRangeMap = Maps.newHashMap(); // 批次表
+    private Map<String, Integer[]> locationYearEqRateMap = Maps.newHashMap();
+
+    public ScoreRankService(BBusiWishScoreGroupsMapper wishScoreGroupsMapper, BBusiWishLocationSubmitsMapper wishLocationSubmitsMapper) {
+        this.wishScoreGroupsMapper = wishScoreGroupsMapper;
+        this.wishLocationSubmitsMapper = wishLocationSubmitsMapper;
+    }
+
+    public void clean() {
+        synchronized (locationYearScoreGroupMapperMap) {
+            locationYearScoreGroupMapperMap.clear();
+        }
+        synchronized (locationYearScoreGroupMapperMap) {
+            locationYearBatchRangeMap.clear();
+        }
+        synchronized (locationYearScoreGroupMapperMap) {
+            locationYearEqRateMap.clear();
+        }
+    }
+
+    // 分数转位次 mode=当年的文科/理科/物理/历史
+    public Integer getRank(String location, Integer year, String mode, Integer score) {
+        ScoreGroupCalculator sgMapper =  getScoreCalculatorMapper(location, year, mode);
+        return sgMapper.getRank2(year, mode, score);
+    }
+
+    // 位次转分数 mode=当年的文科/理科/物理/历史
+    public Integer getScore(String location, Integer year, String mode, Integer rank) {
+        if (null == rank) {
+            return null;
+        }
+        ScoreGroupCalculator sgMapper = getScoreCalculatorMapper(location, year, mode);
+        return sgMapper.getScore(year, mode, rank);
+    }
+
+    public Integer getRankEqRank(String location, Integer maxYear, Integer currYear, String mode, Integer score, Integer rank, Integer eqYear) {
+        BBusiWishScoreGroups currScoreRange = getScoreRangeByScore(location, maxYear, mode, currYear, score);
+        Integer eqRank = null;
+        if(null != currScoreRange) {
+            BBusiWishScoreGroups eqScoreRange = getScoreRangeByBatch(location, currYear, currScoreRange.getMode(), eqYear, currScoreRange.getType());
+            eqRank = getEqRank(currScoreRange, eqScoreRange, location, currYear, currYear, score, rank, eqYear);
+        }
+        return eqRank;
+    }
+
+    // 不需要等效分时使用
+    public Integer getEqRank(String location, Integer maxYear, Integer currYear, String mode, Integer score, Integer eqYear) {
+        BBusiWishScoreGroups currScoreRange = getScoreRangeByScore(location, maxYear, mode, currYear, score);
+        Integer eqRank = null;
+        if(null != currScoreRange) {
+            BBusiWishScoreGroups eqScoreRange = getScoreRangeByBatch(location, currYear, currScoreRange.getMode(), eqYear, currScoreRange.getType());
+            eqRank = getEqRank(currScoreRange, eqScoreRange, location, currYear, currYear, score, null, eqYear);
+        }
+        return eqRank;
+    }
+    // 需要等效分时使用,计算等效位次(rate = (matchRank - matchLow) / (matchHigh - matchLow),  tmpRank(year) = lowRankRank + (highRank - lowRank) * rate); 等效分(等效位数在当年对应的分值)
+    public Integer getEqRank(BBusiWishScoreGroups currScoreRange, BBusiWishScoreGroups eqScoreRange, String location, Integer maxYear, Integer srcYear, Integer srcScore, Integer srcRank, Integer eqYear) {
+        if (null == currScoreRange || null == eqScoreRange) {
+            log.warn("无有效批次范围: {},{},{},{}", location, maxYear, srcYear, srcScore);
+            return null;
+        }
+        String srcMode = currScoreRange.getMode();
+        ScoreGroupCalculator sgMapper =  getScoreCalculatorMapper(location, srcYear, srcMode);
+        if (null == sgMapper) {
+            log.warn("无有效一分一段: {},{},{}", location, srcYear, srcMode);
+            return null;
+        }
+        if(null == srcRank) {
+            srcRank = sgMapper.getRank(srcYear, srcMode, srcScore);
+        }
+        if (null == srcRank) {
+            log.warn("分数不在一分一段: {},{},{},{}", location, srcYear, srcMode, srcScore);
+            return null;
+        }
+        String key = location + "_" + maxYear + "_" + srcMode + "_" + srcYear + "_" + eqYear + "_" + currScoreRange.getType();
+        Integer[] data = locationYearEqRateMap.get(key);
+        Integer eqMinRank = null, egRange = null, matchMinRank, matchRange;
+        if (null == data) {
+            synchronized (locationYearEqRateMap) {
+                if (null == (data = locationYearEqRateMap.get(key))) {
+                    matchMinRank = sgMapper.getRank(srcYear, currScoreRange.getMode(), currScoreRange.getMaxScore());
+                    Integer matchMaxRank = sgMapper.getRank(srcYear, currScoreRange.getMode(), currScoreRange.getScore());
+                    matchRange = null != matchMaxRank && null != matchMinRank ? matchMaxRank - matchMinRank : null;
+
+                    ScoreGroupCalculator eqMapper = getScoreCalculatorMapper(location, eqYear, eqScoreRange.getMode());
+                    Integer eqMaxRank = null;
+                    if (null != eqScoreRange && null != eqMapper) {
+                        eqMinRank = eqMapper.getRank2(eqYear, eqScoreRange.getMode(), eqScoreRange.getMaxScore());
+                        eqMaxRank = eqMapper.getRank2(eqYear, eqScoreRange.getMode(), eqScoreRange.getScore());
+                        egRange = null != eqMaxRank && null != eqMinRank ? eqMaxRank - eqMinRank : null;
+                    }
+                    data = new Integer[]{matchMinRank, matchRange, eqMinRank, egRange};
+                    locationYearEqRateMap.put(key, data);
+                }
+            }
+
+        }
+        matchMinRank = data[0];
+        matchRange = data[1];
+        eqMinRank = data[2];
+        egRange = data[3];
+        if(null == matchMinRank || null == matchRange || null == eqMinRank || null == egRange) {
+            log.warn("参数不全: {},{},{},{},值: {},{},{},{}", location, srcYear, srcMode, srcScore, matchMinRank, matchRange, eqMinRank, egRange);
+            return null;
+        }
+        Double matchRate = (srcRank - matchMinRank + 1) * 1.0 / (matchRange + 1);
+        Integer eqRank = (int) Math.floor(eqMinRank + matchRate * egRange);
+        return eqRank;
+    }
+
+    public BBusiWishScoreGroups getScoreGroups(String location, Integer year, String mode, Integer score) {
+        ScoreGroupCalculator sgMapper =  getScoreCalculatorMapper(location, year, mode);
+        return sgMapper.getScoreGroupByScore(year, mode, score);
+    }
+
+    /**
+     * 根据批次查找对应的批次
+     * @return
+     */
+    public BBusiWishScoreGroups getScoreRangeByBatch(String location, Integer maxYear, String course, Integer year, Integer batch) {
+        Map<Integer, List<BBusiWishScoreGroups>> yearBatchRangeMap = buildScoreBatchRange(location, maxYear, course);
+        if(null == yearBatchRangeMap) {
+            throw new RuntimeException("需要先初始化环境");
+        }
+        List<BBusiWishScoreGroups> batchRangeList = yearBatchRangeMap.get(year);
+        if(null == batchRangeList) {
+            return null;
+        }
+        Integer needType = batch < 4 && batchRangeList.get(0).getStatus() > 0 ? 1 : batch;
+        Optional<BBusiWishScoreGroups> scoreGroupsOptional = batchRangeList.stream().filter(t -> t.getType().equals(needType)).findFirst();
+        BBusiWishScoreGroups scoreGroup = null;
+        if (scoreGroupsOptional.isPresent() && null != (scoreGroup = scoreGroupsOptional.get()) && null == scoreGroup.getMaxScore()) {
+            ScoreGroupCalculator sgMapper = getScoreCalculatorMapper(location, year, scoreGroup.getMode());
+            scoreGroup.setMaxScore(sgMapper.getMaxScore(year, scoreGroup.getMode()));
+        }
+        return scoreGroup;
+    }
+
+    /**
+     * 根据分数定位所在批次
+     */
+    public BBusiWishScoreGroups getScoreRangeByScore(String location, Integer maxYear, String course, Integer year, Integer score) {
+        Map<Integer, List<BBusiWishScoreGroups>> yearBatchRangeMap = buildScoreBatchRange(location, maxYear, course);
+        if(null == yearBatchRangeMap) {
+            throw new RuntimeException("需要先初始化环境");
+        }
+        List<BBusiWishScoreGroups> batchRangeList = yearBatchRangeMap.get(year);
+        Optional<BBusiWishScoreGroups> scoreGroupsOptional = batchRangeList.stream().filter(t -> score >= t.getScore() && (null == t.getMaxScore() || score <= t.getMaxScore())).findFirst();
+        if(!scoreGroupsOptional.isPresent()) {
+            return null;
+        }
+        BBusiWishScoreGroups scoreGroup = null;
+        if (scoreGroupsOptional.isPresent() && null != (scoreGroup = scoreGroupsOptional.get()) && null == scoreGroup.getMaxScore()) {
+            ScoreGroupCalculator sgMapper = getScoreCalculatorMapper(location, year, scoreGroup.getMode());
+            scoreGroup.setMaxScore(sgMapper.getMaxScore(year, scoreGroup.getMode()));
+        }
+        return scoreGroup;
+
+    }
+
+    /**
+     *
+     * @param location
+     * @param maxYear
+     * @param course 文科/历史 或 理科/物理 批次线组,State 标名是否混合
+     * @return mode = course
+     */
+    private Map<Integer, List<BBusiWishScoreGroups>> buildScoreBatchRange(String location, Integer maxYear, String course) {
+        String key = location + "_" + course;
+        Map<Integer, List<BBusiWishScoreGroups>> yearBatchRangeMap = locationYearBatchRangeMap.get(key);
+        if(null != yearBatchRangeMap) {
+            return yearBatchRangeMap;
+        }
+        synchronized (locationYearBatchRangeMap) {
+            if (null != (yearBatchRangeMap = locationYearBatchRangeMap.get(key))) {
+                return yearBatchRangeMap;
+            }
+            Integer minYear = maxYear - 3;
+            BBusiWishLocationSubmits query = new BBusiWishLocationSubmits();
+            query.setLocation(location);
+            List<BBusiWishLocationSubmits> lsList = wishLocationSubmitsMapper.selectBBusiWishLocationSubmitsList(query).stream().sorted(new Comparator<BBusiWishLocationSubmits>() {
+                @Override
+                public int compare(BBusiWishLocationSubmits o1, BBusiWishLocationSubmits o2) {
+                    return o1.getScore().compareTo(o2.getScore());
+                }
+            }).filter(ls -> {
+                Integer year = Integer.parseInt(ls.getYear());
+                return course.equals(ls.getCourse()) &&  year >= minYear && year <= maxYear;
+            }).collect(Collectors.toList());
+            // 判断是否旧转新高考
+            Boolean isMixCourse = lsList.stream().map(t -> t.getCourse()).collect(Collectors.toSet()).size() > 1;
+
+            // 构建立年度与批次范围表
+            yearBatchRangeMap = Maps.newHashMap();
+            for (BBusiWishLocationSubmits ls : lsList) {
+                Integer year = Integer.parseInt(ls.getYear());
+                List<BBusiWishScoreGroups> rangeList = yearBatchRangeMap.get(year);
+                BBusiWishScoreGroups last = null;
+                if (null == rangeList) {
+                    rangeList = new ArrayList<>();
+                    yearBatchRangeMap.put(year, rangeList);
+                } else {
+                    last = rangeList.get(rangeList.size() - 1);
+                    last.setMaxScore(ls.getScore() - 1);
+                }
+                if (isMixCourse && null != last && last.getType() < 4) { // 以本科最低为本科批底线
+                    last.setMaxScore(null); // 合并本科一二批次,要取掉最高分
+                } else {
+                    BBusiWishScoreGroups range = new BBusiWishScoreGroups();
+                    range.setType(isMixCourse && ls.getType() < 4 ? 1 : ls.getType());
+                    range.setStatus(isMixCourse ? 1 : 0); // 备注是否交叉状态
+                    range.setMode(ls.getCourse()); // 文科/理科/物理/历史
+                    range.setScore(ls.getScore());
+                    rangeList.add(range);
+                }
+            }
+            locationYearBatchRangeMap.put(key, yearBatchRangeMap);
+            return yearBatchRangeMap;
+        }
+    }
+
+    /**
+     *
+     * @param location
+     * @param year
+     * @param mode 文科/理科/物理/历史
+     * @return
+     */
+    private ScoreGroupCalculator getScoreCalculatorMapper(String location, Integer year, String mode) {
+        String key = location + "_" + year + "_" + mode;
+        ScoreGroupCalculator sgMapper = locationYearScoreGroupMapperMap.get(key);
+        if (null == sgMapper) {
+            synchronized (locationYearScoreGroupMapperMap) {
+                sgMapper = locationYearScoreGroupMapperMap.get(key);
+                if (null == sgMapper) {
+                    BBusiWishScoreGroups sgCond = new BBusiWishScoreGroups();
+                    sgCond.setLocation(location);
+                    sgCond.setYear(year);
+                    sgCond.setMode(mode);
+                    sgMapper = new ScoreGroupCalculator(wishScoreGroupsMapper.selectBBusiWishScoreGroupsList(sgCond));
+                    locationYearScoreGroupMapperMap.put(key, sgMapper);
+                }
+            }
+        }
+        return sgMapper;
+    }
+
+}

+ 1680 - 0
ie-admin/src/main/java/com/ruoyi/web/service/ZyService.java

@@ -0,0 +1,1680 @@
+package com.ruoyi.web.service;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.github.pagehelper.PageHelper;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.text.Convert;
+import com.ruoyi.common.enums.UserRegStatus;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.bean.BeanUtils;
+import com.ruoyi.dz.domain.DzCards;
+import com.ruoyi.dz.service.IDzCardsService;
+import com.ruoyi.enums.CardType;
+import com.ruoyi.mxjb.domain.BBusiWishUniversityMarjorsCollege;
+import com.ruoyi.mxjb.domain.BBusiWishUniversityMarjorsGroup;
+import com.ruoyi.mxjb.domain.BBusiWishUniversityMarjorsPlanSubmit;
+import com.ruoyi.mxjb.domain.SubmitYearsStats;
+import com.ruoyi.mxjb.mapper.BBusiWishUniversityMarjorsCollegeMapper;
+import com.ruoyi.mxjb.mapper.BBusiWishUniversityMarjorsGroupMapper;
+import com.ruoyi.mxjb.mapper.BBusiWishUniversityMarjorsPlanSubmitMapper;
+import com.ruoyi.mxjb.service.IMxjbWishScoreRateService;
+import com.ruoyi.mxjb.service.impl.MxjbWishScoreRateServiceImpl;
+import com.ruoyi.sy.domain.SyMajor;
+import com.ruoyi.sy.service.ISyMajorService;
+import com.ruoyi.system.service.ISysConfigService;
+import com.ruoyi.syzy.criteria.ZytbMarjorCriteriaNew;
+import com.ruoyi.syzy.domain.*;
+import com.ruoyi.syzy.dto.SubmitWishRecordDTO;
+import com.ruoyi.syzy.dto.UniversitiesCondDTO;
+import com.ruoyi.common.enums.NewgaokaoType;
+import com.ruoyi.syzy.mapper.*;
+import com.ruoyi.syzy.service.IBBusiWishLocationSubmitsService;
+import com.ruoyi.syzy.utils.BatchUtil;
+import com.ruoyi.web.domain.Constant;
+import com.ruoyi.web.domain.ZytbDto;
+import lombok.extern.slf4j.Slf4j;
+import com.ruoyi.web.util.PageUtil;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.commons.lang3.time.StopWatch;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+public class ZyService {
+    private final BBusiWishUniversitySubmitMarjorsMapper busiWishUniversitySubmitMarjorsMapper;
+    private final BBusiWishUniversitySubmitRecruitPlanMapper busiWishUniversitySubmitRecruitPlanMapper;
+    private final BBusiWishScoreGroupsMapper busiWishScoreGroupsMapper;
+    private final BBusiWishUniversitiesMapper bBusiWishUniversitiesMapper;
+    private final BBusiWishRecordsMapper busiWishRecordsMapper;
+    private final BBusiWishUniversitySubmitsMapper busiWishUniversitySubmitsMapper;
+    private final BBusiWishUniversityMarjorsCollegeMapper busiWishUniversityMarjorsCollegeMapper;
+    private final BBusiWishUniversityMarjorsPlanSubmitMapper busiWishUniversityMarjorsPlanSubmitMapper;
+    private final BBusiWishUniversityMarjorsGroupMapper busiWishUniversityMarjorsGroupMapper;
+    private final IBBusiWishLocationSubmitsService busiWishLocationSubmitsService;
+    private final BBusiWishUniversitiesSubjectevaluateMapper busiWishUniversitiesSubjectevaluateMapper;
+    private final BBusiWishUniversitiesProfessionMapper busiWishUniversitiesProfessionMapper;
+    private final BBusiWishUniversitiesSubjectMapper busiWishUniversitiesSubjectMapper;
+    private final ISysConfigService configService;
+    @Autowired
+    private IDzCardsService cardsService;
+    private final IMxjbWishScoreRateService mxjbWishScoreRateService;
+    private final CacheService cacheService;
+    private final ISyMajorService syMajorService;
+    private final MajorFeatureCache majorFeatureCache;
+//    private final IBusiScoreLockService scoreLockService;
+    private final ScoreRankService scoreRankService;
+
+    private Map<String, Map<String, List<String>>> typeMajorChildrenMap;
+    Integer[] PickWeight = new Integer[] {30, 0, -14}; // ZytbUniversityCriteria 0冲刺型 1稳妥型 2保守型
+
+
+    public ZyService(BBusiWishUniversitySubmitMarjorsMapper busiWishUniversitySubmitMarjorsMapper, BBusiWishUniversitySubmitRecruitPlanMapper busiWishUniversitySubmitRecruitPlanMapper,
+                     BBusiWishScoreGroupsMapper busiWishScoreGroupsMapper, BBusiWishUniversitiesMapper bBusiWishUniversitiesMapper, BBusiWishRecordsMapper busiWishRecordsMapper,
+                     BBusiWishUniversitySubmitsMapper busiWishUniversitySubmitsMapper, BBusiWishUniversityMarjorsCollegeMapper busiWishUniversityMarjorsCollegeMapper,
+                     BBusiWishUniversityMarjorsPlanSubmitMapper busiWishUniversityMarjorsPlanSubmitMapper, BBusiWishUniversityMarjorsGroupMapper busiWishUniversityMarjorsGroupMapper,
+                     IBBusiWishLocationSubmitsService busiWishLocationSubmitsService, BBusiWishUniversitiesSubjectevaluateMapper busiWishUniversitiesSubjectevaluateMapper, BBusiWishUniversitiesProfessionMapper busiWishUniversitiesProfessionMapper,
+                     BBusiWishUniversitiesSubjectMapper busiWishUniversitiesSubjectMapper, ISysConfigService configService, IMxjbWishScoreRateService mxjbWishScoreRateService, CacheService cacheService, ISyMajorService syMajorService, ScoreRankService scoreRankService) {
+        this.busiWishUniversitySubmitMarjorsMapper = busiWishUniversitySubmitMarjorsMapper;
+        this.busiWishUniversitySubmitRecruitPlanMapper = busiWishUniversitySubmitRecruitPlanMapper;
+        this.busiWishScoreGroupsMapper = busiWishScoreGroupsMapper;
+        this.bBusiWishUniversitiesMapper = bBusiWishUniversitiesMapper;
+        this.busiWishRecordsMapper = busiWishRecordsMapper;
+        this.busiWishUniversitySubmitsMapper = busiWishUniversitySubmitsMapper;
+        this.busiWishUniversityMarjorsCollegeMapper = busiWishUniversityMarjorsCollegeMapper;
+        this.busiWishUniversityMarjorsPlanSubmitMapper = busiWishUniversityMarjorsPlanSubmitMapper;
+        this.busiWishUniversityMarjorsGroupMapper = busiWishUniversityMarjorsGroupMapper;
+        this.busiWishLocationSubmitsService = busiWishLocationSubmitsService;
+        this.busiWishUniversitiesSubjectevaluateMapper = busiWishUniversitiesSubjectevaluateMapper;
+        this.busiWishUniversitiesProfessionMapper = busiWishUniversitiesProfessionMapper;
+        this.busiWishUniversitiesSubjectMapper = busiWishUniversitiesSubjectMapper;
+        this.configService = configService;
+        this.mxjbWishScoreRateService = mxjbWishScoreRateService;
+        this.cacheService = cacheService;
+        this.syMajorService = syMajorService;
+//        this.scoreLockService = scoreLockService;
+        this.scoreRankService = scoreRankService;
+        this.majorFeatureCache = new MajorFeatureCache(busiWishUniversitiesSubjectevaluateMapper, busiWishUniversitiesProfessionMapper, busiWishUniversitiesSubjectMapper);
+        this.typeMajorChildrenMap = buildMajorChildrenMap();
+    }
+
+    /**
+     * 06-20后才算新的一年
+     * @return
+     */
+    public Integer getYear() {
+        String createtimeArrayStr = configService.selectConfigByKey("voluntary.newyear.createtime");
+        if(!createtimeArrayStr.contains("{")){
+            createtimeArrayStr= "[{\"location\":\"湖南\",\"time\":\"06-28\"},{\"location\":\"湖北\",\"time\":\"06-28\"},{\"location\":\"江西\",\"time\":\"01-24\"},{\"location\":\"安徽\",\"time\":\"01-28\"},{\"location\":\"广东\",\"time\":\"06-28\"},{\"location\":\"广西\",\"time\":\"06-28\"},{\"location\":\"河南\",\"time\":\"06-28\"},{\"location\":\"四川\",\"time\":\"06-28\"}]";
+        }
+        String voluntaryNewyearCreatetime= StringUtils.EMPTY;
+        if(StringUtils.isNotEmpty(createtimeArrayStr)){
+            JSONArray array = JSONArray.parseArray(createtimeArrayStr);
+            for (Object item : array) {
+                JSONObject jsonObject = (JSONObject) item;
+                if (jsonObject.getString("location").trim().contains(SecurityUtils.getLoginUser().getUser().getLocation().trim())) {
+                    voluntaryNewyearCreatetime = jsonObject.getString("time");
+                    break;
+                }
+            }
+        }
+
+        Date registerTime = DateUtils.parseDate(DateUtils.getCurrentYear()+"-"+(StringUtils.isBlank(voluntaryNewyearCreatetime)?("06-22"):voluntaryNewyearCreatetime));
+
+        Calendar cal = Calendar.getInstance();
+        Integer year = cal.get(Calendar.YEAR);
+        if(new Date().before(registerTime)){
+            year= year -1 ;
+        }
+        return year;
+    }
+
+    /**
+     * 查询最近2年的最新录取数据,以决定是用当年还是前一年匹配
+     * @param location
+     * @param type
+     * @param level
+     * @param currYear
+     * @return
+     */
+    public Integer getSubmitYear(String location, String type, String level, Integer currYear) {
+        //20231208 莫:院校投档线列表中status不限制,模拟志愿要限制status>0,解决院校线出了2023年的但是模拟志愿中只使用2022年的
+        List<String> years = busiWishUniversitySubmitsMapper.yearsStatus(location, type, level);
+        for (String y : years) { // years是按年度倒序的,取第一个最近年度的
+            Integer currSubmitYear = Integer.parseInt(y);
+            if (currSubmitYear <= currYear) {
+                return currSubmitYear < currYear - 1 ? currYear : currSubmitYear;
+            }
+        }
+        return currYear;
+    }
+
+    private Map<String, Map<Integer, String>> YearModeCourseMap = Maps.newHashMap();
+    public void clearYearCourseMap() {
+        YearModeCourseMap.clear();
+    }
+    public Map<Integer, String> getYearCourseMap(Integer currYear, String mode) {
+        String location = SecurityUtils.getLoginUser().getUser().getLocation();
+        Integer liberalScience = NewgaokaoType.isNewgaokao33Province(location) ? 2 : (("物理".equals(mode) || "理科".equals(mode)) ? 1 : 0);
+        String key = location + liberalScience + currYear + mode;
+        Map<Integer, String> yearCourseMap = YearModeCourseMap.get(key);
+        if (null == yearCourseMap) {
+            synchronized (YearModeCourseMap) {
+                yearCourseMap = YearModeCourseMap.get(key);
+                if (null == yearCourseMap) {
+                    yearCourseMap = getYearCourseMapInner(location, liberalScience, currYear, mode);
+                    YearModeCourseMap.put(key, yearCourseMap);
+                }
+            }
+        }
+        return yearCourseMap;
+    }
+
+    public Map<Integer, String> getYearCourseMapInner(String location, Integer liberalScience, Integer currYear, String mode) {
+        Map cond = Maps.newHashMap();
+        cond.put("location", location);
+        cond.put("year", currYear - 3);
+        cond.put("currYear", currYear);
+        cond.put("liberalScience", liberalScience);
+        Map<Integer, String> yearTypeMap = busiWishUniversitySubmitMarjorsMapper.selectYearTypes(cond).stream().collect(Collectors.toMap(t -> Integer.parseInt(t.getYear()), t -> t.getType()));
+        String last = mode;
+        Map<Integer, String> yearCourseMap = Maps.newHashMap();
+        for (int i = currYear; i >= currYear - 3; i--) {
+            String type = yearTypeMap.get(i);
+            if (null != type) {
+                last = type;
+            }
+            yearCourseMap.put(i, last);
+        }
+        return yearCourseMap;
+    }
+
+    public List<String> getVoluntaryHeaders(Boolean isMock,Integer currYear, String mode) {
+        String location = SecurityUtils.getLoginUser().getUser().getLocation();
+        currYear = getYear(); // || location.equals("江西") || location.equals("湖北") || location.equals("湖南")
+        Integer currYearTitle=currYear;
+        if(isMock){
+            //同年时才升年
+            if(currYear<Calendar.getInstance().get(Calendar.YEAR)){
+                currYearTitle=currYear+1;
+            }
+        }
+        Map<Integer, String> yearCourseMap = getYearCourseMap(currYear, mode);
+
+        List<String> headerNameList = Lists.newArrayList("推荐类型", "院校", currYearTitle + "年招生计划", "投档线年份","最低分","位次","录取人数");
+        String forceLocation = configService.selectConfigByKey("voluntary.force.locations");
+        if (null != forceLocation && forceLocation.contains(location)||isMock) {
+            currYear = 2023;
+        }
+        for (int i = currYear; i > currYear - 3; i--) {
+            headerNameList.add(i + "&" + yearCourseMap.get(i));
+        }
+        headerNameList.add("填报");
+        return headerNameList;
+    }
+
+    private Integer getScoreOfLastYear(String location, Integer currYear, String mode, Integer score) {
+        BBusiWishScoreGroups currScoreRange = scoreRankService.getScoreRangeByScore(location, currYear, mode, currYear, score);
+        Integer eqScore = null;
+        if(null != currScoreRange) {
+            Integer eqYear = currYear -1;
+            BBusiWishScoreGroups eqScoreRange = scoreRankService.getScoreRangeByBatch(location, currYear, currScoreRange.getMode(), eqYear, currScoreRange.getType());
+            if (null != eqScoreRange) {
+                Integer eqRank = scoreRankService.getEqRank(currScoreRange, eqScoreRange, location, currYear, currYear, score, null, eqYear);
+                eqScore = scoreRankService.getScore(location, eqYear, eqScoreRange.getMode(), eqRank);
+            }
+        }
+        return eqScore;
+    }
+    private Integer getScoreOfLastYear2(String location, Integer currYear, String mode, Integer score) {
+        Map cond = Maps.newHashMap();
+        cond.put("location", location);
+        cond.put("year", currYear);
+        cond.put("mode", mode);
+        cond.put("score", score);
+        List<BBusiWishScoreGroups> groupList = busiWishScoreGroupsMapper.selectBusiWishScoreGroupsByScore(cond);
+        if(CollectionUtils.isNotEmpty(groupList)) {
+            BBusiWishScoreGroups currScoreGroup = groupList.get(0);
+            cond.remove("score");
+            Integer[] ranks = getMappingRank2(new Integer[] {currScoreGroup.getLowestRank()}, location, currYear, currYear - 1);
+            cond.put("year", currYear - 1);
+            cond.put("rank", ranks[0]);
+            groupList = busiWishScoreGroupsMapper.selectBusiWishScoreGroupsByScore(cond);
+        } else {
+            cond.remove("year");
+            groupList = busiWishScoreGroupsMapper.selectBusiWishScoreGroupsByScore(cond);
+        }
+        if (CollectionUtils.isEmpty(groupList)) {
+            return score;
+        }
+        BBusiWishScoreGroups lastScoreGroup = groupList.get(0);
+        return lastScoreGroup.getScore().intValue();
+    }
+
+    private Integer getLowestRank(Map cond, Integer score) {
+        cond.put("score", score);
+        List<BBusiWishScoreGroups> groupList = busiWishScoreGroupsMapper.selectBusiWishScoreGroupsByScore(cond);
+        if (CollectionUtils.isEmpty(groupList)) {
+            return null;
+        }
+        Integer lowestRank = groupList.get(0).getLowestRank();
+        return lowestRank;
+    }
+
+    private String getMajorName(String majorName, String majorDirection) {
+        if(StringUtils.isNotBlank(majorDirection)) {
+            if (majorDirection.contains("国家专项")) {
+                return majorName + "(国家专项)";
+            } else if (majorDirection.contains("地方专项")) {
+                return majorName + "(地方专项)";
+            }
+        }
+        return majorName;
+    }
+    private boolean getScoreLock(String location) {
+        boolean scoreLock = false;
+        return false;
+        /** TODO莫
+        BusiScoreLock scoreLockCond = new BusiScoreLock();
+        scoreLockCond.setIsValid(BoolValues.yes.getValue());
+        scoreLockCond.setProvinceName(location);
+        List<BusiScoreLock> busiScoreLockList = scoreLockService.selectBusiScoreLockList(scoreLockCond);
+        if (CollectionUtils.isEmpty(busiScoreLockList)) {
+            return scoreLock;
+        }
+        try {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+            Date start = sdf.parse(Calendar.getInstance().get(Calendar.YEAR) + "-" + busiScoreLockList.get(0).getStartDate());
+            Date end = sdf.parse(Calendar.getInstance().get(Calendar.YEAR) + "-" + busiScoreLockList.get(0).getEndDate());
+            Date now = new Date();
+            scoreLock = !(now.before(start) || now.after(end));
+        } catch (ParseException e) {
+            log.error("ScoreLock", e);
+        }
+        return scoreLock;**/
+    }
+    private List<String> split2list(String value) {
+        return StringUtils.isNotBlank(value) ? Arrays.asList(value.split(",")) : null;
+    }
+
+    public Map appendScoreCond(ZytbMarjorCriteriaNew query, Integer currYear, String location, String mode) {
+        // 查询最低分数
+        Integer lowestScore = null, highestScore = null;
+        // [Level=冲的最大值, 冲的最低值, 稳的最低值, 保的最低值, Rate>=99的最高值, Rate<=1的最小值]
+        Integer[] scoreRateRanges = mxjbWishScoreRateService.getWishScoreRatioRanges(currYear, query.getScore());
+
+        // MaxScore + 1 是为了让lowRank匹配时包含输入的分数, 现在都是整数,可以+1分变包含
+        Integer[] queryScoreRanges = null != query.getMinScore() && null != query.getMaxScore() ? new Integer[] { query.getMaxScore() + 1, query.getMinScore()} : null;
+        boolean hasScoreRangeBegin = null != queryScoreRanges && null != queryScoreRanges[1];
+        boolean hasScoreRangeEnd = null != queryScoreRanges && null != queryScoreRanges[0];
+
+        Integer pickType = query.getPickType();
+        if (null == pickType) {
+            lowestScore = null; // hasScoreRangeBegin ? queryScoreRanges[1] : scoreRateRanges[3];
+            highestScore = null; // hasScoreRangeEnd ? queryScoreRanges[0] : scoreRateRanges[0];
+        } else {
+            switch (pickType) {
+                case 0: // 冲
+                    lowestScore = hasScoreRangeBegin ? Math.max(queryScoreRanges[1], scoreRateRanges[1]) : scoreRateRanges[1];
+                    // highestScore = hasScoreRangeEnd ? Math.min(queryScoreRanges[0], scoreRateRanges[0]) : scoreRateRanges[0];
+                    break;
+                case 1: // 稳
+                    lowestScore = hasScoreRangeBegin ? Math.max(queryScoreRanges[1], scoreRateRanges[2]) : scoreRateRanges[2];
+                    highestScore = hasScoreRangeEnd ? Math.min(queryScoreRanges[0], scoreRateRanges[1]) : scoreRateRanges[1];
+                    break;
+                default: // 保
+                    // lowestScore = hasScoreRangeBegin ? Math.max(queryScoreRanges[1], scoreRateRanges[3]) : scoreRateRanges[3];
+                    highestScore = hasScoreRangeEnd ? Math.min(queryScoreRanges[0], scoreRateRanges[2]) : scoreRateRanges[2];
+                    break;
+            }
+        }
+        UniversitiesCondDTO uc = query.getUniversity();
+        //处理level(本科/专科)
+        if (null == uc) {
+            uc = new UniversitiesCondDTO();
+            query.setUniversity(uc);
+        }
+        Map cond = Maps.newHashMap();
+        if (StringUtils.isBlank(uc.getName())) {
+            cond.put("lowestScore", lowestScore);
+            cond.put("highestScore", highestScore);
+        }
+        /*if(null != scoreRateRanges) {   // TODO 引入的 99%, 1%时,是想排序时按一个级别,后面已不使用,暂注释,稍后可去掉
+            cond.put("minScore", scoreRateRanges[4]);
+            cond.put("maxScore", scoreRateRanges[5]);
+        } else {
+            cond.put("minScore", query.getScore() - 14);
+            cond.put("maxScore", query.getScore() + 15);
+        }*/
+        return cond;
+    }
+
+    public Map appendSeatCond(ZytbMarjorCriteriaNew query, Integer currPlanYear, Integer currSubmitYear, String location, String mode) {
+        // 查询最低名次 23位次/23年全局最低位次 * 22年全局最低位次=22位次
+        Integer lowestRank = null, highestRank = null;
+        // +30 -15 -60 600分 历史 => 冲:(600-630] 稳:(585-600] 保:(414,585]
+        Integer score = query.getScore().intValue();
+        Integer[] segments = getMappingRank(getPickTypeSegments(query.getScore(), query.getBatchMinScore(), location, currPlanYear, mode), location, currPlanYear, mode, score, currSubmitYear);
+        // MaxScore + 1 是为了让lowRank匹配时包含输入的分数, 现在都是整数,可以+1分变包含
+        Integer[] scoreRanges = null != query.getMinScore() && null != query.getMaxScore() ? getScoreRange(query.getMaxScore() + 1, query.getMinScore(), location, currPlanYear, mode) : null;
+        scoreRanges = getMappingRank(scoreRanges, location, currPlanYear, mode, score, currSubmitYear);
+        boolean hasScoreRangeBegin = null != scoreRanges && null != scoreRanges[0];
+        boolean hasScoreRangeEnd = null != scoreRanges && null != scoreRanges[1];
+
+        Integer pickType = query.getPickType();
+        if (null == pickType) {
+            // lowestRank = hasScoreRangeBegin ? scoreRanges[0] : segments[0];
+            // if (null != segments[3]) {
+            //     highestRank = hasScoreRangeEnd ? scoreRanges[1] : segments[3];
+            // }
+        } else {
+            switch (pickType) {
+                case 0:
+                    // lowestRank = hasScoreRangeBegin ? Math.max(scoreRanges[0], segments[0]) : segments[0];
+                    highestRank = hasScoreRangeEnd ? Math.min(scoreRanges[1], segments[1]) : segments[1];
+                    break;
+                case 1:
+                    lowestRank = hasScoreRangeBegin ? Math.max(scoreRanges[0], segments[1]) : segments[1];
+                    if(null != segments[2]) {
+                        highestRank = hasScoreRangeEnd ? Math.min(scoreRanges[1], segments[2]) : segments[2];
+                    }
+                    break;
+                default: // 保
+                    lowestRank = hasScoreRangeBegin ? Math.max(scoreRanges[0], segments[2]) : segments[2];
+                    // if(null != segments[3]) {
+                    //     highestRank = hasScoreRangeEnd ? Math.min(scoreRanges[1], segments[3]) : segments[3];
+                    // }
+                    break;
+            }
+        }
+        UniversitiesCondDTO uc = query.getUniversity();
+        //处理level(本科/专科)
+        if (null == uc) {
+            uc = new UniversitiesCondDTO();
+            query.setUniversity(uc);
+        }
+        Map cond = Maps.newHashMap();
+        if (StringUtils.isBlank(uc.getName())) {
+            cond.put("lowestRank", lowestRank);
+            cond.put("highestRank", highestRank);
+        }
+        // [Level=冲的最大值, 冲的最低值, 稳的最低值, 保的最低值, Rate>=99的最高值, Rate<=1的最小值]
+        /*Integer[] scoreRateRanges = mxjbWishScoreRateService.getWishScoreRatioRanges(currYear, query.getScore());
+        if(null != scoreRateRanges) { // TODO 引入的 99%, 1%时,是想排序时按一个级别,后面已不使用,暂注释,稍后可去掉
+            cond.put("minScore", scoreRateRanges[4]);
+            cond.put("maxScore", scoreRateRanges[5]);
+        } else {
+            cond.put("minScore", query.getScore() - 14);
+            cond.put("maxScore", query.getScore() + 15);
+        }*/
+        return cond;
+    }
+
+    private Integer getBatchline(String location, Integer year, Integer type, String examMajor) {
+        BBusiWishLocationSubmits lsCond = new BBusiWishLocationSubmits();
+        lsCond.setLocation(location);
+        lsCond.setYear(String.valueOf(year));
+        lsCond.setType(type);
+        lsCond.setCourse(examMajor);
+        List<BBusiWishLocationSubmits> list = busiWishLocationSubmitsService.selectBBusiWishLocationSubmitsList(lsCond);
+        return CollectionUtils.isNotEmpty(list) ? list.get(0).getScore() : null;
+    }
+
+    public List<ZytbDto.ZytbVolunteerRes> getRecommendVoluntary(ZytbMarjorCriteriaNew query, Integer pageNo, Integer pageSize) {
+        String location = SecurityUtils.getLoginUser().getUser().getLocation();
+        // 计划年度
+        Integer currYear = getYear();
+        // 录取年度
+        Integer currSubmitYear = getSubmitYear(location, null, query.getBatchName(), currYear);
+        Integer pickType = query.getPickType();
+
+        List<ZytbDto.ZytbVolunteerRes> volunteerResList = Lists.newArrayList();
+
+        Map cond = currYear.equals(currSubmitYear) ? appendScoreCond(query, currYear, location, query.getMode()) : appendSeatCond(query, currYear, currSubmitYear, location, query.getMode());
+        if (null == cond) {
+            return volunteerResList;
+        }
+        // 查询去年录取的高于排名的学校专业
+        cond.put("location", location);
+        cond.put("planYear", currYear);
+        cond.put("year", currSubmitYear);
+        cond.put("level", query.getBatchName().replaceAll("批", "")); // 本科,专科
+        cond.put("liberalScience", NumberUtils.toInt(query.getMode(), 0));
+        String batchLevel = BatchUtil.getBatchById(query.getBatch());
+        cond.put("majors", CollectionUtils.isNotEmpty(query.getMajors()) ? expandMarjors(batchLevel, query.getMajors()) : null);
+            cond.put("sinoForeign", query.getSinoforeign());
+        cond.put("specialProjectNation", query.getSpecialProjectNation());
+        cond.put("specialProjectLocal", query.getSpecialProjectLocal());
+        if (null != query.getCollect()) {
+            cond.put("collect", query.getCollect()); //  ? "有征集" : ""
+        }
+        UniversitiesCondDTO uc = query.getUniversity();
+        // uc.setLevel(BatchUtil.getBatchById(query.getBatch()));
+        cond.put("uName", uc.getName());
+        cond.put("uCode", uc.getCode());
+        cond.put("uManagerType", uc.getManagerType());
+        cond.put("uLocations", split2list(uc.getLocation()));
+        cond.put("uFeatureses", split2list(uc.getFeatures()));
+        cond.put("uNatureTypeCNs", split2list(uc.getNatureTypeCN()));
+        //20240625莫,此处type对u.`type` like优化为u.`type` in(enum)会提升性能
+        cond.put("uTypes", split2list(uc.getType()));
+//        List<String> uTypes = bBusiWishUniversitiesMapper.listDistinctAttributes("type");
+//        List<String> uTypeQueryList=new ArrayList<>();
+//        if(StringUtils.isNotBlank(uc.getType())){
+//            for (String dbUtype : uTypes) {
+//                for (String queryUtype : split2list(uc.getType())) {
+//                    if (StringUtils.isNotBlank(queryUtype) && (dbUtype.contains(queryUtype) || queryUtype.contains(dbUtype))) {
+//                        uTypeQueryList.add(dbUtype);
+//                    }
+//                }
+//            }
+//        }
+//        uTypeQueryList=uTypeQueryList.stream().filter(t->t != null && !t.isEmpty()).distinct().collect(Collectors.toList());
+//        if (CollectionUtils.isNotEmpty(uTypeQueryList)){
+//            cond.put("uTypes", uTypeQueryList);
+//        }
+
+        cond.put("uLevels", split2list(uc.getLevel()));
+        cond.put("sameYear", currSubmitYear.equals(currYear));
+        // cond.put("newSpecialGroup", "安徽".contains(location)); // 安徽 江西 2024 不在使用uCode
+        PageHelper.startPage(pageNo, pageSize);
+        List<BBusiWishUniversitySubmitRecruitPlan> submitPlanList = busiWishUniversitySubmitRecruitPlanMapper.selectWishUniversitySubmitPlanGroups(cond);
+        if(CollectionUtils.isEmpty(submitPlanList)) {
+            return volunteerResList;
+        }
+        Set<Long> universityIdSet = submitPlanList.stream().map(t -> t.getUniversityId()).collect(Collectors.toSet());
+
+        Map uCond = Maps.newHashMap();
+        uCond.put("ids", universityIdSet);
+        Map<Long, BBusiWishUniversities> wishUniversityMap = universityIdSet.size() > 0 ? bBusiWishUniversitiesMapper.selectBBusiWishUniversitiesListSimpleByIds(uCond).stream().collect(Collectors.toMap(BBusiWishUniversities::getId, Function.identity())) : Maps.newHashMap();
+
+//        Map<Long, BBusiWishUniversitySubmitMarjors> universityMarjorMap = Maps.newHashMap();
+//        Set<Long> matchedUniversityIdSet = submitPlanList.stream().filter(
+//                t -> null != t.getUniversityId() && t.getStats() == null).map(t -> Long.parseLong(t.getUniversityId())).collect(Collectors.toSet());
+//        if (matchedUniversityIdSet.size() > 0) {
+//            cond.clear();
+//            cond.put("location", location);
+//            cond.put("year", currYear - 1);
+//            cond.put("universityIds", matchedUniversityIdSet);
+//            cond.put("level", query.getBatchName().replaceAll("批", "")); // 本科,专科
+//            cond.put("liberalScience", NewgaokaoType.isNewgaokao33Province(location) ? 2 : (("物理".equals(subjects[0]) || "理科".equals(subjects[0])) ? 1 : 0));
+//            for(BBusiWishUniversitySubmits us : busiWishUniversitySubmitsMapper.selectBBusiWishUniversitySubmitsByCond(cond)) {
+//                BBusiWishUniversitySubmitMarjors submitMarjors = new BBusiWishUniversitySubmitMarjors();
+//                submitMarjors.setScore(us.getScore());
+//                submitMarjors.setSeat(us.getSeat());
+//                submitMarjors.setYear(us.getYear());
+//                submitMarjors.setType(us.getType());
+//                universityMarjorMap.put(Long.parseLong(us.getUniversityId()), submitMarjors);
+//            }
+//        }
+        Integer baseYearScore = currSubmitYear.equals(currYear) ? query.getScore().intValue() : getScoreOfLastYear(location, currYear, query.getMode(), query.getScore().intValue());
+        Integer historyIndex = currSubmitYear.equals(currYear) ? 0 : 1;
+
+        boolean scoreLock = getScoreLock(location);
+        boolean showInheritScore = Boolean.valueOf(configService.selectConfigByKey("voluntary.showInheritScore"));
+
+        String planYear = String.valueOf(currYear);
+        // Map<Integer, String> yearCourseMap = getYearCourseMap(currYear, mode);
+        for(BBusiWishUniversitySubmitRecruitPlan submitPlan : submitPlanList) {
+            ZytbDto.ZytbVolunteerRes res = new ZytbDto.ZytbVolunteerRes();
+            BBusiWishUniversities wishUniversities = wishUniversityMap.get(submitPlan.getUniversityId());
+            if (null != wishUniversities && StringUtils.isNotBlank(submitPlan.getUniversityName())
+                    && 0 != StringUtils.compare(submitPlan.getUniversityName(), wishUniversities.getName())) {
+                BBusiWishUniversities newWishUniversities = new BBusiWishUniversities();
+                BeanUtils.copyProperties(wishUniversities, newWishUniversities);
+                newWishUniversities.setName(submitPlan.getUniversityName());
+                res.setUniversity(newWishUniversities);
+            } else {
+                res.setUniversity(wishUniversities);
+            }
+            BBusiWishUniversitySubmitRecruitPlan plan = new BBusiWishUniversitySubmitRecruitPlan();
+            plan.setPlanCount(submitPlan.getPlanCount());
+            plan.setMajorCount(submitPlan.getMajorCount());
+            plan.setCollegeCode(submitPlan.getCollegeCode());
+            plan.setUniversityId(submitPlan.getUniversityId());
+            plan.setType(submitPlan.getType());
+            plan.setCourse(submitPlan.getCourse());
+            plan.setYear(planYear);
+            plan.setGroupsName(submitPlan.getGroupsName());
+            res.setRecruitPlan(plan);
+            res.setJCode(submitPlan.getUniversityCode());
+
+            BBusiWishUniversitySubmitMarjors[] histories = new BBusiWishUniversitySubmitMarjors[4];
+            if (null != submitPlan.getStats() && ArrayUtils.isNotEmpty(submitPlan.getStats().getStats())) {
+                SubmitYearsStats.YearStat[] stats = submitPlan.getStats().getStats();
+                for (int i = 0; i < Math.min(4, stats.length); i++) {
+                    if (stats[i] != null) {
+                        BBusiWishUniversitySubmitMarjors submitMarjor = new BBusiWishUniversitySubmitMarjors();
+                        submitMarjor.setNumReal(stats[i].getNumReal());
+                        submitMarjor.setScore(scoreLock ? stats[i].getScore() : stats[i].getCorrScore());
+                        submitMarjor.setSeat(scoreLock ? stats[i].getSeat() : stats[i].getCorrSeat());
+                        submitMarjor.setInheritScore(showInheritScore && null != stats[i].getScore() && null != submitMarjor.getScore() && stats[i].getScore() == 0 && submitMarjor.getScore() > 0);
+                        submitMarjor.setCollect(stats[i].getCollect());
+                        submitMarjor.setCollectDesc(stats[i].getCollectDesc());
+                        submitMarjor.setSinoForeign(stats[i].getSinoForeign());
+                        submitMarjor.setSinoForeignDesc(stats[i].getSinoForeignDesc());
+                        submitMarjor.setType(submitPlan.getType());
+                        Integer year = stats[i].getYear();
+                        submitMarjor.setYear(String.valueOf(year));
+                        // submitMarjor.setType(yearCourseMap.get(year));
+                        histories[i] = submitMarjor;
+                    }
+                }
+            }
+            BBusiWishUniversitySubmitMarjors empty = new BBusiWishUniversitySubmitMarjors();
+            for (int i = 0; i < histories.length; i++) {
+                if (null == histories[i]) {
+                    histories[i] = empty;
+                }
+            }
+            Integer batchLine = getBatchline(location, currYear, query.getBatchName().contains("本科") ? 1 : 5, getExamMajor());
+            MxjbWishScoreRateServiceImpl.ScoreRatioResult scoreRatioResult = getScoreRatioResult(histories, currYear, currSubmitYear, baseYearScore, location, query.getMode(), query.getScore().intValue(), batchLine);
+            if(null != scoreRatioResult) {
+                res.setPickType(scoreRatioResult.getEnrollLevel());
+                res.setEnrollOver(scoreRatioResult.getOverflow());
+                res.setEnrollRatio(String.valueOf(scoreRatioResult.getRatio()));
+                res.setEnrollRatioText(scoreRatioResult.getRiskLevel());
+            } else {
+                res.setPickType(pickType);
+                res.setEnrollRatio("");
+                res.setEnrollRatioText("");
+            }
+//            if (null == histories[0]) {
+//                histories[0] = universityMarjorMap.get(submitPlan.getUniversityId());
+//            }
+            if (histories != null && histories.length > 1) {
+                histories = historyIndex > 0 ? ArrayUtils.subarray(histories, 1, histories.length) : ArrayUtils.subarray(histories, 0, histories.length - 1);
+            }
+            res.setHistories(histories);
+            res.setHistory(res.getHistories()[0]);
+            res.setSpecialProject(submitPlan.getSpecialProject());
+            volunteerResList.add(res);
+        }
+        /*Collections.sort(volunteerResList, new Comparator<ZytbDto.ZytbVolunteerRes>() {
+            @Override
+            public int compare(ZytbDto.ZytbVolunteerRes o1, ZytbDto.ZytbVolunteerRes o2) {
+                Integer v1 = StringUtils.isNotBlank(o1.getEnrollRatio()) ? Integer.parseInt(o1.getEnrollRatio()) : 0;
+                Integer v2 = StringUtils.isNotBlank(o2.getEnrollRatio()) ? Integer.parseInt(o2.getEnrollRatio()) : 0;
+                return v1.compareTo(v2);
+            }
+        });*/
+        return PageUtil.getDtoListWithPageable(submitPlanList, volunteerResList);
+    }
+
+
+    private MxjbWishScoreRateServiceImpl.ScoreRatioResult getScoreRatioResult(BBusiWishUniversitySubmitMarjors[] histories, Integer currYear, Integer currSubmitYear, Integer baseYearScore, String location, String mode, Integer score, Integer batchLine
+    ) {
+        if(null != batchLine && baseYearScore < batchLine) {
+            return null;
+        }
+        Integer historyYear;
+        for (int i = 0; i < histories.length; i++) {
+            if (null != histories[i].getYear() && null != histories[i].getScore() && histories[i].getScore() > 0 && (historyYear = Integer.parseInt(histories[i].getYear())) <= currSubmitYear) {
+                Integer historyScore = histories[i].getScore().intValue();
+                if(!currYear.equals(currSubmitYear) || !historyYear.equals(currSubmitYear)) {
+                    BBusiWishScoreGroups currScoreRange = scoreRankService.getScoreRangeByScore(location, getYear(), mode, currYear, score);
+                    if(null != currScoreRange) {
+                        BBusiWishScoreGroups submitScoreRange = scoreRankService.getScoreRangeByBatch(location, currYear, currScoreRange.getMode(), currSubmitYear, currScoreRange.getType());
+                        BBusiWishScoreGroups historyScoreRange = scoreRankService.getScoreRangeByBatch(location, currYear, currScoreRange.getMode(), historyYear, currScoreRange.getType());
+                        Integer eqRank = scoreRankService.getEqRank(historyScoreRange, submitScoreRange, location, currYear, historyYear, historyScore, null, currSubmitYear);
+                        historyScore = scoreRankService.getScore(location, currSubmitYear, submitScoreRange.getMode(), eqRank);
+                    }
+                }
+                if(null == historyScore) {
+                    return null;
+                }
+                return mxjbWishScoreRateService.getWishScoreRatioResult(currYear, baseYearScore, historyScore);
+            }
+        }
+        return null;
+    }
+
+    public List<String> expandMarjors(String type, List<String> marjors) {
+        Map<String, List<String>> majorChildrenMap = typeMajorChildrenMap.get(type);
+        if (null == majorChildrenMap) {
+            return marjors;
+        }
+        List<String> marjorsList = Lists.newArrayList();
+        for (String marjor : marjors) {
+            marjorsList.add(marjor);
+            List<String> children = majorChildrenMap.get(marjor);
+            if (null != children) {
+                marjorsList.addAll(children);
+            }
+        }
+        return marjorsList;
+    }
+
+    private Map<String, Map<String, List<String>>> buildMajorChildrenMap() {
+        Map<String, String> majorCodeNameMap = Maps.newHashMap();
+        List<SyMajor> majorList = Lists.newArrayList();
+        syMajorService.selectSyMajorList(new SyMajor()).stream().forEach(m -> {
+            if (m.getLevel() == 2) {
+                majorCodeNameMap.put(m.getType() + m.getCode(), m.getName());
+            } else if (m.getLevel() == 3) {
+                majorList.add(m);
+            }
+        });
+        Map<String, Map<String, List<String>>> typeMajorChildrenMap = Maps.newHashMap();
+        majorList.stream().forEach(m -> {
+            String parent = majorCodeNameMap.get(m.getType() + m.getParentCode());
+            if (StringUtils.isNotBlank(parent)) {
+                Map<String, List<String>> majorChildrenMap = typeMajorChildrenMap.get(m.getType());
+                if (null == majorChildrenMap) {
+                    majorChildrenMap = Maps.newHashMap();
+                    typeMajorChildrenMap.put(m.getType(), majorChildrenMap);
+                }
+                List<String> childrenList = majorChildrenMap.get(parent);
+                if (null == childrenList) {
+                    childrenList = Lists.newArrayList();
+                    majorChildrenMap.put(parent, childrenList);
+                }
+                childrenList.add(m.getName());
+            }
+        });
+        return typeMajorChildrenMap;
+    }
+
+    public List<ZytbDto.ZytbVolunteerRes> filterResEmptyHistory(List<ZytbDto.ZytbVolunteerRes> resList) {
+        for (ZytbDto.ZytbVolunteerRes res : resList) {
+            BBusiWishUniversitySubmitMarjors[] histories = res.getHistories();
+            for (int i = 0; i < histories.length; i++) {
+                if (null != histories[i] && histories[i].getYear() == null) {
+                    histories[i] = null;
+                }
+            }
+        }
+        return resList;
+    }
+
+    public List<ZytbDto.ZytbVoluntaryMarjorDetail> filterEmptyHistory(List<ZytbDto.ZytbVoluntaryMarjorDetail> detailList) {
+        for (ZytbDto.ZytbVoluntaryMarjorDetail d : detailList) {
+            BBusiWishUniversitySubmitMarjors[] histories = d.getHistories();
+            for (int i = 0; i < histories.length; i++) {
+                if (null != histories[i] && histories[i].getYear() == null) {
+                    histories[i] = null;
+                }
+            }
+        }
+        return detailList;
+    }
+
+    public List<ZytbDto.ZytbVoluntaryMarjorDetail> getVoluntaryMarjors(ZytbDto.ZytbVoluntaryMarjorCond query) {
+        String location = SecurityUtils.getLoginUser().getUser().getLocation();
+        if (null == query.getYear()) {
+            query.setYear(getYear());
+        }
+        query.setMode(getExamMajor());
+        Integer currYear = query.getYear();
+        Integer currSubmitYear = getSubmitYear(location, null, query.getBatchName(), currYear);
+        Map cond = Maps.newHashMap();
+        cond.put("location", location);
+        cond.put("universityId", query.getUniversityId());
+        cond.put("level", query.getBatchName().replaceAll("批", "")); // 本科,专科
+        cond.put("liberalScience", NumberUtils.toInt(query.getMode(), 0));
+        cond.put("collegeCode", query.getCollegeCode());
+        cond.put("year", currYear); // 查询当前年的计划
+        // cond.put("uCode", query.getJCode());
+        List<BBusiWishUniversitySubmitRecruitPlan> planGroupDetailList = busiWishUniversitySubmitRecruitPlanMapper.selectWishUniversitySubmitPlanGroupDetails(cond);
+
+        Integer baseYearScore = currSubmitYear.equals(currYear) ? query.getScore() : getScoreOfLastYear(location, currYear, query.getMode(), query.getScore());
+        Integer historyIndex = currSubmitYear.equals(currYear) ? 0 : 1;
+//        Map<String, BBusiWishUniversitySubmitMarjors> universityMarjorMap = Maps.newHashMap();
+//        Set<Long> matchedUniversityIdSet = planGroupDetailList.stream().filter(
+//                t -> null != t.getUniversityId() && (t.getStats() == null || t.getStats().getStats()[0] == null)).map(t -> Long.parseLong(t.getUniversityId())).collect(Collectors.toSet());
+//        if (matchedUniversityIdSet.size() > 0) {
+//            cond.clear();
+//            cond.put("location", location);
+//            cond.put("year", currYear - 1);
+//            cond.put("universityIds", matchedUniversityIdSet);
+//            cond.put("level", query.getBatchName()); // 本科,专科
+//            cond.put("liberalScience", NewgaokaoType.isNewgaokao33Province(location) ? 2 : (("物理".equals(subjects[0]) || "理科".equals(subjects[0])) ? 1 : 0));
+//            for (BBusiWishUniversitySubmits us : busiWishUniversitySubmitsMapper.selectBBusiWishUniversitySubmitsByCond(cond)) {
+//                BBusiWishUniversitySubmitMarjors submitMarjors = new BBusiWishUniversitySubmitMarjors();
+//                submitMarjors.setScore(us.getScore());
+//                submitMarjors.setSeat(us.getSeat());
+//                submitMarjors.setYear(us.getYear());
+//                submitMarjors.setType(us.getType());
+//                universityMarjorMap.put(us.getUniversityId(), submitMarjors);
+//            }
+//        }
+
+        boolean scoreLock = getScoreLock(location);
+        boolean showInheritScore = Boolean.valueOf(configService.selectConfigByKey("voluntary.showInheritScore"));
+        Integer batchLine = getBatchline(location, currYear, query.getBatchName().contains("本科") ? 1 : 5, getExamMajor());
+
+        List<ZytbDto.ZytbVoluntaryMarjorDetail> detailList = Lists.newArrayList();
+        for (BBusiWishUniversitySubmitRecruitPlan planGroupDetail : planGroupDetailList) {
+            ZytbDto.ZytbVoluntaryMarjorDetail d = new ZytbDto.ZytbVoluntaryMarjorDetail();
+            BeanUtils.copyProperties(planGroupDetail, d);
+            majorFeatureCache.setMajorFeature(planGroupDetail, d);
+
+            BBusiWishUniversitySubmitMarjors[] histories = new BBusiWishUniversitySubmitMarjors[4];
+            if (null != planGroupDetail.getStats() && ArrayUtils.isNotEmpty(planGroupDetail.getStats().getStats())) {
+                SubmitYearsStats.YearStat[] stats = planGroupDetail.getStats().getStats();
+                for (int i = 0; i < Math.min(4, stats.length); i++) {
+                    if (stats[i] != null) {
+                        BBusiWishUniversitySubmitMarjors submitMarjor = new BBusiWishUniversitySubmitMarjors();
+                        submitMarjor.setId(stats[i].getSubmitId());
+                        submitMarjor.setYear(String.valueOf(stats[i].getYear()));
+                        submitMarjor.setNumReal(stats[i].getNumReal());
+                        submitMarjor.setScore(scoreLock ? stats[i].getScore() : stats[i].getCorrScore());
+                        submitMarjor.setSeat(scoreLock ? stats[i].getSeat() : stats[i].getCorrSeat());
+                        submitMarjor.setInheritScore(showInheritScore && null != stats[i].getScore() && null != submitMarjor.getScore() && stats[i].getScore() == 0 && submitMarjor.getScore() > 0);
+                        submitMarjor.setCollect(stats[i].getCollect());
+                        submitMarjor.setCollectDesc(stats[i].getCollectDesc());
+                        submitMarjor.setSinoForeign(stats[i].getSinoForeign());
+                        submitMarjor.setSinoForeignDesc(stats[i].getSinoForeignDesc());
+                        Integer year = stats[i].getYear();
+                        submitMarjor.setYear(String.valueOf(year));
+                        // submitMarjor.setType(planGroupDetail.getType());
+                        histories[i] = submitMarjor;
+                    }
+                }
+            }
+            BBusiWishUniversitySubmitMarjors empty = new BBusiWishUniversitySubmitMarjors();
+            for (int i = 0; i < histories.length; i++) {
+                if (null == histories[i]) {
+                    histories[i] = empty;
+                }
+            }
+            MxjbWishScoreRateServiceImpl.ScoreRatioResult scoreRatioResult = getScoreRatioResult(histories, currYear, currSubmitYear, baseYearScore, location, query.getMode(), query.getScore().intValue(), batchLine);;
+            if(null != scoreRatioResult) {
+                d.setPickType(scoreRatioResult.getEnrollLevel());
+                d.setEnrollOver(scoreRatioResult.getOverflow());
+                d.setEnrollRatio(scoreRatioResult.getRatio());
+                d.setEnrollRatioText(scoreRatioResult.getRiskLevel());
+            } else {
+                d.setPickType(null);
+                d.setEnrollRatio(null);
+                d.setEnrollRatioText("");
+            }
+//            if (null == histories[0]) {
+//                histories[0] = universityMarjorMap.get(planGroupDetail.getUniversityId());
+//            }
+            if (histories!= null && histories.length > 1) {
+                histories = historyIndex > 0 ? ArrayUtils.subarray(histories, 1, histories.length) : ArrayUtils.subarray(histories, 0, histories.length - 1);
+            }
+            d.setHistories(histories);
+            d.setHistory(d.getHistories()[0]);
+            detailList.add(d);
+        }
+
+        Collections.sort(detailList, new Comparator<ZytbDto.ZytbVoluntaryMarjorDetail>() {
+            @Override
+            public int compare(ZytbDto.ZytbVoluntaryMarjorDetail o1, ZytbDto.ZytbVoluntaryMarjorDetail o2) {
+                Integer iRet;
+                Integer h1 = null != o1.getHistory() && null != o1.getHistory().getScore() ? 0 : 1;
+                Integer h2 = null != o2.getHistory() && null != o2.getHistory().getScore() ? 0 : 1;
+                if((iRet = h1.compareTo(h2)) != 0) {
+                    return iRet;
+                }
+                Integer v1 = null != o1.getEnrollRatio() ? o1.getEnrollRatio() : 0;
+                Integer v2 = null != o2.getEnrollRatio() ? o2.getEnrollRatio() : 0;
+                if((iRet = v1.compareTo(v2)) != 0) {
+                    return iRet;
+                }
+                String m1 = null != o1.getMarjorBelongs() ? o1.getMarjorBelongs() : "";
+                String m2 = null != o2.getMarjorBelongs() ? o2.getMarjorBelongs() : "";
+                return m1.compareTo(m2);
+            }
+        });
+        return detailList;
+    }
+
+    private static class MajorFeatureCache {
+        Map<String, List<String>> typeNameMap = Maps.newHashMap();
+        Map<String, String> professionNameMap = Maps.newHashMap();
+        Map<String, String> levelMap = Maps.newHashMap();
+
+
+        public MajorFeatureCache(BBusiWishUniversitiesSubjectevaluateMapper busiWishUniversitiesSubjectevaluateMapper,
+                                 BBusiWishUniversitiesProfessionMapper busiWishUniversitiesProfessionMapper,
+                                 BBusiWishUniversitiesSubjectMapper busiWishUniversitiesSubjectMapper) {
+            busiWishUniversitiesSubjectevaluateMapper.selectBBusiWishUniversitiesSubjectevaluateList(new BBusiWishUniversitiesSubjectevaluate()).stream().forEach(t -> {
+                String key = t.getCollegeCode() + "_" + t.getName();
+                levelMap.put(key, t.getLevel());
+            });
+            BBusiWishUniversitiesProfession upCond = new BBusiWishUniversitiesProfession();
+            upCond.setExamType(Constant.EXAM_TYPE_PG);
+            busiWishUniversitiesProfessionMapper.selectBBusiWishUniversitiesProfessionList(new BBusiWishUniversitiesProfession()).stream().forEach(t -> {
+                String key = t.getCollegeCode() + "_" + t.getName();
+                professionNameMap.put(key, t.getProfessionType());
+            });
+            busiWishUniversitiesSubjectMapper.selectBBusiWishUniversitiesSubjectList(new BBusiWishUniversitiesSubject()).stream().forEach(t -> {
+                if(null == t.getSubjects()) {
+                    return;
+                }
+                t.getSubjects().forEach(s -> {
+                    String key = t.getCollegeCode() + "_" + s;
+                    List<String> typeNames = typeNameMap.get(key);
+                    if (null == typeNames) {
+                        typeNames = Lists.newArrayList();
+                        typeNameMap.put(key, typeNames);
+                    }
+                    typeNames.add(t.getTypeName());
+                });
+            });
+        }
+
+        public void setMajorFeature(BBusiWishUniversitySubmitRecruitPlan rp, ZytbDto.ZytbVoluntaryMarjorDetail d) {
+            // String idKey = rp.getUniversityCode() + "_" + rp.getMarjorId();
+            String nameKey = rp.getUniversityCode() + "_" + rp.getMarjorName();
+            d.setLevel(levelMap.get(nameKey));
+            d.setProfessionType(professionNameMap.get(nameKey));
+            d.setTypeNames(typeNameMap.get(nameKey));
+        }
+    };
+
+    /**
+     * 保存专业组
+     * @param wishResId
+     * @param pageNo
+     * @param pageSize
+     * @return
+     */
+    public List<ZytbDto.ZytbVolunteerRes> getRecommendVoluntaryRes(Long wishResId, Integer pageNo, Integer pageSize) {
+        return getRecommendVoluntaryRes(wishResId, pageNo, pageSize, null);
+    }
+    public List<ZytbDto.ZytbVolunteerRes> getRecommendVoluntaryRes(Long wishResId, Integer pageNo, Integer pageSize, Map dataMap) {
+        List<ZytbDto.ZytbVolunteerRes> volunteerResList = Lists.newArrayList();
+
+        BBusiWishRecords busiWishrecords = busiWishRecordsMapper.selectBBusiWishRecordsById(wishResId);
+        if (null == busiWishrecords) {
+            return volunteerResList;
+        }
+        SubmitWishRecordDTO.User us = JSON.parseObject(busiWishrecords.getUserSnapshot(), SubmitWishRecordDTO.User.class);
+        // 初始化院校,计划,录取
+        SubmitWishRecordDTO.SubmitWishRecordDetail detail = JSON.parseObject(busiWishrecords.getDetail(), SubmitWishRecordDTO.SubmitWishRecordDetail.class);
+        if (null == detail.getYear()) {
+            Integer year = NumberUtils.toInt(detail.getBatch().getScores().get(0).split("年")[0], 0);
+            detail.setYear(year > 0 ? year : DateUtils.getCurrentYear());
+            detail.getBatch().setName(StringUtils.replace(detail.getBatch().getName(), "普通类院校", ""));
+        }
+        Set<Long> allUniversityIdSet = Sets.newHashSet();
+        Map<Long, Long> planUniversityMap = Maps.newHashMap();
+        for (SubmitWishRecordDTO.SubmitWishRecordBatchWishes wish : detail.getBatch().getWishes()) {
+            allUniversityIdSet.add(wish.getUniversityId());
+            for (SubmitWishRecordDTO.SubmitWishRecordBatchMarjors marjor : wish.getMarjors()) {
+                planUniversityMap.put(marjor.getId(), wish.getUniversityId());
+            }
+        }
+        String location = SecurityUtils.getLoginUser().getUser().getLocation();
+        Integer currYear = detail.getYear();
+        String mode = us.getExamMajor();
+        // 录取年度
+        Integer currSubmitYear = getSubmitYear(location, null, detail.getBatch().getName(), currYear);
+        if (null != dataMap) {
+            dataMap.put("record", busiWishrecords);
+            dataMap.put("detail", detail);
+            dataMap.put("location", location);
+            dataMap.put("currYear", currYear);
+            dataMap.put("currSubmitYear", currSubmitYear);
+
+            Map cond = Maps.newHashMap();
+            cond.put("location", location);
+            cond.put("year", currYear);
+            cond.put("mode", mode);
+            dataMap.put("seat", getLowestRank(cond, detail.getScore().intValue()));
+        }
+        if (planUniversityMap.size() == 0) {
+            return volunteerResList;
+        }
+        Map cond = Maps.newHashMap();
+        cond.put("ids", Lists.newArrayList(planUniversityMap.keySet()));
+        Map<Long, BBusiWishUniversitySubmitRecruitPlan> planMap = busiWishUniversitySubmitRecruitPlanMapper.selectWishUniversitySubmitRecruitGroups(cond)
+                .stream().collect(Collectors.toMap(BBusiWishUniversitySubmitRecruitPlan::getId, Function.identity()));
+        busiWishUniversityMarjorsPlanSubmitMapper.selectBBusiWishUniversityMarjorsPlanSubmitByIds(planUniversityMap.keySet()).stream().forEach(t -> {
+            if (null != t.getStats()) {
+                planMap.get(t.getPlanId()).setStats(t.getStats());
+                planUniversityMap.remove(t.getPlanId());
+            }
+        });
+//        Map<Long, BBusiWishUniversitySubmitMarjors> universityMarjorMap = Maps.newHashMap();
+//        if (planUniversityMap.size() > 0) {
+//            cond.clear();
+//            cond.put("location", location);
+//            cond.put("year", detail.getYear() - 1);
+//            cond.put("universityIds", Sets.newHashSet(planUniversityMap.values()));
+//            cond.put("level", detail.getBatch().getName()); // 本科,专科
+//            cond.put("liberalScience", NewgaokaoType.isNewgaokao33Province(location) ? 2 : (("物理".equals(subjects[0]) || "理科".equals(subjects[0])) ? 1 : 0));
+//            for (BBusiWishUniversitySubmits us : busiWishUniversitySubmitsMapper.selectBBusiWishUniversitySubmitsByCond(cond)) {
+//                BBusiWishUniversitySubmitMarjors submitMarjors = new BBusiWishUniversitySubmitMarjors();
+//                submitMarjors.setScore(us.getScore());
+//                submitMarjors.setSeat(us.getSeat());
+//                submitMarjors.setYear(us.getYear());
+//                submitMarjors.setType(us.getType());
+//                universityMarjorMap.put(Long.parseLong(us.getUniversityId()), submitMarjors);
+//            }
+//        }
+        cond.clear();
+        cond.put("ids", allUniversityIdSet);
+        Map<Long, BBusiWishUniversities> wishUniversityMap = bBusiWishUniversitiesMapper.selectBBusiWishUniversitiesListSimpleByIds(cond).stream().collect(Collectors.toMap(BBusiWishUniversities::getId, Function.identity()));
+
+        boolean scoreLock = getScoreLock(location);
+        boolean showInheritScore = Boolean.valueOf(configService.selectConfigByKey("voluntary.showInheritScore"));
+
+        // Map<Integer, String> yearCourseMap = getYearCourseMap(detail.getYear(), detail.getMode().split(",")[0]);
+        Integer baseYearScore = currSubmitYear.equals(currYear) ? detail.getScore().intValue() : getScoreOfLastYear(location, currYear, mode, detail.getScore().intValue());
+        Integer historyIndex = currSubmitYear.equals(currYear) ? 0 : 1;
+        Integer batchLine = getBatchline(location, NumberUtils.toInt(busiWishrecords.getBatch(), 5), currYear, getExamMajor());
+        BBusiWishUniversitySubmitMarjors empty = new BBusiWishUniversitySubmitMarjors();
+        List<ZytbDto.ZytbVoluntaryMarjorDetail> marjorList;
+        for (SubmitWishRecordDTO.SubmitWishRecordBatchWishes wish : detail.getBatch().getWishes()) {
+            ZytbDto.ZytbVolunteerRes res = new ZytbDto.ZytbVolunteerRes();
+            BBusiWishUniversities wishUniversities = wishUniversityMap.get(wish.getUniversityId());
+            if (null != wishUniversities && StringUtils.isNotBlank(wish.getName())
+                    && 0 != StringUtils.compare(wish.getName(), wishUniversities.getName())) {
+                BBusiWishUniversities newWishUniversities = new BBusiWishUniversities();
+                BeanUtils.copyProperties(wishUniversities, newWishUniversities);
+                newWishUniversities.setName(wish.getName());
+                res.setUniversity(newWishUniversities);
+            } else {
+                res.setUniversity(wishUniversities);
+            }
+            res.setUniversityId(wish.getUniversityId());
+            res.setJCode(wish.getJCode());
+            res.setPickType(wish.getPickType());
+            volunteerResList.add(res);
+            for (SubmitWishRecordDTO.SubmitWishRecordBatchMarjors marjor : wish.getMarjors()) {
+                BBusiWishUniversitySubmitRecruitPlan plan = planMap.get(marjor.getId());
+                if (null == plan) {
+                    continue;
+                }
+                if (null != dataMap) {
+                    if(null == (marjorList = res.getMarjorList())) {
+                        marjorList = Lists.newArrayList();
+                        res.setMarjorList(marjorList);
+                    }
+                    marjorList.add(toMarjorDetail(mode, batchLine, plan, marjor, null, empty, currYear, baseYearScore, historyIndex, scoreLock, showInheritScore, currSubmitYear, detail.getScore().intValue()));
+                }
+                if (null == res.getRecruitPlan()) {
+                    plan.setId(null);
+                    plan.setMarjorName(null);
+                    plan.setMarjorDirection(null);
+                    plan.setMarjorBelongs(null);
+                    plan.setXuezhi(null);
+                    plan.setXuefei(null);
+                    plan.setMajorCount(1);
+                    res.setRecruitPlan(plan);
+                    res.setSpecialProject(plan.getSpecialProject());
+                } else {
+                    BBusiWishUniversitySubmitRecruitPlan merge = res.getRecruitPlan();
+                    merge.setMajorCount(merge.getMajorCount() + 1);
+                    merge.setPlanCount(merge.getPlanCount() + plan.getPlanCount());
+                }
+                if(null == plan.getStats()) {
+                    continue;
+                }
+                SubmitYearsStats.YearStat[] statsList = plan.getStats().getStats();
+                plan.setStats(null);
+                BBusiWishUniversitySubmitMarjors[] submitMarjorList = res.getHistories();
+                if (null == submitMarjorList) {
+                    submitMarjorList = new BBusiWishUniversitySubmitMarjors[4];
+                    res.setHistories(submitMarjorList);
+                }
+
+                for (int i = 0; i < Math.min(4, statsList.length); i++) {
+                    if (null == statsList[i]) {
+                        continue;
+                    }
+                    BBusiWishUniversitySubmitMarjors merge = submitMarjorList[i];
+                    if (null == merge) {
+                        submitMarjorList[i] = new BBusiWishUniversitySubmitMarjors();
+                        submitMarjorList[i].setScore(scoreLock ? statsList[i].getScore() : statsList[i].getCorrScore());
+                        submitMarjorList[i].setSeat(scoreLock ? statsList[i].getSeat() : statsList[i].getCorrSeat());
+                        submitMarjorList[i].setNumReal(statsList[i].getNumReal());
+                        submitMarjorList[i].setCollect(statsList[i].getCollect());
+                        submitMarjorList[i].setCollectDesc(statsList[i].getCollectDesc());
+                        submitMarjorList[i].setSinoForeign(statsList[i].getSinoForeign());
+                        submitMarjorList[i].setSinoForeignDesc(statsList[i].getSinoForeignDesc());
+                        Integer year = statsList[i].getYear();
+                        submitMarjorList[i].setYear(String.valueOf(year));
+                        // submitMarjorList[i].setType(yearCourseMap.get(year));
+                        continue;
+                    } else {
+                        if (null != merge.getNumReal() && null != statsList[i].getNumReal()) {
+                            merge.setNumReal(merge.getNumReal() + statsList[i].getNumReal());
+                        } else if (null != merge.getNumReal()) {
+                            merge.setNumReal(merge.getNumReal());
+                        } else if (null != statsList[i].getNumReal()) {
+                            merge.setNumReal(statsList[i].getNumReal());
+                        }
+                        if (null == merge.getCollect() && null != statsList[i].getCollect() && statsList[i].getCollect()) {
+                            merge.setCollect(statsList[i].getCollect());
+                            merge.setCollectDesc(statsList[i].getCollectDesc());
+                        }
+                        if (null == merge.getSinoForeign() && null != statsList[i].getSinoForeign() && statsList[i].getSinoForeign()) {
+                            merge.setSinoForeign(statsList[i].getSinoForeign());
+                            merge.setSinoForeignDesc(statsList[i].getSinoForeignDesc());
+                        }
+                        merge.setScore(Math.min(merge.getScore(), scoreLock ? statsList[i].getScore() : statsList[i].getCorrScore()));
+                        merge.setSeat(Math.max(merge.getSeat(), scoreLock ? statsList[i].getSeat() : statsList[i].getCorrSeat()));
+                    }
+                }
+            }
+            res.setEnrollRatio(wish.getEnrollRatio());
+            res.setEnrollRatioText(wish.getEnrollRatioText());
+        }
+        volunteerResList.forEach(t -> {
+            BBusiWishUniversitySubmitMarjors[] submitMarjorsList = t.getHistories();
+            if (null == submitMarjorsList) {
+                submitMarjorsList = new BBusiWishUniversitySubmitMarjors[4];
+                t.setHistories(submitMarjorsList);
+            }
+            for (int i = 0; i < submitMarjorsList.length; i++) {
+                if (null == submitMarjorsList[i]) {
+                    submitMarjorsList[i] = empty;
+                }
+            }
+            MxjbWishScoreRateServiceImpl.ScoreRatioResult scoreRatioResult = getScoreRatioResult(submitMarjorsList, currYear, currSubmitYear, baseYearScore, location, mode, detail.getScore().intValue(), batchLine);
+            if (null != scoreRatioResult) {
+                // t.setPickType(scoreRatioResult.getEnrollLevel());
+                t.setEnrollOver(scoreRatioResult.getOverflow());
+                // t.setEnrollRatio(String.valueOf(scoreRatioResult.getRatio()));
+                // t.setEnrollRatioText(scoreRatioResult.getRiskLevel());
+            } else {
+                // t.setPickType(null);
+                // t.setEnrollRatio("");
+                // t.setEnrollRatioText("");
+            }
+//            if (null == submitMarjorsList[0]) {
+//                submitMarjorsList[0] = universityMarjorMap.get(t.getUniversityId());
+//            }
+            t.setUniversityId(null);
+            if (null != submitMarjorsList && submitMarjorsList.length > 1) {
+                submitMarjorsList = historyIndex > 0 ? ArrayUtils.subarray(submitMarjorsList, 1, submitMarjorsList.length) : ArrayUtils.subarray(submitMarjorsList, 0, submitMarjorsList.length - 1);
+            }
+            t.setHistories(submitMarjorsList);
+            t.setHistory(t.getHistories()[0]);
+        });
+        /*Collections.sort(volunteerResList, new Comparator<ZytbDto.ZytbVolunteerRes>() {
+            @Override
+            public int compare(ZytbDto.ZytbVolunteerRes o1, ZytbDto.ZytbVolunteerRes o2) {
+                Double v1 = null != o1.getHistory() && null != o1.getHistory().getScore() ? o1.getHistory().getScore() : 0.0;
+                Double v2 = null != o2.getHistory() && null != o2.getHistory().getScore() ? o2.getHistory().getScore() : 0.0;
+                return -v1.compareTo(v2);
+            }
+        });*/
+        return PageUtil.buildListForPage(volunteerResList, pageNo, pageSize);
+    }
+    public List<ZytbDto.ZytbVoluntaryMarjorDetail> getVoluntaryMarjorsRes(Long wishResId, String collegeCode, String jCode) {
+        List<ZytbDto.ZytbVoluntaryMarjorDetail> detailList = Lists.newArrayList();
+
+        BBusiWishRecords busiWishrecords = busiWishRecordsMapper.selectBBusiWishRecordsById(wishResId);
+        if (null == busiWishrecords) {
+            return detailList;
+        }
+        SubmitWishRecordDTO.User us = JSON.parseObject(busiWishrecords.getUserSnapshot(), SubmitWishRecordDTO.User.class);
+        String mode = us.getExamMajor();
+        // 初始化院校,计划,录取
+        SubmitWishRecordDTO.SubmitWishRecordDetail detail = JSON.parseObject(busiWishrecords.getDetail(), SubmitWishRecordDTO.SubmitWishRecordDetail.class);
+        Map<Long, Long> planUniversityMap = Maps.newHashMap();
+        for (SubmitWishRecordDTO.SubmitWishRecordBatchWishes wish : detail.getBatch().getWishes()) {
+            if (!wish.getCollegeCode().equals(collegeCode) || StringUtils.isNotBlank(jCode) && !jCode.equals(wish.getJCode())) {
+                continue;
+            }
+            for (SubmitWishRecordDTO.SubmitWishRecordBatchMarjors marjor : wish.getMarjors()) {
+                planUniversityMap.put(marjor.getId(), wish.getUniversityId());
+            }
+        }
+        if (planUniversityMap.size() == 0) {
+            return detailList;
+        }
+        Map cond = Maps.newHashMap();
+        cond.put("ids", Lists.newArrayList(planUniversityMap.keySet()));
+        Map<Long, BBusiWishUniversitySubmitRecruitPlan> planMap = busiWishUniversitySubmitRecruitPlanMapper.selectWishUniversitySubmitRecruitGroups(cond)
+                .stream().collect(Collectors.toMap(BBusiWishUniversitySubmitRecruitPlan::getId, Function.identity()));
+        busiWishUniversityMarjorsPlanSubmitMapper.selectBBusiWishUniversityMarjorsPlanSubmitByIds(planUniversityMap.keySet()).stream().forEach(t -> {
+            planMap.get(t.getPlanId()).setStats(t.getStats());
+            planUniversityMap.remove(t.getPlanId());
+        });
+
+        String location = SecurityUtils.getLoginUser().getUser().getLocation();
+        Integer currYear = detail.getYear();
+        Integer currSubmitYear = getSubmitYear(location, null, detail.getBatch().getName(), currYear);
+//        Map<Long, BBusiWishUniversitySubmitMarjors> universityMarjorMap = Maps.newHashMap();
+//        if (planUniversityMap.size() > 0) {
+//            cond.clear();
+//            cond.put("location", location);
+//            cond.put("year", detail.getYear() - 1);
+//            cond.put("universityIds", Sets.newHashSet(planUniversityMap.values()));
+//            cond.put("level", detail.getBatch().getName()); // 本科,专科
+//            cond.put("liberalScience", NewgaokaoType.isNewgaokao33Province(location) ? 2 : (("物理".equals(subjects[0]) || "理科".equals(subjects[0])) ? 1 : 0));
+//            for (BBusiWishUniversitySubmits us : busiWishUniversitySubmitsMapper.selectBBusiWishUniversitySubmitsByCond(cond)) {
+//                BBusiWishUniversitySubmitMarjors submitMarjors = new BBusiWishUniversitySubmitMarjors();
+//                submitMarjors.setScore(us.getScore());
+//                submitMarjors.setSeat(us.getSeat());
+//                submitMarjors.setYear(us.getYear());
+//                submitMarjors.setType(us.getType());
+//                universityMarjorMap.put(Long.parseLong(us.getUniversityId()), submitMarjors);
+//            }
+//        }
+        cond.clear();
+
+        boolean scoreLock = getScoreLock(location);
+        boolean showInheritScore = Boolean.valueOf(configService.selectConfigByKey("voluntary.showInheritScore"));
+
+        Integer baseYearScore = currSubmitYear.equals(currYear) ? detail.getScore().intValue() : getScoreOfLastYear(location, currYear, mode, detail.getScore().intValue());
+        Integer historyIndex = currSubmitYear.equals(currYear) ? 0 : 1;
+        BBusiWishUniversitySubmitMarjors empty = new BBusiWishUniversitySubmitMarjors();
+        Integer batchLine = getBatchline(location, currYear, NumberUtils.toInt(busiWishrecords.getBatch(), 5), getExamMajor());
+        for (SubmitWishRecordDTO.SubmitWishRecordBatchWishes wish : detail.getBatch().getWishes()) {
+            if (!wish.getCollegeCode().equals(collegeCode) || StringUtils.isNotBlank(jCode) && !jCode.equals(wish.getJCode())) {
+                continue;
+            }
+            for (SubmitWishRecordDTO.SubmitWishRecordBatchMarjors marjor : wish.getMarjors()) {
+                BBusiWishUniversitySubmitRecruitPlan plan = planMap.get(marjor.getId());
+                if (null == plan) {
+                    continue;
+                }
+                ZytbDto.ZytbVoluntaryMarjorDetail d = toMarjorDetail(mode, batchLine, plan, marjor, null,
+                        empty, currYear, baseYearScore, historyIndex, scoreLock, showInheritScore,
+                        currSubmitYear, detail.getScore().intValue());
+                detailList.add(d);
+            }
+        }
+        return detailList;
+    }
+
+    private ZytbDto.ZytbVoluntaryMarjorDetail toMarjorDetail(String mode, Integer batchLine, BBusiWishUniversitySubmitRecruitPlan plan, SubmitWishRecordDTO.SubmitWishRecordBatchMarjors marjor, Map<Integer, String> yearCourseMap,
+                                                             BBusiWishUniversitySubmitMarjors empty, Integer currYear, Integer baseYearScore, Integer historyIndex, boolean scoreLock, boolean showInheritScore,
+                                                             Integer currSubmitYear, Integer score) {
+        ZytbDto.ZytbVoluntaryMarjorDetail d = new ZytbDto.ZytbVoluntaryMarjorDetail();
+        BeanUtils.copyProperties(plan, d);
+        d.setMarjorName(marjor.getName());
+        BBusiWishUniversitySubmitMarjors[] submitMarjorList = d.getHistories();
+        String location = SecurityUtils.getLoginUser().getUser().getLocation();
+        if(null != plan.getStats()) {
+            SubmitYearsStats.YearStat[] statsList = plan.getStats().getStats();
+            for (int i = 0; i < Math.min(4, statsList.length); i++) {
+                if (null == statsList[i]) {
+                    continue;
+                }
+                submitMarjorList[i] = new BBusiWishUniversitySubmitMarjors();
+                submitMarjorList[i].setYear(String.valueOf(statsList[i].getYear()));
+                submitMarjorList[i].setScore(scoreLock ? statsList[i].getScore() : statsList[i].getCorrScore());
+                submitMarjorList[i].setSeat(scoreLock ? statsList[i].getSeat() : statsList[i].getCorrSeat());
+                submitMarjorList[i].setInheritScore(showInheritScore && null != statsList[i].getScore() && null != submitMarjorList[i].getScore() && statsList[i].getScore() == 0 && submitMarjorList[i].getScore() > 0);
+                submitMarjorList[i].setNumReal(statsList[i].getNumReal());
+                submitMarjorList[i].setCollect(statsList[i].getCollect());
+                submitMarjorList[i].setCollectDesc(statsList[i].getCollectDesc());
+                submitMarjorList[i].setSinoForeign(statsList[i].getSinoForeign());
+                submitMarjorList[i].setSinoForeignDesc(statsList[i].getSinoForeignDesc());
+            }
+        }
+        for (int i = 0; i < submitMarjorList.length; i++) {
+            if (null == submitMarjorList[i]) {
+                submitMarjorList[i] = empty;
+            }
+        }
+        d.setPickType(marjor.getPickType());
+        d.setEnrollRatio(NumberUtils.toInt(marjor.getEnrollRatio(), 0));
+        d.setEnrollRatioText(marjor.getEnrollRatioText());
+        d.setEnrollFluctuate(marjor.getEnrollFluctuate());
+        MxjbWishScoreRateServiceImpl.ScoreRatioResult scoreRatioResult = getScoreRatioResult(submitMarjorList, currYear, currSubmitYear, baseYearScore, location, mode, score, batchLine);
+        if (null != scoreRatioResult) {
+            // d.setPickType(scoreRatioResult.getEnrollLevel());
+            d.setEnrollOver(scoreRatioResult.getOverflow());
+            // d.setEnrollRatio(scoreRatioResult.getRatio());
+            // d.setEnrollRatioText(scoreRatioResult.getRiskLevel());
+        } else {
+            // d.setPickType(null);
+            // d.setEnrollRatio(null);
+            // d.setEnrollRatioText("");
+        }
+//                if(null == submitMarjorList[0]) {
+//                    submitMarjorList[0] = universityMarjorMap.get(wish.getUniversityId());
+//                }
+        if (submitMarjorList!= null && submitMarjorList.length > 1) {
+            submitMarjorList = historyIndex > 0 ? ArrayUtils.subarray(submitMarjorList, 1, submitMarjorList.length) : ArrayUtils.subarray(submitMarjorList, 0, submitMarjorList.length - 1);
+        }
+        d.setHistories(submitMarjorList);
+        d.setHistory(d.getHistories()[0]);
+        return d;
+    }
+
+    private Integer[] getScoreRange(Integer maxScore, Integer minScore, String location, Integer currYear, String mode) {
+        Map cond = Maps.newHashMap();
+        cond.put("location", location);
+        cond.put("year", currYear);
+        cond.put("mode", mode);
+        Integer minLevel = getLowestRank(cond, maxScore);
+        Integer maxLevel = getLowestRank(cond, minScore);
+        return new Integer[] {minLevel, maxLevel};
+    }
+
+    /**
+     * 查询
+     */
+    private Integer[] getPickTypeSegments(Integer score, Integer batchMinScore, String location, Integer currYear, String mode) {
+        // +30 -15 -60 => 600分 历史  冲:(600-630] 稳:(585-600] 保:(414,585]  // 600 => [630=70 冲 600=91 稳 585=200 保 414=300)
+        if (null == score) {
+            log.error("Score is null for {} at {} {}", location, currYear, mode);
+            return null;
+        }
+        Map cond = Maps.newHashMap();
+        cond.put("location", location);
+        cond.put("year", currYear);
+        cond.put("mode", mode);
+
+        // [Level=冲的最大值, 冲的最低值, 稳的最低值, 保的最低值, Rate>=99的最高值, Rate<=1的最小值]
+        Integer[] levelRanges = mxjbWishScoreRateService.getWishScoreRatioRanges(currYear, score);
+        if (null == levelRanges) {
+            log.error("getLevelRanges for {} at {} {}", location, currYear, cond.get("mode"));
+            return null;
+        }
+
+        Integer rank1, rank2, rank3, rank4;
+        if (null == (rank2 = getLowestRank(cond, levelRanges[1]))) {
+            log.error("getLowestRank for {} at {} {}", location, currYear, cond.get("mode"));
+            return null;
+        }
+
+        Integer[] segments = new Integer[4];
+        segments[0] = null == (rank1 = getLowestRank(cond, levelRanges[0])) ? rank2 - 1 : Math.min(rank1, rank2 - 1);
+        segments[1] = rank2;
+        segments[2] = null == (rank3 = getLowestRank(cond, levelRanges[2])) ? null : Math.max(rank3, rank2 + 1);
+        segments[3] = null == (rank4 = getLowestRank(cond, Math.max(batchMinScore, levelRanges[3]))) ? null : null == rank3 ? rank4 : Math.max(rank4, rank3 + 1);
+        return segments;
+    }
+
+    // 生成缓存数据表
+    public void calculateSubmitPlanData(String location, Integer year) {
+        Integer[] batchs = new Integer[] {0, 1, 2, 3, 4}; // 0 提前批 1 本科一批 2 本科二批 3 本科三批 4 高职专科批
+        Integer[] liberalSciences = new Integer[] {0, 1, 2}; // 1理科(物理),0文科(历史), 2文理不分
+        StopWatch stopWatch = new StopWatch();
+        for (Integer batch : batchs) {
+            for (Integer liberalScience : liberalSciences) {
+                stopWatch.reset();
+                stopWatch.start();
+                calculateSubmitPlanData(location, year, batch, liberalScience);
+                stopWatch.stop();
+                log.info("process {} {} Batch:{} {} used: {}", location, year, batch, liberalScience, stopWatch.getTime(TimeUnit.SECONDS));
+            }
+        }
+        log.info("process Completed");
+    }
+
+    private void calculateSubmitPlanData(String location, Integer year, Integer batch, Integer liberalScience) {
+        // 查询今年的计划
+        BBusiWishUniversitySubmitRecruitPlan planCond = new BBusiWishUniversitySubmitRecruitPlan();
+        planCond.setLocation(location);
+        planCond.setYear(year.toString());
+        planCond.setBatch(batch.longValue());
+        planCond.setLiberalScience(liberalScience);
+        List<BBusiWishUniversitySubmitRecruitPlan> recruitPlanList = busiWishUniversitySubmitRecruitPlanMapper.selectBBusiWishUniversitySubmitRecruitPlanList(planCond)
+                .stream().filter(t -> StringUtils.isNotBlank(t.getCollegeCode())).collect(Collectors.toList());  // TODO 没有招生代码的如何处理?
+        if (CollectionUtils.isEmpty(recruitPlanList)) {
+            return;
+        }
+        // 检查 Group
+        Map<String, BBusiWishUniversityMarjorsGroup> universityMarjorGroupMap = Maps.newHashMap();
+        BBusiWishUniversityMarjorsGroup groupCond = new BBusiWishUniversityMarjorsGroup();
+        groupCond.setLocation(location);
+        String planLevel = recruitPlanList.get(0).getLevel();
+        groupCond.setLevel(StringUtils.isNotBlank(planLevel) ? planLevel.substring(0, 2) : "");
+        groupCond.setLiberalScience(liberalScience);
+        for (BBusiWishUniversityMarjorsGroup group : busiWishUniversityMarjorsGroupMapper.selectBBusiWishUniversityMarjorsGroupList(groupCond)) {
+            String majorName = getMajorName(group.getMarjorName(), group.getMarjorSpecial());
+            String universityMajorName = group.getUniversityId() + ":" + majorName;
+            universityMarjorGroupMap.put(universityMajorName, group);
+        }
+
+        List<BBusiWishUniversityMarjorsGroup> newGroupList = Lists.newArrayList();
+        // key is universityCollege, value is recruitPlans
+        Map<String, List<BBusiWishUniversitySubmitRecruitPlan>> universityCollegePlansMap = Maps.newHashMap();
+        // key is batch, value is level
+        Map<Long, String> levelNameMap = Maps.newHashMap();
+        // key is universityMarjorName, value is recruitPlan
+        Map<String, BBusiWishUniversitySubmitRecruitPlan> universityMarjorPlanMap = Maps.newHashMap();
+        BBusiWishUniversitySubmitRecruitPlan tmpPlan;
+        Map<Long, BBusiWishUniversityMarjorsGroup> planMarjorsGroupMap = Maps.newHashMap();
+        for (BBusiWishUniversitySubmitRecruitPlan plan : recruitPlanList) {
+            String majorName = getMajorName(plan.getMarjorName(), plan.getMarjorDirection());
+            String universityMajorName = plan.getUniversityId() + ":" + majorName;
+            if (null != (tmpPlan = universityMarjorPlanMap.putIfAbsent(universityMajorName, plan))) {
+                log.warn("Plan {} Dup with {} ", plan.getId(), tmpPlan.getId()); // TODO 计划只取一个,重复的合并还是忽略?
+                continue;
+            }
+            BBusiWishUniversityMarjorsGroup marjorsGroup = universityMarjorGroupMap.get(universityMajorName);
+            if(null == marjorsGroup) {
+                marjorsGroup = new BBusiWishUniversityMarjorsGroup();
+                marjorsGroup.setLocation(location);
+                marjorsGroup.setLevel(plan.getLevel());
+                marjorsGroup.setLiberalScience(liberalScience);
+                marjorsGroup.setUniversityId(plan.getUniversityId());
+                marjorsGroup.setMarjorName(plan.getMarjorName());
+                String special = majorName.substring(plan.getMarjorName().length());
+                if (special.length() > 0) {
+                    marjorsGroup.setMarjorSpecial(special.replace("(|)", ""));
+                } else {
+                    marjorsGroup.setMarjorSpecial(special);
+                }
+                marjorsGroup.setStatus(1L);
+                newGroupList.add(marjorsGroup);
+                universityMarjorGroupMap.put(universityMajorName, marjorsGroup);
+            }
+            planMarjorsGroupMap.put(plan.getId(), marjorsGroup);
+            levelNameMap.putIfAbsent(plan.getBatch(), plan.getLevel());
+            String universityCollege =  plan.getUniversityId() + ":" + plan.getCollegeCode();
+            List<BBusiWishUniversitySubmitRecruitPlan> groupPlanList =  universityCollegePlansMap.get(universityCollege);
+            if (null == groupPlanList) {
+                groupPlanList = Lists.newArrayList();
+                universityCollegePlansMap.put(universityCollege, groupPlanList);
+            }
+            groupPlanList.add(plan);
+        }
+
+        // 查询去年的报名, 然后映射计划与报名
+        BBusiWishUniversitySubmitMarjors majorCond = new BBusiWishUniversitySubmitMarjors();
+        majorCond.setLocation(planCond.getLocation());
+        majorCond.setYear(String.valueOf(year - 1));
+        majorCond.setLevel(levelNameMap.get(planCond.getBatch()));
+        majorCond.setLiberalScience(planCond.getLiberalScience().intValue());
+
+        // key is planId, value is Submit for last year need 3 years
+        Map<Long, BBusiWishUniversitySubmitMarjors[]> planSubmitMarjorsMap = Maps.newHashMap();
+        BBusiWishUniversitySubmitMarjors[] tmpSubmits;
+        for (int yearIdx = 2, yr = year - 3; yr < year; yr++, yearIdx--) {
+            majorCond.setYear(String.valueOf(yr));
+            for (BBusiWishUniversitySubmitMarjors marjor : busiWishUniversitySubmitMarjorsMapper.selectBBusiWishUniversitySubmitMarjorsList(majorCond)) {
+                String majorName = getMajorName(marjor.getMarjorName(), marjor.getMarjorDirection());
+                String universityMajorName = marjor.getUniversityId() + ":" + majorName;
+                BBusiWishUniversitySubmitRecruitPlan plan = universityMarjorPlanMap.get(universityMajorName);
+                if (null == plan) { // 未找到计划的忽略
+                    continue;
+                }
+                planSubmitMarjorsMap.get(plan.getId());
+                if (null == (tmpSubmits = planSubmitMarjorsMap.get(plan.getId()))) {
+                    tmpSubmits = new BBusiWishUniversitySubmitMarjors[4];
+                    planSubmitMarjorsMap.put(plan.getId(), tmpSubmits);
+                } else if (null != tmpSubmits[yearIdx]) {
+                    log.warn("Submit {} Dup with {} ", marjor.getId(), tmpSubmits[yearIdx].getId()); // TODO 报名只取一个,重复的合并还是忽略?
+                    continue;
+                }
+                tmpSubmits[yearIdx] = marjor;
+            }
+        }
+
+        // 计算专业组
+        BBusiWishUniversityMarjorsCollege collegeCond = new BBusiWishUniversityMarjorsCollege();
+        collegeCond.setLocation(planCond.getLocation());
+        collegeCond.setYear(planCond.getYear());
+        collegeCond.setLevel(levelNameMap.get(planCond.getBatch()));
+        collegeCond.setLiberalScience(planCond.getLiberalScience().intValue());
+        Map<String, BBusiWishUniversityMarjorsCollege> universityMarjorsCollegeMap = busiWishUniversityMarjorsCollegeMapper.selectBBusiWishUniversityMarjorsCollegeList(collegeCond)
+                .stream().collect(Collectors.toMap(t -> t.getUniversityId() + ":" + t.getCollegeCode(), Function.identity()));
+
+        BBusiWishUniversityMarjorsPlanSubmit planSubmitCond = new BBusiWishUniversityMarjorsPlanSubmit();
+        planSubmitCond.setLocation(planCond.getLocation());
+        planSubmitCond.setYear(planCond.getYear());
+        planSubmitCond.setLevel(levelNameMap.get(planCond.getBatch()));
+        planSubmitCond.setLiberalScience(planCond.getLiberalScience().intValue());
+        Set<Long> universityMarjorsSubmitIdSet = busiWishUniversityMarjorsPlanSubmitMapper.selectBBusiWishUniversityMarjorsPlanSubmitList(planSubmitCond)
+                .stream().map(BBusiWishUniversityMarjorsPlanSubmit::getPlanId).collect(Collectors.toSet());
+
+        BBusiWishUniversityMarjorsCollege existCollege;
+        for (String universityCollege : universityCollegePlansMap.keySet()) {
+            List<BBusiWishUniversitySubmitRecruitPlan> planList = universityCollegePlansMap.get(universityCollege);
+            // 创建专业组
+            BBusiWishUniversityMarjorsCollege college = new BBusiWishUniversityMarjorsCollege();
+            BeanUtils.copyProperties(collegeCond, college);
+            college.setPlanCount(0L);
+            college.setMarjorCount((long) planList.size());
+            tmpPlan = planList.get(0);
+            college.setUniversityId(tmpPlan.getUniversityId());
+            college.setCollegeCode(tmpPlan.getCollegeCode());
+            // 汇总 MarjorCount, planCount(sum), score(min), seat(max), realNum(sum)
+            for (BBusiWishUniversitySubmitRecruitPlan plan : planList) {
+                college.setPlanCount(college.getPlanCount() + plan.getPlanCount());
+                BBusiWishUniversitySubmitMarjors[] submitMarjorsList = planSubmitMarjorsMap.get(plan.getId());
+                if (null != submitMarjorsList) {
+                    SubmitYearsStats submitYearsStats = new SubmitYearsStats();
+                    // submitYearsStats.setYear(year);
+                    SubmitYearsStats.YearStat yearStats[] = new SubmitYearsStats.YearStat[3];
+                    submitYearsStats.setStats(yearStats);
+                    for (int i = 0; i < submitMarjorsList.length; i++) {
+                        BBusiWishUniversitySubmitMarjors submitMarjors = submitMarjorsList[i];
+                        if (null == submitMarjors) {
+                            continue;
+                        }
+                        Long numReal = null != submitMarjors.getNumReal() ? submitMarjors.getNumReal() : 0;
+                        if (null == yearStats[i]) {
+                            yearStats[i] = new SubmitYearsStats.YearStat();
+                            yearStats[i].setScore(submitMarjors.getScore());
+                            yearStats[i].setSeat(submitMarjors.getSeat());
+                            yearStats[i].setNumReal(numReal);
+                        } else {
+                            yearStats[i].setScore(Math.min(yearStats[i].getScore(), submitMarjors.getScore()));
+                            yearStats[i].setSeat(Math.max(yearStats[i].getSeat(), submitMarjors.getSeat()));
+                            yearStats[i].setNumReal(yearStats[i].getNumReal() + numReal);
+                        }
+                    }
+                    college.setStats(submitYearsStats);
+                }
+            }
+            if (null != (existCollege = universityMarjorsCollegeMap.remove(universityCollege))) {
+                college.setId(existCollege.getId());
+                busiWishUniversityMarjorsCollegeMapper.updateBBusiWishUniversityMarjorsCollege(college);
+            } else {
+                busiWishUniversityMarjorsCollegeMapper.insertBBusiWishUniversityMarjorsCollege(college);
+            }
+
+            // 新增group
+            if (newGroupList.size() > 0) {
+                for (BBusiWishUniversityMarjorsGroup newGroup : newGroupList) {
+                    busiWishUniversityMarjorsGroupMapper.insertBBusiWishUniversityMarjorsGroup(newGroup);
+                }
+            }
+
+            // 保存映射关系及专业组id
+            for (BBusiWishUniversitySubmitRecruitPlan plan : planList) {
+                BBusiWishUniversityMarjorsPlanSubmit planSubmit = new BBusiWishUniversityMarjorsPlanSubmit();
+                BeanUtils.copyProperties(planSubmitCond, planSubmit);
+
+                String course = plan.getCourse();
+                planSubmit.setCourse(plan.getCourse());
+                if (NewgaokaoType.isNewgaokao33Province(location)) {
+                    planSubmit.setCourse0("");
+                    if (course.contains("不限")) {
+                        planSubmit.setCourse1("");
+                        planSubmit.setCourse2("");
+                    } else if (course.contains("+") || course.contains("和")) {
+                        planSubmit.setCourse1("");
+                        planSubmit.setCourse2(course.replaceAll("\\+|和", ","));
+                    } else {
+                        planSubmit.setCourse1(course.replaceAll("/|或", ","));
+                        planSubmit.setCourse2("");
+                    }
+                } else {
+                    course = StringUtils.trimToEmpty(course);
+                    String[] courses = course.split("\\+");
+                    planSubmit.setCourse0(courses[0]);
+                    if (courses.length == 1 || courses[1].contains("不限")) {
+                        planSubmit.setCourse1("");
+                        planSubmit.setCourse2("");
+                    } else if (courses[1].contains("和")) {
+                        planSubmit.setCourse1("");
+                        planSubmit.setCourse2(courses[1].replaceAll("和", ","));
+                    } else {
+                        planSubmit.setCourse1(courses[1].replaceAll("或", ","));
+                        planSubmit.setCourse2("");
+                    }
+                }
+                planSubmit.setPlanId(plan.getId());
+                BBusiWishUniversitySubmitMarjors[] submitMarjorsList = planSubmitMarjorsMap.get(plan.getId());
+                if (null != submitMarjorsList) {
+                    if (null != submitMarjorsList[0]) {
+                        planSubmit.setSubmitId(submitMarjorsList[0].getId());
+                    }
+                    SubmitYearsStats submitYearsStats = new SubmitYearsStats();
+                    // submitYearsStats.setYear(year);
+                    SubmitYearsStats.YearStat yearStats[] = new SubmitYearsStats.YearStat[3];
+                    submitYearsStats.setStats(yearStats);
+                    BBusiWishUniversitySubmitMarjors submitMarjors;
+                    for (int i = 0; i < submitMarjorsList.length; i++) {
+                        if (null == (submitMarjors = submitMarjorsList[i])) {
+                            continue;
+                        }
+                        yearStats[i] = new SubmitYearsStats.YearStat();
+                        Long numReal = null != submitMarjors.getNumReal() ? submitMarjors.getNumReal() : 0;
+                        yearStats[i].setScore(submitMarjors.getScore());
+                        yearStats[i].setSeat(submitMarjors.getSeat());
+                        yearStats[i].setNumReal(numReal);
+                    }
+                    planSubmit.setStats(submitYearsStats);
+                }
+                BBusiWishUniversityMarjorsGroup marjorsGroup = planMarjorsGroupMap.get(plan.getId());
+                planSubmit.setGroupId(marjorsGroup.getGroupId());
+
+                planSubmit.setUniversityId(plan.getUniversityId());
+                planSubmit.setCollegeCode(plan.getCollegeCode());
+                String majorName = getMajorName(plan.getMarjorName(), plan.getMarjorDirection());
+                planSubmit.setMarjorName(majorName);
+                planSubmit.setMarjorCollegeId(college.getId());
+                if (universityMarjorsSubmitIdSet.remove(plan.getId())) {
+                    busiWishUniversityMarjorsPlanSubmitMapper.updateBBusiWishUniversityMarjorsPlanSubmit(planSubmit);
+                } else {
+                    busiWishUniversityMarjorsPlanSubmitMapper.insertBBusiWishUniversityMarjorsPlanSubmit(planSubmit);
+                }
+            }
+        }
+        if (universityMarjorsSubmitIdSet.size() > 0) {
+            busiWishUniversityMarjorsPlanSubmitMapper.deleteBBusiWishUniversityMarjorsPlanSubmitByIds(universityMarjorsSubmitIdSet.toArray(new Long[universityMarjorsSubmitIdSet.size()]));
+        }
+        if (universityMarjorsCollegeMap.size() > 0) {
+            List<Long> idList = universityMarjorsCollegeMap.values().stream().map(t -> t.getId()).collect(Collectors.toList());
+            busiWishUniversityMarjorsCollegeMapper.deleteBBusiWishUniversityMarjorsCollegeByIds(idList.toArray(new Long[idList.size()]));
+        }
+    }
+
+    /**
+     * 限制体验卡在06/15~08/31之间不能使用模拟志愿查看与保存的功能
+     * @param user
+     * @return
+     */
+    public String limitExperienceCard(SysUser user){
+        if(StringUtils.isNull(user.getCardId())|| UserRegStatus.isNotVip()){
+            //未绑定卡的用户不受限制(仅能查询一条记录)
+            return null;
+        }
+
+        //06-15,08-31
+        String limitVoluntaryDate= configService.selectConfigByKey("voluntary.limit.experienceCard");
+        String startDateStr = StringUtils.EMPTY;
+        String endDateStr = StringUtils.EMPTY;
+        if(StringUtils.isEmpty(limitVoluntaryDate)){
+            startDateStr = DateUtils.getCurrentYear()+"-06-15";
+            endDateStr = DateUtils.getCurrentYear()+"-08-31";
+        }else {
+            String[] limitDateArray = Convert.toStrArray(limitVoluntaryDate);
+            startDateStr = DateUtils.getCurrentYear()+"-"+(null==limitDateArray[0]?("06-15"):limitDateArray[0]);
+            endDateStr = DateUtils.getCurrentYear()+"-"+(null==limitDateArray[1]?("08-31"):limitDateArray[1]);
+        }
+
+        Date startLimitDate = DateUtils.parseDate(startDateStr);
+        //结束日期加一天
+        Date endLimitDate = new Date(DateUtils.parseDate(endDateStr).getTime()+24*60*60*1000);
+
+        /** TODO 莫
+        if(new Date().before(endLimitDate)&&startLimitDate.before(new Date())){
+            DzCards card= cardsService.selectDzCardsByCardId(user.getCardId());
+            if(CardType.isExperienceCard(card.getType())){
+                //体验卡在限制时间内
+                return String.format(Constants.EXPERIENCE_CARD_INVALID_VOLUNTARY,user.getUserName(),DateUtils.replaceYear(startDateStr),DateUtils.replaceYear(endDateStr)) ;
+            }
+        }
+
+        if(getScoreLock(user.getLocation())){
+            //锁分:非高三卡不能使用
+            int year = Calendar.getInstance().get(Calendar.YEAR);
+            if(!(user.getYear()==(year-3)||user.getGradeId()==700L)){
+                return String.format(Constants.SENIOR_THIRD_CARD_INVALID_VOLUNTARY,user.getUserName(),DateUtils.replaceYear(startDateStr),DateUtils.replaceYear(endDateStr)) ;
+            }
+        }
+         **/
+
+        return null;
+    }
+
+    private Map<String, BBusiWishScoreGroups> locationYearRangeMap = Maps.newHashMap();
+
+    public void clearScoreGroupRange() {
+        locationYearRangeMap.clear();
+    }
+
+    /**
+     * 计算一分一段极值分及位次
+     * @param location
+     * @param year
+     * @return
+     */
+    public BBusiWishScoreGroups getScoreGroupRange(String location, Integer year) {
+        String key = location + year;
+        BBusiWishScoreGroups range = locationYearRangeMap.get(key);
+        if (null != range) {
+            return range;
+        }
+        BBusiWishScoreGroups cond = new BBusiWishScoreGroups();
+        cond.setLocation(location);
+        cond.setYear(year);
+        range = busiWishScoreGroupsMapper.selectRangeByLocation(cond);
+        locationYearRangeMap.put(key, range);
+        return range;
+    }
+
+    public Integer[] getMappingRank(Integer[] ranges, String location, Integer currYear, String mode, Integer score, Integer targetYear) {
+        Integer planYear = getYear();
+        if(null == ranges) {
+            return ranges;
+        }
+        for (int i = 0; i < ranges.length; i++) {
+            if(null != ranges[i]) {
+                ranges[i] = scoreRankService.getRankEqRank(location, planYear, currYear, mode, score, ranges[i], targetYear);
+            }
+        }
+        return ranges;
+
+    }
+
+    public Integer[] getMappingRank2(Integer[] ranges, String location, Integer currYear, Integer targetYear) {
+        if (null == ranges) {
+            return null;
+        }
+        // currRank / currMinRank * lastMinRank = lastRank
+        BBusiWishScoreGroups currRange = getScoreGroupRange(location, currYear);
+        BBusiWishScoreGroups targetRange = getScoreGroupRange(location, targetYear);
+        if (null == currRange || null == targetRange) {
+            return ranges;
+        }
+        Integer currRangeMinRank = currRange.getLowestRank();
+        Integer targetRangeMinRank = targetRange.getLowestRank();
+        for (int i = 0; i < ranges.length; i++) {
+            if(null != ranges[i]) {
+                Double rate = ranges[i] * 1.0 / currRangeMinRank;
+                ranges[i] = (int) Math.ceil(rate * targetRangeMinRank);
+            }
+        }
+        return ranges;
+    }
+
+    public String getExamMajor(){
+        return String.valueOf(SecurityUtils.getLoginUser().getUser().getExamMajor());
+    }
+}

+ 28 - 0
ie-admin/src/main/java/com/ruoyi/web/util/PageUtil.java

@@ -0,0 +1,28 @@
+package com.ruoyi.web.util;
+
+import com.github.pagehelper.Page;
+
+import java.util.List;
+
+public class PageUtil {
+
+    public static <V, R> List<R> getDtoListWithPageable(List<V> list, List<R> dtoList) {
+        if (list instanceof Page) {
+            Page page = (Page) list;
+            Page<R> dtoPage = new Page(page.getPageNum(), page.getPageSize());
+            dtoPage.setTotal(page.getTotal());
+            dtoPage.addAll(dtoList);
+            return dtoPage;
+        }
+        return dtoList;
+    }
+
+    public static <V> List<V> buildListForPage(List<V> list, Integer pageNo, Integer pageSize) {
+        Page<V> dtoPage = new Page(pageNo, pageSize);
+        dtoPage.setTotal(list.size());
+        Integer begin = (pageNo - 1) * pageSize;
+        Integer end = Math.min(begin + pageSize, list.size());
+        dtoPage.addAll(list.subList(begin, end));
+        return dtoPage;
+    }
+}

+ 44 - 0
ie-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java

@@ -140,6 +140,18 @@ public class SysUser extends BaseEntity
     /** 考生专业类别 **/
     private Integer examMajor;
 
+    /** 分数 */
+    private Integer score;
+
+    /** 分数锁定 */
+    private Integer scoreLock;
+
+    /** 用户位次 */
+    private Integer seatInput;
+
+    /** 考生专业类别名称 */
+    private String examMajorName;
+
     @JsonIgnore
     private String directedStudy;
 
@@ -523,6 +535,38 @@ public class SysUser extends BaseEntity
         this.examMajor = examMajor;
     }
 
+    public Integer getScore() {
+        return score;
+    }
+
+    public void setScore(Integer score) {
+        this.score = score;
+    }
+
+    public Integer getScoreLock() {
+        return scoreLock;
+    }
+
+    public void setScoreLock(Integer scoreLock) {
+        this.scoreLock = scoreLock;
+    }
+
+    public Integer getSeatInput() {
+        return seatInput;
+    }
+
+    public void setSeatInput(Integer seatInput) {
+        this.seatInput = seatInput;
+    }
+
+    public String getExamMajorName() {
+        return examMajorName;
+    }
+
+    public void setExamMajorName(String examMajorName) {
+        this.examMajorName = examMajorName;
+    }
+
     public String getDirectedStudy() {
         return directedStudy;
     }

+ 83 - 0
ie-common/src/main/java/com/ruoyi/common/enums/NewgaokaoType.java

@@ -0,0 +1,83 @@
+package com.ruoyi.common.enums;
+
+import com.ruoyi.common.utils.StringUtils;
+
+public enum NewgaokaoType {
+    newgaokao312("1", "3+1+2"),//语数外 +(物历选1,化生政地4选2)
+    newgaokao33("2", "3+3"),//语数外 +(物化生历政地,6选3)
+//    oldgaokao("3", "文理科"),//文理科
+
+    ;
+    private String value;
+    private String remark;
+
+    private NewgaokaoType(String value, String remark) {
+        this.value = value;
+        this.remark = remark;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public static NewgaokaoType getByValue(String value) {
+        for (NewgaokaoType o : NewgaokaoType.values()) {
+            if (o.getValue().equals(value)) {
+                return o;
+            }
+        }
+        return null;
+    }
+
+    public static Boolean isNewgaokao33Province(String provinceName){
+        //TODO 从数据库中取数据 ,山东需要单独处理
+        if ("山东".equalsIgnoreCase(provinceName)) {
+            return true;
+        }else {
+            return false;
+        }
+    }
+
+    public static String getNewgaokaoType(String provinceName) {
+        if(StringUtils.isBlank(provinceName)){
+            return null;
+        }
+        if (isNewgaokao33Province(provinceName)) {
+            return newgaokao33.value;
+        }
+
+        return newgaokao312.value;
+    }
+
+    public static Boolean isNewgaokao312(String type) {
+        if (newgaokao312.value.equalsIgnoreCase(type)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * type可为类型或省份名称
+     * @param type
+     * @return
+     */
+    public static Boolean isNewgaokao33(String type) {
+        if (newgaokao33.value.equalsIgnoreCase(type)||isNewgaokao33Province(type)) {
+            return true;
+        }
+
+        return false;
+    }
+    public static Boolean isNotNewgaokao33(String type) {
+        return !isNewgaokao33(type);
+    }
+
+        public static void main(String[] args) {
+
+    }
+}

+ 14 - 1
ie-common/src/main/java/com/ruoyi/common/enums/UserRegStatus.java

@@ -1,8 +1,10 @@
 package com.ruoyi.common.enums;
 
+import com.ruoyi.common.utils.SecurityUtils;
+
 /**
  * 用户状态
- * 
+ *
  * @author ruoyi
  */
 public enum UserRegStatus
@@ -20,4 +22,15 @@ public enum UserRegStatus
     {
         return info;
     }
+
+    public static Boolean isVip() {
+        UserRegStatus userRegStatusEnum = SecurityUtils.getLoginUser().getUser().getRegStatus();
+        if (null==userRegStatusEnum) {
+            return false;
+        }
+
+        return UserRegStatus.Student.name().equals(userRegStatusEnum.name());
+    }
+
+    public static Boolean isNotVip(){return !isVip();}
 }

+ 10 - 4
ie-common/src/main/java/com/ruoyi/common/utils/DateUtils.java

@@ -8,12 +8,13 @@ import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
+import java.util.Calendar;
 import java.util.Date;
 import org.apache.commons.lang3.time.DateFormatUtils;
 
 /**
  * 时间工具类
- * 
+ *
  * @author ruoyi
  */
 public class DateUtils extends org.apache.commons.lang3.time.DateUtils
@@ -29,13 +30,13 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
     public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
 
     private static String[] parsePatterns = {
-            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", 
+            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
             "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
             "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
 
     /**
      * 获取当前Date型日期
-     * 
+     *
      * @return Date() 当前日期
      */
     public static Date getNowDate()
@@ -45,7 +46,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
 
     /**
      * 获取当前日期, 默认格式为yyyy-MM-dd
-     * 
+     *
      * @return String
      */
     public static String getDate()
@@ -188,4 +189,9 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
         ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
         return Date.from(zdt.toInstant());
     }
+
+    public static Integer getCurrentYear() {
+        Calendar cal = Calendar.getInstance();
+        return cal.get(Calendar.YEAR);
+    }
 }

+ 19 - 3
ie-system/src/main/resources/mapper/system/SysUserMapper.xml

@@ -22,6 +22,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		<result property="inviteCode"    column="invite_code"     />
 		<result property="scores"        column="scores" typeHandler="com.ruoyi.system.handlers.SubjectScoreTypeHandler"        />
 		<result property="examMajor"     column="exam_major"       />
+		<result property="score"          column="score"            />
+		<result property="scoreLock"      column="score_lock"       />
+		<result property="seatInput"     column="seat_input"       />
+		<result property="examMajorName" column="exam_major_name"  />
 		<result property="directedStudy" column="directed_study"       />
 		<result property="evalCounts"     column="eval_counts" />
 		<result property="cardId"        column="card_id"         />
@@ -64,7 +68,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
 	<sql id="selectUserVo">
         select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.pwd_update_date, u.create_by, u.create_time, u.remark,
-		u.location,u.exam_type,u.reg_status,u.end_year,u.invite_code,u.scores,u.exam_major,u.directed_study,u.eval_counts,u.card_id,u.bind_status,u.account_type,
+		u.location,u.exam_type,u.reg_status,u.end_year,u.invite_code,u.scores,u.exam_major,u.score,u.score_lock,u.seat_input,u.exam_major_name,u.directed_study,u.eval_counts,u.card_id,u.bind_status,u.account_type,
         d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
         r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status, u.user_type, u.user_type_id
         from sys_user u
@@ -284,14 +288,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
 	<select id="selectUserByUserIds" resultMap="SysUserResult">
 		select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.password2, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.pwd_update_date, u.create_by, u.create_time, u.remark,
-		u.location,u.exam_type,u.reg_status,u.end_year,u.invite_code,u.scores,u.exam_major,u.directed_study,u.eval_counts,u.card_id,u.account_type
+		u.location,u.exam_type,u.reg_status,u.end_year,u.invite_code,u.scores,u.exam_major,u.score,u.score_lock,u.seat_input,u.exam_major_name,u.directed_study,u.eval_counts,u.card_id,u.account_type
         from sys_user u
 		where u.user_id in <foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach>
 	</select>
 
 	<select id="selectUserByUserNames" resultMap="SysUserResult">
 		select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.password2, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.pwd_update_date, u.create_by, u.create_time, u.remark,
-		u.location,u.exam_type,u.reg_status,u.end_year,u.invite_code,u.scores,u.exam_major,u.directed_study,u.eval_counts,u.card_id,u.account_type
+		u.location,u.exam_type,u.reg_status,u.end_year,u.invite_code,u.scores,u.exam_major,u.score,u.score_lock,u.seat_input,u.exam_major_name,u.directed_study,u.eval_counts,u.card_id,u.account_type
         from sys_user u
 		where u.user_name in <foreach collection="userNames" item="userName" open="(" separator="," close=")">#{userName}</foreach>
 		and u.del_flag = '0'
@@ -340,6 +344,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		    <if test="scores != null and scores != ''">scores,</if>
 		    <if test="evalCounts != null">eval_counts,</if>
 		    <if test="examMajor != null and examMajor != ''">exam_major,</if>
+		    <if test="score != null">score,</if>
+		    <if test="scoreLock != null">score_lock,</if>
+		    <if test="seatInput != null">seat_input,</if>
+		    <if test="examMajorName != null and examMajorName != ''">exam_major_name,</if>
 		    <if test="directedStudy != null and directedStudy != ''">directed_study,</if>
 		    <if test="cardId != null and cardId != ''">card_id,</if>
 		    <if test="bindStatus != null">bind_status,</if>
@@ -370,6 +378,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  			<if test="scores != null and scores != ''">#{scores, typeHandler=com.ruoyi.system.handlers.SubjectScoreTypeHandler},</if>
 		    <if test="evalCounts != null">#{evalCounts},</if>
  			<if test="examMajor != null and examMajor != ''">#{examMajor},</if>
+ 			<if test="score != null">#{score},</if>
+ 			<if test="scoreLock != null">#{scoreLock},</if>
+ 			<if test="seatInput != null">#{seatInput},</if>
+ 			<if test="examMajorName != null and examMajorName != ''">#{examMajorName},</if>
  			<if test="directedStudy != null and directedStudy != ''">#{directedStudy},</if>
  			<if test="cardId != null and cardId != ''">#{cardId},</if>
 		    <if test="bindStatus != null">#{bindStatus},</if>
@@ -402,6 +414,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 			<if test="inviteCode != null and inviteCode != ''">invite_code = #{inviteCode},</if>
 			<if test="scores != null and scores != ''">scores = #{scores, typeHandler=com.ruoyi.system.handlers.SubjectScoreTypeHandler},</if>
 			<if test="examMajor != null and examMajor != ''">exam_major = #{examMajor},</if>
+			<if test="score != null">score = #{score},</if>
+			<if test="scoreLock != null">score_lock = #{scoreLock},</if>
+			<if test="seatInput != null">seat_input = #{seatInput},</if>
+			<if test="examMajorName != null and examMajorName != ''">exam_major_name = #{examMajorName},</if>
 			<if test="directedStudy != null and directedStudy != ''">directed_study = #{directedStudy},</if>
 			<if test="evalCounts != null and evalCounts != ''">eval_counts = #{evalCounts},</if>
 			<if test="cardId != null and cardId != ''">card_id = #{cardId},</if>