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