瀏覽代碼

排程算法优化

fangpy 1 年之前
父節點
當前提交
2ea472aee7

+ 12 - 0
rw-aps-server/pom.xml

@@ -84,6 +84,18 @@
             <artifactId>druid-spring-boot-starter</artifactId>
             <version>${druid.starter.version}</version>
         </dependency>
+
+        <!--<dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.12.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+            <version>2.3.0</version>
+        </dependency>-->
     </dependencies>
 
     <build>

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

@@ -133,11 +133,18 @@ public class ApsBalancingApplication {
                 .plusMinutes(10); // 加上调整后的分钟数的余数
 
         System.out.println(nearestTenMinutes);*/
-        List<String> a = new ArrayList<>();
+        /*List<String> a = new ArrayList<>();
         a.add("1");
         List<String> b = a;
         b.add("2");
-        System.out.println(a);
+        System.out.println(a);*/
+
+        /*BigDecimal a = new BigDecimal("516.78");
+        System.out.println(a.intValue());*/
+
+        System.out.println( 5 % 3);
+        System.out.println( 5 / 3);
+        System.out.println( 5 * 3);
     }
 
     public static void constraintTest(){

+ 25 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/controller/ApsSchedulingController.java

@@ -56,6 +56,31 @@ public class ApsSchedulingController {
         return productionScheduleRetVo;
     }
 
+    /**
+     * 退火任务运行API
+     * @param productionScheduleVo
+     * @return
+     */
+    @PostMapping("/productionThSchedule")
+    public ProductionScheduleRetVo productionThSchedule(@RequestBody ProductionScheduleVo productionScheduleVo) throws Exception{
+        ProductionScheduleRetVo productionScheduleRetVo = null;
+        try{
+            productionScheduleRetVo = productionScheduleService.tuiHuoSchedule(productionScheduleVo);
+            productionScheduleRetVo.setCode("200");
+        }catch(ApsException ae){
+            productionScheduleRetVo = new ProductionScheduleRetVo();
+            productionScheduleRetVo.setCode("500");
+            productionScheduleRetVo.setMsg(ae.getMessage());
+        }catch(Exception e){
+            e.printStackTrace();
+            log.error("排程平台异常:",e);
+            productionScheduleRetVo = new ProductionScheduleRetVo();
+            productionScheduleRetVo.setCode("500");
+            productionScheduleRetVo.setMsg("排程异常,请联系管理员");
+        }
+        return productionScheduleRetVo;
+    }
+
     /**
      * test
      * @return

+ 25 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/ApsCustomPhaseCommand.java

@@ -0,0 +1,25 @@
+package com.rongwei.rwapsserver.aps.domain;
+
+import org.optaplanner.core.api.score.director.ScoreDirector;
+import org.optaplanner.core.impl.phase.custom.CustomPhaseCommand;
+
+public class ApsCustomPhaseCommand implements CustomPhaseCommand<ApsSolution> {
+
+    @Override
+    public void changeWorkingSolution(ScoreDirector<ApsSolution> scoreDirector) {
+        ApsSolution workingSolution = scoreDirector.getWorkingSolution();
+        System.out.println("ApsCustomPhaseCommand...");
+    }
+
+    private void initializeProcessAssignmentList(ScoreDirector<ApsSolution> scoreDirector,ApsSolution workingSolution) {
+
+        /*for (MrProcessAssignment processAssignment : machineReassignment.getProcessAssignmentList()) {
+            MrMachine originalMachine = processAssignment.getOriginalMachine();
+            MrMachine machine = originalMachine == null ? machineReassignment.getMachineList().get(0) : originalMachine;
+            scoreDirector.beforeVariableChanged(processAssignment, "machine");
+            processAssignment.setMachine(machine);
+            scoreDirector.afterVariableChanged(processAssignment, "machine");
+            scoreDirector.triggerVariableListeners();
+        }*/
+    }
+}

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

@@ -1,5 +1,6 @@
 package com.rongwei.rwapsserver.aps.domain;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 
 import java.io.Serializable;
@@ -15,6 +16,7 @@ import java.util.Map;
 public class ApsOverallConfig implements Serializable {
 
     // 排程计划指定开始时间
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private LocalDateTime startTime;
 
     // 排程计划指定开始时间戳

+ 4 - 2
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/ProductionProcesses.java

@@ -29,7 +29,7 @@ import java.util.stream.Collectors;
 /**
  * 工步,工艺路线里的工步
  */
-@PlanningEntity
+@PlanningEntity(difficultyComparatorClass = ProductionProcessesDifficultyComparator.class)
 public class ProductionProcesses implements Serializable {
 
     private String id;
@@ -306,7 +306,9 @@ public class ProductionProcesses implements Serializable {
     }
 
     public void setDelay(Integer delay) {
-        this.delay = delay;
+        if(!this.ifLock){
+            this.delay = delay;
+        }
     }
 
     @ValueRangeProvider(id="equipmentRange")

+ 13 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/ProductionProcessesDifficultyComparator.java

@@ -0,0 +1,13 @@
+package com.rongwei.rwapsserver.aps.domain;
+
+import java.util.Comparator;
+
+public class ProductionProcessesDifficultyComparator implements Comparator<ProductionProcesses> {
+    @Override
+    public int compare(ProductionProcesses a, ProductionProcesses b) {
+        if(a.getPreviousProcesses() != null && a.getPreviousProcesses().size()>0){
+            System.out.println("a:"+a.getPreviousProcesses().get(0).getStartTime());
+        }
+        return a.getOrderMark().compareTo(b.getOrderMark());
+    }
+}

+ 53 - 40
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/listener/TaskStartTimeListener.java

@@ -89,21 +89,24 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
      */
     private void setNextAllStartTime(ScoreDirector<ApsSolution> scoreDirector,ProductionProcesses process){
         if(process.getEquipment() != null){
-            LocalDateTime startDateTime = startTimeNewSet(process,scoreDirector);
-
-            // 随机延时时间处理
-            if(process.getProcessType().equals("成退") || process.getProcessType().equals("中退")){
-                startDateTime = startDateTime.plusMinutes(process.getDelay() * 10);
-            } else if (process.getProcessType().equals("铸轧")) {
-                startDateTime = startDateTime.plusMinutes(process.getDelay() * 10);
-            } else if (process.getProcessType().equals("冷轧")) {
-                startDateTime = startDateTime.plusMinutes(process.getDelay() * 11);
-            } else{
-                startDateTime = startDateTime.plusMinutes(process.getDelay() * 10);
+            if(!process.getIfLock()){
+                LocalDateTime startDateTime = startTimeNewSet(process,scoreDirector);
+
+                // 随机延时时间处理
+                if(process.getProcessType().equals("成退") || process.getProcessType().equals("中退")){
+                    startDateTime = startDateTime.plusMinutes(process.getDelay() * 60);
+                } else if (process.getProcessType().equals("铸轧")) {
+                    startDateTime = startDateTime.plusMinutes(process.getDelay() * 60);
+                } else if (process.getProcessType().equals("冷轧")) {
+                    startDateTime = startDateTime.plusMinutes(process.getDelay() * 10);
+                } else{
+                    startDateTime = startDateTime.plusMinutes(process.getDelay() * 10);
+                }
+                scoreDirector.beforeVariableChanged(process, "startTime");
+                process.setStartTime(startDateTime);
+                scoreDirector.afterVariableChanged(process, "startTime");
             }
-            scoreDirector.beforeVariableChanged(process, "startTime");
-            process.setStartTime(startDateTime);
-            scoreDirector.afterVariableChanged(process, "startTime");
+
             if(process.getNextProcesses() != null && process.getNextProcesses().size()>0){
                 for (ProductionProcesses nextProcess : process.getNextProcesses()) {
                     setNextAllStartTime(scoreDirector,nextProcess);
@@ -474,11 +477,10 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
     }
 
     private LocalDateTime startTimeNewSet(ProductionProcesses process,ScoreDirector<ApsSolution> scoreDirector){
-        if(process.getBsProcessesId().get(0).equals("aade5e53bbee45a78cc8c3999aba8a39")){
-//            System.out.println(process);
+        if(process.getId().equals("23b6aee636c2461cb3102fa82be48f28")){
             int a = 0;
         }
-        if(process.getId().equals("2bf2e11039234f608730ac417e53008f")){
+        if(process.getId().equals("3236a3604b334a41be97067687e4bb5a")){
             int a = 0;
         }
         // 获取所有规划实体对象数据
@@ -520,8 +522,8 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
             if(process.getProcessType().equals("成退") || process.getProcessType().equals("中退")){
                 proStartTime = proStartTime.minusSeconds(proStartTime.getSecond()) // 减去当前秒数
                         .minusNanos(proStartTime.getNano()) // 减去当前纳秒数
-                        .plusMinutes(-proStartTime.getMinute() % 10) // 减去当前分钟数的余数,向下调整到最近的10的倍数
-                        .plusMinutes(10);
+                        .plusMinutes(-proStartTime.getMinute() % 60) // 减去当前分钟数的余数,向下调整到最近的10的倍数
+                        .plusMinutes(60);
             }
 
             LocalDateTime proEndTime = proStartTime.plusMinutes(process.getProduceTime());
@@ -533,6 +535,10 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
                 proMaxEndTime = proEndTime.plusMinutes(preProcess.getMaxWaitTime());
             }
 
+            /*if(1 == 1){
+                return proStartTime;
+            }*/
+
             // 当前工序设备已占用时间
             List<EquipmentRunTime> equipmentRunTimes = new ArrayList<>();
             if(process.getEquipment().getEquipmentRunTimes() != null && process.getEquipment().getEquipmentRunTimes().size()>0){
@@ -625,6 +631,8 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
             // 过滤
             // 按照开始时间排序
             equipmentRunTimes.sort(Comparator.comparing(EquipmentRunTime::getStartRunTime));
+
+            Integer delay = process.getDelay();
             // 有交叉的时间直接跳过,退火工序特殊处理
             if(equipmentRunTimes.size()>0){
                 for(int i = 0; i < equipmentRunTimes.size(); i++){
@@ -752,6 +760,9 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
                                 if(!preseries){
                                     preEndTime = preEndTime.plusMinutes(equipmentRunTime.getCutfinishmin()).plusMinutes(process.getPrepressworkmin());
                                 }
+                                if(preEndTime.compareTo(proStartTime)<0){
+                                    preEndTime = proStartTime;
+                                }
                                 LocalDateTime nextEndTime = preEndTime.plusMinutes(process.getProduceTime());
                                 if(!nextseries){
                                     nextEndTime = nextEndTime.plusMinutes(process.getCutfinishmin()).plusMinutes(nextEquipmentRunTime.getPrepressworkmin());
@@ -796,28 +807,30 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
      */
     private boolean seriesLz(EquipmentRunTime equipmentRunTime,ProductionProcesses process,Integer isBefore){
         boolean isSeriesLz = true;
-        String[] serspre = null;String[] sersafter = null;
-        if(isBefore == -1){
-            serspre = equipmentRunTime.getSeriesProduceMark().split("\\^_\\^");
-            sersafter = process.getSeriesProduceMark().split("\\^_\\^");
-        }else {
-            serspre = process.getSeriesProduceMark().split("\\^_\\^");
-            sersafter = equipmentRunTime.getSeriesProduceMark().split("\\^_\\^");
-        }
-        if(serspre.length == 5 && sersafter.length == 5){
-            if(!serspre[0].equals(sersafter[0]) || !serspre[1].equals(sersafter[1])){
-                isSeriesLz = false;
-            }else{
-                String s1 = serspre[2];
-                String s2 = sersafter[2];
-                try{
-                    BigDecimal i1 = new BigDecimal(s1);
-                    BigDecimal i2 = new BigDecimal(s2);
-                    if(i1.compareTo(i2)<0){
-                        isSeriesLz = false;
+        if(StrUtil.isNotBlank(equipmentRunTime.getSeriesProduceMark())){
+            String[] serspre = null;String[] sersafter = null;
+            if(isBefore == -1){
+                serspre = equipmentRunTime.getSeriesProduceMark().split("\\^_\\^");
+                sersafter = process.getSeriesProduceMark().split("\\^_\\^");
+            }else {
+                serspre = process.getSeriesProduceMark().split("\\^_\\^");
+                sersafter = equipmentRunTime.getSeriesProduceMark().split("\\^_\\^");
+            }
+            if(serspre.length == 5 && sersafter.length == 5){
+                if(!serspre[0].equals(sersafter[0]) || !serspre[1].equals(sersafter[1])){
+                    isSeriesLz = false;
+                }else{
+                    String s1 = serspre[2];
+                    String s2 = sersafter[2];
+                    try{
+                        BigDecimal i1 = new BigDecimal(s1);
+                        BigDecimal i2 = new BigDecimal(s2);
+                        if(i1.compareTo(i2)<0){
+                            isSeriesLz = false;
+                        }
+                    }catch (Exception e){
+                        e.printStackTrace();
                     }
-                }catch (Exception e){
-                    e.printStackTrace();
                 }
             }
         }

+ 100 - 346
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/score/ApsConstraintProvider.java

@@ -26,41 +26,28 @@ public class ApsConstraintProvider implements ConstraintProvider {
         return new Constraint[]{
 //                eqTypeSame(constraintFactory),
 //                noPreGbAfterNow(constraintFactory),
+//                lzTimeLessMaxWait(constraintFactory),
+
                 hasOnePreGbAfterNow(constraintFactory),
                 eqTimeCross(constraintFactory),
                 seriesProduceTimeWait(constraintFactory),
                 seriesProduceWashTimeWait(constraintFactory),
-                lzTimeLessMaxWait(constraintFactory),
                 equipmentRunTime(constraintFactory),
                 eqTimeCrossTuihuo(constraintFactory),
 
                 deliveryDate(constraintFactory),
                 seriesProduce(constraintFactory),
                 seriesProduceWashingFurnace(constraintFactory),
-//                mergeTuihuo(constraintFactory),
+                mergeTuihuo(constraintFactory),
                 sameEquipment(constraintFactory),
 
-                sameProcessSeries(constraintFactory),
+//                sameProcessSeries(constraintFactory),
                 processNear(constraintFactory),
 
                 //                balancedEqUse(constraintFactory),
         };
     }
 
-    /**
-     * 硬约束:工步所需的设备必须在工序的可选设备之内
-     * @param constraintFactory
-     * @return
-     */
-    private Constraint eqTypeSame(ConstraintFactory constraintFactory) {
-        return constraintFactory.forEach(ProductionProcesses.class)
-                .filter(productionProcesses -> {
-                    return !productionProcesses.getOptionalEquipments().contains(productionProcesses.getEquipment().getId());
-                })
-                .penalize(HardSoftScore.ONE_HARD,(productionProcesses) -> 300)
-                .asConstraint("eqTypeSame");
-    }
-
     /**
      * 硬约束:合并生产工序设备、开始时间、结束时间都一样
      * @param constraintFactory
@@ -118,202 +105,23 @@ public class ApsConstraintProvider implements ConstraintProvider {
     }
 
     /**
-     * 硬约束:没有上一步工步的开始时间小于当前时间
-     * @param constraintFactory
-     * @return
-     */
-    private Constraint noPreGbAfterNow(ConstraintFactory constraintFactory) {
-        return constraintFactory.forEach(ProductionProcesses.class)
-                .filter(productionProcesses -> {
-                    if(productionProcesses.getApsOverallConfig().getStartTimeLong() != null && productionProcesses.getApsOverallConfig().getStartTimeLong()>0){
-                        return productionProcesses.getPreviousProcesses() == null && productionProcesses.getStartTime().atZone(zoneId).toInstant().toEpochMilli() < productionProcesses.getApsOverallConfig().getStartTimeLong();
-                    }else{
-                        return productionProcesses.getPreviousProcesses() == null && productionProcesses.getStartTime().atZone(zoneId).toInstant().toEpochMilli() < DateUtil.date().getTime();
-                    }
-                })
-                .penalize(HardSoftScore.ONE_HARD,(productionProcesses) -> 80)
-                .asConstraint("noPreGbAfterNow");
-    }
-
-    /**
-     * 硬约束:有上一步工步的开始时间要大于上一步工步最早结束时间,小于最晚结束时间
-     * 根据上一步的最小等待时间和最大等待时间来判断
-     * @param constraintFactory
-     * @return
-     */
-    private Constraint hasPreGbAfterNow(ConstraintFactory constraintFactory) {
-        return constraintFactory.forEach(ProductionProcesses.class)
-                .filter(productionProcesses -> {
-                    // 获取上一步最晚结束时间
-                    LocalDateTime preLastMinTime = null;
-                    LocalDateTime preLastMaxTime = null;
-                    // 最大单批次生产时间
-                    Integer maxUnitProduceTime = 0;
-                    if(productionProcesses.getPreviousProcesses() != null){
-                        for (ProductionProcesses previousProcess : productionProcesses.getPreviousProcesses()) {
-                            // 流转时间
-                            Integer lzTimes = 0;
-                            if(previousProcess.getEquipment().getWorkshopid() != null && previousProcess.getEquipment().getWorkshopid().equals(productionProcesses.getEquipment().getWorkshopid())){
-                                lzTimes = productionProcesses.getApsOverallConfig().getRoamTime().get("WORKSHOP_IN");
-                            }else{
-                                lzTimes = productionProcesses.getApsOverallConfig().getRoamTime().get("WORKSHOP_CROSS");
-                            }
-                            // 单批次生产最大时间
-                            if(previousProcess.getUnitProduceTime() != null && maxUnitProduceTime<previousProcess.getUnitProduceTime()){
-                                maxUnitProduceTime = previousProcess.getUnitProduceTime();
-                            }
-
-                            // 计算最小、最大等待时间
-                            LocalDateTime thisMinEndTime = previousProcess.getEndTime();
-                            LocalDateTime thisMaxEndTime = null;
-                            if(previousProcess.getMinWaitTime() != null){
-                                /**
-                                 * 根据前后工序单批次生产时间比较来排序
-                                 * 1、前道工序单批次生产时间小于后道工序单批次生产时间,则最小开始时间等于单批次生产时间
-                                 * 2、前道工序单批次生产时间小于后道工序单批次生产时间,则从最后倒排时间
-                                 */
-
-
-                                // 最小等待时间对比流转时间
-                                if(lzTimes>previousProcess.getMinWaitTime()){
-                                    thisMinEndTime = thisMinEndTime.plusMinutes(lzTimes);
-                                }else{
-                                    thisMinEndTime = thisMinEndTime.plusMinutes(previousProcess.getMinWaitTime());
-                                }
-                            }
-                            if(previousProcess.getMaxWaitTime() != null){
-                                thisMaxEndTime = thisMaxEndTime.plusMinutes(previousProcess.getMaxWaitTime());
-                            }
-                            // 最小结束时间
-                            if(preLastMinTime == null){
-                                preLastMinTime = thisMinEndTime;
-                            }else{
-                                if(preLastMinTime.compareTo(thisMinEndTime)<0){
-                                    preLastMinTime = thisMinEndTime;
-                                }
-                            }
-                            // 最大结束时间
-                            if(thisMaxEndTime != null){
-                                if(preLastMaxTime == null){
-                                    preLastMaxTime = thisMaxEndTime;
-                                }else{
-                                    if(preLastMaxTime.compareTo(thisMinEndTime)>0){
-                                        preLastMaxTime = thisMaxEndTime;
-                                    }
-                                }
-                            }
-                        }
-
-                        boolean bln = productionProcesses.getStartTime().atZone(zoneId).toInstant().toEpochMilli() < preLastMinTime.atZone(zoneId).toInstant().toEpochMilli();
-                        if(preLastMaxTime != null){
-                            System.out.println("preLastMaxTime != null");
-                            bln = bln || productionProcesses.getStartTime().atZone(zoneId).toInstant().toEpochMilli() > preLastMaxTime.atZone(zoneId).toInstant().toEpochMilli();
-                        }
-                        return bln;
-                    }else{
-                        return false;
-                    }
-                })
-                .penalize(HardSoftScore.ONE_HARD,(productionProcesses) -> 80)
-                .asConstraint("hasPreGbAfterNow");
-    }
-
-    /**
-     * 前提条件:前道工序只有一个
-     * 硬约束:有上一步工步的开始时间要大于上一步工步最早结束时间,小于最晚结束时间
-     * 根据上一步的最小等待时间和最大等待时间来判断
+     * 单卷模式下前后道工序时间约束
      * @param constraintFactory
      * @return
      */
-    private Constraint hasOnePreGbAfterNowOld(ConstraintFactory constraintFactory) {
+    private Constraint hasOnePreGbAfterNow(ConstraintFactory constraintFactory) {
         return constraintFactory.forEach(ProductionProcesses.class)
                 .filter(productionProcesses -> {
+                    /*if(productionProcesses.getId().equals("2a231077b58844548c4a9d9e8f90f628")){
+                        int a = 1;
+                    }*/
                     boolean bln = false;
-                    // 最大单批次生产时间
-                    Integer maxUnitProduceTime = 0;
-                    // 最大流转时间
-                    Integer lzMaxTimes = 0;
-                    // 前道工序最小首批加工最大等待时间
-                    LocalDateTime lastFirstMaxWaitTime = null;
                     if(productionProcesses.getPreviousProcesses() != null && productionProcesses.getPreviousProcesses().size()>0){
-                        // 瓶颈工序,简化为等待前道工序全部完成才加工后道工序
-                        if((productionProcesses.getBottleneck() != null && productionProcesses.getBottleneck())
-                                || (productionProcesses.getPreviousProcesses().get(0).getBottleneck() != null && productionProcesses.getPreviousProcesses().get(0).getBottleneck())){
-                            LocalDateTime lastMaxStartTime = null;
-                            LocalDateTime lastMinMaxWaitTime = null;
-                            for (ProductionProcesses previousProcess : productionProcesses.getPreviousProcesses()) {
-                                // 流转时间
-                                Integer lzTimes = 0;
-                                if(previousProcess.getEquipment().getWorkshopid() != null && previousProcess.getEquipment().getWorkshopid().equals(productionProcesses.getEquipment().getWorkshopid())){
-                                    lzTimes = productionProcesses.getApsOverallConfig().getRoamTime().get("WORKSHOP_IN");
-                                }else{
-                                    lzTimes = productionProcesses.getApsOverallConfig().getRoamTime().get("WORKSHOP_CROSS");
-                                }
-                                if(lzMaxTimes<lzTimes){
-                                    lzMaxTimes = lzTimes;
-                                }
-                                // 最小等待时间
-                                Integer minWaitTime = previousProcess.getMinWaitTime() == null ? 0 : previousProcess.getMinWaitTime();
-                                if(lzTimes>minWaitTime){
-                                    minWaitTime = lzTimes;
-                                }
-                                if(lastMaxStartTime == null){
-                                    lastMaxStartTime = previousProcess.getEndTime().plusMinutes(minWaitTime);
-                                }else {
-                                    if(lastMaxStartTime.compareTo(previousProcess.getEndTime().plusMinutes(minWaitTime))<0){
-                                        lastMaxStartTime = previousProcess.getEndTime().plusMinutes(minWaitTime);
-                                    }
-                                }
-                                // 如有最大等待时间,计算首批次加工等待时间不能超过最大等待时间
-                                if(previousProcess.getMaxWaitTime() != null){
-                                    if(lastMinMaxWaitTime == null){
-                                        lastMinMaxWaitTime = previousProcess.getEndTime().plusMinutes(previousProcess.getMaxWaitTime());
-                                    }else{
-                                        if(previousProcess.getEndTime().plusMinutes(previousProcess.getMaxWaitTime()).compareTo(lastMinMaxWaitTime)<0){
-                                            lastMinMaxWaitTime = previousProcess.getEndTime().plusMinutes(previousProcess.getMaxWaitTime());
-                                        }
-                                    }
-                                }
-                            }
-                            // 开始时间不小于最大的最小等待时间、不大于最小的最大等待时间
-                            if(lastMaxStartTime != null && productionProcesses.getStartTime().compareTo(lastMaxStartTime)<0){
-                                bln = true;
-                            }else if(lastMinMaxWaitTime != null && productionProcesses.getStartTime().compareTo(lastMinMaxWaitTime)>0){
-                                bln = true;
-                            }
-                        }
-                        // 非瓶颈工序,非瓶颈工序,默认前道工序只有一个
-                        else{
-                            // 此种情况简化为前道工序只有一个
-                            ProductionProcesses preProcess = productionProcesses.getPreviousProcesses().get(0);
-                            maxUnitProduceTime = preProcess.getUnitProduceTime();
-                            // 前道工序的所有下道工序
-                            List<ProductionProcesses> nextProcesses = preProcess.getNextProcesses();
-                            Map<String,Integer> map = new HashMap<>();
-                            for (ProductionProcesses nextProcess : nextProcesses) {
-                                map.put(nextProcess.getId(),0);
-                                allNextProduceTime(nextProcess,map,nextProcess.getId());
-                                nextProcess.setNextAllProduceTime(map.get(nextProcess.getId()));
-                            }
-                            nextProcesses.sort((o1, o2) -> o1.getNextAllProduceTime().compareTo(o2.getNextAllProduceTime()));
-                            // 前道工序
-                            LocalDateTime startTime = preProcess.getStartTime();
-                            if(startTime == null){
-                                System.out.println("preProcess.getId():"+preProcess.getId());
-                                System.out.println("productionProcesses.getId():"+productionProcesses.getId());
-                            }
-                            LocalDateTime endTime = preProcess.getStartTime();
-                            for (ProductionProcesses nextProcess : nextProcesses) {
-                                int i = preProcess.getUnitProduceTime() * nextProcess.getProducePcNum();
-                                if(!nextProcess.getId().equals(productionProcesses.getId())){
-                                    startTime = startTime.plusMinutes(i);
-                                }else{
-                                    endTime = startTime.plusMinutes(i);
-                                }
-                            }
-
-                            // 流转时间
-                            Integer lzTimes = 0;
+                        // 此种情况简化为前道工序只有一个
+                        ProductionProcesses preProcess = productionProcesses.getPreviousProcesses().get(0);
+                        // 流转时间(最小等待时间)
+                        Integer lzTimes = 0;
+                        if(preProcess.getEquipment() != null){
                             if(preProcess.getEquipment().getWorkshopid() != null && preProcess.getEquipment().getWorkshopid().equals(productionProcesses.getEquipment().getWorkshopid())){
                                 lzTimes = productionProcesses.getApsOverallConfig().getRoamTime().get("WORKSHOP_IN");
                             }else{
@@ -323,98 +131,20 @@ public class ApsConstraintProvider implements ConstraintProvider {
                             if(preProcess.getMinWaitTime() != null && lzTimes<preProcess.getMinWaitTime()){
                                 lzTimes = preProcess.getMinWaitTime();
                             }
-
-                            /**
-                             * 后道工序批次生产时间大于等于前道工序批次生产时间
-                             * 从第一批次开始往后排程
-                             */
-
-                            if(preProcess.getMaxWaitTime() != null){
-                                lastFirstMaxWaitTime = startTime.plusMinutes(preProcess.getUnitProduceTime()).plusMinutes(preProcess.getMaxWaitTime());
-                            }
-                            if(productionProcesses.getUnitProduceTime()>=maxUnitProduceTime){
-                                if(productionProcesses.getStartTime().compareTo(startTime.plusMinutes(preProcess.getUnitProduceTime()).plusMinutes(lzTimes))<0){
-                                    bln = true;
-                                }else{
-                                    if(lastFirstMaxWaitTime != null){
-                                        if(productionProcesses.getStartTime().compareTo(lastFirstMaxWaitTime)>0){
-                                            bln = true;
-                                        }
-                                    }
-                                }
+                            // 最大等待时间
+                            Integer maxWaitTime = preProcess.getMaxWaitTime();
+                            if(productionProcesses.getStartTime().compareTo(preProcess.getEndTime().plusMinutes(lzTimes))<0){
+                                bln = true;
                             }
-                            /**
-                             * 后道工序批次生产时间小于前道工序批次生产时间
-                             * 从最后批次开始往前排程
-                             */
-                            else{
-                                // 开始时间:最后一批次结束时间加流转时间,再往前倒排批次数减一乘以单批次生产时间
-                                LocalDateTime startTime1 = endTime.plusMinutes(lzTimes).minusMinutes(productionProcesses.getUnitProduceTime() * (productionProcesses.getProducePcNum() - 1));
-                                // 结束时间重新赋值
-//                                productionProcesses.setEndTime(endTime.plusMinutes(lzTimes).plusMinutes(productionProcesses.getUnitProduceTime()));
-                                if(productionProcesses.getStartTime().compareTo(startTime1)<0){
+                            if(maxWaitTime != null && maxWaitTime>0){
+                                if(productionProcesses.getStartTime().compareTo(preProcess.getEndTime().plusMinutes(maxWaitTime))>0){
                                     bln = true;
                                 }
-                                // 存在最大等待时间时
-                                if(preProcess.getMaxWaitTime() != null){
-                                    // 超过最大等待时间
-                                    if(productionProcesses.getStartTime().compareTo(startTime1.plusMinutes(preProcess.getMaxWaitTime()))>0){
-                                        bln = true;
-                                    }
-                                }
-                            }
-
-                            if(bln){
-//                                System.out.println("log-开始时间:"+productionProcesses.getStartTime());
-//                                System.out.println("log-正确的开始时间:"+startTime.plusMinutes(preProcess.getUnitProduceTime()).plusMinutes(lzTimes));
                             }
                         }
                     }
-
-                    return bln;
-                })
-                .penalize(HardSoftScore.ONE_HARD,(productionProcesses) -> 40)
-                .asConstraint("hasOnePreGbAfterNow");
-    }
-
-    /**
-     * 单卷模式下前后道工序时间约束
-     * @param constraintFactory
-     * @return
-     */
-    private Constraint hasOnePreGbAfterNow(ConstraintFactory constraintFactory) {
-        return constraintFactory.forEach(ProductionProcesses.class)
-                .filter(productionProcesses -> {
-                    /*if(productionProcesses.getId().equals("2a231077b58844548c4a9d9e8f90f628")){
-                        int a = 1;
-                    }*/
-                    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;
-                            }
-                        }
-                    }
-                    /*if(productionProcesses.getMaxWaitTime() != null && productionProcesses.getMaxWaitTime()>0){
+                    if(productionProcesses.getMaxWaitTime() != null && productionProcesses.getMaxWaitTime()>0
+                            || (productionProcesses.getNextProcesses() != null && productionProcesses.getNextProcesses().size()>0 && "成退,中退,小卷成退".contains(productionProcesses.getNextProcesses().get(0).getProcessType()))){
                         if(productionProcesses.getNextProcesses() != null && productionProcesses.getNextProcesses().size()>0){
                             for (ProductionProcesses nextProcess : productionProcesses.getNextProcesses()) {
                                 if(nextProcess.getEquipment() != null && nextProcess.getStartTime() != null){
@@ -442,7 +172,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
                                 }
                             }
                         }
-                    }*/
+                    }
                     return bln;
                 })
                 .penalize(HardMediumSoftScore.ONE_HARD,(productionProcesses) -> 40)
@@ -470,6 +200,9 @@ public class ApsConstraintProvider implements ConstraintProvider {
      */
     private Constraint equipmentRunTime(ConstraintFactory constraintFactory) {
         return constraintFactory.forEach(ProductionProcesses.class)
+                .filter(pro->{
+                    return !pro.getProcessType().equals("成退") && !pro.getProcessType().equals("中退");
+                })
                 .filter(productionProcesses -> {
                     boolean bol = false;
                     // 瓶颈工序合并生产规则,总宽度和总承重不超过最大值即可
@@ -925,20 +658,30 @@ public class ApsConstraintProvider implements ConstraintProvider {
                     }
                     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);
+                    List<ProduceOrder> produceOrder1 = prePro.getProduceOrder();
+                    List<ProduceOrder> produceOrder2 = nextPro.getProduceOrder();
+                    if(produceOrder1 != null && produceOrder1.size()>0 && produceOrder2 != null && produceOrder2.size()>0
+                            && produceOrder1.get(0).getId().equals(produceOrder2.get(0).getId())
+                            && !prePro.getUniqueBsProcessesId().equals(nextPro.getUniqueBsProcessesId())){
+                        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{
@@ -1098,6 +841,9 @@ public class ApsConstraintProvider implements ConstraintProvider {
                             }
                         }
                     }
+                    if(deliveryMinDate == null){
+                        return false;
+                    }
                     Boolean bol = productionProcesses.getNextProcesses() == null &&
                             productionProcesses.getEndTime().atZone(zoneId).toInstant().toEpochMilli()>deliveryMinDate.getTime();
                     return bol;
@@ -1433,7 +1179,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
                 })
                 .penalize(HardMediumSoftScore.ONE_MEDIUM,(equipmentEquassociated, processess) -> {
                     int washingFurnaceCount = seriesProduceWashingFurnaceCount(processess);
-                    return washingFurnaceCount*10;
+                    return washingFurnaceCount*300;
                 })
                 .asConstraint("seriesProduceWashingFurnace");
     }
@@ -1521,21 +1267,27 @@ public class ApsConstraintProvider implements ConstraintProvider {
                     return StrUtil.isNotBlank(process.getEquipmentId()) && StrUtil.isNotBlank(process.getProcessType())
                             && !"成退".equals(process.getProcessType()) && !"中退".equals(process.getProcessType());
                 })
-                .groupBy(ProductionProcesses::getEquipmentId,ConstraintCollectors.toList())
-                .penalize(HardMediumSoftScore.ONE_SOFT,(equipmentId, processess) -> {
-                    int notSeriesNum = 0;
-                    List<ProductionProcesses> hasStartTimeProcess = processess.stream().filter(v -> v.getStartTime() != null).collect(Collectors.toList());
-                    // 根据开始时间排序
-                    Collections.sort(hasStartTimeProcess, Comparator.comparing(ProductionProcesses::getSeriSort));
-                    // 评分计算
-                    for(int i=0;i<hasStartTimeProcess.size()-1;i++){
-                        ProductionProcesses pre = hasStartTimeProcess.get(i);
-                        ProductionProcesses next = hasStartTimeProcess.get(i+1);
-                        if(!pre.getBsProcessesId().get(0).equals(next.getBsProcessesId().get(0))){
-                            notSeriesNum++;
+                .groupBy(ProductionProcesses::getUniqueBsProcessesId,ConstraintCollectors.toList())
+                .penalize(HardMediumSoftScore.ONE_SOFT,(bsProcessesId, processess) -> {
+                    long a = 0;
+                    if(processess != null && processess.size()>0){
+                        Map<String, List<ProductionProcesses>> orderProcess = processess.stream().collect(Collectors.groupingBy(ProductionProcesses::getEquipmentId));
+                        if(orderProcess != null && orderProcess.size()>0){
+                            for(String key : orderProcess.keySet()) {
+                                List<ProductionProcesses> pss = orderProcess.get(key);
+                                if(pss != null && pss.size()>1){
+                                    Collections.sort(pss, Comparator.comparing(ProductionProcesses::getStartTime));
+                                    for (int i = 0;i<pss.size()-1;i++) {
+                                        ProductionProcesses p1 = pss.get(i);
+                                        ProductionProcesses p2 = pss.get(i+1);
+                                        long minutes = ChronoUnit.MINUTES.between(p1.getStartTime(), p2.getStartTime());
+                                        a = a + minutes*10;
+                                    }
+                                }
+                            }
                         }
                     }
-                    return notSeriesNum;
+                    return (int) a;
                 })
                 .asConstraint("sameProcessSeries");
     }
@@ -1558,7 +1310,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
                         ProductionProcesses preProcess = process.getPreviousProcesses().get(0);
                         // 流转时间
                         Integer lzTimes = 0;
-                        if(preProcess != null){
+                        if(preProcess != null && preProcess.getEquipment() != null){
                             if(preProcess.getEquipment().getWorkshopid() != null && preProcess.getEquipment().getWorkshopid().equals(process.getEquipment().getWorkshopid())){
                                 lzTimes = process.getApsOverallConfig().getRoamTime().get("WORKSHOP_IN");
                             }else{
@@ -1568,10 +1320,10 @@ public class ApsConstraintProvider implements ConstraintProvider {
                             if(preProcess.getMinWaitTime() != null && lzTimes<preProcess.getMinWaitTime()){
                                 lzTimes = preProcess.getMinWaitTime();
                             }
-                        }
-                        LocalDateTime minStartTime = preProcess.getEndTime().plusMinutes(lzTimes);
-                        if(process.getStartTime().compareTo(minStartTime)>0){
-                            return true;
+                            LocalDateTime minStartTime = preProcess.getEndTime().plusMinutes(lzTimes);
+                            if(process.getStartTime().compareTo(minStartTime)>0){
+                                return true;
+                            }
                         }
                         return false;
                     }
@@ -1604,7 +1356,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
     }
 
     /**
-     * 退火工序优先合并
+     * 退火工序组炉规则
      * @param constraintFactory
      * @return
      */
@@ -1622,31 +1374,30 @@ public class ApsConstraintProvider implements ConstraintProvider {
                     }
                 })
                 .penalize(HardMediumSoftScore.ONE_MEDIUM,(equipmentId,processes)->{
+                    // 同一工序的优先组炉
+                    List<ProductionProcesses> ths = new ArrayList<>();
+                    processes.forEach(v->{
+                        ths.add(v);
+                    });
                     // 退火合并工序
                     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){
+                    if(ths.size()>0){
+                        if(ths.size() == 2){
+                            int a = 0;
+                        }
+                        for(int i=0;i<ths.size();i++){
                             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);
+                            String startTimeKey = ths.get(i).getStartTime().format(formatter)+ths.get(i).getEquipmentId();
+                            if(ppMap.containsKey(startTimeKey)){
+                                ppMap.get(startTimeKey).add(ths.get(i));
+                            }else{
+                                List<ProductionProcesses> ps = new ArrayList<>();
+                                ps.add(ths.get(i));
+                                ppMap.put(startTimeKey,ps);
                             }
                         }
                     }
-                    return ppMap.size()*10000;
+                    return ppMap.size()*100;
                 })
                 .asConstraint("mergeTuihuo");
     }
@@ -1658,6 +1409,9 @@ public class ApsConstraintProvider implements ConstraintProvider {
      */
     private Constraint sameEquipment(ConstraintFactory constraintFactory){
         return constraintFactory.forEach(ProductionProcesses.class)
+                .filter(pro->{
+                    return pro.getProcessType().equals("铸轧") || pro.getProcessType().equals("冷轧");
+                })
                 .groupBy(ProductionProcesses::getUniqueBsProcessesId,ConstraintCollectors.toList())
                 .filter((equipmentEquassociated,processes) -> {
                     if(processes != null && processes.size()>0){

+ 14 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/service/ApsService.java

@@ -0,0 +1,14 @@
+package com.rongwei.rwapsserver.aps.service;
+
+import com.rongwei.rwapsserver.aps.domain.ApsSolution;
+import com.rongwei.rwapsserver.aps.vo.ProductionScheduleVo;
+import org.optaplanner.core.api.solver.Solver;
+import org.optaplanner.core.api.solver.SolverFactory;
+
+public interface ApsService {
+
+    ApsSolution tuihuoAps(ApsSolution apsSolution);
+
+    SolverFactory<ApsSolution> solverInit(ProductionScheduleVo productionScheduleVo);
+
+}

+ 2 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/service/ProductionScheduleService.java

@@ -7,4 +7,6 @@ public interface ProductionScheduleService {
 
     ProductionScheduleRetVo productionSchedule(ProductionScheduleVo productionScheduleVo) throws Exception;
 
+    ProductionScheduleRetVo tuiHuoSchedule(ProductionScheduleVo productionScheduleVo) throws Exception;
+
 }

+ 164 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/service/impl/ApsServiceImpl.java

@@ -0,0 +1,164 @@
+package com.rongwei.rwapsserver.aps.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.rongwei.rwapsserver.aps.domain.*;
+import com.rongwei.rwapsserver.aps.score.ApsConstraintProvider;
+import com.rongwei.rwapsserver.aps.service.ApsService;
+import com.rongwei.rwapsserver.aps.util.ApsException;
+import com.rongwei.rwapsserver.aps.vo.ProductionScheduleVo;
+import lombok.extern.slf4j.Slf4j;
+import org.optaplanner.core.api.score.ScoreExplanation;
+import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
+import org.optaplanner.core.api.solver.SolutionManager;
+import org.optaplanner.core.api.solver.Solver;
+import org.optaplanner.core.api.solver.SolverFactory;
+import org.optaplanner.core.api.solver.event.BestSolutionChangedEvent;
+import org.optaplanner.core.api.solver.event.SolverEventListener;
+import org.optaplanner.core.config.constructionheuristic.ConstructionHeuristicPhaseConfig;
+import org.optaplanner.core.config.heuristic.selector.move.generic.ChangeMoveSelectorConfig;
+import org.optaplanner.core.config.heuristic.selector.value.ValueSelectorConfig;
+import org.optaplanner.core.config.phase.PhaseConfig;
+import org.optaplanner.core.config.phase.custom.CustomPhaseConfig;
+import org.optaplanner.core.config.solver.EnvironmentMode;
+import org.optaplanner.core.config.solver.SolverConfig;
+import org.springframework.stereotype.Service;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.Duration;
+import java.util.*;
+
+import static org.optaplanner.core.config.constructionheuristic.ConstructionHeuristicType.FIRST_FIT;
+
+@Slf4j
+@Service
+public class ApsServiceImpl implements ApsService {
+
+    /**
+     * 退火优先排程
+     * @param apsSolution
+     * @return
+     */
+    @Override
+    public ApsSolution tuihuoAps(ApsSolution apsSolution) {
+        ApsSolution apsSolutionTuihuo = new ApsSolution();
+        List<ProductionProcesses> tuihuos = new ArrayList<>();
+        for (ProductionProcesses process : apsSolution.getProcessesList()) {
+            if(process.getProcessType().equals("成退") || process.getProcessType().equals("中退")){
+                List<Integer> preTimes = new ArrayList<>();
+                getAllPreTime(process,preTimes);
+                if(preTimes != null && preTimes.size()>0){
+                    Integer totaltime = 0;
+                    for (Integer preTime : preTimes) {
+                        totaltime = totaltime + preTime;
+                    }
+                    // 松散度
+                    if(process.getApsOverallConfig().getLooseness() != null){
+                        BigDecimal lostime = process.getApsOverallConfig().getLooseness().multiply(new BigDecimal(totaltime)).divide(new BigDecimal("100"));
+                        Integer losinttime = lostime.setScale(0, RoundingMode.CEILING).intValue();
+                        totaltime = totaltime + losinttime;
+                    }
+                    totaltime = totaltime + 60*6;
+                    // 全局配置
+                    ApsOverallConfig apsOverallConfig = new ApsOverallConfig();
+                    BeanUtil.copyProperties(process.getApsOverallConfig(),apsOverallConfig);
+                    apsOverallConfig.setStartTime(process.getApsOverallConfig().getStartTime().plusMinutes(totaltime));
+                    // 开始时间设置
+                    process.setApsOverallConfig(apsOverallConfig);
+                    // 前后道工序置空
+                    process.setPreviousProcesses(null);
+                    process.setNextProcesses(null);
+                }
+                tuihuos.add(process);
+            }
+        }
+        Collections.sort(tuihuos, (p1,p2)->p2.getApsOverallConfig().getStartTime().compareTo(p1.getApsOverallConfig().getStartTime()));
+        apsSolutionTuihuo.setProcessesList(tuihuos);
+        apsSolutionTuihuo.setEquipmentList(apsSolution.getEquipmentList());
+        return apsSolutionTuihuo;
+    }
+
+    /**
+     * 获取所有前道工序的时间总和
+     * @param process
+     * @param preTimes
+     */
+    private void getAllPreTime(ProductionProcesses process,List<Integer> preTimes){
+        if(process.getPreviousProcesses() != null){
+            Integer lzTime = process.getApsOverallConfig().getRoamTime().get("WORKSHOP_IN");
+            if(process.getPreviousProcesses().get(0).getMinWaitTime() != null){
+                if(process.getPreviousProcesses().get(0).getMinWaitTime()>lzTime){
+                    lzTime = process.getPreviousProcesses().get(0).getMinWaitTime();
+                }
+            }
+            int pretime = process.getPreviousProcesses().get(0).getProduceTime() * process.getPreviousProcesses().get(0).getProducePcNum() + lzTime;
+            preTimes.add(pretime);
+            getAllPreTime(process.getPreviousProcesses().get(0),preTimes);
+        }
+    }
+
+    /**
+     * 求解器初始化
+     * @param productionScheduleVo
+     * @return
+     */
+    @Override
+    public SolverFactory<ApsSolution> solverInit(ProductionScheduleVo productionScheduleVo){
+        // 排程校验
+        if(productionScheduleVo.getRoamTime() == null || productionScheduleVo.getRoamTime().size() == 0){
+            throw new ApsException("缺少全局流转时间配置");
+        }
+        // 排程运行时长
+        Integer maxPlanSeconds = productionScheduleVo.getPlanSeconds();
+        Integer prospeed = 20;
+        if(productionScheduleVo.getPcspeed() != null && productionScheduleVo.getPcspeed()>0){
+            prospeed = productionScheduleVo.getPcspeed();
+        }
+        int processNum = productionScheduleVo.getProcesses().size();
+        int runPlanSeconds = (processNum/prospeed + 1)*60;
+        if(maxPlanSeconds == null || maxPlanSeconds <= 0){
+            maxPlanSeconds = 1800;
+        }
+        if(runPlanSeconds > maxPlanSeconds){
+            throw new ApsException("所选排程作业太多,预计排程时间太长,请分开排程");
+        }
+//        int runPlanSeconds = maxPlanSeconds;
+        EnvironmentMode mode = EnvironmentMode.REPRODUCIBLE;
+        if(productionScheduleVo.getEnvironmentMode() != null && productionScheduleVo.getEnvironmentMode() == 1){
+            mode = EnvironmentMode.FULL_ASSERT;
+        }
+        // CPU核数
+        String cores = Runtime.getRuntime().availableProcessors() + "";
+        List<PhaseConfig> phaseConfigList = new ArrayList<>();
+        CustomPhaseConfig phaseConfig = new CustomPhaseConfig();
+        phaseConfig.withCustomPhaseCommands(new ApsCustomPhaseCommand());
+        // CH阶段
+        ConstructionHeuristicPhaseConfig consphaseConfig = new ConstructionHeuristicPhaseConfig();
+        ChangeMoveSelectorConfig changeMoveSelectorConfig = new ChangeMoveSelectorConfig();
+        ValueSelectorConfig valueSelectorConfig = new ValueSelectorConfig();
+        valueSelectorConfig.setVariableName("equipment");
+        changeMoveSelectorConfig.setValueSelectorConfig(valueSelectorConfig);
+        ChangeMoveSelectorConfig changeMoveSelectorConfig1 = new ChangeMoveSelectorConfig();
+        ValueSelectorConfig valueSelectorConfig1 = new ValueSelectorConfig();
+        valueSelectorConfig1.setVariableName("delay");
+        changeMoveSelectorConfig1.setValueSelectorConfig(valueSelectorConfig1);
+        consphaseConfig.setMoveSelectorConfigList(Arrays.asList(changeMoveSelectorConfig,changeMoveSelectorConfig1));
+        consphaseConfig.setConstructionHeuristicType(FIRST_FIT);
+
+        phaseConfigList.add(consphaseConfig);
+//        phaseConfigList.add(phaseConfig);
+//        phaseConfigList.add(new LocalSearchPhaseConfig());
+        // optaplanner 求解器配置实例化
+        SolverConfig solverConfig = new SolverConfig()
+                .withEnvironmentMode(EnvironmentMode.FULL_ASSERT)
+                .withSolutionClass(ApsSolution.class)
+                .withEntityClasses(ProductionProcesses.class)
+                .withConstraintProviderClass(ApsConstraintProvider.class)
+//                .withTerminationConfig(new TerminationConfig().withUnimprovedSecondsSpentLimit(10L))
+                .withTerminationSpentLimit(Duration.ofSeconds(runPlanSeconds))
+//                .withPhaseList(phaseConfigList)
+                .withMoveThreadCount(cores);
+        List<PhaseConfig> phaseConfigList1 = solverConfig.getPhaseConfigList();
+        SolverFactory<ApsSolution> solverFactory = SolverFactory.create(solverConfig);
+        return solverFactory;
+    }
+}

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

@@ -1,12 +1,9 @@
 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.alibaba.nacos.common.utils.StringUtils;
-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.ApsService;
 import com.rongwei.rwapsserver.aps.service.ProductionScheduleService;
 import com.rongwei.rwapsserver.aps.util.ApsConstants;
 import com.rongwei.rwapsserver.aps.util.ApsException;
@@ -23,9 +20,8 @@ import org.optaplanner.core.api.solver.event.BestSolutionChangedEvent;
 import org.optaplanner.core.api.solver.event.SolverEventListener;
 import org.optaplanner.core.config.solver.EnvironmentMode;
 import org.optaplanner.core.config.solver.SolverConfig;
-import org.optaplanner.core.config.solver.termination.TerminationConfig;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-
 import java.math.BigDecimal;
 import java.time.Duration;
 import java.time.LocalDateTime;
@@ -38,6 +34,9 @@ import java.util.stream.Collectors;
 @Service
 public class ProductionScheduleServiceImpl implements ProductionScheduleService {
 
+    @Autowired
+    private ApsService apsService;
+
     /**
      * APS生产计划排程
      * @param productionScheduleVo
@@ -70,6 +69,8 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
         if(productionScheduleVo.getEnvironmentMode() != null && productionScheduleVo.getEnvironmentMode() == 1){
             mode = EnvironmentMode.FULL_ASSERT;
         }
+
+//        runPlanSeconds = 20;
         // CPU核数
         String cores = Runtime.getRuntime().availableProcessors() + "";
         // optaplanner 求解器配置实例化
@@ -113,25 +114,30 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
         });
         // optaplanner 求解器数据装配
         ApsSolution apsSolution = getPreApsSolution(productionScheduleVo);
-//        ApsSolution apsSolutionData = solver.solve(apsSolution);
-        // optaplanner 求解器运行
+        // 去掉锁定工序
+        List<ProductionProcesses> notLocks = new ArrayList<>();
+        List<ProductionProcesses> hasLocks = new ArrayList<>();
+        if(apsSolution.getProcessesList() != null && apsSolution.getProcessesList().size()>0){
+            for (ProductionProcesses productionProcesses : apsSolution.getProcessesList()) {
+                if(!productionProcesses.getIfLock()){
+                    notLocks.add(productionProcesses);
+                }else{
+                    hasLocks.add(productionProcesses);
+                }
+            }
+        }
+        apsSolution.setProcessesList(notLocks);
         ApsSolution solvedBalance = solver.solve(apsSolution);
-        /*List<ProductionProcesses> apsProcess = solvedBalance.getProcessesList();
-        solvedBalance.setProcessesList(solvedBalance.getStepBestProcessesList());*/
-
         log.info("**************排程评分分析***************");
         SolutionManager<ApsSolution, HardSoftScore> scoreManager = SolutionManager.create(solverFactory);
         ScoreExplanation<ApsSolution, HardSoftScore> explain = scoreManager.explain(solvedBalance);
         log.info(explain.toString());
         log.info("**************排程评分分析***************");
-        /*solvedBalance.setProcessesList(apsProcess);
-        ScoreExplanation<ApsSolution, HardSoftScore> explain1 = scoreManager.explain(solvedBalance);
-        log.info(explain1.toString());*/
         productionScheduleRetVo.setScoreResult(scoreManager.explain(solvedBalance).toString());
         // 得分分析
         softExplain(explain,solvedBalance.getProcessesList());
         // 最大等待时间冲突手动解决
-        List<ProductionProcesses> maxSetPros = new ArrayList<>();
+        /*List<ProductionProcesses> maxSetPros = new ArrayList<>();
         for (ProductionProcesses productionProcesses : solvedBalance.getProcessesList()) {
             if(productionProcesses.getConflictDes() != null && "开工时间超出上道工序作业最大等待时间限制".equals(productionProcesses.getConflictDes())){
                 ProductionProcesses newPre = maxWaitTimeCheck(productionProcesses, maxSetPros,solvedBalance.getProcessesList(),solvedBalance.getEquipmentList());
@@ -154,27 +160,19 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
                     }
                 }
             }
-        }
+        }*/
 
-        /*SolverFactory<ApsSolution> solverFactory1 = SolverFactory.create(new SolverConfig()
-                        .withEnvironmentMode(mode)
-                        .withSolutionClass(ApsSolution.class)
-                        .withEntityClasses(ProductionProcesses.class)
-                        .withConstraintProviderClass(ApsConstraintProvider.class)
-                        .withTerminationSpentLimit(Duration.ofSeconds(120))
-                        .withMoveThreadCount(cores)
-        );
-        Solver<ApsSolution> solver1 = solverFactory1.buildSolver();
-        apsSolution.setProcessesList(solvedBalance.getProcessesList());
-        solvedBalance = solver1.solve(apsSolution);*/
+        solvedBalance.getProcessesList().addAll(hasLocks);
         log.info("**************排程最终评分分析***************");
-        ScoreExplanation<ApsSolution, HardSoftScore> explain1 = scoreManager.explain(solvedBalance);
-        log.info(explain1.toString());
+        ScoreExplanation<ApsSolution, HardSoftScore> explain2 = scoreManager.explain(solvedBalance);
+        log.info(explain2.toString());
         log.info("**************排程最终评分分析***************");
-        softExplain(explain1,solvedBalance.getProcessesList());
+        softExplain(explain2,solvedBalance.getProcessesList());
 
         productionScheduleRetVo.setProcesses(solvedBalance.getProcessesList());
         // 循环引用ProductionProcesses置空
+//        solvedBalance.getProcessesList().addAll(solvedBalance1.getProcessesList());
+
         for (ProductionProcesses productionProcesses : solvedBalance.getProcessesList()) {
             productionProcesses.setPreviousProcesses(null);
             productionProcesses.setNextProcesses(null);
@@ -627,7 +625,10 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
         }
         for (ProductionProcesses process : productionScheduleVo.getProcesses()) {
             // 全局配置设置
-            process.setApsOverallConfig(apsOverallConfig);
+            if(process.getApsOverallConfig() == null){
+                process.setApsOverallConfig(apsOverallConfig);
+            }
+
             if(StrUtil.isBlank(process.getTaskType())){
                 process.setTaskType("processes");
             }
@@ -680,6 +681,11 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
                     if(process.getOptionalEquipments().contains(equipment.getId())){
                         providedEq.add(equipment);
                     }
+                    if(StrUtil.isNotBlank(process.getEquipmentId())){
+                        if(process.getEquipmentId().equals(equipment.getId())){
+                            process.setEquipment(equipment);
+                        }
+                    }
                 }
                 if(providedEq.size() == 0){
                     throw new ApsException("500","作业ID:"+ process.getBsProcessesId().get(0) + "可选设备不能为空");
@@ -812,7 +818,8 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
         List<ProductionProcesses> processesList1 = bsMap.get(uniqueBsProcessesId);
         if(processesList1 != null && processesList1.size()>0){
             if(processesList1.get(0).getProcessType().equals("成退") || processesList1.get(0).getProcessType().equals("中退")
-                    || processesList1.get(0).getProcessType().equals("冷轧") || processesList1.get(0).getProcessType().equals("铸轧")){
+//                    || processesList1.get(0).getProcessType().equals("冷轧") || processesList1.get(0).getProcessType().equals("铸轧")
+            ){
 //                List<ProductionProcesses> pres = bsMap.get(processesList1.get(0).getPreviousProcesses().get(0).getUniqueBsProcessesId());
                 if(processesList1.get(0).getPreviousProcesses() != null && processesList1.get(0).getPreviousProcesses().size()>0){
                     for (ProductionProcesses productionProcesses : processesList1) {
@@ -903,4 +910,94 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
             }
         }
     }
+
+    /**
+     * 退火提前合并排程
+     * @param productionScheduleVo
+     * @return
+     */
+    public ProductionScheduleRetVo tuiHuoSchedule(ProductionScheduleVo productionScheduleVo) throws Exception{
+        // 排程结果对象
+        ProductionScheduleRetVo productionScheduleRetVo = new ProductionScheduleRetVo();
+        // 排程运行时长
+        Integer maxPlanSeconds = productionScheduleVo.getPlanSeconds();
+        Integer prospeed = 20;
+        if(productionScheduleVo.getPcspeed() != null && productionScheduleVo.getPcspeed()>0){
+            prospeed = productionScheduleVo.getPcspeed();
+        }
+        int processNum = productionScheduleVo.getProcesses().size();
+        int runPlanSeconds = (processNum/prospeed + 1)*60;
+        if(maxPlanSeconds == null || maxPlanSeconds <= 0){
+            maxPlanSeconds = 1800;
+        }
+        if(runPlanSeconds > maxPlanSeconds){
+            throw new ApsException("所选排程作业太多,预计排程时间太长,请分开排程");
+        }
+        EnvironmentMode mode = EnvironmentMode.REPRODUCIBLE;
+        if(productionScheduleVo.getEnvironmentMode() != null && productionScheduleVo.getEnvironmentMode() == 1){
+            mode = EnvironmentMode.FULL_ASSERT;
+        }
+        ApsSolution apsSolution = getPreApsSolution(productionScheduleVo);
+        // 退火提前排序
+        ApsSolution apsSolutionTh = apsService.tuihuoAps(apsSolution);
+        if(apsSolutionTh.getProcessesList() != null && apsSolutionTh.getProcessesList().size()>0){
+            // 退火工序求解器运行
+            int processNum1 = apsSolutionTh.getProcessesList().size();
+            int runPlanSeconds1 = (processNum1/prospeed + 1)*60;
+            // CPU核数
+            String cores = Runtime.getRuntime().availableProcessors() + "";
+            SolverFactory<ApsSolution> solverFactory1 = SolverFactory.create(new SolverConfig()
+                    .withEnvironmentMode(mode)
+                    .withSolutionClass(ApsSolution.class)
+                    .withEntityClasses(ProductionProcesses.class)
+                    .withConstraintProviderClass(ApsConstraintProvider.class)
+                    .withTerminationSpentLimit(Duration.ofSeconds(runPlanSeconds1))
+                    .withMoveThreadCount(cores)
+            );
+            Solver<ApsSolution> solver1 = solverFactory1.buildSolver();
+            ApsSolution solvedBalance1 = solver1.solve(apsSolutionTh);
+            log.info("**************退火排程评分分析***************");
+            SolutionManager<ApsSolution, HardSoftScore> scoreManager1 = SolutionManager.create(solverFactory1);
+            ScoreExplanation<ApsSolution, HardSoftScore> explain1 = scoreManager1.explain(solvedBalance1);
+            log.info(explain1.toString());
+            log.info("**************退火排程评分分析***************");
+            softExplain(explain1,solvedBalance1.getProcessesList());
+            productionScheduleRetVo.setScoreResult(scoreManager1.explain(solvedBalance1).toString());
+            productionScheduleRetVo.setProcesses(solvedBalance1.getProcessesList());
+            // 循环引用ProductionProcesses置空
+            for (ProductionProcesses productionProcesses : solvedBalance1.getProcessesList()) {
+                productionProcesses.setPreviousProcesses(null);
+                productionProcesses.setNextProcesses(null);
+                productionProcesses.getEquipment().setProcessesList(null);
+                productionProcesses.getEquipment().setEquipmentRunTimes(null);
+                productionProcesses.setPreviousStep(null);
+                productionProcesses.setOptionalProviderEquipments(null);
+                // 冲突约束补充处理
+                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);
+                            }
+                        }
+                    });
+                }
+            }
+        }
+        return productionScheduleRetVo;
+    }
 }