package jnpf.cultivate.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import jnpf.cultivate.mapper.*;
import jnpf.cultivate.service.*;
import jnpf.cultivate.utils.HistoryPaperUtils;
import jnpf.cultivate.utils.QuestionExcelExportUtil;
import jnpf.cultivate.utils.UserApiV2Util;
import jnpf.cultivate.utils.UserExamUtil;
import jnpf.enums.cultivate.ExamQuestionShuffleEnum;
import jnpf.enums.cultivate.ExamRetakeFrequencyEnum;
import jnpf.model.cultivate.po.exam.FtbCultivateExam;
import jnpf.model.cultivate.po.exam.FtbCultivateExamHistoryPaper;
import jnpf.model.cultivate.po.exam.FtbCultivateExamUser;
import jnpf.model.cultivate.po.learn.FtbCultivateLearnTask;
import jnpf.model.cultivate.po.learn.FtbCultivateLearnTaskExam;
import jnpf.model.cultivate.po.learn.FtbCultivateLearnTaskIdentification;
import jnpf.model.cultivate.po.paper.FtbCultivateTestPaper;
import jnpf.model.cultivate.po.paper.FtbCultivateTestPaperQuestion;
import jnpf.model.cultivate.po.position.FtbCultivatePosition;
import jnpf.model.cultivate.po.position.FtbCultivatePositionCourseExam;
import jnpf.model.cultivate.po.position.FtbCultivatePositionExam;
import jnpf.model.cultivate.po.question.FtbCultivateQuestion;
import jnpf.model.cultivate.po.question.FtbCultivateQuestionOption;
import jnpf.model.cultivate.req.exam.QueryExamReq;
import jnpf.model.cultivate.req.exam.ReviewerAppointDto;
import jnpf.model.cultivate.req.exam.SaveExamReq;
import jnpf.model.cultivate.req.exam.WebQueryExamReadOverReq;
import jnpf.model.cultivate.req.paper.PaperConfigReq;
import jnpf.model.cultivate.resp.*;
import jnpf.model.enums.*;
import jnpf.model.personnels.dto.authoritys.PermissionsCacheDTO;
import jnpf.model.personnels.dto.staff.roster.WorkerGroupDataDto;
import jnpf.model.personnels.po.FtbPersonnelsStaffRoster;
import jnpf.permission.RoleApi;
import jnpf.permission.UserApi;
import jnpf.permission.entity.RoleEntity;
import jnpf.permission.entity.UserEntity;
import jnpf.permission.vo.v2.position.PositionAndGradesVO;
import jnpf.permission.vo.v2.position.PositionVO;
import jnpf.permission.vo.v2.user.UserBoundVO;
import jnpf.personnels.utils.PersonnelPerUtils;
import jnpf.util.QuestionAnalysisUtil;
import jnpf.util.SelfGrowthUtil;
import jnpf.util.UploaderUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class FtbCultivateExamServiceImpl extends ServiceImpl<FtbCultivateExamMapper, FtbCultivateExam> implements FtbCultivateExamService {

    @Autowired
    private UserApi userApi;

    @Autowired
    private UserApiV2Util userApiV2Util;

    @Autowired
    private RoleApi roleApi;


    @Autowired
    private PersonnelPerUtils personnelPerUtils;
    /**
     * 考试用户服务
     */

    @Autowired
    private FtbCultivateExamUserService examUserService;

    /**
     * 试卷服务
     */
    @Autowired
    private FtbCultivateTestPaperService paperService;

    /**
     * 岗位学习和考试关联表
     */
    @Autowired
    private FtbCultivatePositionExamService positionExamService;
    /**
     * 题目选项服务
     */
    @Autowired
    FtbCultivateQuestionOptionService questionOptionService;

    /**
     * 岗位学习课程 考试 关联表
     */
    @Autowired
    private FtbCultivatePositionCourseExamService positionCourseExamService;

    @Autowired
    private FtbCultivatePositionExamMapper ftbCultivatePositionExamMapper;
    @Autowired
    private FtbCultivatePositionCourseExamMapper ftbCultivatePositionCourseExamMapper;

    @Autowired
    private FtbCultivatePositionMapper ftbCultivatePositionMapper;

    @Autowired
    private FtbCultivateExamHistoryPaperService ftbCultivateExamHistoryPaperService;

    @Autowired
    private UserExamUtil userExamUtil;

    @Autowired
    private FtbCultivateExamService examService;

    @Autowired
    private FtbCultivateQuestionService questionService;

    @Autowired
    private FtbCultivateLearnTaskExamMapper ftbCultivateLearnTaskExamMapper;


    @Autowired
    private FtbCultivateLearnTaskInfoContentService ftbCultivateLearnTaskInfoContentService;

    @Autowired
    private FtbCultivateLearnTaskIdentificationMapper learnTaskIdentificationMapper;

    private final static String DEFAULT_VERSION_BATCH = "dfa";

    /**
     * 根据试卷ID查询考试列表
     *
     * @param paperId 试卷ID
     * @return
     */
    @Override
    public List<ExamVo> queryExamListByPaperId(String paperId) {
        QueryWrapper<FtbCultivateExam> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(FtbCultivateExam::getPaperId, paperId).eq(FtbCultivateExam::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        List<FtbCultivateExam> list = baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(list)) {
            return CollectionUtil.newArrayList();
        }
        return BeanUtil.copyToList(list, ExamVo.class);
    }

    /**
     * 分页查询考试列表
     *
     * @param req
     * @return
     */
    @Override
    public PageInfo<ExamListVo> getPageList(QueryExamReq req) {
        if (StringUtils.isNotEmpty(req.getKeyword())) {
            req.setKeyword(StringUtils.trim(req.getKeyword()));
        }
        //构建分页
        Page<FtbCultivateExam> page = Page.of(req.getCurrentPage(), req.getPageSize());
        Page<ExamListVo> queryPage = baseMapper.pagingQuery(page, req);
        List<ExamListVo> records = queryPage.getRecords();
        if (CollectionUtil.isNotEmpty(records)) {
            for (ExamListVo record : records) {
                //填充考试的用户统计数据
                fillExamUserData(record);
                fillNeedPassScore(record);
                checkExamExpire(record);
            }
        }
        //构建分页返回数据
        PageInfo<ExamListVo> pageInfo = new PageInfo<>();
        pageInfo.setList(records);
        pageInfo.setPageSize((int) queryPage.getSize());
        pageInfo.setPageNum((int) queryPage.getCurrent());
        pageInfo.setTotal((int) queryPage.getTotal());
        return pageInfo;
    }

    /**
     * 检测并修改考试状态
     *
     * @param record
     */
    private void checkExamExpire(ExamListVo record) {
        if (record.getExamType() == 1 && record.getStatus() != 3) {
            if (record.getStartTime() != null && record.getEndTime() != null) {
                Date now = new Date();
                if (now.before(record.getStartTime())) {
                    record.setStatus(CourseEnums.ExamTimeStatus.NOT_STARTED.getCode());
                } else if (now.after(record.getEndTime())) {
                    record.setStatus(CourseEnums.ExamTimeStatus.DONE.getCode());
                    record.setNeedUpdate(ExamUpdateStatus.NO_UPDATE.getCode());
                } else if (now.after(record.getStartTime()) && now.before(record.getEndTime())) {
                    record.setStatus(CourseEnums.ExamTimeStatus.IN_PROGRESS.getCode());
                }
            } else {
                record.setStatus(CourseEnums.ExamTimeStatus.IN_PROGRESS.getCode());
            }
        }
    }

    private void fillNeedPassScore(ExamListVo vo) {
        FtbCultivateTestPaper paper = null;
        if (StringUtils.isNotEmpty(vo.getPaperInfo())) {
            paper = JSONUtil.toBean(vo.getPaperInfo(), FtbCultivateTestPaper.class);
        } else {
            paper = paperService.getById(vo.getPaperId());
        }
        if (paper == null) {
            return;
        }
        //计算用户需要考多少分才及格
        int needScore = 0;
        Integer passType = vo.getPassType();//合格分数类型（1固定分，2百分比)
        Integer passMark = vo.getPassMark();//合格分数
        if (CourseEnums.ExamScoreCheckType.FIXED.getCode().equals(passType)) {
            needScore = passMark;
        } else {
            needScore = QuestionAnalysisUtil.calculateScore(passMark, paper.getTotalScore());
        }
        vo.setNeedExamPassScore(needScore);


        //计算用户需要考多少分才优秀
        int needExcellentScore = 0;
        Integer excellentType = vo.getExcellentType();//优秀分数类型（1固定分，2百分比)
        Integer excellentMark = vo.getExcellentMark();//优秀分数
        if (CourseEnums.ExamScoreCheckType.FIXED.getCode().equals(excellentType)) {
            needExcellentScore = excellentMark;
        } else {
            needExcellentScore = QuestionAnalysisUtil.calculateScore(excellentMark, paper.getTotalScore());
        }
        vo.setNeedExamExcellentScore(needExcellentScore);
    }

    /**
     * 查询所有批阅角色
     *
     * @return
     */
    @Override
    public List<ReviewerRole> queryRoleReviewerList() {
        List<RoleEntity> listAll = roleApi.getListAll();
        if (CollectionUtil.isEmpty(listAll)) {
            return new ArrayList<>();
        }
        return BeanUtil.copyToList(listAll, ReviewerRole.class);
    }

    @Override
    public PaperVo queryPaperInfoForExamId(String examId) {
        //1、查询考试信息
        FtbCultivateExam exam = queryExamInfo(examId);
        //2、查询试卷信息
        FtbCultivateTestPaper paper = queryPaper(exam.getPaperId());

        return BeanUtil.copyProperties(paper, PaperVo.class);
    }

    /**
     * 根据考试ID列表 查询试卷信息
     *
     * @param examIds 考试ID列表
     * @return examId -> PaperVo 的map
     */
    @Override
    public Map<String, PaperVo> queryPaperInfoForExamIds(List<String> examIds) {
        //1、查询考试信息
        List<FtbCultivateExam> examList = queryExamListForExamIds(examIds);
        if (CollectionUtil.isEmpty(examList)) {
            return new HashMap<>();
        }
        //2、查询试卷信息
        List<String> paperIds = examList.stream().map(FtbCultivateExam::getPaperId).collect(Collectors.toList());

        List<FtbCultivateTestPaper> paperList = queryPaperInfoForPaperId(paperIds);
        //考试ID->vo map
        Map<String, PaperVo> examPaperVoMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(paperList)) {
            //试卷id->vo map
            Map<String, PaperVo> paperVoMap = paperList.stream().collect(Collectors.toMap(FtbCultivateTestPaper::getId, paper -> BeanUtil.copyProperties(paper, PaperVo.class)));
            for (FtbCultivateExam exam : examList) {
                examPaperVoMap.put(exam.getId(), paperVoMap.get(exam.getPaperId()));
            }
        }
        return examPaperVoMap;
    }

    /**
     * 根据考试id列表查询考试信息
     *
     * @param examIds 考试ID列表
     * @return
     */
    private List<FtbCultivateExam> queryExamListForExamIds(List<String> examIds) {
        List<FtbCultivateExam> examList = baseMapper.selectList(Wrappers.lambdaQuery(FtbCultivateExam.class).in(FtbCultivateExam::getId, examIds).eq(FtbCultivateExam::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode()));
        if (CollectionUtil.isEmpty(examList)) {
            return Collections.emptyList();
        }
        return examList;
    }

    /**
     * 根据试卷ID查询试卷信息
     *
     * @param paperIds 试卷ID列表
     * @return
     */
    private List<FtbCultivateTestPaper> queryPaperInfoForPaperId(List<String> paperIds) {
        List<FtbCultivateTestPaper> paperList = paperService.list(Wrappers.lambdaQuery(FtbCultivateTestPaper.class).in(FtbCultivateTestPaper::getId, paperIds).eq(FtbCultivateTestPaper::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode()));
        if (CollectionUtil.isEmpty(paperList)) {
            return Collections.emptyList();
        }
        return paperList;
    }

    /**
     * 根据考试ID批量查询考试信息和考试试卷信息
     *
     * @param examIds
     * @return
     */
    @Override
    public List<AppExamVo> queryExamAndPaperInfo(List<String> examIds) {
        //1、查询考试列表
        List<FtbCultivateExam> examList = queryExamListForExamIds(examIds);
        if (CollectionUtil.isEmpty(examList)) {
            return Collections.emptyList();
        }
        //2、查询试卷信息
        List<String> paperIds = examList.stream().map(FtbCultivateExam::getPaperId).collect(Collectors.toList());
        List<AppExamVo> appExamVoList = BeanUtil.copyToList(examList, AppExamVo.class);
        if (CollectionUtil.isNotEmpty(paperIds)) {
            List<FtbCultivateTestPaper> testPaperList = queryPaperInfoForPaperId(paperIds);
            //试卷id->vo map
            Map<String, PaperVo> paperVoMap = testPaperList.stream().collect(Collectors.toMap(FtbCultivateTestPaper::getId, paper -> BeanUtil.copyProperties(paper, PaperVo.class)));
            for (AppExamVo appExamVo : appExamVoList) {
                appExamVo.setPaperVo(paperVoMap.get(appExamVo.getPaperId()));
            }
        }
        return appExamVoList;
    }

    /**
     * 填充考试的用户统计数据
     *
     * @param vo
     */
    private void fillExamUserData(ExamListVo vo) {
        //查询考试的用户
        QueryWrapper<FtbCultivateExamUser> wrapper = new QueryWrapper<>();
        wrapper.lambda().select(FtbCultivateExamUser::getId, FtbCultivateExamUser::getStatus, FtbCultivateExamUser::getUserId, FtbCultivateExamUser::getExamId, FtbCultivateExamUser::getExamSource, FtbCultivateExamUser::getRelationCourseExamId, FtbCultivateExamUser::getRelationPositionExamId, FtbCultivateExamUser::getRelationRankId).eq(FtbCultivateExamUser::getExamId, vo.getId()).eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        List<FtbCultivateExamUser> examUserList = examUserService.list(wrapper);
        if (CollectionUtil.isEmpty(examUserList)) {
            return;
        }
        UserExamCount userExamCount = QuestionAnalysisUtil.countPassAndTotleExamNum(examUserList);
        vo.setParticipantsNum(userExamCount.getTotleNum());
        vo.setEligibleNum(userExamCount.getPassTotleNum());
        vo.setNoEligibleNum(userExamCount.getNoPassNum());
        vo.setWaitNum(userExamCount.getWaitNum());
    }

    /**
     * 填充试卷的题目数量和总分数
     *
     * @param vo
     */
    private void fillPaperData(ExamListVo vo) {
        String paperId = vo.getPaperId();
        FtbCultivateTestPaper paper = paperService.getById(paperId);
        if (null != paper) {
            vo.setQuestionNum(paper.getQuestionNumber());
            vo.setTotleScore(paper.getTotalScore());
        }
    }

    /**
     * 查询考试详情
     *
     * @param examId 考试ID
     * @return
     */
    @Override
    public ExamVo getInfo(String examId) {
        //1、查询和检测试卷是否存在
        FtbCultivateExam exam = queryExamInfo(examId);
        ExamVo examVo = convertExamVo(exam);
        if (StringUtils.isNotEmpty(exam.getPaperId())) {
            FtbCultivateTestPaper paper = paperService.getById(exam.getPaperId());
            if (null == paper || paper.getEnabledMark() == CourseEnums.EnabledMarkType.INVALID.getCode()) {
                examVo.setPaperDeleteStatus(CourseEnums.EnabledMarkType.INVALID.getCode());
            }
            examVo.setPaperNeedUpdate(paper.getNeedUpdate());

        }
        return examVo;
    }

    /**
     * 转换考试对象
     *
     * @param exam
     * @return
     */
    private ExamVo convertExamVo(FtbCultivateExam exam) {
        ExamVo vo = new ExamVo();
        vo.setId(exam.getId());
        vo.setExamId(exam.getExamId());
        vo.setExamTime(exam.getExamTime());
        vo.setPassType(exam.getPassType());
        vo.setPassMark(exam.getPassMark());
        vo.setExcellentType(exam.getExcellentType());
        vo.setExcellentMark(exam.getExcellentMark());
        vo.setStartTime(exam.getStartTime());
        vo.setEndTime(exam.getEndTime());
        vo.setPaperId(exam.getPaperId());
        vo.setExamName(exam.getExamName());
        vo.setPostRankId(exam.getPostRankId());
        vo.setPostId(exam.getPostId());
        vo.setExamlimitation(exam.getExamlimitation());
        vo.setStatus(exam.getStatus());
        vo.setReviewer(exam.getReviewer());
        vo.setReviewerRole(exam.getReviewerRole());
        vo.setReviewerAppoint(exam.getReviewerAppoint());
        vo.setExamMemberId(exam.getExamMemberId());
        vo.setDescription(exam.getDescription());
        vo.setExamType(exam.getExamType());
        vo.setVersionBatch(exam.getVersionBatch());
        vo.setNeedUpdate(exam.getNeedUpdate());


        if (StringUtils.isNotEmpty(exam.getPostId())) {
            List<String> positionIdList = List.of(exam.getPostId().split(","));
            List<PositionVO> positionEntityList = userExamUtil.getPostInfoList(positionIdList);
            List<PostAndPosition> postAndPositionList = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(positionEntityList)) {
                for (PositionVO positionEntity : positionEntityList) {
                    PostAndPosition postAndPosition = new PostAndPosition();
                    postAndPosition.setId(positionEntity.getId());
                    postAndPosition.setEnCode(positionEntity.getEnCode());
                    postAndPosition.setPostName(positionEntity.getFullName());
                    postAndPositionList.add(postAndPosition);
                }
            }
            vo.setPostAndPositionList(postAndPositionList);
        }

        List<String> userIdList = new ArrayList<>();
        if (StringUtils.isNotEmpty(exam.getExamMemberId())) {
            userIdList.addAll(Arrays.asList(exam.getExamMemberId().split(",")));
        }
        //查询批阅人信息
        if (StringUtils.isNotEmpty(exam.getReviewerAppoint())) {
            userIdList.addAll(Arrays.asList(exam.getReviewerAppoint().split(",")));
        }
        Map<String, UserEntity> userMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(userIdList)) {
            userMap = userApiV2Util.getUserNameForUserIds(userIdList);
        }
        //处理考试用户信息 回显
        if (StringUtils.isNotEmpty(exam.getExamMemberId())) {
            //MemberId转list
            String[] split = exam.getExamMemberId().split(",");
            List<ExamBaseUser> examBaseUserList = new ArrayList<>();
            //获取用户信息
            for (int i = 0; i < split.length; i++) {
                String userId = split[i];
                UserEntity userEntity = userMap.get(userId);
                if (userEntity != null) {
                    ExamBaseUser examBaseUser = new ExamBaseUser();
                    examBaseUser.setUserId(userEntity.getId());
                    examBaseUser.setUserName(userEntity.getRealName());
                    examBaseUser.setHeadLogo(UploaderUtil.uploaderImg(userEntity.getHeadIcon()));
                    examBaseUserList.add(examBaseUser);
                }
            }
            vo.setExamUserList(examBaseUserList);
        }

        //回显批阅人
        if (StringUtils.isNotEmpty(exam.getReviewerAppoint())) {
            //MemberId转list
            String[] split = exam.getReviewerAppoint().split(",");
            List<ExamBaseUser> reviewerList = new ArrayList<>();
            //获取用户信息
            for (int i = 0; i < split.length; i++) {
                String userId = split[i];
                UserEntity userEntity = userMap.get(userId);
                if (userEntity != null) {
                    ExamBaseUser examBaseUser = new ExamBaseUser();
                    examBaseUser.setUserId(userEntity.getId());
                    examBaseUser.setUserName(userEntity.getRealName());
                    examBaseUser.setHeadLogo(UploaderUtil.uploaderImg(userEntity.getHeadIcon()));
                    reviewerList.add(examBaseUser);
                }
            }
            vo.setReviewerAppointList(reviewerList);
        }


        if (StringUtils.isNotEmpty(exam.getReviewerAppointListConfig())) {
            vo.setReviewerAppointListConfig(exam.getReviewerAppointListConfig());
        } else {
            vo.setReviewerAppointListConfig("");
        }
        //考试配置
        vo.setMakeUpCount(exam.getMakeUpCount());
        vo.setWaterMark(exam.getWaterMark());
        vo.setCutScreen(exam.getCutScreen());
        vo.setMaxCutScreenCount(exam.getMaxCutScreenCount());
        vo.setScreenshot(exam.getScreenshot());
        vo.setCopyAndPaste(exam.getCopyAndPaste());
        vo.setOpenOverTime(exam.getOpenOverTime());
        vo.setOverTime(exam.getOverTime());
        vo.setAllowSelectDetail(exam.getAllowSelectDetail());
        vo.setAllowChangeLastQuestion(exam.getAllowChangeLastQuestion());
        vo.setReExamFrequencyType(exam.getReExamFrequencyType());
        vo.setReExamFrequencyNum(exam.getReExamFrequencyNum());
        vo.setExamQuestionRandom(exam.getExamQuestionRandom());
        return vo;

    }

    /**
     * 新增考试
     *
     * @param req
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertData(SaveExamReq req) {
        CourseEnums.ExamType examType = CourseEnums.ExamType.fromCode(req.getExamType());
        List<String> examUserList = new ArrayList<>();
        Map<String, String> defaultPowerReviewer = new HashMap<>(); //userid->
        Map<String, FtbPersonnelsStaffRoster> rosterMap = new HashMap<>();//userid->
        Map<String, List<WorkerGroupDataDto>> userOrgMap = new HashMap<>();//userid->
        checkExamCommonParam(req);
        if (CourseEnums.ExamType.BASE == examType) {
            if (StringUtils.isEmpty(req.getExamMemberId())) {
                throw new RuntimeException("考试用户不能为空");
            }
            examUserList = QuestionExcelExportUtil.stringToList(req.getExamMemberId(), ",");
            rosterMap = userExamUtil.queryRosterSimpleInfo(examUserList);
            userOrgMap = userExamUtil.getUserOrgBoundInfoForUserList(examUserList);
        }
        //检测名称是否重复
        QueryWrapper<FtbCultivateExam> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(FtbCultivateExam::getExamName, req.getExamName()).eq(FtbCultivateExam::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        Long count = baseMapper.selectCount(wrapper);
        if (null != count && count > 0) {
            throw new RuntimeException("考试名称已经存在");
        }
        //1、添加考试
        //1.1根据试卷ID查询试卷信息
        FtbCultivateTestPaper paper = queryPaper(req.getPaperId());
        if (CourseEnums.DraftStatus.YES.getCode().equals(paper.getIsDraft())) {
            throw new RuntimeException("试卷未定稿,不能绑定考试");
        }
        if (ExamUpdateStatus.NEED_UPDATE.getCode().equals(paper.getNeedUpdate())) {
            throw new RuntimeException("试卷异常,请先编辑试卷");
        }
        FtbCultivateExam updateExam = new FtbCultivateExam();
        checkParamAndFillExam(req, updateExam);
        updateExam.setExamName(req.getExamName());
        updateExam.setPaperId(req.getPaperId());
        updateExam.setPaperName(paper.getName());
        updateExam.setPaperInfo(JSONUtil.toJsonStr(paper));
        updateExam.setVersionBatch(DEFAULT_VERSION_BATCH);
        if (CourseEnums.ExamType.POSITION == examType) {
            if (CollectionUtil.isEmpty(req.getPostAndPositionList())) {
                throw new RuntimeException("请选择考试岗位");
            }
            updateExam.setPostRankConf(JSONUtil.toJsonStr(req.getPostAndPositionList()));
            List<String> postIdsList = new ArrayList<>();//岗位ID集合
            for (PostAndPosition postAndPosition : req.getPostAndPositionList()) {
                postIdsList.add(postAndPosition.getId());
            }
            updateExam.setPostId(String.join(",", postIdsList));
        } else {
            updateExam.setPostRankConf("");
            updateExam.setPostId("");
        }
        updateExam.setPassType(req.getPassType());
        updateExam.setPassMark(req.getPassMark());
        updateExam.setExcellentType(req.getExcellentType());
        updateExam.setExcellentMark(req.getExcellentMark());
        updateExam.setDescription(req.getDescription());
        updateExam.setExamMemberId(req.getExamMemberId());
        updateExam.setReviewer(req.getReviewer());//批阅人/直接主管
        updateExam.setReviewerRole(req.getReviewerRole());//批阅角色
        updateExam.setExamId(generateExamId());
        updateExam.setStatus(CourseEnums.ExamTimeStatus.NOT_STARTED.getCode());
        updateExam.setEnabledMark(CourseEnums.EnabledMarkType.VALID.getCode());
        //判断是否是常规考试
        fillExamStatus(updateExam);
        fillExamPaperQuestion(updateExam);
        updateExam.setNeedUpdate(ExamUpdateStatus.NO_UPDATE.getCode());
        baseMapper.insert(updateExam);

        //2、添加考试成员
        switch (examType) {
            case BASE:
                batchInsertExamMemberForMemberIdNew(updateExam, examUserList, rosterMap, userOrgMap, defaultPowerReviewer);
                break;
            case POSITION:
                //岗位学习考试
                break;
            default:
                break;
        }
    }

    /**
     * 校验补考频次参数
     *
     * @param req
     */
    private void checkExamCommonParam(SaveExamReq req) {
        //重复考试
        if (CourseEnums.RepeatExam.REPEAT_EXAM.getCode().equals(req.getExamlimitation())) {
            ExamRetakeFrequencyEnum examRetakeFrequencyEnum = ExamRetakeFrequencyEnum.of(req.getReExamFrequencyType());
            if (examRetakeFrequencyEnum == null) {
                throw new RuntimeException("参数异常,请选择补考频次");
            }
            if (examRetakeFrequencyEnum != ExamRetakeFrequencyEnum.UNLIMITED) {
                if (req.getReExamFrequencyNum() == null) {
                    throw new RuntimeException("参数异常,请选择补考频次次数");
                }
                if (req.getReExamFrequencyNum() > 10) {
                    throw new RuntimeException("参数异常,补考频次不能大于10次");
                }

                if (req.getReExamFrequencyNum() < 0) {
                    throw new RuntimeException("参数异常,补考频次不能小于0次");
                }

            }
        }

        ExamQuestionShuffleEnum sh = ExamQuestionShuffleEnum.of(req.getExamQuestionRandom());
        if (sh == null) {
            throw new RuntimeException("参数异常,请选择试题设置");
        }
    }

    private void batchCheckAndRevierwer(Map<String, FtbPersonnelsStaffRoster> rosterMap, Map<String, List<WorkerGroupDataDto>> userOrgMap, List<String> examUserList, Map<String, String> defaultPowerReviewer) {
        PermissionsCacheDTO permissionsCacheDTO = personnelPerUtils.doQueryUserPermissions(List.of("70"));

        for (String tempUserId : examUserList) {
            List<String> localOrganizeIds = null;
            List<WorkerGroupDataDto> workerGroupDataDtoList = userOrgMap.get(tempUserId);
            if (CollectionUtil.isNotEmpty(workerGroupDataDtoList)) {
                localOrganizeIds = workerGroupDataDtoList.stream().map(WorkerGroupDataDto::getAffiliatedOrg).collect(Collectors.toList());
            }
            List<String> powerUserIdsList = examUserService.getPowerUserIdsForPermission(tempUserId, permissionsCacheDTO, localOrganizeIds);
            String powerUserIds = "";
            if (CollectionUtil.isNotEmpty(powerUserIdsList)) {
                powerUserIds = String.join(",", powerUserIdsList);
            }
            log.error("power examUser=" + powerUserIds);
            if (StringUtils.isEmpty(powerUserIds)) {
                FtbPersonnelsStaffRoster roster = rosterMap.get(tempUserId);
                if (null != roster) {
                    throw new RuntimeException("员工[" + roster.getName() + "]的考试没有批阅人");
                } else {
                    throw new RuntimeException("用户ID" + tempUserId + "没有批阅人");
                }
            } else {
                defaultPowerReviewer.put(tempUserId, powerUserIds);
            }
        }
    }

    /**
     * 填充考试题目数量和分数 和题目备份
     *
     * @param exam
     */
    private void fillExamPaperQuestion(FtbCultivateExam exam) {
        List<ExamQuestionBakVo> list = paperService.queryConfigQuestionList(exam.getPaperId());
        if (CollectionUtil.isEmpty(list)) {
            throw new RuntimeException("试卷没有配置题目");
        }
        exam.setCurrQuestionNumber(list.size());
        exam.setCurrTotalScore(list.stream().mapToInt(examQuestionBakVo -> examQuestionBakVo.getScore()).sum());
        exam.setCurrQuestionList(JSONUtil.toJsonStr(list));
    }

    private void fillExamPaperQuestionOld(FtbCultivateExam exam) {
        List<ExamQuestionBakVo> list = paperService.queryConfigQuestionList(exam.getPaperId());
        if (CollectionUtil.isEmpty(list)) {
            return;
        }
        exam.setCurrQuestionNumber(list.size());
        exam.setCurrTotalScore(list.stream().mapToInt(examQuestionBakVo -> examQuestionBakVo.getScore()).sum());
        exam.setCurrQuestionList(JSONUtil.toJsonStr(list));
    }

    /**
     * 检测考试配置参数
     *
     * @param req
     */
    private void checkParamAndFillExam(SaveExamReq req, FtbCultivateExam exam) {
        CourseEnums.RepeatExam examlimitation = CourseEnums.RepeatExam.fromCode(req.getExamlimitation());
        if (null == examlimitation) {
            throw new RuntimeException("考试限制参数错误");
        }
        exam.setExamlimitation(examlimitation.getCode());
        if (examlimitation == CourseEnums.RepeatExam.REPEAT_EXAM) {
            exam.setReExamFrequencyType(req.getReExamFrequencyType());
            exam.setReExamFrequencyNum(req.getReExamFrequencyNum());
        }

        ExamConfigEnums.WatermarkStatus watermarkStatus = ExamConfigEnums.WatermarkStatus.fromCode(req.getWaterMark());
        if (null == watermarkStatus) {
            throw new RuntimeException("水印设置参数错误");
        }
        exam.setWaterMark(watermarkStatus.getCode());


        ExamConfigEnums.ScreenLockStatus cutScreen = ExamConfigEnums.ScreenLockStatus.fromCode(req.getCutScreen());
        if (null == cutScreen) {
            throw new RuntimeException("切屏限制参数错误");
        }
        exam.setCutScreen(cutScreen.getCode());
        if (cutScreen == ExamConfigEnums.ScreenLockStatus.ENABLED) {
            if (req.getMaxCutScreenCount() < 1) {
                throw new RuntimeException("切屏次数不能小于1");
            }
            exam.setMaxCutScreenCount(req.getMaxCutScreenCount());
        }


        ExamConfigEnums.ScreenshotRestriction screenshot = ExamConfigEnums.ScreenshotRestriction.fromCode(req.getScreenshot());
        if (null == screenshot) {
            throw new RuntimeException("禁止截屏参数错误");
        }
        exam.setScreenshot(screenshot.getCode());


        ExamConfigEnums.CopyPasteRestriction copyAndPaste = ExamConfigEnums.CopyPasteRestriction.fromCode(req.getCopyAndPaste());
        if (null == copyAndPaste) {
            throw new RuntimeException("禁止复制粘贴参数错误");
        }
        exam.setCopyAndPaste(copyAndPaste.getCode());


        ExamConfigEnums.UserInactivityTimeoutCheatingPolicy openOverTime = ExamConfigEnums.UserInactivityTimeoutCheatingPolicy.fromCode(req.getOpenOverTime());
        if (null == openOverTime) {
            throw new RuntimeException("超时无交互退出配置参数错误");
        }
        exam.setOpenOverTime(openOverTime.getCode());
        if (openOverTime == ExamConfigEnums.UserInactivityTimeoutCheatingPolicy.ENABLED) {
            if (null == req.getOverTime()) {
                throw new RuntimeException("超时无交互时间不能为空");
            }
            if (req.getOverTime() < 1) {
                throw new RuntimeException("超时无交互时间不能小于1秒");
            }
            exam.setOverTime(req.getOverTime());
        }


        ExamConfigEnums.ExamDetailVisibility allowSelectDetail = ExamConfigEnums.ExamDetailVisibility.fromCode(req.getAllowSelectDetail());
        if (null == allowSelectDetail) {
            throw new RuntimeException("考试完成后允许学员本人查看考卷详情配置参数错误");
        }
        exam.setAllowSelectDetail(allowSelectDetail.getCode());

        ExamConfigEnums.BackToPreviousQuestionPolicy allowChangeLastQuestion = ExamConfigEnums.BackToPreviousQuestionPolicy.fromCode(req.getAllowChangeLastQuestion());
        if (null == allowChangeLastQuestion) {
            throw new RuntimeException("考试过程中不允许回到上一题配置参数错误");
        }
        exam.setAllowChangeLastQuestion(allowChangeLastQuestion.getCode());

        CourseEnums.ExamType examType = CourseEnums.ExamType.fromCode(req.getExamType());
        if (null == examType) {
            throw new RuntimeException("考试类型参数错误");
        }
        exam.setExamType(examType.getCode());
        if (examType == CourseEnums.ExamType.BASE) {

            if (null != req.getStartTime() && null != req.getEndTime()) {
                //判断开始时间不能小于结束时间
                if (req.getStartTime().after(req.getEndTime())) {
                    throw new RuntimeException("考试开始时间不能大于结束时间");
                }
                exam.setStartTime(req.getStartTime());
                exam.setEndTime(req.getEndTime());
                long maxSecond = DateUtil.between(req.getStartTime(), req.getEndTime(), DateUnit.SECOND);
                if (req.getExamTime() != null) {
                    long examTime = Long.valueOf(req.getExamTime());
                    if (examTime > maxSecond) {
                        throw new RuntimeException("考试时长不能大于考试范围时长");
                    }
                }
            }
        } else if (examType == CourseEnums.ExamType.POSITION) {
            if (req.getExamTime() == null || req.getExamTime() < 1) {
                throw new RuntimeException("考试时长不能小于1");
            }
        }
        exam.setExamTime(req.getExamTime());
        exam.setExamQuestionRandom(req.getExamQuestionRandom());
    }

    /**
     * 根据考试开始日期和结束日期 判断修改考试状态
     *
     * @param exam
     */
    private void fillExamStatus(FtbCultivateExam exam) {
        if (CourseEnums.ExamType.BASE.getCode().equals(exam.getExamType())) {
            Date now = new Date();
            if (exam.getStartTime() != null && exam.getEndTime() != null) {
                if (now.after(exam.getEndTime())) {
                    exam.setStatus(CourseEnums.ExamTimeStatus.DONE.getCode());
                } else {
                    if (now.after(exam.getStartTime())) {
                        exam.setStatus(CourseEnums.ExamTimeStatus.IN_PROGRESS.getCode());
                    } else {
                        exam.setStatus(CourseEnums.ExamTimeStatus.NOT_STARTED.getCode());
                    }
                }
            } else {
                exam.setStatus(CourseEnums.ExamTimeStatus.IN_PROGRESS.getCode());
            }
        } else {
            exam.setStatus(CourseEnums.ExamTimeStatus.NOT_STARTED.getCode());
        }
    }

    /**
     * 查询试卷信息
     *
     * @param paperId 试卷ID
     * @return
     */
    private FtbCultivateTestPaper queryPaper(String paperId) {
        FtbCultivateTestPaper paper = paperService.getById(paperId);
        if (paper == null) {
            throw new RuntimeException("试卷不存在");
        }
        if (CourseEnums.EnabledMarkType.INVALID.getCode().equals(paper.getEnabledMark())) {
            throw new RuntimeException("试卷已删除");
        }
        return paper;
    }


    /**
     * 查询试卷信息
     *
     * @param paperId 试卷ID
     * @return
     */
    private FtbCultivateTestPaper queryPaperNocheckDelete(String paperId) {
        FtbCultivateTestPaper paper = paperService.getById(paperId);
        if (paper == null) {
            throw new RuntimeException("试卷不存在");
        }
        return paper;
    }

    /**
     * 生成考试ID
     *
     * @return
     */
    private String generateExamId() {
        return SelfGrowthUtil.provideACustomIDBasedOnTheModule(SelfrowingEnum.EXAM);
    }


    /**
     * 批量添加考试成员
     *
     * @param exam           考试
     * @param examMemberList 考试用户ID集合
     */
    private void batchInsertExamMemberForMemberId(FtbCultivateExam exam, List<String> examMemberList) {

        List<FtbCultivateExamUser> examUserList = new ArrayList<>();
        for (String examMemberId : examMemberList) {
            FtbCultivateExamUser examUser = new FtbCultivateExamUser();
            examUser.setExamId(exam.getId());
            examUser.setUserId(examMemberId);
            examUser.setStatus(CourseEnums.ExamStatus.WAIT.getCode());
            examUser.setEnabledMark(CourseEnums.EnabledMarkType.VALID.getCode());
            examUser.setPaperId(exam.getPaperId());
            examUser.setStartTime(exam.getStartTime());
            examUser.setEndTime(exam.getEndTime());
            examUser.setExamType(exam.getExamType());
            examUser.setExamSource(CourseEnums.RelationExamSource.REGULAR_EXAM.getCode());
            examUser.setBatch(UUID.randomUUID().toString().replaceAll("-", ""));
            examUser.setUserExamCount(1);
            //查询用户所属组织
            UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(examMemberId, exam.getTenantId());
            List<String> selectOrgList = List.of(userPrimaryBoundOne.getOrganizeId());
            if (CollectionUtil.isNotEmpty(selectOrgList)) {
                examUser.setUserOrgList(String.join(",", selectOrgList));
            }
            //填充批阅人信息 和阅卷角色
//            fillRevierwer(examUser, exam);
//            if (exam.getExamType() == 1 && StringUtils.isEmpty(examUser.getReviewerUserIds())) {
//                UserEntity userEntity = userApi.getInfoById(examUser.getUserId());
//                String userName = "";
//                if (userEntity != null) {
//                    userName = userEntity.getRealName();
//                }
//                throw new RuntimeException("员工：" + userName + "的考试没有批阅人");
//            }
            examUserList.add(examUser);
        }
        examUserService.saveBatch(examUserList);
    }

    private void batchInsertExamMemberForMemberIdNew(FtbCultivateExam exam, List<String> examUserList, Map<String, FtbPersonnelsStaffRoster> rosterMap, Map<String, List<WorkerGroupDataDto>> userOrgMap, Map<String, String> defaultPowerReviewer) {
        List<FtbCultivateExamUser> addList = new ArrayList<>();
        for (String examMemberId : examUserList) {
            FtbCultivateExamUser examUser = new FtbCultivateExamUser();
            examUser.setExamId(exam.getId());
            examUser.setUserId(examMemberId);
            examUser.setStatus(CourseEnums.ExamStatus.WAIT.getCode());
            examUser.setEnabledMark(CourseEnums.EnabledMarkType.VALID.getCode());
            examUser.setPaperId(exam.getPaperId());
            examUser.setStartTime(exam.getStartTime());
            examUser.setEndTime(exam.getEndTime());
            examUser.setExamType(exam.getExamType());
            examUser.setExamSource(CourseEnums.RelationExamSource.REGULAR_EXAM.getCode());
            examUser.setBatch(UUID.randomUUID().toString().replaceAll("-", ""));
            examUser.setUserExamCount(1);
            //查询用户所属组织
            List<WorkerGroupDataDto> workerGroupDataDtoList = userOrgMap.get(examMemberId);
            if (CollectionUtil.isNotEmpty(workerGroupDataDtoList)) {
                examUser.setUserOrgList(String.join(",", QuestionExcelExportUtil.getOrgIds(workerGroupDataDtoList)));
            }
            examUser.setVersionBatch(exam.getVersionBatch());
            addList.add(examUser);
        }
        examUserService.saveBatch(addList);
    }

    @Override
    public void fillRevierwer(FtbCultivateExamUser examUser, FtbCultivateExam exam) {

        //阅卷人
        Set<String> reviewerUserIdList = new HashSet<>();
        if (StringUtils.isNotEmpty(exam.getReviewerAppoint())) {
            reviewerUserIdList.addAll(Arrays.asList(exam.getReviewerAppoint().split(",")));
        }
        if ("0".equals(exam.getReviewer())) {
            //查询当前用户的直接主管
            UserBoundVO bossByUserIdSimple = userApiV2Util.getBossByUserIdSimple(examUser.getUserId(), null);
            if (bossByUserIdSimple != null && StringUtils.isNotEmpty(bossByUserIdSimple.getLeaderId())) {
                reviewerUserIdList.add(bossByUserIdSimple.getLeaderId());
            }
        }
        String powerUserIds = personnelPerUtils.obtainTrainingApproverPermissions(examUser.getUserId());
        if (StringUtils.isNotEmpty(powerUserIds)) {
            reviewerUserIdList.addAll(Arrays.asList(powerUserIds.split(",")));
        }

        if (CollectionUtil.isNotEmpty(reviewerUserIdList)) {
            examUser.setReviewerUserIds(String.join(",", reviewerUserIdList));
        }
    }

    /**
     * 填充考试的批阅人信息
     *
     * @param examUser            考试用户记录薪酬
     * @param exam                考试信息
     * @param permissionsCacheDTO 考试的权限信息
     */
    @Override
    public void fillRevierwerNew(FtbCultivateExamUser examUser, FtbCultivateExam exam, PermissionsCacheDTO permissionsCacheDTO) {
        //阅卷人
        Set<String> reviewerUserIdList = new HashSet<>();
        if (StringUtils.isNotEmpty(exam.getReviewerAppoint())) {
            reviewerUserIdList.addAll(Arrays.asList(exam.getReviewerAppoint().split(",")));
        }
        List<String> localOrganizeIds = null;
        if ("0".equals(exam.getReviewer())) {
            //查询当前用户的直接主管
            UserBoundVO userBoundVO = userApiV2Util.getBossByUserIdSimple(examUser.getUserId(), null);
            if (userBoundVO != null && StringUtils.isNotEmpty(userBoundVO.getLeaderId())) {
                reviewerUserIdList.add(userBoundVO.getLeaderId());
            }
        }
        List<String> powerUserIdsList = examUserService.getPowerUserIdsForPermission(examUser.getUserId(), permissionsCacheDTO, localOrganizeIds);
        String powerUserIds = "";
        if (CollectionUtil.isNotEmpty(powerUserIdsList)) {
            powerUserIds = String.join(",", powerUserIdsList);
        }
//        String powerUserIds = personnelPerUtils.obtainTrainingApproverPermissions(examUser.getUserId());
        if (StringUtils.isNotEmpty(powerUserIds)) {
            reviewerUserIdList.addAll(Arrays.asList(powerUserIds.split(",")));
        }

        if (CollectionUtil.isNotEmpty(reviewerUserIdList)) {
            examUser.setReviewerUserIds(String.join(",", reviewerUserIdList));
        }
    }


    /**
     * 修改考试
     *
     * @param req
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateData(SaveExamReq req) {
        CourseEnums.ExamType examType = CourseEnums.ExamType.fromCode(req.getExamType());
        List<String> examUserList = new ArrayList<>();
        Map<String, String> defaultPowerReviewer = new HashMap<>(); //userid->
        Map<String, FtbPersonnelsStaffRoster> rosterMap = new HashMap<>();//userid->
        Map<String, List<WorkerGroupDataDto>> userOrgMap = new HashMap<>();//userid->
        FtbCultivateExam oldExam = queryExamInfo(req.getId());
        checkExamCommonParam(req);
        if (CourseEnums.ExamType.BASE == examType) {
            if (StringUtils.isEmpty(req.getExamMemberId())) {
                throw new RuntimeException("考试用户不能为空");
            }
            if (CourseEnums.ExamTimeStatus.IN_PROGRESS.getCode().equals(oldExam.getStatus())) {
                throw new RuntimeException("考试进行中,不能修改");
            }
            if (CourseEnums.ExamTimeStatus.DONE.getCode().equals(oldExam.getStatus())) {
                throw new RuntimeException("考试已经完成,不能修改");
            }
            if (CourseEnums.ExamTimeStatus.NULLIFY.getCode().equals(oldExam.getStatus())) {
                throw new RuntimeException("考试已经作废,不能修改");
            }
            examUserList = QuestionExcelExportUtil.stringToList(req.getExamMemberId(), ",");
            rosterMap = userExamUtil.queryRosterSimpleInfo(examUserList);
            userOrgMap = userExamUtil.getUserOrgBoundInfoForUserList(examUserList);
        }
        if (StringUtils.isEmpty(req.getReviewer())) {
            req.setReviewer("");
        }
        //1、检测名称是否重复  试卷是否存在
        QueryWrapper<FtbCultivateExam> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(FtbCultivateExam::getExamName, req.getExamName()).ne(FtbCultivateExam::getId, req.getId()).eq(FtbCultivateExam::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        Long count = baseMapper.selectCount(wrapper);
        if (null != count && count > 0) {
            throw new RuntimeException("考试名称已经存在");
        }

        FtbCultivateTestPaper paper = queryPaper(req.getPaperId());
        if (CourseEnums.DraftStatus.YES.getCode().equals(paper.getIsDraft())) {
            throw new RuntimeException("试卷未定稿,不能绑定考试");
        }
        if (ExamUpdateStatus.NEED_UPDATE.getCode().equals(paper.getNeedUpdate())) {
            throw new RuntimeException("试卷异常,请先编辑试卷");
        }

        //2、修改考试
        FtbCultivateExam updateExam = new FtbCultivateExam();
        checkParamAndFillExam(req, updateExam);
        updateExam.setId(oldExam.getId());
        updateExam.setVersionBatch(oldExam.getVersionBatch());
        updateExam.setExamName(req.getExamName());
        updateExam.setPaperId(req.getPaperId());
        updateExam.setPaperName(paper.getName());
        updateExam.setPassType(req.getPassType());
        updateExam.setPassMark(req.getPassMark());
        updateExam.setExcellentType(req.getExcellentType());
        updateExam.setExcellentMark(req.getExcellentMark());
        updateExam.setDescription(req.getDescription());
        updateExam.setExamMemberId(req.getExamMemberId());
        updateExam.setReviewer(req.getReviewer());//批阅人/直接主管
        updateExam.setNeedUpdate(ExamUpdateStatus.NO_UPDATE.getCode());
        updateExam.setCreatorTime(oldExam.getCreatorTime());
        updateExam.setCreatorUserId(oldExam.getCreatorUserId());

        updateExam.setReviewerRole(req.getReviewerRole());//批阅角色
        updateExam.setLastModifyTime(new Date());
        fillExamStatus(updateExam);
        fillExamPaperQuestion(updateExam);
        countQuestionTypeNum(paper);
        updateExam.setPaperInfo(JSONUtil.toJsonStr(paper));
        //处理岗位 是否有批次
        Boolean isNewBatch = false;
        if (CourseEnums.ExamType.POSITION == examType) {
            if (CollectionUtil.isEmpty(req.getPostAndPositionList())) {
                throw new RuntimeException("请选择考试岗位");
            }
            updateExam.setPostRankConf(JSONUtil.toJsonStr(req.getPostAndPositionList()));
            List<String> postIdsList = new ArrayList<>();//岗位ID集合
            for (PostAndPosition postAndPosition : req.getPostAndPositionList()) {
                postIdsList.add(postAndPosition.getId());
            }
            updateExam.setPostId(String.join(",", postIdsList));
            isNewBatch = fillPaperInfoAndCheckIsNewBatch(updateExam, oldExam, paper);
            if (isNewBatch) {
                updateExam.setVersionBatch(UUID.randomUUID().toString().replaceAll("-", ""));
                ftbCultivateExamHistoryPaperService.recordHistory(oldExam);
            }
        } else {
            updateExam.setPostRankConf("");
            updateExam.setPostId("");
        }
        updateExam.setExamId(oldExam.getExamId());
        baseMapper.deleteById(updateExam.getId());//兼容考试要清楚考试时间和要修改为null的值
        baseMapper.insert(updateExam);

        //3、处理考试成员
        switch (examType) {
            case BASE:
                //常规考试
                batchUpdateExamMemberNew(updateExam, examUserList, rosterMap, userOrgMap, defaultPowerReviewer);
                break;
            case POSITION:
                //把没有考试的调整到最新批次
                if (isNewBatch) {
                    updateNoExamUserToLastest(updateExam);
                }
                break;
            default:
                break;
        }
    }

    private void countQuestionTypeNum(FtbCultivateTestPaper paper) {
        if (paper.getType().equals(2)) {

            PaperConfigReq configReq = JSONUtil.toBean(paper.getPaperConfig(), PaperConfigReq.class);
            Map<String, Map<String, PaperConfigReq.QuestionNum>> questionConfig = configReq.getQuestionConfig();
            Map<String, PaperConfigReq.QuestionScore> scoreConfig = configReq.getScoreConfig();


            List<String> questionIdList = new ArrayList<>();
            List<ExamQuestionBakVo> list = paperService.queryConfigQuestionList(paper.getId());
            if (CollectionUtil.isEmpty(list)) {
                throw new RuntimeException("试卷没有题目");
            }
            for (ExamQuestionBakVo examQuestionBakVo : list) {
                questionIdList.add(examQuestionBakVo.getQuestionId());
            }

            List<FtbCultivateQuestion> questionList = questionService.listByIds(questionIdList);
            if (CollectionUtil.isEmpty(questionList)) {
                throw new RuntimeException("试卷没有题目");
            }
            //按照题库ID分组
            Map<String, List<FtbCultivateQuestion>> currPaperMap = questionList.stream().collect(Collectors.groupingBy(FtbCultivateQuestion::getClassifyId));

            for (Map.Entry<String, Map<String, PaperConfigReq.QuestionNum>> entry : questionConfig.entrySet()) {
                String questionBankId = entry.getKey();
                Map<String, PaperConfigReq.QuestionNum> questionNumbers = entry.getValue();
                List<FtbCultivateQuestion> tempQuestionList = currPaperMap.get(questionBankId);
                Map<String, PaperConfigReq.QuestionNum> analyMap = QuestionAnalysisUtil.initAnalysQuestionCount();
                QuestionAnalysisUtil.analysQuestionCount(analyMap, tempQuestionList);


                // 遍历内层 Map
                for (Map.Entry<String, PaperConfigReq.QuestionNum> qEntry : questionNumbers.entrySet()) {
                    String type = qEntry.getKey();
                    PaperConfigReq.QuestionNum questionNum = qEntry.getValue();
                    PaperConfigReq.QuestionNum currQuestionNum = analyMap.get(type);
                    if (currQuestionNum == null) {
                        questionNum.setSimpleNum(0);
                        questionNum.setHardNum(0);
                        questionNum.setGeneralNum(0);
                    } else {
                        questionNum.setSimpleNum(currQuestionNum.getSimpleNum());
                        questionNum.setGeneralNum(currQuestionNum.getGeneralNum());
                        questionNum.setHardNum(currQuestionNum.getHardNum());
                    }

                }
            }

            paper.setPaperConfig(JSONUtil.toJsonStr(configReq));
        }
    }

    private void updateNoExamUserToLastest(FtbCultivateExam updateExam) {
        LambdaUpdateWrapper<FtbCultivateExamUser> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.set(FtbCultivateExamUser::getVersionBatch, updateExam.getVersionBatch());
        updateWrapper.set(FtbCultivateExamUser::getPaperId, updateExam.getPaperId());
        updateWrapper.in(FtbCultivateExamUser::getStatus, CourseEnums.ExamStatus.WAIT.getCode(), CourseEnums.ExamStatus.OVERDUE.getCode());
        updateWrapper.eq(FtbCultivateExamUser::getExamId, updateExam.getId());
        examUserService.update(null, updateWrapper);
    }


    /**
     * @param updateExam
     * @param oldExam
     * @return true-需要生成新批次 false-不需要生成新批次
     */
    private Boolean fillPaperInfoAndCheckIsNewBatch(FtbCultivateExam updateExam, FtbCultivateExam oldExam, FtbCultivateTestPaper paper) {
        Boolean batch = false;
        updateExam.setPaperInfo(JSONUtil.toJsonStr(paper));
        if (oldExam.getNeedUpdate() == 2) {
            batch = true;
        } else if (!oldExam.getPaperId().equals(updateExam.getPaperId())) {
            batch = true;
        } else if (!oldExam.getPassType().equals(updateExam.getPassType()) || !oldExam.getPassMark().equals(updateExam.getPassMark())
                || !oldExam.getExcellentType().equals(updateExam.getExcellentType()) || !oldExam.getExcellentMark().equals(updateExam.getExcellentMark())) {
            batch = true;
        }
        if (batch) {
            //查询是否有完成的考试 如果有完成的考试就生成 没有就不生成
            List<FtbCultivateExamUser> examUserList = examUserService.queryCompleteExamUserListForExamIdAndBatch(oldExam.getId(), oldExam.getVersionBatch());
            if (CollectionUtil.isEmpty(examUserList)) {
                return false;
            } else {
                return true;
            }

        } else {
            return false;
        }
    }

    private String getReviewerAppoints(List<ReviewerAppointDto> reviewerAppointList) {
        if (CollectionUtil.isEmpty(reviewerAppointList)) {
            return "";
        }
        List<String> userList = new ArrayList<>();
        for (ReviewerAppointDto reviewerAppointDto : reviewerAppointList) {
            if (StringUtils.isNotEmpty(reviewerAppointDto.getUserId())) {
                userList.add(reviewerAppointDto.getUserId());
            }
        }
        return String.join(",", userList);
    }

    /**
     * 批量修改考试成员
     *
     * @param exam         考试信息
     * @param examMemberId 前端传入的考试用户ID
     */
    private void batchUpdateExamMember(FtbCultivateExam exam, String examMemberId) {
        //1、查询已经存在的考试用户列表
        List<FtbCultivateExamUser> exiestMemberList = queryExamMemberListForExamId(exam.getId());
        //2、根据传入的考试用户ID处理
        if (StringUtils.isEmpty(examMemberId)) {
            if (CollectionUtil.isNotEmpty(exiestMemberList)) {
                deleteExamUserExamId(exam.getId());
            }
            return;
        }
        List<String> reqMemberList = Arrays.asList(examMemberId.split(","));
        if (CollectionUtil.isEmpty(reqMemberList)) {
            if (CollectionUtil.isNotEmpty(exiestMemberList)) {
                deleteExamUserExamId(exam.getId());
            }
            return;
        }

        //需要添加的
        List<String> addList = new ArrayList<>();
        //存在的用户集合
        Set<String> set = exiestMemberList.stream().map(FtbCultivateExamUser::getUserId).collect(Collectors.toSet());
        for (String memberId : reqMemberList) {
            if (!set.contains(memberId)) {
                addList.add(memberId);
            }
        }
        if (CollectionUtil.isNotEmpty(addList)) {
            batchInsertExamMemberForMemberId(exam, addList);
        }

        //需要删除的
        List<String> removeList = new ArrayList<>();
        Set<String> reqSet = reqMemberList.stream().collect(Collectors.toSet());
        for (FtbCultivateExamUser examUser : exiestMemberList) {
            if (!reqSet.contains(examUser.getUserId())) {
                removeList.add(examUser.getId());
            }
        }
        if (CollectionUtil.isNotEmpty(removeList)) {
            deleteExamUserForIds(removeList);
        }
        //去存在的
        if (CollectionUtil.isNotEmpty(set) && CollectionUtil.isNotEmpty(reqSet)) {
            Set<String> intersection = getIntersection(reqSet, set);
            if (CollectionUtil.isNotEmpty(intersection)) {

                List<String> stringList = intersection.stream().collect(Collectors.toList());

                deleteExamUserForUserIds(exam.getId(), stringList);
                batchInsertExamMemberForMemberId(exam, stringList);
            }
        }
    }

    private void batchUpdateExamMemberNew(FtbCultivateExam exam, List<String> reqMemberList, Map<String, FtbPersonnelsStaffRoster> rosterMap, Map<String, List<WorkerGroupDataDto>> userOrgMap, Map<String, String> defaultPowerReviewer) {
        //1、查询已经存在的考试用户列表
        List<FtbCultivateExamUser> exiestMemberList = queryExamMemberListForExamId(exam.getId());

        if (CollectionUtil.isEmpty(reqMemberList)) {
            if (CollectionUtil.isNotEmpty(exiestMemberList)) {
                deleteExamUserExamId(exam.getId());
            }
            return;
        }

        //需要添加的
        List<String> addList = new ArrayList<>();
        //存在的用户集合
        Set<String> set = exiestMemberList.stream().map(FtbCultivateExamUser::getUserId).collect(Collectors.toSet());
        for (String memberId : reqMemberList) {
            if (!set.contains(memberId)) {
                addList.add(memberId);
            }
        }
        if (CollectionUtil.isNotEmpty(addList)) {
            batchInsertExamMemberForMemberIdNew(exam, addList, rosterMap, userOrgMap, defaultPowerReviewer);
        }

        //需要删除的
        List<String> removeList = new ArrayList<>();
        Set<String> reqSet = reqMemberList.stream().collect(Collectors.toSet());
        for (FtbCultivateExamUser examUser : exiestMemberList) {
            if (!reqSet.contains(examUser.getUserId())) {
                removeList.add(examUser.getId());
            }
        }
        if (CollectionUtil.isNotEmpty(removeList)) {
            deleteExamUserForIds(removeList);
        }
        //去存在的
        if (CollectionUtil.isNotEmpty(set) && CollectionUtil.isNotEmpty(reqSet)) {
            Set<String> intersection = getIntersection(reqSet, set);
            if (CollectionUtil.isNotEmpty(intersection)) {

                List<String> stringList = intersection.stream().collect(Collectors.toList());

                deleteExamUserForUserIds(exam.getId(), stringList);
                batchInsertExamMemberForMemberIdNew(exam, stringList, rosterMap, userOrgMap, defaultPowerReviewer);
            }
        }
    }

    public static Set<String> getIntersection(Set<String> set1, Set<String> set2) {
        Set<String> intersectionSet = new HashSet<>();

        for (String element : set1) {
            if (set2.contains(element)) {
                intersectionSet.add(element);
            }
        }

        return intersectionSet;
    }

    /**
     * 根据考试ID删除考试用户
     *
     * @param examId 考试ID
     */
    private void deleteExamUserExamId(String examId) {
        UpdateWrapper<FtbCultivateExamUser> wrapper = new UpdateWrapper<>();
        wrapper.lambda().set(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.INVALID.getCode()).set(FtbCultivateExamUser::getDeleteTime, new Date()).eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode()).in(FtbCultivateExamUser::getStatus, CourseEnums.ExamStatus.WAIT.getCode(), CourseEnums.ExamStatus.OVERDUE.getCode()).eq(FtbCultivateExamUser::getExamId, examId);
        examUserService.update(wrapper);
    }

    /**
     * 根据考试ID删除考试用户
     *
     * @param examId 考试ID
     */
    private void deleteAllExamUserExamId(String examId) {
        UpdateWrapper<FtbCultivateExamUser> wrapper = new UpdateWrapper<>();
        wrapper.lambda()
                .set(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.INVALID.getCode())
                .set(FtbCultivateExamUser::getDeleteTime, new Date())
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode())
                .eq(FtbCultivateExamUser::getExamId, examId);
        examUserService.update(wrapper);
    }


    /**
     * 删除考试用户
     *
     * @param removeList 需要删除的考试用户表中的ID
     */

    private void deleteExamUserForIds(List<String> removeList) {
        examUserService.update(Wrappers.<FtbCultivateExamUser>lambdaUpdate().set(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.INVALID.getCode()).set(FtbCultivateExamUser::getDeleteTime, new Date()).in(FtbCultivateExamUser::getId, removeList));
    }

    /**
     * 删除考试用户
     *
     * @param examId  考试ID
     * @param userIds 需要删除的考试用户表中的ID
     */

    private void deleteExamUserForUserIds(String examId, List<String> userIds) {
        examUserService.update(Wrappers.<FtbCultivateExamUser>lambdaUpdate()
                .set(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.INVALID.getCode())
                .set(FtbCultivateExamUser::getDeleteTime, new Date())
                .eq(FtbCultivateExamUser::getExamId, examId)
                .in(FtbCultivateExamUser::getUserId, userIds));
    }

    /**
     * 查询考试成员
     *
     * @param examId 考试ID
     * @return
     */

    private List<FtbCultivateExamUser> queryExamMemberListForExamId(String examId) {
        QueryWrapper<FtbCultivateExamUser> wrap = new QueryWrapper<>();
        wrap.lambda().eq(FtbCultivateExamUser::getExamId, examId).eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        return examUserService.list(wrap);
    }

    /**
     * 删除考试
     *
     * @param examId 考试ID
     */

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteData(String examId) {
        //1、检测并检查考试
        FtbCultivateExam exam = queryExamInfo(examId);
        if (CourseEnums.ExamType.POSITION.getCode().equals(exam.getExamType())) {
            // 岗位学习考试和课程考试删除
            LambdaUpdateWrapper<FtbCultivatePositionCourseExam> ftbCultivatePositionCourseExamLambdaUpdateWrapper = Wrappers.lambdaUpdate();
            ftbCultivatePositionCourseExamLambdaUpdateWrapper.eq(FtbCultivatePositionCourseExam::getExamId, examId);
            ftbCultivatePositionCourseExamLambdaUpdateWrapper.set(FtbCultivatePositionCourseExam::getEnabledMark, 1);
            ftbCultivatePositionCourseExamMapper.update(new FtbCultivatePositionCourseExam(), ftbCultivatePositionCourseExamLambdaUpdateWrapper);

            LambdaUpdateWrapper<FtbCultivatePositionExam> ftbCultivatePositionExamLambdaUpdateWrapper = Wrappers.lambdaUpdate();
            ftbCultivatePositionExamLambdaUpdateWrapper.eq(FtbCultivatePositionExam::getExamId, examId);
            ftbCultivatePositionExamLambdaUpdateWrapper.set(FtbCultivatePositionExam::getEnabledMark, 1);
            ftbCultivatePositionExamMapper.update(new FtbCultivatePositionExam(), ftbCultivatePositionExamLambdaUpdateWrapper);
        }
        //2、删除考试
        FtbCultivateExam updateExam = new FtbCultivateExam();
        updateExam.setId(exam.getId());
        updateExam.setEnabledMark(CourseEnums.EnabledMarkType.INVALID.getCode());
        updateExam.setDeleteTime(new Date());
        baseMapper.updateById(updateExam);
        if (CourseEnums.ExamType.POSITION.getCode().equals(exam.getExamType())) {
            //岗位考试 全部删除
            deleteAllExamUserExamId(exam.getId());
        } else {
            //删除考试用户
            deleteExamUserExamId(exam.getId());
        }

    }

    /**
     * 检查考试是否可以删除
     *
     * @param examId 考试ID
     * @return
     */
    @Override
    public CanDeleteMsg checkExamCanDelete(String examId) {
        FtbCultivateExam exam = queryExamInfo(examId);
        if (CourseEnums.ExamType.BASE.getCode().equals(exam.getExamType())) {
            //常规学习考试
            if (CourseEnums.ExamTimeStatus.IN_PROGRESS.getCode().equals(exam.getStatus())) {
                return new CanDeleteMsg(false, "考试正在进行中,请谨慎操作");
            }
            if (CourseEnums.ExamTimeStatus.DONE.getCode().equals(exam.getStatus())) {
                return new CanDeleteMsg(false, "考试已经完成,请谨慎操作");
            }
        } else {
            //检测考试是否与岗位学习有关联
            LambdaQueryWrapper<FtbCultivatePositionExam> positionExamWrapper = new LambdaQueryWrapper<FtbCultivatePositionExam>().eq(FtbCultivatePositionExam::getExamId, examId).eq(FtbCultivatePositionExam::getEnabledMark, 0);
            List<FtbCultivatePositionExam> positionExamList = positionExamService.list(positionExamWrapper);
            if (CollectionUtil.isNotEmpty(positionExamList)) {
                return new CanDeleteMsg(false, "有岗位学习关联该考试,请谨慎操作");
            }
            //检测考试是否与课程有关联
            LambdaQueryWrapper<FtbCultivatePositionCourseExam> courseExamWraper = new LambdaQueryWrapper<FtbCultivatePositionCourseExam>().eq(FtbCultivatePositionCourseExam::getExamId, examId).eq(FtbCultivatePositionCourseExam::getEnabledMark, 0);
            List<FtbCultivatePositionCourseExam> courseExamList = positionCourseExamService.list(courseExamWraper);
            if (CollectionUtil.isNotEmpty(courseExamList)) {
                return new CanDeleteMsg(false, "有岗位学习 课程关联该考试");
            }
        }
        return new CanDeleteMsg(true, "可以删除");
    }

    /**
     * 查询所有的岗位和考试
     *
     * @return
     */
    @Override
    public List<PositionAndGradesVO> queryPostAndRank() {
        return userApiV2Util.listAllPositionAndGradesByPositionName(null);

    }

    /**
     * 查询考试详情[考试 和 试卷]
     *
     * @param examId
     * @return
     */
    @Override
    public ExamAndPaperDetailVo queryExamDetail(String examId) {
        //1、查询考试信息
        FtbCultivateExam exam = queryExamInfo(examId);
        ExamAndPaperDetailVo vo = BeanUtil.copyProperties(exam, ExamAndPaperDetailVo.class);
        //1.1 补充岗位职能信息
        if (StringUtils.isNotEmpty(exam.getPostRankConf())) {
            vo.setPostAndPositionList(JSONUtil.toList(JSONUtil.parseArray(exam.getPostRankConf()), PostAndPosition.class));
        }
        //2、查看考试中试卷信息
        FtbCultivateTestPaper paper = queryPaper(vo.getPaperId());
        if (null != paper) {
            PaperVo paperVo = BeanUtil.copyProperties(paper, PaperVo.class);
            vo.setPaperVo(paperVo);
            //3、统计试卷的题目数量【各种题型的数量】
            paperVo.setQuestionAnalys(analysPaperQuestionCount(vo.getPaperId()));
        }

        return vo;
    }

    /**
     * APP开始考试，查询考试
     *
     * @param examId 考试ID
     * @return
     */
    @Override
    public ExamAppVo examInfo(String examId) {
        //1、查询和检测试卷是否存在
        FtbCultivateExam exam = queryExamInfo(examId);
        ExamAppVo vo = new ExamAppVo();
        FtbCultivateTestPaper paper = queryPaperNocheckDelete(exam.getPaperId());
        if (exam.getStatus() == 3) {
            vo.setIsNullify(1);
        }
        vo.setPaperName(paper.getName());
        vo.setId(exam.getId());
        vo.setExamId(exam.getExamId());
        vo.setExamTime(exam.getExamTime());
        vo.setStartTime(exam.getStartTime());
        vo.setEndTime(exam.getEndTime());
        vo.setPaperId(exam.getPaperId());
        vo.setExamName(exam.getExamName());
        vo.setExamlimitation(exam.getExamlimitation());
        vo.setStatus(exam.getStatus());
        vo.setDescription(exam.getDescription());
        vo.setExamType(exam.getExamType());
        vo.setTotleScore(paper.getTotalScore());
        //合格分数
        if (CourseEnums.ExamScoreCheckType.FIXED.getCode().equals(exam.getPassType())) {
            vo.setPassMark(exam.getPassMark());
        } else {
            vo.setPassMark(paper.getTotalScore() * exam.getPassMark() / 100);
        }
        //优秀分数
        if (CourseEnums.ExamScoreCheckType.FIXED.getCode().equals(exam.getExcellentType())) {
            vo.setExcellentMark(exam.getExcellentMark());
        } else {
            vo.setExcellentMark(paper.getTotalScore() * exam.getExcellentMark() / 100);
        }
        //常规考试 根据时间判断状态
        if (CourseEnums.ExamType.BASE.getCode().equals(exam.getExamType())) {
            if (exam.getStartTime() != null && exam.getEndTime() != null) {
                Date currentTime = new Date();
                if (currentTime.before(exam.getStartTime())) {
                    //考试还未开始
                    vo.setStatus(CourseEnums.ExamTimeStatus.NOT_STARTED.getCode());
                } else if (currentTime.after(exam.getEndTime())) {
                    //考试已经结束
                    vo.setStatus(CourseEnums.ExamTimeStatus.DONE.getCode());
                } else {
                    //考试正在进行中
                    vo.setStatus(CourseEnums.ExamTimeStatus.IN_PROGRESS.getCode());
                }
            } else {
                vo.setStatus(CourseEnums.ExamTimeStatus.IN_PROGRESS.getCode());
            }
        }
        //查询试卷题目统计数据
        vo.setQuestionNumMap(analysPaperQuestionCount(exam.getPaperId()));

        //考试配置
        vo.setMakeUpCount(exam.getMakeUpCount());
        vo.setWaterMark(exam.getWaterMark());
        vo.setCutScreen(exam.getCutScreen());
        vo.setMaxCutScreenCount(exam.getMaxCutScreenCount());
        vo.setScreenshot(exam.getScreenshot());
        vo.setCopyAndPaste(exam.getCopyAndPaste());
        vo.setOpenOverTime(exam.getOpenOverTime());
        vo.setOverTime(exam.getOverTime());
        vo.setAllowSelectDetail(exam.getAllowSelectDetail());
        vo.setAllowChangeLastQuestion(exam.getAllowChangeLastQuestion());
        vo.setNeedUpdate(exam.getNeedUpdate());
        return vo;
    }

    @Override
    public Map<String, PaperConfigReq.QuestionNum> analysPaperQuestionCount(String paperId) {
        //1、查询试卷中的题目
        List<FtbCultivateQuestion> questionVoList = paperService.queryQuestionListForPaperId(paperId);
        //2、初始化返回值
        Map<String, PaperConfigReq.QuestionNum> analyMap = QuestionAnalysisUtil.initAnalysQuestionCount();
        if (CollectionUtil.isNotEmpty(questionVoList)) {
            QuestionAnalysisUtil.analysQuestionCount(analyMap, questionVoList);
        }
        return analyMap;
    }

    /**
     * 查询并检查考试[是否存在或者是否删除]
     *
     * @param examId 考试ID
     */
    @Override
    public FtbCultivateExam queryExamInfo(String examId) {
        FtbCultivateExam exam = getById(examId);
        if (exam == null) {
            throw new RuntimeException("考试不存在");
        }
        if (CourseEnums.EnabledMarkType.INVALID.getCode().equals(exam.getEnabledMark())) {
            throw new RuntimeException("考试已删除");
        }
        return exam;
    }

    @Override
    public FtbCultivateExam queryExamAndPositionRelation(String examId, String positionId) {
        FtbCultivateExam exam = examService.queryExamInfo(examId);
        if (exam.getExamType() == 1) {//常规考试
            return null;
        }
        if (StringUtils.isEmpty(exam.getPostId())) {
            return null;
        }
        List<String> positionIdList = Arrays.asList(exam.getPostId().split(","));
        if (positionIdList.contains(positionId)) {
            return exam;
        }
        return null;
    }

    @Override
    @Transactional
    public Boolean bindExamAndPositionRelation(String examId, String positionId) {
        FtbCultivateExam exam = examService.queryExamInfo(examId);
        List<String> positionIdList = new ArrayList<>();
        if (StringUtils.isNotEmpty(exam.getPostId())) {
            positionIdList.addAll(Arrays.asList(exam.getPostId().split(",")));
        }
        if (positionIdList.contains(positionId)) {
            return true;
        }
        positionIdList.add(positionId);
        exam.setPostId(StringUtils.join(positionIdList, ","));
        List<PositionVO> positionEntityList = userExamUtil.getPostInfoList(positionIdList);
        List<PostAndPosition> postAndPositionList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(positionEntityList)) {
            for (PositionVO positionEntity : positionEntityList) {
                PostAndPosition postAndPosition = new PostAndPosition();
                postAndPosition.setId(positionEntity.getId());
                postAndPosition.setEnCode(positionEntity.getEnCode());
                postAndPosition.setPostName(positionEntity.getFullName());
                postAndPositionList.add(postAndPosition);
            }
        }
        exam.setPostRankConf(JSONUtil.toJsonStr(postAndPositionList));
        examService.updateById(exam);
        return true;
    }

    /**
     * 查询审核人列表
     *
     * @return
     */
    @Override
    public List<ExamBaseUser> queryReviewerUserList() {
        List<UserEntity> list = userApi.getList();
        if (CollectionUtil.isEmpty(list)) {
            return Collections.EMPTY_LIST;
        }
        //转换
        List<ExamBaseUser> baseUserList = new ArrayList<>();
        for (UserEntity userEntity : list) {
            ExamBaseUser examBaseUser = new ExamBaseUser();
            examBaseUser.setUserName(userEntity.getRealName());
            examBaseUser.setUserId(userEntity.getId());
            examBaseUser.setHeadLogo(userEntity.getHeadIcon());
            baseUserList.add(examBaseUser);
        }
        return baseUserList;
    }

    /**
     * 修改考试状态
     */
    @Override
    public void changeExamStatus() {
        //修改未开始
        baseMapper.update(null, new LambdaUpdateWrapper<FtbCultivateExam>().set(FtbCultivateExam::getStatus, CourseEnums.ExamTimeStatus.NOT_STARTED.getCode()).ge(FtbCultivateExam::getStartTime, new Date()).eq(FtbCultivateExam::getExamType, CourseEnums.ExamType.BASE.getCode()).ne(FtbCultivateExam::getStatus, CourseEnums.ExamTimeStatus.NOT_STARTED.getCode()).eq(FtbCultivateExam::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode()));
        //修改进行中
        baseMapper.update(null, new LambdaUpdateWrapper<FtbCultivateExam>().set(FtbCultivateExam::getStatus, CourseEnums.ExamTimeStatus.IN_PROGRESS.getCode()).le(FtbCultivateExam::getStartTime, new Date()).ge(FtbCultivateExam::getEndTime, new Date()).eq(FtbCultivateExam::getStatus, CourseEnums.ExamTimeStatus.NOT_STARTED.getCode()).eq(FtbCultivateExam::getExamType, CourseEnums.ExamType.BASE.getCode()).eq(FtbCultivateExam::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode()));
        //修改结束
        baseMapper.update(null, new LambdaUpdateWrapper<FtbCultivateExam>().set(FtbCultivateExam::getNeedUpdate, ExamUpdateStatus.NO_UPDATE.getCode()).set(FtbCultivateExam::getStatus, CourseEnums.ExamTimeStatus.DONE.getCode()).le(FtbCultivateExam::getEndTime, new Date()).eq(FtbCultivateExam::getStatus, CourseEnums.ExamTimeStatus.IN_PROGRESS.getCode()).eq(FtbCultivateExam::getExamType, CourseEnums.ExamType.BASE.getCode()).eq(FtbCultivateExam::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode()));
    }


    /**
     * 查询考试信息
     *
     * @param examIds 考试id列表
     * @return
     */
    private List<FtbCultivateExam> queryExamInfoForExamIds(List<String> examIds) {
        return baseMapper.selectBatchIds(examIds);
    }

    /**
     * 查询考试题目列表
     *
     * @param examId 考试id
     * @return
     */
    @Override
    public List<UserQuestionVo> queryExamQuestionList(String examId) {

        //1、查询考试
        FtbCultivateExam exam = queryExamInfo(examId);
        //2、查询试卷中的题目
        List<FtbCultivateQuestion> questionList = paperService.queryQuestionListForPaperId(exam.getPaperId());
        if (CollectionUtil.isEmpty(questionList)) {
            return Collections.EMPTY_LIST;
        }
        List<UserQuestionVo> userQuestionVoList = new ArrayList<>();
        List<FtbCultivateTestPaperQuestion> paperQuestionList = paperService.queryPaperQuestionRelationList(exam.getPaperId());
        Map<String, FtbCultivateTestPaperQuestion> questionMap = paperQuestionList.stream().collect(Collectors.toMap(FtbCultivateTestPaperQuestion::getQuestionId, Function.identity()));

        // 转换题目列表
        for (FtbCultivateQuestion ftbCultivateQuestion : questionList) {
            UserQuestionVo userQuestionVo = BeanUtil.copyProperties(ftbCultivateQuestion, UserQuestionVo.class);
            userQuestionVo.setQuestionId(ftbCultivateQuestion.getId());
            FtbCultivateTestPaperQuestion paperQuestion = questionMap.get(ftbCultivateQuestion.getId());
            userQuestionVo.setQuestionScore(paperQuestion.getScore());
            userQuestionVoList.add(userQuestionVo);
        }
        //3、获取题目选项
        List<String> questionIds = questionList.stream().map(FtbCultivateQuestion::getId).collect(Collectors.toList());
        List<FtbCultivateQuestionOption> questionOptionList = queryOptionListForQuestionIds(questionIds);
        if (CollectionUtil.isEmpty(questionOptionList)) {
            return userQuestionVoList;
        }

        Map<String, List<FtbCultivateQuestionOption>> questionOptionMap = questionOptionList.stream().collect(Collectors.groupingBy(FtbCultivateQuestionOption::getQuestionId));
        //填充题目选项
        for (UserQuestionVo userQuestionVo : userQuestionVoList) {
            List<FtbCultivateQuestionOption> questionOptionVoList = questionOptionMap.get(userQuestionVo.getId());
            if (CollectionUtil.isNotEmpty(questionOptionVoList)) {
                userQuestionVo.setQuestionOptionVoList(BeanUtil.copyToList(questionOptionVoList, QuestionOptionVo.class));
            }
        }


        return userQuestionVoList;
    }

    @Override
    public List<UserQuestionVo> queryExamQuestionListByUserExamId(String userExamId) {
        FtbCultivateExamUser examUser = examUserService.getById(userExamId);
        if (null == examUser) {
            throw new RuntimeException("用户考试信息不存在");
        }
        //1、查询考试
        FtbCultivateExam currExam = queryExamInfo(examUser.getExamId());
        if (currExam.getStatus().equals(3)) {
            throw new RuntimeException("考试已经作废");
        }
        FtbCultivateExam exam = userExamUtil.checkAndUpdateExam(currExam, examUser.getVersionBatch());

        //2、查询试卷中的题目
        FtbCultivateTestPaper testPaper = null;
        if (StringUtils.isNotEmpty(exam.getPaperInfo())) {
            testPaper = JSONUtil.toBean(exam.getPaperInfo(), FtbCultivateTestPaper.class);
        } else {
            testPaper = paperService.getById(exam.getPaperId());
        }
        if (null == testPaper) {
            throw new RuntimeException("试卷信息不存在");
        }
        Boolean isNewQuestion = checkIsGeneraNewQuestion(examUser, testPaper);
        List<FtbCultivateQuestion> questionList = new ArrayList<>();
        List<ExamQuestionBakVo> selectPaperQuestionList = new ArrayList<>();
        if (isNewQuestion == false) {
            selectPaperQuestionList = HistoryPaperUtils.convertQuestionList(exam.getCurrQuestionList());
            questionList = userExamUtil.queryHalfFullQuestionList(selectPaperQuestionList);
        } else {
            //生成随机试卷
            GeneralPaperQuestionVo newQuestionVo = userExamUtil.randomQuestion(exam);
            if (newQuestionVo.getSuccess()) {
                selectPaperQuestionList = newQuestionVo.getRandomList();
                questionList = newQuestionVo.getQuestionList();
            } else {
                selectPaperQuestionList = HistoryPaperUtils.convertQuestionList(exam.getCurrQuestionList());
                questionList = userExamUtil.queryHalfFullQuestionList(selectPaperQuestionList);
            }
        }
        if (CollectionUtil.isEmpty(questionList)) {
            return Collections.EMPTY_LIST;
        }
        List<UserQuestionVo> userQuestionVoList = new ArrayList<>();

        Map<String, ExamQuestionBakVo> questionMap = selectPaperQuestionList.stream().collect(Collectors.toMap(ExamQuestionBakVo::getQuestionId, Function.identity()));

        // 转换题目列表
        for (FtbCultivateQuestion ftbCultivateQuestion : questionList) {
            UserQuestionVo userQuestionVo = BeanUtil.copyProperties(ftbCultivateQuestion, UserQuestionVo.class);
            userQuestionVo.setQuestionId(ftbCultivateQuestion.getId());
            ExamQuestionBakVo paperQuestion = questionMap.get(ftbCultivateQuestion.getId());
            userQuestionVo.setQuestionScore(paperQuestion.getScore());
            userQuestionVoList.add(userQuestionVo);
        }
        //3、获取题目选项
        List<String> questionIds = questionList.stream().map(FtbCultivateQuestion::getId).collect(Collectors.toList());
        List<FtbCultivateQuestionOption> questionOptionList = queryOptionListForQuestionIds(questionIds);
        if (CollectionUtil.isEmpty(questionOptionList)) {
            return userQuestionVoList;
        }

        Map<String, List<FtbCultivateQuestionOption>> questionOptionMap = questionOptionList.stream().collect(Collectors.groupingBy(FtbCultivateQuestionOption::getQuestionId));
        //填充题目选项
        for (UserQuestionVo userQuestionVo : userQuestionVoList) {
            List<FtbCultivateQuestionOption> questionOptionVoList = questionOptionMap.get(userQuestionVo.getId());
            if (CollectionUtil.isNotEmpty(questionOptionVoList)) {
                userQuestionVo.setQuestionOptionVoList(BeanUtil.copyToList(questionOptionVoList, QuestionOptionVo.class));
            }
        }
        if (ExamQuestionShuffleEnum.SHUFFLE.getCode().equals(exam.getExamQuestionRandom())) {
            Collections.shuffle(userQuestionVoList);
        }
        return userQuestionVoList;
    }


    /**
     * 查询当前考试试卷信息
     *
     * @param examId 考试ID
     * @return
     */
    @Override
    public PaperDetailVo queryCurrExamPaperInfo(String examId) {
        PaperDetailVo paperDetailVo = new PaperDetailVo();
        //1、查询考试
        FtbCultivateExam exam = queryExamInfo(examId);

        //2、查询试卷中的题目
        FtbCultivateTestPaper testPaper = null;
        if (StringUtils.isNotEmpty(exam.getPaperInfo())) {
            testPaper = JSONUtil.toBean(exam.getPaperInfo(), FtbCultivateTestPaper.class);
        } else {
            testPaper = paperService.getById(exam.getPaperId());
        }

        if (null == testPaper) {
            throw new RuntimeException("试卷信息不存在");
        }
        paperDetailVo.setId(testPaper.getId());
        paperDetailVo.setName(testPaper.getName());
        paperDetailVo.setQuestionNumber(testPaper.getQuestionNumber());
        paperDetailVo.setTotalScore(testPaper.getTotalScore());
        paperDetailVo.setType(testPaper.getType());
        paperDetailVo.setPaperType(testPaper.getPaperType());
        paperDetailVo.setPaperId(testPaper.getPaperId());
        List<FtbCultivateTestPaperQuestion> paperQuestionRelationList = new ArrayList<>();
        if (StringUtils.isNotEmpty(exam.getCurrQuestionList())) {
            List<ExamQuestionBakVo> selectPaperQuestionList = HistoryPaperUtils.convertQuestionList(exam.getCurrQuestionList());
            if (CollectionUtil.isNotEmpty(selectPaperQuestionList)) {
                paperQuestionRelationList = BeanUtil.copyToList(selectPaperQuestionList, FtbCultivateTestPaperQuestion.class);
            }
        } else {
            paperQuestionRelationList = paperService.queryPaperQuestionRelationList(exam.getPaperId());

        }
        if (CollectionUtil.isEmpty(paperQuestionRelationList)) {
            return paperDetailVo;
        }

        Map<String, FtbCultivateTestPaperQuestion> testQuestionMap = paperQuestionRelationList.stream().collect(Collectors.toMap(FtbCultivateTestPaperQuestion::getQuestionId, Function.identity()));

        //3、根据关联的试卷题目ID，查询题目列表
        if (CollectionUtil.isNotEmpty(paperQuestionRelationList)) {
            List<String> questionIdList = paperQuestionRelationList.stream().map(FtbCultivateTestPaperQuestion::getQuestionId).collect(Collectors.toList());
            List<FtbCultivateQuestion> questionList = questionService.listByIds(questionIdList);
            if (CollectionUtil.isNotEmpty(questionList)) {
                List<AppQuestionVo> questionVoList = BeanUtil.copyToList(questionList, AppQuestionVo.class);
                paperService.fillQuestionOption(questionVoList);
                Map<String, List<AppQuestionVo>> map = new HashMap<>();
                for (AppQuestionVo questionVo : questionVoList) {
                    FtbCultivateTestPaperQuestion paperQuestion = testQuestionMap.get(questionVo.getId());
                    questionVo.setQuestionScore(paperQuestion.getScore());
                    String type = String.valueOf(questionVo.getType());
                    List<AppQuestionVo> list = map.get(type);
                    if (CollectionUtil.isEmpty(list)) {
                        list = new ArrayList<>();
                    }
                    list.add(questionVo);
                    map.put(type, list);
                }
                paperDetailVo.setQuestionMap(map);
            }
        }
        return paperDetailVo;
    }

    /**
     * 是否生成新题目
     *
     * @param examUser
     * @param testPaper
     * @return false-不需要  true-需要
     */
    private Boolean checkIsGeneraNewQuestion(FtbCultivateExamUser examUser, FtbCultivateTestPaper testPaper) {
        if (examUser.getUserExamCount() <= 1) {
            return false;
        }
        if (testPaper.getType().equals(1)) {
            return false;
        }
        return true;
    }

    /**
     * 根据题目ID 批量查询题目的选项
     *
     * @param questionIds 题目id集合
     * @return
     */
    private List<FtbCultivateQuestionOption> queryOptionListForQuestionIds(List<String> questionIds) {
        return questionOptionService.queryOptionListByQuestionIds(questionIds);
    }

    /**
     * 查询批阅人列表
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public List<String> queryExamReviewList(String userId) {
        String powerUserIds = personnelPerUtils.obtainTrainingApproverPermissions(userId);
        if (StringUtils.isEmpty(powerUserIds)) {
            return new ArrayList<>();
        }
        return Arrays.asList(powerUserIds.split(","));
    }

    /**
     * 查询所有的岗位
     *
     * @return
     */
    @Override
    public List<PositionVO> queryAllPostion() {
        QueryWrapper<FtbCultivatePosition> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(FtbCultivatePosition::getEnabledMark, 0);
        List<FtbCultivatePosition> list = ftbCultivatePositionMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        //获取id list
        List<String> postionList = list.stream().map(FtbCultivatePosition::getPostId).collect(Collectors.toList());
//        List<PositionEntity> entityList = positionApi.getPositionName(postionList);
        List<PositionVO> entityList = userApiV2Util.listPositionDetailInfoByIds(postionList, null);
        if (CollectionUtil.isEmpty(entityList)) {
            return new ArrayList<>();
        }
        return entityList;
    }

    /**
     * 根据考试id查询考试相关的历史试卷
     *
     * @param req
     * @return
     */
    @Override
    public List<WebReadOverExamAndPaperDetailVo> historyPaperList(WebQueryExamReadOverReq req) {
        List<WebReadOverExamAndPaperDetailVo> list = new ArrayList<>();
        FtbCultivateExam exam = examService.queryExamInfo(req.getExamId());
        list.add(userExamUtil.convertToWebReadOverExamAndPaperDetailVo(exam));


        List<FtbCultivateExamHistoryPaper> historyList = ftbCultivateExamHistoryPaperService.queryByExamId(req.getExamId());

        List<WebReadOverExamAndPaperDetailVo> historyVoList = userExamUtil.convertWebReadOverExamAndPaperDetailVoForHistory(historyList);
        if (CollectionUtil.isNotEmpty(historyVoList)) {
            list.addAll(historyVoList);
        }

        //查询待批阅人数量
        List<WaitReadOverNumVo> waitReadOverNumVoList = examUserService.queryWaitReadOverNum(req.getExamId());
        Map<String, WaitReadOverNumVo> numMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(waitReadOverNumVoList)) {
            for (WaitReadOverNumVo waitReadOverNumVo : waitReadOverNumVoList) {
                numMap.put(waitReadOverNumVo.getVersionBatch(), waitReadOverNumVo);
            }
        }
        for (WebReadOverExamAndPaperDetailVo vo : list) {
            WaitReadOverNumVo waitReadOverNumVo = numMap.get(vo.getVersionBatch());
            if (null != waitReadOverNumVo) {
                vo.setWaitReadOverNum(waitReadOverNumVo.getNum());
            }
        }
        return list;
    }

    /**
     * 查询考试历史试卷待考试的数量
     *
     * @param req
     * @return
     */
    @Override
    public Map<String, Integer> waitNumberForBatch(WebQueryExamReadOverReq req) {

        List<WaitReadOverNumVo> waitReadOverNumVoList = examUserService.queryWaitReadOverNum(req.getExamId());
        Map<String, Integer> numMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(waitReadOverNumVoList)) {
            for (WaitReadOverNumVo waitReadOverNumVo : waitReadOverNumVoList) {
                numMap.put(waitReadOverNumVo.getVersionBatch(), waitReadOverNumVo.getNum());
            }
        }

        return numMap;
    }

    /**
     * 考试作废-常规考试
     *
     * @param examId 考试ID
     * @return
     */
    @Override
    @Transactional
    public void nullify(String examId) {
        FtbCultivateExam oldExam = queryExamInfo(examId);
        CourseEnums.ExamType examType = CourseEnums.ExamType.fromCode(oldExam.getExamType());
        //1、根据考试ID查询考试基本信息
        if (CourseEnums.ExamType.BASE == examType) {
            if (CourseEnums.ExamTimeStatus.NOT_STARTED.getCode().equals(oldExam.getStatus())) {
                throw new RuntimeException("考试未开始不能作废");
            }

            if (CourseEnums.ExamTimeStatus.NULLIFY.getCode().equals(oldExam.getStatus())) {
                throw new RuntimeException("考试已经作废,不能重复操作");
            }
        } else {
            throw new RuntimeException("岗位学习考试不能作废");
        }
        oldExam.setStatus(CourseEnums.ExamTimeStatus.NULLIFY.getCode());
        oldExam.setNeedUpdate(ExamUpdateStatus.NO_UPDATE.getCode());
        baseMapper.updateById(oldExam);

        LambdaUpdateWrapper<FtbCultivateExamUser> updateWrapper = new LambdaUpdateWrapper<FtbCultivateExamUser>()
                .set(FtbCultivateExamUser::getIsJoinCount, ExamUserStatisticsEnums.NOT_PARTICIPATE.getCode())
                .in(FtbCultivateExamUser::getStatus, 3, 4, 5)
                .eq(FtbCultivateExamUser::getExamId, examId);
        examUserService.update(updateWrapper);

        LambdaUpdateWrapper<FtbCultivateExamUser> updateWrapper1 = new LambdaUpdateWrapper<FtbCultivateExamUser>()
                .set(FtbCultivateExamUser::getAppShow, 1)
                .set(FtbCultivateExamUser::getIsJoinCount, ExamUserStatisticsEnums.NOT_PARTICIPATE.getCode())
                .in(FtbCultivateExamUser::getStatus, 0, 1, 2)
                .eq(FtbCultivateExamUser::getExamId, examId);
        examUserService.update(updateWrapper1);

        //终止未开始和进行中
        List<FtbCultivateLearnTask> list = ftbCultivateLearnTaskExamMapper.queryTaskListForExam(examId);
        if (CollUtil.isNotEmpty(list)) {
            for (FtbCultivateLearnTask ftbCultivateLearnTask : list) {
                ftbCultivateLearnTaskInfoContentService.abort(ftbCultivateLearnTask.getId());
            }
        }
        //未发布的
        List<FtbCultivateLearnTask> listNoPublish = ftbCultivateLearnTaskExamMapper.queryTaskListForExamNoPublish(examId);
        if (CollUtil.isNotEmpty(listNoPublish)) {
            for (FtbCultivateLearnTask noPublish : listNoPublish) {
                //删除任务管理的考试
                QueryWrapper<FtbCultivateLearnTaskExam> taskExamUpdateWrapper = new QueryWrapper<>();
                taskExamUpdateWrapper.lambda()
                        .eq(FtbCultivateLearnTaskExam::getEnableMark, 0)
                        .eq(FtbCultivateLearnTaskExam::getTaskId, noPublish.getId())
                        .eq(FtbCultivateLearnTaskExam::getExamId, examId);
                ftbCultivateLearnTaskExamMapper.delete(taskExamUpdateWrapper);

                LambdaUpdateWrapper<FtbCultivateLearnTaskIdentification> taskIdentificationLambdaUpdateWrapper = new LambdaUpdateWrapper<FtbCultivateLearnTaskIdentification>()
                        .set(FtbCultivateLearnTaskIdentification::getIdentificationRule, 0)
                        .eq(FtbCultivateLearnTaskIdentification::getTaskId, noPublish.getId());
                learnTaskIdentificationMapper.update(null, taskIdentificationLambdaUpdateWrapper);
            }

        }


    }

    /**
     * 根据考试id查询任务列表
     *
     * @param examId 考试ID
     * @return
     */
    @Override
    public List<FtbCultivateLearnTask> checkNullify(String examId) {
        List<FtbCultivateLearnTask> list = ftbCultivateLearnTaskExamMapper.queryTaskListForExamAll(examId);
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        return list;
    }

    /**
     * 根据岗位查询是否考试完成才能够鉴定的标志
     *
     * @param positionId 岗位 id
     * @return 岗位考试合格后才能进行鉴定, 0否 1是
     */
    @Override
    public Integer queryExamAndIdentifyConfig(String positionId) {
        Integer integer = baseMapper.queryExamAndIdentifyConfig(positionId);
        if (null == integer) {
            integer = 0;
        }
        return integer;
    }


    /**
     * 初始化考试数据(兼容旧数据)
     *
     * @return
     */
    @Override
    @Transactional
    public List<String> initOldExamData() {

        List<FtbCultivateExam> examList = baseMapper.selectList(Wrappers.lambdaQuery(FtbCultivateExam.class).eq(FtbCultivateExam::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode()));
        if (CollectionUtil.isEmpty(examList)) {
            return Collections.emptyList();
        }
        List<String> retList = new ArrayList<>();
        for (FtbCultivateExam exam : examList) {
            if (StringUtils.isNotEmpty(exam.getCurrQuestionList())) {
                continue;
            }
            FtbCultivateTestPaper paper = paperService.getById(exam.getPaperId());
            if (paper == null) {
                continue;
            }
            //修改考试
            FtbCultivateExam updateExam = new FtbCultivateExam();
            updateExam.setId(exam.getId());
            updateExam.setPaperId(exam.getPaperId());
            try {
                countQuestionTypeNum(paper);
            } catch (Exception e) {
                log.error("修改考试数据失败", e);
            }
            updateExam.setPaperInfo(JSONUtil.toJsonStr(paper));
            fillExamPaperQuestionOld(updateExam);
            baseMapper.updateById(updateExam);
            retList.add(exam.getId());
        }
        return retList;

    }

    /**
     * 旧数据清洗，删除已经删除的考试 的相关考试记录
     */
    @Override
    public void deleteExamUserForDeleteExam() {

        List<FtbCultivateExam> examList = baseMapper.selectList(Wrappers.lambdaQuery(FtbCultivateExam.class).eq(FtbCultivateExam::getExamType, CourseEnums.ExamType.POSITION.getCode())
                .eq(FtbCultivateExam::getEnabledMark, CourseEnums.EnabledMarkType.INVALID.getCode()));
        if (CollectionUtil.isEmpty(examList)) {
            return;
        }
        for (FtbCultivateExam exam : examList) {
            //岗位考试 全部删除
            deleteAllExamUserExamId(exam.getId());
        }
    }


}
