插单

parent 6430785e
......@@ -400,11 +400,23 @@ public class ResourceGanttController {
return R.ok("复制成功");
}
@PostMapping("/orderInsert")
@Operation(summary = "订单插单", description = "在指定订单后插入新订单")
public R<String> insertOrder(@RequestBody Map<String, Object> params) {
log.info("insertOrder 请求参数: {}", params);
String sceneId = ParamValidator.getString(params, "sceneId", "场景ID");
String afterOrderId = ParamValidator.getString(params, "afterOrderId", "插入位置订单ID");
// 获取新订单信息
@SuppressWarnings("unchecked")
Map<String, Object> newOrderData = (Map<String, Object>) params.get("newOrder");
ParamValidator.validateSceneExists(sceneService, sceneId);
Chromosome result = planResultService.InsertOrder(sceneId, afterOrderId, newOrderData);
return R.ok("插单成功");
}
@PostMapping("/ordermerge")
@Operation(summary = "订单合并", description = "订单合并")
......
......@@ -282,7 +282,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
public void decode(Chromosome chromosome) {
List<OrderMaterialRequirement> orderMaterials = materialRequirementService.buildMultiLevelRequirementNetwork(chromosome, sceneId, baseTime,_globalParam);
// List<OrderMaterialRequirement> orderMaterials = materialRequirementService.buildMultiLevelRequirementNetwork(chromosome, sceneId, baseTime,_globalParam);
chromosome.setScenarioID(sceneId);
if(_globalParam.isIsCheckSf()) {
int isnew= generateGlobalOpList(chromosome);
......
package com.aps.service.Algorithm;
import com.aps.common.util.ProductionDeepCopyUtil;
import com.aps.entity.*;
import com.aps.entity.Algorithm.*;
import com.aps.entity.Algorithm.IDAndChildID.GroupResult;
import com.aps.entity.Algorithm.IDAndChildID.NodeInfo;
......@@ -926,6 +927,220 @@ if(targetOp.getSequence()>1) {
redecode(chromosome, chromosome.getBaseTime(), globalParam);
}
/**
* 插入新订单到排产中
* 将新订单排在指定订单后面
*
* @param chromosome 染色体对象
* @param afterOrderId 插入位置订单ID(新订单将排在此订单后面)
* @param newOrderId 新订单ID
* @param newLaunchOrder 新订单对象
* @param newProcessExecs 新订单的工序列表
* @param globalParam 全局参数
*/
public void InsertOrder(Chromosome chromosome, String afterOrderId, String newOrderId,
ProdLaunchOrder newLaunchOrder, List<ProdProcessExec> newProcessExecs,
GlobalParam globalParam) {
List<Entry> allOperations = chromosome.getAllOperations();
List<Order> orders = chromosome.getOrders();
List<GroupResult> OperatRels = chromosome.getOperatRel();
// 1. 创建新的Order对象
Order newOrder = new Order();
newOrder.setOrderId(newOrderId);
newOrder.setOrderCode(newLaunchOrder.getOrderCode());
newOrder.setQuantity(newLaunchOrder.getQuantity());
newOrder.setPriority(newLaunchOrder.getOrderPriority() != null ? newLaunchOrder.getOrderPriority() : 1);
newOrder.setMaterialId(newLaunchOrder.getMaterialId());
newOrder.setMaterialCode(newLaunchOrder.getMaterialCode());
newOrder.setMaterialName(newLaunchOrder.getMaterialName());
newOrder.setStartDate(newLaunchOrder.getStartDate());
newOrder.setDueDate(newLaunchOrder.getEndDate());
newOrder.setRoutingId(newLaunchOrder.getRoutingId());
newOrder.setRoutingCode(newLaunchOrder.getRoutingCode());
newOrder.setSerie(newLaunchOrder.getSerie());
newOrder.setNewCreate(true);
// 获取当前最大的Order ID
int maxOrderId = orders.stream()
.mapToInt(Order::getId)
.max()
.orElse(0) + 1;
newOrder.setId(maxOrderId);
orders.add(newOrder);
// 2. 创建新订单的Entry对象
int maxGroupId = OperatRels.size();
int newGroupId = maxGroupId + 1;
List<Entry> newEntrys = new ArrayList<>();
List<String> newIdList = new ArrayList<>();
List<String> newChildIdList = new ArrayList<>();
// 从ProdProcessExec创建Entry
for (ProdProcessExec processExec : newProcessExecs) {
Entry newEntry = new Entry();
newEntry.setExecId(processExec.getExecId());
newEntry.setOrderId(newOrderId);
newEntry.setOrderCode(newLaunchOrder.getOrderCode());
newEntry.setGroupId(newGroupId);
newEntry.setQuantity(newLaunchOrder.getQuantity());
newEntry.setSequence(processExec.getTaskSeq() != null ? processExec.getTaskSeq().intValue() : 1);
newEntry.setNewCreate(true);
newEntry.setState(2);
// 设置工序相关信息
newEntry.setRoutingDetailId(processExec.getRoutingDetailId());
// 使用runtime字段
if (processExec.getRuntime() != null) {
newEntry.setRuntime(processExec.getRuntime());
}
newEntry.setPriority(newLaunchOrder.getOrderPriority() != null ? newLaunchOrder.getOrderPriority() : 1);
// 设置其他时间相关字段
if (processExec.getSetupTime() != null) {
newEntry.setSetupTime(processExec.getSetupTime());
}
newEntry.setChangeLineTime(processExec.getChangeLineTime());
newEntry.setConstTime(processExec.getConstTime());
newEntry.setPreTime(processExec.getPreprocessingTime());
newEntry.setTeardownTime(processExec.getPostprocessingTime());
// 设置设备相关信息
newEntry.setEquipTypeName(processExec.getEquipTypeName());
newEntry.setEquipTypeCode(processExec.getEquipTypeCode());
// 设置设备选项(从数据库加载或使用默认值)
// 这里需要根据实际情况设置MachineOptions
// 暂时使用空列表,后续在redecode时会重新计算
newEntry.setMachineOptions(new ArrayList<>());
newEntrys.add(newEntry);
}
// 3. 建立工序之间的依赖关系
for (int i = 0; i < newEntrys.size(); i++) {
Entry entry = newEntrys.get(i);
if (i == 0) {
// 第一道工序,没有前置工序
newIdList.add(entry.getExecId());
newChildIdList.add(i + 1 < newEntrys.size() ? newEntrys.get(i + 1).getExecId() : "");
} else if (i == newEntrys.size() - 1) {
// 最后一道工序,没有后续工序
newIdList.add(entry.getExecId());
newChildIdList.add("");
} else {
// 中间工序
newIdList.add(entry.getExecId());
newChildIdList.add(newEntrys.get(i + 1).getExecId());
}
}
// 4. 添加新数据到OperatRels
OperatRels = IdGroupingWithDualSerial.addNewDataWithIsolatedGroup(OperatRels, newIdList, newChildIdList);
chromosome.setOperatRel(new CopyOnWriteArrayList<>(OperatRels));
// 5. 更新全局ID和Entry信息
int globalOpId = chromosome.getGlobalOpList().stream()
.mapToInt(GlobalOperationInfo::getGlobalOpId)
.max()
.orElse(0) + 1;
GroupResult newGroupResult = OperatRels.get(OperatRels.size() - 1);
List<NodeInfo> nodeInfoList = newGroupResult.getNodeInfoList();
for (NodeInfo nodeInfo : nodeInfoList) {
Entry entry = newEntrys.stream()
.filter(t -> t.getExecId().equals(nodeInfo.getOriginalId()))
.findFirst()
.orElse(null);
if (entry != null) {
entry.setId(nodeInfo.getGlobalSerial());
entry.setGroupId(newGroupId);
entry.setSequence(nodeInfo.getGroupSerial());
// 设置前置和后续工序依赖
if (nodeInfo.getNewParentIds() != null) {
List<OperationDependency> dependencies = new ArrayList<>();
for (int id : nodeInfo.getNewParentIds()) {
OperationDependency od = new OperationDependency();
od.setPrevOperationId(id);
dependencies.add(od);
}
entry.setPrevEntryIds(dependencies);
}
if (nodeInfo.getNewChildIds() != null) {
List<OperationDependency> dependencies = new ArrayList<>();
for (int id : nodeInfo.getNewChildIds()) {
OperationDependency od = new OperationDependency();
od.setNextOperationId(id);
dependencies.add(od);
}
entry.setNextEntryIds(dependencies);
}
// 添加到allOperations
chromosome.getAllOperations().add(entry);
// 添加到全局操作列表
GlobalOperationInfo info = new GlobalOperationInfo();
info.setGlobalOpId(globalOpId);
info.setGroupId(entry.getGroupId());
info.setSequence(entry.getSequence());
info.setOp(entry);
chromosome.getGlobalOpList().add(info);
globalOpId++;
// 添加默认的机器选择(第一个可选设备)
chromosome.getMachineSelection().add(1);
}
}
// 6. 将新订单插入到指定订单后面的位置
List<Entry> afterOrderOps = allOperations.stream()
.filter(o -> o.getOrderId().equals(afterOrderId))
.sorted(Comparator.comparing(Entry::getSequence))
.collect(Collectors.toList());
if (!afterOrderOps.isEmpty()) {
Entry lastOpOfAfterOrder = afterOrderOps.get(afterOrderOps.size() - 1);
List<Integer> operationSequencing = chromosome.getOperationSequencing();
// 找到afterOrder最后一道工序在operationSequencing中的位置
OptionalInt operationIndex = IntStream.range(0, operationSequencing.size())
.filter(i -> operationSequencing.get(i).equals(lastOpOfAfterOrder.getGroupId()))
.findFirst();
if (operationIndex.isPresent()) {
int insertPosition = operationIndex.getAsInt() + 1;
// 在该位置后插入新订单的所有工序
for (int i = 0; i < newEntrys.size(); i++) {
chromosome.getOperationSequencing().add(insertPosition + i, newGroupId);
}
} else {
// 如果找不到位置,就添加到末尾
for (int i = 0; i < newEntrys.size(); i++) {
chromosome.getOperationSequencing().add(newGroupId);
}
}
} else {
// 如果找不到afterOrder,就添加到末尾
for (int i = 0; i < newEntrys.size(); i++) {
chromosome.getOperationSequencing().add(newGroupId);
}
}
// 7. 重新解码,重新计算排产结果
redecode(chromosome, chromosome.getBaseTime(), globalParam);
}
public void MergeOrder(Chromosome chromosome, String sourceorderId,String targetorderId, GlobalParam globalParam) {
List<Entry> allOperations = chromosome.getAllOperations();
List<GlobalOperationInfo> globalOpList= chromosome.getGlobalOpList();
......
......@@ -115,12 +115,22 @@ public class LanuchServiceImpl implements LanuchService {
if (apsOrderIds.isEmpty()) {
apsOrders = new ArrayList<>();
} else {
apsOrders = apsOrderService.lambdaQuery()
// Oracle IN子句限制最多1000个值,需要分批查询
apsOrders = new ArrayList<>();
int batchSize = 1000;
for (int i = 0; i < apsOrderIds.size(); i += batchSize) {
int endIndex = Math.min(i + batchSize, apsOrderIds.size());
List<String> batchIds = apsOrderIds.subList(i, endIndex);
List<ApsOrder> batchOrders = apsOrderService.lambdaQuery()
.eq(ApsOrder::getIsdeleted, 0)
.eq(ApsOrder::getStatus, 4)
// .eq(ApsOrder::getCreatoruserid, username)
.in(ApsOrder::getId, apsOrderIds)
.in(ApsOrder::getId, batchIds)
.list();
apsOrders.addAll(batchOrders);
}
}
if (CollectionUtils.isEmpty(apsOrders)) {
throw new SceneGenerationException("工单列表不能为空");
......@@ -527,8 +537,37 @@ public class LanuchServiceImpl implements LanuchService {
}
launchOrder.setQuantity(order.getQuantity());
launchOrder.setMaterialId(order.getMmid());
// 处理routingId:如果ApsOrder中没有,则根据物料ID查询
if (order.getRoutingid() != null) {
launchOrder.setRoutingId(order.getRoutingid());
launchOrder.setRoutingCode(order.getRoutingcode());
} else {
// 根据物料ID查询工艺路线
if (order.getMmid() != null && !order.getMmid().trim().isEmpty()) {
RoutingHeader routingHeader = routingHeaderService.lambdaQuery()
.eq(RoutingHeader::getMaterialId, order.getMmid())
.eq(RoutingHeader::getIsDeleted, 0)
.orderByDesc(RoutingHeader::getCreationTime)
.last("FETCH FIRST 1 ROWS ONLY")
.one();
if (routingHeader != null) {
launchOrder.setRoutingId(routingHeader.getId());
launchOrder.setRoutingCode(routingHeader.getCode());
log.info("订单 {} 的物料 {} 自动匹配工艺路线: ID={}, Code={}",
order.getCode(), order.getMmid(), routingHeader.getId(), routingHeader.getCode());
} else {
log.warn("订单 {} 的物料 {} 没有配置工艺路线", order.getCode(), order.getMmid());
// 这里可以选择抛出异常或设置默认值
throw new RuntimeException("订单 " + order.getCode() + " 的物料 " + order.getMmid() + " 没有配置工艺路线");
}
} else {
log.error("订单 {} 没有物料ID,无法查询工艺路线", order.getCode());
throw new RuntimeException("订单 " + order.getCode() + " 没有物料ID");
}
}
return launchOrder;
}
......@@ -800,19 +839,33 @@ public class LanuchServiceImpl implements LanuchService {
}
public List<RoutingDetail> getRoutingDetails(List<Long> routingHeaderIds) {
if (routingHeaderIds.isEmpty()) {
return new ArrayList<>();
}
// Oracle IN子句限制最多1000个值,需要分批查询
List<RoutingDetail> allRoutingDetails = new ArrayList<>();
int batchSize = 1000;
for (int i = 0; i < routingHeaderIds.size(); i += batchSize) {
int endIndex = Math.min(i + batchSize, routingHeaderIds.size());
List<Long> batchIds = routingHeaderIds.subList(i, endIndex);
LambdaQueryWrapper<RoutingDetail> wrapper = new LambdaQueryWrapper<>();
wrapper.in(RoutingDetail::getRoutingHeaderId, routingHeaderIds)
wrapper.in(RoutingDetail::getRoutingHeaderId, batchIds)
.eq(RoutingDetail::getIsDeleted, 0) // 添加 is_deleted=0 过滤条件
.orderByAsc(RoutingDetail::getTaskSeq);
List<RoutingDetail> routingDetails = routingDetailMapper.selectList(wrapper);
List<RoutingDetail> batchDetails = routingDetailMapper.selectList(wrapper);
allRoutingDetails.addAll(batchDetails);
}
if (CollectionUtils.isEmpty(routingDetails)) {
if (CollectionUtils.isEmpty(allRoutingDetails)) {
log.error("工艺下无工序信息: {}", routingHeaderIds);
throw new RuntimeException("工艺下无工序信息: " + routingHeaderIds);
}
return routingDetails;
return allRoutingDetails;
}
/**
......
package com.aps.service.plan;
import com.aps.common.util.ProductionDeepCopyUtil;
import com.aps.common.util.redis.RedisUtils;
import com.aps.entity.Algorithm.Chromosome;
import com.aps.entity.Algorithm.GAScheduleResult;
import com.aps.entity.Algorithm.GlobalOperationInfo;
import com.aps.entity.Algorithm.ScheduleResultDetail;
import com.aps.entity.ApsTimeConfig;
import com.aps.entity.Dispatch;
......@@ -72,12 +74,12 @@ public class LockedOrderProcessorService {
log.info("锁定期范围: {} 到 {} (冻结期: {}秒)", config.lockStartTime, config.lockEndTime, config.freezeSeconds);
// 2. 从已下发场景获取锁定期工单
LockedOrdersData lockedData = loadLockedOrdersFromScenes(config, chromosome.getBaseTime());
LockedOrdersData lockedData = loadLockedOrdersFromScenes(config, chromosome.getBaseTime(), chromosome.getScenarioID());
// 3. 如果无法从已下发场景获取,则从Dispatch表创建
if (lockedData.results.isEmpty()) {
lockedData = createLockedOrdersFromDispatch(config, chromosome.getBaseTime());
}
// // 3. 如果无法从已下发场景获取,则从Dispatch表创建
// if (lockedData.results.isEmpty()) {
// lockedData = createLockedOrdersFromDispatch(config, chromosome.getBaseTime());
// }
// 4. 添加锁定期工单到chromosome
addLockedOrdersToChromosome(chromosome, lockedData, config);
......@@ -116,7 +118,7 @@ public class LockedOrderProcessorService {
/**
* 从已下发场景加载锁定期工单
*/
private LockedOrdersData loadLockedOrdersFromScenes(LockPeriodConfig config, LocalDateTime newBaseTime) {
private LockedOrdersData loadLockedOrdersFromScenes(LockPeriodConfig config, LocalDateTime newBaseTime, String newSceneId) {
LockedOrdersData data = new LockedOrdersData();
try {
......@@ -144,7 +146,7 @@ public class LockedOrderProcessorService {
// 遍历每个场景,加载锁定期工单
for (String sceneId : dispatchSceneIds) {
processSceneForLockedOrders(sceneId, frozenDispatches, config, newBaseTime, data);
processSceneForLockedOrders(sceneId, frozenDispatches, config, newBaseTime, data, newSceneId);
}
log.info("从 {} 个已下发场景排产结果中获取到 {} 个锁定期工单", dispatchSceneIds.size(), data.results.size());
......@@ -161,7 +163,7 @@ public class LockedOrderProcessorService {
*/
private void processSceneForLockedOrders(String sceneId, List<Dispatch> allDispatches,
LockPeriodConfig config, LocalDateTime newBaseTime,
LockedOrdersData data) {
LockedOrdersData data, String newSceneId) {
try {
log.info("处理场景: {}", sceneId);
......@@ -194,13 +196,93 @@ public class LockedOrderProcessorService {
copyLockedOrders(dispatchChromosome, currentSceneDispatches, lockedOrderIds,
dispatchBaseTime, newBaseTime, sceneId, data, config);
// 匹配Entry信息
matchLockedEntries(dispatchChromosome, data, sceneId);
// 直接从已下发场景匹配Entry信息,避免ID冲突
matchLockedEntriesFromDispatchScene(dispatchChromosome, data, sceneId, newSceneId);
} catch (Exception ex) {
log.error("处理场景 {} 的排产结果失败: {}", sceneId, ex.getMessage(), ex);
}
}
/**
* 直接从已下发场景匹配锁定期工单的Entry信息,避免ID冲突
*/
private void matchLockedEntriesFromDispatchScene(Chromosome dispatchChromosome, LockedOrdersData data, String oldSceneId, String newSceneId) {
if (dispatchChromosome.getAllOperations() == null) {
return;
}
log.info("场景 {} 中有 {} 个Entry,开始匹配锁定期工单的Entry信息",
oldSceneId, dispatchChromosome.getAllOperations().size());
for (GAScheduleResult result : data.results) {
log.debug("处理锁定期工单: ExecId={}, OperationId={}", result.getExecId(), result.getOperationId());
// 直接从已下发场景的allOperations中查找Entry
Entry entry = dispatchChromosome.getAllOperations().stream()
.filter(e -> e.getExecId().equals(result.getExecId()))
.findFirst()
.orElse(null);
if (entry != null) {
// 检查原始Entry的machineOptions
log.info("原始Entry {} 的machineOptions数量: {}",
entry.getExecId(),
entry.getMachineOptions() != null ? entry.getMachineOptions().size() : "null");
if (entry.getMachineOptions() != null && !entry.getMachineOptions().isEmpty()) {
for (int i = 0; i < entry.getMachineOptions().size(); i++) {
MachineOption option = entry.getMachineOptions().get(i);
log.info(" machineOption[{}]: machineId={}, equipCode={}, equipName={}",
i, option.getMachineId(), option.getEquipCode(), option.getEquipName());
}
}
// 创建Entry副本,保持原有的machineOptions和设备信息
Entry lockedEntry;
try {
lockedEntry = ProductionDeepCopyUtil.deepCopy(entry);
log.info("深拷贝后Entry {} 的machineOptions数量: {}, equipCode={}, equipName={}",
lockedEntry.getExecId(),
lockedEntry.getMachineOptions() != null ? lockedEntry.getMachineOptions().size() : "null",
lockedEntry.getEquipCode(), lockedEntry.getEquipName());
} catch (Exception e) {
log.error("深拷贝Entry失败: {}", e.getMessage(), e);
lockedEntry = entry; // 失败时使用原始Entry
}
// 确保selectMachineID设置正确
lockedEntry.setSelectMachineID(result.getMachineId());
// 修复:不再过滤machineOptions,保持原有的所有设备选项
// 原因:过滤machineOptions会导致在修改订单数量时,重新解码时无法正确处理
// 解码器会根据所有可用的machineOptions进行调度,而不是被限制在单一设备
// 这样可以避免因数量改变导致的时间冲突问题
log.info("锁定期Entry {} 保留所有machineOptions: 数量={}, equipCode={}, equipName={}",
lockedEntry.getExecId(),
lockedEntry.getMachineOptions() != null ? lockedEntry.getMachineOptions().size() : "null",
lockedEntry.getEquipCode(), lockedEntry.getEquipName());
// 重要:更新sceneId为新场景ID,确保查询时能正确匹配
if (newSceneId != null) {
String originalSceneId = lockedEntry.getSceneId();
lockedEntry.setSceneId(newSceneId);
log.info("更新锁定期Entry的sceneId: {} -> {}", originalSceneId, newSceneId);
}
data.entries.put(result.getExecId(), lockedEntry);
log.info("从场景 {} 匹配到锁定期Entry: ExecId={}, 设备ID={}, equipCode={}, equipName={}, machineOptions数量={}",
oldSceneId, result.getExecId(), result.getMachineId(),
lockedEntry.getEquipCode(), lockedEntry.getEquipName(),
lockedEntry.getMachineOptions() != null ? lockedEntry.getMachineOptions().size() : "null");
} else {
log.warn("在场景 {} 中未找到工序 {} 对应的Entry", oldSceneId, result.getExecId());
}
}
log.info("场景 {} 成功匹配 {} 个Entry信息", oldSceneId, data.entries.size());
}
/**
* 找出锁定期内的订单ID
*/
......@@ -265,7 +347,7 @@ public class LockedOrderProcessorService {
// 深拷贝工单并转换时间
GAScheduleResult lockedResult = copyGAScheduleResult(result);
lockedResult.setIsLocked(true);
lockedResult.setIsLocked(false); // 重要:标记为锁定工单,确保重新解码时不被清除
// 转换时间:从旧baseTime转换到新baseTime
LocalDateTime prevStartTime = oldBaseTime.plusSeconds(result.getStartTime());
......@@ -402,7 +484,9 @@ public class LockedOrderProcessorService {
result.setBomTime(0);
result.setDesignatedStartTime(-1);
result.setLockStartTime(0);
result.setForcedMachineId(-1L);
// 关键修复:为dispatch工单设置forcedMachineId,确保重新解码时使用这个设备
// 这样dispatch工单的设备就不会被改变
result.setForcedMachineId(dispatch.getEquipId());
// 创建GeneDetails
List<ScheduleResultDetail> geneDetails = new ArrayList<>();
......@@ -429,19 +513,178 @@ public class LockedOrderProcessorService {
log.info("成功添加 {} 个锁定期工单到调度结果中,result大小从{}变为{}",
data.results.size(), beforeSize, chromosome.getResult().size());
// 1.5. 关键修复:将锁定期工单添加到ResultOld中,确保重新解码时能获取正确的设备ID
if (chromosome.getResultOld() == null) {
chromosome.setResultOld(new CopyOnWriteArrayList<>());
}
// 深拷贝锁定期工单的GAScheduleResult到ResultOld
for (GAScheduleResult result : data.results) {
try {
GAScheduleResult resultCopy = ProductionDeepCopyUtil.deepCopy(result);
chromosome.getResultOld().add(resultCopy);
log.info("添加锁定期工单到ResultOld: OperationId={}, MachineId={}, IsLocked={}",
resultCopy.getOperationId(), resultCopy.getMachineId(), resultCopy.isIsLocked());
} catch (Exception e) {
log.error("深拷贝GAScheduleResult失败: {}", e.getMessage(), e);
chromosome.getResultOld().add(result); // 失败时使用原始对象
}
}
log.info("成功添加 {} 个锁定期工单到ResultOld中", data.results.size());
// 2. 复制锁定期订单的Order对象
copyLockedOrderObjects(chromosome, data, config);
// 3. 添加Entry到allOperations
// 3. 添加Entry到allOperations,并重新分配ID避免冲突
if (!data.entries.isEmpty() && chromosome.getAllOperations() != null) {
int beforeEntrySize = chromosome.getAllOperations().size();
// 获取当前最大的Entry ID,避免ID冲突
int maxExistingId = chromosome.getAllOperations().stream()
.mapToInt(Entry::getId)
.max()
.orElse(0);
int nextAvailableId = maxExistingId + 1;
// 为锁定期Entry重新分配ID
for (Entry lockedEntry : data.entries.values()) {
int oldId = lockedEntry.getId();
lockedEntry.setId(nextAvailableId);
// 更新对应的GAScheduleResult的operationId(包括result和resultOld)
int finalNextAvailableId = nextAvailableId;
// 更新result中的operationId
data.results.stream()
.filter(result -> result.getOperationId() == oldId)
.forEach(result -> result.setOperationId(finalNextAvailableId));
// 关键修复:同时更新resultOld中的operationId
if (chromosome.getResultOld() != null) {
chromosome.getResultOld().stream()
.filter(result -> result.getOperationId() == oldId)
.forEach(result -> {
result.setOperationId(finalNextAvailableId);
log.info("更新ResultOld中的operationId: {} -> {}, ExecId={}",
oldId, finalNextAvailableId, result.getExecId());
});
}
log.info("锁定期Entry ID重新分配: {} -> {}, ExecId={}",
oldId, nextAvailableId, lockedEntry.getExecId());
nextAvailableId++;
}
chromosome.getAllOperations().addAll(data.entries.values());
log.info("成功添加 {} 个锁定期Entry到allOperations中,大小从{}变为{}",
data.entries.size(), beforeEntrySize, chromosome.getAllOperations().size());
log.info("成功添加 {} 个锁定期Entry到allOperations中,大小从{}变为{},ID范围: {}-{}",
data.entries.size(), beforeEntrySize, chromosome.getAllOperations().size(),
maxExistingId + 1, nextAvailableId - 1);
}
// 4. 确保锁定期设备存在
ensureLockedMachines(chromosome, data.machineIds, config);
// 5. 将锁定期订单添加到operationSequencing中,确保它们会被解码处理
if (!data.entries.isEmpty() && chromosome.getOperationSequencing() != null) {
List<Integer> currentSequencing = new ArrayList<>(chromosome.getOperationSequencing());
// 获取所有锁定期订单的ID
Set<String> lockedOrderIds = data.entries.values().stream()
.map(Entry::getOrderId)
.collect(Collectors.toSet());
// 为每个锁定期订单添加其所有工序到排产序列
for (String orderId : lockedOrderIds) {
// 找到该订单的所有工序,按sequence排序
List<Entry> orderEntries = data.entries.values().stream()
.filter(entry -> orderId.equals(entry.getOrderId()))
.sorted(Comparator.comparing(Entry::getSequence))
.collect(Collectors.toList());
// 将每个工序的groupId添加到operationSequencing
for (Entry entry : orderEntries) {
currentSequencing.add(entry.getGroupId());
log.info("添加锁定期工序到排产序列: OrderId={}, GroupId={}, Sequence={}",
orderId, entry.getGroupId(), entry.getSequence());
}
}
chromosome.setOperationSequencing(currentSequencing);
log.info("更新operationSequencing,从{}个工序增加到{}个工序",
chromosome.getOperationSequencing().size() - (currentSequencing.size() - chromosome.getOperationSequencing().size()),
currentSequencing.size());
}
// 6. 关键修复:将锁定期Entry添加到globalOpList中,确保重新解码时不会丢失
if (!data.entries.isEmpty() && chromosome.getGlobalOpList() != null) {
// 获取当前最大的globalOpId
int maxGlobalOpId = chromosome.getGlobalOpList().stream()
.mapToInt(GlobalOperationInfo::getGlobalOpId)
.max()
.orElse(-1);
int nextGlobalOpId = maxGlobalOpId + 1;
// 为每个锁定期Entry创建GlobalOperationInfo并添加到globalOpList
List<Entry> sortedEntries = data.entries.values().stream()
.sorted(Comparator.comparing(Entry::getGroupId)
.thenComparing(Entry::getSequence))
.collect(Collectors.toList());
for (Entry lockedEntry : sortedEntries) {
GlobalOperationInfo info = new GlobalOperationInfo();
info.setGlobalOpId(nextGlobalOpId);
info.setGroupId(lockedEntry.getGroupId());
info.setSequence(lockedEntry.getSequence());
info.setOp(lockedEntry);
chromosome.getGlobalOpList().add(info);
log.info("添加锁定期Entry到globalOpList: GlobalOpId={}, EntryId={}, OrderCode={}, GroupId={}, Sequence={}, EquipCode={}",
nextGlobalOpId, lockedEntry.getId(), lockedEntry.getOrderCode(),
lockedEntry.getGroupId(), lockedEntry.getSequence(), lockedEntry.getEquipCode());
nextGlobalOpId++;
}
log.info("成功添加 {} 个锁定期Entry到globalOpList中,globalOpList大小变为{}",
sortedEntries.size(), chromosome.getGlobalOpList().size());
}
// 7. 关键修复:同步更新machineSelection,确保长度与globalOpList一致
if (!data.entries.isEmpty() && chromosome.getMachineSelection() != null) {
List<Integer> machineSelection = chromosome.getMachineSelection();
// 为每个锁定期Entry添加机器选择索引
// 锁定期工序的机器已经确定,所以机器选择索引设为1(表示使用machineOptions中的第一个,也是唯一的机器)
// 注意:machineSelection的索引是从1开始的,不是从0开始
List<Entry> sortedEntries = data.entries.values().stream()
.sorted(Comparator.comparing(Entry::getGroupId)
.thenComparing(Entry::getSequence))
.collect(Collectors.toList());
for (Entry lockedEntry : sortedEntries) {
// 锁定期工序的机器已经确定,machineSelection设为1(索引从1开始)
machineSelection.add(1);
log.info("添加锁定期Entry的机器选择: EntryId={}, OrderCode={}, EquipCode={}, MachineSelectionIndex=1",
lockedEntry.getId(), lockedEntry.getOrderCode(), lockedEntry.getEquipCode());
}
log.info("成功添加 {} 个锁定期Entry的机器选择到machineSelection中,machineSelection大小变为{}",
sortedEntries.size(), machineSelection.size());
// 验证:确保machineSelection长度与globalOpList长度一致
if (chromosome.getGlobalOpList().size() != machineSelection.size()) {
log.error("警告:machineSelection长度({})与globalOpList长度({})不一致!",
machineSelection.size(), chromosome.getGlobalOpList().size());
} else {
log.info("验证通过:machineSelection长度({})与globalOpList长度({})一致",
machineSelection.size(), chromosome.getGlobalOpList().size());
}
}
}
/**
......@@ -466,6 +709,9 @@ public class LockedOrderProcessorService {
log.info("需要复制的锁定期订单ID: {}", lockedOrderIds);
// 用于存储OrderId到新Order.id的映射
Map<String, Integer> orderIdToNewGroupId = new HashMap<>();
try {
// 查询锁定期Dispatch记录
List<Dispatch> frozenDispatches = queryFrozenDispatches(config);
......@@ -478,10 +724,20 @@ public class LockedOrderProcessorService {
log.info("锁定期Dispatch记录来自 {} 个场景: {}", dispatchSceneIds.size(), dispatchSceneIds);
// 从每个场景复制订单
// 从每个场景复制订单,并收集Order ID映射
for (String sceneId : dispatchSceneIds) {
copyOrdersFromScene(chromosome, sceneId, lockedOrderIds);
Map<String, Integer> sceneMapping = copyOrdersFromScene(chromosome, sceneId, lockedOrderIds);
orderIdToNewGroupId.putAll(sceneMapping);
}
log.info("Order ID映射: {}", orderIdToNewGroupId);
// 更新Entry的groupId
updateEntryGroupIds(data, orderIdToNewGroupId);
// 更新GAScheduleResult的groupId
updateResultGroupIds(data, orderIdToNewGroupId);
} catch (Exception e) {
log.error("复制锁定期订单失败: {}", e.getMessage(), e);
}
......@@ -489,16 +745,19 @@ public class LockedOrderProcessorService {
log.info("成功复制锁定期订单到Orders列表,大小从{}变为{}", beforeOrderSize, chromosome.getOrders().size());
}
/**
* 从指定场景复制订单
* 从场景复制订单,并返回OrderId到新Order.id的映射
* @return Map<OrderId, 新Order.id>
*/
private void copyOrdersFromScene(Chromosome chromosome, String sceneId, Set<String> lockedOrderIds) {
private Map<String, Integer> copyOrdersFromScene(Chromosome chromosome, String sceneId, Set<String> lockedOrderIds) {
Map<String, Integer> orderIdToNewGroupId = new HashMap<>();
try {
log.info("开始从场景 {} 加载Chromosome", sceneId);
Chromosome dispatchChromosome = sceneService.loadChromosomeFromFile(sceneId);
if (dispatchChromosome == null) {
log.warn("场景 {} 加载失败,Chromosome为null", sceneId);
return;
return orderIdToNewGroupId;
}
log.info("场景 {} 加载成功,Orders数量: {}", sceneId,
......@@ -506,7 +765,7 @@ public class LockedOrderProcessorService {
if (dispatchChromosome.getOrders() == null) {
log.warn("场景 {} 的Orders为null", sceneId);
return;
return orderIdToNewGroupId;
}
// 筛选锁定期订单
......@@ -516,15 +775,32 @@ public class LockedOrderProcessorService {
log.info("场景 {} 中找到 {} 个匹配的锁定期订单", sceneId, lockedOrders.size());
// 获取当前最大的Order ID
int maxOrderId = chromosome.getOrders().stream()
.mapToInt(Order::getId)
.max()
.orElse(0);
log.info("当前最大Order ID: {}", maxOrderId);
// 复制订单(避免重复)
for (Order lockedOrder : lockedOrders) {
boolean exists = chromosome.getOrders().stream()
.anyMatch(order -> lockedOrder.getOrderId().equals(order.getOrderId()));
if (!exists) {
// 为dispatch工单分配新的Order ID
int oldOrderId = lockedOrder.getId();
int newOrderId = ++maxOrderId;
lockedOrder.setId(newOrderId);
// 记录映射关系
orderIdToNewGroupId.put(lockedOrder.getOrderId(), newOrderId);
log.info("从场景 {} 复制锁定期订单: OrderId={}, OrderCode={}, 旧Order.id={}, 新Order.id={}",
sceneId, lockedOrder.getOrderId(), lockedOrder.getOrderCode(), oldOrderId, newOrderId);
chromosome.getOrders().add(lockedOrder);
log.info("从场景 {} 复制锁定期订单: OrderId={}, OrderCode={}",
sceneId, lockedOrder.getOrderId(), lockedOrder.getOrderCode());
} else {
log.warn("订单 {} 已存在,跳过复制", lockedOrder.getOrderId());
}
......@@ -532,6 +808,56 @@ public class LockedOrderProcessorService {
} catch (Exception ex) {
log.error("从场景 {} 复制锁定期订单失败: {}", sceneId, ex.getMessage(), ex);
}
return orderIdToNewGroupId;
}
/**
* 更新Entry的groupId
*/
private void updateEntryGroupIds(LockedOrdersData data, Map<String, Integer> orderIdToNewGroupId) {
if (orderIdToNewGroupId.isEmpty()) {
return;
}
log.info("开始更新Entry的groupId,映射数量: {}", orderIdToNewGroupId.size());
for (Entry entry : data.entries.values()) {
String orderId = entry.getOrderId();
if (orderIdToNewGroupId.containsKey(orderId)) {
int oldGroupId = entry.getGroupId();
int newGroupId = orderIdToNewGroupId.get(orderId);
entry.setGroupId(newGroupId);
log.info("更新Entry的groupId: ExecId={}, OrderId={}, 旧groupId={}, 新groupId={}",
entry.getExecId(), orderId, oldGroupId, newGroupId);
}
}
log.info("Entry的groupId更新完成");
}
/**
* 更新GAScheduleResult的groupId
*/
private void updateResultGroupIds(LockedOrdersData data, Map<String, Integer> orderIdToNewGroupId) {
if (orderIdToNewGroupId.isEmpty()) {
return;
}
log.info("开始更新GAScheduleResult的groupId,映射数量: {}", orderIdToNewGroupId.size());
for (GAScheduleResult result : data.results) {
String orderId = result.getOrderId();
if (orderIdToNewGroupId.containsKey(orderId)) {
int oldGroupId = result.getGroupId();
int newGroupId = orderIdToNewGroupId.get(orderId);
result.setGroupId(newGroupId);
log.info("更新GAScheduleResult的groupId: ExecId={}, OrderId={}, 旧groupId={}, 新groupId={}",
result.getExecId(), orderId, oldGroupId, newGroupId);
}
}
log.info("GAScheduleResult的groupId更新完成");
}
/**
......
......@@ -98,6 +98,8 @@ public class PlanResultService {
@Autowired
private OrderSortService orderSortService;
@Autowired
private LanuchService lanuchService;
@Autowired
private MaterialInfoMapper materialInfoMapper;
......@@ -231,6 +233,7 @@ public class PlanResultService {
kpiCalculator.calculatekpi();
// 添加锁定期工单到调度结果中
// 这里会从 Dispatch 表加载锁定期工单,并添加到 chromosome.result 中
// lockedOrderProcessorService.addLockedOrdersToResult(chromosome);
_sceneService.saveChromosomeToFile(chromosome, SceneId);
......@@ -1240,6 +1243,17 @@ public class PlanResultService {
entry.setPriority(order.getActualPriority());
});
}
// 更新调度结果中的数量(关键:处理锁定期工单)
List<GAScheduleResult> results = chromosome.getResult();
if (results != null) {
results.stream()
.filter(result -> result.getOrderId() != null && result.getOrderId().equals(order.getOrderId()))
.forEach(result -> {
result.setQuantity(order.getQuantity());
log.info("更新调度结果中的订单数量: OrderId={}, 新数量={}", order.getOrderId(), order.getQuantity());
});
}
}
/**
......@@ -1424,6 +1438,91 @@ public class PlanResultService {
_sceneService.saveChromosomeToFile(chromosome, SceneId);
return chromosome;
}
/**
* 插单功能:在指定订单后插入新订单
* 步骤1:先将新订单数据插入数据库
* 步骤2:使用类似复制订单的方式将新订单加入排产
*
* @param SceneId 场景ID
* @param afterOrderId 插入位置订单ID(新订单将排在此订单后面)
* @param newOrderData 新订单数据
* @return 更新后的Chromosome
*/
public Chromosome InsertOrder(String SceneId, String afterOrderId, Map<String, Object> newOrderData) {
// 步骤1:调用LanuchService的insertOrder方法,将新订单插入数据库
String orderCode = (String) newOrderData.get("orderCode");
String materialId = (String) newOrderData.get("materialId");
Double quantity = ((Number) newOrderData.get("quantity")).doubleValue();
LocalDateTime startDate = null;
LocalDateTime endDate = null;
Integer priority = 1;
if (newOrderData.containsKey("startDate")) {
startDate = LocalDateTime.parse((String) newOrderData.get("startDate"));
}
if (newOrderData.containsKey("endDate")) {
endDate = LocalDateTime.parse((String) newOrderData.get("endDate"));
}
if (newOrderData.containsKey("priority")) {
priority = ((Number) newOrderData.get("priority")).intValue();
}
// 调用insertOrder插入数据库
R<String> insertResult = lanuchService.insertOrder(SceneId, orderCode, materialId,
startDate, endDate, priority, quantity);
// if (!insertResult.isSuccess()) {
// throw new RuntimeException("插单失败: " + insertResult.getMsg());
// }
//
// 从返回消息中提取新订单ID
String message = insertResult.getData();
String newOrderId = message.substring(message.indexOf("订单ID: ") + 6);
log.info("新订单已插入数据库,订单ID: {}", newOrderId);
// 步骤2:使用类似SpiltOrder的方式,将新订单加入排产
// 这里需要重新加载场景,因为数据库已经有新订单了
// 然后使用类似复制的逻辑,将新订单排在afterOrderId后面
GlobalParam globalParam = new GlobalParam();
Chromosome chromosome = _sceneService.loadChromosomeFromFile(SceneId);
// 从数据库加载新插入的订单及其工序
ProdLaunchOrder newLaunchOrder = _prodLaunchOrderService.lambdaQuery()
.eq(ProdLaunchOrder::getSceneId, SceneId)
.eq(ProdLaunchOrder::getOrderId, newOrderId)
.one();
if (newLaunchOrder == null) {
throw new RuntimeException("未找到新插入的订单: " + newOrderId);
}
// 加载新订单的工序
List<ProdProcessExec> newProcessExecs = _prodProcessExecService.lambdaQuery()
.eq(ProdProcessExec::getSceneId, SceneId)
.eq(ProdProcessExec::getOrderId, newOrderId)
.orderBy(true, true, ProdProcessExec::getTaskSeq)
.list();
if (newProcessExecs.isEmpty()) {
throw new RuntimeException("新订单没有工序: " + newOrderId);
}
log.info("加载新订单: OrderId={}, OrderCode={}, 工序数={}",
newOrderId, newLaunchOrder.getOrderCode(), newProcessExecs.size());
// 调用ScheduleOperationService的方法将新订单加入排产
ScheduleOperationService scheduleOperation = new ScheduleOperationService(materialRequirementService, this);
scheduleOperation.InsertOrder(chromosome, afterOrderId, newOrderId, newLaunchOrder, newProcessExecs, globalParam);
WriteScheduleSummary(chromosome);
_sceneService.saveChromosomeToFile(chromosome, SceneId);
return chromosome;
}
public Chromosome MergeOrder(String SceneId,String sourceorderId,String targetorderId) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment