package com.sw.mes.yb.report.service.impl;

import com.sw.mes.base.factory.init.entity.Device;
import com.sw.mes.base.factory.init.entity.Equipment;
import com.sw.mes.base.factory.init.service.EquipmentService;
import com.sw.mes.base.factory.product.entity.ProductModel;
import com.sw.mes.base.system.entity.DictionaryItem;
import com.sw.mes.base.system.service.DictionaryItemService;
import com.sw.mes.core.utils.DateUtil;
import com.sw.mes.core.utils.StringUtils;
import com.sw.mes.enumvalue.EnumValuesServer;
import com.sw.mes.enumvalue.StepEnum;
import com.sw.mes.inspect.entity.YbInspectData;
import com.sw.mes.inspect.service.YbInspectDataService;
import com.sw.mes.redis.server.RedisUtils;
import com.sw.mes.yb.pad.entity.ProductionBackCuttingRecord;
import com.sw.mes.yb.pad.entity.ProductionPaintingLine;
import com.sw.mes.yb.pad.entity.ProductionPaintingLineDetail;
import com.sw.mes.yb.pad.service.ProductionPaintingLineDetailService;
import com.sw.mes.yb.pad.service.ProductionPaintingLineService;
import com.sw.mes.yb.pad.service.ProductionRecutService;
import com.sw.mes.yb.plan.entity.ProductionSchedule;
import com.sw.mes.yb.plan.service.ProductionScheduleService;
import com.sw.mes.yb.production.entity.*;
import com.sw.mes.yb.production.service.*;
import com.sw.mes.yb.report.dto.*;
import com.sw.mes.yb.report.service.CrystalPullingInfoLogService;
import com.sw.mes.yb.report.service.NumberOfOperationsService;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * @Author
 * @Description：
 * @Date: Create in
 * @Modified By:
 */
@Service
public class NumberOfOperationsServiceImpl implements NumberOfOperationsService {

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private EquipmentService equipmentService;

    @Autowired
    private ProcessWorkingStepService processWorkingStepService;

    @Autowired
    private DictionaryItemService dictionaryItemService;

    @Autowired
    private ProcessWorkingHoursService processWorkingHoursService;

    @Autowired
    private LongCrystalService longCrystalService;

    @Autowired
    private CrystalPullingInfoLogService crystalPullingInfoLogService;

    @Autowired
    private LoadingTaskService loadingTaskService;

    @Autowired
    private BlastFurnaceDetailService blastFurnaceDetailService;

    @Autowired
    private AgainTaskService againTaskService;

    @Autowired
    private AgainTaskDetailService againTaskDetailService;

    @Autowired
    private InputFurnaceDetailService inputFurnaceDetailService;

    @Autowired
    private ProductionPaintingLineService productionPaintingLineService;

    @Autowired
    private YbInspectDataService ybInspectDataService;

    @Autowired
    private ProductionRecutService productionRecutService;

    @Autowired
    private ProductionPaintingLineDetailService productionPaintingLineDetailService;

    @Autowired
    private InputFurnaceBurdenService inputFurnaceBurdenService;

    @Autowired
    private ProductionScheduleService productionScheduleService;

    private static final String STEPNUMBER = "工序次数";
    private static final String HOURS = "工时";
    private static final String HOURSLOTNO = "工时炉台数量";
    private static final String WEIGHT = "重量";
    private static final String CURRENTSTEPNUMBER = "当前工序个数";
    private static final String STATE = "炉台状态";
    private static final String[] STEPNAME = {"回熔", "熔断", "进入引晶", "引断", "进入放肩", "放断", "吊多晶", "断提<500", "断提>1000", "断提500~1000"};
    private static final String[] STEPNAME1 = {"进入放肩", "放断", "断提<500"};
    private static final String[] CURRENTSTEPNAME = {"手动", "熔料", "复投", "熔接", "引晶", "放肩", "等径", "取段收尾"};
    private static final Long TIMEOUT = 10L;

    private static final String DISMOUNTING = "拆炉工时";
    private static final String COMPOUNDOVEN = "合炉工时";
    private static final String PUMP = "抽真空";
    private static final String RODREMOVAL = "取棒工时";
    private static final String DIADPLUS = "二加工时";
    private static final String THERMOREGULATION = "调温工时";
    private static final String PLUSMATERIAL = "加料工时";
    private static final String DRAUGHT = "引放工时";
    private static final String[] HOURLIST = {"合炉工时", "取棒工时", "调温工时", "加料工时"};
    private static final String[] LIST = {"调温工时", "放断调温工时", "等断调温工时", "拆装工时", "合炉工时", "抽空工时", "取棒工时"};
    private static final String[] TIMELONG = {"240", "180", "180", "720", "60", "60", "60", "110"};


    @Override
    public List<NumberOfOperationsDto> getNumerOfOperations(String area) {

        List<NumberOfOperationsDto> numberOfOperationsDtos = new ArrayList<>();

        //1、获取系列
        List<String> seriesList = getSeriesList(area);

        //2、获取工序次数数据
        for (String s : seriesList) {
            NumberOfOperationsDto numberOfOperationsDto = new NumberOfOperationsDto();

            //片区及运行炉台数
            Map<String, List<Equipment>> stringListMap = numberOfOperatingEquipment(1);
            numberOfOperationsDto.setSeries(s);
            if (stringListMap.containsKey(s)) {
                numberOfOperationsDto.setOperatingCount(stringListMap.get(s).size());
            } else {
                numberOfOperationsDto.setOperatingCount(0);
            }
            Class<? extends NumberOfOperationsDto> aClass = numberOfOperationsDto.getClass();
            Field[] fields = aClass.getDeclaredFields();

            for (Field field : fields) {
                ApiModelProperty property = field.getAnnotation(ApiModelProperty.class);
                String value = property.value();
                if (value != null) {
                    //按片区工步次数
                    outer:
                    for (String step : STEPNAME) {
                        if (value.equals(step)) {
                            // 匹配到注解符合要求
                            try {
                                Integer number = getEveryStepNumber(area, s, value);
                                field.setAccessible(true);
                                field.set(numberOfOperationsDto, number);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            }
                            break outer;
                        }
                    }

                    //当前工步数量
                    outer1:
                    for (String s1 : CURRENTSTEPNAME) {
                        if (value.equals(s1)) {
                            // 匹配到注解符合要求
                            try {
                                Integer number = getCurrentStepNumber(area, s, value);
                                field.setAccessible(true);
                                field.set(numberOfOperationsDto, number);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            }
                            break outer1;
                        }
                    }
                }
            }

            //断线汇总
            numberOfOperationsDto.setLineBreakSummary(Optional.ofNullable(numberOfOperationsDto.getLetOffCount()).orElse(0) + Optional.ofNullable(numberOfOperationsDto.getMektBackCount()).orElse(0) +
                    Optional.ofNullable(numberOfOperationsDto.getBreakLessThan500()).orElse(0) + Optional.ofNullable(numberOfOperationsDto.getBreakGreaterThan1000()).orElse(0) + Optional.ofNullable(numberOfOperationsDto.getBreakLess()).orElse(0)
            );

            //引断率
            if (null == numberOfOperationsDto.getCrystalCount() && numberOfOperationsDto.getBreakCount() > 0) {
                numberOfOperationsDto.setBreakRate(new BigDecimal(100));
            } else if ((numberOfOperationsDto.getCrystalCount() == 0 && numberOfOperationsDto.getBreakCount() == 0) || numberOfOperationsDto.getCrystalCount() == 0) {
                numberOfOperationsDto.setBreakRate(new BigDecimal(0));
            } else {
                numberOfOperationsDto.setBreakRate(new BigDecimal(100 * numberOfOperationsDto.getBreakCount() / numberOfOperationsDto.getCrystalCount()).setScale(3, BigDecimal.ROUND_HALF_UP));
            }
            //回熔率
            if (numberOfOperationsDto.getCrystalCount() == 0 && numberOfOperationsDto.getMektBackCount() > 0) {
                numberOfOperationsDto.setMektBackRate(new BigDecimal(100));
            } else if ((numberOfOperationsDto.getCrystalCount() == 0 && numberOfOperationsDto.getMektBackCount() == 0) || numberOfOperationsDto.getCrystalCount() == 0) {
                numberOfOperationsDto.setMektBackRate(new BigDecimal(0));
            } else {
                numberOfOperationsDto.setMektBackRate(new BigDecimal(100 * numberOfOperationsDto.getMektBackCount() / numberOfOperationsDto.getCrystalCount()).setScale(3, BigDecimal.ROUND_HALF_UP));
            }
            //片区停炉数
            Map<String, List<Equipment>> stringListMap1 = numberOfOperatingEquipment(3);
            if (stringListMap1.containsKey(s)) {
                numberOfOperationsDto.setShutdownCount(stringListMap1.get(s).size());
            } else {
                numberOfOperationsDto.setShutdownCount(0);
            }

            //引放成活率
//            if (numberOfOperationsDto.getCrystalCount() == 0 && numberOfOperationsDto.getShoulderCount() > 0) {
//                numberOfOperationsDto.setShoulderRate("100%");
//            } else if (numberOfOperationsDto.getCrystalCount() == 0 && numberOfOperationsDto.getShoulderCount() == 0) {
//                numberOfOperationsDto.setShoulderRate("0%");
//            } else {
//                numberOfOperationsDto.setShoulderRate(new BigDecimal(100 * numberOfOperationsDto.getShoulderCount() / numberOfOperationsDto.getCrystalCount()).setScale(0, BigDecimal.ROUND_HALF_UP).toString() + "%");
//            }
            if(numberOfOperationsDto.getLetOffCount() + numberOfOperationsDto.getBreakLessThan500() == 0 && numberOfOperationsDto.getShoulderCount() > 0){
                numberOfOperationsDto.setShoulderRate("100%");
            } else if (numberOfOperationsDto.getLetOffCount() + numberOfOperationsDto.getBreakLessThan500() == 0 && numberOfOperationsDto.getShoulderCount() == 0) {
                numberOfOperationsDto.setShoulderRate("0%");
            } else if (numberOfOperationsDto.getShoulderCount() == 0) {
                numberOfOperationsDto.setShoulderRate("0%");
            } else {
                numberOfOperationsDto.setShoulderRate(new BigDecimal(100).subtract(new BigDecimal(100 * (numberOfOperationsDto.getLetOffCount() + numberOfOperationsDto.getBreakLessThan500()) / numberOfOperationsDto.getShoulderCount())).setScale(0, BigDecimal.ROUND_HALF_UP).toString() + "%");
            }
            numberOfOperationsDtos.add(numberOfOperationsDto);
        }
        Collections.sort(numberOfOperationsDtos);
        return numberOfOperationsDtos;
    }

    @Override
    public NumberOfErrorDto getConstitutionalDiagram(String area) {

        NumberOfErrorDto numberOfErrorDto = new NumberOfErrorDto();

        //引断
        List<NumberOfOperations1Dto> breakList = new ArrayList<>();
        //放断
        List<NumberOfOperations1Dto> letOffList = new ArrayList<>();
        //等断
        List<NumberOfOperations1Dto> equipList = new ArrayList<>();
        //回熔
        List<NumberOfOperations1Dto> meltBackList = new ArrayList<>();
        //断线率
        List<NumberOfOperations1Dto> lineBreakRateList = new ArrayList<>();
        //断线标准
        List<NumberOfOperations1Dto> lineBreakList = new ArrayList<>();


        //1、获取系列
        List<String> seriesList = getSeriesList(area);

        //获取断线标准
        List<DictionaryItem> board = dictionaryItemService.findByThemeValueAndEnable("board", true);
        Map<String, String> collect = board.stream().collect(Collectors.toMap(DictionaryItem::getName, DictionaryItem::getValue));

        for (String s : seriesList) {

            //引断
            NumberOfOperations1Dto breakDto = new NumberOfOperations1Dto();
            Integer everyStepNumber = getEveryStepNumber(area, s, StepEnum.StepNameEnum.引断.getValue());
            breakDto.setSeries(s);
            breakDto.setCount(everyStepNumber);
            breakList.add(breakDto);

            //放断
            NumberOfOperations1Dto letOffDto = new NumberOfOperations1Dto();
            Integer everyStepNumber1 = getEveryStepNumber(area, s, StepEnum.StepNameEnum.放断.getValue());
            letOffDto.setSeries(s);
            letOffDto.setCount(everyStepNumber1);
            letOffList.add(letOffDto);

            //等断
            NumberOfOperations1Dto equipDto = new NumberOfOperations1Dto();
            Integer equip1 = getEveryStepNumber(area, s, StepEnum.StepNameEnum.断提500.getValue());
            Integer equip2 = getEveryStepNumber(area, s, StepEnum.StepNameEnum.断提1000.getValue());
            Integer equip3 = getEveryStepNumber(area, s, StepEnum.StepNameEnum.断提5001000.getValue());
            equipDto.setSeries(s);
            equipDto.setCount(equip1 + equip2 + equip3);
            equipList.add(equipDto);

            //回熔
            NumberOfOperations1Dto meltBackDto = new NumberOfOperations1Dto();
            Integer everyStepNumber3 = getEveryStepNumber(area, s, StepEnum.StepNameEnum.回熔.getValue());
            meltBackDto.setSeries(s);
            meltBackDto.setCount(everyStepNumber3);
            meltBackList.add(meltBackDto);

            //断线率
            NumberOfOperations1Dto lineBreakRateDto = new NumberOfOperations1Dto();
            BigDecimal num = new BigDecimal(getEveryStepNumber(area, s, StepEnum.StepNameEnum.进入放肩.getValue()));
            lineBreakRateDto.setSeries(s);
            BigDecimal bigDecimal = new BigDecimal(100 * (equip1 + equip2 + equip3 + everyStepNumber1));
            if (num.compareTo(new BigDecimal(0)) > 0) {
                lineBreakRateDto.setCount1(bigDecimal.divide(num, 3, BigDecimal.ROUND_HALF_UP));
            } else if (bigDecimal.compareTo(new BigDecimal(0)) > 0 && num.compareTo(new BigDecimal(0)) > 0) {
                lineBreakRateDto.setCount1(new BigDecimal(100));
            } else {
                lineBreakRateDto.setCount1(new BigDecimal(0));
            }

            lineBreakRateList.add(lineBreakRateDto);

            //断线标准
            NumberOfOperations1Dto lineBreakDto = new NumberOfOperations1Dto();
            lineBreakDto.setSeries(s);
            if (collect.containsKey(s)) {
                lineBreakDto.setCount1(new BigDecimal(collect.get(s)).divide(new BigDecimal(0.01), 0, BigDecimal.ROUND_HALF_UP));
            } else {
                lineBreakDto.setCount1(new BigDecimal(0));
            }
            lineBreakList.add(lineBreakDto);
        }

        numberOfErrorDto.setBreakCount(sortList(breakList));
        numberOfErrorDto.setEquipCount(sortList(equipList));
        numberOfErrorDto.setLetOffCount(sortList(letOffList));
        numberOfErrorDto.setMeltBackCount(sortList(meltBackList));
        numberOfErrorDto.setLineBreakRate(sortList(lineBreakRateList));
        numberOfErrorDto.setLineBreakStandard(sortList(lineBreakList));

        return numberOfErrorDto;
    }

    @Override
    public WorkHourDto getConstitutionalDiagram1(String area) throws Exception {


        //1、获取系列
        List<String> seriesList = getSeriesList(area);
        WorkHourDto workHourDto = new WorkHourDto();

        //拆炉工时
        List<NumberOfOperations1Dto> dismountingList = new ArrayList<>();
        //合炉工时
        List<NumberOfOperations1Dto> compoundOvenList = new ArrayList<>();
        //抽空工时
        List<NumberOfOperations1Dto> pumpList = new ArrayList<>();
        //取棒工时
        List<NumberOfOperations1Dto> rodRemovalList = new ArrayList<>();
        //二加工时
        List<NumberOfOperations1Dto> diadplusList = new ArrayList<>();
        //调温工时
        List<NumberOfOperations1Dto> thermORegulationList = new ArrayList<>();

        for (String s : seriesList) {

            Class<? extends WorkHourDto> aClass = workHourDto.getClass();
            Field[] fields = aClass.getDeclaredFields();
            for (Field field : fields) {
                NumberOfOperations1Dto numberOfOperations1Dto = new NumberOfOperations1Dto();
                ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
                String value = annotation.value();
                BigDecimal workHours = getWorkHours(s, value);
                numberOfOperations1Dto.setSeries(s);
                numberOfOperations1Dto.setCount1(workHours);
                switch (value) {
                    case DISMOUNTING:
                        dismountingList.add(numberOfOperations1Dto);
                        continue;
                    case COMPOUNDOVEN:
                        compoundOvenList.add(numberOfOperations1Dto);
                        continue;
                    case PUMP:
                        pumpList.add(numberOfOperations1Dto);
                        continue;
                    case RODREMOVAL:
                        rodRemovalList.add(numberOfOperations1Dto);
                        continue;
                    case DIADPLUS:
                        diadplusList.add(numberOfOperations1Dto);
                        continue;
                    case THERMOREGULATION:
                        thermORegulationList.add(numberOfOperations1Dto);
                        continue;
                    default:
                        throw new Exception("工时名称不匹配");
                }
            }
        }

        workHourDto.setDismounting(sortList(dismountingList));
        workHourDto.setCompoundOven(sortList(compoundOvenList));
        workHourDto.setPump(sortList(pumpList));
        workHourDto.setRodRemoval(sortList(rodRemovalList));
        workHourDto.setDiadplus(sortList(diadplusList));
        workHourDto.setThermORegulation(sortList(thermORegulationList));
        return workHourDto;
    }

    @Override
    public PerProductDto getConstitutionalDiagram2(String area) {

        //获取计划单产
        List<DictionaryItem> board = dictionaryItemService.findByThemeValueAndEnable("board", true);
        Map<String, String> collect = board.stream().collect(Collectors.toMap(DictionaryItem::getName, DictionaryItem::getExtendValue1));

        //计划单产
        List<NumberOfOperations1Dto> planList = new ArrayList<>();
        //实际单产
        List<NumberOfOperations1Dto> actualList = new ArrayList<>();

        PerProductDto perProductDto = new PerProductDto();
        List<LongCrystal> longCrystals = longCrystalService.findByGmtCreate(DateUtil.formatDate1(DateUtil.getCurrentMonthStartTime1()), getCurrentDayStartTime());
        Map<String, List<LongCrystal>> collect1 = longCrystals.stream().collect(Collectors.groupingBy(LongCrystal::getSeries));

        //1、获取系列
        List<String> seriesList = getSeriesList(area);
        for (String s : seriesList) {

            //计划单产
            NumberOfOperations1Dto numberOfOperation1Dto = getNumberOfOperation1Dto(collect, s);
            planList.add(numberOfOperation1Dto);

            //实际单产
            NumberOfOperations1Dto numberOfOperations1Dto1 = new NumberOfOperations1Dto();
            List<LongCrystal> longCrystalList = collect1.get(s);
            BigDecimal totalWeight = new BigDecimal(0);
            if (null != longCrystalList && longCrystalList.size() > 0) {
                totalWeight = longCrystalList.stream().map(LongCrystal::getWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
            }
            numberOfOperations1Dto1.setSeries(s);
            numberOfOperations1Dto1.setCount1(totalWeight.divide(new BigDecimal(40), 3, BigDecimal.ROUND_HALF_UP).divide(new BigDecimal(DateUtil.getTheDayOfTheMonth()), 2, BigDecimal.ROUND_HALF_UP));

            actualList.add(numberOfOperations1Dto1);
        }

        perProductDto.setPlan(sortList(planList));
        perProductDto.setActual(sortList(actualList));
        return perProductDto;
    }

    @Override
    public PerProductDto getConstitutionalDiagram3(String area) {

        PerProductDto perProductDto = new PerProductDto();

        //获取异常炉台配置
        List<DictionaryItem> board = dictionaryItemService.findByThemeValueAndEnable("board", true);
        Map<String, String> collect = board.stream().collect(Collectors.toMap(DictionaryItem::getName, DictionaryItem::getExtendValue));

        //1、获取系列
        List<String> seriesList = getSeriesList(area);
        //计划异常
        List<NumberOfOperations1Dto> planList = new ArrayList<>();
        //实际异常
        List<NumberOfOperations1Dto> actualList = new ArrayList<>();

        for (String s : seriesList) {
            NumberOfOperations1Dto numberOfOperation1Dto = getNumberOfOperation1Dto(collect, s);
            planList.add(numberOfOperation1Dto);

            List<ProcessWorkingHours> processWorkingHoursList = processWorkingHoursService.getBySeriesAndStepNameAndStartTime(s, StepEnum.StepNameEnum.熔径工时.getValue(), getCurrentDayStartTime(), getCurrentDayEndTime());
            int size = 0;
            if(null != processWorkingHoursList){
                for (ProcessWorkingHours processWorkingHours : processWorkingHoursList) {
                    Long timeLong = processWorkingHours.getTimeLong();
                    if(null != timeLong && timeLong/1000/60/60 > 8){
                        size++;
                    }
                }
            }
            NumberOfOperations1Dto numberOfOperations1Dto = new NumberOfOperations1Dto();
            numberOfOperations1Dto.setSeries(s);
            numberOfOperations1Dto.setCount(size);
            actualList.add(numberOfOperations1Dto);
        }
        perProductDto.setPlan(sortList(planList));
        perProductDto.setActual(sortList(actualList));

        return perProductDto;
    }

    @Override
    public BigDecimal getYield(String area, String type) {

        /**
         * 月看完结的单晶
         * 日看当日产出的单晶
         */
        //总重量
        BigDecimal totalWeight = getCurrentMonthWeight(area, type);
        if(null == totalWeight){
            totalWeight = new BigDecimal(0);
        }
        //总运行时间
        BigDecimal totalRunTime = getTotalRunTime(area, type);
        if (type.equals("月")) {
            if (totalRunTime.compareTo(new BigDecimal(0)) > 0) {
                return totalWeight.divide(totalRunTime.divide(new BigDecimal(24), 3, BigDecimal.ROUND_HALF_UP), 2, BigDecimal.ROUND_HALF_UP);
            }
        }
        return totalWeight.divide(new BigDecimal(720), 2, BigDecimal.ROUND_HALF_UP);
    }

    @Override
    public PerProductDto getYieldChart(String area) {

        PerProductDto perProductDto = new PerProductDto();

        //1、获取系列
        List<String> seriesList = getSeriesList(area);

        //2、获取计划产量
        List<DictionaryItem> board = dictionaryItemService.findByThemeValueAndEnable("board", true);
        Map<String, String> collect = board.stream().collect(Collectors.toMap(DictionaryItem::getName, DictionaryItem::getExtendValue2));

        //计划产量
        List<NumberOfOperations1Dto> planList = new ArrayList<>();
        //实时产量
        List<NumberOfOperations1Dto> actualList = new ArrayList<>();
        //成晶率
        List<NumberOfOperations1Dto> rateList = new ArrayList<>();

        List<DictionaryItem> itemList = dictionaryItemService.findItemByThemeValue("WeightRatio", true);
        Map<String, String> weightRatio = itemList.stream().collect(Collectors.toMap(DictionaryItem::getName, DictionaryItem::getValue));

        for (String s : seriesList) {

            //计划
            NumberOfOperations1Dto planDto = new NumberOfOperations1Dto();
            planDto.setSeries(s);
            if(!collect.containsKey(s)){
                continue;
            }
            planDto.setCount1(new BigDecimal(collect.get(s)));
            planList.add(planDto);

            //实时  看当日产出
            NumberOfOperations1Dto actualDto = new NumberOfOperations1Dto();
            BigDecimal currentDayWeight = getCurrentDayWeight(s);
            actualDto.setSeries(s);
            actualDto.setCount1(currentDayWeight.divide(new BigDecimal(40), 2, BigDecimal.ROUND_HALF_UP));
            actualList.add(actualDto);

            //成晶率  看当日完结的单晶
            NumberOfOperations1Dto crystalDto = new NumberOfOperations1Dto();
            //1、查询当日完结的炉次
            BigDecimal materialWeight = new BigDecimal(0);
            BigDecimal crystalWeight = new BigDecimal(0);
            List<String> lotNoList = longCrystalService.findByGmtCreate1(getCurrentDayStartTime(), getCurrentDayEndTime(), area, s);
            List<LongCrystal> longCrystals = longCrystalService.findByGmtCreate2(lotNoList, area, s);
            //2、查询投料总重量
            materialWeight = getTotalWeight(lotNoList, materialWeight);
            //3、查询成晶总重量
            crystalWeight = getCrystalWeight(longCrystals, weightRatio, crystalWeight);
            //4、成晶率计算
            if(materialWeight.compareTo(new BigDecimal(0)) > 0){
                BigDecimal divide = crystalWeight.divide(materialWeight, 3, BigDecimal.ROUND_HALF_UP);
                crystalDto.setCount1(divide.multiply(new BigDecimal(100)));
            } else {
                crystalDto.setCount1(new BigDecimal(0));
            }
            crystalDto.setSeries(s);
            rateList.add(crystalDto);
        }

        perProductDto.setPlan(sortList(planList));
        perProductDto.setActual(sortList(actualList));
        perProductDto.setRate(sortList(rateList));

        return perProductDto;
    }

    @Override
    public List<HourListDto> getHourList(String area) throws IllegalAccessException {

        //todo 取平均值
        List<HourListDto> list = new ArrayList<>();

        //1、获取系列
        List<String> seriesList = getSeriesList(area);
        for (String s : seriesList) {
            HourListDto hourListDto = new HourListDto();
            BigDecimal totalWeight = new BigDecimal(0);

            hourListDto.setSeries(s);

            Class<? extends HourListDto> aClass = hourListDto.getClass();
            Field[] fields = aClass.getDeclaredFields();
            for (Field field : fields) {
                ApiModelProperty property = field.getAnnotation(ApiModelProperty.class);
                String value = property.value();
                //按片区工步次数
                BigDecimal workHours = getWorkHours(s, value);
                //todo 这里要不要加
                int lotNos = getLotNos(s, value);
                field.setAccessible(true);
                for (String s1 : HOURLIST) {
                    if(s1.equals(value) && lotNos > 0){
                        field.set(hourListDto, workHours.divide(new BigDecimal(lotNos),1,BigDecimal.ROUND_HALF_UP));
                    } else if (s1.equals(value) && lotNos == 0){
                        field.set(hourListDto, new BigDecimal(0));
                    }
                }
            }
            //引放成活率
//            Integer number = getEveryStepNumber(area, s, STEPNAME[2]);
//            Integer number1 = getEveryStepNumber(area, s, STEPNAME[4]);
//            if (number == 0 && number1 > 0) {
//                hourListDto.setShoulderRate(new BigDecimal(100));
//            } else if (number == 0 && number1 == 0) {
//                hourListDto.setShoulderRate(new BigDecimal(0));
//            } else {
//                hourListDto.setShoulderRate(new BigDecimal(100 * number1 / number).setScale(3, BigDecimal.ROUND_HALF_UP));
//            }

            NumberOfOperationsDto numberOfOperationsDto = new NumberOfOperationsDto();
            Class<? extends NumberOfOperationsDto> numberOfOperationsDtoClass = numberOfOperationsDto.getClass();
            Field[] allField = numberOfOperationsDtoClass.getDeclaredFields();
            for (Field field : allField) {
                ApiModelProperty property = field.getAnnotation(ApiModelProperty.class);
                String value = property.value();
                if (value != null) {
                    //按片区工步次数
                    for (String step : STEPNAME1) {
                        if (value.equals(step)) {
                            // 匹配到注解符合要求
                            try {
                                Integer number2 = getEveryStepNumber(area, s, value);
                                field.setAccessible(true);
                                field.set(numberOfOperationsDto, number2);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }

            if(numberOfOperationsDto.getLetOffCount() + numberOfOperationsDto.getBreakLessThan500() == 0 && numberOfOperationsDto.getShoulderCount() > 0){
                hourListDto.setShoulderRate(new BigDecimal(100));
            } else if (numberOfOperationsDto.getLetOffCount() + numberOfOperationsDto.getBreakLessThan500() == 0 && numberOfOperationsDto.getShoulderCount() == 0) {
                hourListDto.setShoulderRate(new BigDecimal(0));
            } else if (numberOfOperationsDto.getShoulderCount() == 0) {
                hourListDto.setShoulderRate(new BigDecimal(0));
            } else {
                hourListDto.setShoulderRate(new BigDecimal(100).subtract(new BigDecimal(100 * (numberOfOperationsDto.getLetOffCount() + numberOfOperationsDto.getBreakLessThan500()) / numberOfOperationsDto.getShoulderCount())).setScale(0, BigDecimal.ROUND_HALF_UP));
            }
            //二加效率
            //当日加料工时
            BigDecimal workHours = getWorkHours(s, PLUSMATERIAL);
            //当日投料总量
            totalWeight = getTotalWeight(s, totalWeight);
            if(workHours.compareTo(new BigDecimal(0)) > 0){
                hourListDto.setDiadplusRate(new BigDecimal(100).multiply(totalWeight).divide(workHours, 2, BigDecimal.ROUND_HALF_UP));
            } else {
                hourListDto.setDiadplusRate(new BigDecimal(100));
            }
            //排名
            BigDecimal rank = new BigDecimal(2).subtract(hourListDto.getCompoundOven()).multiply(new BigDecimal(10)).add(new BigDecimal(6).subtract(hourListDto.getChargeHour()).multiply(new BigDecimal(40))).add(
                    new BigDecimal(1.5).subtract(hourListDto.getRodRemoval()).multiply(new BigDecimal(30))).add(new BigDecimal(4).subtract(hourListDto.getThermORegulation()).multiply(new BigDecimal(40))).add(
                    hourListDto.getShoulderRate().subtract(new BigDecimal(0.8)).multiply(new BigDecimal(100))).add(hourListDto.getDiadplusRate().subtract(new BigDecimal(100)).multiply(new BigDecimal(5)));
            hourListDto.setRank(rank.setScale(0, BigDecimal.ROUND_HALF_UP));
            list.add(hourListDto);
        }

        //排序
        list.sort(Comparator.comparing(HourListDto::getRank).reversed());
        for (int i = 0; i < list.size(); i++) {
            list.get(i).setRank(new BigDecimal(i + 1));
        }
        return list;
    }

    @Override
    public List<ErrorDeviceDto> getErrorDevice(String area) {


        List<ErrorDeviceDto> errorDeviceDtoList = new ArrayList<>();

        PerProductDto perProductDto = getConstitutionalDiagram3(area);
        List<NumberOfOperations1Dto> actual = perProductDto.getActual();
        Map<String, Integer> collect = actual.stream().collect(Collectors.toMap(NumberOfOperations1Dto::getSeries, NumberOfOperations1Dto::getCount));


        //1、获取系列
        List<String> seriesList = getSeriesList(area);
        for (String s : seriesList) {
            ErrorDeviceDto errorDeviceDto = new ErrorDeviceDto();
            TreeSet<String> deviceSet = new TreeSet();
            List<ProcessWorkingHours> processWorkingHoursList = processWorkingHoursService.getBySeriesAndStepNameAndStartTime(s, StepEnum.StepNameEnum.熔径工时.getValue(), getCurrentDayStartTime(), getCurrentDayEndTime());
            if(null != processWorkingHoursList){
                for (ProcessWorkingHours processWorkingHours : processWorkingHoursList) {
                    if(null != processWorkingHours.getTimeLong() && processWorkingHours.getTimeLong()/1000/60/60 > 8){
                        deviceSet.add(processWorkingHours.getEquipmentCode());
                    }
                }
            }
            errorDeviceDto.setSeries(s);
            if (collect.containsKey(s)) {
                errorDeviceDto.setErrorNumber(collect.get(s));
            } else {
                errorDeviceDto.setErrorNumber(0);
            }
            errorDeviceDto.setErrorDeviceList(deviceSet);
            errorDeviceDtoList.add(errorDeviceDto);
        }
        return errorDeviceDtoList;
    }

    @Override
    public List<ErrorListDto> getErrorList(String area) {

        List<ErrorListDto> errorList = new ArrayList<>();

        //设备当前工步状态
        List<Equipment> equipmentList1 = equipmentService.getEveryStepNumber(area, getCurrentDayStartTime(), getCurrentDayEndTime());
//        Map<String, Map<String, List<Equipment>>> step = equipmentList1.stream().collect(Collectors.groupingBy(Equipment::getDevice, Collectors.groupingBy(Equipment::getCurrentStep)));
        Map<String, List<Equipment>> collect10 = equipmentList1.stream().collect(Collectors.groupingBy(Equipment::getCode));

        //当前排程
        List<ProductionSchedule> current_productionSchedule = productionScheduleService.findByStatus1(1);
        Map<String, ProductModel> collect1 = current_productionSchedule.stream().collect(Collectors.toMap(ProductionSchedule::getDeviceNo, ProductionSchedule::getProductModel));

        //工时异常
        List<ProcessWorkingHours> processWorkingHoursList = processWorkingHoursService.getByStartTime(getCurrentDayStartTime(), getCurrentDayEndTime());
        Map<String, List<ProcessWorkingHours>> collect = processWorkingHoursList.stream().collect(Collectors.groupingBy(ProcessWorkingHours::getStepName));

        String currentDayStartTime = getCurrentDayStartTime();
        String substring = currentDayStartTime.substring(0, 10);
        for (int i = 0; i < LIST.length; i++) {

            if (collect.containsKey(LIST[i])) {
                List<ProcessWorkingHours> processWorkingHoursList1 = collect.get(LIST[i]);
                if (null != processWorkingHoursList1 && processWorkingHoursList1.size() > 0) {
                    for (ProcessWorkingHours processWorkingHours : processWorkingHoursList1) {
                        if(null != processWorkingHours.getArea() && !processWorkingHours.getArea().equals(area)){
                            continue;
                        }
                        ErrorListDto errorListDto = new ErrorListDto();
                        long l = processWorkingHours.getTimeLong().longValue();
                        if(LIST[i].equals(RODREMOVAL)){
                            ProductModel productModel = collect1.get(processWorkingHours.getEquipmentCode());
                            if(productModel.getSpecs().equals("12吋") && l / 1000 / 60 > Long.parseLong(TIMELONG[i + 1])){
                                errorListDto.setErrorType("工时异常");
                                errorListDto.setDeviceNo(processWorkingHours.getEquipmentCode());
                                errorListDto.setDetails(substring + "，" + processWorkingHours.getEquipmentCode() + processWorkingHours.getStepName() + "用时" + l / 1000 / 60 +"min，现" + collect10.get(processWorkingHours.getEquipmentCode()).get(0).getCurrentStep());
                                errorList.add(errorListDto);
                                continue;
                            }
                        }
                        if (l / 1000 / 60 > Long.parseLong(TIMELONG[i])) {
                            errorListDto.setErrorType("工时异常");
                            errorListDto.setDeviceNo(processWorkingHours.getEquipmentCode());
                            errorListDto.setDetails(substring + "，" + processWorkingHours.getEquipmentCode() + processWorkingHours.getStepName() + "用时" + l / 1000 / 60 +"min，现" + collect10.get(processWorkingHours.getEquipmentCode()).get(0).getCurrentStep());
                            errorList.add(errorListDto);
                        }
                    }

                }
            }
        }

        //低效炉台
        String startTime1 = DateUtil.formatDate1(DateUtil.addDay(getCurrentDayEndDate(), -7));
        String endTime1 =getCurrentDayEndTime();

        //1、产量1
        List<LongCrystal> longCrystals = longCrystalService.findByGmtCreate(startTime1, endTime1);
        List<LongCrystal> collect8 = longCrystals.stream().filter(longCrystal -> null != longCrystal.getArea() && longCrystal.getArea().equals(area)).collect(Collectors.toList());
        getInefficientStove(errorList, substring, collect8);

        String startTime2 = DateUtil.formatDate1(DateUtil.addDay(getCurrentDayEndDate(), -8));
        String endTime2 = DateUtil.formatDate1(DateUtil.addDay(getCurrentDayEndDate(), -1));

        //2、产量2
        List<LongCrystal> longCrystals1 = longCrystalService.findByGmtCreate(startTime2, endTime2);
        String time = DateUtil.formatDate1(DateUtil.addDay(getCurrentDayEndDate(), -2));
        String substring1 = time.substring(0, 10);
        List<LongCrystal> collect9 = longCrystals1.stream().filter(longCrystal -> null != longCrystal.getArea() && longCrystal.getArea().equals(area)).collect(Collectors.toList());
        getInefficientStove(errorList, substring1, collect9);

        //其他异常
        //1、工步表
        List<ProcessWorkingStep> processWorkingStepList = processWorkingStepService.getEveryStepNumber(area, getCurrentDayStartTime(), getCurrentDayEndTime());
        List<ProcessWorkingStep> collect7 = processWorkingStepList.stream().filter(processWorkingStep -> null != processWorkingStep.getLotNo()).collect(Collectors.toList());
        Map<String, Map<Integer, List<ProcessWorkingStep>>> collect4 = collect7.stream().collect(Collectors.groupingBy(ProcessWorkingStep::getLotNo, Collectors.groupingBy(ProcessWorkingStep::getAgainNum)));

        Set<Map.Entry<String, Map<Integer, List<ProcessWorkingStep>>>> entries = collect4.entrySet();
        for (Map.Entry<String, Map<Integer, List<ProcessWorkingStep>>> entry : entries) {
            String substring2 = entry.getKey().substring(2, 6);
            Map<Integer, List<ProcessWorkingStep>> value = entry.getValue();
            Set<Map.Entry<Integer, List<ProcessWorkingStep>>> entries1 = value.entrySet();
            for (Map.Entry<Integer, List<ProcessWorkingStep>> integerListEntry : entries1) {
                List<ProcessWorkingStep> value1 = integerListEntry.getValue();
                Map<String, List<ProcessWorkingStep>> collect2 = value1.stream().collect(Collectors.groupingBy(ProcessWorkingStep::getStepName));
                //引放次数
                if(collect2.containsKey(STEPNAME[2]) && collect2.get(STEPNAME[2]).size() >= 3){
                    ErrorListDto errorListDto = new ErrorListDto();
                    errorListDto.setErrorType("其他异常");
                    errorListDto.setDeviceNo(substring2);
                    errorListDto.setDetails("截至" + substring + "，" + substring2 + "单循环段引放次数为" + value1.size() + "次");
                    errorList.add(errorListDto);
                }
            }
        }

        List<String> lotNoList = processWorkingStepService.getEveryStepNumberGroupByLotNo(area);
        List<String> byLotNoAndClosureIdentification = longCrystalService.findByLotNoAndClosureIdentification(lotNoList, EnumValuesServer.FINALIDENTIFICATION);
        List<ProcessWorkingStep> everyStepNumberByLotNo = processWorkingStepService.getEveryStepNumberByLotNo(byLotNoAndClosureIdentification);
        Map<String, Map<String, List<ProcessWorkingStep>>> collect2 = everyStepNumberByLotNo.stream().collect(Collectors.groupingBy(ProcessWorkingStep::getEquipmentCode, Collectors.groupingBy(ProcessWorkingStep::getStepName)));
        Set<Map.Entry<String, Map<String, List<ProcessWorkingStep>>>> entries1 = collect2.entrySet();
        for (Map.Entry<String, Map<String, List<ProcessWorkingStep>>> stringMapEntry : entries1) {
            Map<String, List<ProcessWorkingStep>> value = stringMapEntry.getValue();
            //等径断线次数
            int i = 0;
            if(value.containsKey(STEPNAME[7]) && value.containsKey(STEPNAME[8]) && value.containsKey(STEPNAME[9])){
                i = Optional.ofNullable(value.get(STEPNAME[7]).size()).orElse(0) + Optional.ofNullable(value.get(STEPNAME[8]).size()).orElse(0) + Optional.ofNullable(value.get(STEPNAME[9]).size()).orElse(0);
            }
            if(i >= 5){
                ErrorListDto errorListDto = new ErrorListDto();
                errorListDto.setErrorType("其他异常");
                errorListDto.setDeviceNo(stringMapEntry.getKey());
                errorListDto.setDetails("截至" + substring + "，" + stringMapEntry.getKey() + "已等径断线" + i + "次");
                errorList.add(errorListDto);
            }

            //回熔次数
            int c = 0;
            if(value.containsKey(STEPNAME[0])){
                c = Optional.ofNullable(value.get(STEPNAME[0]).size()).orElse(0);
            }
            if(c >= 5){
                ErrorListDto errorListDto = new ErrorListDto();
                errorListDto.setErrorType("其他异常");
                errorListDto.setDeviceNo(stringMapEntry.getKey());
                errorListDto.setDetails("截至" + substring + "，" + stringMapEntry.getKey() + "已回熔" + c + "次");
                errorList.add(errorListDto);
            }
        }

        //2、工时表
        List<ProcessWorkingHours> collect6 = processWorkingHoursList.stream().filter(processWorkingHours -> null != processWorkingHours.getAgainNum() && null != processWorkingHours.getLotNo()).collect(Collectors.toList());
        Map<String, Map<Integer, List<ProcessWorkingHours>>> collect3 = collect6.stream().collect(Collectors.groupingBy(ProcessWorkingHours::getLotNo, Collectors.groupingBy(ProcessWorkingHours::getAgainNum)));
        Set<Map.Entry<String, Map<Integer, List<ProcessWorkingHours>>>> entriess = collect3.entrySet();
        for (Map.Entry<String, Map<Integer, List<ProcessWorkingHours>>> entry : entriess) {
            String substring2 = entry.getKey().substring(2, 6);
            Map<Integer, List<ProcessWorkingHours>> value = entry.getValue();
            Set<Map.Entry<Integer, List<ProcessWorkingHours>>> entries2 = value.entrySet();
            for (Map.Entry<Integer, List<ProcessWorkingHours>> integerListEntry : entries2) {
                List<ProcessWorkingHours> value1 = integerListEntry.getValue();
                Map<String, List<ProcessWorkingHours>> collect5 = value1.stream().collect(Collectors.groupingBy(ProcessWorkingHours::getStepName));
                List<ProcessWorkingHours> processWorkingHoursList1 = collect5.get(DRAUGHT);
                if(null != processWorkingHoursList1 && processWorkingHoursList1.size() > 0){
                    for (ProcessWorkingHours processWorkingHours : processWorkingHoursList1) {
                        if(null != processWorkingHours.getArea() && !processWorkingHours.getArea().equals(area)){
                            continue;
                        }
                        if(processWorkingHours.getTimeLong()/1000/60 > 100){
                            ErrorListDto errorListDto = new ErrorListDto();
                            errorListDto.setErrorType("其他异常");
                            errorListDto.setDeviceNo(substring2);
                            errorListDto.setDetails(substring + "，" + substring2 + "引放工时为" + processWorkingHours.getTimeLong()/1000/60 + "min，现" + collect10.get(processWorkingHours.getEquipmentCode()).get(0).getCurrentStep());
                            errorList.add(errorListDto);
                        }
                    }
                }
            }
        }
        return errorList;
    }

    private void getInefficientStove(List<ErrorListDto> errorList, String substring, List<LongCrystal> longCrystals1) {
        Map<String, List<LongCrystal>> collect3 = longCrystals1.stream().collect(Collectors.groupingBy(LongCrystal::getEquipmentCode));
        Set<Map.Entry<String, List<LongCrystal>>> entries = collect3.entrySet();
        for (Map.Entry<String, List<LongCrystal>> entry : entries) {
            List<LongCrystal> value = entry.getValue();
            BigDecimal weight = value.stream().map(longCrystal -> {
                if(null == longCrystal.getWeight()){
                    return new BigDecimal(0);
                } else {
                    return longCrystal.getWeight();
                }
            }).reduce(BigDecimal.ZERO, BigDecimal::add);
            if(weight.divide(new BigDecimal(7), 2, BigDecimal.ROUND_HALF_UP).compareTo(new BigDecimal(160)) <= 0){
                ErrorListDto errorListDto = new ErrorListDto();
                errorListDto.setErrorType("低效炉台");
                errorListDto.setDeviceNo(entry.getKey());
                errorListDto.setDetails("截至" + substring + "，" + entry.getKey() + "单产为" + weight.divide(new BigDecimal(7), 2, BigDecimal.ROUND_HALF_UP) +"KG");
                errorList.add(errorListDto);
            }
        }
    }

    private NumberOfOperations1Dto getNumberOfOperation1Dto(Map<String, String> collect, String s) {
        //异常炉台数配置
        NumberOfOperations1Dto numberOfOperations1Dto = new NumberOfOperations1Dto();
        if (collect.containsKey(s)) {
            numberOfOperations1Dto.setCount1(new BigDecimal(collect.get(s)));
        } else {
            numberOfOperations1Dto.setCount1(new BigDecimal(0));
        }
        numberOfOperations1Dto.setSeries(s);
        return numberOfOperations1Dto;
    }

    /**
     * 获取车间系列
     *
     * @param area
     * @return
     */

    public List<String> getSeriesList(String area) {
        List<String> equipmentList = equipmentService.findByDeviceIdAndArea(29, area);
        return equipmentList;
    }

    /**
     * 运行设备数、停炉设备数
     *
     * @param status
     * @return
     */

    public Map<String, List<Equipment>> numberOfOperatingEquipment(Integer status) {

        if (null == redisUtils.get(status + STATE)) {
            List<Equipment> equipmentList = equipmentService.findByDeviceIdAndStatus(29, status);
            Map<String, List<Equipment>> collect = equipmentList.stream().collect(Collectors.groupingBy(Equipment::getSeries));
            redisUtils.set(status + STATE, collect, TIMEOUT, TimeUnit.MINUTES);
        }
        Map<String, List<Equipment>> data = (Map<String, List<Equipment>>) redisUtils.get(status + STATE);

        return data;
    }

    /**
     * 获取开始时间结束时间
     *
     * @return
     */

    public String getCurrentDayStartTime() {
        Date date = new Date();
        String s = DateUtil.formatDate(date);
        String s1 = DateUtil.formatDate(DateUtil.addMinute(date, -510));
        String startTime = null;

        if (s.equals(s1)) {
            startTime = DateUtil.formatDate1(DateUtil.getCurrentDayStartTime8H());
        } else {
            startTime = DateUtil.formatDate1(DateUtil.addDay(DateUtil.getCurrentDayStartTime8H(), -1));
        }
        return startTime;
    }

    public String getCurrentDayEndTime() {
        Date date = new Date();
        String s = DateUtil.formatDate(date);
        String s1 = DateUtil.formatDate(DateUtil.addMinute(date, -510));
        String endTime = null;

        if (s.equals(s1)) {
            endTime = DateUtil.formatDate1(DateUtil.addDay(DateUtil.getCurrentDayStartTime8H(), 1));
        } else {
            endTime = DateUtil.formatDate1(DateUtil.getCurrentDayStartTime8H());
        }
        return endTime;
    }

    public Date getCurrentDayEndDate() {
        Date date = new Date();
        String s = DateUtil.formatDate(date);
        String s1 = DateUtil.formatDate(DateUtil.addMinute(date, -510));
        Date endTime = null;

        if (s.equals(s1)) {
            endTime = DateUtil.addDay(DateUtil.getCurrentDayStartTime8H(), 1);
        } else {
            endTime = DateUtil.getCurrentDayStartTime8H();
        }
        return endTime;
    }

    /**
     * 获取工步次数
     *
     * @param area
     * @param series
     * @param stepName
     * @return
     */

    public Integer getEveryStepNumber(String area, String series, String stepName) {
        String startTime = getCurrentDayStartTime();
        String endTime = getCurrentDayEndTime();

        if (null == redisUtils.get(STEPNUMBER)) {
            List<ProcessWorkingStep> processWorkingStepList = processWorkingStepService.getEveryStepNumber(area, startTime, endTime);
            Map<String, Map<String, List<ProcessWorkingStep>>> collect = processWorkingStepList.stream().collect(Collectors.groupingBy(ProcessWorkingStep::getSeries, Collectors.groupingBy(ProcessWorkingStep::getStepName)));
            redisUtils.set(STEPNUMBER, collect, TIMEOUT, TimeUnit.MINUTES);
        }

        Map<String, Map<String, List<ProcessWorkingStep>>> data = (Map<String, Map<String, List<ProcessWorkingStep>>>) redisUtils.get(STEPNUMBER);

        if (data.containsKey(series)) {
            Map<String, List<ProcessWorkingStep>> stringListMap = data.get(series);
            if (stringListMap.containsKey(stepName)) {
                List<ProcessWorkingStep> processWorkingStepList1 = stringListMap.get(stepName);
                return processWorkingStepList1.size();
            }
        }
        return 0;
    }

    /**
     * 获取处于当前工步的数量
     *
     * @param area
     * @param series
     * @param stepName
     * @return
     */

    public Integer getCurrentStepNumber(String area, String series, String stepName) {

        String startTime = getCurrentDayStartTime();
        String endTime = getCurrentDayEndTime();

        if (null == redisUtils.get(CURRENTSTEPNUMBER)) {
            List<Equipment> equipmentList1 = equipmentService.getEveryStepNumber(area, startTime, endTime);
            Map<String, Map<String, List<Equipment>>> collect = equipmentList1.stream().collect(Collectors.groupingBy(Equipment::getSeries, Collectors.groupingBy(Equipment::getCurrentStep)));
            redisUtils.set(CURRENTSTEPNUMBER, collect, TIMEOUT, TimeUnit.MINUTES);
        }

        Map<String, Map<String, List<Equipment>>> data = (Map<String, Map<String, List<Equipment>>>) redisUtils.get(CURRENTSTEPNUMBER);

        if (data.containsKey(series)) {
            Map<String, List<Equipment>> stringListMap = data.get(series);
            if (stringListMap.containsKey(stepName)) {
                List<Equipment> equipmentList = stringListMap.get(stepName);
                return equipmentList.size();
            }
        }
        return 0;
    }

    /**
     * 获取工时
     *
     * @param series
     * @param workHourName
     * @return
     */

    public BigDecimal getWorkHours(String series, String workHourName) {

        String startTime = getCurrentDayStartTime();
        String endTime = getCurrentDayEndTime();

        if (null == redisUtils.get(HOURS)) {
            List<ProcessWorkingHours> processWorkingHoursList = processWorkingHoursService.getByStartTime(startTime, endTime);
            Map<String, Map<String, List<ProcessWorkingHours>>> collect = processWorkingHoursList.stream().collect(Collectors.groupingBy(ProcessWorkingHours::getSeries, Collectors.groupingBy(ProcessWorkingHours::getStepName)));
            redisUtils.set(HOURS, collect, TIMEOUT, TimeUnit.MINUTES);
        }
        Map<String, Map<String, List<ProcessWorkingHours>>> data = (Map<String, Map<String, List<ProcessWorkingHours>>>) redisUtils.get(HOURS);

        if (null != data && data.containsKey(series)) {
            Map<String, List<ProcessWorkingHours>> stringListMap = data.get(series);
            if (stringListMap.containsKey(workHourName)) {
                List<ProcessWorkingHours> processWorkingHoursList = stringListMap.get(workHourName);
                BigDecimal totalHour = new BigDecimal(processWorkingHoursList.stream().mapToLong(ProcessWorkingHours::getTimeLong).sum());
                return totalHour.divide(new BigDecimal(processWorkingHoursList.size() * 1000 * 60 * 60), 1, BigDecimal.ROUND_HALF_UP);
            }
        }
        return new BigDecimal(0);
    }

    /**
     * 工时对应的炉台数量
     *
     * @param series
     * @param workHourName
     * @return
     */

    public int getLotNos(String series, String workHourName) {

        if (null == redisUtils.get(HOURSLOTNO)) {
            List<ProcessWorkingHours> processWorkingHoursList = processWorkingHoursService.getByStartTime(getCurrentDayStartTime(), getCurrentDayEndTime());
            Map<String, Map<String, List<ProcessWorkingHours>>> collect = processWorkingHoursList.stream().collect(Collectors.groupingBy(ProcessWorkingHours::getSeries, Collectors.groupingBy(ProcessWorkingHours::getStepName)));
            redisUtils.set(HOURSLOTNO, collect, TIMEOUT, TimeUnit.MINUTES);
        }
        Map<String, Map<String, List<ProcessWorkingHours>>> data = (Map<String, Map<String, List<ProcessWorkingHours>>>) redisUtils.get(HOURSLOTNO);

        if (data.containsKey(series)) {
            Map<String, List<ProcessWorkingHours>> stringListMap = data.get(series);
            if (stringListMap.containsKey(workHourName)) {
                List<ProcessWorkingHours> processWorkingHoursList = stringListMap.get(workHourName);
                List<ProcessWorkingHours> collect1 = processWorkingHoursList.stream().filter(processWorkingHours -> null != processWorkingHours.getLotNo()).collect(Collectors.toList());
                Map<String, List<ProcessWorkingHours>> collect = collect1.stream().collect(Collectors.groupingBy(ProcessWorkingHours::getLotNo));
                return collect.size();
            }
        }
        return 0;
    }

    /**
     * 获取当月产量
     *
     * @param area
     * @param type
     * @return
     */

    private BigDecimal getCurrentMonthWeight(String area, String type) {

        BigDecimal totalWeight;
        if (type.equals("月")) {
            String endTime = DateUtil.formatDate1(DateUtil.addDay(DateUtil.getCurrentMonthEndTime9H(), 1));
            String startTime = DateUtil.formatDate1(DateUtil.getCurrentMonthStartTime1());
            totalWeight = longCrystalService.findByGmtCreateAndAreaAndarea(startTime, endTime, area);
        } else {
            totalWeight = longCrystalService.findByGmtCreateAndAreaAndarea1(getCurrentDayStartTime(), getCurrentDayEndTime(), area);
        }
        return totalWeight;
    }

    /**
     * 获取当天产量
     *
     * @param series
     * @return
     */

    private BigDecimal getCurrentDayWeight(String series) {

        if (null == redisUtils.get(WEIGHT)) {
            List<LongCrystal> byGmtCreate = longCrystalService.findByGmtCreate(getCurrentDayStartTime(), getCurrentDayEndTime());
            Map<String, List<LongCrystal>> collect = byGmtCreate.stream().collect(Collectors.groupingBy(LongCrystal::getSeries));
            redisUtils.set(WEIGHT, collect, TIMEOUT, TimeUnit.MINUTES);
        }
        Map<String, List<LongCrystal>> data = (Map<String, List<LongCrystal>>) redisUtils.get(WEIGHT);

        List<LongCrystal> longCrystalList = data.get(series);
        if(null != longCrystalList && longCrystalList.size() > 0){
            BigDecimal weight = longCrystalList.stream().map(LongCrystal::getWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
            return weight;
        }
        return new BigDecimal(0);
    }

    /**
     * 获取总的运行时间
     *
     * @param area
     * @param type
     * @return
     */

    private BigDecimal getTotalRunTime(String area, String type) {

        //1、获取系列
        List<String> seriesList = getSeriesList(area);

        BigDecimal totalRunTime;

        if (type.equals("月")) {
            String endTime = DateUtil.formatDate1(DateUtil.addDay(DateUtil.getCurrentMonthEndTime9H(), 1));
            String startTime = DateUtil.formatDate1(DateUtil.getCurrentMonthStartTime1());
            totalRunTime = crystalPullingInfoLogService.getCrystalPullingInfoLogByTimeAndSeries(startTime, endTime, seriesList);

        } else {
            totalRunTime = crystalPullingInfoLogService.getCrystalPullingInfoLogByTimeAndSeries(getCurrentDayStartTime(), getCurrentDayEndTime(), seriesList);
        }

        return totalRunTime;
    }

    /**
     * 查询成晶重量
     *
     * @param longCrystals
     * @param collect
     * @param crystalTotalWeight
     * @return
     */

    public BigDecimal getCrystalWeight(List<LongCrystal> longCrystals, Map<String, String> collect, BigDecimal crystalTotalWeight) {
        for (LongCrystal byCrystalNo : longCrystals) {

            BigDecimal positionStaggeredLength = new BigDecimal(0);
            BigDecimal isometricLength = new BigDecimal(0);
            BigDecimal add = new BigDecimal(0);
            //划线切掉的长度
            ProductionPaintingLine byCrystalNo1 = productionPaintingLineService.findByCrystalNo(byCrystalNo.getCrystalNo());
            if (null != byCrystalNo1) {
                //等径长度
                isometricLength = byCrystalNo1.getIsometricLength();
                if (null != byCrystalNo1.getPositionStaggeredLength()) {
                    positionStaggeredLength = byCrystalNo1.getPositionStaggeredLength();
                }
                add = positionStaggeredLength.add(byCrystalNo1.getLineTailLength()).add(byCrystalNo1.getNoTopLength());
            }
            //评级不合格的总长度
            BigDecimal unqualifiedLength = new BigDecimal(0);

            //评级A2的、退回收料的长度
            List<YbInspectData> inspectDatasByCrystalNo = ybInspectDataService.getInspectDatasByCrystalNo(byCrystalNo.getCrystalNo());
            if (!CollectionUtils.isEmpty(inspectDatasByCrystalNo)) {
                for (YbInspectData ybInspectData : inspectDatasByCrystalNo) {
                    if (StringUtils.isNotBlank(ybInspectData.getProductLevel()) &&
                            (ybInspectData.getProductLevel().equals("A2") ||
                                    ybInspectData.getProductLevel().contains("寿命通体退回收料") ||
                                    ybInspectData.getProductLevel().contains("退高碳料") ||
                                    ybInspectData.getProductLevel().contains("少子退回收料") ||
                                    ybInspectData.getProductLevel().contains("电阻退回收料") ||
                                    ybInspectData.getProductLevel().contains("碳退回收料") ||
                                    ybInspectData.getProductLevel().contains("氧退回收料") ||
                                    ybInspectData.getProductLevel().contains("直径细退回收料") ||
                                    ybInspectData.getProductLevel().contains("短棒退回收料") ||
                                    ybInspectData.getProductLevel().contains("退短棒回收料") ||
                                    ybInspectData.getProductLevel().contains("吋回收料"))) {
                        unqualifiedLength.add(ybInspectData.getActualLength());
                    }
                }
            }
            //返切的长度
            BigDecimal backCutLength = new BigDecimal(0);
            if (!CollectionUtils.isEmpty(inspectDatasByCrystalNo)) {
                for (YbInspectData ybInspectData : inspectDatasByCrystalNo) {
                    ProductionBackCuttingRecord bySegmentNo = productionRecutService.findBySegmentNo(ybInspectData.getSectionNo());
                    if (null != bySegmentNo) {
                        List<ProductionPaintingLineDetail> byOperateReversecutDrawId = productionPaintingLineDetailService.findByOperateReversecutDrawId(bySegmentNo.getId());
                        if (!CollectionUtils.isEmpty(byOperateReversecutDrawId)) {
                            for (ProductionPaintingLineDetail productionPaintingLineDetail : byOperateReversecutDrawId) {
                                if (productionPaintingLineDetail.getType() != 0) {
                                    backCutLength = backCutLength.add(productionPaintingLineDetail.getLength());
                                }
                            }
                        }
                    }
                }
            }
            BigDecimal abs = isometricLength.subtract(add).subtract(unqualifiedLength).subtract(backCutLength);
            String coefficient = collect.get(byCrystalNo.getSpecs());
            BigDecimal divide = abs.divide(new BigDecimal(Double.valueOf(coefficient)), 4, BigDecimal.ROUND_HALF_UP);
            crystalTotalWeight = crystalTotalWeight.add(divide);
        }
        return crystalTotalWeight;
    }

    /**
     * 查询总的投料量
     *
     * @param lotNoList
     * @param totalWeight
     * @return
     */

    public BigDecimal getTotalWeight(List<String> lotNoList, BigDecimal totalWeight) {
        //查询配料明细
        List<LoadingTask> loadingTasks = loadingTaskService.findByLotNoList(lotNoList);
        if (null != loadingTasks && loadingTasks.size() > 0) {
            Long id = loadingTasks.get(0).getId();
            List<BlastFurnaceDetail> blastFurnaceDetailList = blastFurnaceDetailService.getBlastFurnaceDetailList(id);
            blastFurnaceDetailList = blastFurnaceDetailList.stream().filter(blastFurnaceDetail -> !blastFurnaceDetail.getMaterialName().contains("坩埚")).collect(Collectors.toList());
            for (BlastFurnaceDetail blastFurnaceDetail : blastFurnaceDetailList) {
                totalWeight = totalWeight.add(blastFurnaceDetail.getWeight());
            }
        }

        //查询灌料明细
        List<AgainTask> againTaskList = againTaskService.findByLotNoList(lotNoList);
        List<Long> idList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(againTaskList)) {
            for (AgainTask againTask : againTaskList) {
                idList.add(againTask.getId());
            }
            List<AgainTaskDetail> againTaskDetailList = againTaskDetailService.findByAgainTaskIdList(idList);
            totalWeight = getMaterialDetailed(againTaskDetailList, totalWeight);
        }

        return totalWeight;
    }

    /**
     * 查询当日总的投料量
     *
     * @param totalWeight
     * @return
     */

    public BigDecimal getTotalWeight(String series, BigDecimal totalWeight) {
        //查询配料明细
//        if (null != loadingTasks && loadingTasks.size() > 0) {
//
//            List<BlastFurnaceDetail> blastFurnaceDetailList = blastFurnaceDetailService.getBlastFurnaceDetailList(id);
//            blastFurnaceDetailList = blastFurnaceDetailList.stream().filter(blastFurnaceDetail -> !blastFurnaceDetail.getMaterialName().contains("坩埚")).collect(Collectors.toList());
//            for (BlastFurnaceDetail blastFurnaceDetail : blastFurnaceDetailList) {
//                totalWeight = totalWeight.add(blastFurnaceDetail.getWeight());
//            }
//        }

        //查询灌料明细
        List<InputFurnaceBurden> byStartTime = inputFurnaceBurdenService.findByStartTime(getCurrentDayStartTime(), getCurrentDayEndTime(), series);
        BigDecimal reduce = byStartTime.stream().map(InputFurnaceBurden::getWeigth).reduce(BigDecimal.ZERO, BigDecimal::add);

        totalWeight.add(reduce);

        return totalWeight;
    }

    public BigDecimal getMaterialDetailed(List<AgainTaskDetail> againTaskDetailList, BigDecimal totalWeight) {
        if (null != againTaskDetailList && againTaskDetailList.size() > 0) {
            List<Long> idList = new ArrayList<>();
            for (AgainTaskDetail againTaskDetail : againTaskDetailList) {
                idList.add(againTaskDetail.getId());
            }
            List<InputFurnaceDetail> byAgainTaskDetailId = inputFurnaceDetailService.findByAgainTaskDetailIdList(idList);
            for (InputFurnaceDetail inputFurnaceDetail : byAgainTaskDetailId) {
                totalWeight = totalWeight.add(inputFurnaceDetail.getWeight());
            }
        }
        return totalWeight;
    }

    /**
     * 列表排序
     *
     * @param list
     * @return
     */

    private List<NumberOfOperations1Dto> sortList(List<NumberOfOperations1Dto> list) {
        Collections.sort(list);
        return list;
    }
}
