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.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.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.util.IOUtils; import org.apache.poi.xssf.streaming.SXSSFCell; 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.*; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; import static java.util.stream.Collectors.groupingBy; /** * 气体管路产能负载统计Service业务层处理 * * @author hjy * @date 2025-04-24 */ @Slf4j @Service public class ApsGasPipingRouteStatServiceImpl implements IApsGasPipingRouteStatService { @Autowired private ApsGasPipingRouteStatMapper apsGasPipingRouteStatMapper; @Autowired private ApsGasPipingPlanMapper apsGasPipingPlanMapper; @Autowired private ApsGasPipelineCapacityPlanMapper apsGasPipelineCapacityPlanMapper; @Autowired private IApsGasMaterialUsageService apsGasMaterialUsageService; @Autowired private IApsStandardProcessService apsStandardProcessService; @Autowired private ApsPlateStandardRequireErrorMapper apsPlateStandardRequireErrorMapper; /** * 查询气体管路产能负载统计 * * @param id 气体管路产能负载统计主键 * @return 气体管路产能负载统计 */ @Override public ApsGasPipingRouteStat selectApsGasPipingRouteStatById(String id) { return apsGasPipingRouteStatMapper.selectApsGasPipingRouteStatById(id); } /** * 查询气体管路产能负载统计列表 * * @param apsGasPipingRouteStat 气体管路产能负载统计 * @return 气体管路产能负载统计 */ @Override public List selectApsGasPipingRouteStatList(ApsGasPipingRouteStat apsGasPipingRouteStat) { return apsGasPipingRouteStatMapper.selectApsGasPipingRouteStatList(apsGasPipingRouteStat); } /** * 新增气体管路产能负载统计 * * @param apsGasPipingRouteStat 气体管路产能负载统计 * @return 结果 */ @Override public int insertApsGasPipingRouteStat(ApsGasPipingRouteStat apsGasPipingRouteStat) { apsGasPipingRouteStat.setCreateTime(DateUtils.getNowDate()); apsGasPipingRouteStat.setCreateBy(SecurityUtils.getUsername()); return apsGasPipingRouteStatMapper.insertApsGasPipingRouteStat(apsGasPipingRouteStat); } /** * 修改气体管路产能负载统计 * * @param apsGasPipingRouteStat 气体管路产能负载统计 * @return 结果 */ @Override public int updateApsGasPipingRouteStat(ApsGasPipingRouteStat apsGasPipingRouteStat) { apsGasPipingRouteStat.setUpdateBy(SecurityUtils.getUsername()); apsGasPipingRouteStat.setUpdateTime(DateUtils.getNowDate()); return apsGasPipingRouteStatMapper.updateApsGasPipingRouteStat(apsGasPipingRouteStat); } /** * 批量删除气体管路产能负载统计 * * @param ids 需要删除的气体管路产能负载统计主键 * @return 结果 */ @Override public int deleteApsGasPipingRouteStatByIds(String[] ids) { return apsGasPipingRouteStatMapper.deleteApsGasPipingRouteStatByIds(ids); } /** * 删除气体管路产能负载统计信息 * * @param id 气体管路产能负载统计主键 * @return 结果 */ @Override public int deleteApsGasPipingRouteStatById(String id) { return apsGasPipingRouteStatMapper.deleteApsGasPipingRouteStatById(id); } @Override public boolean computeCapacity() { // PageHelper.startPage(1, 500); List apsGasPipingPlans = apsGasPipingPlanMapper.selectApsGasPipingPlanWithProcess(new ApsGasPipingPlan()); List apsGasPipingRouteStatList = new ArrayList<>(); /*本次计算批次号*/ String batchNum = IdUtils.fastSimpleUUID(); try { apsGasPipingPlans.forEach(apsGasPipingPlan -> { List apsProcessRoutes = apsGasPipingPlan.getApsProcessRoutes(); //按照工序序号升序排序 apsProcessRoutes.sort((a, b)->b.getProcessNumber().compareTo(a.getProcessNumber())); //是否找到当前工序 boolean isCurrentProcess = false; boolean lastProcessStartTimeIsBeforeNow = false; ApsGasPipingRouteStat preApsProcessRoute = null; for (int i=0;i apsGasMaterialUsageList = apsGasMaterialUsageService.selectApsGasMaterialUsageList(apsGasMaterialUsage); // apsGasPipingRouteStat.setStandardDosage(apsProcessRoute.getStandardTime().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 tempInsertList = new ArrayList<>(); for (int i = 0; i < apsGasPipingRouteStatList.size(); i++) { tempInsertList.add(apsGasPipingRouteStatList.get(i)); if(tempInsertList.size()==500){ apsGasPipingRouteStatMapper.insertApsGasPipingRouteStatBatch(tempInsertList); tempInsertList = new ArrayList<>(); }else if(i==apsGasPipingRouteStatList.size()-1){ apsGasPipingRouteStatMapper.insertApsGasPipingRouteStatBatch(tempInsertList); } } apsGasPipingRouteStatMapper.deleteApsGasPipingRouteStatByBatchNum(batchNum); } catch (Exception e) { e.printStackTrace(); return false; } return true; } public JSONObject getCapacityPlanDataBackup(ApsGasPipingRouteStat apsGasPipingRouteStat) { JSONObject result = new JSONObject(); YearMonth yearMonth = YearMonth.parse(apsGasPipingRouteStat.getSearchEndDate()); int daysInMonth = yearMonth.lengthOfMonth(); LinkedHashSet startPlanTimeSet = new LinkedHashSet<>(); //工序分组统计 LinkedHashMap> processMap = new LinkedHashMap<>(); List>> processList = new ArrayList<>(); try { //获取标准工序名称 ApsStandardProcess apsStandardProcess = new ApsStandardProcess(); apsStandardProcess.setMajor(apsGasPipingRouteStat.getMajor().equals("gas")?"气柜":"管路"); List apsStandardProcessList = apsStandardProcessService.selectApsStandardProcessList(apsStandardProcess); apsStandardProcessList.sort((a, b)->a.getProcessName().compareTo(b.getProcessName())); for(ApsStandardProcess temp:apsStandardProcessList){ processMap.put(temp.getProcessName(), new ArrayList()); } //获取工序计划产能数据 HashMap 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 yearMonths = getYearMonthsInRange(start, end); startPlanTimeSet.addAll(yearMonths); } List apsGasPipelineCapacityPlanList = apsGasPipelineCapacityPlanMapper.selectApsGasPipelineCapacityPlanList(searchCapacityPlan); apsGasPipelineCapacityPlanList.forEach(apsGasPipelineCapacityPlan -> { apsGasPipingPlanMap.put(apsGasPipelineCapacityPlan.getProcessName()+"-"+apsGasPipelineCapacityPlan.getYear()+"-"+(Integer.parseInt(apsGasPipelineCapacityPlan.getMonth())<10?"0"+apsGasPipelineCapacityPlan.getMonth():apsGasPipelineCapacityPlan.getMonth()),apsGasPipelineCapacityPlan); }); //计算日产能数据 DateTimeFormatter formatter = null; List 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(""); 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.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 apsResourceDateStatList = processMap.get(apsGasPipingRouteStatTemp.getProcessName()); apsResourceDateStatList.add(apsResourceDateStat); processMap.put(apsGasPipingRouteStatTemp.getProcessName(), apsResourceDateStatList); } } //聚合每道工序的开工时间和产能 processMap.forEach((processName, apsResourceDateStatList) -> { LinkedHashMap 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{ 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); } }); List tempList = new ArrayList<>(); dayMap.forEach((key, value) -> { tempList.add(value); }); HashMap> temp = new HashMap<>(); temp.put(processName, tempList); processList.add(temp); }); //排序时间标题 List sortedStartPlanTimeList = new ArrayList<>(startPlanTimeSet); Collections.sort(sortedStartPlanTimeList); for (int i=0;i> temp = processList.get(i); for (Map.Entry> entry : temp.entrySet()){ List apsResourceDateStatList = entry.getValue(); String key = entry.getKey(); List crtList = new ArrayList<>(); for(String tempTime:sortedStartPlanTimeList) { if("month".equals(apsGasPipingRouteStat.getSearchType())){ tempTime += "-01"; } LocalDate crtDate = LocalDate.parse(tempTime, formatter); Optional 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", 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 startPlanTimeSet = new LinkedHashSet<>(); //工序分组统计 LinkedHashMap> processMap = new LinkedHashMap<>(); List>> processList = new ArrayList<>(); try { //获取标准工序名称 ApsStandardProcess apsStandardProcess = new ApsStandardProcess(); apsStandardProcess.setMajor(apsGasPipingRouteStat.getMajor().equals("gas")?"气柜":"管路"); List apsStandardProcessList = apsStandardProcessService.selectApsStandardProcessList(apsStandardProcess); apsStandardProcessList.sort((a, b)->a.getProcessName().compareTo(b.getProcessName())); for(ApsStandardProcess temp:apsStandardProcessList){ processMap.put(temp.getProcessName(), new ArrayList()); } //获取工序计划产能数据 HashMap 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 yearMonths = getYearMonthsInRange(start, end); startPlanTimeSet.addAll(yearMonths); } List 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 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 apsResourceDateStatList = processMap.get(apsGasPipingRouteStatTemp.getProcessName()); apsResourceDateStatList.add(apsResourceDateStat); processMap.put(apsGasPipingRouteStatTemp.getProcessName(), apsResourceDateStatList); } } //聚合每道工序的开工时间和产能 for (Map.Entry> entry : processMap.entrySet()) { String processName = entry.getKey(); List apsResourceDateStatList = entry.getValue(); if("day".equals(apsGasPipingRouteStat.getSearchType())) { // 按天统计时保持原有逻辑,不按工厂分组 LinkedHashMap 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 tempList = new ArrayList<>(dayMap.values()); HashMap> temp = new HashMap<>(); temp.put(processName, tempList); processList.add(temp); } else { // 按月统计时才按工厂分组 if (apsResourceDateStatList.isEmpty()) { // 从产能规划数据中获取所有的工厂 Set 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 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 tempList = new ArrayList<>(dayMap.values()); HashMap> temp = new HashMap<>(); temp.put(processName + "_" + plant, tempList); processList.add(temp); } } else { // 按工厂分组,并过滤掉plant为null或空字符串的记录 Map> plantGroups = apsResourceDateStatList.stream() .filter(stat -> stat.getPlant() != null && !stat.getPlant().trim().isEmpty()) .collect(groupingBy(ApsResourceDateStat::getPlant)); // 如果过滤后没有有效的工厂数据,跳过这个工序 if (plantGroups.isEmpty()) { continue; } // 对每个工厂的数据进行处理 for (Map.Entry> plantEntry : plantGroups.entrySet()) { String plant = plantEntry.getKey(); // 再次确认plant不为空 if (plant == null || plant.trim().isEmpty()) { continue; } List plantStats = plantEntry.getValue(); LinkedHashMap 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 tempList = new ArrayList<>(dayMap.values()); HashMap> temp = new HashMap<>(); temp.put(processName + "_" + plant, tempList); processList.add(temp); } } } } //排序时间标题 List sortedStartPlanTimeList = new ArrayList<>(startPlanTimeSet); Collections.sort(sortedStartPlanTimeList); for (int i=0;i> temp = processList.get(i); for (Map.Entry> entry : temp.entrySet()){ List apsResourceDateStatList = entry.getValue(); String key = entry.getKey(); List crtList = new ArrayList<>(); for(String tempTime:sortedStartPlanTimeList) { if("month".equals(apsGasPipingRouteStat.getSearchType())){ tempTime += "-01"; } LocalDate crtDate = LocalDate.parse(tempTime, formatter); Optional 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); } 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 void exportExcel(HttpServletResponse response, ApsGasPipingRouteStat apsGasPipingRouteStat) { SXSSFWorkbook wb = new SXSSFWorkbook(500); wb.createSheet(); wb.setSheetName(0, "气柜管路产能负载统计表"); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); Map styles = createStyles(wb); CellStyle title = styles.get("title"); try { JSONObject stat = getCapacityPlanData(apsGasPipingRouteStat); List days = (List) stat.get("planTitle"); List>> table= (List>>) stat.get("planTable"); SXSSFSheet sheet = wb.getSheetAt(0); /*填写日期列 和 工时列*/ SXSSFRow rowDay = sheet.createRow(0); SXSSFRow rowTitle = sheet.createRow(1); SXSSFCell daytitle = rowDay.createCell(0); daytitle.setCellValue("日期"); daytitle.setCellStyle(title); SXSSFCell titleCell = rowTitle.createCell(0); titleCell.setCellValue("工序"); titleCell.setCellStyle(title); for (int i = 0; i < days.size(); i++) { SXSSFCell dateCell = rowDay.createCell(i * 3 + 1); SXSSFCell designHoursCell = rowTitle.createCell(i * 3 + 1); SXSSFCell requireHoursCell = rowTitle.createCell(i * 3 + 2); SXSSFCell loadCell = rowTitle.createCell(i * 3 + 3); dateCell.setCellValue(days.get(i)); designHoursCell.setCellValue("设计工时"); requireHoursCell.setCellValue("需求工时"); loadCell.setCellValue("产能负荷"); /*set cell style*/ dateCell.setCellStyle(title); designHoursCell.setCellStyle(title); requireHoursCell.setCellStyle(title); loadCell.setCellStyle(title); /*合并日期单元格*/ sheet.addMergedRegion( new CellRangeAddress(0, 0, i*3+1, i*3+3)); } for (int i = 0; i < table.size(); i++) { Map> resourceList = table.get(i); /*创建数据行*/ SXSSFRow dataRow = sheet.createRow(i+2); for( Map.Entry> entry : resourceList.entrySet()){ String resourceName = entry.getKey(); List resourceDateStats = entry.getValue(); 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().doubleValue()); dataRow.createCell(j*3+2).setCellValue(apsResourceDateStat.getRequireTimes().doubleValue()); if(apsResourceDateStat.getCapacityLoad()!=null){ dataRow.createCell(j*3+3).setCellValue(apsResourceDateStat.getCapacityLoad().doubleValue()+"%"); }else{ dataRow.createCell(j*3+3).setCellValue("%"); } } } } wb.write(response.getOutputStream()); } catch (Exception e) { log.error("导出Excel异常{}", e.getMessage()); } finally { IOUtils.closeQuietly(wb); } } private Map createStyles(SXSSFWorkbook wb) { Map styles=new HashMap<>(); CellStyle style = wb.createCellStyle(); style.setAlignment(HorizontalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.CENTER); Font titleFont = wb.createFont(); titleFont.setFontName("Arial"); titleFont.setFontHeightInPoints((short) 12); titleFont.setBold(true); style.setFont(titleFont); DataFormat dataFormat = wb.createDataFormat(); style.setDataFormat(dataFormat.getFormat("@")); styles.put("title", style); return styles; } public static List getYearMonthsInRange(YearMonth start, YearMonth end) { List 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 tempList = apsGasPipingRouteStatMapper.queryTempStat(); Map> groupByOrderNo = tempList.stream().collect(groupingBy(ApsGasPipingRouteStat::getWorkOrderNo)); Boolean hasBefore = false; LocalDateTime now = LocalDateTime.now(); for (Map.Entry> entry : groupByOrderNo.entrySet()) { List statPerOrder = entry.getValue(); /*num 为根据完工时间排序出的序号,按此排序,可保证是按完工时间倒叙排列*/ statPerOrder.sort((a, b)->a.getNum().compareTo(b.getNum())); ApsGasPipingRouteStat last=null; for (int i = 0; i = 工单当前工序 代表是未来工序,才进行计划开工日 和计划完工日的计算 * 当工艺工序号 < 工单当前工序 过去工序,不进行计算 * */ 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 tempList = apsGasPipingRouteStatMapper.queryTempStat(); Map> groupByOrderNo = tempList.stream().collect(groupingBy(ApsGasPipingRouteStat::getWorkOrderNo)); LocalDateTime now = LocalDateTime.now(); /*待保存的数据*/ List cptStateList = new ArrayList<>(); for (Map.Entry> entry : groupByOrderNo.entrySet()) { List statPerOrder = entry.getValue(); /*num 为根据完工时间排序出的序号,按此排序,可保证是按完工时间倒叙排列*/ statPerOrder.sort((a, b)->a.getNum().compareTo(b.getNum())); ApsGasPipingRouteStat last=null; /*当前工序是否存在 计划开工时间 小于 当前的时间,如果存在后续设置为当前时间*/ boolean hasBefore = false; for (int i = 0; i = 工单当前工序 代表是未来工序,才进行计划开工日 和计划完工日的计算 * 当工艺工序号 < 工单当前工序 过去工序,不进行计算 * */ 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 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 statList = new ArrayList<>(); // 处理手工气体预测数据 - 使用联合查询获取所有相关数据 List> predictionDataList = apsGasPipingRouteStatMapper.selectPredictionRouteData(); // 按物料代码分组,便于处理同一物料的不同工序 Map>> predictionGroups = predictionDataList.stream() .collect(Collectors.groupingBy(data -> data.get("material_code").toString())); // 处理每个物料的工艺路线 for (String materialCode : predictionGroups.keySet()) { List> 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 processList = new ArrayList<>(); for (Map 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> moDataList = apsGasPipingRouteStatMapper.selectMoRouteData(); // 获取所有的MO数据,用于检查哪些MO没有关联到工艺路线 List> allMoData = apsGasPipingRouteStatMapper.selectAllMoData(); // 记录已关联工艺路线的MO编号 Set processedMoSet = new HashSet<>(); // 按工单号分组,便于处理同一工单的不同工序 Map>> moGroups = moDataList.stream() .collect(Collectors.groupingBy(data -> data.get("work_order_no").toString())); // 处理每个工单的工艺路线 for (String workOrderNo : moGroups.keySet()) { List> 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 processList = new ArrayList<>(); for (Map 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 errorList = new ArrayList<>(); for (Map 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 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 aggregateGasPipingRouteStat(Map params) { Map result = new HashMap<>(); List> 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 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 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 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 workshopList = Arrays.asList(workshopStr.split(",")); queryParams.put("workshops", workshopList); } else { queryParams.put("workshop", workshopStr); } } } // 确定时间范围 List 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> rawData = apsGasPipingRouteStatMapper.selectRawStatData(queryParams); // 如果没有查询到原始数据,但需要返回所有工序/车间的数据 if (rawData.isEmpty()) { // 创建没有时间限制的基础查询参数 Map baseParams = new HashMap<>(queryParams); baseParams.remove("yearStart"); baseParams.remove("monthStart"); baseParams.remove("yearEnd"); baseParams.remove("monthEnd"); // 直接从aps_gas_piping_route_stat表查询所有可能的工序和车间 List> baseData = apsGasPipingRouteStatMapper.selectBaseStatData(baseParams); // 为每个工序/车间创建基于时间的空数据 for (Map data : baseData) { String rowGroupValue = getStringValue(data, rowGroupBy); if (rowGroupValue == null || rowGroupValue.trim().isEmpty()) continue; Map rowEntry = new HashMap<>(); Map 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> timeDataList = new ArrayList<>(); for (String timePoint : timePoints) { Map 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); } result.put("plantTable", plantTable); result.put("timePoints", timePoints); result.put("rowGroupBy", rowGroupBy); return result; } // 在Service层完成聚合 // 使用组合key来实现多维度分组(动态rowGroupBy字段 + 可选的工厂/专业/车间) Map> groupInfoMap = new HashMap<>(); Map> groupTimeDataMap = new HashMap<>(); // 存储每个groupKey对应的processName集合 Map> groupProcessNamesMap = new HashMap<>(); // 遍历原始数据,按多维度分组进行聚合 for (Map 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 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 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 rowEntry = new HashMap<>(); Map rowDetail = new HashMap<>(); // 获取该分组的基本信息 Map 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 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> timeDataList = new ArrayList<>(); Map timeMap = groupTimeDataMap.getOrDefault(groupKey, new HashMap<>()); for (String timePoint : timePoints) { Map 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 rowEntry : plantTable) { for (String rowKey : rowEntry.keySet()) { Map rowDetail = (Map) rowEntry.get(rowKey); List> timeDataList = (List>) 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> capacityPlanCache = new HashMap<>(); // 遍历每个时间点 for (Map 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 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> capacityPlanCache = new HashMap<>(); // 遍历每个时间点 for (Map 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 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 detail1 = (Map) map1.get(key1); Map detail2 = (Map) 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); }); } return result; } /** * 从Map中安全获取String值 */ private String getStringValue(Map data, String key) { Object value = data.get(key); if (value == null) { return null; } return value.toString(); } /** * 从Map中安全获取BigDecimal值 */ private BigDecimal getBigDecimalValue(Map 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; } }