|
@@ -2,17 +2,16 @@ package com.rongwei.rwapsserver.aps.score;
|
|
|
|
|
|
import cn.hutool.core.date.DateUtil;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
+import com.rongwei.rwapsserver.aps.domain.Equipment;
|
|
|
+import com.rongwei.rwapsserver.aps.domain.EquipmentRunTime;
|
|
|
import com.rongwei.rwapsserver.aps.domain.ProduceOrder;
|
|
|
import com.rongwei.rwapsserver.aps.domain.ProductionProcesses;
|
|
|
+import com.rongwei.rwapsserver.aps.util.ApsConstants;
|
|
|
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
|
|
|
-import org.optaplanner.core.api.score.stream.Constraint;
|
|
|
-import org.optaplanner.core.api.score.stream.ConstraintFactory;
|
|
|
-import org.optaplanner.core.api.score.stream.ConstraintProvider;
|
|
|
-import org.optaplanner.core.api.score.stream.Joiners;
|
|
|
-
|
|
|
+import org.optaplanner.core.api.score.stream.*;
|
|
|
import java.time.LocalDateTime;
|
|
|
import java.time.ZoneId;
|
|
|
-import java.util.Date;
|
|
|
+import java.util.*;
|
|
|
|
|
|
import static org.optaplanner.core.api.score.stream.ConstraintCollectors.count;
|
|
|
|
|
@@ -25,16 +24,20 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
return new Constraint[]{
|
|
|
eqTypeSame(constraintFactory),
|
|
|
noPreGbAfterNow(constraintFactory),
|
|
|
- hasPreGbAfterNow(constraintFactory),
|
|
|
+// hasPreGbAfterNow(constraintFactory),
|
|
|
+ hasOnePreGbAfterNow(constraintFactory),
|
|
|
eqTimeCross(constraintFactory),
|
|
|
deliveryDate(constraintFactory),
|
|
|
- balancedEqUse(constraintFactory),
|
|
|
+ seriesProduce(constraintFactory),
|
|
|
+ lzTimeLessMaxWait(constraintFactory),
|
|
|
+ equipmentRunTime(constraintFactory),
|
|
|
+// balancedEqUse(constraintFactory),
|
|
|
// mergeProcess(constraintFactory)
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 硬约束:工步所需的设备类型和工步所用的设备类型必须一致
|
|
|
+ * 硬约束:工步所需的设备必须在工序的可选设备之内
|
|
|
* @param constraintFactory
|
|
|
* @return
|
|
|
*/
|
|
@@ -55,7 +58,11 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
private Constraint noPreGbAfterNow(ConstraintFactory constraintFactory) {
|
|
|
return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
.filter(productionProcesses -> {
|
|
|
- return productionProcesses.getPreviousProcesses() == null && productionProcesses.getStartTime().atZone(zoneId).toInstant().toEpochMilli()< DateUtil.date().getTime();
|
|
|
+ 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");
|
|
@@ -73,12 +80,39 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
// 获取上一步最晚结束时间
|
|
|
LocalDateTime preLastMinTime = null;
|
|
|
LocalDateTime preLastMaxTime = null;
|
|
|
+ // 最大单批次生产时间
|
|
|
+ Integer maxUnitProduceTime = 0;
|
|
|
if(productionProcesses.getPreviousProcesses() != null){
|
|
|
for (ProductionProcesses previousProcess : productionProcesses.getPreviousProcesses()) {
|
|
|
+ // 流转时间
|
|
|
+ Integer lzTimes = 0;
|
|
|
+ if(previousProcess.getEquipment().getWorkshop() != null && previousProcess.getEquipment().getWorkshop().equals(productionProcesses.getEquipment().getWorkshop())){
|
|
|
+ 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){
|
|
|
- thisMinEndTime = thisMinEndTime.plusMinutes(previousProcess.getMinWaitTime());
|
|
|
+ /**
|
|
|
+ * 根据前后工序单批次生产时间比较来排序
|
|
|
+ * 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());
|
|
@@ -102,6 +136,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
boolean bln = productionProcesses.getStartTime().atZone(zoneId).toInstant().toEpochMilli() < preLastMinTime.atZone(zoneId).toInstant().toEpochMilli();
|
|
|
if(preLastMaxTime != null){
|
|
|
System.out.println("preLastMaxTime != null");
|
|
@@ -116,6 +151,272 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
.asConstraint("hasPreGbAfterNow");
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 前提条件:前道工序只有一个
|
|
|
+ * 硬约束:有上一步工步的开始时间要大于上一步工步最早结束时间,小于最晚结束时间
|
|
|
+ * 根据上一步的最小等待时间和最大等待时间来判断
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint hasOnePreGbAfterNow(ConstraintFactory constraintFactory) {
|
|
|
+ return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
+ .filter(productionProcesses -> {
|
|
|
+ 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().getWorkshop() != null && previousProcess.getEquipment().getWorkshop().equals(productionProcesses.getEquipment().getWorkshop())){
|
|
|
+ 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(lastFirstMaxWaitTime)<0){
|
|
|
+ lastMinMaxWaitTime = previousProcess.getEndTime().plusMinutes(previousProcess.getMaxWaitTime());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 开始时间不小于最大的最小等待时间、不大于最小的最大等待时间
|
|
|
+ if(productionProcesses.getStartTime().compareTo(lastMaxStartTime)<0){
|
|
|
+ bln = true;
|
|
|
+ }else if(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();
|
|
|
+ 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;
|
|
|
+ if(preProcess.getEquipment().getWorkshop() != null && preProcess.getEquipment().getWorkshop().equals(productionProcesses.getEquipment().getWorkshop())){
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 后道工序批次生产时间大于等于前道工序批次生产时间
|
|
|
+ * 从第一批次开始往后排程
|
|
|
+ */
|
|
|
+ System.out.println("log-开始时间:"+productionProcesses.getStartTime());
|
|
|
+ System.out.println("log-正确的开始时间:"+startTime.plusMinutes(preProcess.getUnitProduceTime()).plusMinutes(lzTimes));
|
|
|
+ if(preProcess.getMaxWaitTime() != null){
|
|
|
+ lastFirstMaxWaitTime = startTime.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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 后道工序批次生产时间小于前道工序批次生产时间
|
|
|
+ * 从最后批次开始往前排程
|
|
|
+ */
|
|
|
+ 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){
|
|
|
+ bln = true;
|
|
|
+ }
|
|
|
+ // 存在最大等待时间时
|
|
|
+ if(preProcess.getMaxWaitTime() != null){
|
|
|
+ // 超过最大等待时间
|
|
|
+ if(productionProcesses.getStartTime().compareTo(startTime1.plusMinutes(preProcess.getMaxWaitTime()))>0){
|
|
|
+ bln = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return bln;
|
|
|
+ })
|
|
|
+ .penalize(HardSoftScore.ONE_HARD,(productionProcesses) -> 80)
|
|
|
+ .asConstraint("hasOnePreGbAfterNow");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 汇总所有下道工序的加工时间
|
|
|
+ * @param nextProcess
|
|
|
+ * @param map
|
|
|
+ */
|
|
|
+ private void allNextProduceTime(ProductionProcesses nextProcess,Map<String,Integer> map,String proId){
|
|
|
+ map.put(proId,map.get(proId)+nextProcess.getProduceTime());
|
|
|
+ if(nextProcess.getNextProcesses() != null && nextProcess.getNextProcesses().size()>0){
|
|
|
+ for (ProductionProcesses process : nextProcess.getNextProcesses()) {
|
|
|
+ allNextProduceTime(process,map,proId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设备运行时间段,不可再排产
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint equipmentRunTime(ConstraintFactory constraintFactory) {
|
|
|
+ return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
+ .filter(productionProcesses -> {
|
|
|
+ boolean bol = false;
|
|
|
+ // 瓶颈工序合并生产规则,总宽度和总承重不超过最大值即可
|
|
|
+ if(productionProcesses.getBottleneck() != null && productionProcesses.getBottleneck()){
|
|
|
+
|
|
|
+ }
|
|
|
+ // 非瓶颈工序设备运行时间段,不可再排产
|
|
|
+ else{
|
|
|
+ if(productionProcesses.getEquipment() != null && productionProcesses.getEquipment().getEquipmentRunTimes() != null &&
|
|
|
+ productionProcesses.getEquipment().getEquipmentRunTimes().size()>0){
|
|
|
+ for (EquipmentRunTime equipmentRunTime : productionProcesses.getEquipment().getEquipmentRunTimes()) {
|
|
|
+ if(equipmentRunTime.getStartRunTime() != null && equipmentRunTime.getEndRunTime() != null){
|
|
|
+ LocalDateTime startTime = equipmentRunTime.getStartRunTime();
|
|
|
+ LocalDateTime endRunTime = equipmentRunTime.getEndRunTime();
|
|
|
+ if((productionProcesses.getStartTime().compareTo(startTime)>=0 && productionProcesses.getStartTime().compareTo(endRunTime)<=0)
|
|
|
+ || (productionProcesses.getEndTime().compareTo(startTime)>=0 && productionProcesses.getEndTime().compareTo(endRunTime)<=0)){
|
|
|
+ bol = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return bol;
|
|
|
+ })
|
|
|
+ .penalize(HardSoftScore.ONE_HARD,(proc1)->80)
|
|
|
+ .asConstraint("equipmentRunTime");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 退火炉等合并工序生产约束
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ /*private Constraint mergeProcess(ConstraintFactory constraintFactory) {
|
|
|
+ return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
+ .filter(productionProcesses -> {
|
|
|
+ boolean bol = false;
|
|
|
+ // 退火炉特殊合并生产规则
|
|
|
+ if(ApsConstants.EQUIPMENTTYPE_TUIHUOLU.equals(productionProcesses.getEquipmentType())){
|
|
|
+ if(productionProcesses.getEquipment() != null && productionProcesses.getEquipment().getProcessesList() != null){
|
|
|
+ // 当前工序所选设备生产中的或待生产的工序集合
|
|
|
+ List<ProductionProcesses> processesList = productionProcesses.getEquipment().getProcessesList();
|
|
|
+ for (ProductionProcesses processes : processesList) {
|
|
|
+ // 开始时间和结束时间要么和已排产的工序一样,要么在这个范围之外
|
|
|
+ if((productionProcesses.getStartTime().compareTo(processes.getStartTime())>0 && productionProcesses.getStartTime().compareTo(processes.getEndTime())<0)
|
|
|
+ || (productionProcesses.getEndTime().compareTo(processes.getStartTime())>0 && productionProcesses.getEndTime().compareTo(processes.getEndTime())<0)){
|
|
|
+ bol = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // 开始时间结束时间在已排产的某个时间段内
|
|
|
+ if(productionProcesses.getStartTime().compareTo(processes.getStartTime())>=0 && productionProcesses.getEndTime().compareTo(processes.getEndTime())<=0){
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return bol;
|
|
|
+ })
|
|
|
+ .penalize(HardSoftScore.ONE_HARD,(proc1)->80)
|
|
|
+ .asConstraint("mergeProcess");
|
|
|
+ }*/
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 最大等待时间,不能小于流转时间
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint lzTimeLessMaxWait(ConstraintFactory constraintFactory) {
|
|
|
+ return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
+ .filter(productionProcesses -> {
|
|
|
+ // 对比前后工序设备所属工厂、获取最大流转时间
|
|
|
+ boolean bol = false;
|
|
|
+ if(productionProcesses.getPreviousProcesses() != null && productionProcesses.getPreviousProcesses().size()>0){
|
|
|
+ for (ProductionProcesses previousProcess : productionProcesses.getPreviousProcesses()) {
|
|
|
+ Integer lzTimes = 0;
|
|
|
+ if(previousProcess.getEquipment().getWorkshop() != null && previousProcess.getEquipment().getWorkshop().equals(productionProcesses.getEquipment().getWorkshop())){
|
|
|
+ lzTimes = productionProcesses.getApsOverallConfig().getRoamTime().get("WORKSHOP_IN");
|
|
|
+ }else{
|
|
|
+ lzTimes = productionProcesses.getApsOverallConfig().getRoamTime().get("WORKSHOP_CROSS");
|
|
|
+ }
|
|
|
+ if(previousProcess.getMaxWaitTime() != null && previousProcess.getMaxWaitTime()>0 && previousProcess.getMaxWaitTime()<lzTimes){
|
|
|
+ bol = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return bol;
|
|
|
+ })
|
|
|
+ .penalize(HardSoftScore.ONE_HARD,(proc1)->90)
|
|
|
+ .asConstraint("lzTimeLessMaxWait");
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 硬约束:同一个设备的不同的工步运行时间不能有交叉
|
|
|
* @param constraintFactory
|
|
@@ -197,7 +498,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
* @param constraintFactory
|
|
|
* @return
|
|
|
*/
|
|
|
- private Constraint mergeProcess(ConstraintFactory constraintFactory){
|
|
|
+ /*private Constraint mergeProcess(ConstraintFactory constraintFactory){
|
|
|
return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
.join(ProductionProcesses.class,Joiners.equal(ProductionProcesses::getEquipmentId))
|
|
|
.filter((proc1,proc2)->{
|
|
@@ -214,5 +515,48 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
})
|
|
|
.penalize(HardSoftScore.ONE_SOFT,(proc1,proc2)->50)
|
|
|
.asConstraint("mergeProcess");
|
|
|
+ }*/
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 连续生产约束条件,同一设备的连续生产标识一样的工序、尽量排在一起
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint seriesProduce(ConstraintFactory constraintFactory){
|
|
|
+ return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
+ .groupBy(ProductionProcesses::getEquipmentId, ConstraintCollectors.toList())
|
|
|
+ .filter((equipmentId,processes) -> {
|
|
|
+ if(processes != null && processes.size()>1){
|
|
|
+ // 安装开始时间排序
|
|
|
+ Collections.sort(processes, Comparator.comparing(ProductionProcesses::getStartTime));
|
|
|
+ // 临时标记
|
|
|
+ Boolean a = false;
|
|
|
+ for(int i=0;i<processes.size()-1;i++){
|
|
|
+ if(processes.get(i).getSeriesProduceMark() != null && processes.get(i+1).getSeriesProduceMark() != null
|
|
|
+ && !processes.get(i).getSeriesProduceMark().equals(processes.get(i+1).getSeriesProduceMark())){
|
|
|
+ a = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return a;
|
|
|
+ }else{
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .penalize(HardSoftScore.ONE_SOFT,(proc1,proc2)->{
|
|
|
+ int b = 0;
|
|
|
+ for(int i=0;i<proc2.size()-1;i++){
|
|
|
+ if(proc2.get(i).getSeriesProduceMark() != null && proc2.get(i+1).getSeriesProduceMark() != null
|
|
|
+ && !proc2.get(i).getSeriesProduceMark().equals(proc2.get(i+1).getSeriesProduceMark())){
|
|
|
+ b++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(b>0){
|
|
|
+// System.out.println("扣分:"+b);
|
|
|
+ return b;
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+ })
|
|
|
+ .asConstraint("seriesProduce");
|
|
|
+
|
|
|
}
|
|
|
}
|