package com.qmth.distributed.print.business.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deepoove.poi.data.*;
import com.deepoove.poi.data.style.CellStyle;
import com.deepoove.poi.data.style.ParagraphStyle;
import com.deepoove.poi.data.style.RowStyle;
import com.google.gson.reflect.TypeToken;
import com.qmth.distributed.print.business.bean.dto.*;
import com.qmth.distributed.print.business.bean.dto.report.*;
import com.qmth.distributed.print.business.bean.result.CourseWeightResult;
import com.qmth.distributed.print.business.bean.result.FinalScoreResult;
import com.qmth.distributed.print.business.bean.result.report.PaperStructDimensionResult;
import com.qmth.distributed.print.business.bean.result.report.word.CourseReportBean;
import com.qmth.distributed.print.business.bean.result.report.word.CourseTargetTableBean3;
import com.qmth.distributed.print.business.bean.result.report.word.CourseTargetTableBean4;
import com.qmth.distributed.print.business.entity.TCPaperStruct;
import com.qmth.distributed.print.business.entity.TRBasicInfo;
import com.qmth.distributed.print.business.entity.TRExamStudent;
import com.qmth.distributed.print.business.mapper.TRBasicInfoMapper;
import com.qmth.distributed.print.business.service.*;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicCourse;
import com.qmth.teachcloud.common.entity.BasicSemester;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.service.BasicCourseService;
import com.qmth.teachcloud.common.service.BasicSemesterService;
import com.qmth.teachcloud.common.util.GsonUtil;
import com.qmth.teachcloud.common.util.JacksonUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
import com.qmth.teachcloud.mark.bean.archivescore.ScoreRangeVo;
import com.qmth.teachcloud.mark.entity.MarkPaper;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 报告基本情况表 服务实现类
 * </p>
 *
 * @author wangliang
 * @since 2024-02-18
 */
@Service
public class TRBasicInfoServiceImpl extends ServiceImpl<TRBasicInfoMapper, TRBasicInfo> implements TRBasicInfoService {

    @Resource
    TCFinalScoreService tcFinalScoreService;

    @Resource
    BasicSemesterService basicSemesterService;

    @Resource
    TCPaperStructService tcPaperStructService;

    @Resource
    TRBasicInfoService trBasicInfoService;

    @Resource
    TRExamStudentService trExamStudentService;

    @Resource
    CourseWeightService courseWeightService;

    @Resource
    ExamStudentService examStudentService;

    @Resource
    BasicCourseService basicCourseService;

    protected static final String tbBgColor = "F2F2F2";
    protected static final String tbPercentWidth = "100%";

    /**
     * 根据考试id/课程编码/试卷编码查询数据库数据
     *
     * @param examId
     * @param courseCode
     * @param paperNumber
     * @param teachCourseId
     * @return
     */
    @Override
    public TRBasicInfo queryBasicInfo(Long examId, String courseCode, String paperNumber, Long teachCourseId) {
        QueryWrapper<TRBasicInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TRBasicInfo::getExamId, examId).eq(TRBasicInfo::getCourseCode, courseCode);
        if (Objects.nonNull(paperNumber)) {
            queryWrapper.lambda().and(w -> w.eq(TRBasicInfo::getPaperNumber, paperNumber).or().isNull(TRBasicInfo::getPaperNumber));
        }
        queryWrapper.lambda().eq(TRBasicInfo::getTeachCourseId, teachCourseId);
        return trBasicInfoService.getOne(queryWrapper);
    }

    /**
     * 获取课程目标考核分布-分数图
     *
     * @param trBasicInfo
     * @param markPaper
     * @return
     */
    @Override
    public ReportScoreViewDto getScoreList(TRBasicInfo trBasicInfo, MarkPaper markPaper) {
        FinalScoreDto finalScoreDto = tcFinalScoreService.finalScoreScoreOverView(trBasicInfo.getExamId(), trBasicInfo.getCourseCode(), trBasicInfo.getPaperNumber(), trBasicInfo.getTeachCourseId());
        Objects.requireNonNull(finalScoreDto, "未找到期末成绩分数信息");

        ReportScoreViewDto reportScoreViewDto = null;
        TCPaperStruct tcPaperStruct = tcPaperStructService.queryPaperStruct(markPaper.getExamId(), markPaper.getCourseCode(), markPaper.getPaperNumber(), trBasicInfo.getTeachCourseId());
        if (Objects.nonNull(tcPaperStruct) && Objects.nonNull(tcPaperStruct.getPaperStruct()) && Objects.nonNull(tcPaperStruct.getTotalScore())) {
            BasicCourse basicCourse = basicCourseService.getByCode(trBasicInfo.getCourseCode());
            markPaper = new MarkPaper(markPaper.getExamId(), markPaper.getCourseCode(), basicCourse.getName(), markPaper.getPaperNumber(), tcPaperStruct.getTotalScore(), tcPaperStruct.getPassScore());
        }
        fillScoreRange(finalScoreDto, trBasicInfo.getExamId(), trBasicInfo.getPaperNumber(), trBasicInfo.getTeachCourseId(), markPaper);
        List<ScoreRangeVo> scoreRangeVoList = finalScoreDto.getScoreRange();
        if (!CollectionUtils.isEmpty(scoreRangeVoList)) {
            Integer failCount = scoreRangeVoList.get(0).getStudentCount();//第一行数据默认为不及格
            Double failRate = scoreRangeVoList.get(0).getRate();

            scoreRangeVoList.remove(0);
            List<ReportScoreRangeViewDto> scoreRangeViewDtoList = GsonUtil.fromJson(JacksonUtil.parseJson(scoreRangeVoList), new TypeToken<List<ReportScoreRangeViewDto>>() {
            }.getType());
            reportScoreViewDto = new ReportScoreViewDto(failCount, failRate, scoreRangeViewDtoList);
        }
        return reportScoreViewDto;
    }

    /**
     * 获取计算参数
     *
     * @param trBasicInfo
     * @param paperStructDimensionResultList
     * @return
     */
    @Override
    public Map<String, Object> getReportCalculateParams(TRBasicInfo trBasicInfo, List<PaperStructDimensionResult> paperStructDimensionResultList, CourseWeightResult courseWeightResult) {
        Map<String, Object> paramsMap = new HashMap<>();
        //查询考生数据
        List<FinalScoreResult> finalScoreResultList = tcFinalScoreService.examStudentOverview(trBasicInfo.getExamId(), trBasicInfo.getCourseCode(), trBasicInfo.getPaperNumber(), trBasicInfo.getTeachCourseId());//考生成绩
        if (CollectionUtils.isEmpty(finalScoreResultList)) {
            throw ExceptionResultEnum.ERROR.exception("成绩数据异常，平时成绩与期末成绩里考生名单不一致，请检查");
        }

//        Map<String, Map<Long, Map<Long, DimensionDto>>> finalScoreExamStudentDimensionMap = new LinkedHashMap<>();//汇总考生课程目标-知识点卷面分（知识点得分用）
        Map<String, Map<Long, Double>> finalScoreExamStudentTargetMap = new LinkedHashMap<>();//汇总考生课程目标-课程目标卷面分
        Map<Long, Map<Long, DimensionDto>> targetDimensionMap = new LinkedHashMap<>();//课程目标-知识点-卷面分（word报表用）

        List<ReportExamStudentDto> examStudentList = null;//考生集合
        Map<String, FinalScoreResult> finalScoreResultMap = null;//考生成绩map
        Map<String, PaperStructDimensionResult> paperStructResultMap = null;//试卷蓝图map
        Map<Long, CourseTargetWordDto> targetWordMap = null;//word目标集合
        Map<Long, CourseTargetWebDto> targetWebMap = null;//web目标集合
        Map<String, ReportEvaluationDto> usualScoreMap = null;//平时作业集合
        Long weightSettingSign = null, dimensionSign = null;//权重变化id,知识点变化id
        if (!CollectionUtils.isEmpty(finalScoreResultList)) {
            targetWordMap = new LinkedHashMap<>();
            targetWebMap = new LinkedHashMap<>();
            usualScoreMap = new LinkedHashMap<>();

            List<CourseWeightDto> courseWeightDtoList = courseWeightResult.getSubmitForm();
            weightSettingSign = courseWeightResult.getWeightSettingSign();
            dimensionSign = courseWeightResult.getDimensionSign();

            for (CourseWeightDto courseWeightDto : courseWeightDtoList) {
                List<CourseWeightDetailDto> courseWeightDetailDtoList = courseWeightDto.getEvaluationList();
                CourseTargetWordDto courseTargetWordDto = new CourseTargetWordDto(courseWeightDto);
                targetWordMap.put(courseWeightDto.getCourseTargetId(), courseTargetWordDto);//word模版

                CourseTargetWebDto courseTargetWebDto = new CourseTargetWebDto(courseWeightDto);
                targetWebMap.put(courseWeightDto.getCourseTargetId(), courseTargetWebDto);//web模版

                if (!CollectionUtils.isEmpty(courseWeightDetailDtoList)) {
                    List<ReportEvaluationDto> reportEvaluationDtoList = new ArrayList<>(courseWeightDetailDtoList.size());
                    List<ReportEvaluationDto> usualScoreDetailList = new ArrayList<>(courseWeightDetailDtoList.size());
                    UsualScoreWordDto usualScoreWordDto = new UsualScoreWordDto(courseWeightResult.getCustomRate());
                    usualScoreWordDto.setUsualScoreDetailList(usualScoreDetailList);
                    BigDecimal usualScoreTargetSumScore = new BigDecimal(0);//平常作业目标总分
                    for (CourseWeightDetailDto courseWeightDetailDto : courseWeightDetailDtoList) {
                        //期末考试
                        if (courseWeightDetailDto.getEnable() && Objects.equals(courseWeightDetailDto.getEvaluationName(), SystemConstant.FINAL_SCORE_STR)) {
                            FinalScoreWordDto finalScoreWordDto = new FinalScoreWordDto(courseWeightDto.getCourseTargetId(), courseWeightDetailDto, courseWeightResult.getDefaultRate());
                            courseTargetWordDto.setFinalScoreDto(finalScoreWordDto);
                            ReportEvaluationDto reportEvaluationDto = new ReportEvaluationDto(courseWeightDto.getCourseTargetId(), courseWeightDetailDto, courseWeightResult.getDefaultRate(), 0.0d, courseWeightDto.getTotalScore().doubleValue());
                            reportEvaluationDtoList.add(reportEvaluationDto);
                        }//非期末考试
                        else if (courseWeightDetailDto.getEnable() && !Objects.equals(courseWeightDetailDto.getEvaluationName(), SystemConstant.FINAL_SCORE_STR)) {
                            BigDecimal usualScoreRealityWeight = usualScoreWordDto.getUsualScoreTargetSumWeight().divide(SystemConstant.PERCENT, 2, BigDecimal.ROUND_HALF_UP).multiply(courseWeightDetailDto.getWeight()).setScale(2, BigDecimal.ROUND_HALF_UP);
                            Double originalTargetScore = courseWeightDto.getTotalWeight().multiply(courseWeightDetailDto.getWeight()).divide(SystemConstant.PERCENT, 2, BigDecimal.ROUND_HALF_UP).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                            ReportEvaluationDto reportEvaluationDto = new ReportEvaluationDto(courseWeightDto.getCourseTargetId(), courseWeightDetailDto, usualScoreRealityWeight, 0.0d, originalTargetScore);
                            usualScoreTargetSumScore = usualScoreTargetSumScore.add(reportEvaluationDto.getTargetScore());
                            usualScoreDetailList.add(reportEvaluationDto);
                            reportEvaluationDtoList.add(reportEvaluationDto);
                            usualScoreMap.put(courseWeightDetailDto.getEvaluationName(), reportEvaluationDto);
                        }
                    }
                    usualScoreWordDto.setUsualScoreTargetSumScore(usualScoreTargetSumScore);
                    Collections.sort(reportEvaluationDtoList);
                    courseTargetWebDto.setEvaluationList(reportEvaluationDtoList);

                    courseTargetWordDto.setUsualScoreDto(usualScoreWordDto);
                }
            }

            //期末成绩明细map
            paperStructResultMap = paperStructDimensionResultList.stream().collect(Collectors.toMap(k -> k.getMainNumber() + "-" + k.getSubNumber(), Function.identity(), (dto1, dto2) -> dto1));
            finalScoreResultMap = finalScoreResultList.stream().collect(Collectors.toMap(FinalScoreResult::getStudentCode, Function.identity(), (dto1, dto2) -> dto1));

            examStudentList = new ArrayList<>(finalScoreResultList.size());
            for (int i = 0; i < finalScoreResultList.size(); i++) {
                FinalScoreResult finalScoreResult = finalScoreResultList.get(i);
                //解析期末成绩知识点
                List<TCFinalScoreDto> tcFinalScoreDtoList = GsonUtil.fromJson(finalScoreResult.getFinalScoreDetail(), new TypeToken<List<TCFinalScoreDto>>() {
                }.getType());
                for (TCFinalScoreDto t : tcFinalScoreDtoList) {
                    Double score = Objects.nonNull(t.getScore()) ? Double.parseDouble(t.getScore().toString()) : 0d;
                    PaperStructDimensionResult paperStructDimensionResult = paperStructResultMap.get(t.getName().toString());
                    if (Objects.nonNull(paperStructDimensionResult)) {
                        List<CourseTargetWebDto> courseTargetDtoList = paperStructDimensionResult.getTargetList();
                        for (CourseTargetWebDto courseTargetDto : courseTargetDtoList) {
                            this.calculateFinalScoreByTargetExamStudent(finalScoreExamStudentTargetMap, finalScoreResult, courseTargetDto, score);
                            //知识点-期末考试明细分
                            List<DimensionDto> dimensionDtoList = courseTargetDto.getDimensionList();
                            for (DimensionDto dimensionDto : dimensionDtoList) {
                                //考生知识点
//                                this.calculateFinalScoreByDimensionExamStudent(finalScoreExamStudentDimensionMap,
//                                        finalScoreResult, courseTargetDto, dimensionDto, score);
                                if (i == 0) {//计算各知识点原始卷面分总和
                                    Double paperScore = paperStructDimensionResult.getScore();
                                    //目标-考生知识点去重
                                    if (!targetDimensionMap.containsKey(courseTargetDto.getTargetId())) {
                                        Map<Long, DimensionDto> dimensionMap = new LinkedHashMap<>();
                                        dimensionMap.put(dimensionDto.getDimensionId(), new DimensionDto(courseTargetDto.getTargetId(), dimensionDto, paperScore));
                                        targetDimensionMap.put(courseTargetDto.getTargetId(), dimensionMap);
                                    } else {
                                        Map<Long, DimensionDto> dimensionMap = targetDimensionMap.get(courseTargetDto.getTargetId());
                                        if (!dimensionMap.containsKey(dimensionDto.getDimensionId())) {
                                            dimensionMap.put(dimensionDto.getDimensionId(), new DimensionDto(courseTargetDto.getTargetId(), dimensionDto, paperScore));
                                        } else {
                                            DimensionDto dimensionDtoTemp = dimensionMap.get(dimensionDto.getDimensionId());
                                            dimensionMap.put(dimensionDto.getDimensionId(), new DimensionDto(courseTargetDto.getTargetId(), dimensionDto, dimensionDtoTemp.getDimensionScore().doubleValue() + paperScore.doubleValue()));
                                        }
                                        targetDimensionMap.put(courseTargetDto.getTargetId(), dimensionMap);
                                    }
                                }
                            }
                        }
                    }
                }

                Map<Long, CourseTargetWordDto> finalTargetWordMap = targetWordMap;
                Map<Long, CourseTargetWebDto> finalTargetWebMap = targetWebMap;
                targetDimensionMap.forEach((k, v) -> {
                    List<DimensionDto> dimensionDtoList = new ArrayList<>(v.values());
                    Collections.sort(dimensionDtoList);
                    Double dimensionScoreSum = dimensionDtoList.stream().mapToDouble(DimensionDto::getDimensionScore).sum();
                    List<String> dimensionDtoNameList = dimensionDtoList.stream().map(s -> s.getDimensionName()).collect(Collectors.toList());
                    if (finalTargetWordMap.containsKey(k)) {
                        finalTargetWordMap.get(k).getFinalScoreDto().setDimensionList(dimensionDtoList);
                        finalTargetWordMap.get(k).setDimensionScoreSum(dimensionScoreSum);
                        finalTargetWordMap.get(k).setDimensionPoint(String.join(",", dimensionDtoNameList));
                    }
                    if (finalTargetWebMap.containsKey(k)) {
                        finalTargetWebMap.get(k).setDimensionScoreSum(dimensionScoreSum);
                        finalTargetWebMap.get(k).setDimensionPoint(String.join(",", dimensionDtoNameList));
                    }
//                    Map<Long, Map<Long, DimensionDto>> mapExamStudent1 = finalScoreExamStudentDimensionMap.get(finalScoreResult.getStudentCode());
//                    Map<Long, DimensionDto> mapExamStudent2 = mapExamStudent1.get(k);
//                    List<DimensionDto> list = new ArrayList<>(mapExamStudent2.values());
//                    Double score = list.stream().mapToDouble(DimensionDto::getDimensionScore).sum();
//                    Map<Long, Double> mapDimension = finalScoreResult.getFinalScoreDimension();
//                    mapDimension.put(k, score);

                    Map<Long, Double> doubleMap = finalScoreExamStudentTargetMap.get(finalScoreResult.getStudentCode());
                    Map<Long, Double> mapTarget = finalScoreResult.getFinalScoreTarget();
                    mapTarget.put(k, doubleMap.get(k));
                });

                //解析平时作业分数图
                ReportExamStudentUsualScoreDto reportExamStudentUsualScoreDto = this.calculateUsualScoreByExamStudent(finalScoreResult, usualScoreMap, targetWordMap);
                finalScoreResult.setUsualScoreDto(reportExamStudentUsualScoreDto);
                examStudentList.add(new ReportExamStudentDto(finalScoreResult));
            }
        }

        paramsMap.put("finalScoreResultList", finalScoreResultList);
        paramsMap.put("usualScoreMap", usualScoreMap);
//        paramsMap.put("finalScoreExamStudentDimensionMap", finalScoreExamStudentDimensionMap);
        paramsMap.put("finalScoreExamStudentTargetMap", finalScoreExamStudentTargetMap);
        paramsMap.put("examStudentList", examStudentList);
        paramsMap.put("finalScoreResultMap", finalScoreResultMap);
        paramsMap.put("targetWordMap", targetWordMap);
        paramsMap.put("targetWebMap", targetWebMap);
        paramsMap.put("weightSettingSign", weightSettingSign);
        paramsMap.put("dimensionSign", dimensionSign);
        return paramsMap;
    }

    /**
     * 计算课程考核成绩评价结果
     *
     * @param trBasicInfo
     * @return
     */
    @Override
    public ReportCourseEvaluationResultDto reportCalculateCourseEvaluationResult(TRBasicInfo trBasicInfo, Map<String, Object> paramsMap) {
        ReportCourseEvaluationResultDto reportCourseEvaluationResultDto = null;
        List<TRExamStudent> trExamStudentList = trExamStudentService.list(new QueryWrapper<TRExamStudent>().lambda().eq(TRExamStudent::getrBasicInfoId, trBasicInfo.getId()));
        if (!CollectionUtils.isEmpty(trExamStudentList)) {
            BigDecimal targetEvaluationSumValue = new BigDecimal(0);
            Map<Long, CourseTargetWebDto> targetWebMap = (Map<Long, CourseTargetWebDto>) paramsMap.get("targetWebMap");
            Map<Long, CourseTargetWordDto> targetWordMap = (Map<Long, CourseTargetWordDto>) paramsMap.get("targetWordMap");
            TRExamStudent targetAvg = trExamStudentList.get(trExamStudentList.size() - 2);//平均分
            if (Objects.nonNull(targetAvg) && Objects.equals(targetAvg.getName(), "平均分") && Objects.nonNull(targetAvg.getResultDetail())) {
                List<ReportExamStudentTargetDto> reportExamStudentTargetAvgDtoList = GsonUtil.fromJson(targetAvg.getResultDetail(), new TypeToken<List<ReportExamStudentTargetDto>>() {
                }.getType());
                for (ReportExamStudentTargetDto r : reportExamStudentTargetAvgDtoList) {
                    Double targetAvgSumScore = 0.0d;//平均分总和
                    BigDecimal targetSumScore = new BigDecimal(0);//目标分总和
                    if (targetWebMap.containsKey(r.getTargetId())) {
                        CourseTargetWebDto courseTargetWebDto = targetWebMap.get(r.getTargetId());
                        CourseTargetWordDto courseTargetWordDto = targetWordMap.get(r.getTargetId());

                        List<ReportEvaluationDto> reportEvaluationDtoList = courseTargetWebDto.getEvaluationList();
                        Map<Long, ReportEvaluationDto> reportEvaluationDtoMap = reportEvaluationDtoList.stream().collect(Collectors.toMap(ReportEvaluationDto::getEvaluationId, Function.identity(), (dto1, dto2) -> dto1));

                        ReportExamStudentFinalScoreDto reportExamStudentFinalScoreDto = r.getFinalScore();
                        ReportExamStudentUsualScoreDto reportExamStudentUsualScoreDto = r.getUsualScore();

                        //期末成绩换算
                        ReportEvaluationDto reportEvaluationDto = reportEvaluationDtoMap.get(reportExamStudentFinalScoreDto.getEvaluationId());
                        reportEvaluationDto.setTargetAvgScore(reportExamStudentFinalScoreDto.getMatrixAvgScore());
                        targetAvgSumScore = targetAvgSumScore + reportEvaluationDto.getTargetAvgScore();
                        targetSumScore = targetSumScore.add(reportEvaluationDto.getTargetScore());

                        //平时作业换算
                        List<ReportExamStudentUsualScoreObjDto> reportExamStudentUsualScoreObjDtoList = reportExamStudentUsualScoreDto.getScoreList();
                        for (ReportExamStudentUsualScoreObjDto reportExamStudentUsualScoreObjDto : reportExamStudentUsualScoreObjDtoList) {
                            reportEvaluationDto = reportEvaluationDtoMap.get(reportExamStudentUsualScoreObjDto.getEvaluationId());
                            reportEvaluationDto.setTargetAvgScore(reportExamStudentUsualScoreObjDto.getMatrixAvgScore());
                            targetAvgSumScore = targetAvgSumScore + reportEvaluationDto.getTargetAvgScore();
                            targetSumScore = targetSumScore.add(reportEvaluationDto.getTargetScore());
                        }

                        //计算目标达成度
                        BigDecimal targetEvaluationValue = new BigDecimal(targetAvgSumScore).divide(targetSumScore, 2, BigDecimal.ROUND_HALF_UP).setScale(2, BigDecimal.ROUND_HALF_UP);
                        courseTargetWebDto.setEvaluationValue(targetEvaluationValue);
                        if (targetEvaluationSumValue.compareTo(new BigDecimal(0)) == 0 || targetEvaluationSumValue.compareTo(targetEvaluationValue) == 1) {
                            targetEvaluationSumValue = targetEvaluationValue;
                        }
                        courseTargetWordDto.setEvaluationValue(targetEvaluationValue);
                    }
                }
                reportCourseEvaluationResultDto = new ReportCourseEvaluationResultDto(targetEvaluationSumValue, new ArrayList<>(targetWebMap.values()), (Long) paramsMap.get("weightSettingSign"));
            }
            paramsMap.put("targetWebMap", targetWebMap);
        }
        return reportCourseEvaluationResultDto;
    }

    /**
     * 获取报告
     *
     * @param trBasicInfo
     * @param markPaper
     * @param userId
     * @param courseWeightResult
     * @param teachCourseId
     * @return
     */
    @Override
    @Transactional
    public TRBasicInfo getReportView(TRBasicInfo trBasicInfo, MarkPaper markPaper, Long userId, CourseWeightResult courseWeightResult, Long teachCourseId) {
        BasicSemester basicSemester = basicSemesterService.selectByExamId(markPaper.getExamId());
        Objects.requireNonNull(basicSemester, "未找到学期信息");

        String teachingObject = null, teacher = null;
        if (Objects.nonNull(markPaper.getPaperNumber())) {
            ExamStudentDto examStudentDto = examStudentService.queryExamStudent(markPaper.getExamId(), markPaper.getCourseCode(), markPaper.getPaperNumber());
            teachingObject = Objects.nonNull(examStudentDto) ? examStudentDto.getClazzNames() : null;
            teacher = Objects.nonNull(examStudentDto) ? examStudentDto.getTeacherNames() : null;
        }

        if (Objects.isNull(trBasicInfo)) {
            trBasicInfo = new TRBasicInfo(markPaper.getExamId(), markPaper.getCourseCode(), markPaper.getCourseName(), markPaper.getPaperNumber(), teachCourseId, basicSemester.getName(), teachingObject, teacher, null, userId);
        } else {
            trBasicInfo.setBasicInfo(markPaper.getExamId(), markPaper.getCourseCode(), markPaper.getCourseName(), markPaper.getPaperNumber(), basicSemester.getName(), teachingObject, teacher, null);
        }
        //课程基本情况
        ReportCourseBasicInfoDto reportCourseBasicInfoDto = new ReportCourseBasicInfoDto(trBasicInfo);
        trBasicInfo.getReportResult().setCourseBasicInfo(reportCourseBasicInfoDto);

        //课程目标考核分布-题目信息
        TCPaperStruct tcPaperStruct = tcPaperStructService.queryPaperStruct(markPaper.getExamId(), markPaper.getCourseCode(), markPaper.getPaperNumber(), teachCourseId);
        if (Objects.isNull(tcPaperStruct) || Objects.isNull(tcPaperStruct.getPaperStructDimension())) {
            throw ExceptionResultEnum.ERROR.exception("未找到试卷蓝图信息");
        }

        List<PaperStructDimensionResult> paperStructDimensionResultList = GsonUtil.fromJson(tcPaperStruct.getPaperStructDimension(), new TypeToken<List<PaperStructDimensionResult>>() {
        }.getType());

        //课程目标考核分布
        ReportCourseEvaluationSpreadDto reportCourseEvaluationSpreadDto = new ReportCourseEvaluationSpreadDto(paperStructDimensionResultList);
        if (Objects.nonNull(reportCourseEvaluationSpreadDto)) {
            reportCourseEvaluationSpreadDto.setScoreList(trBasicInfoService.getScoreList(trBasicInfo, markPaper));
            trBasicInfo.setCourseEvaluationSpread(JacksonUtil.parseJson(reportCourseEvaluationSpreadDto));
            trBasicInfo.getReportResult().setCourseEvaluationSpreadInfo(reportCourseEvaluationSpreadDto);
        }

        Map<String, Object> paramsMap = trBasicInfoService.getReportCalculateParams(trBasicInfo, paperStructDimensionResultList, courseWeightResult);

        //课程目标达成评价明细结果-考生集合
        List<ReportExamStudentDto> examStudentNewList = trExamStudentService.getExamStudentReportDetail(trBasicInfo, paramsMap);
        ReportCourseEvaluationResultDetailDto reportCourseEvaluationResultDetailDto = new ReportCourseEvaluationResultDetailDto(examStudentNewList);
        if (Objects.nonNull(reportCourseEvaluationResultDetailDto)) {
            trBasicInfo.getReportResult().setCourseEvaluationResultDetailInfo(reportCourseEvaluationResultDetailDto);
        }

        //课程考核成绩评价结果
        ReportCourseEvaluationResultDto reportCourseEvaluationResultDto = trBasicInfoService.reportCalculateCourseEvaluationResult(trBasicInfo, paramsMap);
        if (Objects.nonNull(reportCourseEvaluationResultDto)) {
            trBasicInfo.setCourseEvaluationResult(JacksonUtil.parseJson(reportCourseEvaluationResultDto));
            trBasicInfo.getReportResult().setCourseEvaluationResultInfo(reportCourseEvaluationResultDto);
        }

        //存储数据
        if (Objects.nonNull(paramsMap.get("targetWordMap"))) {
            Map<Long, CourseTargetWordDto> targetWordMap = (Map<Long, CourseTargetWordDto>) paramsMap.get("targetWordMap");
            List<CourseTargetWordDto> courseTargetWordDtoList = new ArrayList<>(targetWordMap.values());
            Collections.sort(courseTargetWordDtoList);

            Map<Long, CourseTargetWebDto> targetWebMap = (Map<Long, CourseTargetWebDto>) paramsMap.get("targetWebMap");
            List<CourseTargetWebDto> courseTargetWebDtoList = new ArrayList<>(targetWebMap.values());
            Collections.sort(courseTargetWebDtoList);

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("targetWordMap", courseTargetWordDtoList);
            jsonObject.put("targetWebMap", courseTargetWebDtoList);
            trBasicInfo.setCourseEvaluationResultDetail(jsonObject.toJSONString());
        }
        reportCourseBasicInfoDto.setParticipantCount(examStudentNewList.size() - 3);
        trBasicInfo.setParticipantCount(examStudentNewList.size() - 3);
        trBasicInfo.getReportResult().setCommonInfo(new ReportCommonDto(markPaper.getExamId(), markPaper.getCourseCode(), markPaper.getCourseName(), markPaper.getPaperNumber()));
        return trBasicInfo;
    }

    /**
     * 构建word动态表格1
     *
     * @param courseTargetWordDtoList
     * @return
     */
    @Override
    public TableRenderData buildWordTable1(List<CourseTargetWordDto> courseTargetWordDtoList) {
        //table1课程目标目标与毕业要求指标点的对应关系
        RowRenderData header1 = Rows.of("课程目标", "毕业要求指标点").rowStyle(this.getHeadRowStyle()).create();
        Tables.TableBuilder tableBuilder1 = Tables.ofPercentWidth(tbPercentWidth, new int[]{25, 75});
        tableBuilder1.addRow(header1);

        for (int i = 0; i < courseTargetWordDtoList.size(); i++) {
            CourseTargetWordDto courseTargetWordDto = courseTargetWordDtoList.get(i);
            RowRenderData row = Rows.of(courseTargetWordDto.getTargetName(), courseTargetWordDto.getGraduationRequirement()).rowStyle(this.getRowStyle()).create();
            tableBuilder1.addRow(row);
        }
        return tableBuilder1.left().create();
    }

    /**
     * 构建word动态表格2
     *
     * @param courseTargetWordDtoList
     * @return
     */
    @Override
    public TableRenderData buildWordTable2(List<CourseTargetWordDto> courseTargetWordDtoList) {
        RowRenderData header2_1 = Rows.of("课程目标", "支撑毕业要求", "考核/评价环节及目标分值", "", "目标分值统计").rowStyle(this.getHeadRowStyle()).create();
        RowRenderData header2_2 = Rows.of("课程目标", "支撑毕业要求", "平时成绩", "期末考试", "目标分值统计").rowStyle(this.getHeadRowStyle()).center().create();
        RowRenderData[] rowRenderData2 = new RowRenderData[courseTargetWordDtoList.size() + 3];
        BigDecimal usualScoreTargetSum = new BigDecimal(0), finalScoreTargetSum = new BigDecimal(0);
        for (int i = 0; i < courseTargetWordDtoList.size(); i++) {
            CourseTargetWordDto courseTargetWordDto = courseTargetWordDtoList.get(i);
            FinalScoreWordDto finalScoreWordDto = courseTargetWordDto.getFinalScoreDto();
            finalScoreTargetSum = finalScoreTargetSum.add(finalScoreWordDto.getFinalScoreTargetSumScore());

            UsualScoreWordDto usualScoreWordDto = courseTargetWordDto.getUsualScoreDto();
            usualScoreTargetSum = usualScoreTargetSum.add(usualScoreWordDto.getUsualScoreTargetSumScore());
            rowRenderData2[i + 2] = Rows.of(courseTargetWordDto.getTargetName(), courseTargetWordDto.getGraduationRequirement(), SystemConstant.df.format(usualScoreWordDto.getUsualScoreTargetSumScore()), SystemConstant.df.format(finalScoreWordDto.getFinalScoreTargetSumScore()), SystemConstant.df.format(usualScoreWordDto.getUsualScoreTargetSumScore().add(finalScoreWordDto.getFinalScoreTargetSumScore()))).rowStyle(this.getRowStyle()).create();
        }
        rowRenderData2[0] = header2_1;
        rowRenderData2[1] = header2_2;

        RowRenderData header2_foot = Rows.of("合计", "", SystemConstant.df.format(usualScoreTargetSum), SystemConstant.df.format(finalScoreTargetSum), SystemConstant.df.format(usualScoreTargetSum.add(finalScoreTargetSum))).rowStyle(this.getRowStyle()).create();
        rowRenderData2[rowRenderData2.length - 1] = header2_foot;

        // 表格合并,根据坐标
        MergeCellRule mergeCellRule2 = MergeCellRule.builder().map(MergeCellRule.Grid.of(0, 0), MergeCellRule.Grid.of(1, 0)).
                map(MergeCellRule.Grid.of(0, 1), MergeCellRule.Grid.of(1, 1)).
                map(MergeCellRule.Grid.of(0, 2), MergeCellRule.Grid.of(0, 3)).
                map(MergeCellRule.Grid.of(0, 4), MergeCellRule.Grid.of(1, 4)).
                map(MergeCellRule.Grid.of(rowRenderData2.length - 1, 0), MergeCellRule.Grid.of(rowRenderData2.length - 1, 1)).
                build();

        Tables.TableBuilder tableBuilder2 = Tables.ofPercentWidth(tbPercentWidth, new int[]{25, 26, 16, 16, 17});
        for (int i = 0; i < rowRenderData2.length; i++) {
            tableBuilder2.addRow(rowRenderData2[i]);
        }
        return tableBuilder2.mergeRule(mergeCellRule2).left().create();
    }

    /**
     * 构建word动态表格3
     *
     * @param courseTargetWordDtoList
     * @return
     */
    @Override
    public TableRenderData buildWordTable3(List<CourseTargetWordDto> courseTargetWordDtoList) {
        RowRenderData header3_1 = Rows.of("序号", "项目", "考核内容及要求", "目标分值", "对应的课程目标").rowStyle(this.getHeadRowStyle()).create();
        String tableFootTitle3 = "合计${usualScoreSum}分，占课程总评成绩的${usualScoreSumWeight}%";
        List<CourseTargetTableBean3> courseTargetTableBean3List = new ArrayList<>();
        BigDecimal usualScoreSum3 = new BigDecimal(0), usualScoreTargetSumWeight3 = new BigDecimal(0);
        Integer seq3 = 1;
        for (CourseTargetWordDto courseTargetWordDto : courseTargetWordDtoList) {
            UsualScoreWordDto usualScoreWordDto = courseTargetWordDto.getUsualScoreDto();
            List<ReportEvaluationDto> reportEvaluationDtoList = usualScoreWordDto.getUsualScoreDetailList();
            for (int i = 0; i < reportEvaluationDtoList.size(); i++) {
                ReportEvaluationDto reportEvaluationDto = reportEvaluationDtoList.get(i);
                CourseTargetTableBean3 courseTargetTableBean3 = new CourseTargetTableBean3(seq3++, reportEvaluationDto.getEvaluation(), reportEvaluationDto.getEvaluationDesc(), new BigDecimal(SystemConstant.df.format(reportEvaluationDto.getOriginalTargetScore())), courseTargetWordDto.getTargetName());
                courseTargetTableBean3List.add(courseTargetTableBean3);
                usualScoreSum3 = usualScoreSum3.add(new BigDecimal(reportEvaluationDto.getOriginalTargetScore()));
            }
            usualScoreTargetSumWeight3 = usualScoreTargetSumWeight3.add(usualScoreWordDto.getUsualScoreTargetSumWeight());
        }
        usualScoreTargetSumWeight3 = usualScoreTargetSumWeight3.divide(new BigDecimal(courseTargetWordDtoList.size()), 2, BigDecimal.ROUND_HALF_UP).setScale(2, BigDecimal.ROUND_HALF_UP);
        tableFootTitle3 = tableFootTitle3.replace("${usualScoreSum}", SystemConstant.df.format(usualScoreSum3));
        tableFootTitle3 = tableFootTitle3.replace("${usualScoreSumWeight}", SystemConstant.df.format(usualScoreTargetSumWeight3));

        RowRenderData[] rowRenderData3 = new RowRenderData[courseTargetTableBean3List.size() + 2];
        for (int i = 0; i < courseTargetTableBean3List.size(); i++) {
            CourseTargetTableBean3 courseTargetTableBean3 = courseTargetTableBean3List.get(i);
            rowRenderData3[i + 1] = Rows.of(courseTargetTableBean3.getNum().toString(), courseTargetTableBean3.getProject(), courseTargetTableBean3.getContent(), SystemConstant.df.format(courseTargetTableBean3.getTarget()), courseTargetTableBean3.getCourseTarget()).rowStyle(this.getRowStyle()).create();
        }
        rowRenderData3[0] = header3_1;
        RowRenderData header3_foot = Rows.of(tableFootTitle3, "", "", "", "").center().create();
        rowRenderData3[rowRenderData3.length - 1] = header3_foot;

        //表格合并,根据坐标
        MergeCellRule mergeCellRule3 = MergeCellRule.builder().map(MergeCellRule.Grid.of(rowRenderData3.length - 1, 0), MergeCellRule.Grid.of(rowRenderData3.length - 1, 4)).
                build();

        Tables.TableBuilder tableBuilder3 = Tables.ofPercentWidth(tbPercentWidth, new int[]{8, 20, 37, 14, 21});
        for (int i = 0; i < rowRenderData3.length; i++) {
            tableBuilder3.addRow(rowRenderData3[i]);
        }
        return tableBuilder3.mergeRule(mergeCellRule3).left().create();
    }

    /**
     * 构建word动态表格4
     *
     * @param courseTargetWordDtoList
     * @return
     */
    @Override
    public TableRenderData buildWordTable4(List<CourseTargetWordDto> courseTargetWordDtoList) {
        RowRenderData header4_1 = Rows.of("序号", "考核项目", "考核内容所涵盖的知识单元", "目标分值", "对应的课程目标").rowStyle(this.getHeadRowStyle()).create();
        List<CourseTargetTableBean4> courseTargetTableBean4List = new ArrayList<>();
        BigDecimal finalScoreSum4 = new BigDecimal(0), finalScoreTargetSumWeight4 = new BigDecimal(0);
        for (int i = 0; i < courseTargetWordDtoList.size(); i++) {
            CourseTargetWordDto courseTargetWordDto = courseTargetWordDtoList.get(i);
            FinalScoreWordDto finalScoreWordDto = courseTargetWordDto.getFinalScoreDto();
            finalScoreSum4 = finalScoreSum4.add(courseTargetWordDto.getTargetSumScore());
            finalScoreTargetSumWeight4 = finalScoreTargetSumWeight4.add(finalScoreWordDto.getFinalScoreSumWeight());
            CourseTargetTableBean4 courseTargetTableBean4 = new CourseTargetTableBean4((i + 1), courseTargetWordDto.getGraduationRequirement(), courseTargetWordDto.getDimensionPoint(), Double.parseDouble(SystemConstant.df.format(courseTargetWordDto.getTargetSumScore())), courseTargetWordDto.getTargetName());
            courseTargetTableBean4List.add(courseTargetTableBean4);
        }
        finalScoreTargetSumWeight4 = finalScoreTargetSumWeight4.divide(new BigDecimal(courseTargetWordDtoList.size()), 2, BigDecimal.ROUND_HALF_UP).setScale(2, BigDecimal.ROUND_HALF_UP);
        String tableFootTitle4 = "合计${dimensionScoreSum}分，占课程总评成绩的${dimensionSumWeight}%";
        tableFootTitle4 = tableFootTitle4.replace("${dimensionScoreSum}", SystemConstant.df.format(finalScoreSum4));
        tableFootTitle4 = tableFootTitle4.replace("${dimensionSumWeight}", SystemConstant.df.format(finalScoreTargetSumWeight4));

        RowRenderData[] rowRenderData4 = new RowRenderData[courseTargetTableBean4List.size() + 2];
        for (int i = 0; i < courseTargetTableBean4List.size(); i++) {
            CourseTargetTableBean4 courseTargetTableBean4 = courseTargetTableBean4List.get(i);
            rowRenderData4[i + 1] = Rows.of(courseTargetTableBean4.getNum().toString(), courseTargetTableBean4.getProject(), courseTargetTableBean4.getContent(), SystemConstant.df.format(courseTargetTableBean4.getTargetScore()), courseTargetTableBean4.getCourseTarget()).rowStyle(this.getRowStyle()).create();
        }
        rowRenderData4[0] = header4_1;
        RowRenderData header4_foot = Rows.of(tableFootTitle4, "", "", "", "").center().create();
        rowRenderData4[rowRenderData4.length - 1] = header4_foot;

        //表格合并,根据坐标
        MergeCellRule mergeCellRule4 = MergeCellRule.builder().map(MergeCellRule.Grid.of(rowRenderData4.length - 1, 0), MergeCellRule.Grid.of(rowRenderData4.length - 1, 4)).
                build();

        Tables.TableBuilder tableBuilder4 = Tables.ofPercentWidth(tbPercentWidth, new int[]{8, 20, 37, 14, 21});
        for (int i = 0; i < rowRenderData4.length; i++) {
            tableBuilder4.addRow(rowRenderData4[i]);
        }
        return tableBuilder4.mergeRule(mergeCellRule4).left().create();
    }

    /**
     * 构建word动态表格5
     *
     * @param trBasicInfo
     * @param courseReportBean
     * @return
     */
    @Override
    public TableRenderData buildWordTable5(TRBasicInfo trBasicInfo, CourseReportBean courseReportBean) {
        TableRenderData tableRenderDataExamStudent = null;
        List<TRExamStudent> trExamStudentList = trExamStudentService.list(new QueryWrapper<TRExamStudent>().lambda().eq(TRExamStudent::getrBasicInfoId, trBasicInfo.getId()));
        if (!CollectionUtils.isEmpty(trExamStudentList)) {
            List<CellRenderData> examStudent_cells_1 = new ArrayList<>(), examStudent_cells_2 = new ArrayList<>();
            examStudent_cells_1.add(Cells.of("序号").center().create());
            examStudent_cells_1.add(Cells.of("学号").center().create());
            examStudent_cells_1.add(Cells.of("姓名").center().create());
            examStudent_cells_1.add(Cells.of("行政班级").center().create());
            examStudent_cells_2.addAll(examStudent_cells_1);

            Map<Long, Integer> targetUsualScoreSizeMap = new LinkedHashMap<>();
            TRExamStudent trExamStudentTemp = trExamStudentList.get(0);

            RowRenderData[] rowRenderDataExamStudent = new RowRenderData[trExamStudentList.size() + 2];
            RowRenderData examStudent_header_1 = new RowRenderData();
            examStudent_header_1.setCells(examStudent_cells_1);
            examStudent_header_1.setRowStyle(this.getHeadRowStyle());

            RowRenderData examStudent_header_2 = new RowRenderData();
            examStudent_header_2.setCells(examStudent_cells_2);
            examStudent_header_2.setRowStyle(this.getHeadRowStyle());

            rowRenderDataExamStudent[0] = examStudent_header_1;
            rowRenderDataExamStudent[1] = examStudent_header_2;

            //首行
            if (Objects.nonNull(trExamStudentTemp.getResultDetail())) {
                List<ReportExamStudentTargetDto> reportExamStudentTargetDtoList = JSONArray.parseArray(trExamStudentTemp.getResultDetail(), ReportExamStudentTargetDto.class);
                for (ReportExamStudentTargetDto reportExamStudentTargetDto : reportExamStudentTargetDtoList) {
                    examStudent_cells_1.add(Cells.of(reportExamStudentTargetDto.getTargetName()).center().create());
                    ReportExamStudentUsualScoreDto reportExamStudentUsualScoreDto = reportExamStudentTargetDto.getUsualScore();
                    //平常作业
                    if (Objects.nonNull(reportExamStudentUsualScoreDto) && !CollectionUtils.isEmpty(reportExamStudentUsualScoreDto.getScoreList())) {
                        List<ReportExamStudentUsualScoreObjDto> reportExamStudentUsualScoreObjDtoList = reportExamStudentUsualScoreDto.getScoreList();
                        targetUsualScoreSizeMap.put(reportExamStudentTargetDto.getTargetId(), reportExamStudentUsualScoreObjDtoList.size());
                        for (ReportExamStudentUsualScoreObjDto reportExamStudentUsualScoreObjDto : reportExamStudentUsualScoreObjDtoList) {
                            examStudent_cells_1.add(Cells.of("").center().create());
                            examStudent_cells_2.add(Cells.of(reportExamStudentUsualScoreObjDto.getEvaluation()).center().create());
                        }
                    }
                    //期末考试
                    ReportExamStudentFinalScoreDto reportExamStudentFinalScoreDto = reportExamStudentTargetDto.getFinalScore();
                    if (Objects.nonNull(reportExamStudentFinalScoreDto) && Objects.equals(reportExamStudentFinalScoreDto.getEvaluation(), SystemConstant.FINAL_SCORE_STR)) {
                        examStudent_cells_2.add(Cells.of(SystemConstant.FINAL_SCORE_STR).center().create());
                    }
                }
                examStudent_cells_1.add(Cells.of("综合成绩").center().create());
                examStudent_cells_2.add(Cells.of("综合成绩").center().create());
            }

            for (int i = 0; i < trExamStudentList.size(); i++) {
                TRExamStudent trExamStudent = trExamStudentList.get(i);
                RowRenderData examStudent_row = new RowRenderData();
                List<CellRenderData> examStudent_cells = new ArrayList<>();
                switch (trExamStudent.getName()) {
                    case "目标分":
                        examStudent_cells.add(Cells.of("课程目标考核要素的目标分").create());
                        examStudent_cells.add(Cells.of("课程目标考核要素的目标分").create());
                        examStudent_cells.add(Cells.of("课程目标考核要素的目标分").create());
                        break;
                    case "平均分":
                        examStudent_cells.add(Cells.of("课程目标考核要素的平均分").create());
                        examStudent_cells.add(Cells.of("课程目标考核要素的平均分").create());
                        examStudent_cells.add(Cells.of("课程目标考核要素的平均分").create());
                        break;
                    case "各课程目标平均分":
                        examStudent_cells.add(Cells.of(trExamStudent.getName()).create());
                        examStudent_cells.add(Cells.of(trExamStudent.getStudentCode()).create());
                        examStudent_cells.add(Cells.of(trExamStudent.getName()).create());
                        break;
                    default:
                        examStudent_cells.add(Cells.of(String.valueOf(i + 1)).create());
                        examStudent_cells.add(Cells.of(trExamStudent.getStudentCode()).create());
                        examStudent_cells.add(Cells.of(trExamStudent.getName()).create());
                        break;
                }
                examStudent_cells.add(Cells.of(trExamStudent.getAdministrativeClass()).create());

                BigDecimal targetSumScore = new BigDecimal(0), targetAvgScore = new BigDecimal(0);
                if (Objects.nonNull(trExamStudent.getResultDetail())) {
                    List<ReportExamStudentTargetDto> reportExamStudentTargetDtoList = JSONArray.parseArray(trExamStudent.getResultDetail(), ReportExamStudentTargetDto.class);
                    for (ReportExamStudentTargetDto reportExamStudentTargetDto : reportExamStudentTargetDtoList) {
                        if (Objects.nonNull(reportExamStudentTargetDto)) {
                            ReportExamStudentUsualScoreDto reportExamStudentUsualScoreDto = reportExamStudentTargetDto.getUsualScore();
                            //平常作业
                            if (Objects.nonNull(reportExamStudentUsualScoreDto) && !CollectionUtils.isEmpty(reportExamStudentUsualScoreDto.getScoreList())) {
                                courseReportBean.getCourseBasicBean().setUsualScoreWeight(reportExamStudentUsualScoreDto.getTargetWeight());
                                List<ReportExamStudentUsualScoreObjDto> reportExamStudentUsualScoreObjDtoList = reportExamStudentUsualScoreDto.getScoreList();
                                for (ReportExamStudentUsualScoreObjDto reportExamStudentUsualScoreObjDto : reportExamStudentUsualScoreObjDtoList) {
                                    switch (trExamStudent.getName()) {
                                        case "目标分":
                                            examStudent_cells.add(Cells.of(SystemConstant.df.format(reportExamStudentUsualScoreObjDto.getTargetScore())).create());
                                            targetSumScore = targetSumScore.add(reportExamStudentUsualScoreObjDto.getTargetScore());
                                            break;
                                        case "平均分":
                                            examStudent_cells.add(Cells.of(SystemConstant.df.format(reportExamStudentUsualScoreObjDto.getMatrixAvgScore())).create());
                                            targetAvgScore = targetAvgScore.add(new BigDecimal(reportExamStudentUsualScoreObjDto.getMatrixAvgScore()));
                                            break;
                                        case "各课程目标平均分":
                                            examStudent_cells.add(Cells.of(SystemConstant.df.format(reportExamStudentTargetDto.getTargetMatrixAvgScore())).create());
                                            break;
                                        default:
                                            examStudent_cells.add(Cells.of(SystemConstant.df.format(reportExamStudentUsualScoreObjDto.getScore())).create());
                                            break;
                                    }
                                }
                            }
                            //期末考试
                            ReportExamStudentFinalScoreDto reportExamStudentFinalScoreDto = reportExamStudentTargetDto.getFinalScore();
                            if (Objects.nonNull(reportExamStudentFinalScoreDto) && Objects.equals(reportExamStudentFinalScoreDto.getEvaluation(), SystemConstant.FINAL_SCORE_STR)) {
                                courseReportBean.getCourseBasicBean().setFinalScoreWeight(reportExamStudentFinalScoreDto.getTargetWeight());
                                switch (trExamStudent.getName()) {
                                    case "目标分":
                                        examStudent_cells.add(Cells.of(SystemConstant.df.format(reportExamStudentFinalScoreDto.getTargetScore())).create());
                                        targetSumScore = targetSumScore.add(reportExamStudentFinalScoreDto.getTargetScore());
                                        break;
                                    case "平均分":
                                        examStudent_cells.add(Cells.of(SystemConstant.df.format(reportExamStudentFinalScoreDto.getMatrixAvgScore())).create());
                                        targetAvgScore = targetAvgScore.add(new BigDecimal(reportExamStudentFinalScoreDto.getMatrixAvgScore()));
                                        break;
                                    case "各课程目标平均分":
                                        examStudent_cells.add(Cells.of(SystemConstant.df.format(reportExamStudentTargetDto.getTargetMatrixAvgScore())).create());
                                        break;
                                    default:
                                        examStudent_cells.add(Cells.of(SystemConstant.df.format(reportExamStudentFinalScoreDto.getTargetScoreSum())).create());
                                        break;
                                }
                            }
                        }
                    }
                }
                switch (trExamStudent.getName()) {
                    case "目标分":
                        examStudent_cells.add(Cells.of(SystemConstant.df.format(targetSumScore.setScale(2, BigDecimal.ROUND_HALF_UP))).create());
                        break;
                    case "平均分":
                        examStudent_cells.add(Cells.of(SystemConstant.df.format(targetAvgScore.setScale(1, BigDecimal.ROUND_DOWN))).create());
                        break;
                    case "各课程目标平均分":
                        examStudent_cells.add(Cells.of("").create());
                        break;
                    default:
                        examStudent_cells.add(Cells.of(SystemConstant.df.format(trExamStudent.getScore())).create());
                        break;
                }
                examStudent_row.setCells(examStudent_cells);
                examStudent_row.setRowStyle(this.getRowStyle());
                rowRenderDataExamStudent[i + 2] = examStudent_row;
            }

            String title = Objects.nonNull(trBasicInfo.getTeachingObject()) ? trBasicInfo.getTeachingObject() : "";
            String sumTitle = "学生共${examStudentSum}名";
            sumTitle = sumTitle.replace("${examStudentSum}", trExamStudentList.size() - 3 + "");

            courseReportBean.setExamStudentTitle1(title + sumTitle);
            courseReportBean.setExamStudentTitle2(title + "《" + courseReportBean.getCourseBasicBean().getCourseName() + "》");

            //表格合并,根据坐标
            MergeCellRule mergeCellRuleExamStudent = MergeCellRule.builder().build();
            mergeCellRuleExamStudent.getMapping().add(new MergeCellRule.GridRule(MergeCellRule.Grid.of(0, 0), MergeCellRule.Grid.of(1, 0)));
            mergeCellRuleExamStudent.getMapping().add(new MergeCellRule.GridRule(MergeCellRule.Grid.of(0, 1), MergeCellRule.Grid.of(1, 1)));
            mergeCellRuleExamStudent.getMapping().add(new MergeCellRule.GridRule(MergeCellRule.Grid.of(0, 2), MergeCellRule.Grid.of(1, 2)));
            mergeCellRuleExamStudent.getMapping().add(new MergeCellRule.GridRule(MergeCellRule.Grid.of(0, 3), MergeCellRule.Grid.of(1, 3)));
            mergeCellRuleExamStudent.getMapping().add(new MergeCellRule.GridRule(MergeCellRule.Grid.of(rowRenderDataExamStudent.length - 3, 0), MergeCellRule.Grid.of(rowRenderDataExamStudent.length - 3, 3)));
            mergeCellRuleExamStudent.getMapping().add(new MergeCellRule.GridRule(MergeCellRule.Grid.of(rowRenderDataExamStudent.length - 2, 0), MergeCellRule.Grid.of(rowRenderDataExamStudent.length - 2, 3)));
            mergeCellRuleExamStudent.getMapping().add(new MergeCellRule.GridRule(MergeCellRule.Grid.of(rowRenderDataExamStudent.length - 1, 0), MergeCellRule.Grid.of(rowRenderDataExamStudent.length - 1, 3)));

            //动态扩展列
            AtomicInteger initNum = new AtomicInteger(4);
            targetUsualScoreSizeMap.forEach((k, v) -> {
                int increaseNum = 1;
                while (increaseNum <= v) {
                    mergeCellRuleExamStudent.getMapping().add(new MergeCellRule.GridRule(MergeCellRule.Grid.of(0, initNum.get()), MergeCellRule.Grid.of(0, initNum.get() + increaseNum)));
                    mergeCellRuleExamStudent.getMapping().add(new MergeCellRule.GridRule(MergeCellRule.Grid.of(rowRenderDataExamStudent.length - 1, initNum.get()), MergeCellRule.Grid.of(rowRenderDataExamStudent.length - 1, initNum.get() + increaseNum)));
                    increaseNum++;
                }
                initNum.set(initNum.get() + increaseNum);
            });
            mergeCellRuleExamStudent.getMapping().add(new MergeCellRule.GridRule(MergeCellRule.Grid.of(0, initNum.get()), MergeCellRule.Grid.of(1, initNum.get())));

//            Tables.TableBuilder tableBuilderExamStudent = Tables.ofPercentWidth(tbPercentWidth, new int[]{6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 16});
            Tables.TableBuilder tableBuilderExamStudent = Tables.ofPercentWidth(tbPercentWidth);
            for (int i = 0; i < rowRenderDataExamStudent.length; i++) {
                tableBuilderExamStudent.addRow(rowRenderDataExamStudent[i]);
            }
            tableRenderDataExamStudent = tableBuilderExamStudent.mergeRule(mergeCellRuleExamStudent).left().create();
        }
        return tableRenderDataExamStudent;
    }

    /**
     * 根据考试id/课程编码/试卷编码删除数据
     *
     * @param examId
     * @param courseCode
     * @param paperNumber
     * @param teachCourseId
     * @return
     */
    @Override
    @Transactional
    public Boolean remove(Long examId, String courseCode, String paperNumber, Long teachCourseId) {
        QueryWrapper<TRBasicInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TRBasicInfo::getExamId, examId).eq(TRBasicInfo::getCourseCode, courseCode);
        if (Objects.nonNull(paperNumber)) {
            queryWrapper.lambda().and(w -> w.eq(TRBasicInfo::getPaperNumber, paperNumber).or().isNull(TRBasicInfo::getPaperNumber));
        }
        queryWrapper.lambda().eq(TRBasicInfo::getTeachCourseId, teachCourseId);
        return trBasicInfoService.remove(queryWrapper);
    }

    /**
     * 查找课程评价值
     *
     * @param teachCourseId
     * @return
     */
    @Override
    public CourseWeightResult findCourseWeightResultRmi(Long teachCourseId) {
        CourseWeightResult courseWeightResult = courseWeightService.findCourseWeight(teachCourseId);
        Objects.requireNonNull(courseWeightResult, "未设置课程目标数据");
        Objects.requireNonNull(courseWeightResult.getCustomRate(), "未设置平时成绩权重");
        Objects.requireNonNull(courseWeightResult.getDefaultRate(), "未设置期末考试权重");
        Objects.requireNonNull(courseWeightResult.getWeightSettingSign(), "课程权重变化id为空");
        Objects.requireNonNull(courseWeightResult.getDimensionSign(), "知识点变化id为空");
        List<CourseWeightDto> courseWeightDtoList = courseWeightResult.getSubmitForm();
        if (CollectionUtils.isEmpty(courseWeightDtoList)) {
            throw ExceptionResultEnum.ERROR.exception("未设置课程目标评价方式");
        }
        return courseWeightResult;
    }

    /**
     * 查找课程评价值
     *
     * @param teachCourseId
     * @return
     */
    @Override
    public List<CourseWeightDto> findCourseWeightDtoRmi(Long teachCourseId) {
        CourseWeightResult courseWeightResult = courseWeightService.findCourseWeight(teachCourseId);
        if (Objects.nonNull(courseWeightResult) && !CollectionUtils.isEmpty(courseWeightResult.getSubmitForm())) {
            return courseWeightResult.getSubmitForm();
        }
        return null;
    }

    /**
     * 清除报告数据
     *
     * @param examId
     * @param courseCode
     * @param paperNumber
     * @param teachCourseId
     * @param clearDimension
     */
    @Override
    @Transactional
    public void clearReportData(Long examId, String courseCode, String paperNumber, Long teachCourseId, boolean clearDimension) {
        trExamStudentService.remove(examId, courseCode, paperNumber, teachCourseId);
        trBasicInfoService.remove(examId, courseCode, paperNumber, teachCourseId);
        if (clearDimension) {
            TCPaperStruct tcPaperStruct = tcPaperStructService.queryPaperStruct(examId, courseCode, paperNumber, teachCourseId);
            if (Objects.nonNull(tcPaperStruct)) {
                tcPaperStruct.setPaperStructDimension(null);
                SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
                tcPaperStruct.updateInfo(sysUser.getId());
                tcPaperStructService.updateById(tcPaperStruct);
            }
        }
    }

    /**
     * 获取行样式
     *
     * @return
     */
    protected RowStyle getRowStyle() {
        RowStyle rowStyle = new RowStyle();
        ParagraphStyle paragraphStyle = new ParagraphStyle();
        paragraphStyle.setAlign(ParagraphAlignment.LEFT);
        CellStyle cellStyle = new CellStyle();
        cellStyle.setDefaultParagraphStyle(paragraphStyle);
        cellStyle.setVertAlign(XWPFTableCell.XWPFVertAlign.CENTER);
        rowStyle.setDefaultCellStyle(cellStyle);
        return rowStyle;
    }

    /**
     * 获取行样式
     *
     * @return
     */
    protected RowStyle getHeadRowStyle() {
        RowStyle rowStyle = new RowStyle();
        rowStyle.setRepeated(true);
        ParagraphStyle paragraphStyle = new ParagraphStyle();
        paragraphStyle.setAlign(ParagraphAlignment.CENTER);
        CellStyle cellStyle = new CellStyle();
        cellStyle.setDefaultParagraphStyle(paragraphStyle);
        cellStyle.setBackgroundColor(tbBgColor);
        rowStyle.setDefaultCellStyle(cellStyle);
        return rowStyle;
    }

    /**
     * 计算分数范围
     *
     * @param finalScoreDto
     * @param examId
     * @param paperNumber
     * @param teachCourseId
     * @param markPaper
     */
    protected void fillScoreRange(FinalScoreDto finalScoreDto, Long examId, String paperNumber, Long teachCourseId, MarkPaper markPaper) {
        //分数区间
        Double passScore = markPaper.getPassScore();//及格分
        Objects.requireNonNull(passScore, "及格分为空");

        Double totalScore = markPaper.getTotalScore();
        Objects.requireNonNull(totalScore, "试卷满分为空");

        List<ScoreRangeVo> scoreRange = new ArrayList<>();
        finalScoreDto.setScoreRange(scoreRange);

        //开始、结束分数区间
        Double startInterval = 0.5d, endInterval = 9.5d, increaseStartScore = passScore - startInterval,
                increaseEndScore = increaseStartScore + startInterval + endInterval;
        scoreRange.add(getScoreRangeVo(finalScoreDto.getStudentCount(), examId, markPaper.getCourseCode(), paperNumber, teachCourseId, 1.0d, increaseStartScore));
        increaseStartScore = increaseStartScore + startInterval;
        increaseEndScore = increaseStartScore + endInterval;
        if (totalScore.doubleValue() - increaseEndScore.doubleValue() == startInterval || increaseEndScore.doubleValue() >= totalScore.doubleValue()) {
            increaseEndScore = totalScore;
            scoreRange.add(getScoreRangeVo(finalScoreDto.getStudentCount(), examId, markPaper.getCourseCode(), paperNumber, teachCourseId, increaseStartScore, increaseEndScore));
        } else {
            while (increaseEndScore.doubleValue() < totalScore.doubleValue()) {
                scoreRange.add(getScoreRangeVo(finalScoreDto.getStudentCount(), examId, markPaper.getCourseCode(), paperNumber, teachCourseId, increaseStartScore, increaseEndScore));
                increaseStartScore = increaseEndScore + startInterval;
                increaseEndScore = increaseStartScore + endInterval;
                if (totalScore.doubleValue() - increaseEndScore.doubleValue() == startInterval || increaseEndScore.doubleValue() >= totalScore.doubleValue()) {
                    increaseEndScore = totalScore;
                    scoreRange.add(getScoreRangeVo(finalScoreDto.getStudentCount(), examId, markPaper.getCourseCode(), paperNumber, teachCourseId, increaseStartScore, increaseEndScore));
                }
            }
        }
    }

    /**
     * 计算考生期末成绩知识点纬度
     *
     * @param finalScoreExamStudentDimensionMap
     * @param finalScoreResult
     * @param courseTargetDto
     * @param dimensionDto
     * @param score
     */
    protected void calculateFinalScoreByDimensionExamStudent(Map<String, Map<Long, Map<Long, DimensionDto>>> finalScoreExamStudentDimensionMap,
                                                             FinalScoreResult finalScoreResult,
                                                             CourseTargetWebDto courseTargetDto,
                                                             DimensionDto dimensionDto,
                                                             Double score) {
        if (!finalScoreExamStudentDimensionMap.containsKey(finalScoreResult.getStudentCode())) {
            Map<Long, Map<Long, DimensionDto>> map = new LinkedHashMap<>();
            Map<Long, DimensionDto> dimensionMap = new LinkedHashMap<>();
            dimensionMap.put(dimensionDto.getDimensionId(), new DimensionDto(courseTargetDto.getTargetId(), dimensionDto, score));
            map.put(courseTargetDto.getTargetId(), dimensionMap);
            finalScoreExamStudentDimensionMap.put(finalScoreResult.getStudentCode(), map);
        } else {
            Map<Long, Map<Long, DimensionDto>> map = finalScoreExamStudentDimensionMap.get(finalScoreResult.getStudentCode());
            if (!map.containsKey(courseTargetDto.getTargetId())) {
                Map<Long, DimensionDto> dimensionMap = new LinkedHashMap<>();
                dimensionMap.put(dimensionDto.getDimensionId(), new DimensionDto(courseTargetDto.getTargetId(), dimensionDto, score));
                map.put(courseTargetDto.getTargetId(), dimensionMap);
            } else {
                Map<Long, DimensionDto> dimensionMap = map.get(courseTargetDto.getTargetId());
                if (!dimensionMap.containsKey(dimensionDto.getDimensionId())) {
                    dimensionMap.put(dimensionDto.getDimensionId(), new DimensionDto(courseTargetDto.getTargetId(), dimensionDto, score));
                } else {
                    DimensionDto dimensionDtoTemp = dimensionMap.get(dimensionDto.getDimensionId());
                    dimensionDtoTemp.setDimensionScore(dimensionDtoTemp.getDimensionScore().doubleValue() + score.doubleValue());
                }
                map.put(courseTargetDto.getTargetId(), dimensionMap);
            }
            finalScoreExamStudentDimensionMap.put(finalScoreResult.getStudentCode(), map);
        }
    }

    /**
     * 计算考生期末成绩课程目标卷面分纬度
     *
     * @param finalScoreExamStudentTargetMap
     * @param finalScoreResult
     * @param courseTargetDto
     * @param score
     */
    protected void calculateFinalScoreByTargetExamStudent(Map<String, Map<Long, Double>> finalScoreExamStudentTargetMap,
                                                          FinalScoreResult finalScoreResult,
                                                          CourseTargetWebDto courseTargetDto,
                                                          Double score) {
        if (!finalScoreExamStudentTargetMap.containsKey(finalScoreResult.getStudentCode())) {
            Map<Long, Double> map = new LinkedHashMap<>();
            map.put(courseTargetDto.getTargetId(), score);
            finalScoreExamStudentTargetMap.put(finalScoreResult.getStudentCode(), map);
        } else {
            Map<Long, Double> map = finalScoreExamStudentTargetMap.get(finalScoreResult.getStudentCode());
            if (!map.containsKey(courseTargetDto.getTargetId())) {
                map.put(courseTargetDto.getTargetId(), score);
            } else {
                Double scoreTemp = map.get(courseTargetDto.getTargetId());
                map.put(courseTargetDto.getTargetId(), scoreTemp.doubleValue() + score.doubleValue());
            }
            finalScoreExamStudentTargetMap.put(finalScoreResult.getStudentCode(), map);
        }
    }

    /**
     * 计算考生平时成绩
     *
     * @param finalScoreResult
     * @param usualScoreMap
     * @param targetWordMap
     * @return
     */
    protected ReportExamStudentUsualScoreDto calculateUsualScoreByExamStudent(FinalScoreResult finalScoreResult,
                                                                              Map<String, ReportEvaluationDto> usualScoreMap,
                                                                              Map<Long, CourseTargetWordDto> targetWordMap) {
        List<TCUsualScoreDto> tcUsualScoreDtoList = GsonUtil.fromJson(finalScoreResult.getUsualScore(), new TypeToken<List<TCUsualScoreDto>>() {
        }.getType());
        Map<Long, List<ReportExamStudentUsualScoreObjDto>> scoreListMap = new LinkedHashMap<>();
        ReportExamStudentUsualScoreDto reportExamStudentUsualScoreDto = new ReportExamStudentUsualScoreDto(scoreListMap);
        for (TCUsualScoreDto t : tcUsualScoreDtoList) {
            if (usualScoreMap.containsKey(t.getName())) {
                ReportEvaluationDto reportEvaluationDto = usualScoreMap.get(t.getName());
                List<ReportExamStudentUsualScoreObjDto> reportExamStudentUsualScoreObjDtoList = !scoreListMap.containsKey(reportEvaluationDto.getTargetId()) ? new ArrayList<>() : scoreListMap.get(reportEvaluationDto.getTargetId());
                //计算平时作业转换
                Double score = Objects.nonNull(t.getScore()) ? Double.parseDouble(t.getScore()) : 0d;
                CourseTargetWordDto courseTargetWordDto = targetWordMap.get(reportEvaluationDto.getTargetId());
                UsualScoreWordDto usualScoreWordDto = courseTargetWordDto.getUsualScoreDto();
                Double matrixScore = new BigDecimal(score).divide(SystemConstant.PERCENT, 2, BigDecimal.ROUND_HALF_UP).multiply(reportEvaluationDto.getTargetScore()).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                reportExamStudentUsualScoreObjDtoList.add(new ReportExamStudentUsualScoreObjDto(reportEvaluationDto.getTargetId(), reportEvaluationDto, score, matrixScore, usualScoreWordDto.getUsualScoreTargetSumWeight(), usualScoreWordDto.getUsualScoreTargetSumScore()));
                scoreListMap.put(reportEvaluationDto.getTargetId(), reportExamStudentUsualScoreObjDtoList);
            }
        }
        scoreListMap.forEach((k, v) -> {
            Collections.sort(v);
        });
        return reportExamStudentUsualScoreDto;
    }

    /**
     * 计算分数比率
     *
     * @param toltal
     * @param examId
     * @param courseCode
     * @param paperNumber
     * @param teachCourseId
     * @param start
     * @param end
     * @return
     */
    protected ScoreRangeVo getScoreRangeVo(int toltal, Long examId, String courseCode, String paperNumber, Long teachCourseId, Double start, Double end) {
        int count = tcFinalScoreService.getCountByScoreRange(examId, courseCode, paperNumber, teachCourseId, start, end);
        Double rate = null;
        if (toltal != 0) {
            rate = new BigDecimal(count).divide(new BigDecimal(toltal), 2, BigDecimal.ROUND_HALF_UP).setScale(2, BigDecimal.ROUND_HALF_UP).multiply(SystemConstant.PERCENT).doubleValue();
        }
        return new ScoreRangeVo(count, start, end, rate);
    }
}
