package com.qmth.teachcloud.report.api;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.qmth.boot.api.annotation.Aac;
import com.qmth.boot.api.annotation.BOOL;
import com.qmth.boot.api.constant.ApiConstant;
import com.qmth.teachcloud.common.bean.params.UserSaveParams;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicCourse;
import com.qmth.teachcloud.common.entity.SysOrg;
import com.qmth.teachcloud.common.entity.SysRole;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.RoleTypeEnum;
import com.qmth.teachcloud.common.service.BasicCourseService;
import com.qmth.teachcloud.common.service.SysOrgService;
import com.qmth.teachcloud.common.service.SysRoleService;
import com.qmth.teachcloud.common.service.SysUserService;
import com.qmth.teachcloud.common.util.*;
import com.qmth.teachcloud.report.business.bean.dto.CombineDto;
import com.qmth.teachcloud.report.business.bean.dto.excel.*;
import com.qmth.teachcloud.report.business.bean.dto.query.*;
import com.qmth.teachcloud.report.business.bean.params.CollegeCombineParams;
import com.qmth.teachcloud.report.business.entity.*;
import com.qmth.teachcloud.common.enums.AssignEnum;
import com.qmth.teachcloud.report.business.enums.ExamCloudDataEnum;
import com.qmth.teachcloud.report.business.enums.NumberTypeEnum;
import com.qmth.teachcloud.report.business.enums.PublishStatusEnum;
import com.qmth.teachcloud.report.business.service.*;
import io.swagger.annotations.*;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description: 基础数据导入系统基础表控制类
 * @Author: CaoZixuan
 * @Date: 2021-06-01
 */
@Api(tags = "数据源处理controller")
@RestController
@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/${prefix.url.datasource}")
//@Aac(strict = BOOL.FALSE, auth = BOOL.FALSE)
public class BasicDatasourceController {
    @Resource
    private TBPaperService tbPaperService;
    @Resource
    private TBPaperStructService tbPaperStructService;
    @Resource
    private TBExamCourseService tbExamCourseService;
    @Resource
    private BasicCourseService basicCourseService;
    @Resource
    private TBModuleProficiencyService tbModuleProficiencyService;
    @Resource
    private TBModuleConfigService tbModuleConfigService;
    @Resource
    private TBDimensionService tbDimensionService;
    @Resource
    private TBExamService tbExamService;
    @Resource
    private NewCallApiService newCallApiService;
    @Resource
    private TBSchoolClazzService tbSchoolClazzService;
    @Resource
    private SysOrgService sysOrgService;
    @Resource
    private TBSchoolMajorService tbSchoolMajorService;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private TBStudentService tbStudentService;
    @Resource
    private TBAnswerService tbAnswerService;
    @Resource
    private TBExamRecordService tbExamRecordService;
    @Resource
    private TBExamStudentService tbExamStudentService;
    @Resource
    private TAExamCourseRecordService taExamCourseRecordService;
    @Resource
    private TBCommonLevelConfigService tbCommonLevelConfigService;
    @Resource
    private TBCommonRankLevelConfigService tbCommonRankLevelConfigService;
    @Resource
    private SysRoleService sysRoleService;
    @Resource
    private AnalyzeForReportService analyzeForReportService;
    @Resource
    private TBExaminationService tbExaminationService;
    @Resource
    private TBExaminationRelationService tbExaminationRelationService;
    @Resource
    private TBTeacherService tbTeacherService;
    @Resource
    private CourseUnitOperateService courseUnitOperateService;

    @ApiOperation(value = "试卷数据导入")
    @RequestMapping(value = "/paper/import", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result paperImport(@ApiParam(value = "上传文件", required = true) @RequestParam MultipartFile file, @RequestParam long examId, @RequestParam Long schoolId) throws IOException, NoSuchFieldException {
        if (Objects.isNull(file)) {
            throw ExceptionResultEnum.ERROR.exception("找不到附件");
        }
        if (examId == 0) {
            throw ExceptionResultEnum.ERROR.exception("考试id为空");
        }

        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(file.getInputStream(), Lists.newArrayList(PaperConfigDto.class, PaperStructDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
            if (finalExcelErrorList.size() > 0) {
                throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(finalExcelErrorList));
            }
            return finalExcelList;
        });

        //保存到数据库
        Map<String, Long> paperMap = new HashMap<>();
        List<TBPaper> tbPaperList = new ArrayList<>();
        List<TBPaperStruct> tbPaperStructList = new ArrayList<>();
        if (Objects.nonNull(finalList) && finalList.size() > 0) {
            for (int i = 0; i < finalList.size(); i++) {
                LinkedMultiValueMap<Integer, Object> map = finalList.get(i);
                List<Object> importList = map.get(i);

                for (int y = 0; y < Objects.requireNonNull(importList).size(); y++) {
                    if (importList.get(y) instanceof PaperConfigDto) {
                        PaperConfigDto paperConfigDto = (PaperConfigDto) importList.get(y);

                        String courseCode = paperConfigDto.getCourseCode();
                        String courseName = paperConfigDto.getCourseName();
                        if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, courseName)) {
                            continue;
                        }
                        BigDecimal coefficient = BigDecimal.ZERO;
                        if (Objects.nonNull(paperConfigDto.getCoefficient())) {
                            coefficient = BigDecimal.valueOf(Double.parseDouble(String.valueOf(paperConfigDto.getCoefficient())));
                        }
                        String paperType = paperConfigDto.getPaperType();
                        List<TBPaper> oldList = tbPaperService.list(new QueryWrapper<TBPaper>().lambda()
                                .eq(TBPaper::getExamId, examId).eq(TBPaper::getCourseCode, courseCode).eq(TBPaper::getPaperType, paperType));
                        Long id;
                        if (oldList.size() == 1) {
                            id = oldList.get(0).getId();
                        } else if (oldList.size() < 1) {
                            id = SystemConstant.getDbUuid();
                        } else {
                            throw ExceptionResultEnum.ERROR.exception("表数据异常[t_b_paper]");
                        }

                        paperMap.put(paperType, id);
                        TBPaper tbPaper = new TBPaper();
                        tbPaper.setId(id);
                        tbPaper.setExamId(examId);
                        tbPaper.setCourseCode(courseCode);
                        tbPaper.setCourseName(courseName);
                        tbPaper.setPaperType(paperType);
                        tbPaper.setCoefficient(coefficient);
                        tbPaper.setTotalScore(BigDecimal.valueOf(Double.parseDouble(paperConfigDto.getFullScore())));
                        tbPaper.setPassScore(BigDecimal.valueOf(Double.parseDouble(paperConfigDto.getPassScore())));
                        String scoreType = paperConfigDto.getIsAssigned();
                        tbPaper.setScoreType(AssignEnum.convertToEnum(scoreType));
                        tbPaperList.add(tbPaper);
                    } else if (importList.get(y) instanceof PaperStructDto) {
                        PaperStructDto paperStructDto = (PaperStructDto) importList.get(y);

                        String courseCode = paperStructDto.getCourseCode();
                        String courseName = paperStructDto.getCourseName();
                        if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, courseName)) {
                            continue;
                        }

                        String paperType = paperStructDto.getPaperCode();
                        Long paperId = paperMap.get(paperType);

                        // 考察点去空格
                        String knowledgeDimension = paperStructDto.getKnowledgeDimension();
                        if (SystemConstant.strNotNull(knowledgeDimension)) {
                            knowledgeDimension = knowledgeDimension.trim().replaceAll(SystemConstant.COMMA_OF_CHINESE, SystemConstant.COMMA_OF_ENGLISH).replaceAll(SystemConstant.PAUSE_SIGN, SystemConstant.COMMA_OF_ENGLISH);
                        }
                        String abilityDimension = paperStructDto.getAbilityDimension();
                        if (SystemConstant.strNotNull(abilityDimension)) {
                            abilityDimension = abilityDimension.trim().replaceAll(SystemConstant.COMMA_OF_CHINESE, SystemConstant.COMMA_OF_ENGLISH).replaceAll(SystemConstant.PAUSE_SIGN, SystemConstant.COMMA_OF_ENGLISH);
                        }

                        // 题号组合与匹配
                        String mainNumber = paperStructDto.getMainNumber();
                        String subNumber = paperStructDto.getSubNumber();

                        String questionType = paperStructDto.getQuestionType();
                        if (questionType == null) {
                            questionType = "";
                        }
                        String questionName = questionType + " " + mainNumber + SystemConstant.HYPHEN + subNumber;
                        questionName = questionName.trim(); // 去前后空格

                        TBPaperStruct tbPaperStruct = new TBPaperStruct();
                        tbPaperStruct.setId(SystemConstant.getDbUuid());
                        tbPaperStruct.setPaperId(paperId);
                        tbPaperStruct.setQuestionName(questionName);
                        tbPaperStruct.setNumberType(paperStructDto.getNumberType());
                        tbPaperStruct.setBigQuestionNumber(mainNumber);
                        tbPaperStruct.setSmallQuestionNumber(subNumber);
                        tbPaperStruct.setQuestionType(questionType);
                        tbPaperStruct.setFullScore(BigDecimal.valueOf(Double.parseDouble(paperStructDto.getFullScore())));
                        tbPaperStruct.setScoreRules(paperStructDto.getScoreRules());
                        tbPaperStruct.setRulesDesc(paperStructDto.getRulesDesc());
                        tbPaperStruct.setKnowledgeDimension(knowledgeDimension);
                        tbPaperStruct.setAbilityDimension(abilityDimension);
                        tbPaperStructList.add(tbPaperStruct);
                    }
                }
            }
        }

        List<Long> paperIdList = tbPaperStructList.stream().map(TBPaperStruct::getPaperId).collect(Collectors.toList());
        // 删除已有的试卷结构数据
        if (paperIdList.size() > 0) {
            tbPaperStructService.remove(new QueryWrapper<TBPaperStruct>().lambda().in(TBPaperStruct::getPaperId, paperIdList));
        }

        // 批量新增或更新试卷表
        tbPaperService.saveOrUpdateBatch(tbPaperList);
        // 批量新增试卷结构表
        tbPaperStructService.saveBatch(tbPaperStructList);
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
    }

    @ApiOperation(value = "模块和等级导入接口")
    @RequestMapping(value = "/moduleLevel/import", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result moduleLevelImport(@ApiParam(value = "上传文件", required = true) @RequestParam MultipartFile file, @RequestParam Long schoolId, @RequestParam Long examId) throws IOException, NoSuchFieldException {
        if (Objects.isNull(file)) {
            throw ExceptionResultEnum.ERROR.exception("附件不存在");
        }
        if (schoolId == null || schoolId == 0) {
            throw ExceptionResultEnum.ERROR.exception("参数缺失");
        }
        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(file.getInputStream(),
                Lists.newArrayList(ModuleProficiencyDto.class, ModuleConfigDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
                    if (finalExcelErrorList.size() > 0) {
                        throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(finalExcelErrorList));
                    }
                    return finalExcelList;
                });
        //保存到数据库

        // 模块二级考查点维度熟练度配置，及模块简要描述表
        List<TBModuleProficiency> tbModuleProficiencyList = new ArrayList<>();
        // 考查点模块配置表
        List<TBModuleConfig> tbModuleConfigList = new ArrayList<>();

        if (Objects.nonNull(finalList) && finalList.size() > 0) {
            for (int i = 0; i < finalList.size(); i++) {
                LinkedMultiValueMap<Integer, Object> map = finalList.get(i);
                List<Object> importList = map.get(i);
                for (int y = 0; y < Objects.requireNonNull(importList).size(); y++) {
                    if (importList.get(y) instanceof ModuleProficiencyDto) {

                        ModuleProficiencyDto moduleProficiencyDto = (ModuleProficiencyDto) importList.get(y);
                        String proficiencyDegree = moduleProficiencyDto.getProficiencyDegree(); // 精熟度范围
                        String define = moduleProficiencyDto.getProficiency(); // define
                        String courseCode = moduleProficiencyDto.getCourseCode();
                        String courseName = moduleProficiencyDto.getCourseName();
                        if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, courseName)) {
                            continue;
                        }
                        if (proficiencyDegree != null && proficiencyDegree.length() > 0 && define != null && define.length() > 0) {
                            // - 解析精熟度范围
                            String[] itemCell = proficiencyDegree.split(";"); // 每一项熟练度定义
                            String[] defineCell = define.split(";"); // 每个定义
                            if (itemCell.length > 0 && defineCell.length > 0) {
                                if (defineCell.length != itemCell.length) {
                                    throw ExceptionResultEnum.ERROR.exception("数据异常");
                                }

                                for (int tmp = 0; tmp < itemCell.length; tmp++) {

                                    String[] levelWithScopeCell = itemCell[tmp].split(":"); // 每一项中等级和对应分为标准的定义
                                    if (levelWithScopeCell.length != 2) {
                                        throw ExceptionResultEnum.ERROR.exception("应该有2条数据，实际 ：" + itemCell[tmp]);
                                    }
                                    String level = levelWithScopeCell[0];
                                    String scope = levelWithScopeCell[1];
                                    String limitTmp = scope.substring(1, scope.length() - 1);

                                    String[] limitCell = limitTmp.split(","); // 每个范围中极值的数组
                                    if (limitCell.length != 2) {
                                        throw ExceptionResultEnum.ERROR.exception("数据异常");
                                    }
                                    String min = limitCell[0];
                                    String max = limitCell[1];
                                    TBModuleProficiency tbModuleProficiency = new TBModuleProficiency();
                                    tbModuleProficiency.setId(SystemConstant.getDbUuid());
                                    tbModuleProficiency.setExamId(examId);
                                    tbModuleProficiency.setCourseCode(courseCode);
                                    tbModuleProficiency.setCourseName(courseName);
                                    tbModuleProficiency.setModuleType(moduleProficiencyDto.getName());
                                    tbModuleProficiency.setInterpret(moduleProficiencyDto.getDescription());
                                    tbModuleProficiency.setRemark(moduleProficiencyDto.getRemark());
                                    tbModuleProficiency.setDefine(defineCell[tmp].trim());
                                    tbModuleProficiency.setLevel(level);
                                    tbModuleProficiency.setMin(min);
                                    tbModuleProficiency.setMax(max);
                                    tbModuleProficiency.setScope(scope);

                                    tbModuleProficiencyList.add(tbModuleProficiency);
                                }
                            }
                        } else {
                            TBModuleProficiency tbModuleProficiency = new TBModuleProficiency();
                            tbModuleProficiency.setId(SystemConstant.getDbUuid());
                            tbModuleProficiency.setExamId(examId);
                            tbModuleProficiency.setCourseCode(courseCode);
                            tbModuleProficiency.setCourseName(courseName);
                            tbModuleProficiency.setModuleType(moduleProficiencyDto.getName());
                            tbModuleProficiency.setInterpret(moduleProficiencyDto.getDescription());

                            tbModuleProficiencyList.add(tbModuleProficiency);
                        }
                    } else if (importList.get(y) instanceof ModuleConfigDto) {
                        /*
                            构建config_module
                         */
                        ModuleConfigDto moduleConfigDto = (ModuleConfigDto) importList.get(y);

                        String courseCode = moduleConfigDto.getCourseCode();
                        String courseName = basicCourseService.getOne(new QueryWrapper<BasicCourse>().lambda()
                                        .eq(BasicCourse::getSchoolId, schoolId).eq(BasicCourse::getCode, courseCode))
                                .getName();


                        if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, courseName)) {
                            continue;
                        }
                        TBModuleConfig tbModuleConfig = new TBModuleConfig();
                        tbModuleConfig.setId(SystemConstant.getDbUuid());
                        tbModuleConfig.setExamId(examId);
                        tbModuleConfig.setCourseCode(courseCode);
                        tbModuleConfig.setCourseName(courseName);
                        tbModuleConfig.setModuleType(moduleConfigDto.getModuleName());
                        tbModuleConfig.setFormula(moduleConfigDto.getFormula());
                        tbModuleConfig.setScope(moduleConfigDto.getLevelDegree());
                        tbModuleConfig.setLevelCode(moduleConfigDto.getCode());
                        tbModuleConfig.setLevelName(moduleConfigDto.getLevel());
                        tbModuleConfig.setResult(moduleConfigDto.getDiagnoseResult());
                        tbModuleConfig.setAdvice(moduleConfigDto.getLearnAdvice());
                        if (moduleConfigDto.getModuleName().equals("知识")) {
                            tbModuleConfig.setAttribute("knowledgeDimension");
                        } else if (moduleConfigDto.getModuleName().equals("能力")) {
                            tbModuleConfig.setAttribute("abilityDimension");
                        }
                        tbModuleConfigList.add(tbModuleConfig);
                    }
                }
            }
        }
        Set<String> moduleProficiencyRemove = tbModuleProficiencyList.stream().map(e -> e.getExamId() + SystemConstant.HYPHEN
                + e.getCourseCode() + SystemConstant.HYPHEN
                + e.getModuleType()).collect(Collectors.toSet());

        Set<String> moduleConfigRemove = tbModuleConfigList.stream().map(e -> e.getExamId() + SystemConstant.HYPHEN
                + e.getCourseCode() + SystemConstant.HYPHEN
                + e.getModuleType()).collect(Collectors.toSet());

        for (String s : moduleProficiencyRemove) {
            String[] arr = s.split(SystemConstant.HYPHEN);
            tbModuleProficiencyService.remove(new QueryWrapper<TBModuleProficiency>().lambda()
                    .eq(TBModuleProficiency::getExamId, arr[0])
                    .eq(TBModuleProficiency::getCourseCode, arr[1])
                    .eq(TBModuleProficiency::getModuleType, arr[2]));
        }
        for (String s : moduleConfigRemove) {
            String[] arr = s.split(SystemConstant.HYPHEN);
            tbModuleConfigService.remove(new QueryWrapper<TBModuleConfig>().lambda()
                    .eq(TBModuleConfig::getExamId, arr[0])
                    .eq(TBModuleConfig::getCourseCode, arr[1])
                    .eq(TBModuleConfig::getModuleType, arr[2]));
        }
        tbModuleProficiencyService.saveBatch(tbModuleProficiencyList);
        tbModuleConfigService.saveBatch(tbModuleConfigList);
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
    }

    @ApiOperation(value = "知识点导入模板")
    @RequestMapping(value = "/dimension/import", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result dimensionImport(@ApiParam(value = "上传文件", required = true) @RequestParam MultipartFile file, @RequestParam Long schoolId, @RequestParam Long examId) throws IOException, NoSuchFieldException {
        if (Objects.isNull(file)) {
            throw ExceptionResultEnum.ERROR.exception("附件不存在");
        }
        if (Objects.isNull(schoolId) || schoolId == 0) {
            throw ExceptionResultEnum.ERROR.exception("参数缺失");
        }
        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(file.getInputStream(), Lists.newArrayList(DimensionDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
            if (finalExcelErrorList.size() > 0) {
                throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(finalExcelErrorList));
            }
            return finalExcelList;
        });
        //保存到数据库
        List<TBDimension> tbDimensionList = new ArrayList<>();
        if (Objects.nonNull(finalList) && finalList.size() > 0) {
            for (int i = 0; i < finalList.size(); i++) {
                LinkedMultiValueMap<Integer, Object> map = finalList.get(i);
                List<Object> moduleLevelImportList = map.get(i);
                for (int y = 0; y < Objects.requireNonNull(moduleLevelImportList).size(); y++) {
                    if (moduleLevelImportList.get(y) instanceof DimensionDto) {
                        DimensionDto dimensionDto = (DimensionDto) moduleLevelImportList.get(y);

                        String courseCode = dimensionDto.getCourseCode();
                        String courseName = basicCourseService.getOne(new QueryWrapper<BasicCourse>().lambda()
                                        .eq(BasicCourse::getSchoolId, schoolId).eq(BasicCourse::getCode, courseCode))
                                .getName();

                        if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, courseName)) {
                            continue;
                        }
                        TBDimension tbDimension = new TBDimension();
                        tbDimension.setId(SystemConstant.getDbUuid());
                        tbDimension.setExamId(examId);
                        tbDimension.setCourseCode(courseCode);
                        tbDimension.setCourseName(courseName);
                        tbDimension.setDimensionType(dimensionDto.getModule());
                        tbDimension.setCodePrimary(dimensionDto.getCodeOne());
                        tbDimension.setNamePrimary(dimensionDto.getNameOne());
                        tbDimension.setCodeSecond(dimensionDto.getCodeTwo());
                        tbDimension.setNameSecond(dimensionDto.getNameTwo());
                        tbDimension.setInterpretation(dimensionDto.getInterpretation());

                        tbDimensionList.add(tbDimension);
                    }
                }
            }
        }
        Set<String> tbDimensionRemove = tbDimensionList.stream().map(e -> e.getExamId() + SystemConstant.HYPHEN + e.getCourseCode()).collect(Collectors.toSet());
        for (String s : tbDimensionRemove) {
            String[] arr = s.split(SystemConstant.HYPHEN);
            tbDimensionService.remove(new QueryWrapper<TBDimension>().lambda()
                    .eq(TBDimension::getExamId, arr[0])
                    .eq(TBDimension::getCourseCode, arr[1]));
        }
        tbDimensionService.saveBatch(tbDimensionList);
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
    }

    @ApiOperation(value = "考试作答信息导入模板")
    @RequestMapping(value = "/examAnswer/import", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result examAnswerImport(@ApiParam(value = "云阅卷考试id", required = true) @RequestParam Long id,
                                   @ApiParam(value = "云阅卷考试编号") @RequestParam(required = false) String cloudExamCode,
                                   @ApiParam(value = "教研分析将AB卷分开分析时自定义科目和卷形的连接符(连接符必须和’t_e_course‘表中的科目名称中连接符对应)") @RequestParam(required = false) String linkSign,
                                   @ApiParam(value = "学校id") @RequestParam Long pSchoolId) throws IOException {
        TBExam tbExam = tbExamService.findByCloudExamId(id);
        Long examId = tbExam.getId();
        Long schoolId = tbExamService.getById(examId).getSchoolId();

        if (!schoolId.equals(pSchoolId)) {
            throw ExceptionResultEnum.ERROR.exception("学校id不匹配");
        }

        // 该考试要考查的所有课程
        List<TBExamCourse> tbExamCourseList = tbExamCourseService.list(new QueryWrapper<TBExamCourse>().lambda().eq(TBExamCourse::getExamId, examId));

        List<Map> finalList = newCallApiService.callStudentScore(id, cloudExamCode);
        System.out.println("------------------map : --------------------- \n" + JacksonUtil.parseJson(finalList));

        // 根据云阅卷数据源筛选并保存班级、学院、教师数据源
        // TODO: 2021/6/2 筛选并创建学校班级表
        List<TBSchoolClazzDto> tbSchoolClazzDtoList = new ArrayList<>();
        List<String> clazzList = finalList.stream()
                .map(e -> String.valueOf(e.get(ExamCloudDataEnum.CLASS_NAME.getName())))
                .distinct().collect(Collectors.toList());
        for (String clazzInfo : clazzList) {
            TBSchoolClazzDto tbSchoolClazzDto = new TBSchoolClazzDto();
            tbSchoolClazzDto.setSchoolId(schoolId);
            tbSchoolClazzDto.setClazzCode(clazzInfo);
            tbSchoolClazzDto.setClazzName(clazzInfo);
            tbSchoolClazzDtoList.add(tbSchoolClazzDto);
        }
        this.saveClazzInfo(tbSchoolClazzDtoList);
        // TODO: 2021/6/2 筛选并创建学校学院表
        List<TBSchoolCollegeDto> tbSchoolCollegeDtoList = new ArrayList<>();
        List<String> collegeList = finalList.stream()
                .map(e -> String.valueOf(e.get(ExamCloudDataEnum.COLLEGE.getName())))
                .distinct().collect(Collectors.toList());
        for (String collegeInfo : collegeList) {
            TBSchoolCollegeDto tbSchoolCollegeDto = new TBSchoolCollegeDto();
            tbSchoolCollegeDto.setSchoolId(schoolId);
            tbSchoolCollegeDto.setCollegeCode(collegeInfo);
            tbSchoolCollegeDto.setCollegeName(collegeInfo);
            tbSchoolCollegeDtoList.add(tbSchoolCollegeDto);
        }
        this.saveCollegeInfo(tbSchoolCollegeDtoList);
        // TODO: 2021/6/2 筛选并创建学校教师表
        // 查询考务关系
        List<TBExaminationRelation> tbExaminationRelationList = tbExaminationRelationService.list(new QueryWrapper<TBExaminationRelation>().lambda()
                .eq(TBExaminationRelation::getExamId, examId));

        List<TBSchoolTeacherDto> tbSchoolTeacherDtoList = new ArrayList<>();

        List<Map<String, String>> teacherList = finalList.stream()
                .flatMap(e -> {
                    Map<String, String> map = new HashMap<>();
                    map.put("subjectName", String.valueOf(e.get(ExamCloudDataEnum.SUBJECT_NAME.getName())));
                    map.put("teacherInfo", String.valueOf(e.get(ExamCloudDataEnum.TEACHER.getName())));
                    return Stream.of(map);
                }).distinct().collect(Collectors.toList());

        Map<String,String> teacherUserMap = new HashMap<>();

        for (Map<String, String> teacherPackage : teacherList) {

            String teacherInfo = teacherPackage.get("teacherInfo");
            String subjectName = teacherPackage.get("subjectName");

            Long teacherCollegeId = null;
            // 如果存在A、B卷
            for (TBExamCourse tbExamCourse : tbExamCourseList) {
                String courseName = tbExamCourse.getCourseName();
                if (SystemConstant.strNotNull(linkSign) && courseName.contains(linkSign)) {
                    String[] cellArr = courseName.split(linkSign);
                    if (cellArr.length != 2) {
                        throw ExceptionResultEnum.ERROR.exception("无法解析存在分隔符为 【" + linkSign + "】的课程 【" + courseName + "】");
                    }
                    if (cellArr[0].equals(subjectName)) {
                        teacherCollegeId = tbExamCourse.getTeachCollegeId();
                        break;
                    }
                } else {
                    if (courseName.equals(subjectName)) {
                        teacherCollegeId = tbExamCourse.getTeachCollegeId();
                        break;
                    }
                }
            }

            // 教师信息统一化处理逻辑
            Map<String, String> map = this.disposeTeacherInfo(teacherInfo);
            String teacherName = map.get("teacherName");
            String teacherCode = map.get("teacherCode");

            List<TBExaminationRelation> tbExaminationRelations = tbExaminationRelationList.stream()
                    .filter(e -> teacherName.equals(e.getTeacherName()))
                    .distinct().collect(Collectors.toList());

            // TODO: 2021/7/26 研究下面臃肿且被考务数据限制死的的教师机构获取方式是否可以使用上面的替代
            Long orgId = null;
            if (tbExaminationRelations.size() == 0) {
                if (!SystemConstant.strNotNull(teacherCode)) {
                    List<TBTeacher> tbTeacherList = tbTeacherService.list(new QueryWrapper<TBTeacher>().lambda().eq(TBTeacher::getSchoolId, schoolId).eq(TBTeacher::getTeacherName, teacherName));
                    if (tbTeacherList.size() == 1) {
                        teacherCode = tbTeacherList.get(0).getTeacherCode();
                    } else {
                        teacherCode = teacherInfo;
                    }
                }
                orgId = teacherCollegeId;
            } else {
                List<String> teacherCodeList = tbExaminationRelations.stream().map(TBExaminationRelation::getTeacherCode).distinct().collect(Collectors.toList());
                if (teacherCodeList.size() != 1) {
                    throw ExceptionResultEnum.ERROR.exception("考务数据-教师对应的教师编号有误");
                }
                List<String> teachCollegeNameList = tbExaminationRelations.stream().map(TBExaminationRelation::getTeachCollegeName).distinct().collect(Collectors.toList());
                if (teachCollegeNameList.size() != 1) {
                    throw ExceptionResultEnum.ERROR.exception("考务数据-教师对应的开课学院有误");
                }
                teacherCode = teacherCodeList.get(0);
                String teachCollegeName = teachCollegeNameList.get(0);
                List<SysOrg> sysOrgList = sysOrgService.list(new QueryWrapper<SysOrg>().lambda().eq(SysOrg::getName, teachCollegeName).eq(SysOrg::getSchoolId, schoolId));
                if (sysOrgList.size() != 1) {
                    throw ExceptionResultEnum.ERROR.exception("未能找到考务数据中学院名称的学院");
                }
                orgId = sysOrgList.get(0).getId();
            }
            if (!teacherUserMap.containsKey(teacherName)){
                teacherUserMap.put(teacherName,teacherCode);
            }

            TBSchoolTeacherDto tbSchoolTeacherDto = new TBSchoolTeacherDto();
            tbSchoolTeacherDto.setSchoolId(schoolId);
            tbSchoolTeacherDto.setTeacherCode(teacherCode);
            tbSchoolTeacherDto.setTeacherName(teacherName);
            tbSchoolTeacherDto.setOrgId(orgId);
            tbSchoolTeacherDtoList.add(tbSchoolTeacherDto);
        }
        this.saveTeacherInfo(tbSchoolTeacherDtoList);


        List<TBStudent> tbStudentList = new ArrayList<>();
        List<TBExamStudent> tbExamStudentList = new ArrayList<>();
        List<TBExamRecord> tbExamRecordList = new ArrayList<>();
        List<TBAnswer> tbAnswerList = new ArrayList<>();

        List<String> paperTypeList = finalList.stream().map(e -> String.valueOf(e.get("paperType"))).distinct().collect(Collectors.toList());
        final String specialPaperType = "#";
        paperTypeList.remove(specialPaperType);
        int count = paperTypeList.size();
        int i = 0;

        Map<String, TBStudent> checkMap = new HashMap<>();
        for (Map map : finalList) {
            String subjectCode = String.valueOf(map.get(ExamCloudDataEnum.SUBJECT_CODE.getName())); //科目代码
            String subjectName = String.valueOf(map.get(ExamCloudDataEnum.SUBJECT_NAME.getName())); //科目名称
            String examNumber = String.valueOf(map.get(ExamCloudDataEnum.EXAM_NUMBER.getName())); //准考证号
            String studentCode = String.valueOf(map.get(ExamCloudDataEnum.STUDENT_CODE.getName())); //学号
            String name = String.valueOf(map.get(ExamCloudDataEnum.NAME.getName())); //名称
            String paperType = String.valueOf(map.get(ExamCloudDataEnum.PAPER_TYPE.getName())); //试卷类型
            // 循环依次为#生成（分配）试卷编号为A、B、C......A、B、C......
            if (count > 0 && paperType.equals(specialPaperType)) {
                paperType = paperTypeList.get(i);
                i++;
                if (i == count) {
                    i = 0;
                }
            }

            String college = String.valueOf(map.get(ExamCloudDataEnum.COLLEGE.getName())); //学院
            String className = String.valueOf(map.get(ExamCloudDataEnum.CLASS_NAME.getName())); //班级名称
            String teacher = String.valueOf(map.get(ExamCloudDataEnum.TEACHER.getName())); //教师
            Map<String, String> teacherMap = this.disposeTeacherInfo(teacher);
            String teacherName = teacherMap.get("teacherName");
            String teacherCode = teacherMap.get("teacherCode");
            if (!SystemConstant.strNotNull(teacherCode)){
                teacherCode = teacherUserMap.get(teacherName);
            }
            // 缺考状态 2 -> 缺考 ； 3 -> 违纪
            int status = (int) map.get(ExamCloudDataEnum.STATUS.getName()); //学生考试状态
            String totalScore = String.valueOf(map.get(ExamCloudDataEnum.TOTAL_SCORE.getName())); //考生总分
            String objectiveScore = String.valueOf(map.get(ExamCloudDataEnum.OBJECTIVE_SCORE.getName())); //客观题总分
            String subjectiveScore = String.valueOf(map.get(ExamCloudDataEnum.SUBJECTIVE_SCORE.getName())); //主观题总分
            List<Map<Object, Object>> objectiveScoreDetailList = (List<Map<Object, Object>>) map.get(ExamCloudDataEnum.OBJECTIVE_SCORE_DETAIL.getName()); //客观题明细
            List<Map<Object, Object>> subjectiveScoreDetailList = (List<Map<Object, Object>>) map.get(ExamCloudDataEnum.SUBJECTIVE_SCORE_DETAIL.getName()); //主观题答题明细

            /*
                组建学生基础信息 student
             */
            if (checkMap.containsKey(studentCode)) {
                if (!checkMap.get(studentCode).getName().equals(name)) {
                    throw ExceptionResultEnum.ERROR.exception("有学号【" + studentCode + "】的学生名称不统一");
                }
            } else {
                TBStudent studentTemp = tbStudentService.getOne(new QueryWrapper<TBStudent>().lambda()
                        .eq(TBStudent::getSchoolId, schoolId)
                        .eq(TBStudent::getStudentCode, studentCode));
                Long studentId;
                if (Objects.nonNull(studentTemp)) {
                    studentId = studentTemp.getId();
                } else {
                    studentId = SystemConstant.getDbUuid();
                }
                TBStudent tbStudent = new TBStudent();
                tbStudent.setId(studentId);
                tbStudent.setSchoolId(schoolId);
                tbStudent.setName(name);
                tbStudent.setStudentCode(studentCode);
                checkMap.put(studentCode, tbStudent);
                tbStudentList.add(tbStudent);
            }


            /*
                组建考生考试信息 exm_pap_tik
             */
            List<TBExamCourse> needDisposeList;
            if (linkSign != null && linkSign.length() > 0) { // 云阅卷在同一个考试下 科目名称相同分AB卷 但在教研分析时分科处理的科目
                String finalPaperType = paperType;
                needDisposeList = tbExamCourseList.stream().filter(e -> e.getCourseName().equals(subjectName + linkSign + finalPaperType)).collect(Collectors.toList());
            } else {
                needDisposeList = tbExamCourseList.stream().filter(e -> e.getCourseName().equals(subjectName)).collect(Collectors.toList());
            }
            if (needDisposeList.size() == 1) {

                TBExamCourse tbExamCourse = needDisposeList.get(0);
                String courseCode = tbExamCourse.getCourseCode();
                String courseName = tbExamCourse.getCourseName();
                // 开课学院id
                Long teachCollegeId = tbExamCourse.getTeachCollegeId();
                if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, courseName)) {
                    continue;
                }

                // TODO: 2021/6/2 创建学生-考试关系表(全批次删除并新增)
                // 获取关联的基础表主键
                SysOrg tbSchoolCollege = sysOrgService.findByForeignKey(schoolId, college, college);
                TBSchoolClazz tbSchoolClazz = tbSchoolClazzService.findByForeignKey(schoolId, className, className);
                SysUser tbSchoolTeacher = sysUserService.findByForeignKey(schoolId,teacherCode);

                TBExamStudent tbExamStudent = new TBExamStudent();
                Long examStudentId = SystemConstant.getDbUuid();
                tbExamStudent.setId(examStudentId);
                tbExamStudent.setSchoolId(tbExamService.getById(examId).getSchoolId());
                tbExamStudent.setExamId(examId);
                tbExamStudent.setName(name);
                tbExamStudent.setStudentId(checkMap.get(studentCode).getId());
                tbExamStudent.setStudentCode(studentCode);
                tbExamStudent.setCourseCode(courseCode);
                tbExamStudent.setCourseName(courseName);
                tbExamStudent.setTeachCollegeId(teachCollegeId);
                tbExamStudent.setInspectCollegeId(tbSchoolCollege.getId());
                tbExamStudent.setClazzId(tbSchoolClazz.getId());
                tbExamStudent.setMajorId(0L);
                if (Objects.nonNull(tbSchoolTeacher)) {
                    tbExamStudent.setTeacherId(tbSchoolTeacher.getId());
                } else {
                    tbExamStudent.setTeacherId(0L);
                }
                tbExamStudent.setTicketNumber(examNumber);
                tbExamStudent.setAbsent(status == 2 || status == 3);
                // 全部设置为本届
                tbExamStudent.setStudentCurrent(true);
                tbExamStudentList.add(tbExamStudent);

                // TODO: 2021/6/2 创建考生-考试记录关系表（全批次删除并新增）
                // 构建考生作答记录表(t_b_exam_record)
                Long examRecordId = SystemConstant.getDbUuid();
                TBExamRecord tbExamRecord = new TBExamRecord();
                tbExamRecord.setId(examRecordId);
                tbExamRecord.setExamId(examId);
                tbExamRecord.setPaperId(tbPaperService.findByForeignKey(examId, courseCode, courseName, paperType).getId());
                tbExamRecord.setPaperType(paperType);
                tbExamRecord.setExamStudentId(examStudentId);
                tbExamRecord.setSubjectiveScore(BigDecimal.valueOf(Double.parseDouble(subjectiveScore)));
                tbExamRecord.setObjectiveScore(BigDecimal.valueOf(Double.parseDouble(objectiveScore)));
                tbExamRecord.setTotalScore(BigDecimal.valueOf(Double.parseDouble(totalScore)));
                tbExamRecordList.add(tbExamRecord);

                // TODO: 2021/6/4 构建考生-详细作答记录表（全批次删除并新增）
                // 构建考生作答明细表（t_b_answer）正常考生才记录
                // 客观题（选择）
                if (status == 1) {
                    for (Map<Object, Object> objectObjectMap : objectiveScoreDetailList) {
                        Long answerId = SystemConstant.getDbUuid();
                        TBAnswer tbAnswer = new TBAnswer();
                        tbAnswer.setId(answerId);
                        tbAnswer.setExamRecordId(examRecordId);
                        tbAnswer.setNumberType(NumberTypeEnum.OBJECTIVE.getValue());
                        String cloudMainNumber = String.valueOf(objectObjectMap.get(ExamCloudDataEnum.MAIN_NUMBER.getName()));
                        String cloudSubNumber = String.valueOf(objectObjectMap.get(ExamCloudDataEnum.SUB_NUMBER.getName()));
                        tbAnswer.setMainNumber(cloudMainNumber);
                        tbAnswer.setSubNumber(cloudSubNumber);
                        tbAnswer.setScore(BigDecimal.valueOf(Double.parseDouble(String.valueOf(objectObjectMap.get(ExamCloudDataEnum.SCORE.getName())))));
                        tbAnswer.setAnswer(String.valueOf(objectObjectMap.get(ExamCloudDataEnum.ANSWER.getName())));
                        tbAnswerList.add(tbAnswer);
                    }
                    // 主观题
                    for (Map<Object, Object> objectObjectMap : subjectiveScoreDetailList) {
                        Long answerId = SystemConstant.getDbUuid();
                        TBAnswer tbAnswer = new TBAnswer();
                        tbAnswer.setId(answerId);
                        tbAnswer.setExamRecordId(examRecordId);
                        tbAnswer.setNumberType(NumberTypeEnum.SUBJECTIVE.getValue());
                        String cloudMainNumber = String.valueOf(objectObjectMap.get(ExamCloudDataEnum.MAIN_NUMBER.getName()));
                        String cloudSubNumber = String.valueOf(objectObjectMap.get(ExamCloudDataEnum.SUB_NUMBER.getName()));
                        tbAnswer.setMainNumber(cloudMainNumber);
                        tbAnswer.setSubNumber(cloudSubNumber);
                        tbAnswer.setScore(BigDecimal.valueOf(Double.parseDouble(String.valueOf(objectObjectMap.get(ExamCloudDataEnum.SCORE.getName())))));
                        tbAnswer.setAnswer(String.valueOf(objectObjectMap.get(ExamCloudDataEnum.ANSWER.getName())));
                        tbAnswerList.add(tbAnswer);
                    }
                }
            }
        }

        // 处理并向数据库插入学生信息
        tbStudentService.saveOrUpdateBatch(tbStudentList);

        // 删除原t_b_answer、t_b_exam_record、t_b_exam_student表数据
        List<String> courseInfoList = tbExamStudentList.stream().map(TBExamStudent::getCourseCode).collect(Collectors.toList());
        Set<Long> examStudentRemoveIdSet = new HashSet<>();
        for (String s : courseInfoList) {
            Set<Long> ids = tbExamStudentService.list(new QueryWrapper<TBExamStudent>().lambda()
                            .eq(TBExamStudent::getCourseCode, s))
                    .stream().map(TBExamStudent::getId).collect(Collectors.toSet());
            examStudentRemoveIdSet.addAll(ids);
        }

        if (examStudentRemoveIdSet.size() > 0) {
            // 删除考生表
            tbExamStudentService.removeByIds(examStudentRemoveIdSet);
            List<TBExamRecord> willRemoveRecord = tbExamRecordService.list(new QueryWrapper<TBExamRecord>()
                    .lambda().in(TBExamRecord::getExamStudentId, examStudentRemoveIdSet));
            if (willRemoveRecord.size() > 0) {
                List<Long> willRemoveRecordIdList = willRemoveRecord.stream().map(TBExamRecord::getId).collect(Collectors.toList());
                // 删除考生作答
                tbExamRecordService.removeByIds(willRemoveRecordIdList);
                // 删除考生作答
                tbAnswerService.remove(new QueryWrapper<TBAnswer>().lambda().in(TBAnswer::getExamRecordId, willRemoveRecordIdList));
            }
        }

        // 保存数据
        tbExamStudentService.saveBatch(tbExamStudentList);
        tbExamRecordService.saveBatch(tbExamRecordList);
        tbAnswerService.saveBatch(tbAnswerList);
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
    }

    @ApiOperation(value = "公式赋分操作")
    @RequestMapping(value = "/normal/assignScore", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result normalAssignScore(@RequestParam Long examId, @RequestParam Long schoolId, @RequestParam String courseCode) {
        analyzeForReportService.normalAssignScore(examId, schoolId, courseCode);
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
    }

    @ApiOperation(value = "特殊科目赋分操作")
    @RequestMapping(value = "/special/assignScore", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result specialAssignScore(@ApiParam(value = "上传文件", required = true) @RequestParam MultipartFile file, @RequestParam Long examId, @RequestParam Long schoolId,
                                     @ApiParam(value = "该Excel中包含多科目赋分时，各科目编号用','隔开", required = true) @RequestParam String courseCodeS) throws IOException, NoSuchFieldException {

        List<String> courseCodeList = Arrays.asList(courseCodeS.split(","));
        // 数据同步操作
        // 获取当前课程下所有学生考试成绩记录
        List<BasicExamRecordDto> basicExamRecordDtoDatasource = tbExamRecordService.findByExamIdAndCourseCodeS(examId, courseCodeList);
        Set<TAExamCourseRecord> taExamCourseRecordDatasource = new HashSet<>();
        for (String s : courseCodeList) {
            if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, s, basicCourseService.findByCourseCode(s, schoolId).getName())) {
                throw ExceptionResultEnum.ERROR.exception("课程编号[" + s + "]的课程分析数据已测试或发布，不能变更基础数据");
            }
            List<BasicExamRecordDto> basicExamRecordDtoList = basicExamRecordDtoDatasource.stream()
                    .filter(e -> s.equals(e.getCourseCode())).collect(Collectors.toList());
            if (basicExamRecordDtoList.size() > 0) {
                // 删除源数据
                taExamCourseRecordService.remove(new QueryWrapper<TAExamCourseRecord>()
                        .lambda().eq(TAExamCourseRecord::getExamId, examId).eq(TAExamCourseRecord::getCourseCode, s));
                // 迁移数据至't_a_exam_course_record'
                List<TAExamCourseRecord> taExamCourseRecordList = new ArrayList<>();
                for (BasicExamRecordDto basicExamRecordDto : basicExamRecordDtoList) {
                    if (basicExamRecordDto.getStudentCode().equals("2020303041027")) {
                        System.out.println("进入");
                    }
                    // 正常公式赋分操作
                    Long paperId = basicExamRecordDto.getPaperId();
                    TBPaper tbPaper = tbPaperService.getById(paperId);
                    if (Objects.isNull(tbPaper)) {
                        throw ExceptionResultEnum.ERROR.exception("试卷信息数据异常");
                    }
                    BigDecimal fullScore = tbPaper.getTotalScore();
                    BigDecimal myScore = basicExamRecordDto.getTotalScore();
                    BigDecimal coefficient = tbPaper.getCoefficient();
                    BigDecimal assignScore;
                    if (coefficient != null && coefficient.compareTo(BigDecimal.ZERO) > 0 && !basicExamRecordDto.getAbsent()) {
                        assignScore = myScore.add(fullScore.subtract(myScore).divide(coefficient, 4, RoundingMode.HALF_UP)).setScale(0, RoundingMode.HALF_UP);
                    } else {
                        assignScore = myScore;
                    }
                    TAExamCourseRecord taExamCourseRecord = new TAExamCourseRecord();
                    taExamCourseRecord.setId(SystemConstant.getDbUuid());
                    taExamCourseRecord.setExamRecordId(basicExamRecordDto.getTbExamRecordId());
                    // 数据同步默认赋分成绩为卷面成绩
                    taExamCourseRecord.setSchoolId(tbExamService.getById(examId).getSchoolId());
                    taExamCourseRecord.setAssignedScore(assignScore);
                    taExamCourseRecord.setExamId(examId);
                    taExamCourseRecord.setCourseCode(basicExamRecordDto.getCourseCode());
                    taExamCourseRecord.setPaperId(basicExamRecordDto.getPaperId());
                    taExamCourseRecord.setPaperType(basicExamRecordDto.getPaperType());
                    taExamCourseRecord.setStudentId(basicExamRecordDto.getStudentId());
                    taExamCourseRecord.setStudentCode(basicExamRecordDto.getStudentCode());
                    taExamCourseRecord.setTeacherId(basicExamRecordDto.getTeacherId());
                    taExamCourseRecord.setClazzId(basicExamRecordDto.getClazzId());
                    taExamCourseRecord.setTeachCollegeId(basicExamRecordDto.getTeachCollegeId());
                    taExamCourseRecord.setInspectCollegeId(basicExamRecordDto.getInspectCollegeId());
                    taExamCourseRecord.setMajorId(basicExamRecordDto.getMajorId());
                    taExamCourseRecord.setTotalScore(myScore);
                    taExamCourseRecord.setAbsent(basicExamRecordDto.getAbsent());
                    taExamCourseRecord.setStudentCurrent(basicExamRecordDto.getStudentCurrent());
                    taExamCourseRecordList.add(taExamCourseRecord);
                }
                taExamCourseRecordDatasource.addAll(taExamCourseRecordList);
                taExamCourseRecordService.saveBatch(taExamCourseRecordList);
            }
        }

        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(file.getInputStream(), Lists.newArrayList(AssignDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
            if (finalExcelErrorList.size() > 0) {
                throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(finalExcelErrorList));
            }
            return finalExcelList;
        });

        //保存到数据库
        List<TAExamCourseRecord> willUpdate = new ArrayList<>();
        if (Objects.nonNull(finalList) && finalList.size() > 0) {
            for (int i = 0; i < finalList.size(); i++) {
                LinkedMultiValueMap<Integer, Object> map = finalList.get(i);
                List<Object> assignList = map.get(i);
                for (int y = 0; y < Objects.requireNonNull(assignList).size(); y++) {
                    if (assignList.get(y) instanceof AssignDto) {
                        AssignDto assignDto = (AssignDto) assignList.get(y);
                        Long assExamId = Long.parseLong(assignDto.getExamId());
                        if (!examId.equals(assExamId)) {
                            throw ExceptionResultEnum.ERROR.exception("excel考试数据异常");
                        }
                        String assCourseCodeS = assignDto.getPaperCodeS();
                        String assStudentCode = assignDto.getStudentCode();
                        String assAssignScore = assignDto.getAssignScore();
                        String[] courseCodeArr = assCourseCodeS.split(",");
                        for (String s : courseCodeArr) {
                            List<TAExamCourseRecord> taExamCourseRecordList = taExamCourseRecordDatasource.stream()
                                    .filter(e -> assExamId.equals(e.getExamId()) && s.equals(e.getCourseCode()) && assStudentCode.equals(e.getStudentCode()))
                                    .collect(Collectors.toList());
                            if (taExamCourseRecordList.size() != 1) {
                                if (taExamCourseRecordList.size() < 1) {
                                    continue;
                                }
                                System.out.println("-----------------------");
                                System.out.println(JSON.toJSONString(taExamCourseRecordList));
                                throw ExceptionResultEnum.ERROR.exception("赋分异常,考生记录分析表数据异常");
                            }
                            TAExamCourseRecord taExamCourseRecord = taExamCourseRecordList.get(0);
                            taExamCourseRecord.setAssignedScore(BigDecimal.valueOf(Double.parseDouble(assAssignScore)));
                            willUpdate.add(taExamCourseRecord);
                        }
                    }
                }
            }
        }
        taExamCourseRecordService.saveOrUpdateBatch(willUpdate);
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
    }

    @ApiOperation(value = "常规配置信息导入：试卷难易度和学院排名百分等级档位")
    @RequestMapping(value = "/config/import", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result configImport(@RequestParam Long schoolId, @RequestParam Long examId, @RequestParam String courseCode) {
        String courseName = basicCourseService.findByCourseCode(courseCode, schoolId).getName();
        if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, courseName)) {
            throw ExceptionResultEnum.ERROR.exception("课程编号[" + courseCode + "]的课程分析数据已测试或发布，不能变更基础数据");
        }
        tbCommonLevelConfigService.importLevelConfig(examId, courseCode, courseName);
        tbCommonRankLevelConfigService.importRankLevelConfig(examId, courseCode, courseName);
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
    }

    @ApiOperation(value = "创建课程")
    @RequestMapping(value = "/course/create", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result courseCreate(@RequestParam Long schoolId, @RequestParam String examId, @RequestParam String courseCode, @RequestParam String courseName, @RequestParam(required = false) String examinationCourseCode, @RequestParam(required = false) String teachCollegeName) {
        if ((!SystemConstant.strNotNull(examinationCourseCode) && !SystemConstant.strNotNull(teachCollegeName)) || (SystemConstant.strNotNull(examinationCourseCode) && SystemConstant.strNotNull(teachCollegeName))) {
            throw ExceptionResultEnum.ERROR.exception("参数异常 ： 考务课程编号和课程授课学院不能全不传或全传");
        }
        basicCourseService.createCourse(schoolId, courseCode, courseName);
        tbExamCourseService.createCourse(schoolId, SystemConstant.convertIdToLong(examId), courseCode, courseName, examinationCourseCode, teachCollegeName);

        return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
    }

    @ApiOperation(value = "考务数据同步")
    @RequestMapping(value = "/examination/sync", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result examinationSync(@ApiParam(value = "上传文件", required = true) @RequestParam MultipartFile file, @RequestParam Long schoolId, @RequestParam String examId) throws IOException, NoSuchFieldException {
        if (Objects.isNull(file)) {
            throw ExceptionResultEnum.ERROR.exception("附件不存在");
        }
        if (Objects.isNull(schoolId) || schoolId == 0) {
            throw ExceptionResultEnum.ERROR.exception("参数缺失");
        }
        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(file.getInputStream(), Lists.newArrayList(ExaminationDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
            if (finalExcelErrorList.size() > 0) {
                throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(finalExcelErrorList));
            }
            return finalExcelList;
        });

        List<TBExamination> tbExaminationList = new ArrayList<>();
        if (Objects.nonNull(finalList) && finalList.size() > 0) {
            for (int i = 0; i < finalList.size(); i++) {
                LinkedMultiValueMap<Integer, Object> map = finalList.get(i);
                List<Object> examinationList = map.get(i);
                for (int y = 0; y < Objects.requireNonNull(examinationList).size(); y++) {
                    if (examinationList.get(y) instanceof ExaminationDto) {
                        // excel 数据解析
                        ExaminationDto examinationDto = (ExaminationDto) examinationList.get(y);
                        String courseHeaderCode = examinationDto.getCourseHeaderCode();
                        String courseExaminationCode = examinationDto.getCourseExaminationCode();
                        String courseName = examinationDto.getCourseName();
                        String teacherCode = examinationDto.getTeacherCode();
                        String teacherName = examinationDto.getTeacherName();
                        String teachCollegeName = examinationDto.getTeachCollegeName();
                        String credit = examinationDto.getCredit();
                        String studentCode = examinationDto.getStudentCode();
                        String studentName = examinationDto.getStudentName();
                        String inspectCollegeName = examinationDto.getInspectCollegeName();
                        String major = examinationDto.getMajor();
                        String studyType = examinationDto.getStudyType();
                        String grade = examinationDto.getGrade();
                        // 数据组装
                        TBExamination tbExamination = new TBExamination();
                        tbExamination.setId(SystemConstant.getDbUuid());
                        tbExamination.setSchoolId(schoolId);
                        tbExamination.setExamId(SystemConstant.convertIdToLong(examId));
                        tbExamination.setCourseHeaderCode(courseHeaderCode);
                        tbExamination.setExaminationCourseCode(courseExaminationCode);
                        tbExamination.setCourseName(courseName);
                        tbExamination.setTeacherCode(teacherCode);
                        tbExamination.setTeacherName(teacherName);
                        tbExamination.setTeachCollegeName(teachCollegeName);
                        if (SystemConstant.strNotNull(credit)) {
                            tbExamination.setCredit(credit);
                        }
                        tbExamination.setStudentCode(studentCode);
                        tbExamination.setStudentName(studentName);
                        tbExamination.setInspectCollegeName(inspectCollegeName);
                        tbExamination.setMajor(major);
                        tbExamination.setStudyType(studyType);
                        tbExamination.setGrade(grade);
                        tbExaminationList.add(tbExamination);
                    }
                }
            }
        }
        List<Map<String, Object>> tbExaminationRelationMapList = tbExaminationList.stream().flatMap(e -> {
            Map<String, Object> map = new HashMap<>();
            map.put("schoolId", e.getSchoolId());
            map.put("examId", e.getExamId());
            map.put("examinationCourseCode", e.getExaminationCourseCode());
            map.put("courseName", e.getCourseName());
            map.put("teachCollegeName", e.getTeachCollegeName());
            map.put("teacherCode", e.getTeacherCode());
            map.put("teacherName", e.getTeacherName());
            return Stream.of(map);
        }).distinct().collect(Collectors.toList());

        List<TBExaminationRelation> tbExaminationRelationList = new ArrayList<>();
        for (Map<String, Object> map : tbExaminationRelationMapList) {
            TBExaminationRelation tbExaminationRelation = new TBExaminationRelation();
            tbExaminationRelation.setId(SystemConstant.getDbUuid());
            tbExaminationRelation.setSchoolId(SystemConstant.convertIdToLong(String.valueOf(map.get("schoolId"))));
            tbExaminationRelation.setExamId(SystemConstant.convertIdToLong(String.valueOf(map.get("examId"))));
            tbExaminationRelation.setExaminationCourseCode(String.valueOf(map.get("examinationCourseCode")));
            tbExaminationRelation.setCourseName(String.valueOf(map.get("courseName")));
            tbExaminationRelation.setTeachCollegeName(String.valueOf(map.get("teachCollegeName")));
            tbExaminationRelation.setTeacherCode(String.valueOf(map.get("teacherCode")));
            tbExaminationRelation.setTeacherName(String.valueOf(map.get("teacherName")));
            tbExaminationRelationList.add(tbExaminationRelation);
        }

        tbExaminationService.remove(new QueryWrapper<TBExamination>().lambda().eq(TBExamination::getExamId, examId));
        tbExaminationRelationService.remove(new QueryWrapper<TBExaminationRelation>().lambda().eq(TBExaminationRelation::getExamId, examId));

        tbExaminationService.saveBatch(tbExaminationList);
        tbExaminationRelationService.saveBatch(tbExaminationRelationList);
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
    }

    @ApiOperation(value = "异常考生-批量处理")
    @RequestMapping(value = "/exception_student/batch_dispose", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result exceptionStudentBatchDispose(@RequestParam String schoolId, @RequestParam String examId, @RequestParam(required = false) String courseCode) {
        String courseName = basicCourseService.findByCourseCode(courseCode, SystemConstant.convertIdToLong(schoolId)).getName();
        if (tbExamCourseService.verifyExamCourseCantRun(SystemConstant.convertIdToLong(examId), SystemConstant.convertIdToLong(schoolId), courseCode, courseName)) {
            throw ExceptionResultEnum.ERROR.exception("课程编号[" + courseCode + "]的课程分析数据已测试或发布，不能变更基础数据");
        }
        List<TBExamination> tbExaminationList = tbExaminationService.list(new QueryWrapper<TBExamination>().lambda()
                .eq(TBExamination::getExamId, SystemConstant.convertIdToLong(examId))
                .eq(TBExamination::getSchoolId, SystemConstant.convertIdToLong(schoolId))
                .eq(TBExamination::getExaminationCourseCode, tbExamCourseService.getOne(new QueryWrapper<TBExamCourse>().lambda()
                                .eq(TBExamCourse::getExamId, examId)
                                .eq(TBExamCourse::getCourseCode, courseCode)
                                .eq(TBExamCourse::getSchoolId, schoolId))
                        .getPaperType())
                .eq(TBExamination::getCourseName, courseName)
                .ne(TBExamination::getStudyType, "普通"));
        int count = tbExaminationList.size();
        if (count > 0) {
            List<TBExamStudent> tbExamStudentList = tbExamStudentService.list(new QueryWrapper<TBExamStudent>().lambda()
                    .eq(TBExamStudent::getExamId, examId)
                    .eq(TBExamStudent::getSchoolId, schoolId)
                    .eq(TBExamStudent::getCourseCode, courseCode));

            List<TBExamStudent> willUpdate = new ArrayList<>();
            for (TBExamination tbExamination : tbExaminationList) {
                String studentCode = tbExamination.getStudentCode();
                List<TBExamStudent> cellList = tbExamStudentList.stream().filter(e -> studentCode.equals(e.getStudentCode())).collect(Collectors.toList());
                if (cellList.size() != 1) {
                    throw ExceptionResultEnum.ERROR.exception("数据异常");
                }
                TBExamStudent cell = cellList.get(0);
                cell.setStudentCurrent(false);
                willUpdate.add(cell);
            }
            tbExamStudentService.saveOrUpdateBatch(willUpdate);
        }
        return ResultUtil.ok("有【" + count + "】条非应届学生数据被更新");
    }

    @ApiOperation(value = "异常考生-按学号处理")
    @RequestMapping(value = "/exception_student/dispose_by_student_code", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result exceptionStudentDisposeByStudentCode(@RequestParam String schoolId, @RequestParam String examId, @RequestParam List<String> courseCodeList, @RequestParam String year) {
        for (String courseCode : courseCodeList) {
            TBExamCourse tbExamCourse = tbExamCourseService.getOne(new QueryWrapper<TBExamCourse>().lambda()
                    .eq(TBExamCourse::getExamId, examId)
                    .eq(TBExamCourse::getSchoolId, schoolId)
                    .eq(TBExamCourse::getCourseCode, courseCode));
            if (tbExamCourse.getPublishStatus().equals(PublishStatusEnum.PUBLISH)) {
                throw ExceptionResultEnum.ERROR.exception("已经发布的课程【" + tbExamCourse.getCourseName() + "】不能进行特殊处理");
            }
        }
        // 更改 ‘t_b_exam_student’表考生应届状态
        List<TBExamStudent> tbExamStudentList = tbExamStudentService.list(new QueryWrapper<TBExamStudent>().lambda()
                .eq(TBExamStudent::getSchoolId, schoolId)
                .eq(TBExamStudent::getExamId, examId)
                .in(TBExamStudent::getCourseCode, courseCodeList));
        // 全部改为应届
        for (TBExamStudent tbExamStudent : tbExamStudentList) {
            tbExamStudent.setStudentCurrent(true);
        }
        tbExamStudentService.updateBatchById(tbExamStudentList);
        // 非应届考生
        tbExamStudentList = tbExamStudentList.stream()
                .filter(e -> !e.getStudentCode().substring(0, 4).equals(year))
                .collect(Collectors.toList());

        // 更改 ‘t_a_exam_course_record’表考生应届状态
        List<TAExamCourseRecord> taExamCourseRecordList = taExamCourseRecordService.list(new QueryWrapper<TAExamCourseRecord>().lambda()
                .eq(TAExamCourseRecord::getSchoolId, schoolId)
                .eq(TAExamCourseRecord::getExamId, examId)
                .in(TAExamCourseRecord::getCourseCode, courseCodeList));
        // 全部改为应届
        for (TAExamCourseRecord taExamCourseRecord : taExamCourseRecordList) {
            taExamCourseRecord.setStudentCurrent(true);
        }
        taExamCourseRecordService.updateBatchById(taExamCourseRecordList);

        // 非应届考生记录
        taExamCourseRecordList = taExamCourseRecordList.stream()
                .filter(e -> !e.getStudentCode().substring(0, 4).equals(year))
                .collect(Collectors.toList());

        if (tbExamStudentList.size() > 0) {
            for (TBExamStudent tbExamStudent : tbExamStudentList) {
                tbExamStudent.setStudentCurrent(false);
            }
            tbExamStudentService.updateBatchById(tbExamStudentList);

            if (tbExamStudentList.size() == taExamCourseRecordList.size()) {
                for (TAExamCourseRecord taExamCourseRecord : taExamCourseRecordList) {
                    taExamCourseRecord.setStudentCurrent(false);
                }
                taExamCourseRecordService.updateBatchById(taExamCourseRecordList);
            }
        }
        return ResultUtil.ok("有【" + tbExamStudentList.size() + "】条非应届学生数据被更新");
    }

    @ApiOperation(value = "特殊科目合并题目处理")
    @RequestMapping(value = "/special/combine", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result specialCombine(@RequestBody CombineDto combineDto) {

        Long examId = combineDto.getExamId();
        String courseCode = combineDto.getCourseCode();
        String orgMain1 = combineDto.getOrgMain1();
        String orgSub1 = combineDto.getOrgSub1();
        String orgMain2 = combineDto.getOrgMain2();
        String orgSub2 = combineDto.getOrgSub2();
        String comMain = combineDto.getComMain();
        String comSub = combineDto.getComSub();
        // TODO: 2021/6/25 合题的检验
        TBPaper tbPaper = tbPaperService.getOne(new QueryWrapper<TBPaper>().lambda().eq(TBPaper::getExamId, examId).eq(TBPaper::getCourseCode, courseCode));
        Long paperId = tbPaper.getId();
        List<TBExamRecord> tbExamRecordList = tbExamRecordService.list(new QueryWrapper<TBExamRecord>().lambda().eq(TBExamRecord::getExamId, examId).eq(TBExamRecord::getPaperId, paperId));
        List<Long> examRecordIdList = tbExamRecordList.stream().map(TBExamRecord::getId).distinct().collect(Collectors.toList());

        List<TBAnswer> tbAnswerList = tbAnswerService.list(new QueryWrapper<TBAnswer>().lambda().in(TBAnswer::getExamRecordId, examRecordIdList));

        List<Long> willDeleteList = new ArrayList<>();
        List<TBAnswer> willInsertList = new ArrayList<>();
        for (Long examRecordId : examRecordIdList) {
            List<TBAnswer> oneStudentAnswerList = tbAnswerList.stream().filter(e -> e.getExamRecordId().equals(examRecordId)).collect(Collectors.toList());
            if (oneStudentAnswerList.size() == 0) {
                continue;
            }
            // 原始1题
            TBAnswer org1 = oneStudentAnswerList.stream()
                    .filter(e -> e.getMainNumber().equals(orgMain1) && e.getSubNumber().equals(orgSub1))
                    .collect(Collectors.toList()).get(0);
            Long org1Id = org1.getId();
            BigDecimal org1Score = org1.getScore();

            // 原始2题
            TBAnswer org2 = oneStudentAnswerList.stream()
                    .filter(e -> e.getMainNumber().equals(orgMain2) && e.getSubNumber().equals(orgSub2))
                    .collect(Collectors.toList()).get(0);

            Long org2Id = org2.getId();
            BigDecimal org2Score = org2.getScore();
            if (!org1.getNumberType().equals(org2.getNumberType())) {
                throw ExceptionResultEnum.ERROR.exception("题目类型不一致 合题失败");
            }

            BigDecimal comboScore = org1Score.add(org2Score);
            TBAnswer combo = new TBAnswer();
            combo.setId(SystemConstant.getDbUuid());
            combo.setExamRecordId(examRecordId);
            combo.setNumberType(org1.getNumberType());
            combo.setMainNumber(comMain);
            combo.setSubNumber(comSub);
            combo.setScore(comboScore);

            willInsertList.add(combo);

            willDeleteList.add(org1Id);
            willDeleteList.add(org2Id);
        }
        tbAnswerService.removeByIds(willDeleteList);
        tbAnswerService.saveBatch(willInsertList);
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
    }

    @ApiOperation(value = "异常答案/分数处理（先处理异常后赋分）")
    @RequestMapping(value = "/exception_answer/score_dispose", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result exceptionAnswerScoreDispose(@RequestParam Long schoolId, @RequestParam String examId, @RequestParam String courseCode, @RequestParam String numberType, @RequestParam String mainNumber, @RequestParam String subNumber, @RequestParam String answer, @RequestParam BigDecimal score) {

        TBPaper tbPaper = tbPaperService.getOne(new QueryWrapper<TBPaper>().lambda().eq(TBPaper::getCourseCode, courseCode).eq(TBPaper::getExamId, examId));
        Long paperId = tbPaper.getId();
        List<TBExamRecord> tbExamRecordList = tbExamRecordService.list(new QueryWrapper<TBExamRecord>().lambda().eq(TBExamRecord::getExamId, examId).eq(TBExamRecord::getPaperId, paperId));
        List<Long> examRecordIdList = tbExamRecordList.stream().map(TBExamRecord::getId).distinct().collect(Collectors.toList());

        // 要改分的作答记录
        List<TBAnswer> tbAnswerList = tbAnswerService.list(new QueryWrapper<TBAnswer>().lambda()
                .in(TBAnswer::getExamRecordId, examRecordIdList)
                .eq(TBAnswer::getNumberType, numberType)
                .eq(TBAnswer::getMainNumber, mainNumber)
                .eq(TBAnswer::getSubNumber, subNumber)
                .eq(TBAnswer::getAnswer, answer));

        List<TBExamRecord> willUpdateRecordList = new ArrayList<>();
        for (TBAnswer tbAnswer : tbAnswerList) {
            // 对该考生 详细作答记录的得分修改
            BigDecimal orgScore = tbAnswer.getScore();
            BigDecimal scoreGap = score.subtract(orgScore);
            tbAnswer.setScore(score);

            // 对该考生 总体考试成绩的得分修改
            TBExamRecord tbExamRecord = tbExamRecordList.stream().filter(e -> e.getId().equals(tbAnswer.getExamRecordId())).collect(Collectors.toList()).get(0);
            BigDecimal totalScore = tbExamRecord.getTotalScore();
            if (numberType.equals("客观题")) {
                BigDecimal objectiveScore = tbExamRecord.getObjectiveScore();
                objectiveScore = objectiveScore.add(scoreGap);
                tbExamRecord.setObjectiveScore(objectiveScore);
            } else if (numberType.equals("主观题")) {
                BigDecimal subjectiveScore = tbExamRecord.getSubjectiveScore();
                subjectiveScore = subjectiveScore.add(scoreGap);
                tbExamRecord.setSubjectiveScore(subjectiveScore);
            } else {
                throw ExceptionResultEnum.ERROR.exception("题目类型有误");
            }
            totalScore = totalScore.add(scoreGap);
            tbExamRecord.setTotalScore(totalScore);
            willUpdateRecordList.add(tbExamRecord);
        }
        // 成绩更新操作
        tbAnswerService.updateBatchById(tbAnswerList);
        tbExamRecordService.updateBatchById(willUpdateRecordList);

        // 成绩核对
        List<TBExamRecord> verifyExamRecordList = tbExamRecordService.list(new QueryWrapper<TBExamRecord>().lambda().eq(TBExamRecord::getExamId, examId).eq(TBExamRecord::getPaperId, paperId));
        for (TBExamRecord verifyRecord : verifyExamRecordList) {
            BigDecimal totalScore = verifyRecord.getTotalScore();
            Long examRecordId = verifyRecord.getId();
            List<TBAnswer> oneStudentAnswer = tbAnswerService.list(new QueryWrapper<TBAnswer>().lambda().eq(TBAnswer::getExamRecordId, examRecordId));
            if (oneStudentAnswer.size() == 0 && totalScore.compareTo(BigDecimal.ZERO) != 0) {
                throw ExceptionResultEnum.ERROR.exception("计算数据异常");
            } else {
                double scoreSum = oneStudentAnswer.stream().collect(Collectors.summarizingDouble(e -> e.getScore().doubleValue())).getSum();
                if (totalScore.compareTo(BigDecimal.valueOf(scoreSum)) != 0) {
                    System.out.println("考试总分 ： " + totalScore + ",作答总分 ： " + scoreSum);
                    throw ExceptionResultEnum.ERROR.exception("考试总分和作答总分不一致");
                }
            }
        }

        return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
    }

    @ApiOperation(value = "留学生异常处理")
    @RequestMapping(value = "/exception_student/dispose", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result exceptionStudentDispose(@RequestParam String schoolId, @RequestParam String examId, @RequestParam String courseCode) {

        String courseName = basicCourseService.findByCourseCode(courseCode, SystemConstant.convertIdToLong(schoolId)).getName();
        if (tbExamCourseService.verifyExamCourseCantRun(SystemConstant.convertIdToLong(examId), SystemConstant.convertIdToLong(schoolId), courseCode, courseName)) {
            throw ExceptionResultEnum.ERROR.exception("课程编号[" + courseCode + "]的课程分析数据已测试或发布，不能变更基础数据");
        }
        // 查找留学生
        List<TAExamCourseRecord> taExamCourseRecordList = taExamCourseRecordService.list(new QueryWrapper<TAExamCourseRecord>().lambda()
                .eq(TAExamCourseRecord::getCourseCode, courseCode)
                .eq(TAExamCourseRecord::getExamId, examId)
                .eq(TAExamCourseRecord::getTotalScore, 0)
                .gt(TAExamCourseRecord::getAssignedScore, 0));
        if (taExamCourseRecordList.size() > 0) {
            List<Long> willDeleteTAExamCourseRecordIds = taExamCourseRecordList.stream().map(TAExamCourseRecord::getId).distinct().collect(Collectors.toList());
            List<String> willDeleteStudentCodeList = taExamCourseRecordList.stream().map(TAExamCourseRecord::getStudentCode).distinct().collect(Collectors.toList());
            List<Long> willDeleteExamRecordIdList = taExamCourseRecordList.stream().map(TAExamCourseRecord::getExamRecordId).distinct().collect(Collectors.toList());

            // 删除‘t_a_exam_course_record’
            taExamCourseRecordService.removeByIds(willDeleteTAExamCourseRecordIds);

            // 删除‘t_b_exam_student’
            if (willDeleteStudentCodeList.size() > 0) {
                tbExamStudentService.remove(new QueryWrapper<TBExamStudent>().lambda().eq(TBExamStudent::getExamId, examId).eq(TBExamStudent::getCourseCode, courseCode).in(TBExamStudent::getStudentCode, willDeleteStudentCodeList).gt(TBExamStudent::getId, 0));
            }

            if (willDeleteExamRecordIdList.size() > 0) {
                // 删除't_b_exam_record'
                tbExamRecordService.removeByIds(willDeleteExamRecordIdList);

                // 删除‘t_b_answer’
                tbAnswerService.remove(new QueryWrapper<TBAnswer>().lambda().in(TBAnswer::getExamRecordId, willDeleteExamRecordIdList).gt(TBAnswer::getId, 0));
            }

        }

        return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
    }

    @ApiOperation(value = "教师用户删除")
    @RequestMapping(value = "/user_teacher/delete", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    @Aac(strict = BOOL.FALSE, auth = BOOL.FALSE)
    public Result userTeacherDelete(@ApiParam(value = "用户id", required = true) @RequestParam List<String> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            throw ExceptionResultEnum.ERROR.exception("请选择要删除的用户");
        }
        Set<Long> idSet = idList.stream().map(SystemConstant::convertIdToLong).collect(Collectors.toSet());
        tbTeacherService.deleteSysUserByIdSet(idSet);
        return ResultUtil.ok();
    }

    @ApiOperation(value = "基础教师导入")
    @RequestMapping(value = "/basic_teacher/import", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    @Aac(strict = BOOL.FALSE, auth = BOOL.FALSE)
    public Result basicTeacherImport(@ApiParam(value = "上传文件", required = true) @RequestParam MultipartFile file,
                                     @ApiParam(value = "学校id", required = true) @RequestParam String schoolId) throws Exception {
        return ResultUtil.ok(tbTeacherService.importBasicTeacherInfo(file, SystemConstant.convertIdToLong(schoolId)));
    }

    @ApiOperation(value = "同步基础教师表数据到用户表")
    @RequestMapping(value = "/sync/teacher", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    @Aac(strict = BOOL.FALSE, auth = BOOL.FALSE)
    public Result syncTeacherInfo(@ApiParam(value = "学校id", required = true) @RequestParam String schoolId) {
        tbTeacherService.syncTeacherInfoToSysUser(SystemConstant.convertIdToLong(schoolId));
        return ResultUtil.ok();
    }

    @ApiOperation(value = "特殊科目赋分检查")
    @RequestMapping(value = "/special/assignCheck", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    @Aac(strict = BOOL.FALSE, auth = BOOL.FALSE)
    public Result assignCheck(@ApiParam(value = "上传文件", required = true) @RequestParam MultipartFile file, @RequestParam Long examId, @RequestParam Long schoolId,
                              @ApiParam(value = "该Excel中包含多科目赋分时，各科目编号用','隔开", required = true) @RequestParam String courseCodeS) throws IOException, NoSuchFieldException {

        int count = 0;
        List<AssignCheckDto> result = new ArrayList<>();
        List<String> courseCodeList = Arrays.asList(courseCodeS.split(","));
        // 数据同步操作
        // 获取当前课程下所有学生考试成绩记录
        List<BasicExamRecordDto> basicExamRecordDtoDatasource = tbExamRecordService.findByExamIdAndCourseCodeS(examId, courseCodeList);
        Set<TAExamCourseRecord> taExamCourseRecordDatasource = new HashSet<>();
        for (String s : courseCodeList) {
            taExamCourseRecordDatasource.addAll(taExamCourseRecordService.list(new QueryWrapper<TAExamCourseRecord>()
                    .lambda().eq(TAExamCourseRecord::getExamId, examId).eq(TAExamCourseRecord::getCourseCode, s)));
        }


        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(file.getInputStream(), Lists.newArrayList(AssignCheckDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
            if (finalExcelErrorList.size() > 0) {
                throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(finalExcelErrorList));
            }
            return finalExcelList;
        });

        //保存到数据库
        if (Objects.nonNull(finalList) && finalList.size() > 0) {
            for (int i = 0; i < finalList.size(); i++) {
                LinkedMultiValueMap<Integer, Object> map = finalList.get(i);
                List<Object> assignCheckList = map.get(i);
                for (int y = 0; y < Objects.requireNonNull(assignCheckList).size(); y++) {
                    if (assignCheckList.get(y) instanceof AssignCheckDto) {
                        AssignCheckDto assignCheckDto = (AssignCheckDto) assignCheckList.get(y);
                        Long assExamId = Long.parseLong(assignCheckDto.getExamId());
                        if (!examId.equals(assExamId)) {
                            throw ExceptionResultEnum.ERROR.exception("excel考试数据异常");
                        }
                        String assCourseCodeS = assignCheckDto.getPaperCodeS();
                        String assStudentCode = assignCheckDto.getStudentCode();
                        String assAssignScore = assignCheckDto.getAssignScore();
                        String assStudentName = assignCheckDto.getStudentName();
                        String[] courseCodeArr = assCourseCodeS.split(",");
                        for (String s : courseCodeArr) {
                            List<TAExamCourseRecord> taExamCourseRecordList = taExamCourseRecordDatasource.stream()
                                    .filter(e -> assExamId.equals(e.getExamId()) && s.equals(e.getCourseCode()) && assStudentCode.equals(e.getStudentCode()))
                                    .collect(Collectors.toList());
                            if (taExamCourseRecordList.size() != 1) {
                                if (taExamCourseRecordList.size() < 1) {
                                    continue;
                                }
                                System.out.println("-----------------------");
                                System.out.println(JSON.toJSONString(taExamCourseRecordList));
                                throw ExceptionResultEnum.ERROR.exception("赋分异常,考生记录分析表数据异常");
                            }
                            TAExamCourseRecord taExamCourseRecord = taExamCourseRecordList.get(0);
                            TBStudent tbStudent = tbStudentService.getById(taExamCourseRecord.getStudentId());
                            if (!assStudentName.equals(tbStudent.getName())) {
                                result.add(assignCheckDto);
                            } else {
                                count++;
                            }
                        }
                    }
                }
            }
        }
        System.out.println(JSON.toJSONString(result));

        return ResultUtil.ok(result.size() == 0 ? count : result);
    }

    @ApiOperation(value = "制作演示数据表")
    @RequestMapping(value = "/build/demo_table", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    @Aac(strict = BOOL.FALSE, auth = BOOL.FALSE)
    public Result buildDemoTable() throws ExecutionException, InterruptedException {
        courseUnitOperateService.createDemoData();
        return ResultUtil.ok();
    }

    @ApiOperation(value = "将考察学院数据迁移至开课学院")
    @RequestMapping(value = "/build/migrate_org", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    @Aac(strict = BOOL.FALSE, auth = BOOL.FALSE)
    public Result migrateOrg(@Valid @RequestBody List<CollegeCombineParams> collegeCombineParamsListList, BindingResult bindingResult){
        if (bindingResult.hasErrors()) {
            return ResultUtil.error(bindingResult.getAllErrors().get(0).getDefaultMessage());
        }
        Long schoolId = SystemConstant.convertIdToLong(String.valueOf(ServletUtil.getRequestHeaderSchoolId()));
        courseUnitOperateService.combineCollegeInspectToTeach(schoolId,collegeCombineParamsListList);
        return ResultUtil.ok();
    }

    /**
     * 更新或新增专业信息
     *
     * @param tbSchoolMajorDtoList 基础专业数据源
     */
    private void saveMajorInfo(List<TBSchoolMajorDto> tbSchoolMajorDtoList) {
        List<TBSchoolMajor> tbSchoolMajorList = new ArrayList<>();
        for (TBSchoolMajorDto tbSchoolMajorDto : tbSchoolMajorDtoList) {
            TBSchoolMajor old = tbSchoolMajorService.getOne(new QueryWrapper<TBSchoolMajor>().lambda()
                    .eq(TBSchoolMajor::getSchoolId, tbSchoolMajorDto.getSchoolId())
                    .eq(TBSchoolMajor::getMajorCode, tbSchoolMajorDto.getMajorCode())
                    .eq(TBSchoolMajor::getMajorName, tbSchoolMajorDto.getMajorName()));
            Long id;
            if (Objects.nonNull(old)) {
                id = old.getId();
            } else {
                id = SystemConstant.getDbUuid();
            }

            TBSchoolMajor tbSchoolMajor = new TBSchoolMajor();
            tbSchoolMajor.setId(id);
            tbSchoolMajor.setSchoolId(tbSchoolMajorDto.getSchoolId());
            tbSchoolMajor.setMajorCode(tbSchoolMajorDto.getMajorCode());
            tbSchoolMajor.setMajorName(tbSchoolMajorDto.getMajorName());
            tbSchoolMajor.setEnable(true);
            tbSchoolMajor.setCreateTime(System.currentTimeMillis());
            tbSchoolMajor.setUpdateTime(System.currentTimeMillis());
            tbSchoolMajorList.add(tbSchoolMajor);
        }
        tbSchoolMajorService.saveOrUpdateBatch(tbSchoolMajorList);
    }

    /**
     * 更新或新增班级信息
     *
     * @param tbSchoolClazzDtoList 基础班级数据源
     */
    private void saveClazzInfo(List<TBSchoolClazzDto> tbSchoolClazzDtoList) {
        List<TBSchoolClazz> tbSchoolClazzList = new ArrayList<>();
        for (TBSchoolClazzDto tbSchoolClazzDto : tbSchoolClazzDtoList) {
            TBSchoolClazz old = tbSchoolClazzService.getOne(new QueryWrapper<TBSchoolClazz>().lambda()
                    .eq(TBSchoolClazz::getSchoolId, tbSchoolClazzDto.getSchoolId())
                    .eq(TBSchoolClazz::getClazzCode, tbSchoolClazzDto.getClazzCode())
                    .eq(TBSchoolClazz::getClazzName, tbSchoolClazzDto.getClazzName()));
            Long id;
            if (Objects.nonNull(old)) {
                id = old.getId();
            } else {
                id = SystemConstant.getDbUuid();
            }

            TBSchoolClazz tbSchoolClazz = new TBSchoolClazz();
            tbSchoolClazz.setId(id);
            tbSchoolClazz.setSchoolId(tbSchoolClazzDto.getSchoolId());
            tbSchoolClazz.setClazzCode(tbSchoolClazzDto.getClazzCode());
            tbSchoolClazz.setClazzName(tbSchoolClazzDto.getClazzName());
            tbSchoolClazz.setEnable(true);
            tbSchoolClazz.setCreateTime(System.currentTimeMillis());
            tbSchoolClazz.setUpdateTime(System.currentTimeMillis());
            tbSchoolClazzList.add(tbSchoolClazz);
        }
        tbSchoolClazzService.saveOrUpdateBatch(tbSchoolClazzList);
    }

    /**
     * 更新或新增学院信息
     *
     * @param tbSchoolCollegeDtoList 基础学院数据源
     */
    private void saveCollegeInfo(List<TBSchoolCollegeDto> tbSchoolCollegeDtoList) {
        for (TBSchoolCollegeDto tbSchoolCollegeDto : tbSchoolCollegeDtoList) {
            sysOrgService.searchOrInsert(tbSchoolCollegeDto.getSchoolId(), tbSchoolCollegeDto.getCollegeName());
        }
    }

    /**
     * 更新或新增教师信息
     *
     * @param tbSchoolTeacherDtoList 基础教师数据源
     */
    private void saveTeacherInfo(List<TBSchoolTeacherDto> tbSchoolTeacherDtoList) {
        Map<String, String> checkMap = new HashMap<>();
        for (TBSchoolTeacherDto tbSchoolTeacherDto : tbSchoolTeacherDtoList) {
            if (checkMap.containsKey(tbSchoolTeacherDto.getTeacherCode())) {
                continue;
            }
            SysUser old = sysUserService.getOne(new QueryWrapper<SysUser>().lambda()
                    .eq(SysUser::getSchoolId, tbSchoolTeacherDto.getSchoolId())
                    .eq(SysUser::getLoginName, tbSchoolTeacherDto.getTeacherCode())
                    .eq(SysUser::getRealName, tbSchoolTeacherDto.getTeacherName()));
            checkMap.put(tbSchoolTeacherDto.getTeacherCode(), tbSchoolTeacherDto.getTeacherName());
            Long id = 0L;
            if (Objects.nonNull(old)) {
                id = old.getId();
            }

            SysRole teacherRole = sysRoleService.list(new QueryWrapper<SysRole>().lambda().eq(SysRole::getType, RoleTypeEnum.TEACHER)).get(0);
            List<Long> roleIds = new ArrayList<>();
            roleIds.add(teacherRole.getId());

            UserSaveParams userSaveParams = new UserSaveParams();
            if (id > 0) {
                userSaveParams.setId(id);
            }


            userSaveParams.setSchoolId(tbSchoolTeacherDto.getSchoolId());
            userSaveParams.setLoginName(tbSchoolTeacherDto.getTeacherCode());
            userSaveParams.setRealName(tbSchoolTeacherDto.getTeacherName());
            userSaveParams.setPassword(SystemConstant.DEFAULT_PASSWORD);
            userSaveParams.setOrgId(tbSchoolTeacherDto.getOrgId());
            userSaveParams.setEnable(true);
            userSaveParams.setRoleIds(roleIds.toArray(new Long[0]));
            sysUserService.saveUserNoAuth(userSaveParams);
        }
    }

    /**
     * 由于不同大学的教师数据在云阅卷中出现了不同的储存样式，为了解决这种问题进行统一处理
     * 1.武汉大学：教师名称A
     * 2.山东师范大学：教师编号A/教师名称A;教师编号B/教师名称B......
     * 将教师信息统一处理成如下格式：
     * teacherCode(教师编号)：教师编号A;教师编号B......
     * teacherName(教师名称)：教师名称A:教师名称B......
     *
     * @param teacherInfo 教师信息
     * @return 键值对
     */
    private Map<String, String> disposeTeacherInfo(String teacherInfo) {
        StringBuilder teacherName = new StringBuilder();
        StringBuilder teacherCode = new StringBuilder();
        teacherInfo = teacherInfo.trim().replaceAll("；", ";").replaceAll("\\\\", "/");
        String[] teacherInfoArr = teacherInfo.split(";");
        for (String teacher : teacherInfoArr) {
            String cellName = "";
            String cellCode = "";
            String[] cellArr = teacher.split("/");
            if (cellArr.length == 1) {
                cellName = cellArr[0];
            } else if (cellArr.length == 2) {
                cellCode = cellArr[0];
                cellName = cellArr[1];
            } else {
                System.out.println("error");
            }
            if (SystemConstant.strNotNull(cellName)) {
                teacherName.append(cellName).append(";");
            }
            if (SystemConstant.strNotNull(cellCode)) {
                teacherCode.append(cellCode).append(";");
            }
        }
        if (SystemConstant.strNotNull(teacherName.toString())) {
            teacherName = new StringBuilder(teacherName.substring(0, teacherName.length() - 1));
        }
        if (SystemConstant.strNotNull(teacherCode.toString())) {
            teacherCode = new StringBuilder(teacherCode.substring(0, teacherCode.length() - 1));
        }

        Map<String, String> map = new HashMap<>();
        map.put("teacherName", teacherName.toString());
        map.put("teacherCode", teacherCode.toString());
        return map;
    }
}
