zhanghl
2025-05-13 a9f55fb1ab24f43fee70b16e1a8c58a33fc59fa6
aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsGasPipingRouteStatServiceImpl.java
@@ -1,6 +1,6 @@
package com.aps.core.service.impl;
import com.alibaba.fastjson2.JSONArray;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSONObject;
import com.aps.common.core.utils.DateUtils;
import com.aps.common.core.utils.uuid.IdUtils;
@@ -11,6 +11,7 @@
import com.aps.core.mapper.ApsGasPipingRouteStatMapper;
import com.aps.core.service.IApsGasMaterialUsageService;
import com.aps.core.service.IApsGasPipingRouteStatService;
import com.aps.core.service.IApsStandardProcessService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
@@ -20,18 +21,19 @@
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import static java.util.stream.Collectors.groupingBy;
/**
 * 气体管路产能负载统计Service业务层处理
@@ -54,6 +56,9 @@
    @Autowired
    private IApsGasMaterialUsageService apsGasMaterialUsageService;
    @Autowired
    private IApsStandardProcessService apsStandardProcessService;
    /**
     * 查询气体管路产能负载统计
@@ -142,9 +147,11 @@
            apsGasPipingPlans.forEach(apsGasPipingPlan -> {
                List<ApsProcessRoute> apsProcessRoutes = apsGasPipingPlan.getApsProcessRoutes();
                //按照工序序号升序排序
                apsProcessRoutes.sort((a, b)->a.getProcessNumber().compareTo(b.getProcessNumber()));
                apsProcessRoutes.sort((a, b)->b.getProcessNumber().compareTo(a.getProcessNumber()));
                //是否找到当前工序
                boolean isFind = false;
                boolean isCurrentProcess = false;
                boolean lastProcessStartTimeIsBeforeNow = false;
                ApsGasPipingRouteStat preApsProcessRoute = null;
                for (int i=0;i<apsProcessRoutes.size();i++){
                    ApsProcessRoute apsProcessRoute = apsProcessRoutes.get(i);
                    ApsGasPipingRouteStat apsGasPipingRouteStat = new ApsGasPipingRouteStat();
@@ -153,40 +160,52 @@
                    //料号
                    apsGasPipingRouteStat.setItemNumber(apsGasPipingPlan.getItemNumber());
                    //当前工序号
                    apsGasPipingRouteStat.setCurrentProcessNumber(apsGasPipingPlan.getProcessNumber());
                    apsGasPipingRouteStat.setCurrentProcessNumber(new BigDecimal(apsGasPipingPlan.getProcessNumber()));
                    //生产数量
                    apsGasPipingRouteStat.setProductionQuantity(apsGasPipingPlan.getProductionQuantity());
                    //工序名称
                    apsGasPipingRouteStat.setProcessName(apsProcessRoute.getProcessName());
                    //工序号
                    apsGasPipingRouteStat.setRoadProcessNumber(apsProcessRoute.getProcessNumber());
                    apsGasPipingRouteStat.setRoadProcessNumber( new BigDecimal(apsProcessRoute.getProcessNumber()) );
                    //标准工时
                    apsGasPipingRouteStat.setStandardTime(apsProcessRoute.getStandardTime());
                    //专业
                    apsGasPipingRouteStat.setMajor(apsGasPipingPlan.getPlanType());
                    //工序总工时 等于 标准工时*生产数量
                    apsGasPipingRouteStat.setProcessTotalTime(apsProcessRoute.getStandardTime().multiply(apsGasPipingPlan.getProductionQuantity()));
                    //计划开工日
                    if(apsGasPipingRouteStat.getCurrentProcessNumber().equals(apsGasPipingRouteStat.getRoadProcessNumber())) {
                        /* 对 stat.getProcessPlanStartDay() 和当前日期 进行对比,只对比到日,不用管十分秒*/
                        LocalDate startLocalDate = LocalDate.ofInstant(apsProcessRoute.getProcessPlanStartDay().toInstant(), ZoneId.systemDefault());
                        LocalDate nowLocalDate = LocalDate.now();
                        if (startLocalDate.isBefore(nowLocalDate)) {
                            apsGasPipingRouteStat.setProcessPlanStartDay(new Date());
                        }else{
                            apsGasPipingRouteStat.setProcessPlanStartDay(apsProcessRoute.getProcessPlanStartDay());
                        }
                        isFind = true;
                    }
                    if(!isFind){
                        continue;
                    //计划开工日 如果是当前序
                    if(apsGasPipingPlan.getProcessNumber().equals(apsProcessRoute.getProcessNumber())) {
                        isCurrentProcess = true;
                    }
                    // 上一道工序的结束时间 = 上一道工序的开始时间 + 上一道工序的总工时
                    if(apsGasPipingRouteStat.getProcessPlanStartDay()==null){
                        LocalDateTime previousProcessPlanStartDay = apsProcessRoutes.get(i - 1).getProcessPlanStartDay().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                        long previousProcessTotalTime = apsGasPipingRouteStatList.get(i - 1).getProcessTotalTime().longValue();
                        LocalDateTime currentProcessPlanStartDay = previousProcessPlanStartDay.plusHours(previousProcessTotalTime);
                        apsGasPipingRouteStat.setProcessPlanStartDay(Date.from(Timestamp.valueOf(currentProcessPlanStartDay.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).toInstant()));
                    if(i==0){
                        LocalDate endLocalDate = LocalDate.ofInstant(apsGasPipingPlan.getPlanEndDay().toInstant(), ZoneId.systemDefault());
                        LocalDate nowLocalDate = LocalDate.now();
                        LocalDateTime planEndDay;
                        if(endLocalDate.isBefore(nowLocalDate)){
                            planEndDay = LocalDateTime.now();
                        }else{
                            planEndDay = apsGasPipingPlan.getPlanEndDay().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                        }
                        apsGasPipingRouteStat.setProcessPlanEndDay(Date.from(planEndDay.atZone(ZoneId.systemDefault()).toInstant()));
                        long seconds = apsProcessRoute.getStandardTime().multiply(apsGasPipingPlan.getProductionQuantity()).multiply(new BigDecimal(60)).multiply(new BigDecimal(60)).longValue();
                        LocalDateTime planStartDay = planEndDay.plusSeconds(-seconds);
                        apsGasPipingRouteStat.setProcessPlanStartDay(Date.from(planStartDay.atZone(ZoneId.systemDefault()).toInstant()));
                        if(planStartDay.isBefore(LocalDateTime.now())){
                            lastProcessStartTimeIsBeforeNow = true;
                        }
                    }else{
                        if(lastProcessStartTimeIsBeforeNow){
                            Date now = new Date();
                            apsGasPipingRouteStat.setProcessPlanStartDay(now);
                            apsGasPipingRouteStat.setProcessPlanEndDay(now);
                        }else{
                            apsGasPipingRouteStat.setProcessPlanEndDay(preApsProcessRoute.getProcessPlanStartDay());
                            LocalDateTime planEndDay = preApsProcessRoute.getProcessPlanStartDay().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                            long seconds = apsProcessRoute.getStandardTime().multiply(apsGasPipingPlan.getProductionQuantity()).multiply(new BigDecimal(60)).multiply(new BigDecimal(60)).longValue();
                            LocalDateTime planStartDay = planEndDay.plusSeconds(-seconds);
                            apsGasPipingRouteStat.setProcessPlanStartDay(Date.from(planStartDay.atZone(ZoneId.systemDefault()).toInstant()));
                        }
                    }
                    //插入 年 月 日
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
@@ -200,14 +219,18 @@
//                    apsGasMaterialUsage.setItemNumber(apsGasPipingPlan.getItemNumber());
//                    apsGasMaterialUsage.setProcessName(apsProcessRoute.getProcessName());
//                    List<ApsGasMaterialUsage> apsGasMaterialUsageList = apsGasMaterialUsageService.selectApsGasMaterialUsageList(apsGasMaterialUsage);
                    apsGasPipingRouteStat.setStandardDosage(apsProcessRoute.getStandardTime().multiply(apsGasPipingPlan.getProductionQuantity()));
//                    apsGasPipingRouteStat.setStandardDosage(apsProcessRoute.getStandardTime().multiply(apsGasPipingPlan.getProductionQuantity()));
                    //工序总用量 = 标准用量*生产数量
                    apsGasPipingRouteStat.setProcessTotalDosage(apsGasPipingRouteStat.getStandardDosage().multiply(apsGasPipingPlan.getProductionQuantity()));
//                    apsGasPipingRouteStat.setProcessTotalDosage(apsGasPipingRouteStat.getStandardDosage().multiply(apsGasPipingPlan.getProductionQuantity()));
                    apsGasPipingRouteStat.setCreateTime(DateUtils.getNowDate());
                    apsGasPipingRouteStat.setCreateBy("auto");
                    apsGasPipingRouteStat.setBatchNumber(batchNum);
                    apsGasPipingRouteStat.setId(IdUtils.fastSimpleUUID());
                    apsGasPipingRouteStatList.add(apsGasPipingRouteStat);
                    preApsProcessRoute = apsGasPipingRouteStat;
                    if(isCurrentProcess){
                        break;
                    }
                }
            });
            List<ApsGasPipingRouteStat> tempInsertList = new ArrayList<>();
@@ -231,21 +254,46 @@
    @Override
    public JSONObject getCapacityPlanData(ApsGasPipingRouteStat apsGasPipingRouteStat) {
        JSONObject result = new JSONObject();
        HashSet<String> startPlanTimeSet = new HashSet<>();
        JSONArray processData = new JSONArray();
        YearMonth yearMonth = YearMonth.parse(apsGasPipingRouteStat.getSearchEndDate());
        int daysInMonth = yearMonth.lengthOfMonth();
        LinkedHashSet<String> startPlanTimeSet = new LinkedHashSet<>();
        //工序分组统计
        LinkedHashMap<String, List<ApsResourceDateStat>> processMap = new LinkedHashMap<>();
        List<HashMap<String, List<ApsResourceDateStat>>> processList = new ArrayList<>();
        try {
            //获取标准工序名称
            ApsStandardProcess apsStandardProcess = new ApsStandardProcess();
            apsStandardProcess.setMajor(apsGasPipingRouteStat.getMajor().equals("gas")?"气柜":"管路");
            List<ApsStandardProcess> apsStandardProcessList = apsStandardProcessService.selectApsStandardProcessList(apsStandardProcess);
            apsStandardProcessList.sort((a, b)->a.getProcessName().compareTo(b.getProcessName()));
            for(ApsStandardProcess temp:apsStandardProcessList){
                processMap.put(temp.getProcessName(), new ArrayList<ApsResourceDateStat>());
            }
            //获取工序计划产能数据
            HashMap<String, ApsGasPipelineCapacityPlan> apsGasPipingPlanMap = new HashMap<>();
            List<ApsGasPipelineCapacityPlan> apsGasPipelineCapacityPlanList = apsGasPipelineCapacityPlanMapper.selectApsGasPipelineCapacityPlanList(new ApsGasPipelineCapacityPlan());
            ApsGasPipelineCapacityPlan searchCapacityPlan = new ApsGasPipelineCapacityPlan();
            searchCapacityPlan.setMajor(apsGasPipingRouteStat.getMajor().equals("gas")?"气柜":"管路");
            if("day".equals(apsGasPipingRouteStat.getSearchType())){
                searchCapacityPlan.setYear(yearMonth.getYear()+"");
                searchCapacityPlan.setMonth(yearMonth.getMonthValue()+"");
                for(int i=1;i<=daysInMonth;i++){
                    startPlanTimeSet.add(yearMonth +"-"+ (i<10?"0"+i:i));
                }
            }else if("month".equals(apsGasPipingRouteStat.getSearchType())){
                searchCapacityPlan.setYear(yearMonth.getYear()+"");
                YearMonth start = YearMonth.of(Integer.parseInt(apsGasPipingRouteStat.getSearchStartDate().split("-")[0]), Integer.parseInt(apsGasPipingRouteStat.getSearchStartDate().split("-")[1]));
                YearMonth end = YearMonth.of(Integer.parseInt(apsGasPipingRouteStat.getSearchEndDate().split("-")[0]), Integer.parseInt(apsGasPipingRouteStat.getSearchEndDate().split("-")[1]));
                List<String> yearMonths = getYearMonthsInRange(start, end);
                startPlanTimeSet.addAll(yearMonths);
            }
            List<ApsGasPipelineCapacityPlan> apsGasPipelineCapacityPlanList = apsGasPipelineCapacityPlanMapper.selectApsGasPipelineCapacityPlanList(searchCapacityPlan);
            apsGasPipelineCapacityPlanList.forEach(apsGasPipelineCapacityPlan -> {
                apsGasPipingPlanMap.put(apsGasPipelineCapacityPlan.getProcessName(),apsGasPipelineCapacityPlan);
                apsGasPipingPlanMap.put(apsGasPipelineCapacityPlan.getProcessName()+"-"+apsGasPipelineCapacityPlan.getYear()+"-"+(Integer.parseInt(apsGasPipelineCapacityPlan.getMonth())<10?"0"+apsGasPipelineCapacityPlan.getMonth():apsGasPipelineCapacityPlan.getMonth()),apsGasPipelineCapacityPlan);
            });
            //计算日产能数据
            DateTimeFormatter formatter = null;
            List<ApsGasPipingRouteStat> apsGasPipingRouteStats;
            SimpleDateFormat simpleDateFormat = null;
            YearMonth yearMonth = YearMonth.parse(apsGasPipingRouteStat.getSearchEndDate());
            int daysInMonth = yearMonth.lengthOfMonth();
            apsGasPipingRouteStat.setSearchStartDate(apsGasPipingRouteStat.getSearchStartDate()+"-01 00:00:00");
            apsGasPipingRouteStat.setSearchEndDate(apsGasPipingRouteStat.getSearchEndDate()+"-"+ daysInMonth +" 23:59:59");
            if("day".equals(apsGasPipingRouteStat.getSearchType())){
@@ -255,120 +303,117 @@
                formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                simpleDateFormat = new SimpleDateFormat("yyyy-MM");
            }
            apsGasPipingRouteStats = apsGasPipingRouteStatMapper.selectApsGasPipingRouteStatList(apsGasPipingRouteStat);
            ApsGasPipingRouteStat queryStatParam = new ApsGasPipingRouteStat();
            BeanUtils.copyProperties(apsGasPipingRouteStat,queryStatParam);
            queryStatParam.setMajor("");
            apsGasPipingRouteStats = apsGasPipingRouteStatMapper.selectApsGasPipingRouteStatList(queryStatParam);
            //根据开工日进行升序排序
            apsGasPipingRouteStats.sort((a, b)->a.getPlanStartDay().compareTo(b.getPlanStartDay()));
            //工序分组统计
            HashMap<String, List<ApsResourceDateStat>> processMap = new HashMap<>();
            List<HashMap<String, List<ApsResourceDateStat>>> processList = new ArrayList<>();
            HashMap<String, List<ApsResourceDateStat>> processMapMonth = new HashMap<>();
            List<HashMap<String, List<ApsResourceDateStat>>> processListMonth = new ArrayList<>();
            apsGasPipingRouteStats.sort((a, b)->a.getProcessPlanStartDay().compareTo(b.getProcessPlanStartDay()));
            //工序开工日期
            String planStartDate = "";
            //统计所有工序对应的开工时间
            for (ApsGasPipingRouteStat apsGasPipingRouteStatTemp : apsGasPipingRouteStats) {
                planStartDate = simpleDateFormat.format(apsGasPipingRouteStatTemp.getProcessPlanStartDay());
                if("month".equals(apsGasPipingRouteStat.getSearchType())){
                    planStartDate = planStartDate+"-01";
                }
                ApsResourceDateStat apsResourceDateStat = new ApsResourceDateStat();
                apsResourceDateStat.setPlanDay(LocalDate.parse(planStartDate, formatter));
                apsResourceDateStat.setResourceName(apsGasPipingRouteStatTemp.getProcessName());
                //查询气柜管路产能规划表
                apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(apsGasPipingRouteStatTemp.getProcessName())!=null?apsGasPipingPlanMap.get(apsGasPipingRouteStatTemp.getProcessName()).getDayProduceAllNum().intValue():0);
                //查询料号工序产能表
                apsResourceDateStat.setRequireTimes(apsGasPipingRouteStatTemp.getProcessTotalTime().intValue());
                if(apsResourceDateStat.getDesignTimes()!=0){
                    apsResourceDateStat.setCapacityLoad(BigDecimal.valueOf(apsResourceDateStat.getRequireTimes()/apsResourceDateStat.getDesignTimes()* 100L));
                }else{
                    apsResourceDateStat.setCapacityLoad(BigDecimal.valueOf(0));
                }
                List<ApsResourceDateStat> apsResourceDateStatList = new ArrayList<>();
                if(processMap.containsKey(apsGasPipingRouteStatTemp.getProcessName())){
                    apsResourceDateStatList = processMap.get(apsGasPipingRouteStatTemp.getProcessName());
                }
                apsResourceDateStatList.add(apsResourceDateStat);
                processMap.put(apsGasPipingRouteStatTemp.getProcessName(), apsResourceDateStatList);
            }
            processMap.forEach((processName, apsResourceDateStatList) -> {
                HashMap<String, ApsResourceDateStat> dayMap = new HashMap<>();
                apsResourceDateStatList.forEach(apsResourceDateStat -> {
                    startPlanTimeSet.add(apsResourceDateStat.getPlanDay().toString());
                    planStartDate = simpleDateFormat.format(apsGasPipingRouteStatTemp.getProcessPlanStartDay());
                    if("month".equals(apsGasPipingRouteStat.getSearchType())){
                        if(dayMap.containsKey(apsResourceDateStat.getPlanDay().toString())){
                            ApsResourceDateStat apsResourceDateStatTemp = dayMap.get(apsResourceDateStat.getPlanDay().toString());
                            apsResourceDateStatTemp.setDesignTimes(apsGasPipingPlanMap.get(processName)!=null?apsGasPipingPlanMap.get(processName).getMonthProduceAllNum().intValue():0);
                            apsResourceDateStatTemp.setRequireTimes(apsResourceDateStatTemp.getRequireTimes()+apsResourceDateStat.getRequireTimes());
                            if(apsResourceDateStatTemp.getDesignTimes()!=0){
                                apsResourceDateStatTemp.setCapacityLoad(BigDecimal.valueOf(apsResourceDateStatTemp.getRequireTimes()/apsResourceDateStatTemp.getDesignTimes()* 100L));
                            }else{
                                apsResourceDateStatTemp.setCapacityLoad(BigDecimal.valueOf(0));
                            }
                            apsResourceDateStatTemp.setResourceGroupName(processName);
                            apsResourceDateStatTemp.setPlanDay(apsResourceDateStat.getPlanDay());
                            dayMap.put(apsResourceDateStat.getPlanDay().toString(), apsResourceDateStatTemp);
                        planStartDate = planStartDate+"-01";
                    }
                    ApsResourceDateStat apsResourceDateStat = new ApsResourceDateStat();
                    apsResourceDateStat.setPlanDay(LocalDate.parse(planStartDate, formatter));
                    apsResourceDateStat.setResourceName(apsGasPipingRouteStatTemp.getProcessName());
                    //查询气柜管路产能规划表
                    apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(apsGasPipingRouteStatTemp.getProcessName()+"-"+planStartDate.substring(0, 7))!=null?apsGasPipingPlanMap.get(apsGasPipingRouteStatTemp.getProcessName()+"-"+planStartDate.substring(0, 7)).getDayProduceAllNum():new BigDecimal(0));
                    //查询料号工序产能表
                    apsResourceDateStat.setRequireTimes(apsGasPipingRouteStatTemp.getProcessTotalTime());
                    if(apsResourceDateStat.getDesignTimes().compareTo(BigDecimal.ZERO)>0){
                        apsResourceDateStat.setCapacityLoad(apsResourceDateStat.getRequireTimes()
                                .divide(apsResourceDateStat.getDesignTimes(), 2, RoundingMode.HALF_UP)
                                .multiply(new BigDecimal(100)));
                    }else{
                        apsResourceDateStat.setCapacityLoad(BigDecimal.valueOf(0));
                    }
                   // apsResourceDateStatList = new ArrayList<>();
                    List<ApsResourceDateStat>   apsResourceDateStatList = processMap.get(apsGasPipingRouteStatTemp.getProcessName());
                    apsResourceDateStatList.add(apsResourceDateStat);
                    processMap.put(apsGasPipingRouteStatTemp.getProcessName(), apsResourceDateStatList);
                }
            }
            //聚合每道工序的开工时间和产能
            processMap.forEach((processName, apsResourceDateStatList) -> {
                LinkedHashMap<String, ApsResourceDateStat> dayMap = new LinkedHashMap<>();
                apsResourceDateStatList.forEach(apsResourceDateStat -> {
//                    startPlanTimeSet.add(apsResourceDateStat.getPlanDay().toString());
                    if(dayMap.containsKey(apsResourceDateStat.getPlanDay().toString())){
                        ApsResourceDateStat apsResourceDateStatTemp = dayMap.get(apsResourceDateStat.getPlanDay().toString());
                        if("month".equals(apsGasPipingRouteStat.getSearchType())){
                            apsResourceDateStatTemp.setDesignTimes(apsGasPipingPlanMap.get(processName+"-"+apsResourceDateStat.getPlanDay().toString().substring(0,7))!=null?apsGasPipingPlanMap.get(processName+"-"+apsResourceDateStat.getPlanDay().toString().substring(0,7)).getMonthProduceAllNum():new BigDecimal(0));
                        }else{
                            dayMap.put(apsResourceDateStat.getPlanDay().toString(), apsResourceDateStat);
                            apsResourceDateStatTemp.setDesignTimes(apsGasPipingPlanMap.get(processName+"-"+apsResourceDateStat.getPlanDay().toString().substring(0,7))!=null?apsGasPipingPlanMap.get(processName+"-"+apsResourceDateStat.getPlanDay().toString().substring(0,7)).getDayProduceAllNum():new BigDecimal(0));
                        }
                        apsResourceDateStatTemp.setRequireTimes(apsResourceDateStatTemp.getRequireTimes().add(apsResourceDateStat.getRequireTimes()));
                        if(apsResourceDateStatTemp.getDesignTimes().compareTo(BigDecimal.ZERO) > 0){
                            apsResourceDateStatTemp.setCapacityLoad(apsResourceDateStatTemp.getRequireTimes()
                                    .divide(apsResourceDateStatTemp.getDesignTimes(), 2, RoundingMode.HALF_UP)
                                    .multiply(new BigDecimal(100)));
                        }else{
                            apsResourceDateStatTemp.setCapacityLoad(new BigDecimal(0));
                        }
                        apsResourceDateStatTemp.setResourceGroupName(processName);
                        apsResourceDateStatTemp.setPlanDay(apsResourceDateStat.getPlanDay());
                        dayMap.put(apsResourceDateStat.getPlanDay().toString(), apsResourceDateStatTemp);
                    }else{
                        dayMap.put(apsResourceDateStat.getPlanDay().toString(), apsResourceDateStat);
                    }
                });
                if("month".equals(apsGasPipingRouteStat.getSearchType())){
                    List<ApsResourceDateStat> tempList = new ArrayList<>();
                    dayMap.forEach((key, value) -> {
                        tempList.add(value);
                    });
                    processMapMonth.put(processName, tempList);
                }
                List<ApsResourceDateStat> tempList = new ArrayList<>();
                dayMap.forEach((key, value) -> {
                    tempList.add(value);
                });
                HashMap<String, List<ApsResourceDateStat>> temp = new HashMap<>();
                temp.put(processName, tempList);
                processList.add(temp);
            });
            //排序时间标题
            List<String> sortedStartPlanTimeList = new ArrayList<>(startPlanTimeSet);
            Collections.sort(sortedStartPlanTimeList);
//            processMap.forEach((processName, apsResourceDateStatList) -> {
//                HashMap<String, ApsResourceDateStat> dayMap = new HashMap<>();
//                apsResourceDateStatList.forEach(apsResourceDateStat -> {
//                    startPlanTimeSet.add(apsResourceDateStat.getPlanDay().toString());
//                    if(dayMap.containsKey(apsResourceDateStat.getPlanDay().toString())){
//                        ApsResourceDateStat apsResourceDateStatTemp = dayMap.get(apsResourceDateStat.getPlanDay().toString());
//                        if("day".equals(apsGasPipingRouteStat.getSearchType())){
//                            apsResourceDateStatTemp.setDesignTimes(apsResourceDateStatTemp.getDesignTimes()+apsResourceDateStat.getDesignTimes());
//                        }else if("month".equals(apsGasPipingRouteStat.getSearchType())){
//                            apsResourceDateStatTemp.setDesignTimes(apsGasPipingPlanMap.get(processName)!=null?apsGasPipingPlanMap.get(processName).getMonthProduceAllNum().intValue():0);
//                        }
//                        apsResourceDateStatTemp.setRequireTimes(apsResourceDateStatTemp.getRequireTimes()+apsResourceDateStat.getRequireTimes());
//                        if(apsResourceDateStatTemp.getDesignTimes()!=0){
//                            apsResourceDateStatTemp.setCapacityLoad(BigDecimal.valueOf(apsResourceDateStatTemp.getRequireTimes()/apsResourceDateStatTemp.getDesignTimes()* 100L));
//                        }
//                        apsResourceDateStatTemp.setResourceGroupName(processName);
//                        dayMap.put(apsResourceDateStat.getPlanDay().toString(), apsResourceDateStatTemp);
//                    }else{
//                        dayMap.put(apsResourceDateStat.getPlanDay().toString(), apsResourceDateStat);
//                    }
//                });
//                JSONArray tempList = new JSONArray();
//                dayMap.forEach((key, value) -> {
//                    JSONObject temp = new JSONObject();
//                    temp.put("planDay", key);
//                    temp.put("designTimes", value.getDesignTimes());
//                    temp.put("requireTimes", value.getRequireTimes());
//                    temp.put("capacityLoad", value.getCapacityLoad());
//                    temp.put("resourceGroupName", value.getResourceGroupName());
//                    tempList.add(temp);
//                });
//                processData.add(new JSONObject().put(processName, tempList));
//            });
            if("month".equals(apsGasPipingRouteStat.getSearchType())){
                for (String key : processMapMonth.keySet()) {
                    HashMap<String, List<ApsResourceDateStat>> temp = new HashMap<>();
                    temp.put(key, processMapMonth.get(key));
                    processListMonth.add(temp);
            for (int i=0;i<processList.size();i++){
                HashMap<String, List<ApsResourceDateStat>> temp = processList.get(i);
                for (Map.Entry<String, List<ApsResourceDateStat>> entry : temp.entrySet()){
                    List<ApsResourceDateStat> apsResourceDateStatList = entry.getValue();
                    String key = entry.getKey();
                    List<ApsResourceDateStat> crtList = new ArrayList<>();
                    for(String tempTime:sortedStartPlanTimeList) {
                        if("month".equals(apsGasPipingRouteStat.getSearchType())){
                            tempTime += "-01";
                        }
                        LocalDate crtDate = LocalDate.parse(tempTime, formatter);
                        Optional<ApsResourceDateStat> first = apsResourceDateStatList.stream().filter(x -> x.getPlanDay().equals(crtDate)).findFirst();
                        if (first.isPresent()) {
                            ApsResourceDateStat apsResourceDateStat = first.get();
                            crtList.add(apsResourceDateStat);
                        } else {
                            ApsResourceDateStat apsResourceDateStat = new ApsResourceDateStat();
                            apsResourceDateStat.setPlanDay(LocalDate.parse(tempTime, formatter));
                            if ("month".equals(apsGasPipingRouteStat.getSearchType())) {
                                apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(entry.getKey()+"-"+tempTime.substring(0,7)) != null ? apsGasPipingPlanMap.get(entry.getKey()+"-"+tempTime.substring(0,7)).getMonthProduceAllNum() : new BigDecimal(0));
                            } else {
                                apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(entry.getKey()+"-"+tempTime.substring(0,7)) != null ? apsGasPipingPlanMap.get(entry.getKey()+"-"+tempTime.substring(0,7)).getDayProduceAllNum() : new BigDecimal(0));
                            }
                            apsResourceDateStat.setRequireTimes(new BigDecimal(0));
                            apsResourceDateStat.setCapacityLoad(new BigDecimal(0));
                            apsResourceDateStat.setResourceName(entry.getKey());
                            apsResourceDateStat.setResourceGroupName(entry.getKey());
                            apsResourceDateStatList.add(apsResourceDateStat);
                            crtList.add(apsResourceDateStat);
                        }
                        temp.put(entry.getKey(), crtList);
                        processList.set(i, temp);
                    }
                }
                result.put("planTable", processListMonth);
            }else{
                for (String key : processMap.keySet()) {
                    HashMap<String, List<ApsResourceDateStat>> temp = new HashMap<>();
                    temp.put(key, processMap.get(key));
                    processList.add(temp);
                }
                result.put("planTable", processList);
            }
            result.put("planTable", processList);
            result.put("planTitle", sortedStartPlanTimeList);
        } catch (Exception e) {
            e.printStackTrace();
@@ -431,8 +476,8 @@
                    dataRow.createCell(0).setCellValue(resourceName);
                    for (int j = 0; j < resourceDateStats.size(); j++) {
                        ApsResourceDateStat apsResourceDateStat = resourceDateStats.get(j);
                        dataRow.createCell(j*3+1).setCellValue(apsResourceDateStat.getDesignTimes());
                        dataRow.createCell(j*3+2).setCellValue(apsResourceDateStat.getRequireTimes());
                        dataRow.createCell(j*3+1).setCellValue(apsResourceDateStat.getDesignTimes().doubleValue());
                        dataRow.createCell(j*3+2).setCellValue(apsResourceDateStat.getRequireTimes().doubleValue());
                        if(apsResourceDateStat.getCapacityLoad()!=null){
                            dataRow.createCell(j*3+3).setCellValue(apsResourceDateStat.getCapacityLoad().doubleValue()+"%");
                        }else{
@@ -469,4 +514,213 @@
        styles.put("title", style);
        return styles;
    }
    public static List<String> getYearMonthsInRange(YearMonth start, YearMonth end) {
        List<String> yearMonths = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
        while (!start.isAfter(end)) {
            yearMonths.add(start.format(formatter));
            start = start.plusMonths(1);
        }
        return yearMonths;
    }
    @Override
    public void saveGasPipingProcessStat(){
        try {
            String batchNum = IdUtils.fastSimpleUUID();
            List<ApsGasPipingRouteStat> tempList = apsGasPipingRouteStatMapper.queryTempStat();
            Map<String, List<ApsGasPipingRouteStat>> groupByOrderNo = tempList.stream().collect(groupingBy(ApsGasPipingRouteStat::getWorkOrderNo));
            Boolean hasBefore = false;
            LocalDateTime now = LocalDateTime.now();
            for (Map.Entry<String, List<ApsGasPipingRouteStat>> entry : groupByOrderNo.entrySet()) {
                List<ApsGasPipingRouteStat> statPerOrder = entry.getValue();
                /*num 为根据完工时间排序出的序号,按此排序,可保证是按完工时间倒叙排列*/
                statPerOrder.sort((a, b)->a.getNum().compareTo(b.getNum()));
                ApsGasPipingRouteStat last=null;
                for (int i = 0; i <statPerOrder.size(); i++) {
                    ApsGasPipingRouteStat stat = statPerOrder.get(i);
                    stat.setId(IdUtils.fastSimpleUUID());
                    stat.setBatchNumber(batchNum);
                    stat.setCreateBy(SecurityUtils.getUsername());
                    stat.setWarning(false);
                    if(i==0){
                        Date orderPlanEndDay = stat.getOrderPlanEndDay();
                        LocalDateTime transLocalDateTime = transLocalDateTime(orderPlanEndDay);
                        LocalTime endOfDay = LocalTime.of(23, 59, 59);
                        LocalDateTime orderPlanEndDayLocalDateTime =  LocalDateTime.of( transLocalDateTime.toLocalDate(), endOfDay);
                        if(orderPlanEndDayLocalDateTime.isBefore(now)){
                            hasBefore = true;
                            stat.setWarning(true);
                            stat.setProcessPlanEndDay(transDate(now));
                            stat.setProcessPlanStartDay(transDate(now));
                        }else {
                            /*计划完工日=钣金计划工单完成时间*/
                            stat.setProcessPlanEndDay(transDate(orderPlanEndDayLocalDateTime));
                            /*计划开工日=钣金计划工单完成时间 -  工序总工时*/
                            long seconds = stat.getProcessTotalTime().multiply(new BigDecimal(60)).multiply(new BigDecimal(60)).longValue();
                            LocalDateTime lastPlanStartDt = orderPlanEndDayLocalDateTime.minusSeconds(seconds);
                            if(lastPlanStartDt.isBefore(now)){
                                hasBefore = true;
                                stat.setProcessPlanStartDay(transDate(now));
                            }else {
                                stat.setProcessPlanStartDay(transDate(lastPlanStartDt));
                            }
                        }
                    }
                    /*当工艺工序号 >= 工单当前工序 代表是未来工序,才进行计划开工日 和计划完工日的计算
                     * 当工艺工序号 < 工单当前工序  过去工序,不进行计算
                     * */
                    if( stat.getRouteProcessNumber().compareTo(stat.getCurrentProcessNumber())>=0){
                        /*倒排时 下一道工序存在 比当前时间小的计划时间,则当前计划开始和结束时间都是当前时间*/
                        if(hasBefore){
                            stat.setWarning(true);
                            stat.setProcessPlanEndDay(transDate(now));
                            stat.setProcessPlanStartDay(transDate(now));
                        }else{
                            /*下一道工序计划时间都正常时,*/
                            if (last != null) {
                                /*当前工序结束时间=下一道工序的开始时间*/
                                stat.setProcessPlanEndDay(last.getProcessPlanStartDay());
                                /*开始时间=结束时间-总工时*/
                                long seconds = stat.getProcessTotalTime().multiply(new BigDecimal(60)).multiply(new BigDecimal(60)).longValue();
                                LocalDateTime crtStartDt = transLocalDateTime(last.getProcessPlanStartDay()).minusSeconds(seconds);
                                /*如果开始时间小于当前时间*/
                                if(crtStartDt.isBefore(now)){
                                    hasBefore=true;
                                    stat.setWarning(true);
                                    stat.setProcessPlanStartDay(transDate(now));
                                }else {
                                    stat.setProcessPlanStartDay(transDate(crtStartDt));
                                }
                            }
                        }
                    }
                    last = stat;
                    apsGasPipingRouteStatMapper.insertApsGasPipingRouteStat(stat);
                }
                hasBefore=false;
            }
            apsGasPipingRouteStatMapper.deleteApsGasPipingRouteStatByBatchNum(batchNum);
        } catch (Exception e) {
            e.printStackTrace();
        }
    };
    private Date transDate(LocalDateTime localDateTime){
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }
    private LocalDateTime transLocalDateTime(Date date){
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }
    /**
     * 保存钣金统计数据
     */
    @Transactional
    @Override
    public void saveGasPipingRoutStateList() {
        String batchNum = IdUtils.fastSimpleUUID();
        List<ApsGasPipingRouteStat> tempList = apsGasPipingRouteStatMapper.queryTempStat();
        Map<String, List<ApsGasPipingRouteStat>> groupByOrderNo = tempList.stream().collect(groupingBy(ApsGasPipingRouteStat::getWorkOrderNo));
        LocalDateTime now = LocalDateTime.now();
        /*待保存的数据*/
        List<ApsGasPipingRouteStat> cptStateList = new ArrayList<>();
        for (Map.Entry<String, List<ApsGasPipingRouteStat>> entry : groupByOrderNo.entrySet()) {
            List<ApsGasPipingRouteStat> statPerOrder = entry.getValue();
            /*num 为根据完工时间排序出的序号,按此排序,可保证是按完工时间倒叙排列*/
            statPerOrder.sort((a, b)->a.getNum().compareTo(b.getNum()));
            ApsGasPipingRouteStat last=null;
            /*当前工序是否存在 计划开工时间 小于 当前的时间,如果存在后续设置为当前时间*/
            boolean hasBefore = false;
            for (int i = 0; i <statPerOrder.size(); i++) {
                ApsGasPipingRouteStat stat = statPerOrder.get(i);
                stat.setId(String.valueOf(IdUtil.getSnowflakeNextId()));
                stat.setBatchNumber(batchNum);
                stat.setCreateTime(DateUtils.getNowDate());
                stat.setCreateBy(SecurityUtils.getUsername());
                stat.setWarning(false);
                stat.setDelFlag("0");
                if(i==0){
                    Date orderPlanEndDay = stat.getOrderPlanEndDay();
                    LocalDateTime transLocalDateTime = transLocalDateTime(orderPlanEndDay);
                    LocalTime endOfDay = LocalTime.of(23, 59, 59);
                    LocalDateTime orderPlanEndDayLocalDateTime =  LocalDateTime.of( transLocalDateTime.toLocalDate(), endOfDay);
                    if(orderPlanEndDayLocalDateTime.isBefore(now)){
                        hasBefore = true;
                        stat.setWarning(true);
                        stat.setProcessPlanEndDay(transDate(now));
                        stat.setProcessPlanStartDay(transDate(now));
                    }else {
                        /*计划完工日=钣金计划工单完成时间*/
                        stat.setProcessPlanEndDay(transDate(orderPlanEndDayLocalDateTime));
                        /*计划开工日=钣金计划工单完成时间 -  工序总工时*/
                        long seconds = stat.getProcessTotalTime().multiply(new BigDecimal(60)).multiply(new BigDecimal(60)).longValue();
                        LocalDateTime lastPlanStartDt = orderPlanEndDayLocalDateTime.minusSeconds(seconds);
                        if(lastPlanStartDt.isBefore(now)){
                            hasBefore = true;
                            stat.setProcessPlanStartDay(transDate(now));
                        }else {
                            stat.setProcessPlanStartDay(transDate(lastPlanStartDt));
                        }
                    }
                }
                /*当工艺工序号 >= 工单当前工序 代表是未来工序,才进行计划开工日 和计划完工日的计算
                 * 当工艺工序号 < 工单当前工序  过去工序,不进行计算
                 * */
                if( stat.getRoadProcessNumber().compareTo(stat.getCurrentProcessNumber())>=0){
                    /*倒排时 下一道工序存在 比当前时间小的计划时间,则当前计划开始和结束时间都是当前时间*/
                    if(hasBefore){
                        stat.setWarning(true);
                        stat.setProcessPlanEndDay(transDate(now));
                        stat.setProcessPlanStartDay(transDate(now));
                    }else{
                        /*下一道工序计划时间都正常时,*/
                        if (last != null) {
                            /*当前工序结束时间=下一道工序的开始时间*/
                            stat.setProcessPlanEndDay(last.getProcessPlanStartDay());
                            /*开始时间=结束时间-总工时*/
                            long seconds = stat.getProcessTotalTime().multiply(new BigDecimal(60)).multiply(new BigDecimal(60)).longValue();
                            LocalDateTime crtStartDt = transLocalDateTime(last.getProcessPlanStartDay()).minusSeconds(seconds);
                            /*如果开始时间小于当前时间*/
                            if(crtStartDt.isBefore(now)){
                                hasBefore=true;
                                stat.setWarning(true);
                                stat.setProcessPlanStartDay(transDate(now));
                            }else {
                                stat.setProcessPlanStartDay(transDate(crtStartDt));
                            }
                        }
                    }
                }
               if(stat.getProcessPlanStartDay()!=null){
                   String[] strNow = new SimpleDateFormat("yyyy-MM-dd").format(stat.getProcessPlanStartDay()).toString().split("-");
                   stat.setPlanStartYear(strNow[0]);
                   stat.setPlanStartMonth(strNow[1]);
                   stat.setPlanStartDay(strNow[2]);
               }
                last = stat;
                cptStateList.add(stat);
            }
        }
        // 批量插入以提高性能
        if (!cptStateList.isEmpty()) {
            int batchSize = 1000;
            int size = cptStateList.size();
            for (int i = 0; i < size; i += batchSize) {
                int end = Math.min(i + batchSize, size);
                List<ApsGasPipingRouteStat> batch = cptStateList.subList(i, end);
                apsGasPipingRouteStatMapper.insertApsGasPipingRouteStatBatch(batch);
                log.info("批量插入数据,开始位置:{},结束位置:{}", i, end);
            }
        }
        apsGasPipingRouteStatMapper.deleteApsGasPipingRouteStatByBatchNum(batchNum);
        log.info("批量插入数据完成,batchNum:"+batchNum);
    }
}