package com.xhkjedu.sapi.service.classreport;

import com.alibaba.fastjson.JSON;
import com.xhkjedu.sapi.mapper.classreport.ClassReportMapper;
import com.xhkjedu.sapi.mapper.classreport.ReportClassErrorqueMapper;
import com.xhkjedu.sapi.mapper.classreport.ReportClassErrorquefdMapper;
import com.xhkjedu.sapi.mapper.classreport.ReportClassGuideMapper;
import com.xhkjedu.sapi.mapper.classreport.ReportClassLiveMapper;
import com.xhkjedu.sapi.mapper.classreport.ReportClassPaperMapper;
import com.xhkjedu.sapi.mapper.classreport.ReportClassPointMapper;
import com.xhkjedu.sapi.mapper.classreport.ReportClassReciteMapper;
import com.xhkjedu.sapi.mapper.classreport.ReportClassRoomMapper;
import com.xhkjedu.sapi.mapper.classreport.ReportClasstypeMapper;
import com.xhkjedu.sapi.model.classreport.TReportClassErrorque;
import com.xhkjedu.sapi.model.classreport.TReportClassErrorquefd;
import com.xhkjedu.sapi.model.classreport.TReportClassGuide;
import com.xhkjedu.sapi.model.classreport.TReportClassLive;
import com.xhkjedu.sapi.model.classreport.TReportClassPaper;
import com.xhkjedu.sapi.model.classreport.TReportClassPoint;
import com.xhkjedu.sapi.model.classreport.TReportClassRecite;
import com.xhkjedu.sapi.model.classreport.TReportClassRoom;
import com.xhkjedu.sapi.model.classreport.TReportClasstype;
import com.xhkjedu.sapi.vo.classreport.CGradeSubjectVo;
import com.xhkjedu.sapi.vo.classreport.ReportClasstypeVo;
import com.xhkjedu.sapi.vo.classreport.ReportRateVo;
import com.xhkjedu.sapi.vo.classreport.YearOnYearVo;
import com.xhkjedu.utils.DatesUtil;
import com.xhkjedu.utils.N_Utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.DoubleSummaryStatistics;
import java.util.HashMap;
import java.util.IntSummaryStatistics;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author ywx
 * @classname ClassReportService
 * @description 班级报告
 * @date 2021/5/26 9:55
 **/
@Service
@Slf4j
public class ClassReportService {
    @Resource
    private ClassReportMapper classReportMapper;
    @Resource
    private ReportClasstypeMapper reportClasstypeMapper;
    @Resource
    private ReportClassGuideMapper reportClassGuideMapper;
    @Resource
    private ReportClassPaperMapper reportClassPaperMapper;
    @Resource
    private ReportClassReciteMapper reportClassReciteMapper;
    @Resource
    private ReportClassRoomMapper reportClassRoomMapper;
    @Resource
    private ReportClassErrorqueMapper reportClassErrorqueMapper;
    @Resource
    private ReportClassErrorquefdMapper reportClassErrorquefdMapper;
    @Resource
    private ReportClassLiveMapper reportClassLiveMapper;
    @Resource
    private ReportClassPointMapper reportClassPointMapper;

    public Map<String, List<ReportClasstypeVo>> parseList(List<ReportClasstypeVo> list, Integer type, boolean now) {
        if (!now && type == 1) {//班级
            return list.stream().collect(Collectors.groupingBy(m -> m.getClasstype() + "_" + m.getClassid() + "_" + m.getSubjectid()
                    , LinkedHashMap::new, Collectors.toList()));
        } else if (!now && type == 2) {//年级
            return list.stream().collect(Collectors.groupingBy(m -> m.getSchoolid() + "_" + m.getClasstype() + "_" + m.getGradeid() + "_" + m.getSubjectid()
                    , LinkedHashMap::new, Collectors.toList()));
        } else if (now && type == 1) {//班级日期
            return list.stream().collect(Collectors.groupingBy(m -> m.getClasstype() + "_" + m.getClassid() + "_" + m.getSubjectid()
                    + "_" + m.getBegindate(), LinkedHashMap::new, Collectors.toList()));
        } else {//年级日期
            return list.stream().collect(Collectors.groupingBy(m->m.getSchoolid()+"_"+m.getClasstype()+"_"+m.getGradeid()+"_"+m.getSubjectid()
                    +"_"+m.getBegindate(),LinkedHashMap::new, Collectors.toList()));
        }
    }

    //保存班级报告类型
    public Integer saveType(TReportClasstype type, ReportClasstypeVo vo) {
        TReportClasstype type2 = new TReportClasstype();
        type2.setClassid(vo.getClassid());
        type2.setGradeid(vo.getGradeid());
        type2.setSubjectid(vo.getSubjectid());
        type2.setYear(vo.getYear());
        type2.setSchoolid(vo.getSchoolid());
        type2.setCreatetime(N_Utils.getSecondTimestamp());
        type2.setReporttype(type.getReporttype());
        type2.setBegindate(type.getBegindate());
        type2.setEnddate(type.getEnddate());
        reportClasstypeMapper.insertUseGeneratedKeys(type2);
        return type2.getId();
    }

    //处理班级报告类型
    public void saveType2(TReportClasstype type, ReportClasstypeVo vo, List<TReportClasstype> classtypes) {
        TReportClasstype type2 = new TReportClasstype();
        type2.setClassid(vo.getClassid());
        type2.setGradeid(vo.getGradeid());
        type2.setSubjectid(vo.getSubjectid());
        type2.setYear(vo.getYear());
        type2.setSchoolid(vo.getSchoolid());
        type2.setCreatetime(N_Utils.getSecondTimestamp());
        type2.setReporttype(type.getReporttype());
        type2.setBegindate(type.getBegindate());
        type2.setEnddate(type.getEnddate());
        classtypes.add(type2);
    }

    public void setTypeDate(TReportClasstype type) {
        String begindate;
        String enddate;
        Integer basenum = type.getBasenum() == null ? 0 : type.getBasenum();
        type.setBasenum(basenum);
        if (type.getReporttype() == 1) {
            begindate = DatesUtil.getBeginDayOfLastWeek(basenum);
            enddate = DatesUtil.getEndDayOfLastWeek(basenum);
        } else {
            begindate = DatesUtil.getBeginDayOfLastMonth(basenum);
            enddate = DatesUtil.getEndDayOfLastMonth(basenum);
        }
        type.setBegindate(begindate);
        type.setEnddate(enddate);
        type.setCreatetime(N_Utils.getSecondTimestamp());
    }

    //生成班级报告
    public void generateClassReport(TReportClasstype type){
        setTypeDate(type);

        //预习
        List<ReportClasstypeVo> yxlist = classReportMapper.listPreview(type);
        savePreview(type, yxlist, false);

        //课堂
        List<ReportClasstypeVo> ktlist = classReportMapper.listClassroom(type);
        saveClassroom(type, ktlist, false);
        
        //作业
        List<ReportClasstypeVo> zylist = classReportMapper.listPaper(type);
        savePaper(type, zylist, false);

        //背诵
        List<ReportClasstypeVo> bslist = classReportMapper.listRecite(type);
        saveRecite(type, bslist, false);

        //错题辅导
        List<ReportClasstypeVo> fdlist = classReportMapper.listErrQuestionFd(type);
        saveErrQuestionFd(type, fdlist, false);

        //错题
        List<ReportClasstypeVo> ctlist = classReportMapper.listErrQuestion(type);
        saveErrQuestion(type, ctlist, false);

        //直播
        List<ReportClasstypeVo> zblist = classReportMapper.listLive(type);
        saveLive(type, zblist, false);

        //知识点掌握
        List<ReportClasstypeVo> points = classReportMapper.listPoint(type);
        savePoint(type, points, false);
    }

    public List<TReportClassGuide> savePreview(TReportClasstype type, List<ReportClasstypeVo> list, boolean now) {
        List<TReportClassGuide> list1 = new ArrayList<>();
        Map<String, ReportRateVo> maxnum = new HashMap<>();//年级科目下最高发布次数
        Map<String,Integer> fbrank = new HashMap<>();//年级科目下发布次数排名
        Map<String,Integer> yxrank = new HashMap<>();//年级科目下预习率排名
        Map<String, List<ReportClasstypeVo>> gsubjects = parseList(list, 2, now);
        for(Map.Entry s:gsubjects.entrySet()) {
            List<CGradeSubjectVo> gslist = new ArrayList<>();
            List<ReportClasstypeVo> gsubjects2 = (List<ReportClasstypeVo>) s.getValue();
            Map<Integer,List<ReportClasstypeVo>> clist = gsubjects2.stream().collect(Collectors.groupingBy(m->m.getClassid()));
            for(Map.Entry c:clist.entrySet()) {
                List<ReportClasstypeVo> clist2 = (List<ReportClasstypeVo>) c.getValue();
                ReportClasstypeVo vo = clist2.get(0);
                CGradeSubjectVo gs = new CGradeSubjectVo();
                gs.setClassid(vo.getClassid());
                gs.setClasstype(vo.getClasstype());
                gs.setGradeid(vo.getGradeid());
                gs.setSubjectid(vo.getSubjectid());
                gs.setMaxnum(clist2.stream().mapToInt(ReportClasstypeVo::getFbnum).sum());
                int xsum = clist2.stream().mapToInt(ReportClasstypeVo::getXsnum).sum();
                int tjum = clist2.stream().mapToInt(ReportClasstypeVo::getTjnum).sum();
                gs.setNumrate(N_Utils.getIntegerDivideAndMulitiply(tjum,xsum));
                gslist.add(gs);
            }
            ReportRateVo rateVo = new ReportRateVo();
            String key = (String) s.getKey();
            rateVo.setMaxnum(gslist.stream().max(Comparator.comparing(CGradeSubjectVo::getMaxnum)).get().getMaxnum());
            rateVo.setTjrate(gslist.stream().max(Comparator.comparing(CGradeSubjectVo::getNumrate)).get().getNumrate());
            maxnum.put(key,rateVo);

            //发布次数排名
            gslist = gslist.stream().sorted((s1, s2) -> -Long.compare(s1.getMaxnum(), s2.getMaxnum())).collect(Collectors.toList());
            List<Map.Entry<Integer, List<CGradeSubjectVo>>> gslist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getMaxnum)).entrySet()
                    .stream().sorted((s1, s2) -> -Long.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            Integer index = 1;
            for (Map.Entry<Integer, List<CGradeSubjectVo>> entry : gslist2) {
                for(CGradeSubjectVo cgs : entry.getValue()){
                    fbrank.put(key+"_"+cgs.getClassid(),index);
                }
                index = index + entry.getValue().size();
            }

            //预习率排名
            gslist = gslist.stream().sorted((s1, s2) -> -Double.compare(s1.getNumrate(), s2.getNumrate())).collect(Collectors.toList());
            List<Map.Entry<Double, List<CGradeSubjectVo>>> yxlist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getNumrate)).entrySet()
                    .stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            index = 1;
            for (Map.Entry<Double, List<CGradeSubjectVo>> entry : yxlist2) {
                for (CGradeSubjectVo cgs : entry.getValue()) {
                    yxrank.put(key + "_" + cgs.getClassid(), index);
                }
                index = index + entry.getValue().size();
            }
        }
        Map<String, List<ReportClasstypeVo>> subjects = parseList(list, 1, now);
        Integer classid = type.getClassid();
        List<YearOnYearVo> years = new ArrayList<>();
        if (!now) {
            years = classReportMapper.getPreviewNum(type);
        }
        List<TReportClasstype> classtypes = new ArrayList<>();//班级报告类型集合
        List<TReportClassGuide> guides = new ArrayList<>();//班级报告--预习统计集合
        for (Map.Entry s : subjects.entrySet()) {
            List<ReportClasstypeVo> slist2 = (List<ReportClasstypeVo>) s.getValue();
            DoubleSummaryStatistics statistics = slist2.stream().mapToDouble(ReportClasstypeVo::getNumrate).summaryStatistics();
            ReportClasstypeVo vo = slist2.get(0);
            if (N_Utils.isEmptyInteger(classid) || classid.equals(vo.getClassid())) {
                try {
                    TReportClassGuide rg = new TReportClassGuide();
                    rg.setClassnum(vo.getClassnum());
                    int guidenum = slist2.stream().mapToInt(ReportClasstypeVo::getFbnum).sum();
                    rg.setGuidenum(guidenum);
                    String cgsid = vo.getSchoolid() + "_" + vo.getClasstype() + "_" + vo.getGradeid() + "_" + vo.getSubjectid();
                    if (now) cgsid = cgsid + "_" + vo.getBegindate();
                    ReportRateVo rateVo = maxnum.get(cgsid);
                    rg.setGuidemaxnum(rateVo.getMaxnum());
                    String cgscid = cgsid + "_" + vo.getClassid();
                    rg.setGuiderank(fbrank.get(cgscid));
                    int xsnum = slist2.stream().mapToInt(ReportClasstypeVo::getXsnum).sum();
                    int tjnum = slist2.stream().mapToInt(ReportClasstypeVo::getTjnum).sum();
                    rg.setPrenum(tjnum);
                    Double guiderate = N_Utils.getIntegerDivideAndMulitiply(tjnum, xsnum);
                    rg.setGuiderate(guiderate);
                    rg.setGuideavgrate(N_Utils.formatDouble(statistics.getAverage(), 2));
                    rg.setGuidemaxrate(rateVo.getTjrate());
                    rg.setGuideraterank(yxrank.get(cgscid));
                    rg.setCreatetime(N_Utils.getSecondTimestamp());
                    if (!now) {
                        //计算同比
                        YearOnYearVo y = years.stream().filter(v -> v.getClassid().equals(vo.getClassid()) && v.getSubjectid().equals(vo.getSubjectid())).findFirst().orElse(null);
                        if (y == null) {
                            rg.setGuideprerate(100.0);
                            rg.setPrenumrate(100.0);
                            rg.setPrerate(100.0);
                        } else {
                            rg.setGuideprerate(N_Utils.getIntegerDivideAndMulitiply(guidenum - y.getFbnum(), guidenum));
                            rg.setPrenumrate(N_Utils.getIntegerDivideAndMulitiply(tjnum - y.getTjnum(), tjnum));
                            rg.setPrerate(N_Utils.formatDouble(guiderate - y.getTjrate(), 2));
                        }
                        saveType2(type, vo, classtypes);
                        guides.add(rg);
                    } else {
                        rg.setBegindate(vo.getBegindate());
                        rg.setEnddate(vo.getBegindate());
                    }
                    list1.add(rg);
                } catch (Exception e) {
                    log.error("保存预习报告数据出错：{}", e.getMessage());
                }
            }
        }
        if (N_Utils.isListNotEmpty(classtypes)) {
            reportClasstypeMapper.insertList(classtypes);//批量保存班级报告类型
            for (int i = 0; i < guides.size(); i++) {
                guides.get(i).setCreportid(classtypes.get(i).getId());
            }
            reportClassGuideMapper.insertList(guides);//批量保存班级报告--预习统计
        }
        return list1;
    }
    
    public List<TReportClassRoom> saveClassroom(TReportClasstype type, List<ReportClasstypeVo> list, boolean now) {
        List<TReportClassRoom> list1 = new ArrayList<>();
        Map<String,Integer> maxnum = new HashMap<>();//年级科目下最高发布次数
        Map<String,Integer> fbrank = new HashMap<>();//年级科目下发布次数排名
        Map<String,Integer> cqrank = new HashMap<>();//年级科目下出勤率排名
        Map<String, List<ReportClasstypeVo>> gsubjects = parseList(list, 2, now);
        for(Map.Entry s:gsubjects.entrySet()) {
            List<CGradeSubjectVo> gslist = new ArrayList<>();
            List<ReportClasstypeVo> gsubjects2 = (List<ReportClasstypeVo>) s.getValue();
            Map<Integer,List<ReportClasstypeVo>> clist = gsubjects2.stream().collect(Collectors.groupingBy(m->m.getClassid()));
            for(Map.Entry c:clist.entrySet()) {
                List<ReportClasstypeVo> clist2 = (List<ReportClasstypeVo>) c.getValue();
                ReportClasstypeVo vo = clist2.get(0);
                CGradeSubjectVo gs = new CGradeSubjectVo();
                gs.setClassid(vo.getClassid());
                gs.setClasstype(vo.getClasstype());
                gs.setGradeid(vo.getGradeid());
                gs.setSubjectid(vo.getSubjectid());
                gs.setMaxnum(clist2.stream().mapToInt(ReportClasstypeVo::getFbnum).sum());
                int xsum = clist2.stream().mapToInt(ReportClasstypeVo::getXsnum).sum();
                int tjum = clist2.stream().mapToInt(ReportClasstypeVo::getTjnum).sum();
                gs.setNumrate(N_Utils.getIntegerDivideAndMulitiply(tjum,xsum));
                gslist.add(gs);
            }
            String key = (String) s.getKey();
            CGradeSubjectVo vo2 = gslist.stream().max(Comparator.comparing(CGradeSubjectVo::getMaxnum)).get();
            maxnum.put(key,vo2.getMaxnum());

            //发布次数排名
            gslist = gslist.stream().sorted((s1, s2) -> -Long.compare(s1.getMaxnum(), s2.getMaxnum())).collect(Collectors.toList());
            List<Map.Entry<Integer, List<CGradeSubjectVo>>> gslist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getMaxnum)).entrySet()
                    .stream().sorted((s1, s2) -> -Long.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            Integer index = 1;
            for (Map.Entry<Integer, List<CGradeSubjectVo>> entry : gslist2) {
                for(CGradeSubjectVo cgs : entry.getValue()){
                    fbrank.put(key+"_"+cgs.getClassid(),index);
                }
                index = index + entry.getValue().size();
            }

            //预习率排名
            gslist = gslist.stream().sorted((s1, s2) -> -Double.compare(s1.getNumrate(), s2.getNumrate())).collect(Collectors.toList());
            List<Map.Entry<Double, List<CGradeSubjectVo>>> yxlist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getNumrate)).entrySet()
                    .stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            index = 1;
            for (Map.Entry<Double, List<CGradeSubjectVo>> entry : yxlist2) {
                for (CGradeSubjectVo cgs : entry.getValue()) {
                    cqrank.put(key + "_" + cgs.getClassid(), index);
                }
                index = index + entry.getValue().size();
            }
        }
        Map<String, List<ReportClasstypeVo>> subjects = parseList(list, 1, now);
        Integer classid = type.getClassid();
        List<YearOnYearVo> years = new ArrayList<>();
        if (!now) {
            years = classReportMapper.getClassroomNum(type);
        }
        List<TReportClasstype> classtypes = new ArrayList<>();//班级报告类型集合
        List<TReportClassRoom> rooms = new ArrayList<>();//班级报告--课堂统计集合
        for (Map.Entry s : subjects.entrySet()) {
            List<ReportClasstypeVo> slist2 = (List<ReportClasstypeVo>) s.getValue();
            DoubleSummaryStatistics statistics = slist2.stream().mapToDouble(ReportClasstypeVo::getNumrate).summaryStatistics();
            ReportClasstypeVo vo = slist2.get(0);
            if (N_Utils.isEmptyInteger(classid) || classid.equals(vo.getClassid())) {
                try {
                    TReportClassRoom rr = new TReportClassRoom();
                    rr.setClassnum(vo.getClassnum());
                    int fbnum = slist2.stream().mapToInt(ReportClasstypeVo::getFbnum).sum();
                    rr.setRoomnum(fbnum);
                    String cgsid = vo.getSchoolid() + "_" + vo.getClasstype() + "_" + vo.getGradeid() + "_" + vo.getSubjectid();
                    if (now) cgsid = cgsid + "_" + vo.getBegindate();
                    rr.setRoommaxnum(maxnum.get(cgsid));
                    String cgscid = cgsid + "_" + vo.getClassid();
                    rr.setRoomrank(fbrank.get(cgscid));
                    rr.setTwnum(vo.getTwnum());
                    rr.setTcnum(vo.getTcnum());
                    rr.setDmnum(vo.getDmnum());
                    rr.setQdnum(vo.getQdnum());
                    int xsnum = slist2.stream().mapToInt(ReportClasstypeVo::getXsnum).sum();
                    int tjnum = slist2.stream().mapToInt(ReportClasstypeVo::getTjnum).sum();
                    Double guiderate = N_Utils.getIntegerDivideAndMulitiply(tjnum, xsnum);
                    rr.setCqrate(guiderate);
                    rr.setCqavgrate(N_Utils.formatDouble(statistics.getAverage(), 2));
                    rr.setCqmaxrate(statistics.getMax());
                    rr.setCqraterank(cqrank.get(cgscid));
                    rr.setCreatetime(N_Utils.getSecondTimestamp());
                    if (!now) {
                        //计算同比
                        YearOnYearVo y = years.stream().filter(v -> v.getClassid().equals(vo.getClassid()) && v.getSubjectid().equals(vo.getSubjectid())).findFirst().orElse(null);
                        if (y == null) {
                            rr.setCqprerate(100.0);
                            rr.setPrerate(100.0);
                        } else {
                            rr.setPrerate(N_Utils.getIntegerDivideAndMulitiply(fbnum - y.getFbnum(), fbnum));
                            rr.setCqprerate(N_Utils.formatDouble(guiderate - y.getTjrate(), 2));
                        }
                        saveType2(type, vo, classtypes);
                        rooms.add(rr);
                    } else {
                        rr.setBegindate(vo.getBegindate());
                        rr.setEnddate(vo.getBegindate());
                    }
                    list1.add(rr);
                } catch (Exception e) {
                    log.error("保存课堂数据出错：{}", e.getMessage());
                }
            }
        }
        if (N_Utils.isListNotEmpty(classtypes)) {
            reportClasstypeMapper.insertList(classtypes);//批量保存班级报告类型
            for (int i = 0; i < rooms.size(); i++) {
                rooms.get(i).setCreportid(classtypes.get(i).getId());
            }
            reportClassRoomMapper.insertList(rooms);//批量保存班级报告--课堂统计
        }
        return list1;
    }

    public List<TReportClassPaper> savePaper(TReportClasstype type, List<ReportClasstypeVo> list, boolean now) {
        List<TReportClassPaper> list1 = new ArrayList<>();
        Map<String, ReportRateVo> maxnum = new HashMap<>();//年级科目下最高发布次数
        Map<String,Integer> fbrank = new HashMap<>();//年级科目下发布次数排名
        Map<String,Integer> tjrank = new HashMap<>();//年级科目下提交率排名
        Map<String,Integer> pgrank = new HashMap<>();//年级科目下提交率排名
        Map<String,Integer> zqrank = new HashMap<>();//年级科目下正确率排名
        Map<String, List<ReportClasstypeVo>> gsubjects = parseList(list, 2, now);
        for(Map.Entry s:gsubjects.entrySet()) {
            List<CGradeSubjectVo> gslist = new ArrayList<>();
            List<ReportClasstypeVo> gsubjects2 = (List<ReportClasstypeVo>) s.getValue();
            Map<Integer,List<ReportClasstypeVo>> clist = gsubjects2.stream().collect(Collectors.groupingBy(m->m.getClassid()));
            for(Map.Entry c:clist.entrySet()) {
                List<ReportClasstypeVo> clist2 = (List<ReportClasstypeVo>) c.getValue();
                ReportClasstypeVo vo = clist2.get(0);
                CGradeSubjectVo gs = new CGradeSubjectVo();
                gs.setClassid(vo.getClassid());
                gs.setClasstype(vo.getClasstype());
                gs.setGradeid(vo.getGradeid());
                gs.setSubjectid(vo.getSubjectid());
                gs.setMaxnum(clist2.stream().mapToInt(ReportClasstypeVo::getFbnum).sum());
                int xsum = clist2.stream().mapToInt(ReportClasstypeVo::getXsnum).sum();
                int tjum = clist2.stream().mapToInt(ReportClasstypeVo::getTjnum).sum();
                int pgum = clist2.stream().mapToInt(ReportClasstypeVo::getPgnum).sum();
                Double pscore = clist2.stream().mapToDouble(ReportClasstypeVo::getPscore).sum();
                Double uscore = clist2.stream().mapToDouble(ReportClasstypeVo::getUscore).sum();
                gs.setNumrate(N_Utils.getIntegerDivideAndMulitiply(tjum,xsum));
                gs.setPgrate(N_Utils.getIntegerDivideAndMulitiply(pgum,tjum));
                gs.setZqrate(N_Utils.getDoubleDivideAndMulitiply(uscore,pscore));
                gslist.add(gs);
            }
            ReportRateVo rateVo = new ReportRateVo();
            String key = (String) s.getKey();
            rateVo.setMaxnum(gslist.stream().max(Comparator.comparing(CGradeSubjectVo::getMaxnum)).get().getMaxnum());
            rateVo.setTjrate(gslist.stream().max(Comparator.comparing(CGradeSubjectVo::getNumrate)).get().getNumrate());
            rateVo.setPgrate(gslist.stream().max(Comparator.comparing(CGradeSubjectVo::getPgrate)).get().getPgrate());
            rateVo.setZqrate(gslist.stream().max(Comparator.comparing(CGradeSubjectVo::getZqrate)).get().getZqrate());
            maxnum.put(key,rateVo);

            //发布次数排名
            gslist = gslist.stream().sorted((s1, s2) -> -Long.compare(s1.getMaxnum(), s2.getMaxnum())).collect(Collectors.toList());
            List<Map.Entry<Integer, List<CGradeSubjectVo>>> gslist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getMaxnum)).entrySet()
                    .stream().sorted((s1, s2) -> -Long.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            Integer index = 1;
            for (Map.Entry<Integer, List<CGradeSubjectVo>> entry : gslist2) {
                for(CGradeSubjectVo cgs : entry.getValue()){
                    fbrank.put(key+"_"+cgs.getClassid(),index);
                }
                index = index + entry.getValue().size();
            }

            //提交率排名
            gslist = gslist.stream().sorted((s1, s2) -> -Double.compare(s1.getNumrate(), s2.getNumrate())).collect(Collectors.toList());
            List<Map.Entry<Double, List<CGradeSubjectVo>>> yxlist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getNumrate)).entrySet()
                    .stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            index = 1;
            for (Map.Entry<Double, List<CGradeSubjectVo>> entry : yxlist2) {
                for(CGradeSubjectVo cgs : entry.getValue()){
                    tjrank.put(key+"_"+cgs.getClassid(),index);
                }
                index = index + entry.getValue().size();
            }

            //批改率排名
            gslist = gslist.stream().sorted((s1, s2) -> -Double.compare(s1.getPgrate(), s2.getPgrate())).collect(Collectors.toList());
            yxlist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getPgrate)).entrySet()
                    .stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            index = 1;
            for (Map.Entry<Double, List<CGradeSubjectVo>> entry : yxlist2) {
                for(CGradeSubjectVo cgs : entry.getValue()){
                    pgrank.put(key+"_"+cgs.getClassid(),index);
                }
                index = index + entry.getValue().size();
            }

            //正确率排名
            gslist = gslist.stream().sorted((s1, s2) -> -Double.compare(s1.getZqrate(), s2.getZqrate())).collect(Collectors.toList());
            yxlist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getZqrate)).entrySet()
                    .stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            index = 1;
            for (Map.Entry<Double, List<CGradeSubjectVo>> entry : yxlist2) {
                for (CGradeSubjectVo cgs : entry.getValue()) {
                    zqrank.put(key + "_" + cgs.getClassid(), index);
                }
                index = index + entry.getValue().size();
            }
        }
        Map<String, List<ReportClasstypeVo>> subjects = parseList(list, 1, now);
        Integer classid = type.getClassid();
        List<YearOnYearVo> years = new ArrayList<>();
        if (!now) {
            years = classReportMapper.getPaperNum(type);
        }
        List<TReportClasstype> classtypes = new ArrayList<>();//班级报告类型集合
        List<TReportClassPaper> papers = new ArrayList<>();//班级报告--作业统计集合
        for (Map.Entry s : subjects.entrySet()) {
            List<ReportClasstypeVo> slist2 = (List<ReportClasstypeVo>) s.getValue();
            DoubleSummaryStatistics statistics = slist2.stream().mapToDouble(ReportClasstypeVo::getNumrate).summaryStatistics();
            ReportClasstypeVo vo = slist2.get(0);
            if (N_Utils.isEmptyInteger(classid) || classid.equals(vo.getClassid())) {
                try {
                    TReportClassPaper rp = new TReportClassPaper();
                    rp.setClassnum(vo.getClassnum());
                    int fbnum = slist2.stream().mapToInt(ReportClasstypeVo::getFbnum).sum();
                    rp.setPapernum(fbnum);
                    String cgsid = vo.getSchoolid() + "_" + vo.getClasstype() + "_" + vo.getGradeid() + "_" + vo.getSubjectid();
                    if (now) cgsid = cgsid + "_" + vo.getBegindate();
                    ReportRateVo rateVo = maxnum.get(cgsid);
                    rp.setMaxnum(rateVo.getMaxnum());
                    String cgscid = cgsid + "_" + vo.getClassid();
                    rp.setPaperrank(fbrank.get(cgscid));
                    int xsnum = slist2.stream().mapToInt(ReportClasstypeVo::getXsnum).sum();
                    int tjnum = slist2.stream().mapToInt(ReportClasstypeVo::getTjnum).sum();
                    int pgnum = slist2.stream().mapToInt(ReportClasstypeVo::getPgnum).sum();
                    Double pscore = slist2.stream().mapToDouble(ReportClasstypeVo::getPscore).sum();
                    Double uscore = slist2.stream().mapToDouble(ReportClasstypeVo::getUscore).sum();
                    Double commitrate = N_Utils.getIntegerDivideAndMulitiply(tjnum, xsnum);
                    rp.setCommitrate(commitrate);
                    rp.setCommitavgrate(N_Utils.formatDouble(statistics.getAverage(), 2));
                    rp.setCommitmaxrate(rateVo.getTjrate());
                    rp.setCommitraterank(tjrank.get(cgscid));

                    Double checkrate = N_Utils.getIntegerDivideAndMulitiply(pgnum, tjnum);
                    statistics = slist2.stream().mapToDouble(ReportClasstypeVo::getPgrate).summaryStatistics();
                    rp.setCheckrate(checkrate);
                    rp.setCheckavgrate(N_Utils.formatDouble(statistics.getAverage(), 2));
                    rp.setCheckmaxrate(rateVo.getPgrate());
                    rp.setCheckraterank(pgrank.get(cgscid));

                    Double correctrate = N_Utils.getDoubleDivideAndMulitiply(uscore, pscore);
                    statistics = slist2.stream().mapToDouble(ReportClasstypeVo::getZqrate).summaryStatistics();
                    rp.setCorrectrate(correctrate);
                    rp.setCorrectavgrate(N_Utils.formatDouble(statistics.getAverage(), 2));
                    rp.setCorrectmaxrate(rateVo.getZqrate());
                    rp.setCorrectraterank(zqrank.get(cgscid));
                    rp.setCreatetime(N_Utils.getSecondTimestamp());
                    if (!now) {
                        //计算同比
                        YearOnYearVo y = years.stream().filter(v -> v.getClassid().equals(vo.getClassid()) && v.getSubjectid().equals(vo.getSubjectid())).findFirst().orElse(null);
                        if (y == null) {
                            rp.setPrenumrate(100.0);
                            rp.setCommitprerate(100.0);
                            rp.setCheckprerate(100.0);
                            rp.setCorrectprerate(100.0);
                        } else {
                            rp.setPrenumrate(N_Utils.getIntegerDivideAndMulitiply(fbnum - y.getFbnum(), fbnum));
                            rp.setCommitprerate(N_Utils.formatDouble(commitrate - y.getTjrate(), 2));
                            rp.setCheckprerate(N_Utils.formatDouble(checkrate - y.getPgrate(), 2));
                            rp.setCorrectprerate(N_Utils.formatDouble(correctrate - y.getZqrate(), 2));
                        }
                        saveType2(type, vo, classtypes);
                        papers.add(rp);
                    } else {
                        rp.setBegindate(vo.getBegindate());
                        rp.setEnddate(vo.getBegindate());
                    }
                    list1.add(rp);
                } catch (Exception e) {
                    log.error("保存作业数据出错：{}", e.getMessage());
                }
            }
        }
        if (N_Utils.isListNotEmpty(classtypes)) {
            reportClasstypeMapper.insertList(classtypes);//批量保存班级报告类型
            for (int i = 0; i < papers.size(); i++) {
                papers.get(i).setCreportid(classtypes.get(i).getId());
            }
            reportClassPaperMapper.insertList(papers);//批量保存班级报告--作业统计
        }
        return list1;
    }

    public List<TReportClassRecite> saveRecite(TReportClasstype type, List<ReportClasstypeVo> list, boolean now) {
        List<TReportClassRecite> list1 = new ArrayList<>();
        Map<String, ReportRateVo> maxnum = new HashMap<>();//年级科目下最高发布次数
        Map<String,Integer> fbrank = new HashMap<>();//年级科目下发布次数排名
        Map<String,Integer> tjrank = new HashMap<>();//年级科目下提交率排名
        Map<String,Integer> zqrank = new HashMap<>();//年级科目下正确率排名
        Map<String, List<ReportClasstypeVo>> gsubjects = parseList(list, 2, now);
        for(Map.Entry s:gsubjects.entrySet()) {
            List<CGradeSubjectVo> gslist = new ArrayList<>();
            List<ReportClasstypeVo> gsubjects2 = (List<ReportClasstypeVo>) s.getValue();
            Map<Integer,List<ReportClasstypeVo>> clist = gsubjects2.stream().collect(Collectors.groupingBy(m->m.getClassid()));
            for(Map.Entry c:clist.entrySet()) {
                List<ReportClasstypeVo> clist2 = (List<ReportClasstypeVo>) c.getValue();
                ReportClasstypeVo vo = clist2.get(0);
                CGradeSubjectVo gs = new CGradeSubjectVo();
                gs.setClassid(vo.getClassid());
                gs.setClasstype(vo.getClasstype());
                gs.setGradeid(vo.getGradeid());
                gs.setSubjectid(vo.getSubjectid());
                gs.setMaxnum(clist2.stream().mapToInt(ReportClasstypeVo::getFbnum).sum());
                int xsum = clist2.stream().mapToInt(ReportClasstypeVo::getXsnum).sum();
                int tjum = clist2.stream().mapToInt(ReportClasstypeVo::getTjnum).sum();
                gs.setNumrate(N_Utils.getIntegerDivideAndMulitiply(tjum,xsum));
                Double pscore = clist2.stream().mapToDouble(ReportClasstypeVo::getPscore).sum();
                Double uscore = clist2.stream().mapToDouble(ReportClasstypeVo::getUscore).sum();
                gs.setZqrate(N_Utils.getDoubleDivideAndMulitiply(uscore,pscore));
                gslist.add(gs);
            }
            ReportRateVo rateVo = new ReportRateVo();
            String key = (String) s.getKey();
            rateVo.setMaxnum(gslist.stream().max(Comparator.comparing(CGradeSubjectVo::getMaxnum)).get().getMaxnum());
            rateVo.setTjrate(gslist.stream().max(Comparator.comparing(CGradeSubjectVo::getNumrate)).get().getNumrate());
            rateVo.setZqrate(gslist.stream().max(Comparator.comparing(CGradeSubjectVo::getZqrate)).get().getZqrate());
            maxnum.put(key,rateVo);

            //发布次数排名
            gslist = gslist.stream().sorted((s1, s2) -> -Long.compare(s1.getMaxnum(), s2.getMaxnum())).collect(Collectors.toList());
            List<Map.Entry<Integer, List<CGradeSubjectVo>>> gslist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getMaxnum)).entrySet()
                    .stream().sorted((s1, s2) -> -Long.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            Integer index = 1;
            for (Map.Entry<Integer, List<CGradeSubjectVo>> entry : gslist2) {
                for(CGradeSubjectVo cgs : entry.getValue()){
                    fbrank.put(key+"_"+cgs.getClassid(),index);
                }
                index = index + entry.getValue().size();
            }

            //提交率排名
            gslist = gslist.stream().sorted((s1, s2) -> -Double.compare(s1.getNumrate(), s2.getNumrate())).collect(Collectors.toList());
            List<Map.Entry<Double, List<CGradeSubjectVo>>> yxlist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getNumrate)).entrySet()
                    .stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            index = 1;
            for (Map.Entry<Double, List<CGradeSubjectVo>> entry : yxlist2) {
                for(CGradeSubjectVo cgs : entry.getValue()){
                    tjrank.put(key+"_"+cgs.getClassid(),index);
                }
                index = index + entry.getValue().size();
            }

            //正确率排名
            gslist = gslist.stream().sorted((s1, s2) -> -Double.compare(s1.getZqrate(), s2.getZqrate())).collect(Collectors.toList());
            yxlist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getZqrate)).entrySet()
                    .stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            index = 1;
            for (Map.Entry<Double, List<CGradeSubjectVo>> entry : yxlist2) {
                for (CGradeSubjectVo cgs : entry.getValue()) {
                    zqrank.put(key + "_" + cgs.getClassid(), index);
                }
                index = index + entry.getValue().size();
            }
        }
        Map<String, List<ReportClasstypeVo>> subjects = parseList(list, 1, now);
        Integer classid = type.getClassid();
        List<YearOnYearVo> years = new ArrayList<>();
        if (!now) {
            years = classReportMapper.getReciteNum(type);
        }
        List<TReportClasstype> classtypes = new ArrayList<>();//班级报告类型集合
        List<TReportClassRecite> recites = new ArrayList<>();//班级报告--背诵统计集合
        for (Map.Entry s : subjects.entrySet()) {
            List<ReportClasstypeVo> slist2 = (List<ReportClasstypeVo>) s.getValue();
            DoubleSummaryStatistics statistics = slist2.stream().mapToDouble(ReportClasstypeVo::getNumrate).summaryStatistics();
            ReportClasstypeVo vo = slist2.get(0);
            if (N_Utils.isEmptyInteger(classid) || classid.equals(vo.getClassid())) {
                try {
                    TReportClassRecite rr = new TReportClassRecite();
                    rr.setClassnum(vo.getClassnum());
                    int fbnum = slist2.stream().mapToInt(ReportClasstypeVo::getFbnum).sum();
                    rr.setRecitenum(fbnum);
                    String cgsid = vo.getSchoolid() + "_" + vo.getClasstype() + "_" + vo.getGradeid() + "_" + vo.getSubjectid();
                    if (now) cgsid = cgsid + "_" + vo.getBegindate();
                    ReportRateVo rateVo = maxnum.get(cgsid);
                    rr.setRecitemaxnum(rateVo.getMaxnum());
                    String cgscid = cgsid + "_" + vo.getClassid();
                    rr.setReciterank(fbrank.get(cgscid));
                    int xsnum = slist2.stream().mapToInt(ReportClasstypeVo::getXsnum).sum();
                    int tjnum = slist2.stream().mapToInt(ReportClasstypeVo::getTjnum).sum();
                    Double guiderate = N_Utils.getIntegerDivideAndMulitiply(tjnum, xsnum);
                    rr.setCommitrate(guiderate);
                    rr.setCommitavgrate(N_Utils.formatDouble(statistics.getAverage(), 2));
                    rr.setCommitmaxrate(rateVo.getTjrate());
                    rr.setCommitraterank(tjrank.get(cgscid));

                    Double pscore = slist2.stream().mapToDouble(ReportClasstypeVo::getPscore).sum();
                    Double uscore = slist2.stream().mapToDouble(ReportClasstypeVo::getUscore).sum();
                    Double correctrate = N_Utils.getDoubleDivideAndMulitiply(uscore, pscore);
                    statistics = slist2.stream().mapToDouble(ReportClasstypeVo::getZqrate).summaryStatistics();
                    rr.setCorrectrate(correctrate);
                    rr.setCorrectavgrate(N_Utils.formatDouble(statistics.getAverage(), 2));
                    rr.setCorrectmaxrate(rateVo.getZqrate());
                    rr.setCorrectraterank(zqrank.get(cgscid));
                    rr.setCreatetime(N_Utils.getSecondTimestamp());
                    if (!now) {
                        //计算同比
                        YearOnYearVo y = years.stream().filter(v -> v.getClassid().equals(vo.getClassid()) && v.getSubjectid().equals(vo.getSubjectid())).findFirst().orElse(null);
                        if (y == null) {
                            rr.setReciteprerate(100.0);
                            rr.setCommitprerate(100.0);
                            rr.setCorrectprerate(100.0);
                        } else {
                            rr.setReciteprerate(N_Utils.getIntegerDivideAndMulitiply(fbnum - y.getFbnum(), fbnum));
                            rr.setCommitprerate(N_Utils.formatDouble(guiderate - y.getTjrate(), 2));
                            rr.setCorrectprerate(N_Utils.formatDouble(correctrate - y.getZqrate(), 2));
                        }
                        saveType2(type, vo, classtypes);
                        recites.add(rr);
                    } else {
                        rr.setBegindate(vo.getBegindate());
                        rr.setEnddate(vo.getBegindate());
                    }
                    list1.add(rr);
                } catch (Exception e) {
                    log.error("保存背诵数据出错：{}", e.getMessage());
                }
            }
        }
        if (N_Utils.isListNotEmpty(classtypes)) {
            reportClasstypeMapper.insertList(classtypes);//批量保存班级报告类型
            for (int i = 0; i < recites.size(); i++) {
                recites.get(i).setCreportid(classtypes.get(i).getId());
            }
            reportClassReciteMapper.insertList(recites);//批量保存班级报告--背诵统计
        }
        return list1;
    }

    public List<TReportClassErrorquefd> saveErrQuestionFd(TReportClasstype type, List<ReportClasstypeVo> list, boolean now) {
        List<TReportClassErrorquefd> list1 = new ArrayList<>();
        Map<String,Integer> maxnum = new HashMap<>();//年级科目下最高发布次数
        Map<String,Double> avgnum = new HashMap<>();//年级科目下平均发布次数
        Map<String,Integer> fbrank = new HashMap<>();//年级科目下发布次数排名
        Map<String, List<ReportClasstypeVo>> gsubjects = parseList(list, 2, now);
        for(Map.Entry s:gsubjects.entrySet()) {
            List<CGradeSubjectVo> gslist = new ArrayList<>();
            List<ReportClasstypeVo> gsubjects2 = (List<ReportClasstypeVo>) s.getValue();
            Map<Integer,List<ReportClasstypeVo>> clist = gsubjects2.stream().collect(Collectors.groupingBy(m->m.getClassid()));
            for(Map.Entry c:clist.entrySet()) {
                List<ReportClasstypeVo> clist2 = (List<ReportClasstypeVo>) c.getValue();
                ReportClasstypeVo vo = clist2.get(0);
                CGradeSubjectVo gs = new CGradeSubjectVo();
                gs.setClassid(vo.getClassid());
                gs.setClasstype(vo.getClasstype());
                gs.setGradeid(vo.getGradeid());
                gs.setSubjectid(vo.getSubjectid());
                gs.setMaxnum(clist2.stream().mapToInt(ReportClasstypeVo::getFbnum).sum());
                gslist.add(gs);
            }
            String key = (String) s.getKey();
            CGradeSubjectVo vo2 = gslist.stream().max(Comparator.comparing(CGradeSubjectVo::getMaxnum)).get();
            maxnum.put(key,vo2.getMaxnum());
            Double anum = gslist.stream().mapToInt(CGradeSubjectVo::getMaxnum).average().getAsDouble();
            anum = N_Utils.formatDouble(anum, 2);
            avgnum.put(key,anum);

            //发布次数排名
            gslist = gslist.stream().sorted((s1, s2) -> -Long.compare(s1.getMaxnum(), s2.getMaxnum())).collect(Collectors.toList());
            List<Map.Entry<Integer, List<CGradeSubjectVo>>> gslist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getMaxnum)).entrySet()
                    .stream().sorted((s1, s2) -> -Long.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            Integer index = 1;
            for (Map.Entry<Integer, List<CGradeSubjectVo>> entry : gslist2) {
                for (CGradeSubjectVo cgs : entry.getValue()) {
                    fbrank.put(key + "_" + cgs.getClassid(), index);
                }
                index = index + entry.getValue().size();
            }
        }
        Map<String, List<ReportClasstypeVo>> subjects = parseList(list, 1, now);
        Integer classid = type.getClassid();
        List<YearOnYearVo> years = new ArrayList<>();
        if (!now) {
            years = classReportMapper.getErrQuestionFdNum(type);
        }
        List<TReportClasstype> classtypes = new ArrayList<>();//班级报告类型集合
        List<TReportClassErrorquefd> errorquefds = new ArrayList<>();//班级报告--错题辅导统计集合
        for (Map.Entry s : subjects.entrySet()) {
            List<ReportClasstypeVo> slist2 = (List<ReportClasstypeVo>) s.getValue();
            ReportClasstypeVo vo = slist2.get(0);
            if (N_Utils.isEmptyInteger(classid) || classid.equals(vo.getClassid())) {
                try {
                    TReportClassErrorquefd ref = new TReportClassErrorquefd();

                    ref.setClassnum(vo.getClassnum());
                    int fbnum = slist2.stream().mapToInt(ReportClasstypeVo::getFbnum).sum();
                    ref.setFdnum(fbnum);
                    String cgsid = vo.getSchoolid() + "_" + vo.getClasstype() + "_" + vo.getGradeid() + "_" + vo.getSubjectid();
                    if (now) cgsid = cgsid + "_" + vo.getBegindate();
                    ref.setFdmaxnum(maxnum.get(cgsid));
                    String cgscid = cgsid + "_" + vo.getClassid();
                    ref.setFdrank(fbrank.get(cgscid));
                    ref.setFdavgnum(avgnum.get(cgsid));
                    ref.setCreatetime(N_Utils.getSecondTimestamp());
                    if (!now) {
                        //计算同比
                        YearOnYearVo y = years.stream().filter(v -> v.getClassid().equals(vo.getClassid()) && v.getSubjectid().equals(vo.getSubjectid())).findFirst().orElse(null);
                        if (y == null) {
                            ref.setPrerate(100.0);
                        } else {
                            ref.setPrerate(N_Utils.getIntegerDivideAndMulitiply(fbnum - y.getFbnum(), fbnum));
                        }
                        saveType2(type, vo, classtypes);
                        errorquefds.add(ref);
                    } else {
                        ref.setBegindate(vo.getBegindate());
                        ref.setEnddate(vo.getBegindate());
                    }
                    list1.add(ref);
                } catch (Exception e) {
                    log.error("保存错题辅导数据出错：{}", e.getMessage());
                }
            }
        }
        if (N_Utils.isListNotEmpty(classtypes)) {
            reportClasstypeMapper.insertList(classtypes);//批量保存班级报告类型
            for (int i = 0; i < errorquefds.size(); i++) {
                errorquefds.get(i).setCreportid(classtypes.get(i).getId());
            }
            reportClassErrorquefdMapper.insertList(errorquefds);//批量保存班级报告--错题辅导统计
        }
        return list1;
    }

    public List<TReportClassErrorque> saveErrQuestion(TReportClasstype type, List<ReportClasstypeVo> list, boolean now) {
        List<TReportClassErrorque> list1 = new ArrayList<>();
        Map<String,Integer> maxnum = new HashMap<>();//年级科目下最高发布次数
        Map<String,Integer> fbrank = new HashMap<>();//年级科目下发布次数排名
        Map<String, List<ReportClasstypeVo>> gsubjects = parseList(list, 2, false);
        for(Map.Entry s:gsubjects.entrySet()) {
            List<CGradeSubjectVo> gslist = new ArrayList<>();
            List<ReportClasstypeVo> gsubjects2 = (List<ReportClasstypeVo>) s.getValue();
            Map<Integer,List<ReportClasstypeVo>> clist = gsubjects2.stream().collect(Collectors.groupingBy(m->m.getClassid()));
            for(Map.Entry c:clist.entrySet()) {
                List<ReportClasstypeVo> clist2 = (List<ReportClasstypeVo>) c.getValue();
                ReportClasstypeVo vo = clist2.get(0);
                CGradeSubjectVo gs = new CGradeSubjectVo();
                gs.setClassid(vo.getClassid());
                gs.setClasstype(vo.getClasstype());
                gs.setGradeid(vo.getGradeid());
                gs.setSubjectid(vo.getSubjectid());
                gs.setMaxnum(clist2.size());
                gslist.add(gs);
            }
            String key = (String) s.getKey();
            CGradeSubjectVo vo2 = gslist.stream().max(Comparator.comparing(CGradeSubjectVo::getMaxnum)).get();
            maxnum.put(key,vo2.getMaxnum());

            //发布次数排名
            gslist = gslist.stream().sorted((s1, s2) -> -Long.compare(s1.getMaxnum(), s2.getMaxnum())).collect(Collectors.toList());
            List<Map.Entry<Integer, List<CGradeSubjectVo>>> gslist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getMaxnum)).entrySet()
                    .stream().sorted((s1, s2) -> -Long.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            Integer index = 1;
            for (Map.Entry<Integer, List<CGradeSubjectVo>> entry : gslist2) {
                for (CGradeSubjectVo cgs : entry.getValue()) {
                    fbrank.put(key + "_" + cgs.getClassid(), index);
                }
                index = index + entry.getValue().size();
            }
        }

        Map<String, List<ReportClasstypeVo>> subjects = parseList(list, 1, false);
        Integer classid = type.getClassid();
        List<YearOnYearVo> years = new ArrayList<>();
        if (!now) {
            years = classReportMapper.getErrQuestionNum(type);
        }
        List<TReportClasstype> classtypes = new ArrayList<>();//班级报告类型集合
        List<TReportClassErrorque> errorques = new ArrayList<>();//班级报告--错题统计集合
        for (Map.Entry s : subjects.entrySet()) {
            List<Map> types = new ArrayList<>();
            List<ReportClasstypeVo> slist2 = (List<ReportClasstypeVo>) s.getValue();
            ReportClasstypeVo vo = slist2.get(0);
            if (N_Utils.isEmptyInteger(classid) || classid.equals(vo.getClassid())) {
                try {
                    Map<String, List<ReportClasstypeVo>> qtypes = slist2.stream().collect(Collectors.groupingBy(m -> m.getTypeid()));
                    for (Map.Entry t : qtypes.entrySet()) {
                        List<ReportClasstypeVo> qtypes2 = (List<ReportClasstypeVo>) t.getValue();
                        ReportClasstypeVo t2 = qtypes2.get(0);
                        Map map = new HashMap();
                        map.put("qtypeid", t2.getTypeid());
                        map.put("qtypename", t2.getTypename());
                        map.put("num", qtypes2.size());
                        types.add(map);
                    }
                    vo.setReporttype(type.getReporttype());
                    vo.setBasenum(type.getBasenum());
                    List<Map> points = classReportMapper.listErrQuestionPoint(vo);
                    TReportClassErrorque rq = new TReportClassErrorque();
                    rq.setClassnum(vo.getClassnum());
                    int fbnum = slist2.size();
                    rq.setCeqnum(fbnum);
                    String cgsid = vo.getSchoolid() + "_" + vo.getClasstype() + "_" + vo.getGradeid() + "_" + vo.getSubjectid();
                    rq.setCeqmaxnum(maxnum.get(cgsid));
                    String cgscid = cgsid + "_" + vo.getClassid();
                    rq.setCeqrank(fbrank.get(cgscid));
                    rq.setQtypejson(JSON.toJSONString(types));
                    rq.setPointjson(JSON.toJSONString(points));
                    rq.setCreatetime(N_Utils.getSecondTimestamp());
                    if (!now) {
                        //计算同比
                        YearOnYearVo y = years.stream().filter(v -> v.getClassid().equals(vo.getClassid()) && v.getSubjectid().equals(vo.getSubjectid())).findFirst().orElse(null);
                        if (y == null) {
                            rq.setPrerate(100.0);
                        } else {
                            rq.setPrerate(N_Utils.getIntegerDivideAndMulitiply(fbnum - y.getFbnum(), fbnum));
                        }
                        saveType2(type, vo, classtypes);
                        errorques.add(rq);
                    } else {
                        rq.setBegindate(type.getBegindate());
                        rq.setEnddate(type.getEnddate());
                    }
                    list1.add(rq);
                } catch (Exception e) {
                    log.error("保存错题数据出错：{}", e.getMessage());
                }
            }
        }
        if (N_Utils.isListNotEmpty(classtypes)) {
            reportClasstypeMapper.insertList(classtypes);//批量保存班级报告类型
            for (int i = 0; i < errorques.size(); i++) {
                errorques.get(i).setCreportid(classtypes.get(i).getId());
            }
            reportClassErrorqueMapper.insertList(errorques);//批量保存班级报告--错题统计
        }
        return list1;
    }

    public List<TReportClassLive> saveLive(TReportClasstype type, List<ReportClasstypeVo> list, boolean now) {
        List<TReportClassLive> list1 = new ArrayList<>();
        Map<String,Integer> maxnum = new HashMap<>();//年级科目下最高发布次数
        Map<String,Integer> zbrank = new HashMap<>();//年级科目下直播次数排名
        Map<String,Integer> scrank = new HashMap<>();//年级科目下时长排名
        Map<String,Integer> minutenum = new HashMap<>();//年级科目下直播时长
        Map<String, List<ReportClasstypeVo>> gsubjects = parseList(list, 2, now);
        for(Map.Entry s:gsubjects.entrySet()) {
            List<CGradeSubjectVo> gslist = new ArrayList<>();
            List<ReportClasstypeVo> gsubjects2 = (List<ReportClasstypeVo>) s.getValue();
            Map<Integer,List<ReportClasstypeVo>> clist = gsubjects2.stream().collect(Collectors.groupingBy(m->m.getClassid()));
            String key = (String) s.getKey();
            for(Map.Entry c:clist.entrySet()) {
                List<ReportClasstypeVo> clist2 = (List<ReportClasstypeVo>) c.getValue();
                ReportClasstypeVo vo = clist2.get(0);
                CGradeSubjectVo gs = new CGradeSubjectVo();
                gs.setClassid(vo.getClassid());
                gs.setClasstype(vo.getClasstype());
                gs.setGradeid(vo.getGradeid());
                gs.setSubjectid(vo.getSubjectid());
                gs.setMaxnum(clist2.stream().mapToInt(ReportClasstypeVo::getFbnum).sum());
                int scnum = clist2.stream().mapToInt(ReportClasstypeVo::getMinutenum).sum();
                gs.setMinutenum(scnum);
                minutenum.put(key+"_"+vo.getClassid(),scnum);
                gslist.add(gs);
            }
            CGradeSubjectVo vo2 = gslist.stream().max(Comparator.comparing(CGradeSubjectVo::getMaxnum)).get();
            maxnum.put(key,vo2.getMaxnum());


            //直播次数排名
            gslist = gslist.stream().sorted((s1, s2) -> -Long.compare(s1.getMaxnum(), s2.getMaxnum())).collect(Collectors.toList());
            List<Map.Entry<Integer, List<CGradeSubjectVo>>> gslist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getMaxnum)).entrySet()
                    .stream().sorted((s1, s2) -> -Long.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            Integer index = 1;
            for (Map.Entry<Integer, List<CGradeSubjectVo>> entry : gslist2) {
                for(CGradeSubjectVo cgs : entry.getValue()){
                    zbrank.put(key+"_"+cgs.getClassid(),index);
                }
                index = index + entry.getValue().size();
            }

            //时长排名
            gslist = gslist.stream().sorted((s1, s2) -> -Double.compare(s1.getMinutenum(), s2.getMinutenum())).collect(Collectors.toList());
            List<Map.Entry<Integer, List<CGradeSubjectVo>>> yxlist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getMinutenum)).entrySet()
                    .stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            index = 1;
            for (Map.Entry<Integer, List<CGradeSubjectVo>> entry : yxlist2) {
                for (CGradeSubjectVo cgs : entry.getValue()) {
                    scrank.put(key + "_" + cgs.getClassid(), index);
                }
                index = index + entry.getValue().size();
            }
        }
        Map<String, List<ReportClasstypeVo>> subjects = parseList(list, 1, now);
        Integer classid = type.getClassid();
        List<YearOnYearVo> years = new ArrayList<>();
        if (!now) {
            years = classReportMapper.getLiveNum(type);
        }
        List<TReportClasstype> classtypes = new ArrayList<>();//班级报告类型集合
        List<TReportClassLive> lives = new ArrayList<>();//班级报告--直播统计集合
        for (Map.Entry s : subjects.entrySet()) {
            List<ReportClasstypeVo> slist2 = (List<ReportClasstypeVo>) s.getValue();
            IntSummaryStatistics statistics = slist2.stream().mapToInt(ReportClasstypeVo::getMinutenum).summaryStatistics();
            ReportClasstypeVo vo = slist2.get(0);
            if (N_Utils.isEmptyInteger(classid) || classid.equals(vo.getClassid())) {
                try {
                    TReportClassLive rl = new TReportClassLive();
                    rl.setClassnum(vo.getClassnum());
                    int fbnum = slist2.stream().mapToInt(ReportClasstypeVo::getFbnum).sum();
                    rl.setLivenum(fbnum);
                    String cgsid = vo.getSchoolid() + "_" + vo.getClasstype() + "_" + vo.getGradeid() + "_" + vo.getSubjectid();
                    if (now) cgsid = cgsid + "_" + vo.getBegindate();
                    rl.setLivemaxnum(maxnum.get(cgsid));
                    String cgscid = cgsid + "_" + vo.getClassid();
                    rl.setLiverank(zbrank.get(cgscid));
                    Integer scnum = minutenum.get(cgscid);
                    rl.setMinutenum(scnum);
                    rl.setMinuteave(N_Utils.formatDouble(statistics.getAverage(), 2));
                    rl.setMinutemax(statistics.getMax());
                    rl.setMinuterank(scrank.get(cgscid));
                    rl.setCreatetime(N_Utils.getSecondTimestamp());
                    if (!now) {
                        //计算同比
                        YearOnYearVo y = years.stream().filter(v -> v.getClassid().equals(vo.getClassid()) && v.getSubjectid().equals(vo.getSubjectid())).findFirst().orElse(null);
                        if (y == null) {
                            rl.setLiveprerate(100.0);
                            rl.setMinutepre(100.0);
                        } else {
                            rl.setLiveprerate(N_Utils.getIntegerDivideAndMulitiply(fbnum - y.getFbnum(), fbnum));
                            rl.setMinutepre(N_Utils.getIntegerDivideAndMulitiply(scnum - y.getTjnum(), scnum));
                        }
                        saveType2(type, vo, classtypes);
                        lives.add(rl);
                    } else {
                        rl.setBegindate(vo.getBegindate());
                        rl.setEnddate(vo.getBegindate());
                    }
                    list1.add(rl);
                } catch (Exception e) {
                    log.error("保存直播数据出错：{}", e.getMessage());
                }
            }
        }
        if (N_Utils.isListNotEmpty(classtypes)) {
            reportClasstypeMapper.insertList(classtypes);//批量保存班级报告类型
            for (int i = 0; i < lives.size(); i++) {
                lives.get(i).setCreportid(classtypes.get(i).getId());
            }
            reportClassLiveMapper.insertList(lives);//批量保存班级报告--直播统计
        }
        return list1;
    }

    public List<TReportClassGuide> listYx(TReportClasstype type) {
        Integer reporttype = type.getReporttype();
        if (reporttype <= 2) {
            return classReportMapper.listYx(type)
                    .stream().sorted(Comparator.comparing(TReportClassGuide::getCreportid)).collect(Collectors.toList());
        } else {
            //预习
            List<ReportClasstypeVo> yxlist = classReportMapper.listPreview(type);
            type.setReporttype(reporttype - 2);
            setTypeDate(type);
            List<TReportClassGuide> list1 = savePreview(type, yxlist, true);
            Map<Integer, List<ReportClasstypeVo>> collect = yxlist.stream().collect(Collectors.groupingBy(m -> m.getClassid()));
            TReportClassGuide r = new TReportClassGuide();
            Integer classnum = collect.size();//班级数量
            type.setModule("preview");
            CGradeSubjectVo c = getcGradeSubjectVo(type, collect);//计算同比等数据
            r.setClassnum(classnum);//班级人数
            r.setGuidenum(c.getFbnum());//发布预习次数
            r.setGuidemaxnum(c.getMaxnum());//发布预习最高次数
            r.setGuideprerate(c.getNumrate());//发布预习次数同比
            r.setGuiderank(c.getRank());//发布预习次数排名
            r.setPrerate(c.getTjprerate());//预习率同比
            r.setGuideavgrate(c.getPjtjrate());//平均预习率
            list1.add(r);
            return list1;
        }
    }

    public List<TReportClassRoom> listKt(TReportClasstype type) {
        Integer reporttype = type.getReporttype();
        if (reporttype <= 2) {
            return classReportMapper.listKt(type)
                    .stream().sorted(Comparator.comparing(TReportClassRoom::getCreportid)).collect(Collectors.toList());
        } else {
            //课堂
            List<ReportClasstypeVo> list = classReportMapper.listClassroom(type);
            type.setReporttype(reporttype - 2);
            setTypeDate(type);
            List<TReportClassRoom> list1 = saveClassroom(type, list, true);
            Map<Integer, List<ReportClasstypeVo>> collect = list.stream().collect(Collectors.groupingBy(m -> m.getClassid()));
            TReportClassRoom r = new TReportClassRoom();
            Integer classnum = collect.size();//班级数量
            type.setModule("classroom");
            CGradeSubjectVo c = getcGradeSubjectVo(type, collect);//计算同比等数据
            r.setClassnum(classnum);
            r.setRoomnum(c.getFbnum());
            r.setRoommaxnum(c.getMaxnum());
            r.setPrerate(c.getNumrate());
            r.setRoomrank(c.getRank());
            r.setCqavgrate(c.getPjtjrate());
            r.setCqprerate(c.getTjprerate());
            list1.add(r);
            return list1;
        }
    }

    public List<TReportClassPaper> listZy(TReportClasstype type) {
        Integer reporttype = type.getReporttype();
        if (reporttype <= 2) {
            return classReportMapper.listZy(type)
                    .stream().sorted(Comparator.comparing(TReportClassPaper::getCreportid)).collect(Collectors.toList());
        } else {
            //作业
            List<ReportClasstypeVo> list = classReportMapper.listPaper(type);
            type.setReporttype(reporttype - 2);
            setTypeDate(type);
            List<TReportClassPaper> list1 = savePaper(type, list, true);
            Map<Integer, List<ReportClasstypeVo>> collect = list.stream().collect(Collectors.groupingBy(m -> m.getClassid()));
            TReportClassPaper r = new TReportClassPaper();
            Integer classnum = collect.size();//班级数量
            type.setModule("paper");
            CGradeSubjectVo c = getcGradeSubjectVo(type, collect);//计算同比等数据
            r.setClassnum(classnum);
            r.setPapernum(c.getFbnum());
            r.setMaxnum(c.getMaxnum());
            r.setPrenumrate(c.getNumrate());
            r.setPaperrank(c.getRank());
            r.setCommitavgrate(c.getPjtjrate());
            r.setCommitprerate(c.getTjprerate());
            r.setCheckavgrate(c.getPjpgrate());
            r.setCheckprerate(c.getPgprerate());
            r.setCorrectavgrate(c.getPjzqrate());
            r.setCorrectprerate(c.getZqprerate());
            list1.add(r);
            return list1;
        }
    }

    public List<TReportClassRecite> listBs(TReportClasstype type) {
        Integer reporttype = type.getReporttype();
        if (reporttype <= 2) {
            return classReportMapper.listBs(type)
                    .stream().sorted(Comparator.comparing(TReportClassRecite::getCreportid)).collect(Collectors.toList());
        } else {
            //背诵
            List<ReportClasstypeVo> list = classReportMapper.listRecite(type);
            type.setReporttype(reporttype - 2);
            setTypeDate(type);
            List<TReportClassRecite> list1 = saveRecite(type, list, true);
            Map<Integer, List<ReportClasstypeVo>> collect = list.stream().collect(Collectors.groupingBy(m -> m.getClassid()));
            TReportClassRecite r = new TReportClassRecite();
            Integer classnum = collect.size();//班级数量
            type.setModule("recite");
            CGradeSubjectVo c = getcGradeSubjectVo(type, collect);//计算同比等数据
            r.setClassnum(classnum);
            r.setRecitenum(c.getFbnum());
            r.setRecitemaxnum(c.getMaxnum());
            r.setReciteprerate(c.getNumrate());
            r.setReciterank(c.getRank());
            r.setCommitavgrate(c.getPjtjrate());
            r.setCommitprerate(c.getTjprerate());
            r.setCorrectavgrate(c.getPjzqrate());
            r.setCorrectprerate(c.getZqprerate());
            list1.add(r);
            return list1;
        }
    }

    //计算同比等数据
    private CGradeSubjectVo getcGradeSubjectVo(TReportClasstype type, Map<Integer, List<ReportClasstypeVo>> collect) {
        String module = type.getModule();
        Integer cid = type.getClassid();
        CGradeSubjectVo c = new CGradeSubjectVo();
        Integer fbnum = 0;//次数
        Integer maxnum = 0;//最高次数
        Double prerate = 100.0;//次数同比率
        Double tjprerate = 100.0;//提交率同比
        Double pgprerate = 100.0;//批改率同比
        Double zqprerate = 100.0;//正确率同比
        Double pjtjrate = 0.0;//平均提交率
        Double pjpgrate = 0.0;//平均批改率
        Double pjzqrate = 0.0;//平均正确率
        Integer rank = 0;//次数排名
        if (collect == null || collect.size() == 0) {
            List<ReportClasstypeVo> clist = new ArrayList<>();
            collect.put(cid, clist);
        }
        List<CGradeSubjectVo> gslist = new ArrayList<>();
        List<YearOnYearVo> years = new ArrayList<>();
        if (module.equals("preview")) {
            years = classReportMapper.getPreviewNum(type);
        } else if (module.equals("paper")) {
            years = classReportMapper.getPaperNum(type);
        } else if (module.equals("recite")) {
            years = classReportMapper.getReciteNum(type);
        } else if (module.equals("classroom")) {
            years = classReportMapper.getClassroomNum(type);
        } else if (module.equals("live")) {
            years = classReportMapper.getLiveNum(type);
        } else if (module.equals("errQuestion")) {
            years = classReportMapper.getErrQuestionNum(type);
        } else if (module.equals("errQuestionFd")) {
            years = classReportMapper.getErrQuestionFdNum(type);
        }
        for (Map.Entry<Integer, List<ReportClasstypeVo>> entry : collect.entrySet()) {
            List<ReportClasstypeVo> list2 = entry.getValue();
            Integer num = 0;
            if (module.equals("errQuestion")) {
                num = list2.size();
            } else {
                num = list2.stream().mapToInt(ReportClasstypeVo::getFbnum).sum();
            }
            Integer classid = entry.getKey();
            CGradeSubjectVo gs = new CGradeSubjectVo();
            gs.setClassid(classid);
            gs.setFbnum(num);

            Double commitrate = 0.0;//提交率
            Double checkrate = 0.0;//批改率
            gslist.add(gs);
            if (cid.equals(classid)) {
                if (module.equals("preview") || module.equals("classroom") || module.equals("paper") || module.equals("recite")) {//预习、课堂、作业、背诵
                    int xsnum = list2.stream().mapToInt(ReportClasstypeVo::getXsnum).sum();
                    int tjnum = list2.stream().mapToInt(ReportClasstypeVo::getTjnum).sum();
                    pjtjrate = N_Utils.formatDouble(list2.stream().mapToDouble(ReportClasstypeVo::getNumrate).summaryStatistics().getAverage(), 2);
                    commitrate = N_Utils.getIntegerDivideAndMulitiply(tjnum, xsnum);

                    if (module.equals("paper")) {//作业
                        int pgnum = list2.stream().mapToInt(ReportClasstypeVo::getPgnum).sum();
                        checkrate = N_Utils.getIntegerDivideAndMulitiply(pgnum, tjnum);
                        pjpgrate = N_Utils.formatDouble(list2.stream().mapToDouble(ReportClasstypeVo::getPgrate).summaryStatistics().getAverage(), 2);
                    }
                } else if (module.equals("live")) {//直播
                    pjtjrate = N_Utils.formatDouble(list2.stream().mapToDouble(ReportClasstypeVo::getMinutenum).summaryStatistics().getAverage(), 2);
                }

                Double correctrate = 0.0;//正确率
                if (module.equals("paper") || module.equals("recite")) {//作业、背诵
                    Double pscore = list2.stream().mapToDouble(ReportClasstypeVo::getPscore).sum();
                    Double uscore = list2.stream().mapToDouble(ReportClasstypeVo::getUscore).sum();
                    correctrate = N_Utils.getDoubleDivideAndMulitiply(uscore, pscore);
                    pjzqrate = N_Utils.formatDouble(list2.stream().mapToDouble(ReportClasstypeVo::getZqrate).summaryStatistics().getAverage(), 2);
                }
                fbnum = num;
                if (module.equals("preview")) {//预习
                    YearOnYearVo y = years.stream().filter(v -> v.getClassid().equals(type.getClassid()) && v.getSubjectid().equals(type.getSubjectid())).findFirst().orElse(null);
                    if (y != null) {
                        prerate = N_Utils.getIntegerDivideAndMulitiply(fbnum - y.getFbnum(), fbnum);
                        tjprerate = N_Utils.formatDouble(commitrate - y.getTjrate(), 2);
                    }
                } else if (module.equals("paper")) {//作业
                    YearOnYearVo y = years.stream().filter(v -> v.getClassid().equals(type.getClassid()) && v.getSubjectid().equals(type.getSubjectid())).findFirst().orElse(null);
                    if (y != null) {
                        prerate = N_Utils.getIntegerDivideAndMulitiply(fbnum - y.getFbnum(), fbnum);
                        tjprerate = N_Utils.formatDouble(commitrate - y.getTjrate(), 2);
                        pgprerate = N_Utils.formatDouble(checkrate - y.getPgrate(), 2);
                        zqprerate = N_Utils.formatDouble(correctrate - y.getZqrate(), 2);
                    }
                }
                if (module.equals("recite")) {//背诵
                    YearOnYearVo y = years.stream().filter(v -> v.getClassid().equals(type.getClassid()) && v.getSubjectid().equals(type.getSubjectid())).findFirst().orElse(null);
                    if (y != null) {
                        prerate = N_Utils.getIntegerDivideAndMulitiply(fbnum - y.getFbnum(), fbnum);
                        tjprerate = N_Utils.formatDouble(commitrate - y.getTjrate(), 2);
                        zqprerate = N_Utils.formatDouble(correctrate - y.getZqrate(), 2);
                    }
                }
                if (module.equals("classroom")) {//课堂
                    YearOnYearVo y = years.stream().filter(v -> v.getClassid().equals(type.getClassid()) && v.getSubjectid().equals(type.getSubjectid())).findFirst().orElse(null);
                    if (y != null) {
                        prerate = N_Utils.getIntegerDivideAndMulitiply(fbnum - y.getFbnum(), fbnum);
                        tjprerate = N_Utils.formatDouble(commitrate - y.getTjrate(), 2);
                    }
                }
                if (module.equals("live")) {//直播
                    YearOnYearVo y = years.stream().filter(v -> v.getClassid().equals(type.getClassid()) && v.getSubjectid().equals(type.getSubjectid())).findFirst().orElse(null);
                    if (y != null) {
                        prerate = N_Utils.getIntegerDivideAndMulitiply(fbnum - y.getFbnum(), fbnum);
                        int tjnum = list2.stream().mapToInt(ReportClasstypeVo::getMinutenum).sum();
                        tjprerate = N_Utils.getIntegerDivideAndMulitiply(tjnum - y.getTjnum(), tjnum);//时长同比
                    }
                }
                if (module.equals("errQuestion")) {//错题
                    YearOnYearVo y = years.stream().filter(v -> v.getClassid().equals(type.getClassid()) && v.getSubjectid().equals(type.getSubjectid())).findFirst().orElse(null);
                    if (y != null) {
                        prerate = N_Utils.getIntegerDivideAndMulitiply(fbnum - y.getFbnum(), fbnum);
                    }
                }
                if (module.equals("errQuestionFd")) {//错题辅导
                    pjtjrate = N_Utils.formatDouble(list2.stream().mapToDouble(ReportClasstypeVo::getFbnum).summaryStatistics().getAverage(), 2);
                    YearOnYearVo y = years.stream().filter(v -> v.getClassid().equals(type.getClassid()) && v.getSubjectid().equals(type.getSubjectid())).findFirst().orElse(null);
                    if (y != null) {
                        prerate = N_Utils.getIntegerDivideAndMulitiply(fbnum - y.getFbnum(), fbnum);
                    }
                }
            }
        }

        c.setFbnum(fbnum);
        maxnum = gslist.stream().max(Comparator.comparing(CGradeSubjectVo::getFbnum)).get().getFbnum();
        c.setMaxnum(maxnum);
        c.setNumrate(prerate);
        c.setTjprerate(tjprerate);
        c.setPgprerate(pgprerate);
        c.setZqprerate(zqprerate);
        c.setPjtjrate(pjtjrate);
        c.setPjpgrate(pjpgrate);
        c.setPjzqrate(pjzqrate);

        if (maxnum != 0) {
            Map<Integer, Integer> fbrank = new HashMap<>();//年级科目下发布次数排名
            //发布次数排名
            gslist = gslist.stream().sorted((s1, s2) -> -Long.compare(s1.getFbnum(), s2.getFbnum())).collect(Collectors.toList());
            List<Map.Entry<Integer, List<CGradeSubjectVo>>> gslist2 = gslist.stream()
                    .collect(Collectors.groupingBy(CGradeSubjectVo::getFbnum)).entrySet()
                    .stream().sorted((s1, s2) -> -Long.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            Integer index = 1;
            for (Map.Entry<Integer, List<CGradeSubjectVo>> entry : gslist2) {
                for (CGradeSubjectVo cgs : entry.getValue()) {
                    fbrank.put(cgs.getClassid(), index);
                }
                index = index + entry.getValue().size();
            }
            rank = fbrank.get(cid);
        }
        c.setRank(rank);

        return c;
    }

    public List<TReportClassErrorquefd> listFd(TReportClasstype type) {
        Integer reporttype = type.getReporttype();
        if (reporttype <= 2) {
            return classReportMapper.listFd(type)
                    .stream().sorted(Comparator.comparing(TReportClassErrorquefd::getCreportid)).collect(Collectors.toList());
        } else {
            //错题辅导
            List<ReportClasstypeVo> list = classReportMapper.listErrQuestionFd(type);
            type.setReporttype(reporttype - 2);
            setTypeDate(type);
            List<TReportClassErrorquefd> list1 = saveErrQuestionFd(type, list, true);
            Map<Integer, List<ReportClasstypeVo>> collect = list.stream().collect(Collectors.groupingBy(m -> m.getClassid()));
            TReportClassErrorquefd r = new TReportClassErrorquefd();
            Integer classnum = collect.size();//班级数量
            type.setModule("errQuestionFd");
            CGradeSubjectVo c = getcGradeSubjectVo(type, collect);//计算同比等数据
            r.setClassnum(classnum);
            r.setFdnum(c.getFbnum());
            r.setFdmaxnum(c.getMaxnum());
            r.setPrerate(c.getNumrate());
            r.setFdrank(c.getRank());
            r.setFdavgnum(c.getPjtjrate());
            list1.add(r);
            return list1;
        }
    }

    public List<TReportClassErrorque> listCt(TReportClasstype type) {
        Integer reporttype = type.getReporttype();
        if (reporttype <= 2) {
            return classReportMapper.listCt(type)
                    .stream().sorted(Comparator.comparing(TReportClassErrorque::getCreportid)).collect(Collectors.toList());
        } else {
            //错题
            List<ReportClasstypeVo> list = classReportMapper.listErrQuestion(type);
            type.setReporttype(reporttype - 2);
            setTypeDate(type);
            List<TReportClassErrorque> list1 = saveErrQuestion(type, list, true);
            Map<Integer, List<ReportClasstypeVo>> collect = list.stream().collect(Collectors.groupingBy(m -> m.getClassid()));
            TReportClassErrorque r = new TReportClassErrorque();
            Integer classnum = collect.size();//班级数量
            type.setModule("errQuestion");
            CGradeSubjectVo c = getcGradeSubjectVo(type, collect);//计算同比等数据
            r.setClassnum(classnum);
            r.setCeqnum(c.getFbnum());
            r.setCeqmaxnum(c.getMaxnum());
            r.setPrerate(c.getNumrate());
            r.setCeqrank(c.getRank());
            list1.add(r);
            return list1;
        }
    }

    public List<TReportClassLive> listZb(TReportClasstype type) {
        Integer reporttype = type.getReporttype();
        if (reporttype <= 2) {
            return classReportMapper.listZb(type)
                    .stream().sorted(Comparator.comparing(TReportClassLive::getCreportid)).collect(Collectors.toList());
        } else {
            //直播
            List<ReportClasstypeVo> list = classReportMapper.listLive(type);
            type.setReporttype(reporttype - 2);
            setTypeDate(type);
            List<TReportClassLive> list1 = saveLive(type, list, true);
            Map<Integer, List<ReportClasstypeVo>> collect = list.stream().collect(Collectors.groupingBy(m -> m.getClassid()));
            TReportClassLive r = new TReportClassLive();
            Integer classnum = collect.size();//班级数量
            type.setModule("live");
            CGradeSubjectVo c = getcGradeSubjectVo(type, collect);//计算同比等数据
            r.setClassnum(classnum);
            r.setLivenum(c.getFbnum());
            r.setLivemaxnum(c.getMaxnum());
            r.setLiveprerate(c.getNumrate());
            r.setLiverank(c.getRank());
            r.setMinuteave(c.getPjtjrate());
            r.setMinutepre(c.getTjprerate());
            list1.add(r);
            return list1;
        }
    }

    /**
     * 知识点掌握统计
     *
     * @param [type]
     * @return java.util.List<com.xhkjedu.sapi.model.classreport.TReportClassPoint>
     * @author ywx
     * @date 2022/4/22 14:05
     */
    public List<TReportClassPoint> listZsd(TReportClasstype type) {
        Integer reporttype = type.getReporttype();
        if (reporttype <= 2) {
            return classReportMapper.listZsd(type)
                    .stream().sorted(Comparator.comparing(TReportClassPoint::getCreportid)).collect(Collectors.toList());
        } else {
            //知识点
            List<ReportClasstypeVo> list = classReportMapper.listPoint(type);
            type.setReporttype(reporttype - 2);
            setTypeDate(type);
            return savePoint(type, list, true);
        }
    }

    public List<TReportClassPoint> savePoint(TReportClasstype type, List<ReportClasstypeVo> list, boolean now) {
        List<TReportClassPoint> list1 = new ArrayList<>();
        Map<String, List<ReportClasstypeVo>> subjects = list.stream().collect(Collectors.groupingBy(m -> m.getClassid() + "_" + m.getSubjectid()
                , LinkedHashMap::new, Collectors.toList()));
        for (Map.Entry s : subjects.entrySet()) {
            List<ReportClasstypeVo> slist2 = (List<ReportClasstypeVo>) s.getValue();
            ReportClasstypeVo vo = slist2.get(0);
            List<TReportClassPoint> points = new ArrayList<>();
            try {
                for (ReportClasstypeVo p : slist2) {
                    TReportClassPoint rp = new TReportClassPoint();
                    rp.setPointid(p.getPointid());
                    rp.setPointname(p.getPointname());
                    rp.setPointrate(N_Utils.getDoubleDivideAndMulitiply(p.getUscore(), p.getPscore()));
                    rp.setCreatetime(N_Utils.getSecondTimestamp());
                    rp.setBegindate(type.getBegindate());
                    rp.setEnddate(type.getEnddate());
                    points.add(rp);
                }
                if (!now) {
                    Integer creportid = saveType(type, vo);
                    points.forEach(p -> {
                        p.setCreportid(creportid);
                    });
                    reportClassPointMapper.insertList(points);
                }
                list1.addAll(points);
            } catch (Exception e) {
                log.error("保存知识点掌握统计出错：{}", e.getMessage());
            }
        }
        return list1;
    }
}
