Forráskód Böngészése

单卷模型设计改造

fangpy 1 éve
szülő
commit
873c235bef

+ 7 - 2
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/ApsBalancingApplication.java

@@ -2,6 +2,7 @@ package com.rongwei.rwapsserver.aps;
 
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
 import com.rongwei.rwapsserver.aps.domain.*;
 import com.rongwei.rwapsserver.aps.score.ApsConstraintProvider;
@@ -96,7 +97,7 @@ public class ApsBalancingApplication {
         DateTime dateTime = DateUtil.offsetHour(deliverydate, -deliverytime);
         System.out.println(dateTime);*/
 
-        Map<String,List<Integer>> equipmentPlanActualTime = new HashMap<>();
+        /*Map<String,List<Integer>> equipmentPlanActualTime = new HashMap<>();
         List<Integer> planActualTimeList = new ArrayList<>();
         planActualTimeList.add(1);planActualTimeList.add(2);
         equipmentPlanActualTime.put("a",planActualTimeList);
@@ -107,7 +108,11 @@ public class ApsBalancingApplication {
         planActualTimeList1.set(0,2);
         System.out.println(planActualTimeList1);
 
-        System.out.println(equipmentPlanActualTime);
+        System.out.println(equipmentPlanActualTime);*/
+
+        ProductionProcesses a = new ProductionProcesses();
+        a.setId("11111");
+        System.out.println(ObjectUtil.cloneByStream(a).getId());
     }
 
     public static void testAps(){

+ 45 - 1
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/controller/ApsSchedulingController.java

@@ -14,6 +14,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cloud.commons.util.IdUtils;
 import org.springframework.web.bind.annotation.*;
 
+import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -92,7 +93,7 @@ public class ApsSchedulingController {
             processes2.setId(id2);
             processes2.setIfLock(false);
             processes2.setSeriesProduceMark("1100^_^1100H14冷轧卷普料 厚6.8*宽1025mm 6吨^_^1025.00");
-            processes2.setProduceTime(3100);
+            processes2.setProduceTime(1440);
             processes2.setPreviousProcessesIds(Arrays.asList(new String[]{id1}));
             processes2.setProduceOrder(Arrays.asList(new ProduceOrder[]{produceOrder1}));
             processes2.setMinWaitTime(310);
@@ -100,6 +101,8 @@ public class ApsSchedulingController {
             processes2.setVolumeMetal("1100");
             processes2.setOptionalEquipments(Arrays.asList(new String[]{"0001be252874536843730b100158","0001be252874536843730b100162","0001be252874536843730b100160"}));
             processes2.setUnitProduceTime(3100);
+            processes2.setVolumeWidth(new BigDecimal("1025"));
+            processes2.setSinglerollweight(new BigDecimal("5.8"));
             processes2.setBottleneck(true);
             processes2.setProcessType("成退");
             processes2.setBsProcessesId(Arrays.asList(new String[]{"d8ac56ea9335401f871cd691d1ba9442"}));
@@ -107,6 +110,47 @@ public class ApsSchedulingController {
             processes.add(processes1);
             processes.add(processes2);
         }
+        for(int i=6;i<14;i++){
+            String id1 = (i*2+1)+"";
+            String id2 = (i*2+2)+"";
+            ProductionProcesses processes1 = new ProductionProcesses();
+            processes1.setId(id1);
+            processes1.setCutfinishmin(70);
+            processes1.setIfLock(false);
+            processes1.setSeriesProduceMark("1100^_^1100H14冷轧卷普料 厚6.8*宽1025mm 6吨^_^1025.00");
+            processes1.setProduceTime(600);
+            processes1.setPrepressworkmin(55);
+            processes1.setNextProcessesIds(Arrays.asList(new String[]{id2}));
+            ProduceOrder produceOrder1 = new ProduceOrder("34f200bcbac748fb8f817eea88fb9a5d","订单1", DateUtil.parseDateTime("2024-06-22 08:00:00"));
+            processes1.setProduceOrder(Arrays.asList(new ProduceOrder[]{produceOrder1}));
+            processes1.setMinWaitTime(600);
+            processes1.setVolumeMetal("1100");
+            processes1.setOptionalEquipments(Arrays.asList(new String[]{"0001be252874536843730b100018","0001be252874536843730b100017","0001be252874536843730b100016"}));
+            processes1.setUnitProduceTime(360);
+            processes1.setProcessType("铸轧");
+            processes1.setBsProcessesId(Arrays.asList(new String[]{"f29671831358404ab047848aade7e682"}));
+
+            ProductionProcesses processes2 = new ProductionProcesses();
+            processes2.setId(id2);
+            processes2.setIfLock(false);
+            processes2.setSeriesProduceMark("1100^_^1100H14冷轧卷普料 厚6.8*宽1025mm 6吨^_^1025.00");
+            processes2.setProduceTime(1680);
+            processes2.setPreviousProcessesIds(Arrays.asList(new String[]{id1}));
+            processes2.setProduceOrder(Arrays.asList(new ProduceOrder[]{produceOrder1}));
+            processes2.setMinWaitTime(310);
+            processes2.setMaxWaitTime(3000);
+            processes2.setVolumeMetal("1100");
+            processes2.setOptionalEquipments(Arrays.asList(new String[]{"0001be252874536843730b100158","0001be252874536843730b100162","0001be252874536843730b100160"}));
+            processes2.setUnitProduceTime(3100);
+            processes2.setBottleneck(true);
+            processes2.setVolumeWidth(new BigDecimal("1100"));
+            processes2.setSinglerollweight(new BigDecimal("7.2"));
+            processes2.setProcessType("成退");
+            processes2.setBsProcessesId(Arrays.asList(new String[]{"d8ac56ea9335401f871cd691d1ba9443"}));
+
+            processes.add(processes1);
+            processes.add(processes2);
+        }
         return processes;
     }
 

+ 2 - 1
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/ApsOverallConfig.java

@@ -2,6 +2,7 @@ package com.rongwei.rwapsserver.aps.domain;
 
 import lombok.Data;
 
+import java.io.Serializable;
 import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Map;
@@ -10,7 +11,7 @@ import java.util.Map;
  * APS全局配置类
  */
 @Data
-public class ApsOverallConfig {
+public class ApsOverallConfig implements Serializable {
 
     // 排程计划指定开始时间
     private LocalDateTime startTime;

+ 4 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/ApsSolution.java

@@ -32,6 +32,10 @@ public class ApsSolution extends ApsAbstractPersistable{
     private Long incrementUnitAmount;
 
     public LocalDateTime startTime;
+    // 每一步骤最优规划实体
+    private List<ProductionProcesses> stepBestProcessesList;
+    // 是否初始结束
+    private boolean constructionHeuristicEnd;
 
     public ApsSolution(String id, List<ProductionProcesses> processesList, List<Equipment> equipmentList) {
         super(id);

+ 14 - 2
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/Equipment.java

@@ -4,7 +4,9 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import org.optaplanner.core.api.domain.entity.PlanningEntity;
+import org.optaplanner.core.api.domain.lookup.PlanningId;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.util.Date;
 import java.util.List;
@@ -12,11 +14,21 @@ import java.util.List;
 /**
  * 设备
  */
-@EqualsAndHashCode(callSuper = true)
 @NoArgsConstructor
 @Data
 //@PlanningEntity
-public class Equipment extends Step{
+public class Equipment implements Serializable {
+
+    private String id;
+
+    @PlanningId
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
 
     /**
      * 业务表订单工序ID

+ 2 - 1
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/EquipmentParameter.java

@@ -2,13 +2,14 @@ package com.rongwei.rwapsserver.aps.domain;
 
 import lombok.Data;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
 
 /**
  * 设备参数实体类
  */
 @Data
-public class EquipmentParameter {
+public class EquipmentParameter implements Serializable {
 
     // 设备宽度
     private BigDecimal equipmentWidth;

+ 7 - 1
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/EquipmentRunTime.java

@@ -3,6 +3,7 @@ package com.rongwei.rwapsserver.aps.domain;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 
@@ -10,7 +11,7 @@ import java.time.LocalDateTime;
  * 设备运行中时间,表示排程锁定后设备运行时间段
  */
 @Data
-public class EquipmentRunTime {
+public class EquipmentRunTime implements Serializable {
 
     /**
      * 设备运行开始时间
@@ -58,4 +59,9 @@ public class EquipmentRunTime {
      */
     private boolean locked;
 
+    /**
+     * 设备时间段占用类型(process:作业加工占用,maintenance:保养维修占用)
+     */
+    private String occupyType;
+
 }

+ 2 - 1
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/ProduceOrder.java

@@ -3,6 +3,7 @@ package com.rongwei.rwapsserver.aps.domain;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 
+import java.io.Serializable;
 import java.util.Date;
 import java.util.List;
 
@@ -10,7 +11,7 @@ import java.util.List;
  * 生产订单,即输出一种产品
  */
 @Data
-public class ProduceOrder {
+public class ProduceOrder implements Serializable {
 
     public ProduceOrder(String id,String orderName,Date deliveryDate){
         this.id = id;

+ 2 - 1
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/Product.java

@@ -1,11 +1,12 @@
 package com.rongwei.rwapsserver.aps.domain;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
 
 /**
  * 产品
  */
-public class Product {
+public class Product implements Serializable {
 
     /**
      * 产品类型

+ 14 - 1
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/ProductionProcesses.java

@@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.rongwei.rwapsserver.aps.listener.TaskStartTimeListener;
 import com.rongwei.rwapsserver.aps.util.DelayStrengthComparator;
 import org.optaplanner.core.api.domain.entity.PlanningEntity;
+import org.optaplanner.core.api.domain.lookup.PlanningId;
 import org.optaplanner.core.api.domain.valuerange.CountableValueRange;
 import org.optaplanner.core.api.domain.valuerange.ValueRangeFactory;
 import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
@@ -15,6 +16,7 @@ import org.optaplanner.core.api.domain.variable.PlanningVariableGraphType;
 import org.optaplanner.core.api.domain.variable.ShadowVariable;
 import org.springframework.beans.BeanUtils;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
@@ -27,7 +29,18 @@ import java.util.stream.Collectors;
  * 工步,工艺路线里的工步
  */
 @PlanningEntity
-public class ProductionProcesses extends Step{
+public class ProductionProcesses implements Serializable {
+
+    private String id;
+
+    @PlanningId
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
 
     public ProductionProcesses(){
 

+ 3 - 1
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/WashingMetal.java

@@ -2,11 +2,13 @@ package com.rongwei.rwapsserver.aps.domain;
 
 import lombok.Data;
 
+import java.io.Serializable;
+
 /**
  * 洗炉合金配置表
  */
 @Data
-public class WashingMetal {
+public class WashingMetal implements Serializable {
 
     // 当前作业合金
     private String processmetals;

+ 66 - 56
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/listener/TaskStartTimeListener.java

@@ -14,6 +14,7 @@ import org.optaplanner.core.api.score.director.ScoreDirector;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
 import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -92,14 +93,13 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
             }*/
             LocalDateTime startDateTime = startTimeNewSet(process,scoreDirector);
 
-            /*if(process.getDelay() != null && process.getDelay()>0){
-                if(process.getProduceTime()>1000){
-                    int bc = (int) Math.ceil((double) process.getProduceTime() / 20);
-                    startDateTime = startDateTime.plusMinutes(process.getDelay() * bc);
-                }else{
-                    startDateTime = startDateTime.plusMinutes(process.getDelay() * 30);
-                }
-            }*/
+            // 随机延时时间处理
+            if(process.getProcessType().equals("成退") || process.getProcessType().equals("中退")
+                    || process.getProcessType().equals("铸轧") || process.getProcessType().equals("冷轧")){
+                startDateTime = startDateTime.plusMinutes(process.getDelay() * 60);
+            }else{
+                startDateTime = startDateTime.plusMinutes(process.getDelay() * 10);
+            }
             scoreDirector.beforeVariableChanged(process, "startTime");
             process.setStartTime(startDateTime);
             scoreDirector.afterVariableChanged(process, "startTime");
@@ -473,6 +473,8 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
     }
 
     private LocalDateTime startTimeNewSet(ProductionProcesses process,ScoreDirector<ApsSolution> scoreDirector){
+        // 获取所有规划实体对象数据
+        ApsSolution workingSolution = scoreDirector.getWorkingSolution();
         // 时间设定
         LocalDateTime toUpdateStartTime = null;
         if(process.getEquipment() != null){
@@ -505,18 +507,11 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
             // 当前工序最大开始时间、结束时间
             LocalDateTime proMaxStartTime = null;
             LocalDateTime proMaxEndTime = null;
-            if(preProcess.getMaxWaitTime() != null && preProcess.getMaxWaitTime()>0){
+            if(preProcess != null && preProcess.getMaxWaitTime() != null && preProcess.getMaxWaitTime()>0){
                 proMaxStartTime = proStartTime.plusMinutes(preProcess.getMaxWaitTime());
                 proMaxEndTime = proEndTime.plusMinutes(preProcess.getMaxWaitTime());
             }
 
-            // 随机延时时间处理
-            if(process.getProcessType().equals("成退") || process.getProcessType().equals("中退")
-                    || process.getProcessType().equals("铸轧") || process.getProcessType().equals("冷轧")){
-                proStartTime = proStartTime.plusMinutes(process.getDelay() * 60);
-            }else{
-                proStartTime = proStartTime.plusMinutes(process.getDelay() * 10);
-            }
             // 当前工序设备已占用时间
             List<EquipmentRunTime> equipmentRunTimes = new ArrayList<>();
             if(process.getEquipment().getEquipmentRunTimes() != null && process.getEquipment().getEquipmentRunTimes().size()>0){
@@ -524,37 +519,52 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
                     EquipmentRunTime copy = new EquipmentRunTime();
                     copy.setStartRunTime(equipmentRunTime.getStartRunTime());
                     copy.setEndRunTime(equipmentRunTime.getEndRunTime());
+                    copy.setTotalVolumeWidth(equipmentRunTime.getTotalVolumeWidth());
+                    copy.setTotalSinglerollweight(equipmentRunTime.getTotalSinglerollweight());
+                    copy.setOccupyType(equipmentRunTime.getOccupyType());
                     copy.setLocked(true);
                     equipmentRunTimes.add(copy);
                 }
             }
             // 排程中当前设备其它作业占用时间
             // 过滤同一设备存在开始时间不是当前工序的其它所有工序
-            // 获取所有规划实体对象数据
-            ApsSolution workingSolution = scoreDirector.getWorkingSolution();
             Equipment pe = process.getEquipment();
             List<ProductionProcesses> allProcessesList = workingSolution.getProcessesList();
+            if(workingSolution.isConstructionHeuristicEnd()){
+                allProcessesList = workingSolution.getStepBestProcessesList();
+            }
             List<ProductionProcesses> filterProcess = allProcessesList.stream().filter(v -> {
                 return v.getEquipment() != null && v.getEquipment().getId().equals(pe.getId()) && v.getStartTime() != null && !v.getId().equals(process.getId());
             }).sorted(Comparator.comparing(ProductionProcesses::getProduceTime)).collect(Collectors.toList());
+            /*if(process.getId().equals("066e031c712848bd8d40f5a3ae19d5f5")){
+                int i = workingSolution.getScore().initScore();
+                System.out.println("i:"+i);
+                if(i == 0){
+                    List<ProductionProcesses> collect = allProcessesList.stream().filter(v -> v.getId().equals("96b9d96463524780ae7711c1f1bb8f20") && "2024-05-17 09:46".equals(v.getStartTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))).collect(Collectors.toList());
+                    if(collect != null && collect.size()>0){
+                        System.out.println(collect.get(0));
+                    }
+                }
+            }*/
             if(filterProcess != null && filterProcess.size()>0){
                 for (ProductionProcesses productionProcesses : filterProcess) {
-                    if(equipmentRunTimes == null || equipmentRunTimes.size() == 0){
-                        continue;
-                    }
                     boolean merged = false;
                     if(process.getProcessType().equals("成退") || process.getProcessType().equals("中退")){
-                        for (EquipmentRunTime equipmentRunTime : equipmentRunTimes) {
-                            // 判断当前排程的退火作业哪些是合并工序,只要开始时间到结束时间是包含关系即认为是合并工序
-                            if(equipmentRunTime.getStartRunTime().compareTo(productionProcesses.getStartTime())<=0
-                                    && equipmentRunTime.getEndRunTime().compareTo(productionProcesses.getEndTime())>=0){
-                                // 合并退火作业总宽度、承重
-                                equipmentRunTime.setTotalVolumeWidth(equipmentRunTime.getTotalVolumeWidth().add(productionProcesses.getVolumeWidth()));
-                                equipmentRunTime.setTotalSinglerollweight(equipmentRunTime.getTotalSinglerollweight().add(productionProcesses.getSinglerollweight()));
-                                merged = true;
-                                break;
-                            }else{
-                                // 未锁定的是排程中的作业占用时间段,可以合并更大的加工时间
+                        if(equipmentRunTimes != null && equipmentRunTimes.size()>0){
+                            for (EquipmentRunTime equipmentRunTime : equipmentRunTimes) {
+                                if(equipmentRunTime.getOccupyType() != null && "maintenance".equals(equipmentRunTime.getOccupyType())){
+                                    continue;
+                                }
+                                // 判断当前排程的退火作业哪些是合并工序,只要开始时间到结束时间是包含关系即认为是合并工序
+                                if(equipmentRunTime.getStartRunTime().compareTo(productionProcesses.getStartTime())<=0
+                                        && equipmentRunTime.getEndRunTime().compareTo(productionProcesses.getEndTime())>=0){
+                                    // 合并退火作业总宽度、承重
+                                    equipmentRunTime.setTotalVolumeWidth(equipmentRunTime.getTotalVolumeWidth().add(productionProcesses.getVolumeWidth()));
+                                    equipmentRunTime.setTotalSinglerollweight(equipmentRunTime.getTotalSinglerollweight().add(productionProcesses.getSinglerollweight()));
+                                    merged = true;
+                                    break;
+                                }else{
+                                    // 未锁定的是排程中的作业占用时间段,可以合并更大的加工时间
 //                                if(!equipmentRunTime.isLocked()){
                                     if(equipmentRunTime.getStartRunTime().compareTo(productionProcesses.getStartTime())>=0
                                             && equipmentRunTime.getEndRunTime().compareTo(productionProcesses.getEndTime())<=0){
@@ -567,6 +577,7 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
                                         break;
                                     }
 //                                }
+                                }
                             }
                         }
                     }
@@ -575,6 +586,8 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
                         EquipmentRunTime copy = new EquipmentRunTime();
                         copy.setStartRunTime(productionProcesses.getStartTime());
                         copy.setEndRunTime(productionProcesses.getEndTime());
+                        copy.setTotalVolumeWidth(productionProcesses.getVolumeWidth());
+                        copy.setTotalSinglerollweight(productionProcesses.getSinglerollweight());
                         copy.setLocked(false);
                         equipmentRunTimes.add(copy);
                     }
@@ -588,27 +601,19 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
                 for (EquipmentRunTime equipmentRunTime : equipmentRunTimes) {
                     // 退火工序
                     if(process.getProcessType().equals("成退") || process.getProcessType().equals("中退")){
-                        if(equipmentRunTime.getEndRunTime().compareTo(proStartTime)<=0){
+                        if(equipmentRunTime.getEndRunTime().compareTo(proStartTime)<=0 || equipmentRunTime.getStartRunTime().compareTo(proEndTime)>=0){
                             continue;
                         }else{
-                            if(equipmentRunTime.getStartRunTime().compareTo(proStartTime)<0){
-                                proStartTime = equipmentRunTime.getEndRunTime().plusMinutes(1);
-                            }else{
-                                if(equipmentRunTime.getStartRunTime().compareTo(proEndTime)<0){
-                                    boolean merge = isMerge(pe, equipmentRunTime, process);
-                                    if(merge){
-                                        proStartTime = equipmentRunTime.getStartRunTime();
-                                    }else{
-                                        proStartTime = equipmentRunTime.getEndRunTime().plusMinutes(1);
-                                    }
+                            if((equipmentRunTime.getStartRunTime().compareTo(proStartTime)<=0 && equipmentRunTime.getEndRunTime().compareTo(proEndTime)>=0)
+                                    || (equipmentRunTime.getStartRunTime().compareTo(proStartTime)>=0 && equipmentRunTime.getEndRunTime().compareTo(proEndTime)<=0)){
+                                boolean merge = isMerge(pe, equipmentRunTime, process);
+                                if(merge){
+                                    proStartTime = equipmentRunTime.getStartRunTime();
                                 }else{
-                                    if(equipmentRunTime.getStartRunTime().compareTo(proMaxStartTime)<0){
-                                        boolean merge = isMerge(pe, equipmentRunTime, process);
-                                        if(merge){
-                                            proStartTime = equipmentRunTime.getStartRunTime();
-                                        }
-                                    }
+                                    proStartTime = equipmentRunTime.getEndRunTime().plusMinutes(1);
                                 }
+                            }else{
+                                proStartTime = equipmentRunTime.getEndRunTime().plusMinutes(1);
                             }
                         }
                     }
@@ -618,7 +623,7 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
                             continue;
                         }else{
                             proStartTime = equipmentRunTime.getEndRunTime().plusMinutes(1);
-                            proEndTime = proStartTime.plusMinutes(process.getProduceTime());
+//                            proEndTime = proStartTime.plusMinutes(process.getProduceTime());
                         }
                     }
                 }
@@ -638,13 +643,18 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
      */
     private boolean isMerge(Equipment pe,EquipmentRunTime equipmentRunTime,ProductionProcesses process){
         boolean jumpMark = true;
-        // 宽度余量
-        if (pe.getEquipmentParameter().getEquipmentWidth().subtract(equipmentRunTime.getTotalVolumeWidth()).compareTo(process.getVolumeWidth()) < 0) {
-            jumpMark = false;
-        }
-        // 重量余量
-        if (pe.getEquipmentParameter().getEquipmentBearing().subtract(equipmentRunTime.getTotalSinglerollweight()).compareTo(process.getSinglerollweight()) < 0) {
+        // 保养维修占用时间不能合并
+        if("maintenance".equals(equipmentRunTime.getOccupyType())){
             jumpMark = false;
+        }else{
+            // 宽度余量
+            if (pe.getEquipmentParameter().getEquipmentWidth().subtract(equipmentRunTime.getTotalVolumeWidth()).compareTo(process.getVolumeWidth()) < 0) {
+                jumpMark = false;
+            }
+            // 重量余量
+            if (pe.getEquipmentParameter().getEquipmentBearing().subtract(equipmentRunTime.getTotalSinglerollweight()).compareTo(process.getSinglerollweight()) < 0) {
+                jumpMark = false;
+            }
         }
         return jumpMark;
     }

+ 41 - 1
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/score/ApsConstraintProvider.java

@@ -216,7 +216,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
      * @param constraintFactory
      * @return
      */
-    private Constraint hasOnePreGbAfterNow(ConstraintFactory constraintFactory) {
+    private Constraint hasOnePreGbAfterNowOld(ConstraintFactory constraintFactory) {
         return constraintFactory.forEach(ProductionProcesses.class)
                 .filter(productionProcesses -> {
                     boolean bln = false;
@@ -368,6 +368,46 @@ public class ApsConstraintProvider implements ConstraintProvider {
                 .asConstraint("hasOnePreGbAfterNow");
     }
 
+    /**
+     * 单卷模式下前后道工序时间约束
+     * @param constraintFactory
+     * @return
+     */
+    private Constraint hasOnePreGbAfterNow(ConstraintFactory constraintFactory) {
+        return constraintFactory.forEach(ProductionProcesses.class)
+                .filter(productionProcesses -> {
+                    boolean bln = false;
+                    if(productionProcesses.getPreviousProcesses() != null && productionProcesses.getPreviousProcesses().size()>0){
+                        // 此种情况简化为前道工序只有一个
+                        ProductionProcesses preProcess = productionProcesses.getPreviousProcesses().get(0);
+                        // 流转时间(最小等待时间)
+                        Integer lzTimes = 0;
+                        if(preProcess.getEquipment().getWorkshopid() != null && preProcess.getEquipment().getWorkshopid().equals(productionProcesses.getEquipment().getWorkshopid())){
+                            lzTimes = productionProcesses.getApsOverallConfig().getRoamTime().get("WORKSHOP_IN");
+                        }else{
+                            lzTimes = productionProcesses.getApsOverallConfig().getRoamTime().get("WORKSHOP_CROSS");
+                        }
+                        // 最小等待时间对比流转时间
+                        if(preProcess.getMinWaitTime() != null && lzTimes<preProcess.getMinWaitTime()){
+                            lzTimes = preProcess.getMinWaitTime();
+                        }
+                        // 最大等待时间
+                        Integer maxWaitTime = preProcess.getMaxWaitTime();
+                        if(productionProcesses.getStartTime().compareTo(preProcess.getEndTime().plusMinutes(lzTimes))<0){
+                            bln = true;
+                        }
+                        if(maxWaitTime != null && maxWaitTime>0){
+                            if(productionProcesses.getStartTime().compareTo(preProcess.getEndTime().plusMinutes(maxWaitTime))>0){
+                                bln = true;
+                            }
+                        }
+                    }
+                    return bln;
+                })
+                .penalize(HardSoftScore.ONE_HARD,(productionProcesses) -> 40)
+                .asConstraint("hasOnePreGbAfterNow");
+    }
+
     /**
      * 汇总所有下道工序的加工时间
      * @param nextProcess

+ 56 - 13
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/service/impl/ProductionScheduleServiceImpl.java

@@ -1,11 +1,10 @@
 package com.rongwei.rwapsserver.aps.service.impl;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
-import com.rongwei.rwapsserver.aps.domain.ApsOverallConfig;
-import com.rongwei.rwapsserver.aps.domain.ApsSolution;
-import com.rongwei.rwapsserver.aps.domain.Equipment;
-import com.rongwei.rwapsserver.aps.domain.ProductionProcesses;
+import com.baomidou.mybatisplus.extension.api.R;
+import com.rongwei.rwapsserver.aps.domain.*;
 import com.rongwei.rwapsserver.aps.score.ApsConstraintProvider;
 import com.rongwei.rwapsserver.aps.service.ProductionScheduleService;
 import com.rongwei.rwapsserver.aps.util.ApsConstants;
@@ -67,14 +66,18 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
 //                .withMoveThreadCount("4")
         );
         Solver<ApsSolution> solver = solverFactory.buildSolver();
-        /*solver.addEventListener(new SolverEventListener<ApsSolution>() {
+        solver.addEventListener(new SolverEventListener<ApsSolution>() {
             public void bestSolutionChanged(BestSolutionChangedEvent<ApsSolution> event) {
-                System.out.println("************"+event.getNewBestScore()+"************");
-                *//*if(solver.isEveryProblemChangeProcessed()) {
-                    System.out.println(event.getNewBestScore());
-                }*//*
+                if(solver.isEveryProblemChangeProcessed()) {
+                    event.getNewBestSolution().setConstructionHeuristicEnd(true);
+//                    if(event.getNewBestSolution().getStepBestProcessesList() == null){
+                    List<ProductionProcesses> processesList = ObjectUtil.cloneByStream(event.getNewBestSolution().getProcessesList());
+                    event.getNewBestSolution().setStepBestProcessesList(processesList);
+//                    }
+                    System.out.println("************"+event.getNewBestScore()+"************");
+                }
             }
-        });*/
+        });
         // optaplanner 求解器数据装配
         ApsSolution apsSolution = getPreApsSolution(productionScheduleVo);
 //        ApsSolution apsSolutionData = solver.solve(apsSolution);
@@ -95,6 +98,13 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
             productionProcesses.getEquipment().setProcessesList(null);
             productionProcesses.setPreviousStep(null);
             productionProcesses.setOptionalProviderEquipments(null);
+            /*if(productionProcesses.getProcessType().equals("成退")){
+                System.out.println("***************************");
+                System.out.println(productionProcesses.getEquipmentId());
+                System.out.println(productionProcesses.getStartTime());
+                System.out.println(productionProcesses.getEndTime());
+                System.out.println("***************************");
+            }*/
         }
         // 得分分析
         softExplain(explain,solvedBalance.getProcessesList());
@@ -204,7 +214,7 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
                 List<ProductionProcesses> pres = new ArrayList<>();
                 for (String previousProcessesId : process.getPreviousProcessesIds()) {
                     for (ProductionProcesses productionScheduleVoProcess : productionScheduleVo.getProcesses()) {
-                        if(productionScheduleVoProcess.getId().contains(previousProcessesId)){
+                        if(productionScheduleVoProcess.getId().equals(previousProcessesId)){
                             pres.add(productionScheduleVoProcess);
                         }
                     }
@@ -222,7 +232,7 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
                 }*/
                 for (String previousProcessesId : process.getNextProcessesIds()) {
                     for (ProductionProcesses nextprocess : productionScheduleVo.getProcesses()) {
-                        if(nextprocess.getId().contains(previousProcessesId)){
+                        if(nextprocess.getId().equals(previousProcessesId)){
                             nexts.add(nextprocess);
                         }
                     }
@@ -249,7 +259,7 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
                     }
                 }
                 if(providedEq.size() == 0){
-                    throw new ApsException("500","作业ID:"+ process.getId() + "可选设备不能为空");
+                    throw new ApsException("500","作业ID:"+ process.getBsProcessesId().get(0) + "可选设备不能为空");
                 }
                 process.setOptionalProviderEquipments(providedEq);
             }
@@ -268,6 +278,39 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
                 process.setIfLock(true);
             }
         }
+        // 设备占用时间段合并处理
+        for (Equipment equipment : productionScheduleVo.getEquipmentList()) {
+            List<EquipmentRunTime> equipmentRunTimesMerge = new ArrayList<>();
+            List<EquipmentRunTime> equipmentRunTimes = equipment.getEquipmentRunTimes();
+            if(equipmentRunTimes != null && equipmentRunTimes.size()>0){
+                for (EquipmentRunTime equipmentRunTime : equipmentRunTimes) {
+                    if("maintenance".equals(equipmentRunTime.getOccupyType())){
+                        equipmentRunTimesMerge.add(equipmentRunTime);
+                    }else{
+                        boolean isMerged = false;
+                        for (EquipmentRunTime runTime : equipmentRunTimesMerge) {
+                            if((runTime.getStartRunTime().compareTo(equipmentRunTime.getStartRunTime())<=0 && runTime.getEndRunTime().compareTo(equipmentRunTime.getEndRunTime())>=0)
+                                    || (runTime.getStartRunTime().compareTo(equipmentRunTime.getStartRunTime())>=0 && runTime.getEndRunTime().compareTo(equipmentRunTime.getEndRunTime())<=0)){
+                                runTime.setTotalVolumeWidth(runTime.getTotalVolumeWidth().add(equipmentRunTime.getTotalVolumeWidth()));
+                                runTime.setTotalSinglerollweight(runTime.getTotalSinglerollweight().add(equipmentRunTime.getTotalSinglerollweight()));
+                                if(equipmentRunTime.getStartRunTime().compareTo(runTime.getStartRunTime())<0){
+                                    runTime.setStartRunTime(equipmentRunTime.getStartRunTime());
+                                }
+                                if(equipmentRunTime.getEndRunTime().compareTo(runTime.getEndRunTime())>0){
+                                    runTime.setEndRunTime(equipmentRunTime.getEndRunTime());
+                                }
+                                isMerged = true;
+                                break;
+                            }
+                        }
+                        if(!isMerged){
+                            equipmentRunTimesMerge.add(equipmentRunTime);
+                        }
+                    }
+                }
+                equipment.setEquipmentRunTimes(equipmentRunTimesMerge);
+            }
+        }
         // 设备列表初始化
         unsolvedCloudBalance.setEquipmentList(productionScheduleVo.getEquipmentList());