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.DateUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
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.base.ActionResult;
import jnpf.cultivate.mapper.FtbCultivateExamFrequncyLogMapper;
import jnpf.cultivate.mapper.FtbCultivateExamUserMapper;
import jnpf.cultivate.mapper.FtbCultivatePositionCourseExamMapper;
import jnpf.cultivate.service.*;
import jnpf.cultivate.utils.HistoryPaperUtils;
import jnpf.cultivate.utils.UserApiV2Util;
import jnpf.cultivate.utils.UserExamUtil;
import jnpf.cultivate.v2.util.CultivateMqSendUtil;
import jnpf.enums.cultivate.ExamRetakeFrequencyEnum;
import jnpf.model.cultivate.CultivatePage;
import jnpf.model.cultivate.dto.learn.BatchCommonCountDto;
import jnpf.model.cultivate.dto.statistics.*;
import jnpf.model.cultivate.po.exam.*;
import jnpf.model.cultivate.po.paper.FtbCultivateTestPaper;
import jnpf.model.cultivate.po.paper.FtbCultivateTestPaperQuestion;
import jnpf.model.cultivate.po.question.FtbCultivateQuestion;
import jnpf.model.cultivate.req.exam.*;
import jnpf.model.cultivate.resp.*;
import jnpf.model.cultivate.vo.common.InnerPowerUserVO;
import jnpf.model.cultivate.vo.position.web.FtbCultivatePositionExamPersonVO;
import jnpf.model.cultivate.vo.position.web.FtbCultivatePositionExamVO;
import jnpf.model.cultivate.vo.promotion.FtbCultivatePromotionVO;
import jnpf.model.enums.CourseEnums;
import jnpf.model.enums.ExamConfigEnums;
import jnpf.model.enums.ExamUserStatisticsEnums;
import jnpf.model.personnels.dto.authoritys.PermissionsCacheDTO;
import jnpf.model.personnels.dto.staff.roster.WorkerGroupDataDto;
import jnpf.model.personnels.po.FtbPersonnelsPermissions;
import jnpf.permission.OrganizeApi;
import jnpf.permission.PositionApi;
import jnpf.permission.RoleApi;
import jnpf.permission.UserApi;
import jnpf.permission.entity.PositionEntity;
import jnpf.permission.entity.RoleEntity;
import jnpf.permission.entity.UserEntity;
import jnpf.permission.model.position.PositionGradesInfoBoundVO;
import jnpf.permission.model.position.PositionGradesInfoVO;
import jnpf.permission.vo.v2.grades.GradeVO;
import jnpf.permission.vo.v2.organzie.OrganizeGeneralDetailVO;
import jnpf.permission.vo.v2.position.PositionVO;
import jnpf.permission.vo.v2.user.UserBoundVO;
import jnpf.permission.vo.v2.user.UserPageListVO;
import jnpf.personnels.utils.PersonnelOrgUtils;
import jnpf.personnels.utils.PersonnelPerUtils;
import jnpf.util.ConstantUtil;
import jnpf.util.QuestionAnalysisUtil;
import jnpf.util.UploaderUtil;
import jnpf.util.UserProvider;
import lombok.extern.slf4j.Slf4j;
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.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class FtbCultivateExamUserServiceImpl extends ServiceImpl<FtbCultivateExamUserMapper, FtbCultivateExamUser> implements FtbCultivateExamUserService {
    private static final List<String> EMPTY_USER_LIST = List.of("-1");
    /**
     * 用户服务
     */
    @Autowired
    private UserApi userApi;

    /**
     * 角色服务
     */
    @Autowired
    private RoleApi roleApi;

    /**
     * 岗位服务
     */
    @Autowired
    private PositionApi positionApi;

    @Autowired
    private OrganizeApi organizeApi;

    @Autowired
    private PersonnelPerUtils personnelPerUtils;

    /**
     * 考试详情服务
     */
    @Autowired
    private FtbCultivateExamUserDetailService userDetailService;
    /**
     * 考试服务
     */
    @Autowired
    private FtbCultivateExamService examService;

    @Autowired
    private CultivateExamSettingService cultivateExamSettingService;

    /**
     * 考试服务（试卷）
     */
    @Autowired
    private FtbCultivateExamHistoryPaperService examHistoryPaperService;

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

    /**
     * 用户考试服务
     */
    @Autowired
    private FtbCultivateExamUserMapper examUserMapper;


    @Autowired
    private PersonnelOrgUtils personnelOrgUtils;


    @Autowired
    private UserExamUtil userExamUtil;

    @Autowired
    private FtbCultivatePromotionMemberService promotionMemberService;

    @Autowired
    private FtbCultivateExamFrequncyLogMapper ftbCultivateExamFrequncyLogMapper;

    @Autowired
    private FtbCultivatePositionCourseExamMapper ftbCultivatePositionCourseExamMapper;

    @Autowired
    private UserApiV2Util userApiV2Util;


    @Autowired
    private CultivateMqSendUtil cultivateMqSendUtil;

    /**
     * 获取分页列表
     *
     * @param req
     * @return
     */
    @Override
    public PageInfo<ExamListUserVo> getPageList(QueryExamUserReq req) {
        String loginUserId = UserProvider.getLoginUserId();
        //构建分页
        Page<FtbCultivateExamUser> page = Page.of(req.getCurrentPage(), req.getPageSize());
        //构建查询 查询条件是 匹配 考试名称 或者试卷ID
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .eq(FtbCultivateExamUser::getExamId, req.getExamId())
                .eq(req.getStatus() != null, FtbCultivateExamUser::getStatus, req.getStatus())
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode())
                .eq(FtbCultivateExamUser::getVersionBatch, req.getVersionBatch())
                .orderByDesc(FtbCultivateExamUser::getCreatorTime);
        Page<FtbCultivateExamUser> queryPage = baseMapper.selectPage(page, wrapper);
        List<FtbCultivateExamUser> records = queryPage.getRecords();
        //转换查询对象
        List<ExamListUserVo> list = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(records)) {
            InnerPowerUserVO innerPowerUserVO = userApiV2Util.getLoginManagerUserIdsForEncode();
            FtbCultivateExam exam = examService.getById(req.getExamId());
            //查询我的角色
            for (FtbCultivateExamUser entity : records) {
                ExamListUserVo vo = new ExamListUserVo();
                vo.setId(entity.getId());
                vo.setScore(entity.getScore());
                vo.setExamid(entity.getExamId());
                vo.setDuration(entity.getDuration());
                vo.setUserId(entity.getUserId());
                vo.setStatus(entity.getStatus());
                vo.setUserStartTime(entity.getUserStartTime());
                vo.setFinishtime(entity.getFinishTime());
                if (CourseEnums.ExamStatus.WAIT_CHECK.getCode().equals(vo.getStatus())) {
                    if (innerPowerUserVO.getCode().equals(1)) {
                        if (innerPowerUserVO.getUserIds().contains(vo.getUserId())) {
                            vo.setCanReviewer(true);
                        } else {
                            vo.setCanReviewer(false);
                        }
                    } else if (innerPowerUserVO.getCode().equals(0)) {
                        vo.setCanReviewer(true);
                    } else if (innerPowerUserVO.getCode().equals(2)) {
                        vo.setCanReviewer(false);
                    }
                }
                vo.setScoreRatio(entity.getScoreRatio());
                if (CourseEnums.ExamStatus.PASS.getCode().equals(vo.getStatus()) || CourseEnums.ExamStatus.NO_PASS.getCode().equals(vo.getStatus()) || CourseEnums.ExamStatus.VERY_PASS.getCode().equals(vo.getStatus())) {
                    if (entity.getScoreRatio() == null) {
                        if (exam.getCurrTotalScore() != null && exam.getCurrTotalScore() > 0) {
                            vo.setScoreRatio(new BigDecimal(entity.getScore()).divide(new BigDecimal(exam.getCurrTotalScore()), 2, BigDecimal.ROUND_HALF_UP));
                        }
                    }
                }
                vo.setUserExamCount(entity.getUserExamCount());
                vo.setUserExamResultValid(entity.getUserExamResultValid());
                list.add(vo);
            }


            fillExamUserInfo(list);
            //填充组织和岗位
            fillOrgAndPost(list);

        }
        //构建分页返回数据
        PageInfo<ExamListUserVo> pageInfo = new PageInfo<>();
        pageInfo.setList(list);
        pageInfo.setPageSize((int) queryPage.getSize());
        pageInfo.setPageNum((int) queryPage.getCurrent());
        pageInfo.setTotal((int) queryPage.getTotal());
        return pageInfo;
    }

    /**
     * 查询指定用户的考试列表
     *
     * @param req
     * @return
     */
    @Override
    public PageInfo<MyExamListVo> queryExamList(QueryCultivateExamReq req) {
        List<String> positionIdList = new ArrayList<>();
        if (StringUtils.isNotEmpty(req.getPositionId())) {
            positionIdList.addAll(Arrays.asList(req.getPositionId().split(",")));
        }
        //构建分页
        Page<FtbCultivateExamUser> page = Page.of(req.getCurrentPage(), req.getPageSize());
        //构建查询 查询条件是 匹配 考试名称 或者试卷ID
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .eq(FtbCultivateExamUser::getUserId, req.getUserId())
                .in(FtbCultivateExamUser::getStatus,
                        CourseEnums.ExamStatus.PASS.getCode(),
                        CourseEnums.ExamStatus.NO_PASS.getCode(),
                        CourseEnums.ExamStatus.VERY_PASS.getCode()
                )
                .in(CollectionUtil.isNotEmpty(positionIdList), FtbCultivateExamUser::getRelationPositionId, positionIdList)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode())
                .eq(FtbCultivateExamUser::getIsJoinCount, ExamUserStatisticsEnums.PARTICIPATE.getCode())
                .orderByDesc(FtbCultivateExamUser::getCreatorTime);
        Page<FtbCultivateExamUser> queryPage = baseMapper.selectPage(page, wrapper);
        List<FtbCultivateExamUser> records = queryPage.getRecords();
        //转换查询对象
        List<MyExamListVo> list = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(records)) {

            records.forEach(entity -> {
                MyExamListVo vo = new MyExamListVo();
                vo.setId(entity.getId());
                vo.setFinishtime(entity.getFinishTime());
                vo.setScore(entity.getScore());
                vo.setExamId(entity.getExamId());
                vo.setDuration(entity.getDuration());

                if (StringUtils.isNotEmpty(entity.getExamId())) {
                    FtbCultivateExam exam = examService.getById(entity.getExamId());
                    if (null != exam) {
                        vo.setExamName(exam.getExamName());
                        vo.setExamType(exam.getExamType());
                        vo.setExamTime(exam.getExamTime());
                    }
                }
                if (StringUtils.isNotEmpty(entity.getPaperId())) {
                    FtbCultivateTestPaper paper = paperService.getById(entity.getPaperId());
                    if (null != paper) {
                        vo.setPaperName(paper.getName());
                        vo.setExamTotleScore(paper.getTotalScore());
                    }
                }
                vo.setExamSource(entity.getExamSource());
                vo.setStatus(entity.getStatus());
                if (vo.getExamSource() == 1 || vo.getExamSource() == 2) {
                    if (StringUtils.isNotEmpty(entity.getRelationPositionId())) {
                        //查询岗位
//                        PositionEntity positionEntity = positionApi.queryInfoById(entity.getRelationPositionId());
                        PositionVO positionEntity = userApiV2Util.infoPosition(entity.getRelationPositionId(), null);
                        if (null != positionEntity) {
                            vo.setCurrPostName(positionEntity.getFullName());
                        }
                    }
                }
                list.add(vo);
            });
        }
        //构建分页返回数据
        PageInfo<MyExamListVo> pageInfo = new PageInfo<>();
        pageInfo.setList(list);
        pageInfo.setPageSize((int) queryPage.getSize());
        pageInfo.setPageNum((int) queryPage.getCurrent());
        pageInfo.setTotal((int) queryPage.getTotal());
        return pageInfo;
    }

    /**
     * 考试按照组织维度统计信息
     *
     * @param dto 查询信息
     * @return
     */
    @Override
    public List<ExamStatisticsForOrgVo> queryExamStatisticsForOrg(ExamStatisticsForOrgDTO dto, List<String> userIds) {

        List<String> powerOrgList = userApiV2Util.queryPowerOrgList();
        if (CollUtil.isEmpty(powerOrgList)) {
            return new ArrayList<>();
        }

        if (StringUtils.isEmpty(dto.getOrgIds())) {
            return new ArrayList<>();
        }


        List<String> selectOrgList = new ArrayList<>(Arrays.asList(dto.getOrgIds().split(",")));

        if (dto.getIsNext() == 1) {
            List<OrganizeGeneralDetailVO> organizeGeneralDetailVOS = userApiV2Util.organizesOrHaveChildByOrganizeIds(selectOrgList, true, null);
            if (CollectionUtil.isNotEmpty(organizeGeneralDetailVOS)) {
                List<String> collect = organizeGeneralDetailVOS.stream().map(OrganizeGeneralDetailVO::getId).collect(Collectors.toList());
                selectOrgList.addAll(collect);
            }
        }
        List<String> intersection = UserApiV2Util.getIntersection(powerOrgList, selectOrgList);
        if (CollUtil.isEmpty(intersection)) {
            return new ArrayList<>();
        }
        selectOrgList = intersection;
        List<UserPageListVO> userListForOrgIds = userApiV2Util.getUserListForOrgIds(selectOrgList, null);
        if (CollUtil.isEmpty(userListForOrgIds)) {
            return new ArrayList<>();
        }
        Map<String, UserPageListVO> userPageListVOMap = userListForOrgIds.stream().collect(Collectors.toMap(UserPageListVO::getId, v -> v));
        InnerExamStatisticsForOrgDTO innerExamStatisticsForOrgDTO = BeanUtil.copyProperties(dto, InnerExamStatisticsForOrgDTO.class);


        innerExamStatisticsForOrgDTO.setSelectUserIds(userListForOrgIds.stream().map(UserPageListVO::getId).collect(Collectors.toList()));
        List<AppExamListVo> queryList = baseMapper.countForOrg(innerExamStatisticsForOrgDTO);

        if (CollectionUtil.isEmpty(queryList)) {
            return new ArrayList<>();
        }
        changeCurrOrg(userPageListVOMap, queryList);


        //查询组织
        Map<String, OrganizeGeneralDetailVO> organizeEntityMap = userApiV2Util.organizesByOrganizeIdsReturenMap(selectOrgList, null);

//userOrgList分组

        Map<String, List<AppExamListVo>> orgIdToExamUserMap = queryList.stream().collect(Collectors.groupingBy(AppExamListVo::getUserOrgList));

        List<ExamStatisticsForOrgVo> retList = new ArrayList<>();
        for (Map.Entry<String, List<AppExamListVo>> entry : orgIdToExamUserMap.entrySet()) {
            String orgId = entry.getKey(); // 组织id
            List<AppExamListVo> examUserList = new ArrayList<>(entry.getValue());
            //按照考试分组
            Map<String, List<AppExamListVo>> examGroupUserMap = examUserList.stream()
                    .collect(Collectors.groupingBy(AppExamListVo::getExamId));
            for (Map.Entry<String, List<AppExamListVo>> examGroupEntity : examGroupUserMap.entrySet()) {
                String examId = examGroupEntity.getKey(); // 当前键
                String examName = "";
                Integer examType = null;
                String examTypeName = "";
                List<AppExamListVo> examGroupList = examGroupEntity.getValue(); // 当前值（List<AppExamListVo>）
                if (CollectionUtil.isNotEmpty(examGroupList)) {
                    examName = examGroupList.get(0).getExamName();
                    examType = examGroupList.get(0).getExamType();
                    if (examGroupList.get(0).getExamType() == 1) {
                        examTypeName = "岗位学习考试";
                    } else {
                        examTypeName = "自定义考试";
                    }
                }
                //按照试卷分组
                Map<String, List<AppExamListVo>> paperGroupUserMap = examGroupList.stream()
                        .collect(Collectors.groupingBy(AppExamListVo::getPaperId));
                //遍历 paperGroupUserMap
                for (Map.Entry<String, List<AppExamListVo>> paperGroupEntity : paperGroupUserMap.entrySet()) {
                    String paperId = paperGroupEntity.getKey(); // 当前键
                    String paperName = "";
                    String paperTypeName = "";
                    Integer paperType = null;
                    List<AppExamListVo> paperGroupList = paperGroupEntity.getValue(); // 当前值（List<AppExamListVo>）
                    if (CollectionUtil.isNotEmpty(paperGroupList)) {
                        paperName = paperGroupList.get(0).getPaperName();
                        paperType = paperGroupList.get(0).getPaperType();
                        if (paperGroupList.get(0).getPaperType() == 1) {
                            paperTypeName = "岗位学习试卷";
                        } else {
                            paperTypeName = "常规试卷";
                        }
                    }
                    StatisticsResultDto statisticsResultDto = QuestionAnalysisUtil.statisticeLvForAppExam(paperGroupList);
                    ExamStatisticsForOrgVo vo = new ExamStatisticsForOrgVo();
                    vo.setOrgId(orgId);
                    OrganizeGeneralDetailVO organizeEntity = organizeEntityMap.get(orgId);
                    if (null != organizeEntity) {
                        vo.setOrgName(organizeEntity.getName());
                        vo.setOrgCode(organizeEntity.getEnCode());
                    }
                    vo.setExamId(examId);
                    vo.setExamName(examName);
                    vo.setExamType(examType);
                    vo.setExamTypeName(examTypeName);

                    vo.setPaperId(paperId);
                    vo.setPaperName(paperName);
                    vo.setPaperTypeName(paperTypeName);
                    vo.setPaperType(paperType);

                    vo.setTotleNum(String.valueOf(statisticsResultDto.getTotle()));
                    vo.setExcellentNum(String.valueOf(statisticsResultDto.getExcellent()));
                    vo.setPassNum(String.valueOf(statisticsResultDto.getPass()));
                    vo.setNoPassNum(String.valueOf(statisticsResultDto.getNoPass()));

                    vo.setNoPassRate(String.valueOf(statisticsResultDto.getNoPassLv()));
                    vo.setPassRate(String.valueOf(statisticsResultDto.getPassLv()));
                    vo.setExcellentRate(String.valueOf(statisticsResultDto.getExcellentLv()));
                    retList.add(vo);
                }

            }

        }
        return retList;
    }

    private void changeCurrOrg(Map<String, UserPageListVO> userPageListVOMap, List<AppExamListVo> queryList) {
        for (AppExamListVo appExamListVo : queryList) {
            UserPageListVO userPageListVO = userPageListVOMap.get(appExamListVo.getUserId());
            if (userPageListVO != null) {
                appExamListVo.setUserOrgList(userPageListVO.getOrganizeId());
            }
        }
    }

    private InnerAnalysisOrgInfoDto analysisOrgInfo(List<AppExamListVo> currExamUserList, List<String> selectOrgList, Boolean selectALL) {
        Set<String> allOrgSet = new HashSet<>();//所有组织集合
        Set<String> allPaperIdSet = new HashSet<>();//所有试卷ID
        Map<String, Set<AppExamListVo>> orgIdToExamUserMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(currExamUserList)) {
            for (AppExamListVo examUser : currExamUserList) {
                allPaperIdSet.add(examUser.getPaperId());
                if (StringUtils.isNotEmpty(examUser.getUserOrgList())) {
                    String[] splits = examUser.getUserOrgList().split(",");
                    if (selectALL) {
                        for (String split : splits) {
                            allOrgSet.add(split);
                            Set<AppExamListVo> itemSet = orgIdToExamUserMap.get(split);
                            if (null == itemSet) {
                                itemSet = new HashSet<>();
                            }
                            itemSet.add(examUser);
                            orgIdToExamUserMap.put(split, itemSet);
                        }
                    } else {
                        for (String split : splits) {
                            if (selectOrgList.contains(split)) {
                                allOrgSet.add(split);
                                Set<AppExamListVo> itemSet = orgIdToExamUserMap.get(split);
                                if (null == itemSet) {
                                    itemSet = new HashSet<>();
                                }
                                itemSet.add(examUser);
                                orgIdToExamUserMap.put(split, itemSet);
                            }
                        }
                    }
                }
            }
        }
        InnerAnalysisOrgInfoDto dto = new InnerAnalysisOrgInfoDto();
        dto.setAllOrgSet(allOrgSet);
        dto.setAllPaperIdSet(allPaperIdSet);
        dto.setOrgIdToExamUserMap(orgIdToExamUserMap);
        return dto;
    }

    /**
     * 考试按照个人维度统计信息
     *
     * @param dto 查询信息
     * @return
     */
    @Override
    public PageInfo<ExamStatisticsForPersonVo> queryExamStatisticsForPerson(ExamStatisticsForPersonDTO dto) {

        if (null == dto.getCurrentPage() || null == dto.getPageSize()) {
            throw new RuntimeException("请传入分页信息");
        }

        InnerExamStatisticsForPersonDTO innerDto = BeanUtil.copyProperties(dto, InnerExamStatisticsForPersonDTO.class);
        //0待考试，1待批阅，2已逾期，3合格，4不合格 5、优秀
        List<Integer> innerStatus = buildExamStatus(dto);
        innerDto.setInnerStatus(innerStatus);

        List<String> innerUserIds = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(dto.getUserIds()) && CollectionUtil.isNotEmpty(dto.getPersionPositonIds())) {
            List<String> stringList = queryUserIdsForPostionIds(dto.getPersionPositonIds());
            if (CollectionUtil.isEmpty(stringList)) {
                return new PageInfo<>();
            }
            innerUserIds = dto.getUserIds().stream().filter(stringList::contains).collect(Collectors.toList());
            if (CollectionUtil.isEmpty(innerUserIds)) {
                return new PageInfo<>();
            }
            innerUserIds.addAll(dto.getUserIds());
        } else if (CollectionUtil.isNotEmpty(dto.getUserIds())) {
            innerUserIds.addAll(dto.getUserIds());
        } else if (CollectionUtil.isNotEmpty(dto.getPersionPositonIds())) {
            List<String> stringList = queryUserIdsForPostionIds(dto.getPersionPositonIds());
            if (CollectionUtil.isEmpty(stringList)) {
                return new PageInfo<>();
            }
            innerUserIds.addAll(stringList);
        }
        if (StringUtils.isNotEmpty(dto.getOrgId())) {
            String[] split = dto.getOrgId().split(",");
            List<UserPageListVO> userListForOrgIds = userApiV2Util.getUserListForOrgIds(Arrays.asList(split), null);
            if (CollUtil.isEmpty(userListForOrgIds)) {
                return new PageInfo<>();
            }
            if (CollUtil.isEmpty(innerUserIds)) {
                innerUserIds = userListForOrgIds.stream().map(UserPageListVO::getId).collect(Collectors.toList());
            } else {
                List<String> intersection = UserApiV2Util.getIntersection(userListForOrgIds.stream().map(UserPageListVO::getId).collect(Collectors.toList()), innerUserIds);
                if (CollUtil.isEmpty(intersection)) {
                    return new PageInfo<>();
                }
                innerUserIds = intersection;
            }
        }
        innerDto.setInnerUserIds(innerUserIds);


        List<String> innerPaperIds = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(dto.getPaperIds())) {
            innerPaperIds = dto.getPaperIds();
        }
        innerDto.setInnerPaperIds(innerPaperIds);
        InnerPowerUserVO innerPowerUserVO = userApiV2Util.getLoginManagerUserIdsForEncode();
        if (innerPowerUserVO.getCode() == 1) {
            if (CollUtil.isNotEmpty(innerDto.getInnerUserIds())) {
                List<String> intersection = UserApiV2Util.getIntersection(innerPowerUserVO.getUserIds(), innerDto.getInnerUserIds());
                if (CollUtil.isEmpty(intersection)) {
                    PageInfo<ExamStatisticsForPersonVo> pageInfo = new PageInfo<>();
                    pageInfo.setList(new ArrayList<>());
                    pageInfo.setPageSize(dto.getPageSize());
                    pageInfo.setPageNum(dto.getCurrentPage());
                    pageInfo.setTotal(0);
                    return pageInfo;
                } else {
                    innerDto.setInnerUserIds(intersection);
                }
            } else {
                innerDto.setInnerUserIds(innerPowerUserVO.getUserIds());
            }
        } else if (innerPowerUserVO.getCode() == 2) {
            PageInfo<ExamStatisticsForPersonVo> pageInfo = new PageInfo<>();
            pageInfo.setList(new ArrayList<>());
            pageInfo.setPageSize(dto.getPageSize());
            pageInfo.setPageNum(dto.getCurrentPage());
            pageInfo.setTotal(0);
            return pageInfo;
        }
//        innerDto.setLeaverUserIds(userApiV2Util.queryLeaveUserId());


        Page<ExamStatisticsForPersonVo> queryPage = baseMapper.queryExamStatisticsForPerson(Page.of(dto.getCurrentPage(), dto.getPageSize()),
                innerDto);
        List<ExamStatisticsForPersonVo> list = queryPage.getRecords();
        if (CollectionUtil.isNotEmpty(list)) {
            List<String> tempUserId = new ArrayList<>();
            List<String> tempPostionId = new ArrayList<>();
            for (ExamStatisticsForPersonVo examStatisticsForPersonVo : list) {
                tempUserId.add(examStatisticsForPersonVo.getUserId());
                if (examStatisticsForPersonVo.getExamSource() == 1 || examStatisticsForPersonVo.getExamSource() == 2) {
                    tempPostionId.add(examStatisticsForPersonVo.getRelationPositionId());
                }
            }

            Map<String, UserBoundVO> userPrimaryBoundBatch = userApiV2Util.getUserPrimaryBoundBatch(tempUserId, null);
            List<PositionVO> positionVOS = userApiV2Util.listPositionDetailInfoByIds(tempPostionId, null);
            Map<String, PositionVO> tempPositionMap = new HashMap<>();
            if (CollectionUtil.isNotEmpty(positionVOS)) {
                tempPositionMap = positionVOS.stream()
                        .collect(Collectors.toMap(PositionVO::getId, Function.identity()));
            }
            for (ExamStatisticsForPersonVo examStatisticsForPersonVo : list) {
                if (examStatisticsForPersonVo.getExamSource() == 1 || examStatisticsForPersonVo.getExamSource() == 2) {
                    PositionVO positionEntity = tempPositionMap.get(examStatisticsForPersonVo.getRelationPositionId());
                    if (null != positionEntity) {
                        examStatisticsForPersonVo.setStudyPostionName(positionEntity.getFullName());
                    }
                }
                UserBoundVO userPrimaryBoundOne = userPrimaryBoundBatch.get(examStatisticsForPersonVo.getUserId());
                if (userPrimaryBoundOne != null) {
                    WorkerGroupDataDto workerGroupDataDto = new WorkerGroupDataDto();
                    workerGroupDataDto.setAffiliatedOrg(userPrimaryBoundOne.getOrganizeEnCode());
                    workerGroupDataDto.setAffiliatedPosition(userPrimaryBoundOne.getPositionEnCode());
                    workerGroupDataDto.setAffiliatedRank(userPrimaryBoundOne.getGradeId());
                    workerGroupDataDto.setAffiliatedOrgName(userPrimaryBoundOne.getOrganizeName());
                    workerGroupDataDto.setAffiliatedPositionName(userPrimaryBoundOne.getPositionName());
                    workerGroupDataDto.setAffiliatedRankName(userPrimaryBoundOne.getGradeName());
                    workerGroupDataDto.setOrgEncode(userPrimaryBoundOne.getOrganizeEnCode());
                    workerGroupDataDto.setPositionEncode(userPrimaryBoundOne.getPositionEnCode());
                    examStatisticsForPersonVo.setUserOrgList(List.of(workerGroupDataDto));
                    examStatisticsForPersonVo.setUserName(userPrimaryBoundOne.getUserName());
                } else {
                    examStatisticsForPersonVo.setUserOrgList(new ArrayList<>());
                }
                if (null != examStatisticsForPersonVo.getExamTime()) {
                    examStatisticsForPersonVo.setExamTime(examStatisticsForPersonVo.getExamTime() / 60);
                }
            }
        }

        PageInfo<ExamStatisticsForPersonVo> pageInfo = new PageInfo<>();
        pageInfo.setList(list);
        pageInfo.setPageSize((int) queryPage.getSize());
        pageInfo.setPageNum((int) queryPage.getCurrent());
        pageInfo.setTotal((int) queryPage.getTotal());
        return pageInfo;
    }

    private List<String> queryUserIdsForPostionIds(List<String> persionPositonIds) {
        List<UserBoundVO> voList = userApiV2Util.getUserListForPositions(persionPositonIds, null);
        if (CollectionUtil.isEmpty(voList)) {
            return new ArrayList<>();
        }
        return voList.stream().map(UserBoundVO::getId).collect(Collectors.toList());
    }


    /**
     * 根据职等ID统计合格率
     *
     * @param positionId
     * @return
     */

    @Override
    public BigDecimal queryExamStatisticsForPositionId(String positionId) {

        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .select(FtbCultivateExamUser::getId, FtbCultivateExamUser::getStatus, FtbCultivateExamUser::getUserId, FtbCultivateExamUser::getExamId, FtbCultivateExamUser::getExamSource,
                        FtbCultivateExamUser::getRelationCourseExamId, FtbCultivateExamUser::getRelationPositionExamId, FtbCultivateExamUser::getRelationRankId, FtbCultivateExamUser::getPaperId)
                .notIn(FtbCultivateExamUser::getStatus, CourseEnums.ExamStatus.OVERDUE.getCode(), CourseEnums.ExamStatus.WAIT.getCode())
                .in(FtbCultivateExamUser::getExamSource, 1, 2)
                .in(FtbCultivateExamUser::getRelationPositionId, positionId)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        List<FtbCultivateExamUser> examUserList = baseMapper.selectList(wrapper);

        StatisticsResultDto curr = QuestionAnalysisUtil.statisticeLv(examUserList);
        return new BigDecimal(curr.getPassLv());
    }

    /**
     * 处理考试用户的岗位数据，兼容老数据
     */
    @Override
    @Deprecated
    public void dealExamUserPositionForOldData() {

        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .select(FtbCultivateExamUser::getId, FtbCultivateExamUser::getStatus, FtbCultivateExamUser::getUserId, FtbCultivateExamUser::getExamId, FtbCultivateExamUser::getExamSource,
                        FtbCultivateExamUser::getRelationCourseExamId, FtbCultivateExamUser::getRelationPositionExamId, FtbCultivateExamUser::getRelationRankId, FtbCultivateExamUser::getPaperId,
                        FtbCultivateExamUser::getUserOrgList, FtbCultivateExamUser::getRelationPositionId)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        List<FtbCultivateExamUser> examUserList = baseMapper.selectList(wrapper);
        if (CollectionUtil.isNotEmpty(examUserList)) {
            for (FtbCultivateExamUser examUser : examUserList) {
                if (StringUtils.isEmpty(examUser.getRelationPositionId()) && StringUtils.isNotEmpty(examUser.getRelationRankId())) {
                    //查询岗位
                    if (examUser.getExamSource() == 1 || examUser.getExamSource() == 2) {
                        ActionResult<PositionGradesInfoVO> gradesInfo = null;
                        try {
                            gradesInfo = positionApi.getGradesInfo(examUser.getRelationRankId());
                            if (null != gradesInfo && null != gradesInfo.getData()) {
                                examUser.setRelationPositionId(gradesInfo.getData().getPositionId());
                            }
                        } catch (Exception e) {
                            log.error("查询岗位信息失败");
                        }
                    }
                }

                //查询组织
                List<String> selectOrgList = organizeApi.getOrganizeIdsByUserId(examUser.getUserId());
                if (CollectionUtil.isNotEmpty(selectOrgList)) {
                    examUser.setUserOrgList(String.join(",", selectOrgList));
                }
                baseMapper.updateById(examUser);
            }
        }
    }

    private List<Integer> buildExamStatus(ExamStatisticsForPersonDTO dto) {
        List<Integer> innerStatus = new ArrayList<>();
        if (null != dto.getExamStatus() && dto.getExamStatus() == 1) {
            innerStatus.add(0);
            innerStatus.add(2);
        } else if (null != dto.getExamStatus() && dto.getExamStatus() == 2) {
            if (null != dto.getExamResult() && dto.getExamResult() == 0) {
                innerStatus.add(1);
                innerStatus.add(3);
                innerStatus.add(4);
                innerStatus.add(5);
            } else if (null != dto.getExamResult() && dto.getExamResult() == 1) {
                innerStatus.add(5);
            } else if (null != dto.getExamResult() && dto.getExamResult() == 2) {
                innerStatus.add(3);
            } else if (null != dto.getExamResult() && dto.getExamResult() == 3) {
                innerStatus.add(4);
            } else {
                innerStatus.add(1);
                innerStatus.add(3);
                innerStatus.add(4);
                innerStatus.add(5);
            }
        } else {
            if (null != dto.getExamResult() && dto.getExamResult() == 0) {
                innerStatus.add(0);
                innerStatus.add(1);
                innerStatus.add(2);
                innerStatus.add(3);
                innerStatus.add(4);
                innerStatus.add(5);
            } else if (null != dto.getExamResult() && dto.getExamResult() == 1) {
                innerStatus.add(5);
            } else if (null != dto.getExamResult() && dto.getExamResult() == 2) {
                innerStatus.add(3);
            } else if (null != dto.getExamResult() && dto.getExamResult() == 3) {
                innerStatus.add(4);
            } else {
                innerStatus.add(0);
                innerStatus.add(1);
                innerStatus.add(2);
                innerStatus.add(3);
                innerStatus.add(4);
                innerStatus.add(5);
            }
        }
        return innerStatus;
    }


    /**
     * @param exam
     * @param examUser
     * @param userId
     * @return false 不能批阅，true 可以批阅
     */
    public Boolean checkMyIsRevierverDynamic(FtbCultivateExam exam, FtbCultivateExamUser examUser, String userId, PermissionsCacheDTO permissionsCacheDTO) {
        //阅卷人
        Set<String> reviewerUserIdList = new HashSet<>();
        if (StringUtils.isNotEmpty(exam.getReviewerAppoint())) {
            reviewerUserIdList.addAll(Arrays.asList(exam.getReviewerAppoint().split(",")));
            if (reviewerUserIdList.contains(userId)) {
                return true;
            }
        }
        List<String> localOrganizeIds = null;
        if ("0".equals(exam.getReviewer())) {
            //查询当前用户的直接主管
            UserBoundVO bossByUserIdSimple = userApiV2Util.getBossByUserIdSimple(examUser.getUserId(), null);
            if (bossByUserIdSimple != null && StringUtils.isNotEmpty(bossByUserIdSimple.getLeaderId())) {
                reviewerUserIdList.add(bossByUserIdSimple.getLeaderId());
            }
            if (reviewerUserIdList.contains(userId)) {
                return true;
            }
        }
        //todo 下一班 优化查询权
        List<String> powerUserIdsList = 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 (reviewerUserIdList.contains(userId)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 查询用户有批阅权限的用户集合
     *
     * @param userId              用户id
     * @param permissionsCacheDTO 批阅权限
     * @param localOrganizeIds    用户的组织id集合
     * @return
     */
    @Override
    public List<String> getPowerUserIdsForPermission(String userId, PermissionsCacheDTO permissionsCacheDTO, List<String> localOrganizeIds) {
        Map<FtbPersonnelsPermissions, List<String>> allUserListIdsMap = permissionsCacheDTO.getAllUserListIdsMap();
        Map<FtbPersonnelsPermissions, List<String>> allOrgListMap = permissionsCacheDTO.getAllOrgListMap();
        List<String> retUserListIds = new ArrayList<>();

        for (Map.Entry<FtbPersonnelsPermissions, List<String>> entry : allUserListIdsMap.entrySet()) {
            FtbPersonnelsPermissions key = entry.getKey();
            List<String> values = entry.getValue();
            if (values.contains(userId)) {
                retUserListIds.add(key.getUserId());
            }
        }
        if (localOrganizeIds == null) {
            localOrganizeIds = organizeApi.getOrganizeIdsByUserId(userId);
        }

        for (Map.Entry<FtbPersonnelsPermissions, List<String>> entry : allOrgListMap.entrySet()) {
            FtbPersonnelsPermissions key = entry.getKey();
            List<String> values = entry.getValue();
            if (personnelPerUtils.haveIntersection(localOrganizeIds, values)) {
                retUserListIds.add(key.getUserId());
            }
        }
        return retUserListIds;
    }

    /**
     * 查询任务考试结果
     *
     * @param taskId 任务id
     * @param userId 用户ID
     * @return -1：没有考试记录
     * 0:未完成考试
     * 1：已经完成考试(待批阅，未出考试结果)
     * 3合格
     * 4不合格
     * 5优秀
     */
    @Override
    public Integer queryExamResultForTask(String taskId, String userId) {
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .eq(FtbCultivateExamUser::getUserId, userId)
                .eq(FtbCultivateExamUser::getExamSource, 4)
                .eq(FtbCultivateExamUser::getRelationTaskId, taskId)
                .eq(FtbCultivateExamUser::getEnabledMark, 1)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode()).orderByDesc(FtbCultivateExamUser::getCreatorTime);
        List<FtbCultivateExamUser> examUserList = baseMapper.selectList(wrapper);

        if (CollectionUtil.isEmpty(examUserList)) {
            return -1;
        }
        FtbCultivateExamUser examUser = examUserList.get(0);
        //（0待考试，1待批阅，2已逾期，3合格，4不合格 5优秀）
        if (examUser.getStatus() == 0 || examUser.getStatus() == 2) {
            return 0;
        }
        if (examUser.getStatus() == 1) {
            return 1;
        }
        return examUser.getStatus();
    }

    /***
     * 查询任务考试结果
     * @param taskId 任务id
     * @param userId 用户id
     * @return
     */
    @Override
    public List<FtbCultivateExamUser> queryExamResultForTaskInfo(String taskId, String userId) {
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .eq(FtbCultivateExamUser::getUserId, userId)
                .eq(FtbCultivateExamUser::getExamSource, 4)
                .eq(FtbCultivateExamUser::getRelationTaskId, taskId)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode()).orderByDesc(FtbCultivateExamUser::getCreatorTime);
        return baseMapper.selectList(wrapper);
    }


    /**
     * 填充组织和岗位
     *
     * @param list
     */
    private void fillOrgAndPost(List<ExamListUserVo> list) {

        List<String> userIds = new ArrayList<>();
        for (ExamListUserVo examListUserVo : list) {
            userIds.add(examListUserVo.getUserId());
        }
        Map<String, List<PositionGradesInfoBoundVO>> map = queryUserOrganizationByUserIds(userIds);
        for (ExamListUserVo examListUserVo : list) {
            List<PositionGradesInfoBoundVO> userOrganizationVoList = map.get(examListUserVo.getUserId());
            examListUserVo.setUserOrganizationVoList(userOrganizationVoList);
        }
    }

    /**
     * 查询用户考试详情
     *
     * @param userExamId 用户考试ID
     * @return
     */
    @Override
    public FtbCultivateExamUser getInfo(String userExamId) {
        //查看是否有记录
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .eq(FtbCultivateExamUser::getId, userExamId)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        FtbCultivateExamUser examUser = baseMapper.selectOne(wrapper);
        if (null == examUser) {
            throw new RuntimeException("用户考试信息不存在");
        }
        return examUser;
    }

    /**
     * 删除用户考试
     *
     * @param userExamId 用户考试ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteData(String userExamId) {
        //1、查询检测用户考试
        FtbCultivateExamUser examUser = queryAndCheckUserExam(userExamId);
        //2、删除考试
        examUser.setDeleteTime(new Date());
        examUser.setEnabledMark(CourseEnums.EnabledMarkType.INVALID.getCode());
        baseMapper.updateById(examUser);
        //3、删除考试记录
        LambdaUpdateWrapper<FtbCultivateExamUserDetail> updateWrapper = new LambdaUpdateWrapper<FtbCultivateExamUserDetail>()
                .set(FtbCultivateExamUserDetail::getEnabledMark, CourseEnums.EnabledMarkType.INVALID.getCode())
                .eq(FtbCultivateExamUserDetail::getBatch, examUser.getBatch())
                .eq(FtbCultivateExamUserDetail::getUserExamId, examUser.getId())
                .eq(FtbCultivateExamUserDetail::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        userDetailService.update(updateWrapper);

        delExamCountRecord(examUser.getUserId(), examUser.getExamId());
    }

    /**
     * 检测用户考试是否可以删除
     *
     * @param userExamId 用户考试ID
     * @return
     */
    @Override
    public CanDeleteMsg checkUserExamCanDelete(String userExamId) {
        FtbCultivateExamUser examUser = queryAndCheckUserExam(userExamId);
//        if (CourseEnums.ExamStatus.WAIT_CHECK.getCode().equals(examUser.getStatus())) {
//            return new CanDeleteMsg(false, "考试已完成,等待批阅", examUser);
//        }
//        if (CourseEnums.ExamStatus.PASS.getCode().equals(examUser.getStatus())
//                || CourseEnums.ExamStatus.VERY_PASS.getCode().equals(examUser.getStatus())) {
//            return new CanDeleteMsg(false, "考试已经合格", examUser);
//        }
        return new CanDeleteMsg(true, "可以删除", examUser);
    }

    /**
     * 批阅用户考试
     *
     * @param req
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void readOver(ReadOverExamReq req) {
        String loginUserId = UserProvider.getLoginUserId();
        //1、检测
        FtbCultivateExamUser examUser = queryAndCheckUserExam(req.getUserExamId());
        if (CourseEnums.ExamStatus.PASS.getCode().equals(examUser.getStatus())) {
            throw new RuntimeException("考试已合格，不能再次批阅");
        }

        if (CourseEnums.ExamStatus.VERY_PASS.getCode().equals(examUser.getStatus())) {
            throw new RuntimeException("考试已合格，不能再次批阅");
        }
        if (CourseEnums.ExamStatus.WAIT.getCode().equals(examUser.getStatus())
                || CourseEnums.ExamStatus.OVERDUE.getCode().equals(examUser.getStatus())) {
            throw new RuntimeException("用户未考试，不能批阅");
        }
        //2、查询考试用户的题目列表
        List<FtbCultivateExamUserDetail> examUserDetailList = queryUserQuestion(examUser.getId(), examUser.getUserId(), examUser.getBatch());
        if (CollectionUtil.isEmpty(examUserDetailList)) {
            throw new RuntimeException("用户考试的试题信息为空，不能批阅");
        }
        //3、查看考试信息和试卷
        FtbCultivateExam exam = examService.getById(examUser.getExamId());
        if (exam == null) {
            throw new RuntimeException("用户考试的信息不存在，不能批阅");
        }
        if (exam.getStatus().equals(3)) {
            userExamUtil.updateUserExamNullify(examUser.getId());
            return;
        }

        if (loginUserId.equals(examUser.getUserId())) {
            throw new RuntimeException("不能批阅自己的考试");
        }
        //不用再查询历史表 再用户的考试记录中保存有相关配置
//        exam = userExamUtil.queryExamByIdAndBatch(exam.getId(), examUser.getVersionBatch());

        int readOverScore = 0;//批阅分数
        int correctCount = 0;//正确数量
        List<FtbCultivateExamUserDetail> batchUpdateList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(req.getAnswerScoreList())) {
            //转换成map questionId->FtbCultivateExamUserDetail
            Map<String, FtbCultivateExamUserDetail> userDetailMap = examUserDetailList.stream().collect(Collectors.toMap(FtbCultivateExamUserDetail::getQuestionId, detail -> detail));
            //处理用户的答题结果
            List<ReadOverExamReq.QuestionAnswerScore> answerScoreList = req.getAnswerScoreList();
            for (ReadOverExamReq.QuestionAnswerScore answerScore : answerScoreList) {
                FtbCultivateExamUserDetail userDetail = userDetailMap.get(answerScore.getQuestionId());
                if (null == userDetail) {
                    log.error("用户考试的试题信息为空,questionId={}", answerScore.getQuestionId());
                    continue;
                }
                if (CourseEnums.QuestionType.SINGLE.getCode().equals(userDetail.getType())
                        || CourseEnums.QuestionType.MULTI.getCode().equals(userDetail.getType())
                        || CourseEnums.QuestionType.ONE_OR_MULTI.getCode().equals(userDetail.getType())
                        || CourseEnums.QuestionType.JUDGE.getCode().equals(userDetail.getType())) {
                    continue;
                }
                //满分算对
                if (answerScore.getScore().equals(userDetail.getQuestionScore())) {
                    correctCount++;
                    userDetail.setIsRight(CourseEnums.IsRightAnswer.YES.getCode());
                } else {
                    userDetail.setIsRight(CourseEnums.IsRightAnswer.NO.getCode());
                }
                if (answerScore.getScore() < 0) {
                    throw new RuntimeException("[" + userDetail.getContent() + "]的评分不能小于0分");
                }
                if (answerScore.getScore() > userDetail.getQuestionScore()) {
                    throw new RuntimeException("[" + userDetail.getContent() + "]的评分不能大于" + userDetail.getQuestionScore() + "分");
                }
                userDetail.setUserScore(answerScore.getScore());
                readOverScore += answerScore.getScore();
                batchUpdateList.add(userDetail);
            }
        }
        examUser.setReadOverScore(readOverScore);
        //4、批量修改考试用户详情
        userDetailService.saveOrUpdateBatch(batchUpdateList);
        //5、修改考试的批阅分数和总分数 和根据分数判断考试是否合格
        FtbCultivateExamUser updateExamUser = new FtbCultivateExamUser();
        updateExamUser.setReviewerUserId(loginUserId);
        updateExamUser.setId(examUser.getId());
        updateExamUser.setExamId(examUser.getExamId());
        updateExamUser.setUserId(examUser.getUserId());

        updateExamUser.setCorrectCount(examUser.getCorrectCount() + correctCount);//题目正确数量
        updateExamUser.setReadOverScore(readOverScore);//批阅分数
        updateExamUser.setScore(examUser.getAutoScore() + readOverScore);//总分数
        int paperTotalScore = examUser.getTotalScore();
        if (examUser.getTotalScore() == 0) {
            paperTotalScore = exam.getCurrTotalScore();
        }
        updateExamUser.setStatus(QuestionAnalysisUtil.calculateUserExamStatus(exam, paperTotalScore, updateExamUser.getScore()));
        BigDecimal score = BigDecimal.valueOf(updateExamUser.getScore());
        BigDecimal totalScore = BigDecimal.valueOf(paperTotalScore);
        BigDecimal divide = score.divide(totalScore, 2, RoundingMode.HALF_UP);
        updateExamUser.setScoreRatio(divide);
        updateExamUser.setLastModifyTime(new Date());

        baseMapper.updateById(updateExamUser);
//        if (updateExamUser.getStatus().equals(CourseEnums.ExamStatus.PASS.getCode())
//                || updateExamUser.getStatus().equals(CourseEnums.ExamStatus.VERY_PASS.getCode())) {
//            if (StringUtils.isNotEmpty(examUser.getRelationPositionId())) {
//                String courseId = "";
//                Integer issuanceType = 0;
//                if (examUser.getExamSource() == 1) {
//                    //岗位学习课程
//                    issuanceType = 0;
//                    FtbCultivatePositionCourseExam ftbCultivatePositionCourseExam = ftbCultivatePositionCourseExamMapper.selectById(examUser.getRelationCourseExamId());
//                    courseId = ftbCultivatePositionCourseExam.getCourseId();
//                } else if (examUser.getExamSource() == 2) {
//                    //岗位学习
//                    issuanceType = 1;
//                }
//                userExamUtil.publishExam(examUser.getUserId(), examUser.getRelationPositionId(), issuanceType, courseId);
//            }
//        }
//        if (updateExamUser.getStatus().equals(CourseEnums.ExamStatus.PASS.getCode())
//                || updateExamUser.getStatus().equals(CourseEnums.ExamStatus.NO_PASS.getCode())
//                || updateExamUser.getStatus().equals(CourseEnums.ExamStatus.VERY_PASS.getCode())) {
//            if (StringUtils.isNotEmpty(examUser.getRelationPositionId()) && examUser.getExamSource() == 2) {
//                userExamUtil.publishExamCallBack(examUser.getUserId(), examUser.getRelationPositionId(), updateExamUser.getStatus());
//                // updateExamUser.setExamIdentifyConfig(integer);
//            } else if (StringUtils.isNotEmpty(examUser.getRelationTaskId())) {
//                userExamUtil.publishTaskExamCallBack(examUser.getUserId(), examUser.getRelationTaskId(), updateExamUser.getStatus());
//            }
//        }

        cultivateMqSendUtil.sendExamMessage(updateExamUser);
    }


    /**
     * 获取用户考试详情
     *
     * @param userExamId          用户考试ID
     * @param isQueryQuestionList 是否查询题目
     * @return
     */
    @Override
    public UserExamDetailVo getUserExamDetail(String userExamId, Boolean isQueryQuestionList) {
        //查用户基本信息
        UserExamDetailVo vo = queryBaseUserExamInfo(userExamId);
        //查看用户的考试题目详情
        if (isQueryQuestionList) {
            List<FtbCultivateExamUserDetail> questionList = queryUserQuestion(vo.getId(), vo.getUserId(), vo.getBatch());
            List<UserQuestionVo> userQuestionVoList = new ArrayList<>();
            for (FtbCultivateExamUserDetail question : questionList) {
                UserQuestionVo userQuestionVo = BeanUtil.copyProperties(question, UserQuestionVo.class);
                //转换题目选项
                if (StringUtils.isNotEmpty(question.getQuestionOption())) {
                    userQuestionVo.setQuestionOptionVoList(JSON.parseArray(question.getQuestionOption(), QuestionOptionVo.class));
                }
                userQuestionVoList.add(userQuestionVo);
            }
            vo.setQuestionMap(convertUserQuestionListForType(userQuestionVoList));
        }
        //查询晋升通道

        List<PositionGradesInfoBoundVO> userOrganizationList = vo.getUserOrganizationList();
        List<AppPromotionVO> promotionList = new ArrayList<>();
        for (PositionGradesInfoBoundVO positionGradesInfoBoundVO : userOrganizationList) {
            AppPromotionVO appPromotionVO = BeanUtil.copyProperties(positionGradesInfoBoundVO, AppPromotionVO.class);
            FtbCultivatePromotionVO promotionVO = promotionMemberService.queryPromotionByUser(vo.getUserId(), positionGradesInfoBoundVO.getPositionId());
            if (promotionVO != null) {
                appPromotionVO.setPromotionVO(promotionVO);
            }
            promotionList.add(appPromotionVO);
        }
        vo.setPromotion(promotionList);
        if (CourseEnums.ExamType.POSITION.getCode().equals(vo.getExamType())) {
            String relationRankId = vo.getRelationRankId();
            if (StringUtils.isNotEmpty(relationRankId)) {
                try {

                    GradeVO gradesInfoData = userApiV2Util.infoGrade(relationRankId, vo.getTenantId());
                    if (null != gradesInfoData) {

                        vo.setCurrPostName("");
                        vo.setCurrRankName(gradesInfoData.getFullName());
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            } else if (StringUtils.isNotEmpty(vo.getRelationPositionId())) {
//                PositionEntity positionEntity = positionApi.queryInfoById(vo.getRelationPositionId());
                PositionVO positionEntity = userApiV2Util.infoPosition(vo.getRelationPositionId(), null);
                if (null != positionEntity) {
                    vo.setCurrPostName(positionEntity.getFullName());
                }
            }
        }

        return vo;
    }

    /**
     * 根据用户ID 补充用户信息
     *
     * @param vo
     * @param <T>
     */
    private <T extends ExamBaseUser> void fillUserInfoForUserId(T vo) {
        UserEntity userEntity = userApi.getInfoById(vo.getUserId());
        if (userEntity != null) {
            vo.setUserName(userEntity.getRealName());
            vo.setHeadLogo(UploaderUtil.uploaderImg(userEntity.getHeadIcon()));
        }
    }

    private Map<String, List<UserQuestionVo>> convertUserQuestionListForType(List<UserQuestionVo> userQuestionVoList) {
        Map<String, List<UserQuestionVo>> questionMap = new HashMap<>();
        for (UserQuestionVo userQuestionVo : userQuestionVoList) {
            String type = String.valueOf(userQuestionVo.getType());
            List<UserQuestionVo> temp = questionMap.get(type);
            if (CollectionUtil.isEmpty(temp)) {
                temp = new ArrayList<>();
            }
            temp.add(userQuestionVo);
            questionMap.put(type, temp);
        }
        return questionMap;
    }


    /**
     * 查询用户绑定的组织 岗位职等
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public List<PositionGradesInfoBoundVO> queryUserOrganization(String userId) {
        if (StringUtils.isEmpty(userId)) {
            return CollectionUtil.newArrayList();
        }
        UserBoundVO userBoundVO = userApiV2Util.getUserPrimaryBoundOne(userId, null);

        if (userBoundVO == null) {
            return CollectionUtil.newArrayList();
        }
        List<PositionGradesInfoBoundVO> orgPositionInfoList = new ArrayList<>();
        PositionGradesInfoBoundVO vo = new PositionGradesInfoBoundVO();
        vo.setOrganizeIds(List.of(userBoundVO.getOrganizeId()));
        vo.setOrganizeNames(List.of(userBoundVO.getOrganizeName()));
        vo.setUserId(userId);
        vo.setPositionId(userBoundVO.getPositionId());
        vo.setPositionName(userBoundVO.getPositionName());
        vo.setPositionGradesId(userBoundVO.getGradeId());
        vo.setPositionGradesName(userBoundVO.getGradeName());
        orgPositionInfoList.add(vo);
        return orgPositionInfoList;
    }

    /**
     * 根据用户id批量查询用户的岗位信息
     *
     * @param userIds 用户ID 集合
     * @return
     */
    @Override
    public Map<String, List<PositionGradesInfoBoundVO>> queryUserOrganizationByUserIds(List<String> userIds) {
        if (CollectionUtil.isEmpty(userIds)) {
            return new HashMap<>();
        }
        userIds = userExamUtil.uniqueStringList(userIds);
        Map<String, UserBoundVO> userPrimaryBoundBatch = userApiV2Util.getUserPrimaryBoundBatch(userIds, null);

        if (CollectionUtil.isEmpty(userPrimaryBoundBatch)) {
            return new HashMap<>();
        }
        Map<String, List<PositionGradesInfoBoundVO>> map = new HashMap<>();
        //遍历userPrimaryBoundBatch
        for (Map.Entry<String, UserBoundVO> entry : userPrimaryBoundBatch.entrySet()) {
            String userId = entry.getKey();
            UserBoundVO value = entry.getValue();
            PositionGradesInfoBoundVO vo = new PositionGradesInfoBoundVO();
            vo.setOrganizeIds(List.of(value.getOrganizeId()));
            vo.setOrganizeNames(List.of(value.getOrganizeName()));
            vo.setPositionId(value.getPositionId());
            vo.setPositionName(value.getPositionName());
            vo.setPositionGradesId(value.getGradeId());
            vo.setPositionGradesName(value.getGradeName());
            map.put(userId, List.of(vo));
        }

        return map;
    }

    /**
     * 查询考试人数
     *
     * @param examId
     * @return
     */
    @Override
    public Long queryCompleteNumForExamId(String examId) {
        //查看是否有记录
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .eq(FtbCultivateExamUser::getExamId, examId)
                .notIn(FtbCultivateExamUser::getStatus, 1, 2)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        return baseMapper.selectCount(wrapper);
    }

    /**
     * 查询用户考试记录基本信息
     *
     * @param userExamId 用户考试记录ID
     * @return
     */
    @Override
    public UserExamDetailVo queryBaseUserExamInfo(String userExamId) {
        UserExamDetailVo vo = new UserExamDetailVo();
        //查询用户的考试汇总信息
        FtbCultivateExamUser examUser = queryAndCheckUserExam(userExamId);
        //查询考试信息
        FtbCultivateExam exam = examService.getById(examUser.getExamId());
        if (exam.getStatus().equals(3)) {
            vo.setIsNullify(1);
        } else {
            vo.setIsNullify(0);
        }
        if (examUser.getVersionBatch().equals(exam.getVersionBatch())) {
            if (CourseEnums.ExamStatus.WAIT.getCode().equals(examUser.getStatus()) || CourseEnums.ExamStatus.OVERDUE.getCode().equals(examUser.getStatus())) {
                vo.setNeedUpdate(exam.getNeedUpdate());
            }
        }
        exam = userExamUtil.checkAndUpdateExam(exam, examUser.getVersionBatch());
        vo.setId(examUser.getId());
        vo.setScore(examUser.getScore());
        vo.setExamId(examUser.getExamId());
        vo.setDuration(examUser.getDuration());
        vo.setUserId(examUser.getUserId());
        vo.setStatus(examUser.getStatus());
        vo.setReadOverScore(examUser.getReadOverScore());
        vo.setAutoScore(examUser.getAutoScore());
        vo.setCorrectCount(examUser.getCorrectCount());
        vo.setPaperId(examUser.getPaperId());
        vo.setUserStartTime(examUser.getUserStartTime());
        vo.setStartTime(examUser.getStartTime());
        vo.setEndTime(examUser.getEndTime());
        vo.setFinishtime(examUser.getFinishTime());
        vo.setBatch(examUser.getBatch());
        vo.setExamSource(examUser.getExamSource());
        vo.setRelationPositionExamId(examUser.getRelationPositionExamId());
        vo.setRelationCourseExamId(examUser.getRelationCourseExamId());
        vo.setRelationRankId(examUser.getRelationRankId());
        vo.setRelationPositionId(examUser.getRelationPositionId());
        //查询考试信息
        if (CourseEnums.ExamStatus.WAIT.getCode().equals(examUser.getStatus()) || CourseEnums.ExamStatus.OVERDUE.getCode().equals(examUser.getStatus())) {
            vo.setExamTotleScore(exam.getCurrTotalScore());
            vo.setQuestionNumber(exam.getCurrQuestionNumber());
        } else {
            vo.setExamTotleScore(examUser.getTotalScore());
            if (examUser.getQuestionNumber() == null || examUser.getQuestionNumber() == 0) {
                LambdaQueryWrapper<FtbCultivateExamUserDetail> examUserDetailLambdaQueryWrapper = new LambdaQueryWrapper<FtbCultivateExamUserDetail>()
                        .eq(FtbCultivateExamUserDetail::getUserExamId, examUser.getId())
                        .eq(FtbCultivateExamUserDetail::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
                long count = userDetailService.count(examUserDetailLambdaQueryWrapper);
                vo.setQuestionNumber((int) count);
            } else {
                vo.setQuestionNumber(examUser.getQuestionNumber());
            }
        }
        //考试相关的岗位
        if (StringUtils.isNotEmpty(exam.getPostId())) {
            List<PositionVO> positionEntityList = userApiV2Util.listPositionDetailInfoByIds(Arrays.asList(exam.getPostId().split(",")), null);
            List<PostAndPosition> postAndPositionList = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(positionEntityList)) {
                for (PositionVO positionEntity : positionEntityList) {
                    PostAndPosition postAndPosition = new PostAndPosition();
                    postAndPosition.setId(positionEntity.getId());
                    postAndPosition.setPostName(positionEntity.getFullName());
                    postAndPosition.setEnCode(positionEntity.getEnCode());//todo岗位编码
                    postAndPositionList.add(postAndPosition);
                }
            }
            vo.setExamRelationPositionList(postAndPositionList);
        }
        vo.setExamName(exam.getExamName());
        vo.setExamType(exam.getExamType());
        vo.setExamTime(exam.getExamTime());
        vo.setExamlimitation(exam.getExamlimitation());
        vo.setPassMark(exam.getPassMark());
        vo.setPassType(exam.getPassType());
        vo.setExcellentType(exam.getExcellentType());
        vo.setExcellentMark(exam.getExcellentMark());
        vo.setDescription(exam.getDescription());
        //补充试卷题型数量统计
        List<ExamQuestionBakVo> questionList = new ArrayList<>();
        if (StringUtils.isNotEmpty(exam.getCurrQuestionList())) {
            questionList = HistoryPaperUtils.convertQuestionList(exam.getCurrQuestionList());
        } else {
            questionList = paperService.queryConfigQuestionList(exam.getPaperId());
        }
        List<FtbCultivateQuestion> halfFullQuestion = userExamUtil.queryHalfFullQuestionList(questionList);
        vo.setQuestionNumMap(HistoryPaperUtils.analysPaperQuestionCount(halfFullQuestion));
        //补充用户信息
        fillUserInfoForUserId(vo);
        List<PositionGradesInfoBoundVO> userOrganizationList = queryUserOrganization(vo.getUserId());
        vo.setUserOrganizationList(userOrganizationList);
        //计算用户需要考多少分才及格
        int needScore = 0;
        Integer passType = exam.getPassType();//合格分数类型（1固定分，2百分比)
        Integer passMark = exam.getPassMark();//合格分数
        if (CourseEnums.ExamScoreCheckType.FIXED.getCode().equals(passType)) {
            needScore = passMark;
        } else {
            needScore = QuestionAnalysisUtil.calculateScore(passMark, vo.getExamTotleScore());
        }
        vo.setNeedExamPassScore(needScore);
        //计算用户需要考多少分才优秀
        int needExcellentScore = 0;
        Integer excellentType = exam.getExcellentType();//优秀分数类型（1固定分，2百分比)
        Integer excellentMark = exam.getExcellentMark();//优秀分数
        if (CourseEnums.ExamScoreCheckType.FIXED.getCode().equals(excellentType)) {
            needExcellentScore = excellentMark;
        } else {
            needExcellentScore = QuestionAnalysisUtil.calculateScore(excellentMark, vo.getExamTotleScore());
        }
        vo.setNeedExamExcellentScore(needExcellentScore);
        return vo;
    }

    /**
     * 根据考试id查询排行版
     *
     * @param examId 考试id
     * @return
     */
    @Override
    public UserRankingVo queryMyRank(String examId) {
        String loginUserId = UserProvider.getLoginUserId();

        //1、查看考试信息
        FtbCultivateExam exam = examService.getById(examId);
        if (exam == null) {
            throw new RuntimeException("考试信息不存在");
        }
        UserRankingVo vo = new UserRankingVo();
        List<UserRankingVo> list = baseMapper.queryMyRank(examId, loginUserId);
        if (CollectionUtil.isEmpty(list)) {
            vo.setScore("-1");
        } else {
            vo = QuestionAnalysisUtil.getMaxScore(list);
        }
        vo.setUserId(loginUserId);
        //补充组织
        List<PositionGradesInfoBoundVO> userOrganizationVoList = queryUserOrganization(vo.getUserId());
        vo.setUserOrganizationVoList(userOrganizationVoList);
        fillUserInfoForUserId(vo);
        return vo;
    }

    /**
     * 删除考试，同时创建考试
     *
     * @param userExamId 删除id并重新创建考试
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAndCreateExam(String userExamId) {
        //检测是否已经删除
        FtbCultivateExamUser examUser = queryAndCheckUserExam(userExamId);
        FtbCultivateExam exam = examService.queryExamInfo(examUser.getExamId());
        CourseEnums.ExamType examType = CourseEnums.ExamType.fromCode(exam.getExamType());
        switch (examType) {
            case BASE://常规考试
                //判断当前时间是否已经过了考试结束时间
                if (examUser.getEndTime() != null) {
                    if (examUser.getEndTime().getTime() < new Date().getTime()) {
                        throw new RuntimeException("当前时间已经超过了考试结束时间");
                    }
                }
                break;
            case POSITION://岗位学习考试
                break;
        }
        //删除考试记录和考试记录详情
        examUser.setDeleteTime(new Date());
        examUser.setEnabledMark(CourseEnums.EnabledMarkType.INVALID.getCode());
        baseMapper.updateById(examUser);
        LambdaUpdateWrapper<FtbCultivateExamUserDetail> updateWrapper = new LambdaUpdateWrapper<FtbCultivateExamUserDetail>()
                .set(FtbCultivateExamUserDetail::getEnabledMark, CourseEnums.EnabledMarkType.INVALID.getCode())
                .eq(FtbCultivateExamUserDetail::getBatch, examUser.getBatch())
                .eq(FtbCultivateExamUserDetail::getUserExamId, examUser.getId())
                .eq(FtbCultivateExamUserDetail::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        userDetailService.update(updateWrapper);

        //重新生成一条记录
        FtbCultivateExamUser user = FtbCultivateExamUser.builder()
                .examId(exam.getId())
                .examType(exam.getExamType())
                .userId(examUser.getUserId())
                .status(CourseEnums.ExamStatus.WAIT.getCode())
                .reviewerUserIds(examUser.getReviewerUserIds())
                .reviewerRoleId(examUser.getReviewerRoleId())
                .paperId(exam.getPaperId())
                .examSource(examUser.getExamSource())
                .relationRankId(examUser.getRelationRankId())
                .relationPositionExamId(examUser.getRelationPositionExamId())
                .relationPositionId(examUser.getRelationPositionId())
                .relationCourseExamId(examUser.getRelationCourseExamId())
                .enabledMark(CourseEnums.EnabledMarkType.VALID.getCode())
                .batch(UUID.randomUUID().toString().replaceAll("-", ""))
                .versionBatch(exam.getVersionBatch())
                .relationTaskId(examUser.getRelationTaskId())
                .userExamCount(1)
                .build();
        if (CourseEnums.ExamType.BASE.getCode().equals(exam.getExamType())) {
            if (exam.getStartTime() != null) {
                user.setStartTime(exam.getStartTime());
            }
            if (exam.getEndTime() != null) {
                user.setEndTime(exam.getEndTime());
            }
        }
//        examService.fillRevierwer(user, exam);
        //查询用户所属组织
//        List<String> selectOrgList = organizeApi.getOrganizeIdsByUserId(examUser.getUserId());
        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(examUser.getUserId(), null);
        if (userPrimaryBoundOne != null && userPrimaryBoundOne.getOrganizeId() != null) {
            user.setUserOrgList(userPrimaryBoundOne.getOrganizeId());
        }
        baseMapper.insert(user);

        delExamCountRecord(examUser.getUserId(), examUser.getExamId());

    }

    /**
     * 删除考试统计数量
     *
     * @param userId 用户id
     * @param examId 考试id
     */
    public void delExamCountRecord(String userId, String examId) {
        LambdaQueryWrapper<FtbCultivateExamFrequencyLog> updateWrapper = new LambdaQueryWrapper<FtbCultivateExamFrequencyLog>()
                .eq(FtbCultivateExamFrequencyLog::getUserId, userId)
                .eq(FtbCultivateExamFrequencyLog::getExamId, examId);
        ftbCultivateExamFrequncyLogMapper.delete(updateWrapper);
    }

    /**
     * 培训功能优化,统计组织下用户考试合格率、合格人数、考试总人数
     *
     * @param dto
     * @return
     */
    @Override
    public ExamCultivateCountVo queryCultivateCount(CultivateUserExamCountDTO dto, List<String> userIds) {
        //1、根据组织查询用户列表
        if (CollectionUtil.isEmpty(userIds)) {
            return new ExamCultivateCountVo();
        }
        //2、根据用户ID查询考试信息 当前时间段
        Date start = dto.getStartTime();
        Date end = dto.getEndTime();
        List<FtbCultivateExamUser> currExamUserList = queryUserExamForDate(userIds, start, end);
        StatisticsResultDto curr = QuestionAnalysisUtil.statisticeLv(currExamUserList);

        ExamCultivateCountVo vo = new ExamCultivateCountVo();


        vo.setCurrPassRate(String.valueOf(curr.getPassLv()));
        vo.setCurrExamTotleNum(String.valueOf(curr.getTotle()));
        vo.setCurrExamPassNum(String.valueOf(curr.getPass()));
        return vo;
    }

    /**
     * 根据岗位id统计 考试人数，优秀人数 合格人数 不合格人数
     *
     * @param positionId 岗位id
     * @return
     */
    @Override
    public ExamCultivateForPositionVo queryCultivateCountForPositionId(String positionId) {
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .select(FtbCultivateExamUser::getId, FtbCultivateExamUser::getStatus, FtbCultivateExamUser::getUserId, FtbCultivateExamUser::getExamId, FtbCultivateExamUser::getExamSource,
                        FtbCultivateExamUser::getRelationCourseExamId, FtbCultivateExamUser::getRelationPositionExamId, FtbCultivateExamUser::getRelationRankId, FtbCultivateExamUser::getPaperId)
                .eq(FtbCultivateExamUser::getRelationPositionId, positionId)
                .notIn(FtbCultivateExamUser::getStatus, CourseEnums.ExamStatus.OVERDUE.getCode(), CourseEnums.ExamStatus.WAIT.getCode())
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        List<FtbCultivateExamUser> currExamUserList = baseMapper.selectList(wrapper);

        StatisticsResultDto curr = QuestionAnalysisUtil.statisticeLv(currExamUserList);

        ExamCultivateForPositionVo vo = new ExamCultivateForPositionVo();

        vo.setTotle(curr.getTotle());
        vo.setPass(curr.getPass());
        vo.setNoPass(curr.getNoPass());
        vo.setExcellent(curr.getExcellent());
        return vo;
    }

    /**
     * 排行榜
     *
     * @param examId 考试ID
     * @param req
     * @return
     */
    @Override
    public PageInfo<UserRankingVo> rankIngList(String examId, QueryExamRankListReq req) {
        //1、查看考试信息
        FtbCultivateExam exam = examService.getById(examId);
        if (exam == null) {
            throw new RuntimeException("考试信息不存在");
        }
        Page<FtbCultivateExamUser> page = Page.of(req.getCurrentPage(), req.getPageSize());
        Page<UserRankingVo> queryPage = baseMapper.pagingQueryRankingExamList(page, req, examId);
        List<UserRankingVo> list = queryPage.getRecords();
        //3、补充用户信息
        if (CollectionUtil.isNotEmpty(list)) {
            Map<String, UserEntity> userMap = new HashMap<>();
            List<String> userIdList = list.stream().map(UserRankingVo::getUserId).collect(Collectors.toList());
            List<UserEntity> userEntityList = userApi.getUserName(userIdList);
            if (CollectionUtil.isNotEmpty(userEntityList)) {
                userMap = userEntityList.stream().collect(Collectors.toMap(UserEntity::getId, userEntity -> userEntity));
            }
            for (int i = 0; i < list.size(); i++) {
                UserRankingVo vo = list.get(i);
                vo.setRanking(i + 1);
                UserEntity userEntity = userMap.get(vo.getUserId());
                if (null != userEntity) {
                    vo.setUserName(userEntity.getRealName());
                    vo.setHeadLogo(UploaderUtil.uploaderImg(userEntity.getHeadIcon()));
                }
                //补充组织
                List<PositionGradesInfoBoundVO> userOrganizationVoList = queryUserOrganization(vo.getUserId());
                vo.setUserOrganizationVoList(userOrganizationVoList);
            }
        }
        //构建分页返回数据
        PageInfo<UserRankingVo> pageInfo = new PageInfo<>();
        pageInfo.setList(list);
        pageInfo.setPageSize((int) queryPage.getSize());
        pageInfo.setPageNum((int) queryPage.getCurrent());
        pageInfo.setTotal((int) queryPage.getTotal());
        return pageInfo;
    }

    /**
     * 开始考试
     *
     * @param userExamId 用户考试ID
     * @return
     */
    @Override
    public FtbCultivateExamUser startExam(String userExamId) {
        //获取当前用户信息
        String loginUserId = UserProvider.getLoginUserId();
        //查看是否有记录
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .eq(FtbCultivateExamUser::getUserId, loginUserId)
                .eq(FtbCultivateExamUser::getId, userExamId)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        FtbCultivateExamUser examUser = baseMapper.selectOne(wrapper);
        if (null == examUser) {
            throw new RuntimeException("用户考试信息不存在");
        }

        if (examUser.getUserStartTime() != null) {
            examUser.setUserStartTime(new Date());
            baseMapper.updateById(examUser);
        }
        return examUser;
    }

    /**
     * 查询用户考试详情
     *
     * @param examId     考试ID
     * @param userExamId 用户考试ID
     * @param userId     用户ID
     * @return
     */
    @Override
    public List<FtbCultivateExamUserDetail> queryExamUserQuestion(String examId, String userExamId, String userId) {
        FtbCultivateExamUser examUser = examUserMapper.selectById(userExamId);
        LambdaQueryWrapper<FtbCultivateExamUserDetail> wrapper = new LambdaQueryWrapper<FtbCultivateExamUserDetail>()
                .eq(FtbCultivateExamUserDetail::getUserExamId, userExamId)
                .eq(FtbCultivateExamUserDetail::getExamId, examId)
                .eq(FtbCultivateExamUserDetail::getBatch, examUser.getBatch())
                .eq(FtbCultivateExamUserDetail::getUserId, userId)
                .eq(FtbCultivateExamUserDetail::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        return userDetailService.list(wrapper);
    }

    /**
     * 提交考试试卷
     *
     * @param userExamId 用户考试记录表ID
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SubExamVo subExam(String userExamId, SubExamQuestionReq req) {
        SubExamVo vo = new SubExamVo();
        if (CollectionUtil.isEmpty(req.getAnswerDetail())) {
            throw new RuntimeException("提交的答案信息为空");
        }
        if (null == req.getDuration()) {
            throw new RuntimeException("考试时长为空");
        }
        //获取当前用户信息
        String loginUserId = UserProvider.getLoginUserId();
        //查看是否有记录
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .eq(FtbCultivateExamUser::getUserId, loginUserId)
                .eq(FtbCultivateExamUser::getId, userExamId)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        FtbCultivateExamUser examUser = baseMapper.selectOne(wrapper);
        if (null == examUser) {
            throw new RuntimeException("用户考试信息不存在");
        }
        if (CourseEnums.EnabledMarkType.INVALID.getCode().equals(examUser.getEnabledMark())) {
            throw new RuntimeException("参加考试的人员考试取消");
        }
        //查看考试信息
        FtbCultivateExam exam = examService.queryExamInfo(examUser.getExamId());
        if (exam.getStatus().equals(3)) {
            userExamUtil.updateUserExamNullify(userExamId);
            return vo;
        }
        //检测是否可以提交考试
        checkSubmitExam(examUser, exam);
        FtbCultivateExam batchExam = userExamUtil.queryExamByIdAndBatch(exam.getId(), examUser.getVersionBatch());
        //写入用户考试的题目和答案信息
        List<FtbCultivateExamUserDetail> userDetailList = writeUserQuestion(req, examUser, batchExam);
        int autoScore = 0;//试卷自动阅卷得分
        int correctCount = 0;//正确数
        boolean isNeedReview = false;//是否需要批阅试卷 true:需要批阅 false:不需要批阅
        for (FtbCultivateExamUserDetail userDetail : userDetailList) {
            CourseEnums.QuestionType questionType = CourseEnums.QuestionType.fromCode(userDetail.getType());
            switch (questionType) {
                case SINGLE://单选
                case JUDGE://判断
                case MULTI://多选
                case ONE_OR_MULTI://不定项
                    if (userDetail.getIsRight() == CourseEnums.IsRightAnswer.YES.getCode()) {
                        autoScore += userDetail.getQuestionScore();
                        correctCount++;
                    }
                    break;
                case FILL://填空题
                case INPUT://问答题
                    isNeedReview = true;
                    break;
            }
        }
        //修改考试题目信息
        Date now = new Date();
        FtbCultivateExamUser updateExamUser = new FtbCultivateExamUser();
        updateExamUser.setId(examUser.getId());
        updateExamUser.setUserId(examUser.getUserId());
        updateExamUser.setExamId(examUser.getExamId());
        updateExamUser.setCorrectCount(correctCount);
        updateExamUser.setAutoScore(autoScore);
        updateExamUser.setScore(autoScore);
        updateExamUser.setFinishTime(now);
        updateExamUser.setUserStartTime(new Date(now.getTime() - req.getDuration() * 1000));
        updateExamUser.setDuration(req.getDuration());
        updateExamUser.setStatus(CourseEnums.ExamStatus.WAIT_CHECK.getCode());
        fillTotleQuestionAndTotleScore(updateExamUser, userDetailList);
        //填充阅卷人和阅卷角色
//        examService.fillRevierwer(updateExamUser, exam);
        //修改用户考试
        if (!isNeedReview) {
            //根据试卷ID查询试卷信息
            updateExamUser.setStatus(QuestionAnalysisUtil.calculateUserExamStatus(exam, updateExamUser.getTotalScore(), updateExamUser.getScore()));
            BigDecimal score = BigDecimal.valueOf(updateExamUser.getScore());
            BigDecimal totleScore = BigDecimal.valueOf(updateExamUser.getTotalScore());
            BigDecimal divide = score.divide(totleScore, 2, RoundingMode.HALF_UP);
            updateExamUser.setScoreRatio(divide);
        }
        baseMapper.updateById(updateExamUser);
        if (examUser.getUserExamCount() > 1) {
            ftbCultivateExamFrequncyLogMapper.insert(FtbCultivateExamFrequencyLog.builder().examId(examUser.getExamId()).userId(examUser.getUserId()).build());
        }
//        if (updateExamUser.getStatus().equals(CourseEnums.ExamStatus.PASS.getCode())
//                || updateExamUser.getStatus().equals(CourseEnums.ExamStatus.VERY_PASS.getCode())) {
//            if (StringUtils.isNotEmpty(examUser.getRelationPositionId())) {
//                Integer issuanceType = 0;
//                String courseId = "";
//                if (examUser.getExamSource() == 1) {
//                    //岗位学习课程
//                    issuanceType = 0;
//                    FtbCultivatePositionCourseExam ftbCultivatePositionCourseExam = ftbCultivatePositionCourseExamMapper.selectById(examUser.getRelationCourseExamId());
//                    courseId = ftbCultivatePositionCourseExam.getCourseId();
//                } else if (examUser.getExamSource() == 2) {
//                    //岗位学习
//                    issuanceType = 1;
//                }
//                userExamUtil.publishExam(examUser.getUserId(), examUser.getRelationPositionId(), issuanceType, courseId);
//            }
//        }
//        if (updateExamUser.getStatus().equals(CourseEnums.ExamStatus.PASS.getCode())
//                || updateExamUser.getStatus().equals(CourseEnums.ExamStatus.NO_PASS.getCode())
//                || updateExamUser.getStatus().equals(CourseEnums.ExamStatus.VERY_PASS.getCode())) {
//            if (StringUtils.isNotEmpty(examUser.getRelationPositionId()) && examUser.getExamSource() == 2) {
//                Integer integer = userExamUtil.publishExamCallBack(examUser.getUserId(), examUser.getRelationPositionId(), updateExamUser.getStatus());
//                vo.setAlertFlag(integer);
////                updateExamUser.setExamIdentifyConfig(integer);
//            } else if (StringUtils.isNotEmpty(examUser.getRelationTaskId())) {
////                userExamUtil.publishTaskExamCallBack(examUser.getUserId(), examUser.getRelationTaskId(), updateExamUser.getStatus());
//            }
//        }
        cultivateMqSendUtil.sendExamMessage(updateExamUser);
        return vo;
    }

    private void fillTotleQuestionAndTotleScore(FtbCultivateExamUser updateExamUser, List<FtbCultivateExamUserDetail> userDetailList) {
        int totleScore = 0;
        int sum = 0;
        if (CollectionUtil.isNotEmpty(userDetailList)) {
            sum = userDetailList.size();
            for (FtbCultivateExamUserDetail userDetail : userDetailList) {
                if (userDetail.getQuestionScore() != null) {
                    totleScore += userDetail.getQuestionScore();
                }
            }
        }
        updateExamUser.setTotalScore(totleScore);
        updateExamUser.setQuestionNumber(sum);
    }

    /**
     * 检测是否可以提交考试
     *
     * @param examUser
     * @param exam
     */
    private void checkSubmitExam(FtbCultivateExamUser examUser, FtbCultivateExam exam) {
        CourseEnums.ExamType examType = CourseEnums.ExamType.fromCode(exam.getExamType());
        switch (examType) {
            case BASE://常规考试
                if (StringUtils.isEmpty(examUser.getRelationTaskId()) && examUser.getStartTime() != null && examUser.getEndTime() != null) {
                    //判断当前时间是否已经过了考试结束时间
                    long time = new Date().getTime();//当前时间毫秒数
                    /*long delay = 10 * 1000;//延迟时间10s，主要是避免前端时间到了，强制交卷时，时间过了
                    if (examUser.getEndTime().getTime() < time + delay) {
                        throw new RuntimeException("考试已经结束");
                    }*/
                    //判断当前时间是否已经过了考试开始时间
                    if (examUser.getStartTime().getTime() > time) {
                        throw new RuntimeException("考试未开始");
                    }
                }
                break;
            case POSITION://岗位学习考试
                break;

        }

        if (!CourseEnums.ExamStatus.WAIT.getCode().equals(examUser.getStatus()) && !CourseEnums.ExamStatus.OVERDUE.getCode().equals(examUser.getStatus())) {
            throw new RuntimeException("考试已经提交,请不要重复提交");
        }
    }

    /**
     * 检测是否可以重复考试
     *
     * @param examUser 用户考试信息
     * @param exam     考试信息
     */
    private void checkCanReExam(FtbCultivateExamUser examUser, FtbCultivateExam exam) {
        if (CourseEnums.RepeatExam.SINGLE_EXAM.getCode().equals(exam.getExamlimitation())) {
            throw new RuntimeException("该考试不能重复考试");
        } else {
            checkReExamNum(examUser, exam);
        }
        if (exam.getStatus().equals(3)) {
            throw new RuntimeException("考试已经作废");
        }

        if (CourseEnums.ExamStatus.PASS.getCode().equals(examUser.getStatus())
                || CourseEnums.ExamStatus.VERY_PASS.getCode().equals(examUser.getStatus())) {
            throw new RuntimeException("考试已经合格,不能够重复考试");
        } else if (CourseEnums.ExamStatus.WAIT.getCode().equals(examUser.getStatus())) {
            throw new RuntimeException("当前考试未完成,不能够重复考试");
        } else if (CourseEnums.ExamStatus.WAIT_CHECK.getCode().equals(examUser.getStatus())) {
            throw new RuntimeException("当前考试待批阅,不能够重复考试");
        }
        CourseEnums.ExamType examType = CourseEnums.ExamType.fromCode(exam.getExamType());
        switch (examType) {
            case BASE://常规考试
                if (StringUtils.isEmpty(examUser.getRelationTaskId()) && examUser.getStartTime() != null && examUser.getEndTime() != null) {
                    //判断当前时间是否已经过了考试结束时间
                    if (examUser.getEndTime().getTime() < new Date().getTime()) {
                        throw new RuntimeException("考试已经结束");
                    }
                    //判断当前时间是否已经过了考试开始时间
                    if (examUser.getStartTime().getTime() > new Date().getTime()) {
                        throw new RuntimeException("考试未开始");
                    }
                }
                break;
            case POSITION://岗位学习考试
                break;

        }
    }

    /**
     * 检测用户考试频次是否满足
     *
     * @param examUser 用户考试信息
     * @param exam     考试信息
     */
    private void checkReExamNum(FtbCultivateExamUser examUser, FtbCultivateExam exam) {
        ExamRetakeFrequencyEnum frequencyEnum = ExamRetakeFrequencyEnum.of(exam.getReExamFrequencyType());
        if (frequencyEnum == null) {
            throw new RuntimeException("重复考试频次配置错误");
        }

        Date startTime = null;
        Date endTime = new Date();
        Integer num = 0;

        switch (frequencyEnum) {
            case DAILY:
                startTime = UserExamUtil.getTodayStart();
                num = ftbCultivateExamFrequncyLogMapper.queryExamNum(exam.getId(), examUser.getUserId(), startTime, endTime);
                if (null != num && num >= exam.getReExamFrequencyNum()) {
                    throw new RuntimeException("已经超过当天最大考试次数，不能再重复考试了");
                }
                break;
            case WEEKLY:
                startTime = UserExamUtil.getWeekStart();
                num = ftbCultivateExamFrequncyLogMapper.queryExamNum(exam.getId(), examUser.getUserId(), startTime, endTime);
                if (null != num && num >= exam.getReExamFrequencyNum()) {
                    throw new RuntimeException("已经超过本周最大考试次数，不能再重复考试了");
                }
                break;
            case MONTHLY:
                startTime = UserExamUtil.getMonthStart();
                num = ftbCultivateExamFrequncyLogMapper.queryExamNum(exam.getId(), examUser.getUserId(), startTime, endTime);
                if (null != num && num >= exam.getReExamFrequencyNum()) {
                    throw new RuntimeException("已经超过本月最大考试次数，不能再重复考试了");
                }
                break;
            case CUMULATIVE:
                if (examUser.getUserExamCount() >= exam.getReExamFrequencyNum()) {
                    throw new RuntimeException("已经超过最大考试次数，不能再重复考试了");
                }
                break;
            case UNLIMITED:
                break;
        }
    }

    /**
     * 提交考试写入考试题目记录
     *
     * @param req      请求信息
     * @param examUser 考试用户记录信息
     * @param exam     考试信息
     * @return
     */

    private List<FtbCultivateExamUserDetail> writeUserQuestion(SubExamQuestionReq req, FtbCultivateExamUser examUser, FtbCultivateExam exam) {

        //获取当前用户信息
        String loginUserId = UserProvider.getLoginUserId();
        List<AppQuestionVo> answerDetailList = req.getAnswerDetail();
        if (CollectionUtil.isEmpty(answerDetailList)) {
            CollectionUtil.newArrayList();
        }
        List<FtbCultivateExamUserDetail> addList = new ArrayList<>();
        for (AppQuestionVo answerDetail : answerDetailList) {
            String questionId = answerDetail.getQuestionId();
            String userAnswer = answerDetail.getUserAnswer();
            //查询题目分数
            Integer questionScore = answerDetail.getQuestionScore();
            FtbCultivateExamUserDetail user = FtbCultivateExamUserDetail.builder()
                    .enabledMark(CourseEnums.EnabledMarkType.VALID.getCode())
                    .userExamId(examUser.getId())
                    .examId(exam.getId())
                    .questionId(questionId)
                    .questionOption(JSONUtil.toJsonStr(answerDetail.getQuestionOptionVoList()))
                    .classifyId(answerDetail.getClassifyId())
                    .type(answerDetail.getType())
                    .difficulty(answerDetail.getDifficulty())
                    .userAnswer(userAnswer)
                    .content(answerDetail.getContent())
                    .analysis(answerDetail.getAnalysis())
                    .paperId(exam.getPaperId())
                    .userId(loginUserId)
                    .answer(answerDetail.getAnswer())
                    .questionScore(questionScore)
                    .batch(examUser.getBatch()).build();

            CourseEnums.QuestionType questionType = CourseEnums.QuestionType.fromCode(answerDetail.getType());
            switch (questionType) {
                case SINGLE://单选
                case JUDGE://判断
                    if (answerDetail.getAnswer().equals(userAnswer)) {
                        user.setUserScore(user.getQuestionScore());
                        user.setIsRight(CourseEnums.IsRightAnswer.YES.getCode());
                    } else {
                        user.setUserScore(0);
                        user.setIsRight(CourseEnums.IsRightAnswer.NO.getCode());
                    }
                    break;
                case MULTI://多选
                case ONE_OR_MULTI://不定项选择题
                    if (QuestionAnalysisUtil.checkMultiRight(user.getAnswer(), user.getUserAnswer())) {
                        user.setUserScore(user.getQuestionScore());
                        user.setIsRight(CourseEnums.IsRightAnswer.YES.getCode());
                    } else {
                        user.setUserScore(0);
                        user.setIsRight(CourseEnums.IsRightAnswer.NO.getCode());
                    }
                    break;
                case FILL://填空题
                case INPUT://问答题
                    user.setUserScore(0);//给一个默认分数
                    break;

            }
            addList.add(user);
        }
        userDetailService.saveBatch(addList);
        return addList;
    }

    private List<FtbCultivateExamUserDetail> writeUserQuestionNoScore(SubExamQuestionReq req, FtbCultivateExamUser examUser, FtbCultivateExam exam) {
        //获取当前用户信息
        String loginUserId = UserProvider.getLoginUserId();
        List<AppQuestionVo> answerDetailList = req.getAnswerDetail();
        if (CollectionUtil.isEmpty(answerDetailList)) {
            CollectionUtil.newArrayList();
        }
        //根据试卷ID 查询试卷中的题目和分数
        List<FtbCultivateTestPaperQuestion> paperQuestionList = paperService.queryPaperQuestionRelationList(examUser.getPaperId());
        Map<String, FtbCultivateTestPaperQuestion> questionMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(paperQuestionList)) {
            questionMap = paperQuestionList.stream().collect(Collectors.toMap(FtbCultivateTestPaperQuestion::getQuestionId, Function.identity()));
        }


        List<FtbCultivateExamUserDetail> addList = new ArrayList<>();
        for (AppQuestionVo answerDetail : answerDetailList) {
            String questionId = answerDetail.getQuestionId();
            String userAnswer = answerDetail.getUserAnswer();

            //查询题目分数
            Integer questionScore = answerDetail.getQuestionScore();
            FtbCultivateTestPaperQuestion paperQuestion = questionMap.get(questionId);
            if (null != paperQuestion) {
                questionScore = paperQuestion.getScore();
            }
            FtbCultivateExamUserDetail user = FtbCultivateExamUserDetail.builder()
                    .enabledMark(CourseEnums.EnabledMarkType.VALID.getCode())
                    .userExamId(examUser.getId())
                    .examId(exam.getId())
                    .questionId(questionId)
                    .questionOption(JSONUtil.toJsonStr(answerDetail.getQuestionOptionVoList()))
                    .classifyId(answerDetail.getClassifyId())
                    .type(answerDetail.getType())
                    .difficulty(answerDetail.getDifficulty())
                    .userAnswer(userAnswer)
                    .content(answerDetail.getContent())
                    .analysis(answerDetail.getAnalysis())
                    .paperId(exam.getPaperId())
                    .userId(loginUserId)
                    .answer(answerDetail.getAnswer())
                    .questionScore(questionScore)
                    .batch(examUser.getBatch()).build();

            CourseEnums.QuestionType questionType = CourseEnums.QuestionType.fromCode(answerDetail.getType());
            switch (questionType) {
                case SINGLE://单选
                case JUDGE://判断
                    if (answerDetail.getAnswer().equals(userAnswer)) {
                        user.setUserScore(0);
                        user.setIsRight(CourseEnums.IsRightAnswer.YES.getCode());
                    } else {
                        user.setUserScore(0);
                        user.setIsRight(CourseEnums.IsRightAnswer.NO.getCode());
                    }
                    break;
                case MULTI://多选
                    if (QuestionAnalysisUtil.checkMultiRight(user.getAnswer(), user.getUserAnswer())) {
                        user.setUserScore(0);
                        user.setIsRight(CourseEnums.IsRightAnswer.YES.getCode());
                    } else {
                        user.setUserScore(0);
                        user.setIsRight(CourseEnums.IsRightAnswer.NO.getCode());
                    }
                    break;
                case FILL://填空题
                case INPUT://问答题
                    user.setUserScore(0);//给一个默认分数
                    break;

            }

            addList.add(user);
        }
        userDetailService.saveBatch(addList);
        return addList;
    }


    /**
     * 查询用户考试题目
     *
     * @param userExamId 用户考试ID
     * @param userId     用户ID
     * @param batch      批次ID
     * @return
     */
    private List<FtbCultivateExamUserDetail> queryUserQuestion(String userExamId, String userId, String batch) {
        LambdaQueryWrapper<FtbCultivateExamUserDetail> wrapper = new LambdaQueryWrapper<FtbCultivateExamUserDetail>()
                .eq(FtbCultivateExamUserDetail::getUserExamId, userExamId)
                .eq(FtbCultivateExamUserDetail::getBatch, batch)
                .eq(FtbCultivateExamUserDetail::getUserId, userId)
                .eq(FtbCultivateExamUserDetail::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        return userDetailService.list(wrapper);
    }

    /**
     * 查询用户考试信息
     *
     * @param userExamId 用户考试ID
     * @return
     */
    private FtbCultivateExamUser queryAndCheckUserExam(String userExamId) {
        FtbCultivateExamUser examUser = getById(userExamId);
        if (null == examUser) {
            throw new RuntimeException("用户考试信息不存在");
        }
        if (CourseEnums.EnabledMarkType.INVALID.getCode().equals(examUser.getEnabledMark())) {
            throw new RuntimeException("用户考试信息已删除");
        }
        return examUser;
    }

    /**
     * 填充用户信息
     *
     * @param list
     */

    private <T extends ExamBaseUser> void fillExamUserInfo(List<T> list) {
        //获取用户列表
        List<String> userIdList = list.stream().map(ExamBaseUser::getUserId).collect(Collectors.toList());
        Map<String, UserEntity> userMap = userApiV2Util.getUserNameAndCopyForUserIds(userIdList);
        for (ExamBaseUser vo : list) {
            UserEntity userEntity = userMap.get(vo.getUserId());
            if (userEntity != null) {
                vo.setUserName(userEntity.getRealName());
                vo.setHeadLogo(UploaderUtil.uploaderImg(userEntity.getHeadIcon()));
            }
        }
    }


    /**
     * 查询我的考试列表
     *
     * @param req
     * @return
     */
    @Override
    public PageInfo<AppExamListVo> queryMyExamList(QueryExamListReq req) {
        //获取当前用户信息
        String loginUserId = UserProvider.getLoginUserId();
        if (!CourseEnums.ExamType.BASE.getCode().equals(req.getExamType())
                && !CourseEnums.ExamType.POSITION.getCode().equals(req.getExamType())) {
            throw new RuntimeException("查询类型错误");
        }
        Page<FtbCultivateExamUser> page = Page.of(req.getCurrentPage(), req.getPageSize());
        QueryMyExamListReq queryMyExamListReq = BeanUtil.copyProperties(req, QueryMyExamListReq.class);
        queryMyExamListReq.setUserId(loginUserId);
        queryMyExamListReq.setInnerExamIds(searchFrzzExamName(req.getKeyword()));
        Page<AppExamListVo> queryPage = baseMapper.pagingQueryMyExamList(page, queryMyExamListReq);
        List<AppExamListVo> list = queryPage.getRecords();
        batchFillExamUserInfo(list);
        PageInfo<AppExamListVo> pageInfo = new PageInfo<>();
        pageInfo.setList(list);
        pageInfo.setPageSize((int) queryPage.getSize());
        pageInfo.setPageNum((int) queryPage.getCurrent());
        pageInfo.setTotal((int) queryPage.getTotal());
        return pageInfo;
    }

    /**
     * 查询我的岗位考试列表（完成考试合格且需要考试合格才能鉴定 却未鉴定的岗位）
     *
     * @return
     * @userId 用户ID
     */
    @Override
    public List<PositionEntity> queryAlertPostionIdentify(String userId) {
        List<AppExamListVo> appExamListVos = baseMapper.queryAlertPostionIdentify(userId);
        if (CollectionUtil.isEmpty(appExamListVos)) {
            return new ArrayList<>();
        }
        List<String> positionIds = new ArrayList<>();
        for (AppExamListVo vo : appExamListVos) {
            if (StringUtils.isNotEmpty(vo.getRelationPositionId())) {
                positionIds.add(vo.getRelationPositionId());
            }
        }
        if (CollectionUtil.isEmpty(positionIds)) {
            return new ArrayList<>();
        }

        List<PositionVO> positionEntityList = userApiV2Util.listPositionDetailInfoByIds(positionIds, null);
        List<PositionEntity> postAndPositionList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(positionEntityList)) {
            for (PositionVO positionEntity : positionEntityList) {
                PositionEntity postAndPosition = new PositionEntity();
                postAndPosition.setId(positionEntity.getId());
                postAndPosition.setFullName(positionEntity.getFullName());
                postAndPosition.setEnCode(positionEntity.getEnCode());//todo岗位编码
                postAndPositionList.add(postAndPosition);
            }
        }
        return postAndPositionList;

    }

    /**
     * 岗位完成鉴定
     *
     * @param userId     用户id
     * @param positionId 岗位ID
     */
    @Override
    public void completeIdentifyCallBack(String userId, String positionId) {
        log.error("completeIdentifyCallBack={},{}", userId, positionId);
        //构建修改wrap
        LambdaUpdateWrapper<FtbCultivateExamUser> wrapper = new LambdaUpdateWrapper<FtbCultivateExamUser>()
                .set(FtbCultivateExamUser::getCompleteIdentify, 1)
                .in(FtbCultivateExamUser::getStatus, CourseEnums.ExamStatus.PASS.getCode(),
                        CourseEnums.ExamStatus.VERY_PASS.getCode())
                .eq(FtbCultivateExamUser::getRelationPositionId, positionId)
                .eq(FtbCultivateExamUser::getUserId, userId)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        baseMapper.update(null, wrapper);

    }

    /**
     * 批量填充用户考试信息
     *
     * @param examUserList
     */
    @Override
    public void batchFillExamUserInfo(List<AppExamListVo> examUserList) {
        List<String> examIds = new ArrayList<>();
        for (AppExamListVo appExamListVo : examUserList) {
            if (StringUtils.isNotEmpty(appExamListVo.getExamId())) {
                examIds.add(appExamListVo.getExamId());
            }
        }
        InnerQueryExamResultDto innerQueryExamResultDto = queryCurrExamListByIds(examIds);
        Map<String, FtbCultivateExam> examMap = innerQueryExamResultDto.getExamMap();
        Map<String, FtbCultivateExam> versionBatchMap = innerQueryExamResultDto.getVersionBatchMap();

        List<String> historyExamIds = new ArrayList<>();
        for (AppExamListVo vo : examUserList) {
            FtbCultivateExam exam = examMap.get(vo.getExamId());
            if (null != exam) {
                if (exam.getStatus() != null && exam.getStatus().equals(3)) {
                    vo.setIsNullify(1);
                }
                vo.setNeedUpdate(exam.getNeedUpdate());
            }
            //补充当前考试
            String verKey = vo.getExamId() + vo.getVersionBatch();
            FtbCultivateExam exam1 = versionBatchMap.get(verKey);
            if (null != exam1) {
                vo.setExamName(exam1.getExamName());
                vo.setExamTime(exam1.getExamTime());
                vo.setInnerExamFlag(0);
                FtbCultivateTestPaper paper = null;
                if (StringUtils.isNotEmpty(exam1.getPaperInfo())) {
                    paper = JSONUtil.toBean(exam1.getPaperInfo(), FtbCultivateTestPaper.class);
                } else {
                    paper = paperService.getById(exam.getPaperId());
                }
                if (null != paper) {
                    vo.setPaperName(paper.getName());
                }
                vo.setExamTotleScore(exam1.getCurrTotalScore());
                vo.setQuestionNum(exam1.getCurrQuestionNumber());
            } else {
                vo.setInnerExamFlag(1);
                historyExamIds.add(vo.getExamId());
            }
        }

        //补充历史考试
        if (CollectionUtil.isNotEmpty(historyExamIds)) {
            Map<String, FtbCultivateExamHistoryPaper> historyExam = examHistoryPaperService.queryHistoryExamListByIds(examIds);
            for (AppExamListVo vo : examUserList) {
                String verKey = vo.getExamId() + vo.getVersionBatch();
                FtbCultivateExamHistoryPaper exam2 = historyExam.get(verKey);
                if (null != exam2) {
                    vo.setExamName(exam2.getExamName());
                    vo.setExamTime(exam2.getExamTime());
                    FtbCultivateTestPaper paper = null;
                    if (StringUtils.isNotEmpty(exam2.getPaperInfo())) {
                        paper = JSONUtil.toBean(exam2.getPaperInfo(), FtbCultivateTestPaper.class);
                    } else {
                        paper = paperService.getById(exam2.getPaperId());
                    }
                    if (null != paper) {
                        vo.setPaperName(paper.getName());
                    }
                    if (vo.getStatus() == 1 || vo.getStatus() == 3 || vo.getStatus() == 4 || vo.getStatus() == 5) {
                        vo.setExamTotleScore(exam2.getCurrTotalScore());
                        vo.setQuestionNum(exam2.getCurrQuestionNumber());
                    }
                }
            }
        }

    }


    /**
     * 查询当前考试表
     *
     * @param examIds
     * @return
     */
    private InnerQueryExamResultDto queryCurrExamListByIds(List<String> examIds) {
        InnerQueryExamResultDto dto = new InnerQueryExamResultDto();
        if (CollectionUtil.isEmpty(examIds)) {
            return dto;
        }
        Map<String, FtbCultivateExam> examMap = new HashMap<>();
        Map<String, FtbCultivateExam> versionBatchMap = new HashMap<>();

        List<FtbCultivateExam> examList = examService.listByIds(examIds);
        if (CollectionUtil.isNotEmpty(examList)) {
            for (FtbCultivateExam exam : examList) {
                examMap.put(exam.getId(), exam);
                versionBatchMap.put(exam.getId() + exam.getVersionBatch(), exam);
            }
        }
        dto.setExamMap(examMap);
        dto.setVersionBatchMap(versionBatchMap);
        return dto;
    }

    private List<String> searchFrzzExamName(String keyword) {
        List<String> examIds = new ArrayList<>();
        if (StringUtils.isEmpty(keyword)) {
            return examIds;
        }
        LambdaQueryWrapper<FtbCultivateExam> wrapper = new LambdaQueryWrapper<FtbCultivateExam>()
                .select(FtbCultivateExam::getId, FtbCultivateExam::getExamId)
                .like(FtbCultivateExam::getExamName, keyword)
                .eq(FtbCultivateExam::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        List<FtbCultivateExam> list = examService.list(wrapper);
        if (CollectionUtil.isNotEmpty(list)) {
            for (FtbCultivateExam ftbCultivateExam : list) {
                examIds.add(ftbCultivateExam.getExamId());
            }
        }
        examIds.addAll(examHistoryPaperService.searchFrzzExamName(keyword));
        return QuestionAnalysisUtil.uniqueStringList(examIds);

    }

    /**
     * 根据用户ID 查询考试列表
     *
     * @param userId  用户ID
     * @param reqPage
     * @return
     */
    @Override
    public PageInfo<AppExamListVo> queryExamListForUserId(String userId, CultivatePage reqPage) {

        Page<FtbCultivateExamUser> page = Page.of(reqPage.getCurrentPage(), reqPage.getPageSize());
        Page<AppExamListVo> queryPage = baseMapper.pagingQueryExamListForUserId(page, userId);
        List<AppExamListVo> list = queryPage.getRecords();
        PageInfo<AppExamListVo> pageInfo = new PageInfo<>();
        if (CollectionUtil.isNotEmpty(list)) {
            for (AppExamListVo appExamListVo : list) {
                fillNeedPassScore(appExamListVo);
            }
        }
        pageInfo.setList(list);
        pageInfo.setPageSize((int) queryPage.getSize());
        pageInfo.setPageNum((int) queryPage.getCurrent());
        pageInfo.setTotal((int) queryPage.getTotal());
        return pageInfo;
    }

    private void fillNeedPassScore(AppExamListVo vo) {
        //计算用户需要考多少分才及格
        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, vo.getExamTotleScore());
        }
        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, vo.getExamTotleScore());
        }
        vo.setNeedExamExcellentScore(needExcellentScore);
    }

    /**
     * 根据用户ID 和岗位ID 查询用户的考试列表
     *
     * @param dto
     * @return
     */
    public PageInfo<PositionExamDto> queryExamListForUserIdAndPostId(QueryUserExamListDto dto) {
        //获取当前用户信息
        Page<FtbCultivateExamUser> page = Page.of(dto.getCurrentPage(), dto.getPageSize());
        Page<PositionExamDto> queryPage = new Page<>();
        if (StringUtils.isNotEmpty(dto.getRankId())) {
            queryPage = baseMapper.pagingQueryExamList(page, dto);
        } else {
            queryPage = baseMapper.pagingQueryExamListByPosition(page, dto);
        }
        List<PositionExamDto> list = queryPage.getRecords();
        PageInfo<PositionExamDto> pageInfo = new PageInfo<>();
        List<PositionExamDto> userExamList = new ArrayList<>();
        //补充考试信息
        if (CollectionUtil.isNotEmpty(list)) {
            for (PositionExamDto vo : list) {
                vo.setUserId(dto.getUserId());
                LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                        .eq(FtbCultivateExamUser::getExamId, vo.getExamId())
                        .eq(FtbCultivateExamUser::getUserId, dto.getUserId())
                        .eq(FtbCultivateExamUser::getExamSource, vo.getExamSource())
                        .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode())
                        .orderByDesc(FtbCultivateExamUser::getCreatorTime);
                if (vo.getExamSource().equals(2)) {
                    wrapper.eq(FtbCultivateExamUser::getRelationPositionExamId, vo.getInnerBuinessId());
                } else {
                    wrapper.eq(FtbCultivateExamUser::getRelationCourseExamId, vo.getInnerBuinessId());
                }
                List<FtbCultivateExamUser> examUserList = baseMapper.selectList(wrapper);
                if (CollectionUtil.isEmpty(examUserList)) {
                    vo.setStatus(-1);
                    continue;
                }
                //补充用户考试数据
                FtbCultivateExamUser user = examUserList.get(0);

                for (FtbCultivateExamUser examUser : examUserList) {
                    if (examUser.getCreatorTime().after(user.getCreatorTime())) {
                        user = examUser;
                    }
                }
                vo.setStatus(user.getStatus());
                vo.setUserStartTime(user.getUserStartTime());
                vo.setFinishtime(user.getFinishTime());
                vo.setDuration(user.getDuration());
                vo.setUserExamId(user.getId());
                vo.setScore(user.getScore());
                vo.setRelationCourseExamId(user.getRelationCourseExamId());
                vo.setRelationPositionExamId(user.getRelationPositionExamId());
                userExamList.add(vo);
            }
            userExamList = sortByStatus(userExamList);

        }

        pageInfo.setList(userExamList);
        pageInfo.setPageSize(userExamList.size());
        pageInfo.setPageNum(1);
        pageInfo.setTotal(userExamList.size());
        return pageInfo;
    }

    /**
     * 按照状态排序
     *
     * @param list
     * @return
     */
    private List<PositionExamDto> sortByStatus(List<PositionExamDto> list) {
        return list.stream()
                .sorted(Comparator.comparing(PositionExamDto::getStatus))
                .collect(Collectors.toList());
    }


    /**
     * 查询待我批阅的
     *
     * @param req
     * @return
     */
    @Override
    public PageInfo<AppExamListVo> queryWaitMyReadOver(QueryExamListReq req) {
        //获取当前用户信息
        String loginUserId = UserProvider.getLoginUserId();
        if (!CourseEnums.ExamType.BASE.getCode().equals(req.getExamType())
                && !CourseEnums.ExamType.POSITION.getCode().equals(req.getExamType())) {
            throw new RuntimeException("查询类型错误");
        }
        Page<FtbCultivateExamUser> page = Page.of(req.getCurrentPage(), req.getPageSize());
        QueryWaitMyExamListReq queryReq = BeanUtil.copyProperties(req, QueryWaitMyExamListReq.class);
        List<String> managerUserIds = new ArrayList<>();
        InnerPowerUserVO innerPowerUserVO = userApiV2Util.getLoginManagerUserIdsForEncode();
        if (innerPowerUserVO.getCode().equals(1)) {
            managerUserIds = innerPowerUserVO.getUserIds();
        } else if (innerPowerUserVO.getCode().equals(2)) {
            managerUserIds.add("-1");
        }
        Page<AppExamListVo> queryPage = baseMapper.pagingQueryWaitMyExamList(page, queryReq, managerUserIds);
        List<AppExamListVo> list = queryPage.getRecords();
        //补充组织信息 和用户信息
        fillExtraInfo(loginUserId, list);

        fillRelationPositionName(list);

        PageInfo<AppExamListVo> pageInfo = new PageInfo<>();
        pageInfo.setList(list);
        pageInfo.setPageSize((int) queryPage.getSize());
        pageInfo.setPageNum((int) queryPage.getCurrent());
        pageInfo.setTotal((int) queryPage.getTotal());
        //异步处理动态为考试权限
//        examAsyncDealUtil.asyncRefreshUserExamPower(userExamUtil.getTenantId(), userExamUtil.getHeadersForLogin());
        return pageInfo;
    }

    @Override
    public void fillRelationPositionName(List<AppExamListVo> list) {
        if (CollectionUtil.isEmpty(list)) {
            return;
        }
        Set<String> positonIdSet = new HashSet<>();
        for (AppExamListVo vo : list) {
            if (StringUtils.isNotEmpty(vo.getRelationPositionId())) {
                positonIdSet.add(vo.getRelationPositionId());
            }
        }
        if (CollectionUtil.isEmpty(positonIdSet)) {
            return;
        }
        List<PositionEntity> positionEntities = personnelOrgUtils.queryPostionInfoForIds(new ArrayList<>(positonIdSet));
        //转换成map
        if (CollectionUtil.isEmpty(positionEntities)) {
            return;
        }
        Map<String, PositionEntity> positionMap = positionEntities.stream().collect(Collectors.toMap(PositionEntity::getId, Function.identity()));
        for (AppExamListVo vo : list) {
            if (StringUtils.isNotEmpty(vo.getRelationPositionId())) {
                PositionEntity positionEntity = positionMap.get(vo.getRelationPositionId());
                if (positionEntity != null) {
                    vo.setRelationPositionName(positionEntity.getFullName());
                }
            }
        }
    }

    /**
     * 查询我的下属
     *
     * @param userId
     * @return
     */
    private Set<String> queryMyBelowUser(String userId) {
        Set<String> userIds = new HashSet<>();
        List<UserPageListVO> listVOS = userApiV2Util.listUnderlingTargetUser(userId, null);
        if (CollectionUtil.isNotEmpty(listVOS)) {
            userIds = listVOS.stream().map(UserPageListVO::getId).collect(Collectors.toSet());
        }
        return userIds;
    }

    /**
     * 查询我的已批阅
     *
     * @param req
     * @return
     */
    @Override
    public PageInfo<AppExamListVo> queryMyCompleteReadOver(QueryExamListReq req) {
        //获取当前用户信息
        String loginUserId = UserProvider.getLoginUserId();
        if (!CourseEnums.ExamType.BASE.getCode().equals(req.getExamType())
                && !CourseEnums.ExamType.POSITION.getCode().equals(req.getExamType())) {
            throw new RuntimeException("查询类型错误");
        }
        Page<FtbCultivateExamUser> page = Page.of(req.getCurrentPage(), req.getPageSize());
        QueryMyCompleteExamListReq queryReq = BeanUtil.copyProperties(req, QueryMyCompleteExamListReq.class);
        queryReq.setUserId(loginUserId);
        Page<AppExamListVo> queryPage = baseMapper.pagingQueryMyCompleteExamList(page, queryReq);
        List<AppExamListVo> list = queryPage.getRecords();

        //补充组织信息 和用户信息
        fillExtraInfo(loginUserId, list);

        fillRelationPositionName(list);


        PageInfo<AppExamListVo> pageInfo = new PageInfo<>();
        pageInfo.setList(list);
        pageInfo.setPageSize((int) queryPage.getSize());
        pageInfo.setPageNum((int) queryPage.getCurrent());
        pageInfo.setTotal((int) queryPage.getTotal());
        return pageInfo;
    }

    /**
     * 查询下属逾期未考试的考试列表
     *
     * @param req
     * @return
     */
    @Override
    public PageInfo<AppExamListVo> expireExam(QueryExpireListReq req) {
        //获取当前用户信息
        String loginUserId = UserProvider.getLoginUserId();
        Page<FtbCultivateExamUser> page = Page.of(req.getCurrentPage(), req.getPageSize());
        QueryExpireExamListReq queryReq = BeanUtil.copyProperties(req, QueryExpireExamListReq.class);
        queryReq.setUserId(loginUserId);

        List<String> managerUserIds = new ArrayList<>();
        InnerPowerUserVO innerPowerUserVO = userApiV2Util.getLoginManagerUserIdsForEncode();
        if (innerPowerUserVO.getCode().equals(1)) {
            managerUserIds = innerPowerUserVO.getUserIds();
        } else if (innerPowerUserVO.getCode().equals(2)) {
            managerUserIds.add("-1");
        }

        Page<AppExamListVo> queryPage = baseMapper.pagingQueryExpireExamList(page, queryReq, managerUserIds);
        List<AppExamListVo> list = queryPage.getRecords();
        //补充组织信息 和用户信息
        fillExtraInfo(loginUserId, list);
        fillRelationPositionName(list);

        PageInfo<AppExamListVo> pageInfo = new PageInfo<>();
        pageInfo.setList(list);
        pageInfo.setPageSize((int) queryPage.getSize());
        pageInfo.setPageNum((int) queryPage.getCurrent());
        pageInfo.setTotal((int) queryPage.getTotal());
        return pageInfo;
    }

    @Override
    public void fillExtraInfo(String loginUserId, List<AppExamListVo> list) {
        if (CollectionUtil.isNotEmpty(list)) {
            //补充组织信息 和用户信息
            for (AppExamListVo appExamListVo : list) {
                List<PositionGradesInfoBoundVO> userOrganizationList = queryUserOrganization(appExamListVo.getUserId());
                appExamListVo.setOrganizationVoList(userOrganizationList);
            }
            fillExamUserInfo(list);
            //检测是否是我的下属
            Set<String> queryMyBelowUser = queryMyBelowUser(loginUserId);
            for (AppExamListVo appExamListVo : list) {
                if (queryMyBelowUser.contains(appExamListVo.getUserId())) {
                    appExamListVo.setIsMyBelow(true);
                } else {
                    appExamListVo.setIsMyBelow(false);
                }
            }
        }
    }

    /**
     * 清楚逾期未考试的考试记录
     *
     * @param userExamIds 用户考试记录id集合
     */
    @Override
    public void clearExpireExam(String userExamIds) {
        if (StringUtils.isEmpty(userExamIds)) {
            return;
        }
        List<String> userExamIdsList = Arrays.asList(userExamIds.split(","));
        if (CollectionUtil.isEmpty(userExamIdsList)) {
            return;
        }
        //1、查询
        List<FtbCultivateExamUser> examUserList = baseMapper.selectList(Wrappers.<FtbCultivateExamUser>lambdaQuery()
                .in(FtbCultivateExamUser::getId, userExamIdsList)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode())
                .eq(FtbCultivateExamUser::getAppShow, CourseEnums.ExamRecordDisplay.SHOW.getCode())
                .eq(FtbCultivateExamUser::getExamType, CourseEnums.ExamType.BASE.getCode())
        );
        if (CollectionUtil.isEmpty(examUserList)) {
            throw new RuntimeException("未查询到相关逾期考试记录");
        }
        //2、批量删除已经过期的
        Date now = new Date();
        List<FtbCultivateExamUser> deleteExamUserList = new ArrayList<>();
        examUserList.forEach(examUser -> {
            if (CourseEnums.ExamStatus.OVERDUE.getCode().equals(examUser.getStatus())) {
                examUser.setAppShow(CourseEnums.ExamRecordDisplay.HIDDEN.getCode());
                deleteExamUserList.add(examUser);
            }
        });
        //批量删除
        if (CollectionUtil.isNotEmpty(deleteExamUserList)) {
            saveOrUpdateBatch(deleteExamUserList);
        }
    }

    /**
     * 触发考试
     *
     * @param req
     * @return
     */
    @Override
    public Boolean triggerPositionExam(TriggerExamDto req) {

        log.error("临时日志，触发考试={}", JSONUtil.toJsonStr(req));


        //1、查看考试信息
        FtbCultivateExam exam = examService.queryExamInfo(req.getExamId());
        if (CourseEnums.RelationExamSource.COURSE_RELATED_EXAM.getCode().equals(req.getExamSource())) {
            //查看是否有记录
            LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                    .eq(FtbCultivateExamUser::getUserId, req.getUserId())
                    .eq(FtbCultivateExamUser::getExamSource, req.getExamSource())
                    .eq(FtbCultivateExamUser::getExamId, req.getExamId())
                    .eq(StringUtils.isNotEmpty(req.getRelationPositionId()), FtbCultivateExamUser::getRelationPositionId, req.getRelationPositionId())
                    .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());

            wrapper.eq(FtbCultivateExamUser::getRelationCourseExamId, req.getRelationId());

            Long count = baseMapper.selectCount(wrapper);
            if (null != count && count > 0) {
                return true;
            }
        } else if (CourseEnums.RelationExamSource.JOB_LEARNING_RELATED_EXAM.getCode().equals(req.getExamSource())) {
            //查看是否有记录
            LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                    .eq(FtbCultivateExamUser::getUserId, req.getUserId())
                    .eq(FtbCultivateExamUser::getExamSource, req.getExamSource())
                    .eq(FtbCultivateExamUser::getRelationPositionId, req.getRelationPositionId())
                    .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
            Long count = baseMapper.selectCount(wrapper);
            if (null != count && count > 0) {
                log.error("用户{}，岗位={},用户已经有这个岗位的考试了", req.getUserId(), req.getRelationPositionId());
                return true;
            }
        } else if (CourseEnums.RelationExamSource.TASK_EXAM.getCode().equals(req.getExamSource())) {
            //查看是否有记录
            LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                    .eq(FtbCultivateExamUser::getUserId, req.getUserId())
                    .eq(FtbCultivateExamUser::getExamSource, req.getExamSource())
                    .eq(FtbCultivateExamUser::getRelationTaskId, req.getRelationTaskId())
                    .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
            Long count = baseMapper.selectCount(wrapper);
            if (null != count && count > 0) {
                log.error("用户{}，taskId={},用户已经有这个岗位的考试了", req.getUserId(), req.getRelationTaskId());
                return true;
            }
        }

        //2、没有就写入一条记录
        FtbCultivateExamUser user = FtbCultivateExamUser.builder()
                .examId(req.getExamId())
                .examType(exam.getExamType())
                .userId(req.getUserId())
                .status(CourseEnums.ExamStatus.WAIT.getCode())
                .paperId(exam.getPaperId())
                .examSource(req.getExamSource())
                .relationPositionId(req.getRelationPositionId())
                .relationRankId(req.getRelationRankId())
                .relationTaskId(req.getRelationTaskId())
                .enabledMark(CourseEnums.EnabledMarkType.VALID.getCode())
                .batch(UUID.randomUUID().toString().replaceAll("-", ""))
                .userExamCount(1)
                .build();
        if (CourseEnums.RelationExamSource.COURSE_RELATED_EXAM.getCode().equals(req.getExamSource())) {
            user.setRelationCourseExamId(req.getRelationId());
        } else if (CourseEnums.RelationExamSource.JOB_LEARNING_RELATED_EXAM.getCode().equals(req.getExamSource())) {
            user.setRelationPositionExamId(req.getRelationId());
        } else if (CourseEnums.RelationExamSource.TASK_EXAM.getCode().equals(req.getExamSource())) {
            user.setRelationTaskId(req.getRelationTaskId());
        }
        //调整根据权限来确定批阅人
//        examService.fillRevierwer(user, exam);
        //查询用户所属组织
//        List<String> selectOrgList = organizeApi.getOrganizeIdsByUserId(req.getUserId());
//        if (CollectionUtil.isNotEmpty(selectOrgList)) {
//            user.setUserOrgList(String.join(",", selectOrgList));
//        }
        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(req.getUserId(), null);
        if (userPrimaryBoundOne != null && userPrimaryBoundOne.getOrganizeId() != null) {
            user.setUserOrgList(userPrimaryBoundOne.getOrganizeId());
        }
        user.setVersionBatch(exam.getVersionBatch());
        baseMapper.insert(user);
        return true;
    }

    /**
     * 取消学习了 但是未考试的用户数据
     *
     * @param req
     * @return
     */
    @Override
    public Boolean cancelPositionExam(InnerExamDto req) {

        log.error("取消未完成考试的用户数据={}", JSONUtil.toJsonStr(req));
        if (StringUtils.isEmpty(req.getExamId())) {
            throw new RuntimeException("取消未完成的用户考试,考试ID为空");
        }
        if (StringUtils.isEmpty(req.getRelationRankId())) {
            throw new RuntimeException("取消未完成的用户考试,岗位为空");
        }
        if (StringUtils.isEmpty(req.getRelationId())) {
            throw new RuntimeException("取消未完成的用户考试,关联业务ID为空");
        }
        if (null == req.getExamSource()) {
            throw new RuntimeException("取消未完成的用户考试,考试来源为空");
        }

        //构建修改wrap
        LambdaUpdateWrapper<FtbCultivateExamUser> wrapper = new LambdaUpdateWrapper<FtbCultivateExamUser>()
                .set(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.INVALID.getCode())
                .eq(FtbCultivateExamUser::getStatus, CourseEnums.ExamStatus.WAIT.getCode())
                .eq(FtbCultivateExamUser::getExamSource, req.getExamSource())
                .eq(FtbCultivateExamUser::getRelationPositionId, req.getRelationRankId())
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        if (CourseEnums.RelationExamSource.COURSE_RELATED_EXAM.getCode().equals(req.getExamSource())) {
            wrapper.eq(FtbCultivateExamUser::getRelationCourseExamId, req.getRelationId());
        } else {
            wrapper.eq(FtbCultivateExamUser::getRelationPositionExamId, req.getRelationId());
        }
        baseMapper.update(null, wrapper);
        if (CourseEnums.RelationExamSource.JOB_LEARNING_RELATED_EXAM.getCode().equals(req.getExamSource())) {
            LambdaUpdateWrapper<FtbCultivateExamUser> wrapper1 = new LambdaUpdateWrapper<FtbCultivateExamUser>()
                    .set(FtbCultivateExamUser::getExamIdentifyConfig, 0)
                    .eq(FtbCultivateExamUser::getRelationPositionId, req.getRelationRankId())
                    .eq(FtbCultivateExamUser::getExamId, req.getRelationId())
                    .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
            baseMapper.update(null, wrapper1);
        }

        return true;
    }


    /**
     * 查询用户已完成的考试列表
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public List<UserExamDetailVo> queryCompleteExamListForUserId(String userId) {
        //查看是否有记录
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .eq(FtbCultivateExamUser::getUserId, userId)
                .notIn(FtbCultivateExamUser::getStatus, CourseEnums.ExamStatus.WAIT.getCode(), CourseEnums.ExamStatus.OVERDUE.getCode())
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        List<FtbCultivateExamUser> examUserList = baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(examUserList)) {
            return new ArrayList<>();
        }
        List<UserExamDetailVo> list = new ArrayList<>();
        for (FtbCultivateExamUser examUser : examUserList) {
            UserExamDetailVo vo = new UserExamDetailVo();
            vo.setId(examUser.getId());
            vo.setScore(examUser.getScore());
            vo.setExamId(examUser.getExamId());
            vo.setDuration(examUser.getDuration());
            vo.setUserId(examUser.getUserId());
            vo.setStatus(examUser.getStatus());
            vo.setCorrectCount(examUser.getCorrectCount());
            vo.setPaperId(examUser.getPaperId());
            vo.setUserStartTime(examUser.getUserStartTime());
            vo.setStartTime(examUser.getStartTime());
            vo.setEndTime(examUser.getEndTime());
            vo.setFinishtime(examUser.getFinishTime());
            //2、查询考试信息和试卷信息
            FtbCultivateTestPaper paper = paperService.getById(examUser.getPaperId());
            vo.setExamTotleScore(paper.getTotalScore());
            vo.setQuestionNumber(paper.getQuestionNumber());
            vo.setPaperName(paper.getName());
            FtbCultivateExam exam = examService.getById(examUser.getExamId());
            vo.setExamName(exam.getExamName());
            vo.setExamType(exam.getExamType());
            vo.setExamTime(exam.getExamTime());
            vo.setExamlimitation(exam.getExamlimitation());
            vo.setExamSource(examUser.getExamSource());
            vo.setRelationRankId(examUser.getRelationRankId());
            vo.setRelationPositionExamId(examUser.getRelationPositionExamId());
            vo.setRelationCourseExamId(examUser.getRelationCourseExamId());
            vo.setRelationPositionId(examUser.getRelationPositionId());
            if (CourseEnums.ExamType.POSITION.getCode().equals(examUser.getExamType()) && StringUtils.isNotEmpty(examUser.getRelationPositionId())) {

                PositionVO positionVO = userApiV2Util.infoPosition(examUser.getRelationPositionId(), null);
                if (null != positionVO) {
                    vo.setCurrPostName(positionVO.getFullName());
                }
            }

            list.add(vo);
        }
        return list;
    }

    /**
     * 重新考试
     *
     * @param userExamId 用户考试ID
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public FtbCultivateExamUser reStartExam(String userExamId) {

        //获取当前用户信息
        String loginUserId = UserProvider.getLoginUserId();
        //查看用户考试信息
        FtbCultivateExamUser examUserRecord = baseMapper.selectOne(new LambdaQueryWrapper<FtbCultivateExamUser>()
                .eq(FtbCultivateExamUser::getUserId, loginUserId)
                .eq(FtbCultivateExamUser::getId, userExamId)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode()));
        if (null == examUserRecord) {
            throw new RuntimeException("用户考试信息不存在");
        }

        //查看考试信息
        FtbCultivateExam exam = examService.queryExamInfo(examUserRecord.getExamId());
        checkCanReExam(examUserRecord, exam);
        //没有就写入一条记录
        FtbCultivateExamUser user = FtbCultivateExamUser.builder()
                .examId(exam.getId())
                .examType(exam.getExamType())
                .userId(loginUserId)
                .status(CourseEnums.ExamStatus.WAIT.getCode())
                .userStartTime(new Date())
                .reviewerUserIds(examUserRecord.getReviewerUserIds())
                .reviewerRoleId(examUserRecord.getReviewerRoleId())
                .paperId(exam.getPaperId())
                .examSource(examUserRecord.getExamSource())
                .relationRankId(examUserRecord.getRelationRankId())
                .relationPositionExamId(examUserRecord.getRelationPositionExamId())
                .relationPositionId(examUserRecord.getRelationPositionId())
                .relationCourseExamId(examUserRecord.getRelationCourseExamId())
                .relationTaskId(examUserRecord.getRelationTaskId())
                .enabledMark(CourseEnums.EnabledMarkType.VALID.getCode())
                .batch(UUID.randomUUID().toString().replaceAll("-", ""))
                .build();
        if (CourseEnums.ExamType.BASE.getCode().equals(exam.getExamType())) {
            if (exam.getStartTime() != null) {
                user.setStartTime(exam.getStartTime());
            }
            if (exam.getEndTime() != null) {
                user.setEndTime(exam.getEndTime());
            }
        }
        if (exam.getExamType().equals(0)) {
            user.setVersionBatch(exam.getVersionBatch());
        }
        //查询用户所属组织
//        List<String> selectOrgList = organizeApi.getOrganizeIdsByUserId(examUserRecord.getUserId());
//        if (CollectionUtil.isNotEmpty(selectOrgList)) {
//            user.setUserOrgList(String.join(",", selectOrgList));
//        }
        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(examUserRecord.getUserId(), null);
        if (userPrimaryBoundOne != null && userPrimaryBoundOne.getOrganizeId() != null) {
            user.setUserOrgList(userPrimaryBoundOne.getOrganizeId());
        }
        user.setId(examUserRecord.getId());
        user.setAppShow(0);
        user.setDuration(0L);
        user.setScore(0);
        user.setAutoScore(0);
        user.setReadOverScore(0);
        user.setReviewerUserId("");
        if (examUserRecord.getStatus().equals(CourseEnums.ExamStatus.WAIT.getCode()) || examUserRecord.getStatus().equals(CourseEnums.ExamStatus.OVERDUE.getCode())) {
            user.setUserExamCount(examUserRecord.getUserExamCount());
        } else {
            user.setUserExamCount(examUserRecord.getUserExamCount() + 1);
        }
        user.setUserExamResultValid(0);//用户考试结果是否有效:0-有效,1-超过切屏次数视为作弊,2-超过考试时间无交互视为作弊
        baseMapper.updateById(user);

        //删除考试记录
        LambdaUpdateWrapper<FtbCultivateExamUserDetail> updateWrapper = new LambdaUpdateWrapper<FtbCultivateExamUserDetail>()
                .set(FtbCultivateExamUserDetail::getEnabledMark, CourseEnums.EnabledMarkType.INVALID.getCode())
                .eq(FtbCultivateExamUserDetail::getBatch, examUserRecord.getBatch())
                .eq(FtbCultivateExamUserDetail::getUserExamId, examUserRecord.getId())
                .eq(FtbCultivateExamUserDetail::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        userDetailService.update(updateWrapper);
        return user;
    }

    /**
     * 查询用户考试总数和已完成数
     *
     * @param userIds
     */
    @Override
    public Map<String, UserExamCount> queryExamTotalAndCompleteNumForUserIds(List<String> userIds) {
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .select(FtbCultivateExamUser::getId, FtbCultivateExamUser::getUserId, FtbCultivateExamUser::getStatus, FtbCultivateExamUser::getExamId, FtbCultivateExamUser::getExamSource,
                        FtbCultivateExamUser::getRelationCourseExamId, FtbCultivateExamUser::getRelationPositionExamId, FtbCultivateExamUser::getRelationRankId)
                .in(FtbCultivateExamUser::getUserId, userIds)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        List<FtbCultivateExamUser> examUserList = baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(examUserList)) {
            return new HashMap<>();
        }
        //转成成 userId ->map
        Map<String, List<FtbCultivateExamUser>> userIdToListMap = examUserList.stream()
                .collect(Collectors.groupingBy(FtbCultivateExamUser::getUserId));
        Map<String, UserExamCount> map = new HashMap<>();
        userIdToListMap.forEach((userId, list) -> {
            map.put(userId, QuestionAnalysisUtil.countCompleteAndTotleExamNum(list));
        });
        return map;
    }


    /**
     * 统计合格率
     *
     * @param req
     * @return
     */
    @Override
    public ExamStatisticsVo statistics(FtbCultivateStatisticsDTO req) {
        //1、查询组织
        List<String> selectOrgList = new ArrayList<>();
        if (StringUtils.isEmpty(req.getOrgId())) {
            return new ExamStatisticsVo();
        }

        List<String> powerOrgList = userApiV2Util.queryPowerOrgList();
        if (CollUtil.isEmpty(powerOrgList)) {
            return new ExamStatisticsVo();
        }

        if (!powerOrgList.contains(req.getOrgId())) {
            return new ExamStatisticsVo();
        }
        selectOrgList.add(req.getOrgId());
        if (req.getIsSelectNext() == 1) {
            List<OrganizeGeneralDetailVO> childrenById = userApiV2Util.organizesOrHaveChildByOrganizeIds(List.of(req.getOrgId()), true, null);
//            List<String> childrenById = organizeApi.getChildrenById(req.getOrgId());
            if (CollectionUtil.isNotEmpty(childrenById)) {
                selectOrgList.addAll(childrenById.stream().map(OrganizeGeneralDetailVO::getId).collect(Collectors.toList()));
            }
        }
        List<String> intersection = UserApiV2Util.getIntersection(powerOrgList, selectOrgList);
        if (CollUtil.isEmpty(intersection)) {
            return new ExamStatisticsVo();
        }
        selectOrgList = userExamUtil.uniqueStringList(intersection);
        List<UserPageListVO> userListForOrgIds = userApiV2Util.getUserListForOrgIds(selectOrgList, null);
        if (CollUtil.isEmpty(userListForOrgIds)) {
            return new ExamStatisticsVo();
        }


        InnerCultivateStatisticsDTO innerCultivateStatisticsDTO = new InnerCultivateStatisticsDTO();
        innerCultivateStatisticsDTO.setStartTime(req.getStartTime());
        innerCultivateStatisticsDTO.setEndTime(req.getEndTime());
        innerCultivateStatisticsDTO.setSelectUserIds(userListForOrgIds.stream().map(UserPageListVO::getId).collect(Collectors.toList()));
        //2、根据用户ID查询考试信息 当前时间段
        List<FtbCultivateExamUser> currExamUserList = baseMapper.webStatisticsForOrg(innerCultivateStatisticsDTO);
        StatisticsResultDto curr = QuestionAnalysisUtil.statisticeLv(currExamUserList);
        //3、查询整体的,应该是不需要查询整体的去掉
        innerCultivateStatisticsDTO.setStartTime(DateUtil.beginOfYear(req.getStartTime()));
        innerCultivateStatisticsDTO.setEndTime(DateUtil.endOfYear(req.getEndTime()));
        List<FtbCultivateExamUser> allExamUserList = baseMapper.webStatisticsForOrg(innerCultivateStatisticsDTO);
        StatisticsResultDto all = QuestionAnalysisUtil.statisticeLv(allExamUserList);
        ExamStatisticsVo vo = new ExamStatisticsVo();

        vo.setTotleRate(String.valueOf(all.getPassLv()));
        vo.setTotleNum(String.valueOf(all.getTotle()));
        vo.setPassNum(String.valueOf(all.getPass()));
        vo.setPassRate(String.valueOf(all.getPassLv()));
        vo.setNoPassNum(String.valueOf(all.getNoPass()));
        vo.setNoPassRate(String.valueOf(all.getNoPassLv()));


        vo.setCurrPassRate(String.valueOf(curr.getPassLv()));
        vo.setCurrExamTotleNum(String.valueOf(curr.getTotle()));
        vo.setCurrExamPassNum(String.valueOf(curr.getPass()));
        vo.setCurrExamNoPassNum(String.valueOf(curr.getNoPass()));
        vo.setCurrExamNoPassRate(String.valueOf(curr.getNoPassLv()));
        return vo;
    }

    /**
     * 统计合格率
     *
     * @param req
     * @return
     */
    @Override
    public ExamStatisticsVo statisticsNew(FtbCultivateStatisticsDTO req) {

        //1、根据组织查询用户列表
        ExamStatisticsVo vo = new ExamStatisticsVo();

        //2、根据用户ID查询考试信息 当前时间段
        Date start = req.getStartTime();
        Date end = req.getEndTime();

        InnerCultivateStatisticsDTO dto = new InnerCultivateStatisticsDTO();
        dto.setStartTime(start);
        dto.setEndTime(end);
        dto.setSelectOrgList(req.getOrgIds());
        dto.setSelectUserIds(req.getUserIds());
        List<FtbCultivateExamUser> examUserList = examUserMapper.webStatisticsForOrg(dto);
        StatisticsResultDto curr = QuestionAnalysisUtil.statisticeLv(examUserList);


        vo.setCurrPassRate(String.valueOf(curr.getPassLv()));
        vo.setCurrExamTotleNum(String.valueOf(curr.getTotle()));
        vo.setCurrExamPassNum(String.valueOf(curr.getPass()));
        vo.setCurrExamNoPassNum(String.valueOf(curr.getNoPass()));
        vo.setCurrExamNoPassRate(String.valueOf(curr.getNoPassLv()));
        return vo;
    }

    /**
     * 统计考试排名
     *
     * @param req
     * @return
     */

    @Override
    public List<UserRankingVo> statisticsExamRankingList(FtbCultivateStatisticsDTO req) {
        //1、查询组织

        if (StringUtils.isEmpty(req.getOrgId())) {
            return new ArrayList<>();
        }

        List<String> powerOrgList = userApiV2Util.queryPowerOrgList();
        if (CollUtil.isEmpty(powerOrgList)) {
            return new ArrayList<>();
        }

        if (!powerOrgList.contains(req.getOrgId())) {
            return new ArrayList<>();
        }
        List<String> selectOrgList = new ArrayList<>();
        selectOrgList.add(req.getOrgId());
        if (req.getIsSelectNext() == 1) {
            List<OrganizeGeneralDetailVO> childrenById = userApiV2Util.organizesOrHaveChildByOrganizeIds(List.of(req.getOrgId()), true, null);
//            List<String> childrenById = organizeApi.getChildrenById(req.getOrgId());
            if (CollectionUtil.isNotEmpty(childrenById)) {
                selectOrgList.addAll(childrenById.stream().map(OrganizeGeneralDetailVO::getId).collect(Collectors.toList()));
            }
        }
        List<String> intersection = UserApiV2Util.getIntersection(powerOrgList, selectOrgList);
        if (CollUtil.isEmpty(intersection)) {
            return new ArrayList<>();
        }
        selectOrgList = intersection;
        selectOrgList = userExamUtil.uniqueStringList(selectOrgList);
        List<UserPageListVO> userListForOrgIds = userApiV2Util.getUserListForOrgIds(selectOrgList, null);
        if (CollUtil.isEmpty(userListForOrgIds)) {
            return new ArrayList<>();
        }

        InnerCultivateStatisticsDTO innerCultivateStatisticsDTO = new InnerCultivateStatisticsDTO();
        innerCultivateStatisticsDTO.setStartTime(req.getStartTime());
        innerCultivateStatisticsDTO.setEndTime(req.getEndTime());
//        innerCultivateStatisticsDTO.setSelectOrgList(selectOrgList);
        innerCultivateStatisticsDTO.setSelectUserIds(userListForOrgIds.stream().map(UserPageListVO::getId).collect(Collectors.toList()));
        //根据用户分组 查询平均分排行榜
        List<UserRankingVo> userRankingVoList = baseMapper.queryAvgScore(innerCultivateStatisticsDTO);
        fillExamUserInfo(userRankingVoList);
        return userRankingVoList;
    }


    /**
     * 统计考试排名（不按照权限过滤）
     *
     * @param req 请求参数
     * @return 考试排名
     */

    @Override
    public List<UserRankingVo> statisticsExamRankingListNoPower(FtbCultivateStatisticsDTO req) {
        InnerCultivateStatisticsDTO innerCultivateStatisticsDTO = new InnerCultivateStatisticsDTO();
        innerCultivateStatisticsDTO.setStartTime(req.getStartTime());
        innerCultivateStatisticsDTO.setEndTime(req.getEndTime());
        innerCultivateStatisticsDTO.setSelectUserIds(req.getUserIds());
        //根据用户分组 查询平均分排行榜
        List<UserRankingVo> userRankingVoList = baseMapper.queryAvgScore(innerCultivateStatisticsDTO);
        fillExamUserInfo(userRankingVoList);
        return userRankingVoList;
    }


    /**
     * 查询用户考试信息 未考试的不记入合格率
     *
     * @param userIds 用户ID
     * @param start   开始时间
     * @param end     结束时间
     * @return
     */
    private List<FtbCultivateExamUser> queryUserExamForDate(List<String> userIds, Date start, Date end) {
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .select(FtbCultivateExamUser::getId, FtbCultivateExamUser::getStatus, FtbCultivateExamUser::getUserId, FtbCultivateExamUser::getExamId, FtbCultivateExamUser::getExamSource,
                        FtbCultivateExamUser::getRelationCourseExamId, FtbCultivateExamUser::getRelationPositionExamId, FtbCultivateExamUser::getRelationRankId, FtbCultivateExamUser::getPaperId)
                .in(FtbCultivateExamUser::getUserId, userIds)
                .notIn(FtbCultivateExamUser::getStatus, CourseEnums.ExamStatus.OVERDUE.getCode(), CourseEnums.ExamStatus.WAIT.getCode())
                .between(null != start && null != end, FtbCultivateExamUser::getFinishTime, start, end)
                .eq(FtbCultivateExamUser::getIsJoinCount, ExamUserStatisticsEnums.PARTICIPATE.getCode())
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        return baseMapper.selectList(wrapper);

    }


    /**
     * 检测并修改过期考试
     *
     * @return
     */
    @Override
    public Integer checkAndUpdateExpireUserExamStatus() {
        //构建修改wrap
        LambdaUpdateWrapper<FtbCultivateExamUser> wrapper = new LambdaUpdateWrapper<FtbCultivateExamUser>()
                .set(FtbCultivateExamUser::getStatus, CourseEnums.ExamStatus.OVERDUE.getCode())
                .set(FtbCultivateExamUser::getLastModifyTime, new Date())
                .lt(FtbCultivateExamUser::getEndTime, new Date())
                .eq(FtbCultivateExamUser::getStatus, CourseEnums.ExamStatus.WAIT.getCode())
                .eq(FtbCultivateExamUser::getExamType, CourseEnums.ExamType.BASE.getCode())
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        return baseMapper.update(null, wrapper);
    }

    /**
     * 查询我的考试数量，统计数量
     *
     * @return
     */
    @Override
    public MyBlowExamNum queryMyBlowExamNum() {
        String loginUserId = UserProvider.getLoginUserId();
        QueryMyCompleteExamListReq completeReq = new QueryMyCompleteExamListReq();
        completeReq.setUserId(loginUserId);

        QueryWaitMyExamListReq waitReq = new QueryWaitMyExamListReq();
        waitReq.setUserId(loginUserId);

        QueryExpireExamListReq expireReq = new QueryExpireExamListReq();
        expireReq.setUserId(loginUserId);
        List<RoleEntity> userRole = roleApi.getByUserId(loginUserId);
        if (CollectionUtil.isNotEmpty(userRole)) {
            //获取角色id列表
            for (RoleEntity roleEntity : userRole) {
                expireReq.getRoleIdList().add(roleEntity.getId());
                waitReq.getRoleIdList().add(roleEntity.getId());
            }
        }
        //查询过期
        int expire = baseMapper.queryExpireExamNum(expireReq);

        //查询完成的
        int complete = baseMapper.queryMyCompleteExamNum(completeReq);

        //查询带我批阅的
        int wait = baseMapper.queryWaitMyExamNum(waitReq);

        return new MyBlowExamNum(wait, complete, expire);
    }

    /**
     * @param userId     用户ID
     * @param positionId 岗位ID
     * @param settings   是否开启合格设置 1是 0 否
     * @return [1:已经完成考试或者合格     2:未完成考试, 3:考试未合格]
     */
    @Override
    public Integer queryExamIsCompleteForUserIdAndPostion(String userId, String positionId, Integer settings) {
//        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
//                .eq(FtbCultivateExamUser::getUserId, userId)
//                .eq(FtbCultivateExamUser::getRelationPositionId, positionId)
//                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode())
//                .orderByDesc(FtbCultivateExamUser::getCreatorTime).last("limit 1");
//        FtbCultivateExamUser examUser = baseMapper.selectOne(wrapper);
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .eq(FtbCultivateExamUser::getUserId, userId)
                .eq(FtbCultivateExamUser::getRelationPositionId, positionId)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode())
                .eq(FtbCultivateExamUser::getExamSource, 2)
                .orderByDesc(FtbCultivateExamUser::getCreatorTime).last("limit 1");
        FtbCultivateExamUser examUser = baseMapper.selectOne(wrapper);
        if (null == examUser) {
            return 0;
        }
        //（0待考试，1待批阅，2已逾期，3合格，4不合格 5优秀）
        if (examUser.getStatus() == 0 || examUser.getStatus() == 2 || examUser.getStatus() == 1) {
            return 2;
        }
        if (1 == settings && (examUser.getStatus() == 4)) {
            return 3;
        }
        return 1;
    }

    /**
     * 查询
     *
     * @param str                用户考试记录id
     * @param learningMapSetting 是否开启合格设置 1是 0 否
     * @return （0待考试，1待批阅，2已逾期，3合格，4不合格 5优秀）
     */
    @Override
    public Integer queryExamIsCompleteForUserIdAndPostionWithNew(String str, Integer learningMapSetting) {
        FtbCultivateExamUser examUser = baseMapper.selectById(str);
        if (null == examUser) {
            return 0;
        }
        //（0待考试，1待批阅，2已逾期，3合格，4不合格 5优秀）
        if (examUser.getStatus() == 0 || examUser.getStatus() == 2 || examUser.getStatus() == 1) {
            return 2;
        }
        if (1 == learningMapSetting && (examUser.getStatus() == 4)) {
            return 3;
        }
        return 1;
    }

    @Override
    @Transactional
    public void webRestartExam(WebRestartExamReq req) {
        FtbCultivateExam exam = examService.queryExamInfo(req.getExamId());
        if (CourseEnums.ExamType.BASE.getCode().equals(exam.getExamType())) {
            if (null == req.getStartTime()) {
                throw new RuntimeException("开始考试时间不能为空");
            } else if (null == req.getEndTime()) {
                throw new RuntimeException("结束考试时间不能为空");
            }
            if (req.getStartTime().after(req.getEndTime())) {
                throw new RuntimeException("考试开始时间不能大于结束时间");
            }
        }
        if (CollectionUtil.isEmpty(req.getUserExamIdList())) {
            throw new RuntimeException("请选择需要重考的员工");
        }
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .eq(FtbCultivateExamUser::getExamId, exam.getId())
                .in(FtbCultivateExamUser::getStatus, CourseEnums.ExamStatus.WAIT.getCode(), CourseEnums.ExamStatus.OVERDUE.getCode(), CourseEnums.ExamStatus.NO_PASS.getCode())
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode())
                .in(FtbCultivateExamUser::getId, req.getUserExamIdList())
                .orderByDesc(FtbCultivateExamUser::getCreatorTime);
        List<FtbCultivateExamUser> userExamList = baseMapper.selectList(wrapper);


        if (CollectionUtil.isEmpty(userExamList)) {
            return;
        }
        for (FtbCultivateExamUser oldExamUser : userExamList) {
            FtbCultivateExamUser examUser = new FtbCultivateExamUser();
            examUser.setId(oldExamUser.getId());
            examUser.setExamType(exam.getExamType());
            examUser.setPaperId(exam.getPaperId());
            examUser.setDuration(0L);
            examUser.setScore(0);
            examUser.setAutoScore(0);
            examUser.setReadOverScore(0);
            examUser.setReviewerUserId("");
            examUser.setStatus(CourseEnums.ExamStatus.WAIT.getCode());
            examUser.setEnabledMark(CourseEnums.EnabledMarkType.VALID.getCode());
            examUser.setAppShow(0);
            examUser.setUserExamResultValid(0);
            examUser.setUserId(oldExamUser.getUserId());
            examUser.setTotalScore(0);
            examUser.setQuestionNumber(0);
            examUser.setRemark(null);
            examUser.setBatch(UUID.randomUUID().toString().replaceAll("-", ""));
            if (oldExamUser.getStatus().equals(CourseEnums.ExamStatus.WAIT.getCode()) || oldExamUser.getStatus().equals(CourseEnums.ExamStatus.OVERDUE.getCode())) {
                examUser.setUserExamCount(oldExamUser.getUserExamCount());
            } else {
                examUser.setUserExamCount(oldExamUser.getUserExamCount() + 1);
            }
            examUser.setUserExamResultValid(0);//用户考试结果是否有效:0-有效,1-超过切屏次数视为作弊,2-超过考试时间无交互视为作弊
            if (CourseEnums.ExamType.BASE.getCode().equals(exam.getExamType())) {
                examUser.setStartTime(req.getStartTime());
                examUser.setEndTime(req.getEndTime());
            }
            UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(examUser.getUserId(), null);
//            List<String> selectOrgList = organizeApi.getOrganizeIdsByUserId(examUser.getUserId());
            if (userPrimaryBoundOne != null && userPrimaryBoundOne.getOrganizeId() != null) {
                examUser.setUserOrgList(userPrimaryBoundOne.getOrganizeId());
            }
            examUser.setVersionBatch(exam.getVersionBatch());
            baseMapper.updateById(examUser);
            //删除考试记录
            LambdaUpdateWrapper<FtbCultivateExamUserDetail> updateWrapper = new LambdaUpdateWrapper<FtbCultivateExamUserDetail>()
                    .set(FtbCultivateExamUserDetail::getEnabledMark, CourseEnums.EnabledMarkType.INVALID.getCode())
                    .eq(FtbCultivateExamUserDetail::getBatch, oldExamUser.getBatch())
                    .eq(FtbCultivateExamUserDetail::getUserExamId, oldExamUser.getId())
                    .eq(FtbCultivateExamUserDetail::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
            userDetailService.update(updateWrapper);
        }
    }

    /**
     * 视为作弊提交试卷
     *
     * @param cheatType  作弊类型 1-超过切屏次数视为作弊,2-超过考试时间无交互视为作弊
     * @param userExamId 用户考试ID
     * @param req
     * @return
     */
    @Override
    public void setCheat(String userExamId, Integer cheatType, SubExamQuestionReq req) throws Exception {
        ExamConfigEnums.ExamValidity cheatTypeEnum = ExamConfigEnums.ExamValidity.fromCode(cheatType);
        if (null == cheatTypeEnum || cheatTypeEnum == ExamConfigEnums.ExamValidity.VALID) {
            throw new RuntimeException("作弊类型参数错误");
        }
        if (CollectionUtil.isEmpty(req.getAnswerDetail())) {
            throw new RuntimeException("提交的答案信息为空");
        }
        if (null == req.getDuration()) {
            throw new RuntimeException("考试时长为空");
        }
        //获取当前用户信息
        String loginUserId = UserProvider.getLoginUserId();
        //查看是否有记录
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .eq(FtbCultivateExamUser::getUserId, loginUserId)
                .eq(FtbCultivateExamUser::getId, userExamId)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        FtbCultivateExamUser examUser = baseMapper.selectOne(wrapper);
        if (null == examUser) {
            throw new RuntimeException("用户考试信息不存在");
        }
        if (CourseEnums.EnabledMarkType.INVALID.getCode().equals(examUser.getEnabledMark())) {
            throw new RuntimeException("参加考试的人员考试取消");
        }
        // 查询考试作弊配置
        FtbCultivateExamSettingEntity setting = cultivateExamSettingService.getById(ConstantUtil.STR_TRUE);
        if (null == setting) {
            throw new Exception("查询考试配置失败");
        }
        //查看考试信息
        // FtbCultivateExam exam = examService.queryExamInfo(examUser.getExamId());
        if (cheatTypeEnum == ExamConfigEnums.ExamValidity.CHEATING_SCREEN_LIMIT_EXCEEDED) {
            if (setting.getBanScreenshot() == ConstantUtil.NUM_FALSE) {
                //未开启切屏防作弊
                log.error("未开启切屏防作弊,userExamId={}", userExamId);
                return;
            }
        } else if (cheatTypeEnum == ExamConfigEnums.ExamValidity.CHEATING_NO_INTERACTION_TIME_EXCEEDED) {
            if (setting.getNoInteractTimeout() == ConstantUtil.NUM_FALSE) {
                //未开启超时无交互退出是作弊
                log.error("未开启超时无交互退出是作弊,userExamId={}", userExamId);
                return;
            }
        }
        // 检测是否可以提交考试
        // checkSubmitExam(examUser, exam);
        //修改考试题目信息
        Date now = new Date();
        FtbCultivateExamUser updateExamUser = new FtbCultivateExamUser();
        updateExamUser.setId(examUser.getId());
        updateExamUser.setUserId(examUser.getUserId());
        updateExamUser.setCorrectCount(0);
        updateExamUser.setAutoScore(0);
        updateExamUser.setScore(0);
        updateExamUser.setFinishTime(now);
        updateExamUser.setUserStartTime(new Date(now.getTime() - req.getDuration() * 1000));
        updateExamUser.setDuration(req.getDuration());
        updateExamUser.setStatus(CourseEnums.ExamStatus.NO_PASS.getCode());
        updateExamUser.setUserExamResultValid(cheatTypeEnum.getCode());
        updateExamUser.setLastModifyTime(new Date());
        updateExamUser.setQuestionNumber(examUser.getQuestionNumber());
        updateExamUser.setTotalScore(examUser.getTotalScore());
        updateExamUser.setRemark(req.getRemark());
        baseMapper.updateById(updateExamUser);
    }

    /**
     * 用户考试的批阅人权限
     */
    @Override
    public void refreshUserExamPower() {
        //查询所有待批阅的
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .in(FtbCultivateExamUser::getStatus, CourseEnums.ExamStatus.WAIT_CHECK.getCode())
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode())
                .orderByDesc(FtbCultivateExamUser::getCreatorTime);
        List<FtbCultivateExamUser> waitUserExamList = baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(waitUserExamList)) {
            return;
        }
        //获取所有的考试id
        List<String> examIds = new ArrayList<>();
        for (FtbCultivateExamUser examUser : waitUserExamList) {
            examIds.add(examUser.getExamId());
        }
        examIds = userExamUtil.uniqueStringList(examIds);
        //查询考试信息
        List<FtbCultivateExam> examList = examService.listByIds(examIds);
        Map<String, FtbCultivateExam> examIdMap = new HashMap<>();//考试id-考试信息

        for (FtbCultivateExam exam : examList) {
            examIdMap.put(exam.getId(), exam);
        }

        //处理每一个考试的动态批阅人
        List<FtbCultivateExamUser> plExamUserList = new ArrayList<>();
        PermissionsCacheDTO permissionsCacheDTO = personnelPerUtils.doQueryUserPermissions(List.of("70"));
        for (FtbCultivateExamUser oldUserExam : waitUserExamList) {
            FtbCultivateExam exam = examIdMap.get(oldUserExam.getExamId());
            FtbCultivateExamUser examUser = new FtbCultivateExamUser();
            examUser.setId(oldUserExam.getId());
            examUser.setUserId(oldUserExam.getUserId());
            //填充批阅人信息 和阅卷角色
            if (null != exam) {
                examService.fillRevierwerNew(examUser, exam, permissionsCacheDTO);
            } else {
                examUser.setReviewerUserIds(oldUserExam.getReviewerUserIds());
            }

            if (StringUtils.isNotEmpty(examUser.getReviewerUserIds()) && examUser.getReviewerUserIds().equals(oldUserExam.getReviewerUserIds())) {
                continue;
            }
            plExamUserList.add(examUser);
        }
        log.info("异步修改用户权限：={}", JSONUtil.toJsonStr(plExamUserList));

        if (CollectionUtil.isNotEmpty(plExamUserList)) {
            updateBatchById(plExamUserList);
        }


    }

    /**
     * app批阅考试查询考试信息（简单）
     *
     * @param userExamId 用户考试记录id
     * @return
     */
    @Override
    public UserExamDetailVo queryUserExamSimpleMsg(String userExamId) {
        UserExamDetailVo vo = new UserExamDetailVo();
        //查询用户的考试汇总信息
        FtbCultivateExamUser examUser = queryAndCheckUserExam(userExamId);
        //查询考试信息
        FtbCultivateExam exam = examService.getById(examUser.getExamId());
        if (exam.getStatus().equals(3)) {
            vo.setIsNullify(1);
        } else {
            vo.setIsNullify(0);
        }
        if (examUser.getVersionBatch().equals(exam.getVersionBatch())) {
            if (CourseEnums.ExamStatus.WAIT.getCode().equals(examUser.getStatus()) || CourseEnums.ExamStatus.OVERDUE.getCode().equals(examUser.getStatus())) {
                vo.setNeedUpdate(exam.getNeedUpdate());
            }
        }
        exam = userExamUtil.checkAndUpdateExam(exam, examUser.getVersionBatch());
        vo.setId(examUser.getId());
        vo.setScore(examUser.getScore());
        vo.setExamId(examUser.getExamId());
        vo.setDuration(examUser.getDuration());
        vo.setUserId(examUser.getUserId());
        vo.setStatus(examUser.getStatus());
        vo.setReadOverScore(examUser.getReadOverScore());
        vo.setAutoScore(examUser.getAutoScore());
        vo.setCorrectCount(examUser.getCorrectCount());
        vo.setPaperId(examUser.getPaperId());
        vo.setUserStartTime(examUser.getUserStartTime());
        vo.setStartTime(examUser.getStartTime());
        vo.setEndTime(examUser.getEndTime());
        vo.setFinishtime(examUser.getFinishTime());
        vo.setBatch(examUser.getBatch());
        vo.setExamSource(examUser.getExamSource());
        vo.setRelationPositionExamId(examUser.getRelationPositionExamId());
        vo.setRelationCourseExamId(examUser.getRelationCourseExamId());
        vo.setRelationRankId(examUser.getRelationRankId());
        //查询考试信息和试卷信息

        if (CourseEnums.ExamStatus.WAIT.getCode().equals(examUser.getStatus()) || CourseEnums.ExamStatus.OVERDUE.getCode().equals(examUser.getStatus())) {
            vo.setExamTotleScore(exam.getCurrTotalScore());
            vo.setQuestionNumber(exam.getCurrQuestionNumber());
        } else {
            vo.setExamTotleScore(examUser.getTotalScore());
            vo.setQuestionNumber(examUser.getQuestionNumber());
        }

        vo.setPaperName(exam.getPaperName());
        vo.setExamName(exam.getExamName());
        vo.setExamType(exam.getExamType());
        vo.setExamTime(exam.getExamTime());
        vo.setExamlimitation(exam.getExamlimitation());
        vo.setDescription(exam.getDescription());
        //补充用户信息
        fillUserInfoForUserId(vo);
        if (exam.getStatus().equals(3)) {
            vo.setIsNullify(1);
        }


        //合格分数
        if (CourseEnums.ExamScoreCheckType.FIXED.getCode().equals(exam.getPassType())) {
            vo.setPassMark(exam.getPassMark());
        } else {
            vo.setPassMark(examUser.getTotalScore() * exam.getPassMark() / 100);
        }
        //优秀分数
        if (CourseEnums.ExamScoreCheckType.FIXED.getCode().equals(exam.getExcellentType())) {
            vo.setExcellentMark(exam.getExcellentMark());
        } else {
            vo.setExcellentMark(examUser.getTotalScore() * exam.getExcellentMark() / 100);
        }
        //常规考试 根据时间判断状态
        if (CourseEnums.ExamType.BASE.getCode().equals(exam.getExamType())) {
            Date currentTime = new Date();
            if (examUser.getStartTime() != null && examUser.getEndTime() != null) {
                if (currentTime.before(examUser.getStartTime())) {
                    //考试还未开始
                    vo.setStatus(CourseEnums.ExamTimeStatus.NOT_STARTED.getCode());
                } else if (currentTime.after(examUser.getEndTime())) {
                    //考试已经结束
                    vo.setStatus(CourseEnums.ExamTimeStatus.DONE.getCode());
                } else {
                    //考试正在进行中
                    vo.setStatus(CourseEnums.ExamTimeStatus.IN_PROGRESS.getCode());
                }
            } else {
                vo.setStatus(CourseEnums.ExamTimeStatus.IN_PROGRESS.getCode());
            }
        }
        //查询试卷题目统计数据
        List<ExamQuestionBakVo> questionList = HistoryPaperUtils.convertQuestionList(exam.getCurrQuestionList());
        List<FtbCultivateQuestion> halfFullQuestion = userExamUtil.queryHalfFullQuestionList(questionList);
        vo.setQuestionNumMap(HistoryPaperUtils.analysPaperQuestionCount(halfFullQuestion));

        return vo;
    }

    /**
     * 历史考试记录列表
     *
     * @param req
     * @return
     */
    @Override
    public PageInfo<ExamListUserVo> webHistoryExamUserList(WebHistoryQueryExamUserReq req) {
        return null;
    }

    /**
     * 隐藏我的考试记录
     *
     * @param userExamId 用户考试记录ID
     */
    @Override
    public void hiddenMyExamRecord(String userExamId) {
        if (StringUtils.isEmpty(userExamId)) {
            throw new RuntimeException("用户考试ID为空");
        }

        //1、查询
        FtbCultivateExamUser examUser = baseMapper.selectById(userExamId);
        if (null == examUser) {
            throw new RuntimeException("未查询到相关考试记录");
        }
        FtbCultivateExam exam = examService.getById(examUser.getExamId());
        if (null == exam) {
            throw new RuntimeException("考试信息不存在");
        }
        if (!exam.getStatus().equals(3)) {
            throw new RuntimeException("考试正常不能删除");
        }
        examUser.setAppShow(CourseEnums.ExamRecordDisplay.HIDDEN.getCode());
        baseMapper.updateById(examUser);
    }

    /**
     * 根据岗位查询指定用户的考试信息
     *
     * @param positionId        岗位id
     * @param userIdsByGradesId 用户列表
     * @return
     */
    @Override
    public FtbCultivatePositionExamVO queryExamPassingInformation(String positionId, List<String> userIdsByGradesId) {
        FtbCultivatePositionExamVO examVO = new FtbCultivatePositionExamVO();
        // 查寻这些岗位下那些人参与了岗位学习考试
        List<FtbCultivateExamUser> cultivateExamUsers = baseMapper.queryTheListOfQualifiedPersonsNew(userIdsByGradesId, positionId);
        StatisticsResultDto curr = QuestionAnalysisUtil.statisticeLv(cultivateExamUsers);
        examVO.setNumberExam(curr.getPass());
        examVO.setExamPassRate(BigDecimal.valueOf(curr.getPassLv()));
        return examVO;
    }

    /**
     * 批量查询一个岗位的指定人员的考试信息
     *
     * @param userIds    用户id集合
     * @param positionId 岗位id
     * @param exmIds     考试id
     * @return
     */
    @Override
    public FtbCultivatePositionExamPersonVO queryTheListOfQualifiedPersons(List<String> userIds, String positionId, List<String> exmIds) {
        FtbCultivateExamUser cultivateExamUsers = baseMapper.queryTheListOfQualifiedPersons(userIds, positionId, exmIds);
        return FtbCultivatePositionExamPersonVO.covert(cultivateExamUsers);
    }

    /**
     * 根据考试id和批次查询考试人员列表
     *
     * @param examId       考试id
     * @param versionBatch 批次
     * @return
     */
    @Override
    public List<FtbCultivateExamUser> queryCompleteExamUserListForExamIdAndBatch(String examId, String versionBatch) {
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>();
        wrapper.notIn(FtbCultivateExamUser::getStatus, CourseEnums.ExamStatus.OVERDUE.getCode())
                .eq(FtbCultivateExamUser::getExamId, examId)
                .eq(FtbCultivateExamUser::getVersionBatch, versionBatch)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        return baseMapper.selectList(wrapper);
    }

    /**
     * 根据考试ID查询待考试的列表
     *
     * @param examId 考试ID
     * @return
     */
    @Override
    public List<WaitReadOverNumVo> queryWaitReadOverNum(String examId) {
        return baseMapper.queryWaitReadOverNum(examId);
    }

    /**
     * 检查用户是否完成考试
     *
     * @param positionId 岗位ID
     * @param userId     用户ID
     * @return
     */
    @Override
    public CompleteExamVo checkIsCompleteExamForUserId(String positionId, String userId) {
        CompleteExamVo vo = new CompleteExamVo();
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>()
                .eq(FtbCultivateExamUser::getRelationPositionId, positionId)
                .eq(FtbCultivateExamUser::getExamSource, 2)
                .eq(FtbCultivateExamUser::getUserId, userId)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode()).orderByDesc(FtbCultivateExamUser::getCreatorTime);
        List<FtbCultivateExamUser> examUserList = baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(examUserList)) {
            return vo;
        }
        FtbCultivateExamUser examUser = examUserList.get(0);
        vo.setIsHasExam(true);
        if (examUser.getStatus().equals(CourseEnums.ExamStatus.WAIT_CHECK.getCode())
                || examUser.getStatus().equals(CourseEnums.ExamStatus.PASS.getCode())
                || examUser.getStatus().equals(CourseEnums.ExamStatus.VERY_PASS.getCode())
                || examUser.getStatus().equals(CourseEnums.ExamStatus.NO_PASS.getCode())) {
            vo.setIsComplete(true);
        }
        return vo;
    }

    /**
     * 岗位学习的考试 或者 是否是考试合格才能触发鉴定 发生变化时回调
     *
     * @param positionId         岗位学ID
     * @param examId             考试ID
     * @param examIdentifyConfig 是否是考试合格才能触发鉴定,0-否 1-是
     */
    @Override
    public void positionConfigChangeCallBack(String positionId, String examId, Integer examIdentifyConfig) {
        log.error("positionConfigChangeCallBack positionId={},examId={},examIdentifyConfig={}", positionId, examId, examIdentifyConfig);


        LambdaUpdateWrapper<FtbCultivateExamUser> updateWrapper1 = new LambdaUpdateWrapper<FtbCultivateExamUser>()
                .set(FtbCultivateExamUser::getExamIdentifyConfig, 0)
                .eq(FtbCultivateExamUser::getRelationPositionId, positionId)
                .eq(FtbCultivateExamUser::getExamSource, 2)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        this.update(updateWrapper1);
        if (examIdentifyConfig == 1 && StringUtils.isNotEmpty(examId)) {
            LambdaUpdateWrapper<FtbCultivateExamUser> updateWrapper2 = new LambdaUpdateWrapper<FtbCultivateExamUser>()
                    .set(FtbCultivateExamUser::getExamIdentifyConfig, examIdentifyConfig)
                    .eq(FtbCultivateExamUser::getRelationPositionId, positionId)
                    .eq(FtbCultivateExamUser::getExamId, examId)
                    .eq(FtbCultivateExamUser::getExamSource, 2)
                    .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
            this.update(updateWrapper2);
        }


    }


    /**
     * 统计通过的任务考试数量
     *
     * @param taskIds 任务集合ID
     * @return
     */
    @Override
    public Map<String, Integer> groupPassCountNum(List<String> taskIds) {
        Map<String, Integer> ret = new HashMap<>();
        List<BatchCommonCountDto> list = baseMapper.groupPassCountNum(taskIds);
        if (CollectionUtil.isEmpty(list)) {
            return ret;
        }
        for (BatchCommonCountDto batchCommonCountDto : list) {
            ret.put(batchCommonCountDto.getSelectKey(), batchCommonCountDto.getNum());
        }
        return ret;
    }

    /**
     * 批量统计所有的任务考试数量
     *
     * @param taskIds 任务ID集合
     * @return
     */
    @Override
    public Map<String, Integer> groupAllCountNum(List<String> taskIds) {
        Map<String, Integer> ret = new HashMap<>();
        List<BatchCommonCountDto> list = baseMapper.groupAllCountNum(taskIds);
        if (CollectionUtil.isEmpty(list)) {
            return ret;
        }
        for (BatchCommonCountDto batchCommonCountDto : list) {
            ret.put(batchCommonCountDto.getSelectKey(), batchCommonCountDto.getNum());
        }
        return ret;
    }

    @Override
    public Map<String, Integer> groupAllCountNumV2(List<String> taskIds) {
        Map<String, Integer> ret = new HashMap<>();
        List<BatchCommonCountDto> list = baseMapper.groupAllCountNumV2(taskIds);
        if (CollectionUtil.isEmpty(list)) {
            return ret;
        }
        for (BatchCommonCountDto batchCommonCountDto : list) {
            ret.put(batchCommonCountDto.getSelectKey(), batchCommonCountDto.getNum());
        }
        return ret;
    }

    /**
     * 删除任务考试记录
     *
     * @param taskId 任务ID
     */
    @Override
    public void deleteTaskExamUserRecord(String taskId) {
        LambdaUpdateWrapper<FtbCultivateExamUser> updateWrapper = new LambdaUpdateWrapper<FtbCultivateExamUser>()
                .set(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.INVALID.getCode())
                .eq(FtbCultivateExamUser::getRelationTaskId, taskId)
                .eq(FtbCultivateExamUser::getExamSource, 4)
                .eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
        this.update(updateWrapper);
    }

    /**
     * 统计通过的任务考试数量
     *
     * @param taskIds 任务集合ID
     * @return 统计结果
     */
    @Override
    public Map<String, Integer> groupPassCountNumV2(List<String> taskIds) {
        Map<String, Integer> ret = new HashMap<>();
        List<BatchCommonCountDto> list = baseMapper.groupPassCountNumV2(taskIds);
        if (CollectionUtil.isEmpty(list)) {
            return ret;
        }
        for (BatchCommonCountDto batchCommonCountDto : list) {
            ret.put(batchCommonCountDto.getSelectKey(), batchCommonCountDto.getNum());
        }
        return ret;
    }
}
