Parcourir la source

taskassigning新模型

fangpy il y a 6 mois
Parent
commit
93f5cb49f2

+ 19 - 13
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/taskassigning/ApsSolutionTa.java

@@ -1,8 +1,7 @@
-package com.rongwei.rwapsserver.aps.domain.taskassigning;
+package com.rongwei.rwapsserver.aps.taskassigning;
 
 import com.rongwei.rwapsserver.aps.domain.ApsAbstractPersistable;
 import com.rongwei.rwapsserver.aps.domain.Equipment;
-import com.rongwei.rwapsserver.aps.domain.ProductionProcesses;
 import lombok.*;
 import org.optaplanner.core.api.domain.solution.PlanningEntityCollectionProperty;
 import org.optaplanner.core.api.domain.solution.PlanningScore;
@@ -23,11 +22,18 @@ import java.util.List;
 @PlanningSolution
 public class ApsSolutionTa extends ApsAbstractPersistable {
 
-    @Getter(value = AccessLevel.NONE)
+    /*@Getter(value = AccessLevel.NONE)
     private List<ProductionProcesses> processesList;
 
     @Getter(value = AccessLevel.NONE)
-    private List<Equipment> equipmentList;
+    private List<Equipment> equipmentList;*/
+
+    @ValueRangeProvider
+    @ProblemFactCollectionProperty
+    private List<ProductionProcessesTa> processesList;
+
+    @PlanningEntityCollectionProperty
+    private List<EquipmentTa> equipmentList;
 
     @Getter(value = AccessLevel.NONE)
     private HardMediumSoftScore score;
@@ -36,31 +42,31 @@ public class ApsSolutionTa extends ApsAbstractPersistable {
 
     public LocalDateTime startTime;
     // 每一步骤最优规划实体
-    private List<ProductionProcesses> stepBestProcessesList;
+    private List<ProductionProcessesTa> stepBestProcessesList;
     // 是否初始结束
     private boolean constructionHeuristicEnd;
 
-    public ApsSolutionTa(String id, List<ProductionProcesses> processesList, List<Equipment> equipmentList) {
+    public ApsSolutionTa(String id, List<ProductionProcessesTa> processesList, List<EquipmentTa> equipmentList) {
         super(id);
         this.processesList = processesList;
         this.equipmentList = equipmentList;
     }
 
-    @ValueRangeProvider(id="taskRange")
-    @PlanningEntityCollectionProperty
-    public List<ProductionProcesses> getProcessesList() {
+//    @ValueRangeProvider(id="taskRange")
+//    @PlanningEntityCollectionProperty
+    public List<ProductionProcessesTa> getProcessesList() {
         return processesList;
     }
 
-    @ProblemFactCollectionProperty
-    public List<Equipment> getEquipmentList() {
+//    @ProblemFactCollectionProperty
+    public List<EquipmentTa> getEquipmentList() {
         return equipmentList;
     }
 
-    @ValueRangeProvider(id="timeRange")
+//    @ValueRangeProvider(id="timeRange")
     public CountableValueRange<LocalDateTime> getxRange(){
         Long produceTimeTotal = 0L;
-        for (ProductionProcesses productionProcesses : processesList) {
+        for (ProductionProcessesTa productionProcesses : processesList) {
             produceTimeTotal = produceTimeTotal + productionProcesses.getProduceTime();
         }
         LocalDateTime fromTime = LocalDateTime.now();

+ 7 - 2
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/taskassigning/EquipmentTa.java

@@ -1,11 +1,13 @@
-package com.rongwei.rwapsserver.aps.domain.taskassigning;
+package com.rongwei.rwapsserver.aps.taskassigning;
 
 import com.rongwei.rwapsserver.aps.domain.EquipmentParameter;
 import com.rongwei.rwapsserver.aps.domain.EquipmentRunTime;
 import com.rongwei.rwapsserver.aps.domain.ProductionProcesses;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import org.optaplanner.core.api.domain.entity.PlanningEntity;
 import org.optaplanner.core.api.domain.lookup.PlanningId;
+import org.optaplanner.core.api.domain.variable.PlanningListVariable;
 
 import java.io.Serializable;
 import java.math.BigDecimal;
@@ -17,7 +19,7 @@ import java.util.List;
  */
 @NoArgsConstructor
 @Data
-//@PlanningEntity
+@PlanningEntity
 public class EquipmentTa implements Serializable {
 
     private String id;
@@ -31,6 +33,9 @@ public class EquipmentTa implements Serializable {
         this.id = id;
     }
 
+    @PlanningListVariable
+    private List<ProductionProcessesTa> tasks;
+
     /**
      * 业务表订单工序ID
      */

+ 20 - 16
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/taskassigning/ProductionProcessesTa.java

@@ -1,4 +1,4 @@
-package com.rongwei.rwapsserver.aps.domain.taskassigning;
+package com.rongwei.rwapsserver.aps.taskassigning;
 
 import cn.hutool.core.date.DateUtil;
 import com.fasterxml.jackson.annotation.JsonFormat;
@@ -11,6 +11,7 @@ import org.optaplanner.core.api.domain.lookup.PlanningId;
 import org.optaplanner.core.api.domain.valuerange.CountableValueRange;
 import org.optaplanner.core.api.domain.valuerange.ValueRangeFactory;
 import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
+import org.optaplanner.core.api.domain.variable.InverseRelationShadowVariable;
 import org.optaplanner.core.api.domain.variable.PlanningVariable;
 import org.optaplanner.core.api.domain.variable.ShadowVariable;
 
@@ -95,12 +96,12 @@ public class ProductionProcessesTa implements Serializable {
     /**
      * 可选设备ID
      */
-    private List<Equipment> optionalProviderEquipments;
+    private List<EquipmentTa> optionalProviderEquipments;
 
     /**
      * 铸轧机按熔炉分组设备集合
      */
-    private Map<String, List<Equipment>> equass;
+    private Map<String, List<EquipmentTa>> equass;
 
     /**
      * 工步生产时的设备
@@ -110,7 +111,7 @@ public class ProductionProcessesTa implements Serializable {
     /**
      * 工步生产时的设备
      */
-    private Equipment equipment;
+    private EquipmentTa equipment;
 
     /**
      * 加工设备关联设备
@@ -393,6 +394,8 @@ public class ProductionProcessesTa implements Serializable {
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private LocalDateTime maxStartTime;
 
+    private EquipmentTa employee;
+
 
     public String getEquipmentType() {
         return equipmentType;
@@ -402,13 +405,14 @@ public class ProductionProcessesTa implements Serializable {
         this.equipmentType = equipmentType;
     }
 
-    @PlanningVariable(valueRangeProviderRefs={"equipmentRange"})
+//    @PlanningVariable(valueRangeProviderRefs={"equipmentRange"})
 //    @AnchorShadowVariable(sourceVariableName = "previousStep")
-    public Equipment getEquipment() {
+    @InverseRelationShadowVariable(sourceVariableName = "tasks")
+    public EquipmentTa getEquipment() {
         return equipment;
     }
 
-    @PlanningVariable(strengthComparatorClass = DelayStrengthComparator.class)
+//    @PlanningVariable(strengthComparatorClass = DelayStrengthComparator.class)
     public Integer getDelay() {
         return delay;
     }
@@ -419,13 +423,13 @@ public class ProductionProcessesTa implements Serializable {
         }
     }
 
-    @ValueRangeProvider(id="equipmentRange")
+//    @ValueRangeProvider(id="equipmentRange")
     @JsonIgnore
-    public List<Equipment> getOptionalProviderEquipments() {
+    public List<EquipmentTa> getOptionalProviderEquipments() {
         return optionalProviderEquipments;
     }
 
-    @ValueRangeProvider
+//    @ValueRangeProvider
     @JsonIgnore
     public CountableValueRange<Integer> getDelayRange() {
         /*if(this.getPreviousProcesses() != null && this.getPreviousProcesses().size()>0){
@@ -463,13 +467,13 @@ public class ProductionProcessesTa implements Serializable {
         return ValueRangeFactory.createIntValueRange(0, maxDelay);
     }
 
-    public void setOptionalProviderEquipments(List<Equipment> optionalProviderEquipments) {
+    public void setOptionalProviderEquipments(List<EquipmentTa> optionalProviderEquipments) {
         this.optionalProviderEquipments = optionalProviderEquipments;
     }
 
     //    @PlanningVariable(valueRangeProviderRefs={"timeRange"})
-    @ShadowVariable(variableListenerClass = TaskStartTimeListener.class, sourceVariableName = "equipment")
-    @ShadowVariable(variableListenerClass = TaskStartTimeListener.class, sourceVariableName = "delay")
+    @ShadowVariable(variableListenerClass = TaskStartTimeListenerTa.class, sourceEntityClass = EquipmentTa.class, sourceVariableName = "tasks")
+//    @ShadowVariable(variableListenerClass = TaskStartTimeListener.class, sourceVariableName = "delay")
 //    @AnchorShadowVariable(sourceVariableName = "equipment")
     public LocalDateTime getStartTime() {
         return startTime;
@@ -484,7 +488,7 @@ public class ProductionProcessesTa implements Serializable {
         this.previousStep = previousStep;
     }
 
-    public void setEquipment(Equipment equipment) {
+    public void setEquipment(EquipmentTa equipment) {
         if(!this.ifLock){
             this.equipment = equipment;
             if(equipment != null){
@@ -980,11 +984,11 @@ public class ProductionProcessesTa implements Serializable {
         this.mergeProOrders = mergeProOrders;
     }
 
-    public Map<String, List<Equipment>> getEquass() {
+    public Map<String, List<EquipmentTa>> getEquass() {
         return equass;
     }
 
-    public void setEquass(Map<String, List<Equipment>> equass) {
+    public void setEquass(Map<String, List<EquipmentTa>> equass) {
         this.equass = equass;
     }
 

+ 27 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/taskassigning/ProductionScheduleRetVoTa.java

@@ -0,0 +1,27 @@
+package com.rongwei.rwapsserver.aps.taskassigning;
+
+import com.rongwei.rwapsserver.aps.domain.ProductionProcesses;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ProductionScheduleRetVoTa {
+
+    /**
+     * 返回状态码
+     */
+    private String code;
+    /**
+     * 返回错误信息
+     */
+    private String msg;
+
+    private String scoreResult;
+
+    /**
+     * 排程后的生产工序集合
+     */
+    private List<ProductionProcesses> processes;
+
+}

+ 121 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/taskassigning/ProductionScheduleVoTa.java

@@ -0,0 +1,121 @@
+package com.rongwei.rwapsserver.aps.taskassigning;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.rongwei.rwapsserver.aps.domain.*;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+@Data
+public class ProductionScheduleVoTa {
+
+    private String productionScheduleId;
+
+    /**
+     * APS 排程计划开始时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date apsPlanStartDate;
+
+    /**
+     * 指定运行秒数
+     */
+    private Integer planSeconds;
+
+    /**
+     * 排程模式:
+     * default:分批排程(默认排程)
+     * mix:混合排程
+     */
+    private String scheduleType;
+
+    /**
+     * 生产工序集合
+     */
+    private List<ProductionProcessesTa> processes;
+
+    /**
+     * 生产设备集合
+     */
+    private List<EquipmentTa> equipmentList;
+
+    /**
+     * 工序之间流转时间设置(暂时不考虑跨工厂)
+     * 车间内流转时间:WORKSHOP_IN
+     * 跨车间流转时间:WORKSHOP_CROSS
+     */
+    private Map<String,Integer> roamTime;
+
+    private Integer environmentMode;
+
+    /**
+     * 洗炉合金
+     */
+    private List<WashingMetal> closealloynames;
+
+    /**
+     * 小卷成退合并装炉分组规则
+     */
+    private List<ApsFurnaceInstallationDo> furnaceInstallations;
+
+    /**
+     * 小卷成退合并装炉兼容规则
+     */
+    private List<ApsMergeFurnaceDo> mergeFurnaces;
+
+    /**
+     * 退火合炉厚差配置表
+     */
+    private List<ApsAnnealingDifferenceDo> apsAnnealingDifferences;
+
+    /**
+     * 铸轧兼容配置表
+     */
+    private List<ApsNochangeRollerDo> apsNochangeRollerDos;
+
+    /**
+     * 洗炉时间(小时)
+     */
+    private Integer washingtime;
+    /**
+     * 立板时间(小时)
+     */
+    private Integer standingtime;
+    /**
+     * 周期立板产量(吨)
+     */
+    private Integer standingyield;
+    /**
+     * 松散度
+     */
+    private BigDecimal looseness;
+    /**
+     * 排程速度
+     */
+    private Integer pcspeed;
+
+    /**
+     * 除铸轧外期望交货天数
+     */
+    private Integer expecteddays;
+    /**
+     * 中退组炉宽差,默认:250mm
+     */
+    private Integer middifference;
+    /**
+     * 成退组炉宽差,默认:200mm
+     */
+    private Integer furnacedifference;
+    /**
+     * 中退组炉卷重差(吨)
+     */
+    private BigDecimal weightdifference;
+    /**
+     * 成退组炉卷重差(吨)
+     */
+    private BigDecimal midweightdifference;
+
+}

+ 8 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/taskassigning/TaskAssignApsService.java

@@ -0,0 +1,8 @@
+package com.rongwei.rwapsserver.aps.taskassigning;
+
+
+public interface TaskAssignApsService {
+
+    ProductionScheduleRetVoTa productionSchedule(ProductionScheduleVoTa productionScheduleVo) throws Exception;
+
+}

+ 222 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/taskassigning/TaskAssignApsServiceImpl.java

@@ -0,0 +1,222 @@
+package com.rongwei.rwapsserver.aps.taskassigning;
+
+import cn.hutool.core.util.StrUtil;
+import com.rongwei.rwapsserver.aps.domain.*;
+import com.rongwei.rwapsserver.aps.util.ApsException;
+import com.rongwei.rwapsserver.aps.vo.ProductionScheduleRetVo;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class TaskAssignApsServiceImpl implements TaskAssignApsService{
+    @Override
+    public ProductionScheduleRetVoTa productionSchedule(ProductionScheduleVoTa productionScheduleVo) throws Exception {
+        log.info("*************** 排程开始:"+productionScheduleVo.getProductionScheduleId()+" *******************");
+        // 排程结果对象
+        ProductionScheduleRetVo productionScheduleRetVo = new ProductionScheduleRetVo();
+        // 排程校验
+        if(productionScheduleVo.getRoamTime() == null || productionScheduleVo.getRoamTime().size() == 0){
+            throw new ApsException("缺少全局流转时间配置");
+        }
+        // optaplanner 求解器数据装配
+        List<ProductionProcessesTa> otherThproces = new ArrayList<>();
+        List<ProductionProcessesTa> otherNotThproces = new ArrayList<>();
+        ApsSolutionTa apsSolution = getPreApsSolution(productionScheduleVo,otherThproces);
+        // 判断是否有非锁定的工序
+        boolean hasSchedulePro = false;
+        for (ProductionProcessesTa productionProcesses : apsSolution.getProcessesList()) {
+            if(!productionProcesses.getIfLock()){
+                hasSchedulePro = true;
+                break;
+            }
+        }
+        if(!hasSchedulePro){
+            throw new ApsException("没有可排程的工序");
+        }
+
+
+        return null;
+    }
+
+    private ApsSolutionTa getPreApsSolution(ProductionScheduleVoTa productionScheduleVo,List<ProductionProcessesTa> otherThproces){
+        ApsSolutionTa unsolvedCloudBalance = new ApsSolutionTa();
+        // 排程全局配置
+        ApsOverallConfig apsOverallConfig = new ApsOverallConfig();
+        // 排程计划开始时间
+        Date startDate = productionScheduleVo.getApsPlanStartDate();
+        LocalDateTime startTime = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+        apsOverallConfig.setStartTimeLong(startDate.getTime());
+        apsOverallConfig.setStartTime(startTime);
+        // 排程全局配置
+        apsOverallConfig.setRoamTime(productionScheduleVo.getRoamTime());
+        apsOverallConfig.setWashingtime(productionScheduleVo.getWashingtime());
+        apsOverallConfig.setStandingtime(productionScheduleVo.getStandingtime());
+        apsOverallConfig.setClosealloynames(productionScheduleVo.getClosealloynames());
+        apsOverallConfig.setFurnaceInstallations(productionScheduleVo.getFurnaceInstallations());
+        apsOverallConfig.setMergeFurnaces(productionScheduleVo.getMergeFurnaces());
+        apsOverallConfig.setLooseness(productionScheduleVo.getLooseness());
+        apsOverallConfig.setStandingyield(productionScheduleVo.getStandingyield());
+        // 铸轧连续兼容配置
+        apsOverallConfig.setApsNochangeRollerDos(productionScheduleVo.getApsNochangeRollerDos());
+        unsolvedCloudBalance.setStartTime(startTime);
+
+        // 根据前道、后道工序ID,转换为前道、后道工序对象
+        Map<String,ProductionProcessesTa> idMaps = new HashMap<>();
+        for (ProductionProcessesTa process : productionScheduleVo.getProcesses()) {
+            idMaps.put(String.join(",",process.getId()),process);
+        }
+        /*List<ProductionProcessesTa> thList = apsService.thProcessMerge(productionScheduleVo,otherThproces);
+        productionScheduleVo.setProcesses(thList);*/
+        for (ProductionProcessesTa process : productionScheduleVo.getProcesses()) {
+            // 全局配置设置
+            if(process.getApsOverallConfig() == null){
+                process.setApsOverallConfig(apsOverallConfig);
+            }else{
+                // 铸轧连续兼容配置
+                process.getApsOverallConfig().setApsNochangeRollerDos(productionScheduleVo.getApsNochangeRollerDos());
+            }
+            process.getApsOverallConfig().setApsAnnealingDifferences(productionScheduleVo.getApsAnnealingDifferences());
+            process.getApsOverallConfig().setMiddifference(productionScheduleVo.getMiddifference());
+            process.getApsOverallConfig().setFurnacedifference(productionScheduleVo.getFurnacedifference());
+            process.getApsOverallConfig().setWeightdifference(productionScheduleVo.getWeightdifference());
+            process.getApsOverallConfig().setMidweightdifference(productionScheduleVo.getMidweightdifference());
+
+            if(StrUtil.isBlank(process.getTaskType())){
+                process.setTaskType("processes");
+            }
+            process.setMergeRooprocess(new ArrayList<>());
+            process.setApsStatus("CH");
+            process.setOrderId(process.getProduceOrder().get(0).getId());
+            process.setTotalSinglerollweight(process.getSinglerollweight());
+            process.setTotalVolumeWidth(process.getVolumeWidth());
+            // 前道工序
+            if(process.getPreviousProcessesIds() != null && process.getPreviousProcessesIds().size()>0){
+                List<ProductionProcessesTa> pres = new ArrayList<>();
+                for (String previousProcessesId : process.getPreviousProcessesIds()) {
+                    for (ProductionProcessesTa productionScheduleVoProcess : productionScheduleVo.getProcesses()) {
+                        if(productionScheduleVoProcess.getId().equals(previousProcessesId)){
+                            pres.add(productionScheduleVoProcess);
+                        }
+                    }
+
+                }
+                if(pres != null && pres.size()>0){
+                    process.setPreviousProcesses(pres);
+                }
+                // 前道工序历史备份
+                List<String> oldpreids = new ArrayList<>();
+                oldpreids.addAll(process.getPreviousProcessesIds());
+                process.setOldPreviousProcessesIds(oldpreids);
+            }
+            // 后道工序
+            if(process.getNextProcessesIds() != null && process.getNextProcessesIds().size()>0){
+                List<ProductionProcessesTa> nexts = new ArrayList<>();
+                /*for (String nextId : process.getNextProcessesIds()) {
+                    nexts.add(idMaps.get(nextId));
+                }*/
+                for (String previousProcessesId : process.getNextProcessesIds()) {
+                    for (ProductionProcessesTa nextprocess : productionScheduleVo.getProcesses()) {
+                        if(nextprocess.getId().equals(previousProcessesId)){
+                            nexts.add(nextprocess);
+                        }
+                    }
+
+                }
+                if(nexts != null && nexts.size()>0){
+                    process.setNextProcesses(nexts);
+                }
+                // 后道工序历史备份
+                List<String> oldnextids = new ArrayList<>();
+                oldnextids.addAll(process.getNextProcessesIds());
+                process.setOldNextProcessesIds(oldnextids);
+            }
+            // 默认批次为1
+            if(process.getProducePcNum() == null){
+                process.setProducePcNum(1);
+            }
+            // 单位批次生产时间
+            if(process.getUnitProduceTime() == null){
+                process.setUnitProduceTime((int)(Math.ceil((double)process.getProduceTime()/process.getProducePcNum())));
+            }
+            process.setVolumeMetalAndState(process.getVolumeMetal() + (process.getVolumeMetalstate() == null ? "" : process.getVolumeMetalstate()) + process.getProcessType());
+            // 可选设备初始化
+            if(process.getOptionalEquipments() != null){
+                List<EquipmentTa> providedEq = new ArrayList<>();
+                for (EquipmentTa equipment : productionScheduleVo.getEquipmentList()) {
+                    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","坯料计划号:"+process.getProduceOrder().get(0).getOrderNo()+"作业名称:"+ process.getProcessName() + ",可选设备不能为空");
+                }
+                process.setOptionalProviderEquipments(providedEq);
+            }
+            // 铸轧机熔炉分组
+            List<EquipmentTa> zzrls = productionScheduleVo.getEquipmentList().stream().filter(v->StrUtil.isNotBlank(v.getEquassociated())).collect(Collectors.toList());
+            Map<String, List<EquipmentTa>> equass = zzrls.stream().collect(Collectors.groupingBy(EquipmentTa::getEquassociated));
+            process.setEquass(equass);
+
+            // 上机时间和下机时间如果为null,设置为0
+            if(process.getPrepressworkmin() == null){
+                process.setPrepressworkmin(0);
+            }
+            if(process.getCutfinishmin() == null){
+                process.setCutfinishmin(0);
+            }
+            // 锁定工序处理
+            if(process.getIfLock() && process.getOptionalProviderEquipments().size()>0){
+                process.setIfLock(false);
+                int ai = -1;
+                if(process.getOptionalProviderEquipments().get(0).getEquipmentRunTimes() != null
+                        && process.getOptionalProviderEquipments().get(0).getEquipmentRunTimes().size()>0){
+                    for (int i = 0; i < process.getOptionalProviderEquipments().get(0).getEquipmentRunTimes().size(); i++) {
+                        EquipmentRunTime equipmentRunTime = process.getOptionalProviderEquipments().get(0).getEquipmentRunTimes().get(i);
+                        if(equipmentRunTime.getStartRunTime().compareTo(process.getStartTime()) == 0 && equipmentRunTime.getEndRunTime().compareTo(process.getEndTime()) == 0){
+                            ai = i;
+                        }
+                    }
+                }
+                if(ai>-1){
+                    process.getOptionalProviderEquipments().get(0).getEquipmentRunTimes().remove(ai);
+                }
+                // 锁定工序的设备即可选设备
+                process.setEquipment(process.getOptionalProviderEquipments().get(0));
+                process.setIfLock(true);
+            }
+            // 特殊冲突约束Map初始化
+            process.setConflictRoptions(new ConcurrentHashMap<>());
+            // 唯一作业ID设值
+            process.setUniqueBsProcessesId(process.getBsProcessesId().get(0));
+        }
+        // 设备占用时间段合并处理
+        /*for (Equipment equipment : productionScheduleVo.getEquipmentList()) {
+            if(equipment.getId().equals("07a5e263a79c47b48c6ff3ea6152e611")){
+                int a = 1;
+            }
+            apsService.equipmentRunTimeMerge(equipment,productionScheduleVo.getFurnaceInstallations());
+        }*/
+        // 设备列表初始化
+        unsolvedCloudBalance.setEquipmentList(productionScheduleVo.getEquipmentList());
+
+        /*List<ProductionProcessesTa> productionProcesses = sortProcess(productionScheduleVo.getProcesses());
+        // 工序任务初始化
+        unsolvedCloudBalance.setProcessesList(productionProcesses);*/
+
+//        sortProcess(productionScheduleVo.getProcesses(),0);
+        unsolvedCloudBalance.setProcessesList(productionScheduleVo.getProcesses());
+        return unsolvedCloudBalance;
+    }
+}

+ 97 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/taskassigning/TaskStartTimeListenerTa.java

@@ -0,0 +1,97 @@
+package com.rongwei.rwapsserver.aps.taskassigning;
+
+import cn.hutool.core.util.StrUtil;
+import com.rongwei.rwapsserver.aps.domain.*;
+import lombok.extern.slf4j.Slf4j;
+import org.optaplanner.core.api.domain.variable.ListVariableListener;
+import org.optaplanner.core.api.domain.variable.VariableListener;
+import org.optaplanner.core.api.score.director.ScoreDirector;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.*;
+
+/**
+ * 设备赋值后任务起止时间自动计算
+ */
+@Slf4j
+public class TaskStartTimeListenerTa implements ListVariableListener<ApsSolutionTa,EquipmentTa, ProductionProcessesTa> {
+
+    @Override
+    public void beforeEntityAdded(ScoreDirector<ApsSolutionTa> scoreDirector, EquipmentTa equipmentTa) {
+        throw new UnsupportedOperationException("This example does not support adding employees.");
+    }
+
+    @Override
+    public void afterEntityAdded(ScoreDirector<ApsSolutionTa> scoreDirector, EquipmentTa equipmentTa) {
+        throw new UnsupportedOperationException("This example does not support adding employees.");
+    }
+
+    @Override
+    public void beforeEntityRemoved(ScoreDirector<ApsSolutionTa> scoreDirector, EquipmentTa equipmentTa) {
+        throw new UnsupportedOperationException("This example does not support adding employees.");
+    }
+
+    @Override
+    public void afterEntityRemoved(ScoreDirector<ApsSolutionTa> scoreDirector, EquipmentTa equipmentTa) {
+        throw new UnsupportedOperationException("This example does not support adding employees.");
+    }
+
+    @Override
+    public void afterListVariableElementUnassigned(ScoreDirector<ApsSolutionTa> scoreDirector, ProductionProcessesTa productionProcessesTa) {
+        scoreDirector.beforeVariableChanged(productionProcessesTa, "startTime");
+        productionProcessesTa.setStartTime(null);
+        scoreDirector.afterVariableChanged(productionProcessesTa, "startTime");
+    }
+
+    @Override
+    public void beforeListVariableChanged(ScoreDirector<ApsSolutionTa> scoreDirector, EquipmentTa equipmentTa, int fromIndex, int toIndex) {
+        // Do nothing
+    }
+
+    @Override
+    public void afterListVariableChanged(ScoreDirector<ApsSolutionTa> scoreDirector, EquipmentTa equipmentTa, int fromIndex, int toIndex) {
+        updateStartTime(scoreDirector, equipmentTa, fromIndex);
+    }
+
+    protected void updateStartTime(ScoreDirector<ApsSolutionTa> scoreDirector, EquipmentTa equipmentTa, int index) {
+        List<ProductionProcessesTa> tasks = equipmentTa.getTasks();
+        ProductionProcessesTa productionProcessesTa = tasks.get(index);
+        LocalDateTime previousEndTime = index == 0 ? productionProcessesTa.getApsOverallConfig().getStartTime() : tasks.get(index - 1).getEndTime();
+
+        for (int i = index; i < tasks.size(); i++) {
+            ProductionProcessesTa t = tasks.get(i);
+            LocalDateTime previousLastEndTime = null;
+            if(t.getPreviousProcesses() != null && t.getPreviousProcesses().size()>0){
+                for (ProductionProcessesTa previousProcess : t.getPreviousProcesses()) {
+                    int lzTimes = 0;
+                    if(previousProcess.getEquipment().getWorkshopid() != null && previousProcess.getEquipment().getWorkshopid().equals(equipmentTa.getWorkshopid())){
+                        lzTimes = t.getApsOverallConfig().getRoamTime().get("WORKSHOP_IN");
+                    }else if(!previousProcess.getEquipment().getId().equals(equipmentTa.getId())){
+                        lzTimes = t.getApsOverallConfig().getRoamTime().get("WORKSHOP_CROSS");
+                    }
+
+                    if(previousLastEndTime == null){
+                        previousLastEndTime = previousProcess.getEndTime();
+                    }else{
+                        if(previousLastEndTime.compareTo(previousProcess.getEndTime().plusMinutes(lzTimes))<0){
+                            previousLastEndTime = previousProcess.getEndTime().plusMinutes(lzTimes);
+                        }
+                    }
+                }
+            }
+            if(t.getMinWaitTime() != null && t.getMinWaitTime()>0 && previousLastEndTime != null){
+                previousLastEndTime = previousLastEndTime.plusMinutes(t.getMinWaitTime());
+            }
+            if(previousLastEndTime != null && previousLastEndTime.compareTo(previousEndTime)>0){
+                previousEndTime = previousLastEndTime;
+            }
+            if (!Objects.equals(t.getStartTime(), previousEndTime)) {
+                scoreDirector.beforeVariableChanged(t, "startTime");
+                t.setStartTime(previousEndTime);
+                scoreDirector.afterVariableChanged(t, "startTime");
+            }
+            previousEndTime = t.getEndTime();
+        }
+    }
+}