sfd
2025-05-26 2a64b537e8e3bce9ce030585a3da17d48379c0ad
aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsGasPipingRouteStatServiceImpl.java
@@ -1,16 +1,17 @@
package com.aps.core.service.impl;
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;
import com.aps.common.security.utils.SecurityUtils;
import com.aps.core.domain.*;
import com.aps.core.mapper.ApsGasPipelineCapacityPlanMapper;
import com.aps.core.mapper.ApsGasPipingPlanMapper;
import com.aps.core.mapper.ApsGasPipingRouteStatMapper;
import com.aps.core.domain.ApsPlate.ApsPlateStandardRequireError;
import com.aps.core.mapper.*;
import com.aps.core.service.IApsGasMaterialUsageService;
import com.aps.core.service.IApsGasPipingRouteStatService;
import com.aps.core.service.IApsStandardProcessService;
import com.aps.core.mapper.ApsPlateStandardRequireErrorMapper;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
@@ -20,18 +21,20 @@
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.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 java.util.stream.Collectors;
import static java.util.stream.Collectors.groupingBy;
/**
 * 气体管路产能负载统计Service业务层处理
@@ -57,6 +60,9 @@
    @Autowired
    private IApsStandardProcessService apsStandardProcessService;
    @Autowired
    private ApsPlateStandardRequireErrorMapper apsPlateStandardRequireErrorMapper;
    /**
     * 查询气体管路产能负载统计
@@ -148,6 +154,7 @@
                apsProcessRoutes.sort((a, b)->b.getProcessNumber().compareTo(a.getProcessNumber()));
                //是否找到当前工序
                boolean isCurrentProcess = false;
                boolean lastProcessStartTimeIsBeforeNow = false;
                ApsGasPipingRouteStat preApsProcessRoute = null;
                for (int i=0;i<apsProcessRoutes.size();i++){
                    ApsProcessRoute apsProcessRoute = apsProcessRoutes.get(i);
@@ -163,7 +170,7 @@
                    //工序名称
                    apsGasPipingRouteStat.setProcessName(apsProcessRoute.getProcessName());
                    //工序号
                    apsGasPipingRouteStat.setRoadProcessNumber(apsProcessRoute.getProcessNumber());
                    apsGasPipingRouteStat.setRoadProcessNumber( new BigDecimal(apsProcessRoute.getProcessNumber()) );
                    //标准工时
                    apsGasPipingRouteStat.setStandardTime(apsProcessRoute.getStandardTime());
                    //专业
@@ -171,28 +178,34 @@
                    //工序总工时 等于 标准工时*生产数量
                    apsGasPipingRouteStat.setProcessTotalTime(apsProcessRoute.getStandardTime().multiply(apsGasPipingPlan.getProductionQuantity()));
                    //计划开工日 如果是当前序
                    if(apsGasPipingRouteStat.getCurrentProcessNumber().toString().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());
                        }
                        apsGasPipingRouteStat.setProcessPlanEndDay(apsProcessRoute.getProcessPlanEndDay());
                    if(apsGasPipingPlan.getProcessNumber().equals(apsProcessRoute.getProcessNumber())) {
                        isCurrentProcess = true;
                    }else{
                        // 上一道工序的结束时间 = 上一道工序的开始时间 + 上一道工序的总工时
                        if(i==0){
                            apsGasPipingRouteStat.setProcessPlanEndDay(apsGasPipingPlan.getPlanEndDay());
                            LocalDateTime planEndDay = apsGasPipingPlan.getPlanEndDay().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()));
                    }
                    // 上一道工序的结束时间 = 上一道工序的开始时间 + 上一道工序的总工时
                    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{
                            apsGasPipingRouteStat.setProcessPlanEndDay(preApsProcessRoute.getProcessPlanEndDay());
                            LocalDateTime planEndDay = apsGasPipingPlan.getPlanEndDay().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                            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()));
@@ -242,8 +255,7 @@
        return true;
    }
    @Override
    public JSONObject getCapacityPlanData(ApsGasPipingRouteStat apsGasPipingRouteStat) {
    public JSONObject getCapacityPlanDataBackup(ApsGasPipingRouteStat apsGasPipingRouteStat) {
        JSONObject result = new JSONObject();
        YearMonth yearMonth = YearMonth.parse(apsGasPipingRouteStat.getSearchEndDate());
        int daysInMonth = yearMonth.lengthOfMonth();
@@ -294,37 +306,42 @@
                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.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()+"-"+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));
                }
                List<ApsResourceDateStat> apsResourceDateStatList = new ArrayList<>();
                if(processMap.containsKey(apsGasPipingRouteStatTemp.getProcessName())){
                    apsResourceDateStatList = processMap.get(apsGasPipingRouteStatTemp.getProcessName());
                    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()+"-"+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);
                }
                apsResourceDateStatList.add(apsResourceDateStat);
                processMap.put(apsGasPipingRouteStatTemp.getProcessName(), apsResourceDateStatList);
            }
            //聚合每道工序的开工时间和产能
            processMap.forEach((processName, apsResourceDateStatList) -> {
@@ -391,6 +408,292 @@
                            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", processList);
            result.put("planTitle", sortedStartPlanTimeList);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    @Override
    public JSONObject getCapacityPlanData(ApsGasPipingRouteStat apsGasPipingRouteStat) {
        JSONObject result = new JSONObject();
        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<>();
            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 -> {
                String key = apsGasPipelineCapacityPlan.getProcessName() + "-" + apsGasPipelineCapacityPlan.getOrgCode() + "-" + apsGasPipelineCapacityPlan.getYear() + "-" + (Integer.parseInt(apsGasPipelineCapacityPlan.getMonth())<10?"0"+apsGasPipelineCapacityPlan.getMonth():apsGasPipelineCapacityPlan.getMonth());
                apsGasPipingPlanMap.put(key, apsGasPipelineCapacityPlan);
            });
            //计算日产能数据
            DateTimeFormatter formatter = null;
            List<ApsGasPipingRouteStat> apsGasPipingRouteStats;
            SimpleDateFormat simpleDateFormat = null;
            apsGasPipingRouteStat.setSearchStartDate(apsGasPipingRouteStat.getSearchStartDate()+"-01 00:00:00");
            apsGasPipingRouteStat.setSearchEndDate(apsGasPipingRouteStat.getSearchEndDate()+"-"+ daysInMonth +" 23:59:59");
            if("day".equals(apsGasPipingRouteStat.getSearchType())){
                formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            }else if("month".equals(apsGasPipingRouteStat.getSearchType())){
                formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                simpleDateFormat = new SimpleDateFormat("yyyy-MM");
            }
            ApsGasPipingRouteStat queryStatParam = new ApsGasPipingRouteStat();
            BeanUtils.copyProperties(apsGasPipingRouteStat,queryStatParam);
            queryStatParam.setMajor(apsGasPipingRouteStat.getMajor());
            queryStatParam.setPlant(apsGasPipingRouteStat.getPlant());
            apsGasPipingRouteStats = apsGasPipingRouteStatMapper.selectApsGasPipingRouteStatList(queryStatParam);
            //根据开工日进行升序排序
            apsGasPipingRouteStats.sort((a, b)->a.getProcessPlanStartDay().compareTo(b.getProcessPlanStartDay()));
            //工序开工日期
            String planStartDate = "";
            //统计所有工序对应的开工时间
            for (ApsGasPipingRouteStat apsGasPipingRouteStatTemp : apsGasPipingRouteStats) {
                if(processMap.containsKey(apsGasPipingRouteStatTemp.getProcessName())){
                    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.setPlant(apsGasPipingRouteStatTemp.getPlant());
                    //查询气柜管路产能规划表
                    String capacityKey = apsGasPipingRouteStatTemp.getProcessName() + "-" + apsGasPipingRouteStatTemp.getPlant() + "-" + planStartDate.substring(0, 7);
                    apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(capacityKey)!=null?apsGasPipingPlanMap.get(capacityKey).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));
                    }
                    List<ApsResourceDateStat> apsResourceDateStatList = processMap.get(apsGasPipingRouteStatTemp.getProcessName());
                    apsResourceDateStatList.add(apsResourceDateStat);
                    processMap.put(apsGasPipingRouteStatTemp.getProcessName(), apsResourceDateStatList);
                }
            }
            //聚合每道工序的开工时间和产能
            for (Map.Entry<String, List<ApsResourceDateStat>> entry : processMap.entrySet()) {
                String processName = entry.getKey();
                List<ApsResourceDateStat> apsResourceDateStatList = entry.getValue();
                if("day".equals(apsGasPipingRouteStat.getSearchType())) {
                    // 按天统计时保持原有逻辑,不按工厂分组
                    LinkedHashMap<String, ApsResourceDateStat> dayMap = new LinkedHashMap<>();
                    // 首先,为所有日期创建初始记录
                    for(String date : startPlanTimeSet) {
                        ApsResourceDateStat initStat = new ApsResourceDateStat();
                        initStat.setPlanDay(LocalDate.parse(date, formatter));
                        initStat.setResourceName(processName);
                        initStat.setResourceGroupName(processName);
                        initStat.setRequireTimes(new BigDecimal(0));
                        String capacityKey = processName + "-" + date.substring(0,7);
                        initStat.setDesignTimes(apsGasPipingPlanMap.get(capacityKey)!=null?apsGasPipingPlanMap.get(capacityKey).getDayProduceAllNum():new BigDecimal(0));
                        initStat.setCapacityLoad(new BigDecimal(0));
                        dayMap.put(date, initStat);
                    }
                    // 然后处理实际数据
                    for (ApsResourceDateStat apsResourceDateStat : apsResourceDateStatList) {
                        String dateKey = apsResourceDateStat.getPlanDay().toString();
                        if(dayMap.containsKey(dateKey)){
                            ApsResourceDateStat apsResourceDateStatTemp = dayMap.get(dateKey);
                            String capacityKey = processName + "-"+ apsResourceDateStat.getPlant() + "-" + dateKey.substring(0,7);
                            apsResourceDateStatTemp.setDesignTimes(apsGasPipingPlanMap.get(capacityKey)!=null?apsGasPipingPlanMap.get(capacityKey).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(dateKey, apsResourceDateStatTemp);
                        }
                    }
                    List<ApsResourceDateStat> tempList = new ArrayList<>(dayMap.values());
                    HashMap<String, List<ApsResourceDateStat>> temp = new HashMap<>();
                    temp.put(processName, tempList);
                    processList.add(temp);
                } else {
                    // 按月统计时才按工厂分组
                    if (apsResourceDateStatList.isEmpty()) {
                        // 从产能规划数据中获取所有的工厂
                        Set<String> plants = apsGasPipelineCapacityPlanList.stream()
                                .filter(plan -> plan.getProcessName().equals(processName))
                                .map(ApsGasPipelineCapacityPlan::getOrgCode)
                                .filter(orgCode -> orgCode != null && !orgCode.trim().isEmpty())
                                .collect(Collectors.toSet());
                        // 如果没有找到任何有效工厂,跳过这个工序
                        if (plants.isEmpty()) {
                            continue;
                        }
                        // 为每个工厂创建空记录
                        for (String plant : plants) {
                            LinkedHashMap<String, ApsResourceDateStat> dayMap = new LinkedHashMap<>();
                            // 为每个月份创建记录
                            for(String monthDate : startPlanTimeSet) {
                                String tempTime = monthDate + "-01";
                                ApsResourceDateStat apsResourceDateStat = new ApsResourceDateStat();
                                apsResourceDateStat.setPlanDay(LocalDate.parse(tempTime, formatter));
                                apsResourceDateStat.setResourceName(processName);
                                apsResourceDateStat.setResourceGroupName(processName + "-" + plant);
                                apsResourceDateStat.setPlant(plant);
                                apsResourceDateStat.setRequireTimes(new BigDecimal(0));
                                String capacityKey = processName + "-" + plant + "-" + monthDate;
                                apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(capacityKey)!=null?apsGasPipingPlanMap.get(capacityKey).getMonthProduceAllNum():new BigDecimal(0));
                                apsResourceDateStat.setCapacityLoad(new BigDecimal(0));
                                dayMap.put(monthDate, apsResourceDateStat);
                            }
                            List<ApsResourceDateStat> tempList = new ArrayList<>(dayMap.values());
                            HashMap<String, List<ApsResourceDateStat>> temp = new HashMap<>();
                            temp.put(processName + "_" + plant, tempList);
                            processList.add(temp);
                        }
                    } else {
                        // 按工厂分组,并过滤掉plant为null或空字符串的记录
                        Map<String, List<ApsResourceDateStat>> plantGroups = apsResourceDateStatList.stream()
                                .filter(stat -> stat.getPlant() != null && !stat.getPlant().trim().isEmpty())
                                .collect(groupingBy(ApsResourceDateStat::getPlant));
                        // 如果过滤后没有有效的工厂数据,跳过这个工序
                        if (plantGroups.isEmpty()) {
                            continue;
                        }
                        // 对每个工厂的数据进行处理
                        for (Map.Entry<String, List<ApsResourceDateStat>> plantEntry : plantGroups.entrySet()) {
                            String plant = plantEntry.getKey();
                            // 再次确认plant不为空
                            if (plant == null || plant.trim().isEmpty()) {
                                continue;
                            }
                            List<ApsResourceDateStat> plantStats = plantEntry.getValue();
                            LinkedHashMap<String, ApsResourceDateStat> dayMap = new LinkedHashMap<>();
                            // 首先为所有月份创建初始记录
                            for(String monthDate : startPlanTimeSet) {
                                String tempTime = monthDate + "-01";
                                ApsResourceDateStat initStat = new ApsResourceDateStat();
                                initStat.setPlanDay(LocalDate.parse(tempTime, formatter));
                                initStat.setResourceName(processName);
                                initStat.setResourceGroupName(processName + "-" + plant);
                                initStat.setPlant(plant);
                                initStat.setRequireTimes(new BigDecimal(0));
                                String capacityKey = processName + "-" + plant + "-" + monthDate;
                                initStat.setDesignTimes(apsGasPipingPlanMap.get(capacityKey)!=null?apsGasPipingPlanMap.get(capacityKey).getMonthProduceAllNum():new BigDecimal(0));
                                initStat.setCapacityLoad(new BigDecimal(0));
                                dayMap.put(monthDate, initStat);
                            }
                            // 然后处理实际数据
                            for (ApsResourceDateStat stat : plantStats) {
                                String monthKey = stat.getPlanDay().toString().substring(0, 7);
                                if (dayMap.containsKey(monthKey)) {
                                    ApsResourceDateStat existingStat = dayMap.get(monthKey);
                                    String capacityKey = processName + "-" + plant + "-" + monthKey;
                                    existingStat.setDesignTimes(apsGasPipingPlanMap.get(capacityKey)!=null?apsGasPipingPlanMap.get(capacityKey).getMonthProduceAllNum():new BigDecimal(0));
                                    existingStat.setRequireTimes(existingStat.getRequireTimes().add(stat.getRequireTimes()));
                                    if(existingStat.getDesignTimes().compareTo(BigDecimal.ZERO) > 0){
                                        existingStat.setCapacityLoad(existingStat.getRequireTimes()
                                                .divide(existingStat.getDesignTimes(), 2, RoundingMode.HALF_UP)
                                                .multiply(new BigDecimal(100)));
                                    }
                                }
                            }
                            List<ApsResourceDateStat> tempList = new ArrayList<>(dayMap.values());
                            HashMap<String, List<ApsResourceDateStat>> temp = new HashMap<>();
                            temp.put(processName + "_" + plant, tempList);
                            processList.add(temp);
                        }
                    }
                }
            }
            //排序时间标题
            List<String> sortedStartPlanTimeList = new ArrayList<>(startPlanTimeSet);
            Collections.sort(sortedStartPlanTimeList);
            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));
                            String[] keyParts = key.split("-");
                            String processNamePart = keyParts[0];
                            String plantPart = keyParts[1];
                            String capacityKey = processNamePart + "-" + plantPart + "-" + tempTime.substring(0,7);
                            if ("month".equals(apsGasPipingRouteStat.getSearchType())) {
                                apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(capacityKey) != null ? apsGasPipingPlanMap.get(capacityKey).getMonthProduceAllNum() : new BigDecimal(0));
                            } else {
                                apsResourceDateStat.setDesignTimes(apsGasPipingPlanMap.get(capacityKey) != null ? apsGasPipingPlanMap.get(capacityKey).getDayProduceAllNum() : new BigDecimal(0));
                            }
                            apsResourceDateStat.setRequireTimes(new BigDecimal(0));
                            apsResourceDateStat.setCapacityLoad(new BigDecimal(0));
                            apsResourceDateStat.setResourceName(processNamePart);
                            apsResourceDateStat.setResourceGroupName(key);
                            apsResourceDateStat.setPlant(plantPart);
                            apsResourceDateStatList.add(apsResourceDateStat);
                            crtList.add(apsResourceDateStat);
                        }
@@ -512,4 +815,1233 @@
        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);
    }
    /**
     * 根据手工气体预测数据和手工气体工单数据生成统计数据
     *
     * @return 结果
     */
    @Override
    @Transactional
    public int generateGasPipingRouteStatData() {
        int count = 0;
        // 清空之前的数据
        apsGasPipingRouteStatMapper.deleteAll();
        // 生成批次号
        String batchNumber = IdUtils.fastSimpleUUID();
        List<ApsGasPipingRouteStat> statList = new ArrayList<>();
        // 处理手工气体预测数据 - 使用联合查询获取所有相关数据
        List<Map<String, Object>> predictionDataList = apsGasPipingRouteStatMapper.selectPredictionRouteData();
        // 按物料代码分组,便于处理同一物料的不同工序
        Map<String, List<Map<String, Object>>> predictionGroups = predictionDataList.stream()
                .collect(Collectors.groupingBy(data -> data.get("material_code").toString()));
        // 处理每个物料的工艺路线
        for (String materialCode : predictionGroups.keySet()) {
            List<Map<String, Object>> materialData = predictionGroups.get(materialCode);
            // 按工序号排序
            materialData.sort((a, b) -> {
                String numA = a.get("process_number").toString();
                String numB = b.get("process_number").toString();
                return numA.compareTo(numB);
            });
            // 获取所有工序的信息并创建统计记录
            List<ApsGasPipingRouteStat> processList = new ArrayList<>();
            for (Map<String, Object> data : materialData) {
                ApsGasPipingRouteStat stat = new ApsGasPipingRouteStat();
                stat.setId(IdUtils.fastSimpleUUID());
                stat.setWorkOrderNo(""); // 预测数据没有工单号
                stat.setItemNumber(data.get("material_code").toString());
                stat.setProcessName(data.get("process_name").toString());
                stat.setRoadProcessNumber(new BigDecimal(data.get("process_number").toString()));
                // 生产数量和标准工时
                BigDecimal quantity = new BigDecimal(data.get("predict_quantity").toString()).setScale(4, RoundingMode.HALF_UP);
                BigDecimal standardTime = new BigDecimal(data.get("standard_time").toString()).setScale(4, RoundingMode.HALF_UP);
                stat.setProductionQuantity(quantity);
                stat.setStandardTime(standardTime);
                stat.setProcessTotalTime(standardTime.multiply(quantity).setScale(4, RoundingMode.HALF_UP));
                // 工厂、专业和车间
                stat.setPlant(data.get("factory").toString());
                stat.setMajor(data.get("domain") != null ? data.get("domain").toString() : "");
                stat.setWorkshop(data.get("workshop") != null ? data.get("workshop").toString() : "");
                // 批次号和创建信息
                stat.setBatchNumber(batchNumber);
                stat.setCreateBy(SecurityUtils.getUsername());
                stat.setCreateTime(truncateToSeconds(DateUtils.getNowDate()));
                processList.add(stat);
            }
            // 计算计划完工日和计划开工日
            if (!processList.isEmpty()) {
                int lastIndex = processList.size() - 1;
                // 最后一道工序的计划完工日期为预测日期
                ApsGasPipingRouteStat lastProcess = processList.get(lastIndex);
                Date predictDate = (Date) materialData.get(lastIndex).get("predict_date");
                lastProcess.setProcessPlanEndDay(truncateToSeconds(predictDate));
                // 标记是否出现过时间冲突的情况
                boolean hasTimeConflict = false;
                // 计算每个工序的计划开工日和完工日 - 从最后一道工序开始倒推
                for (int i = lastIndex; i >= 0; i--) {
                    ApsGasPipingRouteStat current = processList.get(i);
                    // 如果当前是最后一道工序,计划开工日 = 计划完工日 - 工序总工时
                    if (i == lastIndex) {
                        hasTimeConflict = calculateProcessPlanStartDay(current, hasTimeConflict);
                    } else {
                        // 非最后一道工序,计划完工日为下一道工序的计划开工日
                        ApsGasPipingRouteStat next = processList.get(i + 1);
                        current.setProcessPlanEndDay(next.getProcessPlanStartDay());
                        // 如果已经出现时间冲突,后续工序的计划开工日和计划完工日都设为当前时间
                        if (hasTimeConflict) {
                            current.setProcessPlanStartDay(truncateToSeconds(new Date()));
                        } else {
                            // 否则正常计算,并检查是否出现时间冲突
                            hasTimeConflict = calculateProcessPlanStartDay(current, hasTimeConflict);
                        }
                    }
                    // 设置年、月、日
                    setDateComponents(current);
                }
                statList.addAll(processList);
            }
        }
        // 处理手工气体工单数据 - 使用联合查询获取所有相关数据
        List<Map<String, Object>> moDataList = apsGasPipingRouteStatMapper.selectMoRouteData();
        // 获取所有的MO数据,用于检查哪些MO没有关联到工艺路线
        List<Map<String, Object>> allMoData = apsGasPipingRouteStatMapper.selectAllMoData();
        // 记录已关联工艺路线的MO编号
        Set<String> processedMoSet = new HashSet<>();
        // 按工单号分组,便于处理同一工单的不同工序
        Map<String, List<Map<String, Object>>> moGroups = moDataList.stream()
                .collect(Collectors.groupingBy(data -> data.get("work_order_no").toString()));
        // 处理每个工单的工艺路线
        for (String workOrderNo : moGroups.keySet()) {
            List<Map<String, Object>> workOrderData = moGroups.get(workOrderNo);
            // 标记该工单已处理
            processedMoSet.add(workOrderNo);
            // 按工序号排序
            workOrderData.sort((a, b) -> {
                String numA = a.get("process_number").toString();
                String numB = b.get("process_number").toString();
                return numA.compareTo(numB);
            });
            // 获取所有工序的信息并创建统计记录
            List<ApsGasPipingRouteStat> processList = new ArrayList<>();
            for (Map<String, Object> data : workOrderData) {
                ApsGasPipingRouteStat stat = new ApsGasPipingRouteStat();
                stat.setId(IdUtils.fastSimpleUUID());
                stat.setWorkOrderNo(data.get("work_order_no").toString());
                stat.setItemNumber(data.get("material_code").toString());
                stat.setProcessName(data.get("process_name").toString());
                stat.setRoadProcessNumber(new BigDecimal(data.get("process_number").toString()));
                // 生产数量和标准工时
                BigDecimal quantity = new BigDecimal(data.get("quantity").toString()).setScale(4, RoundingMode.HALF_UP);
                BigDecimal standardTime = new BigDecimal(data.get("standard_time").toString()).setScale(4, RoundingMode.HALF_UP);
                stat.setProductionQuantity(quantity);
                stat.setStandardTime(standardTime);
                stat.setProcessTotalTime(standardTime.multiply(quantity).setScale(4, RoundingMode.HALF_UP));
                // 工厂、专业和车间
                stat.setPlant(data.get("factory").toString());
                stat.setMajor(data.get("domain") != null ? data.get("domain").toString() : "");
                stat.setWorkshop(data.get("workshop") != null ? data.get("workshop").toString() : "");
                // 批次号和创建信息
                stat.setBatchNumber(batchNumber);
                stat.setCreateBy(SecurityUtils.getUsername());
                stat.setCreateTime(truncateToSeconds(DateUtils.getNowDate()));
                processList.add(stat);
            }
            // 计算计划完工日和计划开工日
            if (!processList.isEmpty()) {
                int lastIndex = processList.size() - 1;
                // 最后一道工序的计划完工日期为工单计划完工日期
                ApsGasPipingRouteStat lastProcess = processList.get(lastIndex);
                Date planEnd = (Date) workOrderData.get(0).get("plan_end");
                lastProcess.setProcessPlanEndDay(truncateToSeconds(planEnd));
                // 标记是否出现过时间冲突的情况
                boolean hasTimeConflict = false;
                // 计算每个工序的计划开工日和完工日 - 从最后一道工序开始倒推
                for (int i = lastIndex; i >= 0; i--) {
                    ApsGasPipingRouteStat current = processList.get(i);
                    // 如果当前是最后一道工序,计划开工日 = 计划完工日 - 工序总工时
                    if (i == lastIndex) {
                        hasTimeConflict = calculateProcessPlanStartDay(current, hasTimeConflict);
                    } else {
                        // 非最后一道工序,计划完工日为下一道工序的计划开工日
                        ApsGasPipingRouteStat next = processList.get(i + 1);
                        current.setProcessPlanEndDay(next.getProcessPlanStartDay());
                        // 如果已经出现时间冲突,后续工序的计划开工日和计划完工日都设为当前时间
                        if (hasTimeConflict) {
                            current.setProcessPlanStartDay(truncateToSeconds(new Date()));
                        } else {
                            // 否则正常计算,并检查是否出现时间冲突
                            hasTimeConflict = calculateProcessPlanStartDay(current, hasTimeConflict);
                        }
                    }
                    // 设置年、月、日
                    setDateComponents(current);
                }
                statList.addAll(processList);
            }
        }
        // 处理没有关联到工艺路线的MO数据
        List<ApsPlateStandardRequireError> errorList = new ArrayList<>();
        for (Map<String, Object> moData : allMoData) {
            String workOrderNo = moData.get("mo").toString();
            // 如果该工单没有被处理过,说明没有关联到工艺路线
            if (!processedMoSet.contains(workOrderNo)) {
                ApsPlateStandardRequireError error = ApsPlateStandardRequireError.builder()
                        .id(Long.valueOf(IdUtils.fastSimpleUUID().hashCode()))
                        .batchNumber(batchNumber)
                        .requireId(IdUtil.getSnowflakeNextId())
                        .docNum(workOrderNo)
                        .itemNum(moData.get("material_code").toString())
                        .orgCode(moData.get("factory").toString())
                        .message("标准工艺路线不存在")
                        .delFlag("0")
                        .build();
                // 设置基类属性
                error.setCreateBy(SecurityUtils.getUsername());
                error.setCreateTime(truncateToSeconds(DateUtils.getNowDate()));
                errorList.add(error);
            }
        }
        // 批量插入异常数据
        if (!errorList.isEmpty()) {
            apsPlateStandardRequireErrorMapper.batchInsert(errorList);
        }
        // 批量插入数据
        if (!statList.isEmpty()) {
            for (int i = 0; i < statList.size(); i += 500) {
                int endIndex = Math.min(i + 500, statList.size());
                List<ApsGasPipingRouteStat> batch = statList.subList(i, endIndex);
                count += apsGasPipingRouteStatMapper.insertApsGasPipingRouteStatBatch(batch);
            }
        }
        return count;
    }
    /**
     * 计算工序计划开工日,并判断是否发生时间冲突
     *
     * @param stat 当前工序统计对象
     * @param hasTimeConflict 之前是否已经发生时间冲突
     * @return 是否发生时间冲突
     */
    private boolean calculateProcessPlanStartDay(ApsGasPipingRouteStat stat, boolean hasTimeConflict) {
        Date planEndDay = stat.getProcessPlanEndDay();
        if (planEndDay == null) {
            return hasTimeConflict;
        }
        // 计算工序总工时对应的秒数
        long processTotalTimeSeconds = stat.getProcessTotalTime()
                .multiply(BigDecimal.valueOf(60 * 60))
                .longValue();
        // 获取当前时间并精确到秒级别
        Date now = truncateToSeconds(new Date());
        // 计算开工日期并精确到秒级别
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(planEndDay);
        // 分批减去秒数,避免int溢出
        long seconds = processTotalTimeSeconds;
        while (seconds > 0) {
            int step = (seconds > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) seconds;
            calendar.add(Calendar.SECOND, -step);
            seconds -= step;
        }
        Date calculatedStartDay = truncateToSeconds(calendar.getTime());
        // 如果计划完工日期小于等于当前时间,则计划开工日也设为计划完工日(当前时间)
        if (planEndDay.compareTo(now) <= 0) {
            stat.setProcessPlanStartDay(truncateToSeconds(planEndDay));
            return true; // 发生时间冲突
        }
        // 如果计算出的计划开工日小于等于当前时间,则设为当前时间
        else if (calculatedStartDay.compareTo(now) <= 0) {
            stat.setProcessPlanStartDay(now);
            return true; // 首次出现时间冲突
        }
        // 否则正常设置计划开工日
        else {
            stat.setProcessPlanStartDay(calculatedStartDay);
            return hasTimeConflict; // 保持原有冲突状态
        }
    }
    /**
     * 将日期精确到秒级别,去除毫秒信息
     *
     * @param date 原始日期
     * @return 精确到秒的日期
     */
    private Date truncateToSeconds(Date date) {
        if (date == null) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }
    /**
     * 设置日期相关组件(年、月、日)
     */
    private void setDateComponents(ApsGasPipingRouteStat stat) {
        if (stat.getProcessPlanStartDay() != null) {
            SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
            SimpleDateFormat monthFormat = new SimpleDateFormat("MM");
            SimpleDateFormat dayFormat = new SimpleDateFormat("dd");
            stat.setPlanStartYear(yearFormat.format(stat.getProcessPlanStartDay()));
            stat.setPlanStartMonth(monthFormat.format(stat.getProcessPlanStartDay()));
            stat.setPlanStartDay(dayFormat.format(stat.getProcessPlanStartDay()));
        }
    }
    /**
     * 聚合气体管路产能负载统计数据
     * 在Service层完成聚合处理,支持多维度分组
     *
     * @param params 聚合参数
     * @return 聚合结果
     */
    @Override
    public Map<String, Object> aggregateGasPipingRouteStat(Map<String, Object> params) {
        Map<String, Object> result = new HashMap<>();
        List<Map<String, Object>> plantTable = new ArrayList<>();
        // 获取时间颗粒度参数
        String timeGranularity = params.containsKey("timeGranularity") ?
                (String) params.get("timeGranularity") : "day"; // 默认为"日"粒度
        // 获取row维度的聚合字段 - 默认为工序名称(processName)
        String rowGroupBy = params.containsKey("rowGroupBy") ?
                (String) params.get("rowGroupBy") : "processName";
        // 确定分组维度 - 工厂、专业、车间
        boolean groupByPlant = params.containsKey("groupByPlant") && Boolean.TRUE.equals(params.get("groupByPlant"));
        boolean groupByMajor = params.containsKey("groupByMajor") && Boolean.TRUE.equals(params.get("groupByMajor"));
        boolean groupByWorkshop = params.containsKey("groupByWorkshop") && Boolean.TRUE.equals(params.get("groupByWorkshop"));
        // 如果rowGroupBy已经是某个维度,则该维度不需要再次分组
        if ("plant".equals(rowGroupBy)) groupByPlant = false;
        if ("major".equals(rowGroupBy)) groupByMajor = false;
        if ("workshop".equals(rowGroupBy)) groupByWorkshop = false;
        // 构建查询条件
        Map<String, Object> queryParams = new HashMap<>();
        // 设置查询条件 - 分类条件
        if (params.containsKey("plant")) {
            Object plantParam = params.get("plant");
            if (plantParam instanceof List) {
                queryParams.put("plants", plantParam);
            } else if (plantParam instanceof String) {
                // 处理可能的逗号分隔字符串
                String plantStr = (String) plantParam;
                if (plantStr.contains(",")) {
                    List<String> plantList = Arrays.asList(plantStr.split(","));
                    queryParams.put("plants", plantList);
                } else {
                    queryParams.put("plant", plantStr);
                }
            }
        }
        if (params.containsKey("major")) {
            Object majorParam = params.get("major");
            if (majorParam instanceof List) {
                queryParams.put("majors", majorParam);
            } else if (majorParam instanceof String) {
                // 处理可能的逗号分隔字符串
                String majorStr = (String) majorParam;
                if (majorStr.contains(",")) {
                    List<String> majorList = Arrays.asList(majorStr.split(","));
                    queryParams.put("majors", majorList);
                } else {
                    queryParams.put("major", majorStr);
                }
            }
        }
        if (params.containsKey("workshop")) {
            Object workshopParam = params.get("workshop");
            if (workshopParam instanceof List) {
                queryParams.put("workshops", workshopParam);
            } else if (workshopParam instanceof String) {
                // 处理可能的逗号分隔字符串
                String workshopStr = (String) workshopParam;
                if (workshopStr.contains(",")) {
                    List<String> workshopList = Arrays.asList(workshopStr.split(","));
                    queryParams.put("workshops", workshopList);
                } else {
                    queryParams.put("workshop", workshopStr);
                }
            }
        }
        // 确定时间范围
        List<String> timePoints = new ArrayList<>();
        if ("day".equalsIgnoreCase(timeGranularity)) {
            // "日"粒度:传入一个月份,聚合该月每一天的数据
            if (!params.containsKey("yearMonth")) {
                result.put("plantTable", plantTable);
                result.put("message", "日粒度聚合需要指定yearMonth参数");
                return result;
            }
            String yearMonth = (String) params.get("yearMonth");
            // 生成指定月份中的每一天
            YearMonth ym = YearMonth.parse(yearMonth);
            int daysInMonth = ym.lengthOfMonth();
            for (int day = 1; day <= daysInMonth; day++) {
                String dayStr = String.format("%02d", day);
                timePoints.add(yearMonth + "-" + dayStr);
            }
            // 设置查询参数
            String[] ymParts = yearMonth.split("-");
            queryParams.put("yearStart", ymParts[0]);
            queryParams.put("monthStart", ymParts[1]);
            queryParams.put("yearEnd", ymParts[0]);
            queryParams.put("monthEnd", ymParts[1]);
        } else if ("month".equalsIgnoreCase(timeGranularity)) {
            // "月"粒度:传入一个时间区间,聚合该区间内每个月的数据
            if (!params.containsKey("startDate") || !params.containsKey("endDate")) {
                result.put("plantTable", plantTable);
                result.put("message", "月粒度聚合需要指定startDate和endDate参数");
                return result;
            }
            String startDate = (String) params.get("startDate");
            String endDate = (String) params.get("endDate");
            // 解析开始和结束年月
            YearMonth start = YearMonth.parse(startDate);
            YearMonth end = YearMonth.parse(endDate);
            // 生成区间内的每个月
            timePoints = getYearMonthsInRange(start, end);
            // 设置查询参数
            String[] startParts = startDate.split("-");
            String[] endParts = endDate.split("-");
            queryParams.put("yearStart", startParts[0]);
            queryParams.put("monthStart", startParts[1]);
            queryParams.put("yearEnd", endParts[0]);
            queryParams.put("monthEnd", endParts[1]);
        }
        if (timePoints.isEmpty()) {
            result.put("plantTable", plantTable);
            result.put("message", "未能生成有效的时间点列表");
            return result;
        }
        // 查询原始数据(不依赖数据库聚合)
        List<Map<String, Object>> rawData = apsGasPipingRouteStatMapper.selectRawStatData(queryParams);
        // 如果没有查询到原始数据,但需要返回所有工序/车间的数据
        if (rawData.isEmpty()) {
            // 创建没有时间限制的基础查询参数
            Map<String, Object> baseParams = new HashMap<>(queryParams);
            baseParams.remove("yearStart");
            baseParams.remove("monthStart");
            baseParams.remove("yearEnd");
            baseParams.remove("monthEnd");
            // 直接从aps_gas_piping_route_stat表查询所有可能的工序和车间
            List<Map<String, Object>> baseData = apsGasPipingRouteStatMapper.selectBaseStatData(baseParams);
            // 为每个工序/车间创建基于时间的空数据
            for (Map<String, Object> data : baseData) {
                String rowGroupValue = getStringValue(data, rowGroupBy);
                if (rowGroupValue == null || rowGroupValue.trim().isEmpty()) continue;
                Map<String, Object> rowEntry = new HashMap<>();
                Map<String, Object> rowDetail = new HashMap<>();
                // 添加基本信息
                String plant = getStringValue(data, "plant");
                String major = getStringValue(data, "major");
                String workshop = getStringValue(data, "workshop");
                if (groupByPlant) rowDetail.put("plant", plant);
                if (groupByMajor) rowDetail.put("major", major);
                if (groupByWorkshop) rowDetail.put("workshop", workshop);
                // 处理工序名称 - 如果rowGroupBy为workshop,需要添加processName字段
                if ("workshop".equals(rowGroupBy)) {
                    String processName = getStringValue(data, "processName");
                    rowDetail.put("processName", processName != null ? processName : "");
                }
                // 为每个时间点创建零值数据
                List<Map<String, Object>> timeDataList = new ArrayList<>();
                for (String timePoint : timePoints) {
                    Map<String, Object> pointData = new HashMap<>();
                    pointData.put("planDay", timePoint);
                    pointData.put("requireTimes", BigDecimal.ZERO);
                    pointData.put("designTimes", BigDecimal.ZERO);
                    pointData.put("capacityLoad", BigDecimal.ZERO);
                    timeDataList.add(pointData);
                }
                rowDetail.put("timeData", timeDataList);
                rowEntry.put(rowGroupValue, rowDetail);
                plantTable.add(rowEntry);
            }
            // 更新结果但不直接返回,继续执行后续注意点4的处理
            result.put("plantTable", plantTable);
            result.put("timePoints", timePoints);
            result.put("rowGroupBy", rowGroupBy);
        } else {
            // 在Service层完成聚合
            // 使用组合key来实现多维度分组(动态rowGroupBy字段 + 可选的工厂/专业/车间)
            Map<String, Map<String, Object>> groupInfoMap = new HashMap<>();
            Map<String, Map<String, BigDecimal>> groupTimeDataMap = new HashMap<>();
            // 存储每个groupKey对应的processName集合
            Map<String, Set<String>> groupProcessNamesMap = new HashMap<>();
            // 遍历原始数据,按多维度分组进行聚合
            for (Map<String, Object> data : rawData) {
                // 获取行分组字段值
                String rowGroupValue = getStringValue(data, rowGroupBy);
                if (rowGroupValue == null || rowGroupValue.trim().isEmpty()) {
                    log.warn("跳过处理:{} 字段值为空", rowGroupBy);
                    continue;
                }
                // 获取工序名称(用于日志和后续处理)
                String processName = getStringValue(data, "processName");
                // 处理开工日期
                Date processPlanStartDay = (Date) data.get("processPlanStartDay");
                if (processPlanStartDay == null) {
                    log.warn("跳过处理:计划开工日为null, {}={}", rowGroupBy, rowGroupValue);
                    continue;
                }
                // 构建分组键 - 基于row分组字段和可选的其他维度
                String plant = getStringValue(data, "plant");
                String major = getStringValue(data, "major");
                String workshop = getStringValue(data, "workshop");
                StringBuilder groupKeyBuilder = new StringBuilder(rowGroupValue);
                // 根据用户选择的分组维度添加到分组键
                if (groupByPlant && plant != null) {
                    groupKeyBuilder.append("_PLANT_").append(plant);
                }
                if (groupByMajor && major != null) {
                    groupKeyBuilder.append("_MAJOR_").append(major);
                }
                if (groupByWorkshop && workshop != null) {
                    groupKeyBuilder.append("_WORKSHOP_").append(workshop);
                }
                String groupKey = groupKeyBuilder.toString();
                // 记录分组的基本信息(只记录一次)
                if (!groupInfoMap.containsKey(groupKey)) {
                    Map<String, Object> groupInfo = new HashMap<>();
                    groupInfo.put(rowGroupBy, rowGroupValue);
                    groupInfo.put("plant", plant);
                    groupInfo.put("major", major);
                    groupInfo.put("workshop", workshop);
                    groupInfo.put("processName", processName);
                    groupInfoMap.put(groupKey, groupInfo);
                }
                // 收集processName
                if (processName != null && !processName.trim().isEmpty()) {
                    if (!groupProcessNamesMap.containsKey(groupKey)) {
                        groupProcessNamesMap.put(groupKey, new HashSet<>());
                    }
                    groupProcessNamesMap.get(groupKey).add(processName);
                }
                // 计算时间点Key
                String timeKey;
                LocalDate planStartLocalDate = processPlanStartDay.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                if ("day".equalsIgnoreCase(timeGranularity)) {
                    // 日粒度: 2025-05-25
                    timeKey = planStartLocalDate.format(DateTimeFormatter.ISO_LOCAL_DATE);
                } else {
                    // 月粒度: 2025-05
                    timeKey = planStartLocalDate.getYear() + "-" + String.format("%02d", planStartLocalDate.getMonthValue());
                }
                // 获取该分组的时间点映射,如果不存在则创建
                if (!groupTimeDataMap.containsKey(groupKey)) {
                    groupTimeDataMap.put(groupKey, new HashMap<>());
                }
                Map<String, BigDecimal> timeMap = groupTimeDataMap.get(groupKey);
                // 累加该分组在该时间点的工时数据
                BigDecimal processTotalTime = getBigDecimalValue(data, "processTotalTime");
                if (processTotalTime != null) {
                    BigDecimal currentTotal = timeMap.getOrDefault(timeKey, BigDecimal.ZERO);
                    timeMap.put(timeKey, currentTotal.add(processTotalTime));
                }
            }
            // 构建最终返回的数据结构
            for (String groupKey : groupInfoMap.keySet()) {
                Map<String, Object> rowEntry = new HashMap<>();
                Map<String, Object> rowDetail = new HashMap<>();
                // 获取该分组的基本信息
                Map<String, Object> groupInfo = groupInfoMap.get(groupKey);
                String rowGroupValue = (String) groupInfo.get(rowGroupBy);
                // 添加分组基本信息
                if (groupByPlant) {
                    rowDetail.put("plant", groupInfo.get("plant"));
                }
                if (groupByMajor) {
                    rowDetail.put("major", groupInfo.get("major"));
                }
                if (groupByWorkshop) {
                    rowDetail.put("workshop", groupInfo.get("workshop"));
                }
                // 处理processName - 如果rowGroupBy为workshop,则将所有processName用分号连接
                if ("workshop".equals(rowGroupBy)) {
                    Set<String> processNames = groupProcessNamesMap.getOrDefault(groupKey, new HashSet<>());
                    if (!processNames.isEmpty()) {
                        String joinedProcessNames = String.join(";", processNames);
                        rowDetail.put("processName", joinedProcessNames);
                    } else {
                        rowDetail.put("processName", groupInfo.get("processName"));
                    }
                } else if (!"processName".equals(rowGroupBy)) {
                    // 保留工序名称信息,以便前端展示
                    rowDetail.put("processName", groupInfo.get("processName"));
                }
                // 添加时间数据
                List<Map<String, Object>> timeDataList = new ArrayList<>();
                Map<String, BigDecimal> timeMap = groupTimeDataMap.getOrDefault(groupKey, new HashMap<>());
                for (String timePoint : timePoints) {
                    Map<String, Object> pointData = new HashMap<>();
                    pointData.put("planDay", timePoint);
                    // 获取该时间点的需求工时,如果不存在则设为0
                    BigDecimal requireTimes = timeMap.getOrDefault(timePoint, BigDecimal.ZERO);
                    pointData.put("requireTimes", requireTimes);
                    // 设计工时和产能负荷稍后计算
                    pointData.put("designTimes", 0);
                    pointData.put("capacityLoad", 0);
                    timeDataList.add(pointData);
                }
                rowDetail.put("timeData", timeDataList);
                rowEntry.put(rowGroupValue, rowDetail);
                plantTable.add(rowEntry);
            }
        }
        // 在返回前查询设计产能数据并计算产能负荷
        for (Map<String, Object> rowEntry : plantTable) {
            for (String rowKey : rowEntry.keySet()) {
                Map<String, Object> rowDetail = (Map<String, Object>) rowEntry.get(rowKey);
                List<Map<String, Object>> timeDataList = (List<Map<String, Object>>) rowDetail.get("timeData");
                // 获取基本信息
                String plant = rowDetail.containsKey("plant") ? (String) rowDetail.get("plant") : null;
                String major = rowDetail.containsKey("major") ? (String) rowDetail.get("major") : null;
                String workshop = rowDetail.containsKey("workshop") ? (String) rowDetail.get("workshop") : null;
                // 处理不同的rowGroupBy情况
                if ("workshop".equals(rowGroupBy) && rowDetail.containsKey("processName")) {
                    // 情况1: 按workshop聚合,需要拆分processName字段
                    String processNamesStr = (String) rowDetail.get("processName");
                    String[] processNames = processNamesStr.split(";");
                    // 优化查询 - 创建缓存,按月份缓存查询结果
                    // Key: year-month-processName, Value: 查询结果列表
                    Map<String, List<ApsGasPipelineCapacityPlan>> capacityPlanCache = new HashMap<>();
                    // 遍历每个时间点
                    for (Map<String, Object> timeData : timeDataList) {
                        String planDay = (String) timeData.get("planDay");
                        BigDecimal requireTimes = new BigDecimal(timeData.get("requireTimes").toString());
                        BigDecimal totalDesignTimes = BigDecimal.ZERO;
                        // 拆分年月日
                        String[] dateParts = planDay.split("-");
                        String year = dateParts[0];
                        String month = dateParts[1];
                        // 统一month格式为整数字符串,去掉前导零
                        month = String.valueOf(Integer.parseInt(month));
                        String yearMonth = year + "-" + month;
                        // 累加多个工序的设计产能
                        for (String processName : processNames) {
                            // 构建缓存键
                            String cacheKey = yearMonth + "-" + processName.trim();
                            // 从缓存获取或查询数据
                            List<ApsGasPipelineCapacityPlan> capacityPlans;
                            if (capacityPlanCache.containsKey(cacheKey)) {
                                capacityPlans = capacityPlanCache.get(cacheKey);
                            } else {
                                // 使用专用查询方法查询设计产能数据
                                // 按文档要求:根据process_name和plant去aps_gas_pipeline_capacity_plan表中查询
                                capacityPlans = apsGasPipelineCapacityPlanMapper.selectDesignCapacityForInterface2(
                                        processName.trim(), year, month, major, plant);
                                // 将结果存入缓存
                                capacityPlanCache.put(cacheKey, capacityPlans);
                            }
                            // 累加设计产能值
                            for (ApsGasPipelineCapacityPlan plan : capacityPlans) {
                                if ("day".equalsIgnoreCase(timeGranularity)) {
                                    // 日粒度使用日产出数量
                                    if (plan.getDayProduceAllNum() != null) {
                                        totalDesignTimes = totalDesignTimes.add(plan.getDayProduceAllNum());
                                    }
                                } else {
                                    // 月粒度使用月产出总数量
                                    if (plan.getMonthProduceAllNum() != null) {
                                        totalDesignTimes = totalDesignTimes.add(plan.getMonthProduceAllNum());
                                    }
                                }
                            }
                        }
                        // 更新设计工时
                        timeData.put("designTimes", totalDesignTimes);
                        // 计算产能负荷 = 需求产能/设计产能×100%
                        if (totalDesignTimes.compareTo(BigDecimal.ZERO) > 0) {
                            BigDecimal capacityLoad = requireTimes
                                    .divide(totalDesignTimes, 2, RoundingMode.HALF_UP)
                                    .multiply(new BigDecimal(100));
                            timeData.put("capacityLoad", capacityLoad);
                        } else {
                            timeData.put("capacityLoad", 0);
                        }
                    }
                } else {
                    // 情况2: 按processName或其他字段聚合
                    String processName = rowDetail.containsKey("processName") ?
                            (String) rowDetail.get("processName") : rowKey;
                    // 优化查询 - 创建缓存,按月份缓存查询结果
                    Map<String, List<ApsGasPipelineCapacityPlan>> capacityPlanCache = new HashMap<>();
                    // 遍历每个时间点
                    for (Map<String, Object> timeData : timeDataList) {
                        String planDay = (String) timeData.get("planDay");
                        BigDecimal requireTimes = new BigDecimal(timeData.get("requireTimes").toString());
                        // 拆分年月日
                        String[] dateParts = planDay.split("-");
                        String year = dateParts[0];
                        String month = dateParts[1];
                        // 统一month格式为整数字符串,去掉前导零
                        month = String.valueOf(Integer.parseInt(month));
                        String yearMonth = year + "-" + month;
                        // 构建缓存键
                        String cacheKey = yearMonth + "-" + processName;
                        // 从缓存获取或查询数据
                        List<ApsGasPipelineCapacityPlan> capacityPlans;
                        if (capacityPlanCache.containsKey(cacheKey)) {
                            capacityPlans = capacityPlanCache.get(cacheKey);
                        } else {
                            // 使用专用查询方法查询设计产能数据
                            // 按文档要求:根据process_name和plant去aps_gas_pipeline_capacity_plan表中查询
                            capacityPlans = apsGasPipelineCapacityPlanMapper.selectDesignCapacityForInterface2(
                                    processName, year, month, major, plant);
                            // 将结果存入缓存
                            capacityPlanCache.put(cacheKey, capacityPlans);
                        }
                        // 累加设计产能值
                        BigDecimal totalDesignTimes = BigDecimal.ZERO;
                        for (ApsGasPipelineCapacityPlan plan : capacityPlans) {
                            if ("day".equalsIgnoreCase(timeGranularity)) {
                                // 日粒度使用日产出数量
                                if (plan.getDayProduceAllNum() != null) {
                                    totalDesignTimes = totalDesignTimes.add(plan.getDayProduceAllNum());
                                }
                            } else {
                                // 月粒度使用月产出总数量
                                if (plan.getMonthProduceAllNum() != null) {
                                    totalDesignTimes = totalDesignTimes.add(plan.getMonthProduceAllNum());
                                }
                            }
                        }
                        // 更新设计工时
                        timeData.put("designTimes", totalDesignTimes);
                        // 计算产能负荷 = 需求产能/设计产能×100%
                        if (totalDesignTimes.compareTo(BigDecimal.ZERO) > 0) {
                            BigDecimal capacityLoad = requireTimes
                                    .divide(totalDesignTimes, 2, RoundingMode.HALF_UP)
                                    .multiply(new BigDecimal(100));
                            timeData.put("capacityLoad", capacityLoad);
                        } else {
                            timeData.put("capacityLoad", 0);
                        }
                    }
                }
            }
        }
        result.put("plantTable", plantTable);
        result.put("timePoints", timePoints);
        result.put("rowGroupBy", rowGroupBy);
        // 根据文档注意点3,添加排序逻辑
        if (!plantTable.isEmpty()) {
            // 对聚合结果进行排序
            Collections.sort(plantTable, (map1, map2) -> {
                String key1 = map1.keySet().iterator().next();
                String key2 = map2.keySet().iterator().next();
                // 首先按rowGroupBy排序(processName或workshop)
                int result1 = key1.compareTo(key2);
                if (result1 != 0) {
                    return result1;
                }
                // 如果rowGroupBy相同,再按plant排序
                Map<String, Object> detail1 = (Map<String, Object>) map1.get(key1);
                Map<String, Object> detail2 = (Map<String, Object>) map2.get(key2);
                String plant1 = detail1.containsKey("plant") ? (String) detail1.get("plant") : "";
                String plant2 = detail2.containsKey("plant") ? (String) detail2.get("plant") : "";
                return plant1.compareTo(plant2);
            });
        }
        // 实现注意点4:当时间颗粒度为"日"时,确保没有数据的工厂也返回完整结构
        if ("day".equalsIgnoreCase(timeGranularity) && params.containsKey("plant")) {
            // 获取请求中的工厂列表
            List<String> requestedPlants = new ArrayList<>();
            Object plantParam = params.get("plant");
            if (plantParam instanceof List) {
                requestedPlants.addAll((List<String>) plantParam);
            } else if (plantParam instanceof String) {
                String plantStr = (String) plantParam;
                if (plantStr.contains(",")) {
                    requestedPlants.addAll(Arrays.asList(plantStr.split(",")));
                } else {
                    requestedPlants.add(plantStr);
                }
            }
            if (!requestedPlants.isEmpty()) {
                // 检查哪些工厂没有数据
                Set<String> plantsWithData = new HashSet<>();
                for (Map<String, Object> rowEntry : plantTable) {
                    for (String rowKey : rowEntry.keySet()) {
                        Map<String, Object> rowDetail = (Map<String, Object>) rowEntry.get(rowKey);
                        if (rowDetail.containsKey("plant")) {
                            plantsWithData.add((String) rowDetail.get("plant"));
                        }
                    }
                }
                // 找出没有数据的工厂
                List<String> plantsWithoutData = requestedPlants.stream()
                        .filter(plant -> !plantsWithData.contains(plant))
                        .collect(Collectors.toList());
                if (!plantsWithoutData.isEmpty()) {
                    // 获取所有去重的processName或workshop
                    List<String> allUniqueValues;
                    if ("processName".equals(rowGroupBy)) {
                        allUniqueValues = apsGasPipingRouteStatMapper.selectDistinctProcessNames();
                    } else if ("workshop".equals(rowGroupBy)) {
                        allUniqueValues = apsGasPipingRouteStatMapper.selectDistinctWorkshops();
                    } else {
                        // 如果rowGroupBy不是processName或workshop,跳过处理
                        return result;
                    }
                    // 为每个没有数据的工厂创建空数据结构
                    for (String plant : plantsWithoutData) {
                        for (String uniqueValue : allUniqueValues) {
                            if (uniqueValue == null || uniqueValue.trim().isEmpty()) {
                                continue;
                            }
                            // 检查是否已经存在这个值
                            boolean exists = false;
                            for (Map<String, Object> entry : plantTable) {
                                if (entry.containsKey(uniqueValue)) {
                                    Map<String, Object> detail = (Map<String, Object>) entry.get(uniqueValue);
                                    String existingPlant = detail.containsKey("plant") ? (String) detail.get("plant") : "";
                                    if (plant.equals(existingPlant)) {
                                        exists = true;
                                        break;
                                    }
                                }
                            }
                            // 如果不存在,创建新的空数据结构
                            if (!exists) {
                                Map<String, Object> rowEntry = new HashMap<>();
                                Map<String, Object> rowDetail = new HashMap<>();
                                // 设置基本信息
                                rowDetail.put("plant", plant);
                                if (groupByMajor) {
                                    rowDetail.put("major", "");
                                }
                                if (groupByWorkshop && !"workshop".equals(rowGroupBy)) {
                                    rowDetail.put("workshop", "");
                                }
                                // 处理processName - 如果rowGroupBy为workshop,需要设置空的processName
                                if ("workshop".equals(rowGroupBy)) {
                                    rowDetail.put("processName", "");
                                }
                                // 为每个时间点创建零值数据
                                List<Map<String, Object>> timeDataList = new ArrayList<>();
                                for (String timePoint : timePoints) {
                                    Map<String, Object> pointData = new HashMap<>();
                                    pointData.put("planDay", timePoint);
                                    pointData.put("requireTimes", BigDecimal.ZERO);
                                    pointData.put("designTimes", BigDecimal.ZERO);
                                    pointData.put("capacityLoad", BigDecimal.ZERO);
                                    timeDataList.add(pointData);
                                }
                                rowDetail.put("timeData", timeDataList);
                                rowEntry.put(uniqueValue, rowDetail);
                                plantTable.add(rowEntry);
                            }
                        }
                    }
                    // 重新排序结果
                    Collections.sort(plantTable, (map1, map2) -> {
                        String key1 = map1.keySet().iterator().next();
                        String key2 = map2.keySet().iterator().next();
                        // 首先按rowGroupBy排序(processName或workshop)
                        int result1 = key1.compareTo(key2);
                        if (result1 != 0) {
                            return result1;
                        }
                        // 如果rowGroupBy相同,再按plant排序
                        Map<String, Object> detail1 = (Map<String, Object>) map1.get(key1);
                        Map<String, Object> detail2 = (Map<String, Object>) map2.get(key2);
                        String plant1 = detail1.containsKey("plant") ? (String) detail1.get("plant") : "";
                        String plant2 = detail2.containsKey("plant") ? (String) detail2.get("plant") : "";
                        return plant1.compareTo(plant2);
                    });
                    // 更新结果
                    result.put("plantTable", plantTable);
                }
            }
        }
        return result;
    }
    /**
     * 从Map中安全获取String值
     */
    private String getStringValue(Map<String, Object> data, String key) {
        Object value = data.get(key);
        if (value == null) {
            return null;
        }
        return value.toString();
    }
    /**
     * 从Map中安全获取BigDecimal值
     */
    private BigDecimal getBigDecimalValue(Map<String, Object> data, String key) {
        Object value = data.get(key);
        if (value == null) {
            return null;
        }
        if (value instanceof BigDecimal) {
            return (BigDecimal) value;
        } else if (value instanceof Number) {
            return new BigDecimal(((Number) value).toString());
        } else if (value instanceof String) {
            try {
                return new BigDecimal((String) value);
            } catch (NumberFormatException e) {
                log.warn("无法将值转换为BigDecimal: {}", value);
                return null;
            }
        }
        return null;
    }
}