fangpy 1 سال پیش
والد
کامیت
d63ea21de9

+ 3 - 2
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/ApsSolution.java

@@ -8,6 +8,7 @@ import org.optaplanner.core.api.domain.solution.ProblemFactCollectionProperty;
 import org.optaplanner.core.api.domain.valuerange.CountableValueRange;
 import org.optaplanner.core.api.domain.valuerange.ValueRangeFactory;
 import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
+import org.optaplanner.core.api.score.buildin.hardmediumsoft.HardMediumSoftScore;
 import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
 
 import java.time.LocalDateTime;
@@ -27,7 +28,7 @@ public class ApsSolution extends ApsAbstractPersistable{
     private List<Equipment> equipmentList;
 
     @Getter(value = AccessLevel.NONE)
-    private HardSoftScore score;
+    private HardMediumSoftScore score;
 
     private Long incrementUnitAmount;
 
@@ -79,7 +80,7 @@ public class ApsSolution extends ApsAbstractPersistable{
     }
 
     @PlanningScore
-    public HardSoftScore getScore() {
+    public HardMediumSoftScore getScore() {
         return score;
     }
 

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

@@ -15,5 +15,7 @@ public class EquipmentParameter implements Serializable {
     private BigDecimal equipmentWidth;
     // 设备承重
     private BigDecimal equipmentBearing;
+    // 设备宽度
+    private BigDecimal furnace;
 
 }

+ 24 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/ProductionProcesses.java

@@ -23,6 +23,7 @@ import java.time.ZoneId;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
@@ -63,6 +64,11 @@ public class ProductionProcesses implements Serializable {
      */
     private List<String> bsProcessesId;
 
+    /**
+     * 业务表订单工序ID(唯一的情况下)
+     */
+    private String uniqueBsProcessesId;
+
     /**
      * 设备类型
      */
@@ -271,6 +277,8 @@ public class ProductionProcesses implements Serializable {
      */
     private Integer cutfinishmin;
 
+    private Map<String, String> conflictRoptions;
+
     public String getEquipmentType() {
         return equipmentType;
     }
@@ -693,6 +701,22 @@ public class ProductionProcesses implements Serializable {
         this.singlerollweight = singlerollweight;
     }
 
+    public Map<String, String> getConflictRoptions() {
+        return conflictRoptions;
+    }
+
+    public void setConflictRoptions(Map<String, String> conflictRoptions) {
+        this.conflictRoptions = conflictRoptions;
+    }
+
+    public String getUniqueBsProcessesId() {
+        return uniqueBsProcessesId;
+    }
+
+    public void setUniqueBsProcessesId(String uniqueBsProcessesId) {
+        this.uniqueBsProcessesId = uniqueBsProcessesId;
+    }
+
     public String getSeriSort(){
         String sortStr = this.getId();
         if(this.getStartTime() != null){

+ 8 - 6
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/listener/TaskStartTimeListener.java

@@ -536,9 +536,11 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
                 allProcessesList = workingSolution.getStepBestProcessesList();
             }
             List<ProductionProcesses> filterProcess = null;
-            /*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.getProcessType().equals("成退") || process.getProcessType().equals("中退")){
+                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();
@@ -564,7 +566,7 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
                                 if(equipmentRunTime.getStartRunTime().compareTo(productionProcesses.getStartTime())<=0
                                         && equipmentRunTime.getEndRunTime().compareTo(productionProcesses.getEndTime())>=0){
                                     // 合并退火作业总宽度、承重
-                                    equipmentRunTime.setTotalVolumeWidth(equipmentRunTime.getTotalVolumeWidth().add(productionProcesses.getVolumeWidth()));
+                                    equipmentRunTime.setTotalVolumeWidth(equipmentRunTime.getTotalVolumeWidth().add(productionProcesses.getVolumeWidth()).add(pe.getEquipmentParameter().getFurnace()));
                                     equipmentRunTime.setTotalSinglerollweight(equipmentRunTime.getTotalSinglerollweight().add(productionProcesses.getSinglerollweight()));
                                     merged = true;
                                     break;
@@ -574,7 +576,7 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
                                     if(equipmentRunTime.getStartRunTime().compareTo(productionProcesses.getStartTime())>=0
                                             && equipmentRunTime.getEndRunTime().compareTo(productionProcesses.getEndTime())<=0){
                                         // 合并退火作业总宽度、承重
-                                        equipmentRunTime.setTotalVolumeWidth(equipmentRunTime.getTotalVolumeWidth().add(productionProcesses.getVolumeWidth()));
+                                        equipmentRunTime.setTotalVolumeWidth(equipmentRunTime.getTotalVolumeWidth().add(productionProcesses.getVolumeWidth()).add(pe.getEquipmentParameter().getFurnace()));
                                         equipmentRunTime.setTotalSinglerollweight(equipmentRunTime.getTotalSinglerollweight().add(productionProcesses.getSinglerollweight()));
                                         equipmentRunTime.setStartRunTime(productionProcesses.getStartTime());
                                         equipmentRunTime.setEndRunTime(productionProcesses.getEndTime());
@@ -653,7 +655,7 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
             jumpMark = false;
         }else{
             // 宽度余量
-            if (pe.getEquipmentParameter().getEquipmentWidth().subtract(equipmentRunTime.getTotalVolumeWidth()).compareTo(process.getVolumeWidth()) < 0) {
+            if (pe.getEquipmentParameter().getEquipmentWidth().subtract(equipmentRunTime.getTotalVolumeWidth()).compareTo(process.getVolumeWidth().add(pe.getEquipmentParameter().getFurnace())) < 0) {
                 jumpMark = false;
             }
             // 重量余量

+ 328 - 34
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/score/ApsConstraintProvider.java

@@ -1,22 +1,22 @@
 package com.rongwei.rwapsserver.aps.score;
 
-import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateUnit;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.StrUtil;
 import com.rongwei.rwapsserver.aps.domain.*;
-import com.rongwei.rwapsserver.aps.util.ApsConstants;
+import org.optaplanner.core.api.score.buildin.hardmediumsoft.HardMediumSoftScore;
 import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
 import org.optaplanner.core.api.score.stream.*;
 
 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.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
-import static org.optaplanner.core.api.score.stream.ConstraintCollectors.count;
-
 public class ApsConstraintProvider implements ConstraintProvider {
 
     private ZoneId zoneId = ZoneId.systemDefault();
@@ -28,17 +28,22 @@ public class ApsConstraintProvider implements ConstraintProvider {
 //                noPreGbAfterNow(constraintFactory),
                 hasOnePreGbAfterNow(constraintFactory),
                 eqTimeCross(constraintFactory),
-                deliveryDate(constraintFactory),
-                seriesProduce(constraintFactory),
                 seriesProduceTimeWait(constraintFactory),
+                seriesProduceWashTimeWait(constraintFactory),
                 lzTimeLessMaxWait(constraintFactory),
                 equipmentRunTime(constraintFactory),
-                balancedEqUse(constraintFactory),
+                eqTimeCrossTuihuo(constraintFactory),
 
+                deliveryDate(constraintFactory),
+                seriesProduce(constraintFactory),
                 seriesProduceWashingFurnace(constraintFactory),
-                seriesProduceWashTimeWait(constraintFactory),
+                mergeTuihuo(constraintFactory),
+                sameEquipment(constraintFactory),
 
                 sameProcessSeries(constraintFactory),
+                processNear(constraintFactory),
+
+                //                balancedEqUse(constraintFactory),
         };
     }
 
@@ -408,7 +413,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
                     }
                     return bln;
                 })
-                .penalize(HardSoftScore.ONE_HARD,(productionProcesses) -> 40)
+                .penalize(HardMediumSoftScore.ONE_HARD,(productionProcesses) -> 40)
                 .asConstraint("hasOnePreGbAfterNow");
     }
 
@@ -462,7 +467,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
                     }
                     return bol;
                 })
-                .penalize(HardSoftScore.ONE_HARD,(proc1)->80)
+                .penalize(HardMediumSoftScore.ONE_HARD,(proc1)->80)
                 .asConstraint("equipmentRunTime");
     }
 
@@ -500,7 +505,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
                     }
                     return bol;
                 })
-                .penalize(HardSoftScore.ONE_HARD,(proc1)->90)
+                .penalize(HardMediumSoftScore.ONE_HARD,(proc1)->90)
                 .asConstraint("lzTimeLessMaxWait");
     }
 
@@ -525,7 +530,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
                     }
                     return false;
                 })
-                .penalize(HardSoftScore.ONE_HARD,(equipmentEquassociated, processess) -> {
+                .penalize(HardMediumSoftScore.ONE_HARD,(equipmentEquassociated, processess) -> {
                     int washingFurnaceCount = seriesProduceWashingTimeFurnaceCount(processess);
                     return washingFurnaceCount*10;
                 })
@@ -620,7 +625,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
                     }
                     return false;
                 })
-                .penalize(HardSoftScore.ONE_HARD,(equipmentId,processes)->{
+                .penalize(HardMediumSoftScore.ONE_HARD,(equipmentId,processes)->{
                     int counNum = seriesProduceTimeWaitCount(processes);
                     return counNum*10;
                 })
@@ -761,11 +766,15 @@ public class ApsConstraintProvider implements ConstraintProvider {
                     if(proc1.getStartTime() == null || proc2.getStartTime() == null){
                         return false;
                     }
-                    Boolean b1 = (proc1.getStartTime().compareTo(proc2.getStartTime())<=0 && proc2.getStartTime().compareTo(proc1.getEndTime())<=0);
-                    Boolean b2 = (proc2.getStartTime().compareTo(proc1.getStartTime())<=0 && proc1.getStartTime().compareTo(proc2.getEndTime())<=0);
-                    return b1 || b2;
+                    Boolean b1 = proc1.getEndTime().compareTo(proc2.getStartTime())<=0;
+                    Boolean b2 = proc2.getEndTime().compareTo(proc1.getStartTime())<=0;
+                    if(b1 || b2){
+                        return false;
+                    }else{
+                        return true;
+                    }
                 })
-                .penalize(HardSoftScore.ONE_HARD,(proc1,proc2)->100)
+                .penalize(HardMediumSoftScore.ONE_HARD,(proc1,proc2)->100)
                 .asConstraint("eqTimeCross");
     }
 
@@ -779,23 +788,131 @@ public class ApsConstraintProvider implements ConstraintProvider {
                 .filter(pro->{
                     return pro.getProcessType().equals("成退") || pro.getProcessType().equals("中退");
                 })
-                .join(ProductionProcesses.class,Joiners.equal(ProductionProcesses::getEquipmentId))
-                .filter((proc1,proc2)->{
-                    if(proc1.getId() == proc2.getId() ||
-                            (StrUtil.isNotBlank(proc1.getMergeProcessMark()) && StrUtil.isNotBlank(proc2.getMergeProcessMark()) && proc1.getMergeProcessMark().equals(proc2.getMergeProcessMark()))){
+                .groupBy(ProductionProcesses::getEquipmentId,ConstraintCollectors.toList())
+                .filter((equipmentEquassociated,processes) -> {
+                    if(processes != null && processes.size()>0){
+                        Integer num = eqTimeCrossTuihuoCount(processes,"1");
+                        if(num>0){
+                            return true;
+                        }
                         return false;
-                    }
-                    if(proc1.getStartTime() == null || proc2.getStartTime() == null){
+                    }else{
                         return false;
                     }
-                    Boolean b1 = (proc1.getStartTime().compareTo(proc2.getStartTime())<0 && proc2.getStartTime().compareTo(proc1.getEndTime())<0);
-                    Boolean b2 = (proc2.getStartTime().compareTo(proc1.getStartTime())<0 && proc1.getStartTime().compareTo(proc2.getEndTime())<0);
-                    return b1 || b2;
                 })
-                .penalize(HardSoftScore.ONE_HARD,(proc1,proc2)->100)
+                .penalize(HardMediumSoftScore.ONE_HARD,(equipmentEquassociated,processes)->{
+                    Integer num = eqTimeCrossTuihuoCount(processes,"2");
+                    return num*100;
+                })
                 .asConstraint("eqTimeCrossTuihuo");
     }
 
+    /**
+     * 退火工序冲突计算
+     * @param processes
+     * @param type(1:是否存在冲突,2:冲突得分计算)
+     * @return
+     */
+    private Integer eqTimeCrossTuihuoCount(List<ProductionProcesses> processes,String type){
+        int b = 0;
+        Equipment equipment = null;
+        if(processes != null && processes.size()>0){
+            equipment = processes.get(0).getEquipment();
+        }
+        List<ProductionProcesses> hasStartTimeProcess = processes.stream().filter(v -> v.getStartTime() != null).collect(Collectors.toList());
+        // 设备占用时间参与连续生产排程
+        if(equipment != null && equipment.getEquipmentRunTimes() != null && equipment.getEquipmentRunTimes().size()>0){
+            for (EquipmentRunTime equipmentRunTime : equipment.getEquipmentRunTimes()) {
+                ProductionProcesses pp = new ProductionProcesses();
+                pp.setStartTime(equipmentRunTime.getStartRunTime());
+                pp.setSeriesProduceMark(equipmentRunTime.getSeriesProduceMark());
+                pp.setProcessType(equipmentRunTime.getProcessType());
+                pp.setBsProcessesId(Arrays.asList(new String[]{"haspcprocess"}));
+                pp.setVolumeWidth(equipmentRunTime.getTotalVolumeWidth());
+                pp.setSinglerollweight(equipmentRunTime.getTotalSinglerollweight());
+                if(equipmentRunTime.getOccupyType().equals("process")){
+                    pp.setTaskType("processes");
+                }else {
+                    pp.setTaskType("maintenance");
+                }
+                hasStartTimeProcess.add(pp);
+            }
+        }
+        // 按照开始时间排序
+        Collections.sort(hasStartTimeProcess, Comparator.comparing(ProductionProcesses::getSeriSort));
+        // 退火合并工序
+        Map<String,List<ProductionProcesses>> ppMap = new HashMap<>();
+        for(int i=0;i<hasStartTimeProcess.size()-1;i++){
+            ProductionProcesses prePro = hasStartTimeProcess.get(i);
+            ProductionProcesses nextPro = hasStartTimeProcess.get(i+1);
+            Map<String, String> conflictRoptions1 = prePro.getConflictRoptions();
+            Map<String, String> conflictRoptions2 = nextPro.getConflictRoptions();
+            if(conflictRoptions1.containsKey("hard-eqTimeCrossTuihuo")){
+                conflictRoptions1.remove("hard-eqTimeCrossTuihuo");
+            }
+            if(conflictRoptions2.containsKey("hard-eqTimeCrossTuihuo")){
+                conflictRoptions2.remove("hard-eqTimeCrossTuihuo");
+            }
+            // 开始时间相等为合并工序
+            if (prePro.getStartTime().compareTo(nextPro.getStartTime()) == 0){
+                if(prePro.getTaskType().equals("maintenance") || nextPro.getTaskType().equals("maintenance")){
+                    if("2".equals(type)){
+//                        System.out.println("1:作业加工时间有交叉");
+                        conflictRoptions1.put("hard-eqTimeCrossTuihuo","作业加工时间有交叉");
+                        conflictRoptions2.put("hard-eqTimeCrossTuihuo","作业加工时间有交叉");
+                    }
+                    b++;
+                }else{
+                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+                    String startTimeKey = prePro.getStartTime().format(formatter);
+                    if(!ppMap.containsKey(startTimeKey)){
+                        List<ProductionProcesses> pps = new ArrayList<>();
+                        ppMap.put(startTimeKey,pps);
+                    }
+                    List<ProductionProcesses> processesList = ppMap.get(startTimeKey);
+                    List<ProductionProcesses> preHas = processesList.stream().filter(v -> v.getId().equals(prePro.getId())).collect(Collectors.toList());
+                    List<ProductionProcesses> nextHas = processesList.stream().filter(v -> v.getId().equals(nextPro.getId())).collect(Collectors.toList());
+                    if(preHas == null || preHas.size() == 0){
+                        processesList.add(prePro);
+                    }
+                    if(nextHas == null || nextHas.size() == 0){
+                        processesList.add(nextPro);
+                    }
+                }
+            }else{
+                if(prePro.getEndTime().compareTo(nextPro.getStartTime()) == 1){
+                    if("2".equals(type)){
+//                        System.out.println("1:作业加工时间有交叉");
+                        conflictRoptions1.put("hard-eqTimeCrossTuihuo","作业加工时间有交叉");
+                        conflictRoptions2.put("hard-eqTimeCrossTuihuo","作业加工时间有交叉");
+                    }
+                    b++;
+                }
+            }
+        }
+        //  检查合并工序是否超过容量
+        for (Map.Entry<String,List<ProductionProcesses>> entry: ppMap.entrySet()) {
+            List<ProductionProcesses> v = entry.getValue();
+            BigDecimal totalWidth = new BigDecimal("0");
+            BigDecimal totalWeight = new BigDecimal("0");
+            for (ProductionProcesses productionProcesses : v) {
+                totalWidth = totalWidth.add(productionProcesses.getVolumeWidth()).add(productionProcesses.getEquipment().getEquipmentParameter().getFurnace());
+                totalWeight = totalWeight.add(productionProcesses.getSinglerollweight());
+            }
+            if(totalWidth.compareTo(v.get(0).getEquipment().getEquipmentParameter().getEquipmentWidth())>0
+                    || totalWeight.compareTo(v.get(0).getEquipment().getEquipmentParameter().getEquipmentBearing())>0){
+                if("2".equals(type)){
+//                    System.out.println("1:作业加工时间有交叉");
+                    for (ProductionProcesses productionProcesses : v) {
+                        productionProcesses.getConflictRoptions().put("hard-eqTimeCrossTuihuo","合并的作业超出设备容量");
+                    }
+                }
+                b++;
+            }
+        }
+        return b;
+    }
+
     /**
      * 软约束:交货日期,根据延迟交货日期的天数来做惩罚分数计算
      * @param constraintFactory
@@ -803,12 +920,13 @@ public class ApsConstraintProvider implements ConstraintProvider {
      */
     private Constraint deliveryDate(ConstraintFactory constraintFactory) {
         return constraintFactory.forEach(ProductionProcesses.class)
+                .filter(productionProcesses -> productionProcesses.getNextProcesses() == null)
                 .filter(productionProcesses -> {
                     /*
                         获取最后一步工步的结束时间(最后一步工步的结束时间即此产品生产的实际结束时间)
                         并且获取结束时间大于生产订单的交货日期
                      */
-                    if(productionProcesses.getEndTime() == null || productionProcesses.getNextProcesses() == null){
+                    if(productionProcesses.getEndTime() == null){
                         return false;
                     }
                     // 取最小订单交货日期
@@ -826,7 +944,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
                             productionProcesses.getEndTime().atZone(zoneId).toInstant().toEpochMilli()>deliveryMinDate.getTime();
                     return bol;
                 })
-                .penalize(HardSoftScore.ONE_SOFT,(productionProcesses) ->{
+                .penalize(HardMediumSoftScore.ONE_MEDIUM,(productionProcesses) ->{
                     Date deliveryMinDate = null;
                     for (ProduceOrder produceOrder : productionProcesses.getProduceOrder()) {
                         if(deliveryMinDate == null){
@@ -864,7 +982,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
                     }
                     return isbalance;
                 })
-                .penalize(HardSoftScore.ONE_SOFT,(taskType, processess) -> {
+                .penalize(HardMediumSoftScore.ONE_SOFT,(taskType, processess) -> {
                     Integer balanceNum = balanceCount(processess);
                     return balanceNum;
                 })
@@ -946,7 +1064,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
                     }
                     return false;*/
                 })
-                .penalize(HardSoftScore.ONE_SOFT,(equipmentId,processes)->{
+                .penalize(HardMediumSoftScore.ONE_MEDIUM,(equipmentId,processes)->{
                     int countNum = seriesProduceCount(processes);
                     return countNum*100;
                 })
@@ -986,13 +1104,23 @@ public class ApsConstraintProvider implements ConstraintProvider {
         }
         for(int i=0;i<hasStartTimeProcess.size()-1;i++){
             if(hasStartTimeProcess.get(i).getSeriesProduceMark() != null && hasStartTimeProcess.get(i+1).getSeriesProduceMark() != null){
+                Map<String, String> conflictRoptions1 = hasStartTimeProcess.get(i).getConflictRoptions();
+                Map<String, String> conflictRoptions2 = hasStartTimeProcess.get(i+1).getConflictRoptions();
                 if("铸轧".equals(hasStartTimeProcess.get(i).getProcessType())){
+                    if(conflictRoptions1.containsKey("soft-seriesProduceZz")){
+                        conflictRoptions1.remove("soft-seriesProduceZz");
+                    }
+                    if(conflictRoptions2.containsKey("soft-seriesProduceZz")){
+                        conflictRoptions2.remove("soft-seriesProduceZz");
+                    }
                     String[] serspre = hasStartTimeProcess.get(i).getSeriesProduceMark().split("\\^_\\^");
                     String[] sersafter = hasStartTimeProcess.get(i+1).getSeriesProduceMark().split("\\^_\\^");
                     if(serspre.length == 5 && sersafter.length == 5){
                         // 合金不同或者产品类型不同则需要换辊和立板
                         if(!serspre[0].equals(sersafter[0]) || !serspre[1].equals(sersafter[1])){
                             b = b+2;
+                            conflictRoptions1.put("soft-seriesProduceZz","和后一道工序违反换辊和立板的连续约束");
+                            conflictRoptions2.put("soft-seriesProduceZz","和前一道工序违反换辊和立板的连续约束");
                         }else{
                             // 合金相同情况下后面的宽度大于前面的宽度需要换辊和立板
                             // 合金相同情况下后面的宽度小于前面的宽度需要立板
@@ -1004,8 +1132,12 @@ public class ApsConstraintProvider implements ConstraintProvider {
                                 BigDecimal i2 = new BigDecimal(s2);
                                 if(i1.compareTo(i2)<0){
                                     b = b+2;
+                                    conflictRoptions1.put("soft-seriesProduceZz","和后一道工序违反换辊和立板的连续约束");
+                                    conflictRoptions2.put("soft-seriesProduceZz","和前一道工序违反换辊和立板的连续约束");
                                 }else if(i1.compareTo(i2)>0){
                                     b++;
+                                    conflictRoptions1.put("soft-seriesProduceZz","和后一道工序违反立板的连续约束");
+                                    conflictRoptions2.put("soft-seriesProduceZz","和前一道工序违反立板的连续约束");
                                 }
                             }catch (Exception e){
                                 e.printStackTrace();
@@ -1013,6 +1145,12 @@ public class ApsConstraintProvider implements ConstraintProvider {
                         }
                     }
                 } else if ("冷轧".equals(hasStartTimeProcess.get(i).getProcessType())) {
+                    if(conflictRoptions1.containsKey("soft-seriesProduceLz")){
+                        conflictRoptions1.remove("soft-seriesProduceLz");
+                    }
+                    if(conflictRoptions2.containsKey("soft-seriesProduceLz")){
+                        conflictRoptions2.remove("soft-seriesProduceLz");
+                    }
                     String[] serspre = hasStartTimeProcess.get(i).getSeriesProduceMark().split("\\^_\\^");
                     String[] sersafter = hasStartTimeProcess.get(i+1).getSeriesProduceMark().split("\\^_\\^");
                     // 前后道所属作业ID
@@ -1021,6 +1159,8 @@ public class ApsConstraintProvider implements ConstraintProvider {
                     if(serspre.length == 5 && sersafter.length == 5){
                         if(!serspre[0].equals(sersafter[0]) || !serspre[1].equals(sersafter[1])){
                             b = b+10;
+                            conflictRoptions1.put("soft-seriesProduceLz","和后一道工序违反换辊的连续约束");
+                            conflictRoptions2.put("soft-seriesProduceLz","和前一道工序违反换辊的连续约束");
                         }else{
                             // 前道工序宽度、输入物料厚度、输出物料厚度
                             String s1 = serspre[2];
@@ -1036,10 +1176,14 @@ public class ApsConstraintProvider implements ConstraintProvider {
                                 // 后端工序大于前道工序,并且大于30mm
                                 if((i1.add(new BigDecimal("30"))).compareTo(i2)<0){
                                     b = b+6;
+                                    conflictRoptions1.put("soft-seriesProduceLz","和后一道工序违反换辊的连续约束");
+                                    conflictRoptions2.put("soft-seriesProduceLz","和前一道工序违反换辊的连续约束");
                                 }
                                 // 后端工序大于前道工序,并且小于30mm
                                 else if(i1.compareTo(i2)<0 && (i1.add(new BigDecimal("30"))).compareTo(i2)>=0){
                                     b = b+5;
+                                    conflictRoptions1.put("soft-seriesProduceLz","和后一道工序违反换辊的连续约束");
+                                    conflictRoptions2.put("soft-seriesProduceLz","和前一道工序违反换辊的连续约束");
                                 }
                                 // 后端工序小于前道工序
                                 else if(i1.compareTo(i2)>0){
@@ -1096,9 +1240,9 @@ public class ApsConstraintProvider implements ConstraintProvider {
                     }
                     return false;*/
                 })
-                .penalize(HardSoftScore.ONE_SOFT,(equipmentEquassociated, processess) -> {
+                .penalize(HardMediumSoftScore.ONE_MEDIUM,(equipmentEquassociated, processess) -> {
                     int washingFurnaceCount = seriesProduceWashingFurnaceCount(processess);
-                    return washingFurnaceCount*10000;
+                    return washingFurnaceCount*100;
                 })
                 .asConstraint("seriesProduceWashingFurnace");
     }
@@ -1148,6 +1292,14 @@ public class ApsConstraintProvider implements ConstraintProvider {
         int notSeriesNum = 0;
         // 评分计算
         for(int i=0;i<hasStartTimeProcess.size()-1;i++){
+            Map<String, String> conflictRoptions1 = hasStartTimeProcess.get(i).getConflictRoptions();
+            Map<String, String> conflictRoptions2 = hasStartTimeProcess.get(i+1).getConflictRoptions();
+            if(conflictRoptions1.containsKey("soft-seriesProduceWashingFurnaceZz")){
+                conflictRoptions1.remove("soft-seriesProduceWashingFurnaceZz");
+            }
+            if(conflictRoptions2.containsKey("soft-seriesProduceWashingFurnaceZz")){
+                conflictRoptions2.remove("soft-seriesProduceWashingFurnaceZz");
+            }
             List<WashingMetal> closealloynames = hasStartTimeProcess.get(i).getApsOverallConfig().getClosealloynames();
             if(closealloynames != null && closealloynames.size()>0){
                 for (WashingMetal closealloyname : closealloynames) {
@@ -1155,6 +1307,8 @@ public class ApsConstraintProvider implements ConstraintProvider {
                     if(closealloyname.getProcessmetals().contains(hasStartTimeProcess.get(i).getVolumeMetal())
                             && closealloyname.getNextprocessmetals().contains(hasStartTimeProcess.get(i+1).getVolumeMetal())){
                         notSeriesNum++;
+                        conflictRoptions1.put("soft-seriesProduceWashingFurnaceZz","和后一道工序违反洗炉的连续约束");
+                        conflictRoptions2.put("soft-seriesProduceWashingFurnaceZz","和前一道工序违反洗炉的连续约束");
                         break;
                     }
                 }
@@ -1176,7 +1330,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
                             && !"成退".equals(process.getProcessType()) && !"中退".equals(process.getProcessType());
                 })
                 .groupBy(ProductionProcesses::getEquipmentId,ConstraintCollectors.toList())
-                .penalize(HardSoftScore.ONE_SOFT,(equipmentId, processess) -> {
+                .penalize(HardMediumSoftScore.ONE_SOFT,(equipmentId, processess) -> {
                     int notSeriesNum = 0;
                     List<ProductionProcesses> hasStartTimeProcess = processess.stream().filter(v -> v.getStartTime() != null).collect(Collectors.toList());
                     // 根据开始时间排序
@@ -1193,4 +1347,144 @@ public class ApsConstraintProvider implements ConstraintProvider {
                 })
                 .asConstraint("sameProcessSeries");
     }
+
+    /**
+     * 排程时间尽量靠前
+     * @param constraintFactory
+     * @return
+     */
+    private Constraint processNear(ConstraintFactory constraintFactory){
+        return constraintFactory.forEach(ProductionProcesses.class)
+                .filter((process)->{
+                    if(process.getPreviousProcesses() == null || process.getPreviousProcesses().size() == 0){
+                        if(process.getStartTime().compareTo(process.getApsOverallConfig().getStartTime())>0){
+                            return true;
+                        }else{
+                            return false;
+                        }
+                    }else{
+                        ProductionProcesses preProcess = process.getPreviousProcesses().get(0);
+                        // 流转时间
+                        Integer lzTimes = 0;
+                        if(preProcess != null){
+                            if(preProcess.getEquipment().getWorkshopid() != null && preProcess.getEquipment().getWorkshopid().equals(process.getEquipment().getWorkshopid())){
+                                lzTimes = process.getApsOverallConfig().getRoamTime().get("WORKSHOP_IN");
+                            }else{
+                                lzTimes = process.getApsOverallConfig().getRoamTime().get("WORKSHOP_CROSS");
+                            }
+                            // 最小等待时间对比流转时间
+                            if(preProcess.getMinWaitTime() != null && lzTimes<preProcess.getMinWaitTime()){
+                                lzTimes = preProcess.getMinWaitTime();
+                            }
+                        }
+                        LocalDateTime minStartTime = preProcess.getEndTime().plusMinutes(lzTimes);
+                        if(process.getStartTime().compareTo(minStartTime)>0){
+                            return true;
+                        }
+                        return false;
+                    }
+                })
+                .penalize(HardMediumSoftScore.ONE_SOFT,(process) -> {
+                    int processNearNum = 0;
+                    if(process.getPreviousProcesses() == null || process.getPreviousProcesses().size() == 0){
+                        processNearNum = (int)ChronoUnit.MINUTES.between(process.getApsOverallConfig().getStartTime(), process.getStartTime());
+                    }else{
+                        ProductionProcesses preProcess = process.getPreviousProcesses().get(0);
+                        // 流转时间
+                        Integer lzTimes = 0;
+                        if(preProcess != null){
+                            if(preProcess.getEquipment().getWorkshopid() != null && preProcess.getEquipment().getWorkshopid().equals(process.getEquipment().getWorkshopid())){
+                                lzTimes = process.getApsOverallConfig().getRoamTime().get("WORKSHOP_IN");
+                            }else{
+                                lzTimes = process.getApsOverallConfig().getRoamTime().get("WORKSHOP_CROSS");
+                            }
+                            // 最小等待时间对比流转时间
+                            if(preProcess.getMinWaitTime() != null && lzTimes<preProcess.getMinWaitTime()){
+                                lzTimes = preProcess.getMinWaitTime();
+                            }
+                        }
+                        LocalDateTime minStartTime = preProcess.getEndTime().plusMinutes(lzTimes);
+                        processNearNum = (int)ChronoUnit.MINUTES.between(minStartTime, process.getStartTime());
+                    }
+                    return processNearNum;
+                })
+                .asConstraint("processNear");
+    }
+
+    /**
+     * 退火工序优先合并
+     * @param constraintFactory
+     * @return
+     */
+    private Constraint mergeTuihuo(ConstraintFactory constraintFactory){
+        return constraintFactory.forEach(ProductionProcesses.class)
+                .filter(pro->{
+                    return pro.getProcessType().equals("成退") || pro.getProcessType().equals("中退");
+                })
+                .groupBy(ProductionProcesses::getEquipmentId,ConstraintCollectors.toList())
+                .filter((equipmentId,processes) -> {
+                    if(processes != null && processes.size()>0){
+                        return true;
+                    }else{
+                        return false;
+                    }
+                })
+                .penalize(HardMediumSoftScore.ONE_MEDIUM,(equipmentId,processes)->{
+                    // 退火合并工序
+                    Map<String,List<ProductionProcesses>> ppMap = new HashMap<>();
+                    for(int i=0;i<processes.size()-1;i++){
+                        ProductionProcesses prePro = processes.get(i);
+                        ProductionProcesses nextPro = processes.get(i+1);
+                        // 开始时间相等为合并工序
+                        if (prePro.getStartTime().compareTo(nextPro.getStartTime()) == 0){
+                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+                            String startTimeKey = prePro.getStartTime().format(formatter);
+                            if(!ppMap.containsKey(startTimeKey)){
+                                List<ProductionProcesses> pps = new ArrayList<>();
+                                ppMap.put(startTimeKey,pps);
+                            }
+                            List<ProductionProcesses> processesList = ppMap.get(startTimeKey);
+                            List<ProductionProcesses> preHas = processesList.stream().filter(v -> v.getId().equals(prePro.getId())).collect(Collectors.toList());
+                            List<ProductionProcesses> nextHas = processesList.stream().filter(v -> v.getId().equals(nextPro.getId())).collect(Collectors.toList());
+                            if(preHas == null || preHas.size() == 0){
+                                processesList.add(prePro);
+                            }
+                            if(nextHas == null || nextHas.size() == 0){
+                                processesList.add(nextPro);
+                            }
+                        }
+                    }
+                    return ppMap.size()*10000;
+                })
+                .asConstraint("mergeTuihuo");
+    }
+
+    /**
+     * 相同作业放在同一设备上加工
+     * @param constraintFactory
+     * @return
+     */
+    private Constraint sameEquipment(ConstraintFactory constraintFactory){
+        return constraintFactory.forEach(ProductionProcesses.class)
+                .groupBy(ProductionProcesses::getUniqueBsProcessesId,ConstraintCollectors.toList())
+                .filter((equipmentEquassociated,processes) -> {
+                    if(processes != null && processes.size()>0){
+                        return true;
+                    }else{
+                        return false;
+                    }
+                })
+                .penalize(HardMediumSoftScore.ONE_MEDIUM,(uniqueBsProcessesId,processes)->{
+                    /*if(uniqueBsProcessesId.equals("8aa1d524436149859623a6a67a4af6c0")){
+                        System.out.println("*********************************");
+                        for (ProductionProcesses process : processes) {
+                            System.out.println(process.getEquipmentId());
+                        }
+                        System.out.println("*********************************");
+                    }*/
+                    Map<String, List<ProductionProcesses>> listMap = processes.stream().collect(Collectors.groupingBy(ProductionProcesses::getEquipmentId));
+                    return listMap.size()*1000;
+                })
+                .asConstraint("sameEquipment");
+    }
 }

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

@@ -75,7 +75,22 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
                 if(solver.isEveryProblemChangeProcessed()) {
                     event.getNewBestSolution().setConstructionHeuristicEnd(true);
                     if(event.getNewBestSolution().getStepBestProcessesList() == null){
-                        List<ProductionProcesses> processesList = ObjectUtil.cloneByStream(event.getNewBestSolution().getProcessesList());
+                        List<ProductionProcesses> processesList = new ArrayList<>();
+//                        List<ProductionProcesses> processesList = ObjectUtil.cloneByStream(event.getNewBestSolution().getProcessesList());
+                        for (ProductionProcesses productionProcesses : event.getNewBestSolution().getProcessesList()) {
+                            ProductionProcesses newPro = new ProductionProcesses();
+                            newPro.setId(productionProcesses.getId());
+                            newPro.setEquipmentId(productionProcesses.getEquipmentId());
+                            Equipment eq = new Equipment();
+                            eq.setId(productionProcesses.getEquipment().getId());
+                            newPro.setEquipment(eq);
+                            newPro.setProduceTime(productionProcesses.getProduceTime());
+                            newPro.setStartTime(productionProcesses.getStartTime());
+                            newPro.setEndTime(productionProcesses.getEndTime());
+                            newPro.setVolumeWidth(productionProcesses.getVolumeWidth());
+                            newPro.setSinglerollweight(productionProcesses.getSinglerollweight());
+                            processesList.add(newPro);
+                        }
                         event.getNewBestSolution().setStepBestProcessesList(processesList);
                     }
                     System.out.println("************"+event.getNewBestScore()+"************");
@@ -99,7 +114,9 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
         ScoreExplanation<ApsSolution, HardSoftScore> explain1 = scoreManager.explain(solvedBalance);
         log.info(explain1.toString());*/
         productionScheduleRetVo.setScoreResult(scoreManager.explain(solvedBalance).toString());
-
+        // 得分分析
+        softExplain(explain,solvedBalance.getProcessesList());
+        productionScheduleRetVo.setProcesses(solvedBalance.getProcessesList());
         // 循环引用ProductionProcesses置空
         for (ProductionProcesses productionProcesses : solvedBalance.getProcessesList()) {
             productionProcesses.setPreviousProcesses(null);
@@ -107,17 +124,31 @@ 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("***************************");
-            }*/
+            // 冲突约束补充处理
+            if(productionProcesses.getConflictRoptions() != null && productionProcesses.getConflictRoptions().size()>0){
+                productionProcesses.getConflictRoptions().forEach((k,v)->{
+                    if(StrUtil.isBlank(productionProcesses.getHasConflict())){
+                        productionProcesses.setHasConflict("y");
+                    }
+                    // 强制约束
+                    if(k.indexOf("hard") == 0){
+                        if(StrUtil.isBlank(productionProcesses.getConflictDes())){
+                            productionProcesses.setConflictDes(v);
+                        }else{
+                            productionProcesses.setConflictDes(productionProcesses.getConflictDes()+";"+v);
+                        }
+                    }
+                    // 非强制约束
+                    else if (k.indexOf("soft") == 0) {
+                        if(StrUtil.isBlank(productionProcesses.getSoftconflictdes())){
+                            productionProcesses.setSoftconflictdes(v);
+                        }else{
+                            productionProcesses.setSoftconflictdes(productionProcesses.getSoftconflictdes()+";"+v);
+                        }
+                    }
+                });
+            }
         }
-        // 得分分析
-        softExplain(explain,solvedBalance.getProcessesList());
-        productionScheduleRetVo.setProcesses(solvedBalance.getProcessesList());
         return productionScheduleRetVo;
     }
 
@@ -307,6 +338,10 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
                 process.setEquipment(process.getOptionalProviderEquipments().get(0));
                 process.setIfLock(true);
             }
+            // 特殊冲突约束Map初始化
+            process.setConflictRoptions(new HashMap<>());
+            // 唯一作业ID设值
+            process.setUniqueBsProcessesId(process.getBsProcessesId().get(0));
         }
         // 设备占用时间段合并处理
         for (Equipment equipment : productionScheduleVo.getEquipmentList()) {

+ 1 - 1
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/util/ApsConstants.java

@@ -22,7 +22,7 @@ public class ApsConstants {
         constraintDesc.put("eqTimeCross","与加工设备其他作业加工时间重叠");
         constraintDesc.put("seriesProduceTimeWait","没有预留足够的上机准备时间和下机收尾时间");
         constraintDesc.put("deliveryDate","不满足订单交货期");
-        constraintDesc.put("seriesProduce","与上道工序作业不能连续生产");
+//        constraintDesc.put("seriesProduce","与上道工序作业不能连续生产");
 
         hardConstraint.add("eqTypeSame");
         hardConstraint.add("noPreGbAfterNow");