滚动排产

parent 994fc45b
......@@ -133,6 +133,28 @@ public class SwaggerMapParamConfig {
));
break;
case "insertOrder":
properties.put("sceneId", new StringSchema().description("场景ID").example("B571EF6682DB463AB2977B1055A74112"));
properties.put("orderCode", new StringSchema().description("订单编码").example("ORDER-2026-001"));
properties.put("materialId", new StringSchema().description("物料ID").example("MAT001"));
properties.put("startDate", new StringSchema().description("开始时间(ISO格式)").example("2026-03-10T08:00:00"));
properties.put("endDate", new StringSchema().description("结束时间(ISO格式)").example("2026-03-20T18:00:00"));
properties.put("priority", new StringSchema().description("优先级").example("1"));
properties.put("quantity", new StringSchema().description("数量").example("100.0"));
examples.put("插单示例", createExample(
"向现有场景添加新订单",
"{\n" +
" \"sceneId\": \"B571EF6682DB463AB2977B1055A74112\",\n" +
" \"orderCode\": \"ORDER-2026-001\",\n" +
" \"materialId\": \"MAT001\",\n" +
" \"startDate\": \"2026-03-10T08:00:00\",\n" +
" \"endDate\": \"2026-03-20T18:00:00\",\n" +
" \"priority\": 1,\n" +
" \"quantity\": 100.0\n" +
"}"
));
break;
case "getResourceGantt":
case "getProductGantt":
......
......@@ -187,4 +187,30 @@ public class LanuchController {
return lanuchService.savePlan(sceneId);
}
/**
* 插单:向现有场景添加新订单
*/
@PostMapping("/insertOrder")
@Operation(summary = "插单", description = "向现有场景添加新订单,订单ID会自动生成UUID格式")
public R<String> insertOrder(@RequestBody Map<String, Object> params) {
String sceneId = (String) params.get("sceneId");
String orderCode = (String) params.get("orderCode");
String materialId = (String) params.get("materialId");
// 解析时间参数
String startDateStr = (String) params.get("startDate");
String endDateStr = (String) params.get("endDate");
java.time.LocalDateTime startDate = java.time.LocalDateTime.parse(startDateStr);
java.time.LocalDateTime endDate = java.time.LocalDateTime.parse(endDateStr);
// 解析优先级和数量
Integer priority = params.get("priority") != null ?
Integer.valueOf(params.get("priority").toString()) : 1;
Double quantity = params.get("quantity") != null ?
Double.valueOf(params.get("quantity").toString()) : 0.0;
return lanuchService.insertOrder(sceneId, orderCode, materialId,
startDate, endDate, priority, quantity);
}
}
\ No newline at end of file
......@@ -51,4 +51,6 @@ public class ScheduleResultDetail {
public int getProcessingTime() {
return EndTime - StartTime; // 绝对处理时间(分钟)
}
}
......@@ -66,4 +66,6 @@ private Long issplit;
private Long parentid;
private Long statusOrtems;
private LocalDateTime actualEndTimeOrtems;
private String sceneId;
}
\ No newline at end of file
package com.aps.service.Algorithm;
import com.aps.common.util.DateTimeUtil;
import com.aps.common.util.DeepCopyUtil;
import com.aps.common.util.FileHelper;
import com.aps.common.util.ProductionDeepCopyUtil;
import com.aps.common.util.*;
import com.aps.entity.Algorithm.*;
import com.aps.entity.Algorithm.IDAndChildID.GroupResult;
import com.aps.entity.basic.*;
......@@ -82,16 +79,6 @@ public class GeneticAlgorithm {
throw new RuntimeException("没有待排产工单");
}
// if(materials!=null&&materials.size()>0) {
//
// materialRequirementService.init(materials, orders, allOperations, _entryRel, machineScheduler, machines,_GlobalParam);
//
// orderMaterials = materialRequirementService.buildMultiLevelRequirementNetwork(param.getBaseTime());
// Set<Long> existIds = new HashSet<>();
// machines=machines.stream()
// .filter(t->existIds.add(t.getId()))//HashSet.add() 方法:添加成功返回 true,重复返回 false;
// .collect(Collectors.toList());
// }
LocalDateTime starttime=LocalDateTime.now();
FileHelper.writeLogFile("排产-----------开始-----------"+allOperations.get(0).getSceneId());
......@@ -424,6 +411,15 @@ return population;
// chromosome.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines,Machine.class)); // 简单拷贝,实际可能需要深拷贝
// _sceneService.saveChromosomeToFile(chromosome, "12345679");
// 加载锁定工单到ResultOld
List<GAScheduleResult> lockedOrders = GlobalCacheUtil.get("locked_orders_" + sceneId);
if (lockedOrders != null && !lockedOrders.isEmpty()) {
chromosome.setResultOld(ProductionDeepCopyUtil.deepCopyList(lockedOrders, GAScheduleResult.class));
FileHelper.writeLogFile("将 " + lockedOrders.size() + " 个锁定工单加载到初始种群中");
} else {
chromosome.setResultOld(new CopyOnWriteArrayList<>());
}
decoder.decodeChromosomeWithCache(chromosome);
if (chromosome.getFitness() == 0) {
chromosome.setFitness(_fitnessCalculator.calculateFitness(chromosome, _objectiveWeights));
......
......@@ -371,16 +371,6 @@ if(finishedOrder==null||finishedOrder.size()==0)
Entry currentOp = orderOps.get(scheduledCount);
int opSequence = currentOp.getSequence();
GAScheduleResult existingResult = chromosome.getResultOld().stream()
.filter(r-> r.getOperationId() == currentOp.getId())
.findFirst().orElse(null);
if(existingResult!=null) {
if(existingResult.isIsLocked())
{
continue;
}
}
// 从映射表中获取机器和加工时间
OpMachine machineOption=opMachineMap.stream()
.filter(m -> m.getGroupId() == groupId&&m.getSequence()==opSequence)
......@@ -1509,15 +1499,22 @@ if(MaterialRequirements==null||MaterialRequirements.size()==0)
.filter(t->orderIds.contains(t.getOrderId()))
.max(Comparator.comparing(Order::getDueDate))
.orElse(null);
if(order.isNewCreate())
{continue;}
// 如果找不到对应的工单,跳过此工单组
if(order == null) {
continue;
}
// 如果是新创建的工单,跳过延迟计算
if(order.isNewCreate()) {
continue;
}
LocalDateTime dueDateTime=order.getDueDate();
// 如果交付期为空,跳过延迟计算
if(dueDateTime == null) {
continue;
}
LocalDateTime completionTime =baseTime.plusSeconds(orderCompletion);
if (completionTime.isAfter(dueDateTime)) {
// 计算延迟小时数(修复时间计算)
long hours = ChronoUnit.HOURS.between(dueDateTime, completionTime);
......@@ -1583,8 +1580,6 @@ if(order.isNewCreate())
.mapToInt(g -> g.getFlowTime())
.sum();
machineUtilization.put(machine.getId(), busyTime / sumWork);
}
......@@ -1592,6 +1587,11 @@ if(order.isNewCreate())
.mapToDouble(Double::doubleValue)
.sum()/ chromosome.getMachines().size();
// 如果平均利用率为0,返回0
if (avgUtilization == 0) {
return 0;
}
double variance = machineUtilization.values().stream()
.mapToDouble(u -> Math.pow(u - avgUtilization, 2))
.sum() / chromosome.getMachines().size();
......
......@@ -3,6 +3,7 @@ package com.aps.service;
import com.aps.common.util.R;
import com.aps.entity.*;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
......@@ -67,4 +68,20 @@ public interface LanuchService {
*/
R<String> savePlan(String sceneId);
/**
* 插单功能:向现有场景添加新订单
* orderId 会在方法内部自动生成 UUID
*
* @param sceneId 场景ID
* @param orderCode 订单编码
* @param materialId 物料ID
* @param startDate 开始时间
* @param endDate 结束时间
* @param priority 优先级
* @param quantity 数量
* @return 结果
*/
R<String> insertOrder(String sceneId, String orderCode, String materialId,
LocalDateTime startDate, LocalDateTime endDate, Integer priority, Double quantity);
}
\ No newline at end of file
......@@ -1169,6 +1169,13 @@ public class ChromosomeDataService {
config.setEntityName(entityName);
config.setDataSource(DataSourceType.FILE);
config.setFieldName("Machines");
}
// 特殊处理:当实体是Order时,映射到orders字段
else if ("order".equalsIgnoreCase(key)) {
config = new EntityConfig();
config.setEntityName(entityName);
config.setDataSource(DataSourceType.FILE);
config.setFieldName("orders");
} else {
// 自动创建数据库配置(默认行为)
config = createDefaultDbConfig(entityName);
......
......@@ -64,6 +64,8 @@ public class LanuchServiceImpl implements LanuchService {
private final PlanResourceService planResourceService;
private final OrderMaterialRequirementService orderMaterialRequirementService;
private final EquipinfoService equipinfoService;
private final MaterialInfoService materialInfoService;
private final RoutingHeaderService routingHeaderService;
/**
* 生成场景数据
*
......@@ -243,52 +245,151 @@ public class LanuchServiceImpl implements LanuchService {
mesOrder.setTaskType(prodLaunchOrder.getFinishOrderId() != null ? "半成品" : "成品");
mesOrderList.add(mesOrder);
}
mesOrderService.remove(new LambdaQueryWrapper<>());
boolean saved = mesOrderService.saveBatch(mesOrderList);
// 更新或插入 mes_order 数据
List<String> orderIds = prodLanuchList.stream().map(Order::getOrderId).distinct().collect(Collectors.toList());
if (saved) {
log.info("插入 {} 条数据到mes_order", mesOrderList.size());
// 查询已存在的 mes_order 记录
List<MesOrder> existingMesOrders = mesOrderService.lambdaQuery()
.in(MesOrder::getMesCode, orderIds)
.list();
Map<String, MesOrder> existingMesOrderMap = existingMesOrders.stream()
.collect(Collectors.toMap(MesOrder::getMesCode, order -> order));
List<MesOrder> toUpdate = new ArrayList<>();
List<MesOrder> toInsert = new ArrayList<>();
for (Order prodLaunchOrder : prodLanuchList) {
MesOrder existingOrder = existingMesOrderMap.get(prodLaunchOrder.getOrderId());
MesOrder mesOrder;
if (existingOrder != null) {
// 更新现有记录
mesOrder = existingOrder;
mesOrder.setLastModifierUserId(Long.valueOf(sceneConfig.getCreateUser()));
mesOrder.setLastModificationTime(LocalDateTime.now());
toUpdate.add(mesOrder);
} else {
log.error("插入失败");
throw new RuntimeException("插入mes_order失败");
// 创建新记录
mesOrder = new MesOrder();
mesOrder.setCreatorUserId(Long.valueOf(sceneConfig.getCreateUser()));
mesOrder.setCreationTime(LocalDateTime.now());
toInsert.add(mesOrder);
}
// 设置部门信息(使用upId字段存储部门ID)
Integer departmentId = orderDepartmentMap.get(prodLaunchOrder.getOrderId());
if (departmentId != null) {
mesOrder.setUpId(Long.valueOf(departmentId));
}
mesOrder.setMesCode(prodLaunchOrder.getOrderId());
mesOrder.setMaterialId(prodLaunchOrder.getMaterialId());
mesOrder.setQuantity(prodLaunchOrder.getQuantity());
mesOrder.setRoutingId(Long.valueOf(prodLaunchOrder.getRoutingId()));
mesOrder.setDemandStartDate(prodLaunchOrder.getStartDate());
mesOrder.setDemandFinishDate(prodLaunchOrder.getDueDate());
mesOrder.setDrawnNumber(prodLaunchOrder.getMaterialCode());
mesOrder.setOrderCode(prodLaunchOrder.getOrderCode());
mesOrder.setStatus(12L);
mesOrder.setIsDeleted(0L);
mesOrder.setTaskType(prodLaunchOrder.getFinishOrderId() != null ? "半成品" : "成品");
}
// 批量更新和插入
boolean updateSuccess = true;
boolean insertSuccess = true;
if (!toUpdate.isEmpty()) {
updateSuccess = mesOrderService.updateBatchById(toUpdate);
log.info("更新 {} 条 mes_order 记录", toUpdate.size());
}
if (!toInsert.isEmpty()) {
insertSuccess = mesOrderService.saveBatch(toInsert);
log.info("插入 {} 条 mes_order 记录", toInsert.size());
}
if (!updateSuccess || !insertSuccess) {
log.error("mes_order 操作失败");
throw new RuntimeException("mes_order 操作失败");
}
// 构建 orderId -> mes_order.id 映射,供 dispatch 的 PART_TASK_READY_ID 使用
List<String> orderIds = prodLanuchList.stream().map(Order::getOrderId).distinct().collect(Collectors.toList());
List<MesOrder> savedMesOrders = mesOrderService.lambdaQuery()
List<MesOrder> allMesOrders = mesOrderService.lambdaQuery()
.in(MesOrder::getMesCode, orderIds)
.list();
Map<String, Long> mesOrderIdByOrderId = savedMesOrders.stream()
Map<String, Long> mesOrderIdByOrderId = allMesOrders.stream()
.collect(Collectors.toMap(MesOrder::getMesCode, MesOrder::getId, (a, b) -> a));
// List<ProdProcessExec> processExecList = prodProcessExecService.lambdaQuery()
// .eq(ProdProcessExec::getSceneId, sceneId)
// .list();
List<Entry> entrys= chromosome.getAllOperations();
// 查询当前场景已存在的 dispatch 记录
List<Dispatch> existingDispatches = dispatchService.lambdaQuery()
.eq(Dispatch::getSceneId, sceneId)
.eq(Dispatch::getIsDeleted, 0L)
.list();
// 构建现有记录的映射 (executeId + routingDetailId 作为唯一标识)
Map<String, Dispatch> existingDispatchMap = existingDispatches.stream()
.collect(Collectors.toMap(
dispatch -> dispatch.getExecuteId() + "_" + dispatch.getRoutingDetailId(),
dispatch -> dispatch,
(existing, replacement) -> existing
));
List<Dispatch> toUpdateDispatches = new ArrayList<>();
List<Dispatch> toInsertDispatches = new ArrayList<>();
// 遍历GAScheduleResult结果并转换为dispatch
List<Dispatch> dispatches = new ArrayList<>();
for (GAScheduleResult gaResult : chromosome.getResult()) {
Entry entry1 = entrys.stream()
.filter(entry -> entry.getExecId().equals(gaResult.getExecId()))
.findFirst()
.orElse(null);
Dispatch dispatch = new Dispatch();
if (entry1 == null) {
log.warn("未找到对应的Entry,ExecId: {}", gaResult.getExecId());
continue;
}
String dispatchKey = entry1.getId() + "_" + entry1.getRoutingDetailId();
Dispatch existingDispatch = existingDispatchMap.get(dispatchKey);
Dispatch dispatch;
if (existingDispatch != null) {
// 更新现有记录
dispatch = existingDispatch;
dispatch.setLastModifierUserId(Long.parseLong(sceneConfig.getCreateUser()));
dispatch.setLastModificationTime(LocalDateTime.now());
toUpdateDispatches.add(dispatch);
} else {
// 创建新记录
dispatch = new Dispatch();
dispatch.setCreatorUserId(Long.parseLong(sceneConfig.getCreateUser()));
dispatch.setCreationTime(LocalDateTime.now());
dispatch.setExecuteId((long) entry1.getId());
dispatch.setRoutingDetailId(entry1.getRoutingDetailId());
toInsertDispatches.add(dispatch);
}
// 更新相关字段
dispatch.setENof(gaResult.getOrderId());
dispatch.setQuantity(gaResult.getQuantity());
// 设置场景ID
dispatch.setSceneId(sceneId);
// 设置设备ID(从排产结果中获取)
dispatch.setEquipId(gaResult.getMachineId());
LocalDateTime baseTime = chromosome.getBaseTime() != null ? chromosome.getBaseTime() : LocalDateTime.now();
dispatch.setBeginTime(baseTime.plusSeconds(gaResult.getStartTime()));
dispatch.setEndTime(baseTime.plusSeconds(gaResult.getEndTime()));
dispatch.setENof(gaResult.getOrderId());
dispatch.setCreatorUserId(Long.parseLong(sceneConfig.getCreateUser()));
// 设置状态等其他字段
dispatch.setTaskSeq(entry1.getTaskSeq());
dispatch.setMesCode(gaResult.getOrderId());
dispatch.setRoutingDetailId(entry1.getRoutingDetailId());
dispatch.setOpe(entry1.getRoutingDetailName());
dispatch.setRoutingDetailId(entry1.getRoutingDetailId());
dispatch.setIsDeleted(0L);
dispatch.setStatus(12L);
// PART_TASK_READY_ID:取对应 mes_order 的主键 id(按 orderId/mesCode 关联)
......@@ -297,15 +398,23 @@ public class LanuchServiceImpl implements LanuchService {
dispatch.setPartTaskReadyId(partTaskReadyId);
}
dispatch.setShopid(entry1.getDepartmentId());
}
// 添加到列表中
dispatches.add(dispatch);
// 批量更新和插入 dispatch
boolean updateDispatchSuccess = true;
boolean insertDispatchSuccess = true;
if (!toUpdateDispatches.isEmpty()) {
updateDispatchSuccess = dispatchService.updateBatchById(toUpdateDispatches);
log.info("更新 {} 条 dispatch 记录", toUpdateDispatches.size());
}
dispatchService.remove(new LambdaQueryWrapper<>());
// 批量保存到数据库
if (!toInsertDispatches.isEmpty()) {
insertDispatchSuccess = dispatchService.saveBatch(toInsertDispatches);
log.info("插入 {} 条 dispatch 记录", toInsertDispatches.size());
}
boolean savedDispatch = dispatchService.saveOrUpdateBatch(dispatches);
boolean savedDispatch = updateDispatchSuccess && insertDispatchSuccess;
// 构建ExecId到GAScheduleResult的映射,用于获取工序开始时间
Map<String, GAScheduleResult> execIdToScheduleMap = new HashMap<>();
......@@ -333,7 +442,7 @@ public class LanuchServiceImpl implements LanuchService {
if (operationStartTime != null) {
omr.setShortageTime(operationStartTime);
}
if (omr.getQuantity() >0) {
if (omr.getQuantity() > 0) {
orderMaterials.add(omr);
}
}
......@@ -341,13 +450,12 @@ public class LanuchServiceImpl implements LanuchService {
}
}
// 先删除表中所有数据
orderMaterialRequirementService.remove(new LambdaQueryWrapper<>());
// 再批量插入新数据
orderMaterialRequirementService.saveBatch(orderMaterials);
System.out.println("保存物料需求成功");
log.info("保存物料需求成功");
if (savedDispatch) {
// 清理历史版本的排产结果文件,只留下当前版本
boolean cleanupSuccess = sceneService.cleanupHistoricalVersions(sceneId);
......@@ -1510,4 +1618,103 @@ public class LanuchServiceImpl implements LanuchService {
throw e;
}
}
/**
* 插单功能:向现有场景添加新订单
*
* @param sceneId 场景ID
* @param orderCode 订单编码
* @param materialId 物料ID
* @param startDate 开始时间
* @param endDate 结束时间
* @param priority 优先级
* @param quantity 数量
* @return 结果
*/
@Override
@Transactional(rollbackFor = Exception.class)
public R<String> insertOrder(String sceneId, String orderCode, String materialId,
LocalDateTime startDate, LocalDateTime endDate,
Integer priority, Double quantity) {
// 1. 参数校验
if (sceneId == null || sceneId.trim().isEmpty()) {
throw new IllegalArgumentException("场景ID不能为空");
}
if (orderCode == null || orderCode.trim().isEmpty()) {
throw new IllegalArgumentException("订单编码不能为空");
}
if (materialId == null || materialId.trim().isEmpty()) {
throw new IllegalArgumentException("物料ID不能为空");
}
if (quantity == null || quantity <= 0) {
throw new IllegalArgumentException("数量必须大于0");
}
// 2. 检查场景是否存在
ProdSceneConfig sceneConfig = prodSceneConfigService.lambdaQuery()
.eq(ProdSceneConfig::getSceneId, sceneId)
.one();
if (sceneConfig == null) {
throw new RuntimeException("场景不存在");
}
// 3. 根据物料ID查询物料信息(使用 MaterialInfo 表)
MaterialInfo material = materialInfoService.lambdaQuery()
.eq(MaterialInfo::getId, materialId)
.eq(MaterialInfo::getIsdeleted, 0)
.one();
if (material == null) {
throw new RuntimeException("物料不存在");
}
// 4. 查询工艺路线(按创建时间倒序,获取最新的)
RoutingHeader routingHeader = routingHeaderService.lambdaQuery()
.eq(RoutingHeader::getMaterialId, materialId)
.eq(RoutingHeader::getIsDeleted, 0)
.orderByDesc(RoutingHeader::getCreationTime)
.last("FETCH FIRST 1 ROWS ONLY")
.one();
if (routingHeader == null) {
throw new RuntimeException("物料没有配置工艺路线");
}
log.info("查询到物料 {} 的最新工艺路线: ID={}, Code={}, Version={}, CreationTime={}",
materialId, routingHeader.getId(), routingHeader.getCode(),
routingHeader.getVersion(), routingHeader.getCreationTime());
// 5. 生成订单ID(UUID格式)
String orderId = java.util.UUID.randomUUID().toString();
// 6. 创建 ProdLaunchOrder
ProdLaunchOrder launchOrder = new ProdLaunchOrder();
launchOrder.setOrderId(orderId);
launchOrder.setSceneId(sceneId);
launchOrder.setOrderCode(orderCode);
launchOrder.setMaterialId(materialId);
launchOrder.setMaterialCode(material.getCode());
launchOrder.setMaterialName(material.getName());
launchOrder.setStartDate(startDate);
launchOrder.setEndDate(endDate);
launchOrder.setOrderPriority(priority != null ? priority : 1);
launchOrder.setQuantity(quantity);
launchOrder.setRoutingId(routingHeader.getId());
launchOrder.setRoutingCode(routingHeader.getCode());
launchOrder.setCreateUser(sceneConfig.getCreateUser());
launchOrder.setOrderStatus("S"); // S未启动
// 7. 保存到 PROD_LAUNCH_ORDER 表
prodLaunchOrderService.save(launchOrder);
log.info("成功创建插单订单,订单ID: {}, 订单编码: {}", orderId, orderCode);
// 8. 转换工单于工序执行表(参考 launchPlan 方法)
List<ProdLaunchOrder> orderList = new ArrayList<>();
orderList.add(launchOrder);
convertToProcessExecBatch(orderList, sceneId);
// 9. 生成工序关联关系(参考 launchPlan 方法)
generateProcessRelationsBatch(orderList, sceneId);
log.info("插单成功,场景ID: {}, 订单编码: {}", sceneId, orderCode);
return R.ok("插单成功,订单ID: " + orderId);
}
}
package com.aps.service.plan;
import com.aps.common.util.redis.RedisUtils;
import com.aps.entity.Algorithm.Chromosome;
import com.aps.entity.Algorithm.GAScheduleResult;
import com.aps.entity.Algorithm.ScheduleResultDetail;
import com.aps.entity.ApsTimeConfig;
import com.aps.entity.Dispatch;
import com.aps.entity.MesShiftWorkSched;
import com.aps.entity.PlanResource;
import com.aps.entity.Schedule.SceneChromsome;
import com.aps.entity.basic.*;
import com.aps.service.ApsTimeConfigService;
import com.aps.service.DispatchService;
import com.aps.service.MesShiftWorkSchedService;
import com.aps.service.PlanResourceService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.File;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
/**
* 锁定期工单处理服务
* 负责处理锁定期工单的加载、复制和添加到排产结果中
*/
@Slf4j
@Service
public class LockedOrderProcessorService {
@Autowired
private ApsTimeConfigService apsTimeConfigService;
@Autowired
private DispatchService dispatchService;
@Autowired
private SceneService sceneService;
@Autowired
private PlanResourceService planResourceService;
@Autowired
private MesShiftWorkSchedService mesShiftWorkSchedService;
@Autowired
private RedisUtils redisUtils;
/**
* 添加锁定期工单到调度结果中
* 从上一次排产结果中获取冻结期内的工单,保持时间、数量、设备、Entry等信息不变
*
* @param chromosome 染色体对象
*/
public void addLockedOrdersToResult(Chromosome chromosome) {
try {
// 1. 获取锁定期配置
LockPeriodConfig config = getLockPeriodConfig();
if (config == null) {
return;
}
log.info("锁定期范围: {} 到 {} (冻结期: {}秒)", config.lockStartTime, config.lockEndTime, config.freezeSeconds);
// 2. 从已下发场景获取锁定期工单
LockedOrdersData lockedData = loadLockedOrdersFromScenes(config, chromosome.getBaseTime());
// 3. 如果无法从已下发场景获取,则从Dispatch表创建
if (lockedData.results.isEmpty()) {
lockedData = createLockedOrdersFromDispatch(config, chromosome.getBaseTime());
}
// 4. 添加锁定期工单到chromosome
addLockedOrdersToChromosome(chromosome, lockedData, config);
} catch (Exception e) {
log.error("添加锁定期工单时发生错误: {}", e.getMessage(), e);
}
}
/**
* 获取锁定期配置
*/
private LockPeriodConfig getLockPeriodConfig() {
ApsTimeConfig timeConfig = apsTimeConfigService.getOne(new LambdaQueryWrapper<>());
if (timeConfig == null || timeConfig.getBaseTime() == null) {
log.warn("未找到ApsTimeConfig配置或baseTime为空,无法添加锁定期工单");
return null;
}
LocalDateTime baseTime = timeConfig.getBaseTime();
long freezeSeconds = timeConfig.getFreezeDate() != null ? timeConfig.getFreezeDate().longValue() : 0;
if (freezeSeconds <= 0) {
log.info("冻结期秒数为{},跳过添加锁定期工单", freezeSeconds);
return null;
}
LockPeriodConfig config = new LockPeriodConfig();
config.baseTime = baseTime;
config.freezeSeconds = freezeSeconds;
config.lockStartTime = baseTime;
config.lockEndTime = baseTime.plusSeconds(freezeSeconds);
return config;
}
/**
* 从已下发场景加载锁定期工单
*/
private LockedOrdersData loadLockedOrdersFromScenes(LockPeriodConfig config, LocalDateTime newBaseTime) {
LockedOrdersData data = new LockedOrdersData();
try {
// 查询锁定期内的Dispatch记录
List<Dispatch> frozenDispatches = queryFrozenDispatches(config);
if (frozenDispatches.isEmpty()) {
log.info("冻结期内没有工单需要添加");
return data;
}
log.info("查询到冻结期内的工序数: {}", frozenDispatches.size());
// 获取所有不同的sceneId
Set<String> dispatchSceneIds = frozenDispatches.stream()
.map(Dispatch::getSceneId)
.filter(id -> id != null && !id.isEmpty())
.collect(Collectors.toSet());
if (dispatchSceneIds.isEmpty()) {
log.warn("Dispatch表中的工单没有sceneId信息");
return data;
}
log.info("锁定期工单来自 {} 个已下发场景: {}", dispatchSceneIds.size(), dispatchSceneIds);
// 遍历每个场景,加载锁定期工单
for (String sceneId : dispatchSceneIds) {
processSceneForLockedOrders(sceneId, frozenDispatches, config, newBaseTime, data);
}
log.info("从 {} 个已下发场景排产结果中获取到 {} 个锁定期工单", dispatchSceneIds.size(), data.results.size());
} catch (Exception ex) {
log.error("从已下发场景排产结果获取锁定期工单失败: {}", ex.getMessage(), ex);
}
return data;
}
/**
* 处理单个场景的锁定期工单
*/
private void processSceneForLockedOrders(String sceneId, List<Dispatch> allDispatches,
LockPeriodConfig config, LocalDateTime newBaseTime,
LockedOrdersData data) {
try {
log.info("处理场景: {}", sceneId);
// 加载场景的排产结果
Chromosome dispatchChromosome = loadSceneChromosome(sceneId);
if (dispatchChromosome == null || dispatchChromosome.getResult() == null) {
return;
}
LocalDateTime dispatchBaseTime = dispatchChromosome.getBaseTime();
if (dispatchBaseTime == null) {
log.warn("场景 {} 的baseTime为空,无法计算时间偏移", sceneId);
return;
}
log.info("场景 {} - 已下发场景baseTime: {}, 新场景baseTime: {}", sceneId, dispatchBaseTime, newBaseTime);
// 筛选属于当前场景的Dispatch记录
List<Dispatch> currentSceneDispatches = allDispatches.stream()
.filter(d -> sceneId.equals(d.getSceneId()))
.collect(Collectors.toList());
// 找出锁定期内的订单ID
Set<String> lockedOrderIds = findLockedOrderIds(dispatchChromosome, currentSceneDispatches,
config, dispatchBaseTime, sceneId);
log.info("场景 {} 中发现 {} 个订单在锁定期内有工序: {}", sceneId, lockedOrderIds.size(), lockedOrderIds);
// 复制锁定期订单的所有工序
copyLockedOrders(dispatchChromosome, currentSceneDispatches, lockedOrderIds,
dispatchBaseTime, newBaseTime, sceneId, data, config);
// 匹配Entry信息
matchLockedEntries(dispatchChromosome, data, sceneId);
} catch (Exception ex) {
log.error("处理场景 {} 的排产结果失败: {}", sceneId, ex.getMessage(), ex);
}
}
/**
* 找出锁定期内的订单ID
*/
private Set<String> findLockedOrderIds(Chromosome chromosome, List<Dispatch> dispatches,
LockPeriodConfig config, LocalDateTime baseTime, String sceneId) {
Set<String> lockedOrderIds = new HashSet<>();
log.info("场景 {} 开始分析工序时间,锁定期范围: {} 到 {}", sceneId, config.lockStartTime, config.lockEndTime);
for (GAScheduleResult result : chromosome.getResult()) {
LocalDateTime startTime = baseTime.plusSeconds(result.getStartTime());
log.debug("分析工序: ExecId={}, OrderId={}, 原始StartTime={}秒, 绝对开始时间={}",
result.getExecId(), result.getOrderId(), result.getStartTime(), startTime);
// 检查工序是否在锁定期内
if (!startTime.isBefore(config.lockStartTime) && !startTime.isAfter(config.lockEndTime)) {
log.info("工序在锁定期内: ExecId={}, OrderId={}, 开始时间={}",
result.getExecId(), result.getOrderId(), startTime);
// 通过订单号匹配Dispatch记录
boolean hasValidDispatch = dispatches.stream()
.anyMatch(d -> d.getMesCode() != null &&
d.getMesCode().equals(result.getOrderId()) &&
d.getBeginTime() != null &&
!d.getBeginTime().isBefore(config.lockStartTime) &&
!d.getBeginTime().isAfter(config.lockEndTime));
if (hasValidDispatch && result.getOrderId() != null) {
lockedOrderIds.add(result.getOrderId());
log.info("订单 {} 被标记为锁定期订单(通过订单号匹配)", result.getOrderId());
} else {
log.warn("工序 {} 在锁定期内但没有有效的Dispatch记录(订单号: {})",
result.getExecId(), result.getOrderId());
}
}
}
return lockedOrderIds;
}
/**
* 复制锁定期订单的所有工序
*/
private void copyLockedOrders(Chromosome chromosome, List<Dispatch> dispatches,
Set<String> lockedOrderIds, LocalDateTime oldBaseTime,
LocalDateTime newBaseTime, String sceneId, LockedOrdersData data,
LockPeriodConfig config) {
for (GAScheduleResult result : chromosome.getResult()) {
if (!lockedOrderIds.contains(result.getOrderId())) {
continue;
}
// 检查是否有对应的Dispatch记录
boolean hasDispatch = dispatches.stream()
.anyMatch(d -> d.getMesCode() != null && d.getMesCode().equals(result.getOrderId()));
if (!hasDispatch) {
log.warn("订单 {} 的工序 {} 没有对应的Dispatch记录", result.getOrderId(), result.getExecId());
continue;
}
// 深拷贝工单并转换时间
GAScheduleResult lockedResult = copyGAScheduleResult(result);
lockedResult.setIsLocked(true);
// 转换时间:从旧baseTime转换到新baseTime
LocalDateTime prevStartTime = oldBaseTime.plusSeconds(result.getStartTime());
LocalDateTime prevEndTime = oldBaseTime.plusSeconds(result.getEndTime());
int newStartTime = (int) java.time.temporal.ChronoUnit.SECONDS.between(newBaseTime, prevStartTime);
int newEndTime = (int) java.time.temporal.ChronoUnit.SECONDS.between(newBaseTime, prevEndTime);
lockedResult.setStartTime(newStartTime);
lockedResult.setEndTime(newEndTime);
data.results.add(lockedResult);
data.machineIds.add(result.getMachineId());
boolean isInLockPeriod = !prevStartTime.isBefore(config.lockStartTime) &&
!prevStartTime.isAfter(config.lockEndTime);
log.info("从场景 {} 获取订单 {} 的工序: ExecId={}, OrderCode={}, MachineId={}, 原始时间=[{} 到 {}], 新相对时间=[{} 到 {}]秒, 是否在锁定期内={}",
sceneId, result.getOrderId(), lockedResult.getExecId(), lockedResult.getOrderCode(),
lockedResult.getMachineId(), prevStartTime, prevEndTime, newStartTime, newEndTime, isInLockPeriod);
}
}
/**
* 匹配锁定期工单的Entry信息
*/
private void matchLockedEntries(Chromosome chromosome, LockedOrdersData data, String sceneId) {
if (chromosome.getAllOperations() == null) {
return;
}
log.info("场景 {} 中有 {} 个Entry,开始匹配锁定期工单的Entry信息",
sceneId, chromosome.getAllOperations().size());
for (GAScheduleResult result : data.results) {
log.debug("处理锁定期工单: ExecId={}, OperationId={}", result.getExecId(), result.getOperationId());
Entry entry = null;
if (result.getOperationId() > 0) {
entry = chromosome.getAllOperations().stream()
.filter(e -> e.getId() == result.getOperationId())
.findFirst()
.orElse(null);
}
// 如果通过OperationId找不到,尝试通过ExecId匹配
if (entry == null) {
entry = chromosome.getAllOperations().stream()
.filter(e -> e.getExecId().equals(result.getExecId()))
.findFirst()
.orElse(null);
if (entry != null) {
result.setOperationId(entry.getId());
log.info("通过ExecId匹配到Entry并修正OperationId: ExecId={}, EntryId={}",
result.getExecId(), entry.getId());
}
}
if (entry != null) {
data.entries.put(result.getExecId(), entry);
} else {
log.warn("未找到工序 {} 对应的Entry", result.getExecId());
}
}
log.info("场景 {} 成功匹配 {} 个Entry信息", sceneId, data.entries.size());
}
/**
* 从Dispatch表创建锁定期工单
*/
private LockedOrdersData createLockedOrdersFromDispatch(LockPeriodConfig config, LocalDateTime baseTime) {
LockedOrdersData data = new LockedOrdersData();
log.info("从Dispatch表查询锁定期工单");
List<Dispatch> frozenDispatches = queryFrozenDispatches(config);
if (frozenDispatches.isEmpty()) {
log.info("冻结期内没有工单需要添加");
return data;
}
log.info("查询到冻结期内的工序数: {}", frozenDispatches.size());
for (Dispatch dispatch : frozenDispatches) {
GAScheduleResult result = createResultFromDispatch(dispatch, baseTime);
data.results.add(result);
data.machineIds.add(result.getMachineId());
}
return data;
}
/**
* 从Dispatch记录创建GAScheduleResult
*/
private GAScheduleResult createResultFromDispatch(Dispatch dispatch, LocalDateTime baseTime) {
GAScheduleResult result = new GAScheduleResult();
log.info("处理Dispatch记录: id={}, executeId={}, mesCode={}, equipId={}, beginTime={}, endTime={}",
dispatch.getId(), dispatch.getExecuteId(), dispatch.getMesCode(),
dispatch.getEquipId(), dispatch.getBeginTime(), dispatch.getEndTime());
// 设置基本信息
result.setOperationId(dispatch.getExecuteId() != null ? dispatch.getExecuteId().intValue() : 0);
result.setExecId(dispatch.getExecuteId() != null ? dispatch.getExecuteId().toString() : "");
result.setOrderId(dispatch.getMesCode() != null ? dispatch.getMesCode() : "");
result.setOrderCode(dispatch.getMesCode());
result.setMachineId(dispatch.getEquipId() != null ? dispatch.getEquipId() : 0L);
result.setQuantity(dispatch.getQuantity() != null ? dispatch.getQuantity() : 0.0);
result.setProductId("");
result.setProductName("");
result.setProductCode("");
log.info("从Dispatch创建锁定期工单: executeId={}, OperationId={}, mesCode={}",
dispatch.getExecuteId(), result.getOperationId(), dispatch.getMesCode());
// 计算相对时间
if (dispatch.getBeginTime() != null && dispatch.getEndTime() != null) {
int startTime = (int) java.time.temporal.ChronoUnit.SECONDS.between(baseTime, dispatch.getBeginTime());
int endTime = (int) java.time.temporal.ChronoUnit.SECONDS.between(baseTime, dispatch.getEndTime());
log.info("锁定期工单时间计算: ExecId={}, Dispatch时间=[{} 到 {}], baseTime={}, 相对时间=[{} 到 {}]秒",
dispatch.getExecuteId(), dispatch.getBeginTime(), dispatch.getEndTime(),
baseTime, startTime, endTime);
result.setStartTime(startTime);
result.setEndTime(endTime);
result.setProcessingTime((double) (endTime - startTime) / 60.0);
}
// 设置其他信息
result.setIsLocked(true);
result.setTeardownTime(0);
result.setChangeOverTime(0);
result.setPreTime(0);
result.setSeq(dispatch.getTaskSeq() != null ? dispatch.getTaskSeq().intValue() : 0);
result.setBomTime(0);
result.setDesignatedStartTime(-1);
result.setLockStartTime(0);
result.setForcedMachineId(-1L);
// 创建GeneDetails
List<ScheduleResultDetail> geneDetails = new ArrayList<>();
ScheduleResultDetail detail = new ScheduleResultDetail();
detail.setStartTime(result.getStartTime());
detail.setEndTime(result.getEndTime());
detail.setQuantity(dispatch.getQuantity() != null ? dispatch.getQuantity() : 0.0);
geneDetails.add(detail);
result.setGeneDetails(geneDetails);
return result;
}
/**
* 将锁定期工单添加到chromosome
*/
private void addLockedOrdersToChromosome(Chromosome chromosome, LockedOrdersData data, LockPeriodConfig config) {
// 1. 添加到result列表
if (chromosome.getResult() == null) {
chromosome.setResult(new CopyOnWriteArrayList<>());
}
int beforeSize = chromosome.getResult().size();
chromosome.getResult().addAll(data.results);
log.info("成功添加 {} 个锁定期工单到调度结果中,result大小从{}变为{}",
data.results.size(), beforeSize, chromosome.getResult().size());
// 2. 复制锁定期订单的Order对象
copyLockedOrderObjects(chromosome, data, config);
// 3. 添加Entry到allOperations
if (!data.entries.isEmpty() && chromosome.getAllOperations() != null) {
int beforeEntrySize = chromosome.getAllOperations().size();
chromosome.getAllOperations().addAll(data.entries.values());
log.info("成功添加 {} 个锁定期Entry到allOperations中,大小从{}变为{}",
data.entries.size(), beforeEntrySize, chromosome.getAllOperations().size());
}
// 4. 确保锁定期设备存在
ensureLockedMachines(chromosome, data.machineIds, config);
}
/**
* 复制锁定期订单的Order对象
*/
private void copyLockedOrderObjects(Chromosome chromosome, LockedOrdersData data, LockPeriodConfig config) {
if (data.results.isEmpty()) {
return;
}
if (chromosome.getOrders() == null) {
chromosome.setOrders(new CopyOnWriteArrayList<>());
}
int beforeOrderSize = chromosome.getOrders().size();
// 收集锁定期订单ID
Set<String> lockedOrderIds = data.results.stream()
.map(GAScheduleResult::getOrderId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
log.info("需要复制的锁定期订单ID: {}", lockedOrderIds);
try {
// 查询锁定期Dispatch记录
List<Dispatch> frozenDispatches = queryFrozenDispatches(config);
log.info("查询到 {} 个锁定期Dispatch记录", frozenDispatches.size());
Set<String> dispatchSceneIds = frozenDispatches.stream()
.map(Dispatch::getSceneId)
.filter(id -> id != null && !id.isEmpty())
.collect(Collectors.toSet());
log.info("锁定期Dispatch记录来自 {} 个场景: {}", dispatchSceneIds.size(), dispatchSceneIds);
// 从每个场景复制订单
for (String sceneId : dispatchSceneIds) {
copyOrdersFromScene(chromosome, sceneId, lockedOrderIds);
}
} catch (Exception e) {
log.error("复制锁定期订单失败: {}", e.getMessage(), e);
}
log.info("成功复制锁定期订单到Orders列表,大小从{}变为{}", beforeOrderSize, chromosome.getOrders().size());
}
/**
* 从指定场景复制订单
*/
private void copyOrdersFromScene(Chromosome chromosome, String sceneId, Set<String> lockedOrderIds) {
try {
log.info("开始从场景 {} 加载Chromosome", sceneId);
Chromosome dispatchChromosome = sceneService.loadChromosomeFromFile(sceneId);
if (dispatchChromosome == null) {
log.warn("场景 {} 加载失败,Chromosome为null", sceneId);
return;
}
log.info("场景 {} 加载成功,Orders数量: {}", sceneId,
dispatchChromosome.getOrders() != null ? dispatchChromosome.getOrders().size() : 0);
if (dispatchChromosome.getOrders() == null) {
log.warn("场景 {} 的Orders为null", sceneId);
return;
}
// 筛选锁定期订单
List<Order> lockedOrders = dispatchChromosome.getOrders().stream()
.filter(order -> lockedOrderIds.contains(order.getOrderId()))
.collect(Collectors.toList());
log.info("场景 {} 中找到 {} 个匹配的锁定期订单", sceneId, lockedOrders.size());
// 复制订单(避免重复)
for (Order lockedOrder : lockedOrders) {
boolean exists = chromosome.getOrders().stream()
.anyMatch(order -> lockedOrder.getOrderId().equals(order.getOrderId()));
if (!exists) {
chromosome.getOrders().add(lockedOrder);
log.info("从场景 {} 复制锁定期订单: OrderId={}, OrderCode={}",
sceneId, lockedOrder.getOrderId(), lockedOrder.getOrderCode());
} else {
log.warn("订单 {} 已存在,跳过复制", lockedOrder.getOrderId());
}
}
} catch (Exception ex) {
log.error("从场景 {} 复制锁定期订单失败: {}", sceneId, ex.getMessage(), ex);
}
}
/**
* 确保锁定期设备存在于initMachines中
*/
private void ensureLockedMachines(Chromosome chromosome, Set<Long> lockedMachineIds, LockPeriodConfig config) {
if (chromosome.getInitMachines() == null || lockedMachineIds.isEmpty()) {
return;
}
Set<Long> existingMachineIds = chromosome.getInitMachines().stream()
.map(Machine::getId)
.collect(Collectors.toSet());
Set<Long> missingMachineIds = lockedMachineIds.stream()
.filter(id -> id != null && id > 0 && !existingMachineIds.contains(id))
.collect(Collectors.toSet());
if (missingMachineIds.isEmpty()) {
return;
}
log.info("锁定期工单使用的设备不在本次排产中,需要从已下发场景获取设备信息: {}", missingMachineIds);
try {
List<Dispatch> frozenDispatches = queryFrozenDispatches(config);
Set<String> dispatchSceneIds = frozenDispatches.stream()
.map(Dispatch::getSceneId)
.filter(id -> id != null && !id.isEmpty())
.collect(Collectors.toSet());
// 从各个场景查找设备
for (String sceneId : dispatchSceneIds) {
if (missingMachineIds.isEmpty()) {
break;
}
loadMachinesFromScene(chromosome, sceneId, missingMachineIds);
}
// 如果还有设备没找到,创建默认设备
if (!missingMachineIds.isEmpty()) {
log.warn("在所有已下发场景中都没有找到锁定期设备,将创建默认设备信息: {}", missingMachineIds);
createDefaultMachines(chromosome, missingMachineIds);
}
} catch (Exception ex) {
log.error("从已下发场景排产结果获取设备信息失败: {}", ex.getMessage(), ex);
createDefaultMachines(chromosome, missingMachineIds);
}
}
/**
* 从指定场景加载设备信息
*/
private void loadMachinesFromScene(Chromosome chromosome, String sceneId, Set<Long> missingMachineIds) {
try {
log.info("从场景 {} 获取设备信息", sceneId);
Chromosome dispatchChromosome = loadSceneChromosome(sceneId);
if (dispatchChromosome == null || dispatchChromosome.getInitMachines() == null) {
return;
}
List<Machine> foundMachines = dispatchChromosome.getInitMachines().stream()
.filter(m -> missingMachineIds.contains(m.getId()))
.collect(Collectors.toList());
if (!foundMachines.isEmpty()) {
log.info("从场景 {} 的排产结果中找到 {} 个锁定期设备", sceneId, foundMachines.size());
chromosome.getInitMachines().addAll(foundMachines);
Set<Long> foundIds = foundMachines.stream()
.map(Machine::getId)
.collect(Collectors.toSet());
missingMachineIds.removeAll(foundIds);
}
} catch (Exception ex) {
log.error("从场景 {} 获取设备信息失败: {}", sceneId, ex.getMessage(), ex);
}
}
/**
* 加载场景的Chromosome
*/
private Chromosome loadSceneChromosome(String sceneId) {
try {
SceneChromsome sceneChromsome = (SceneChromsome) redisUtils.get("SceneId." + sceneId);
if (sceneChromsome == null) {
log.warn("未找到场景 {} 的版本信息", sceneId);
return null;
}
int version = sceneChromsome.getVersion();
File file = new File("result", "chromosome_result_" + sceneId + "_" + version + "_.json");
if (!file.exists()) {
log.warn("场景 {} 的排产结果文件不存在: {}", sceneId, file.getAbsolutePath());
return null;
}
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return objectMapper.readValue(file, Chromosome.class);
} catch (Exception ex) {
log.error("加载场景 {} 失败: {}", sceneId, ex.getMessage(), ex);
return null;
}
}
/**
* 查询冻结期内的Dispatch记录
*/
private List<Dispatch> queryFrozenDispatches(LockPeriodConfig config) {
return dispatchService.lambdaQuery()
.ge(Dispatch::getBeginTime, config.lockStartTime)
.le(Dispatch::getBeginTime, config.lockEndTime)
.eq(Dispatch::getIsDeleted, 0L)
.orderBy(true, true, Dispatch::getMesCode, Dispatch::getTaskSeq)
.list();
}
/**
* 为锁定期工单创建默认设备信息
* @param chromosome 染色体对象
* @param machineIds 需要创建的设备ID集合
*/
private void createDefaultMachines(Chromosome chromosome, Set<Long> machineIds) {
try {
// 查询这些设备的信息
List<PlanResource> planResources = planResourceService.lambdaQuery()
.eq(PlanResource::getIsdeleted, 0)
.in(PlanResource::getId, machineIds.stream()
.map(Long::intValue)
.collect(Collectors.toList()))
.list();
// 查询班次信息
List<MesShiftWorkSched> allShiftWorkScheds = mesShiftWorkSchedService.lambdaQuery()
.eq(MesShiftWorkSched::getIsdeleted, 0)
.list();
// 创建Machine对象并添加到initMachines
for (Long machineId : machineIds) {
Machine machine = new Machine();
machine.setId(machineId);
PlanResource planResource = planResources.stream()
.filter(pr -> pr.getId() == machineId.intValue())
.findFirst()
.orElse(null);
if (planResource != null) {
machine.setCode(planResource.getReferenceCode());
machine.setName(planResource.getTitle());
machine.setDepartment(planResource.getDepartTitle());
log.info("为设备 {} 查询班次信息,workSchedId: {}", machineId, planResource.getWorkSchedId());
// 查询设备的真实班次信息
List<MesShiftWorkSched> shiftWorkScheds = allShiftWorkScheds.stream()
.filter(t -> (long) t.getWeekWorkSchedId() == planResource.getWorkSchedId())
.collect(Collectors.toList());
log.info("设备 {} 找到 {} 个班次记录", machineId, shiftWorkScheds.size());
if (!shiftWorkScheds.isEmpty()) {
// 使用真实的班次信息
List<Shift> shifts = mergeShiftData(shiftWorkScheds);
for (Shift shift : shifts) {
shift.setMachineId(machineId);
shift.setSpecial(false);
shift.setStartDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
shift.setEndDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
}
machine.setShifts(shifts);
log.info("为设备 {} 设置真实班次信息,共 {} 个班次", machineId, shifts.size());
} else {
// 如果没有找到班次信息,使用默认24小时班次
machine.setShifts(createDefault24HourShift(machineId));
log.warn("设备 {} 没有找到班次信息,使用默认24小时班次", machineId);
}
} else {
machine.setCode("LOCKED-" + machineId);
machine.setName("锁定期设备-" + machineId);
// 使用默认24小时班次
machine.setShifts(createDefault24HourShift(machineId));
log.warn("设备 {} 没有找到PlanResource信息,使用默认24小时班次", machineId);
}
chromosome.getInitMachines().add(machine);
}
log.info("成功创建 {} 个默认锁定期设备", machineIds.size());
} catch (Exception e) {
log.error("创建默认设备信息失败: {}", e.getMessage(), e);
}
}
/**
* 创建默认的24小时班次
* @param machineId 设备ID
* @return 24小时班次列表
*/
private List<Shift> createDefault24HourShift(Long machineId) {
List<Shift> shifts = new ArrayList<>();
Shift shift = new Shift();
shift.setMachineId(machineId);
shift.setStartTime(LocalTime.of(0, 0, 0));
shift.setEndTime(LocalTime.of(23, 59, 59));
HashSet<Integer> days = new HashSet<>();
for (int i = 0; i <= 6; i++) {
days.add(i);
}
shift.setDays(days);
shift.setSpecial(false);
shift.setStartDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
shift.setEndDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
shifts.add(shift);
return shifts;
}
/**
* 合并班次数据
* @param shiftWorkScheds 班次工作计划列表
* @return 合并后的班次列表
*/
private List<Shift> mergeShiftData(List<MesShiftWorkSched> shiftWorkScheds) {
// 这里需要根据实际的MesShiftWorkSched结构来实现班次合并逻辑
// 暂时返回默认24小时班次,实际项目中需要根据具体需求实现
List<Shift> shifts = new ArrayList<>();
// 按班次分组并合并
Map<String, List<MesShiftWorkSched>> shiftGroups = shiftWorkScheds.stream()
.collect(Collectors.groupingBy(s -> s.getShiftName() != null ? s.getShiftName() : "默认班次"));
for (Map.Entry<String, List<MesShiftWorkSched>> entry : shiftGroups.entrySet()) {
Shift shift = new Shift();
List<MesShiftWorkSched> schedList = entry.getValue();
if (!schedList.isEmpty()) {
MesShiftWorkSched firstSched = schedList.get(0);
// 设置班次时间(需要根据实际字段调整)
if (firstSched.getShiftStart() != null && firstSched.getShiftEnd() != null) {
shift.setStartTime(firstSched.getShiftStart().toLocalTime());
shift.setEndTime(firstSched.getShiftEnd().toLocalTime());
} else {
// 默认24小时
shift.setStartTime(LocalTime.of(0, 0, 0));
shift.setEndTime(LocalTime.of(23, 59, 59));
}
// 设置工作日(需要根据实际字段调整)
HashSet<Integer> days = new HashSet<>();
for (int i = 0; i <= 6; i++) {
days.add(i);
}
shift.setDays(days);
}
shifts.add(shift);
}
return shifts.isEmpty() ? createDefault24HourShift(0L) : shifts;
}
/**
* 深拷贝 GAScheduleResult 对象
*
* @param source 源对象
* @return 拷贝后的新对象
*/
private GAScheduleResult copyGAScheduleResult(GAScheduleResult source) {
if (source == null) {
return null;
}
GAScheduleResult copy = new GAScheduleResult();
// 拷贝基本字段
copy.setGroupId(source.getGroupId());
copy.setOperationId(source.getOperationId());
copy.setExecId(source.getExecId());
copy.setOrderId(source.getOrderId());
copy.setOrderCode(source.getOrderCode());
copy.setProductId(source.getProductId());
copy.setProductName(source.getProductName());
copy.setProductCode(source.getProductCode());
copy.setMachineId(source.getMachineId());
copy.setStartTime(source.getStartTime());
copy.setEndTime(source.getEndTime());
copy.setTeardownTime(source.getTeardownTime());
copy.setQuantity(source.getQuantity());
copy.setDesignatedStartTime(source.getDesignatedStartTime());
copy.setLockStartTime(source.getLockStartTime());
copy.setForcedMachineId(source.getForcedMachineId());
copy.setIsLocked(source.isIsLocked());
copy.setOneTime(source.getOneTime());
copy.setProcessingTime(source.getProcessingTime());
copy.setChangeOverTime(source.getChangeOverTime());
copy.setPreTime(source.getPreTime());
copy.setSeq(source.getSeq());
copy.setBomTime(source.getBomTime());
// 深拷贝 GeneDetails 列表
if (source.getGeneDetails() != null) {
List<ScheduleResultDetail> detailsCopy = new ArrayList<>();
for (ScheduleResultDetail detail : source.getGeneDetails()) {
ScheduleResultDetail detailCopy = new ScheduleResultDetail();
detailCopy.setKey(detail.getKey());
detailCopy.setStartTime(detail.getStartTime());
detailCopy.setEndTime(detail.getEndTime());
detailCopy.setOneTime(detail.getOneTime());
detailCopy.setQuantity(detail.getQuantity());
// 深拷贝 usedSegment
if (detail.getUsedSegment() != null) {
List<com.aps.entity.basic.TimeSegment> segmentsCopy = new ArrayList<>(detail.getUsedSegment());
detailCopy.setUsedSegment(segmentsCopy);
}
detailsCopy.add(detailCopy);
}
copy.setGeneDetails(detailsCopy);
}
// 深拷贝 TargetFinishedOperationId 列表
if (source.getTargetFinishedOperationId() != null) {
copy.setTargetFinishedOperationId(new ArrayList<>(source.getTargetFinishedOperationId()));
}
return copy;
}
/**
* 在排产前标记锁定期工单占用的设备时间段
* 将锁定期工单占用的设备时间段标记为不可用,避免新工单与锁定期工单冲突
*
* @param machines 设备列表
* @param baseTime 基准时间
*/
public void markLockedOrdersOccupiedTime(List<Machine> machines, LocalDateTime baseTime) {
try {
// 1. 获取时间配置
LockPeriodConfig config = getLockPeriodConfig();
if (config == null) {
log.warn("未找到锁定期配置,跳过标记锁定期设备占用");
return;
}
log.info("开始标记锁定期设备占用时间段,锁定期范围: {} 到 {}", config.lockStartTime, config.lockEndTime);
// 2. 从Dispatch表查询锁定期内的工单
List<Dispatch> frozenDispatches = dispatchService.lambdaQuery()
.ge(Dispatch::getBeginTime, config.lockStartTime)
.le(Dispatch::getBeginTime, config.lockEndTime)
.eq(Dispatch::getIsDeleted, 0L)
.isNotNull(Dispatch::getEquipId)
.isNotNull(Dispatch::getBeginTime)
.isNotNull(Dispatch::getEndTime)
.list();
if (frozenDispatches.isEmpty()) {
log.info("没有锁定期工单需要标记设备占用");
return;
}
log.info("查询到 {} 个锁定期工单,开始标记设备占用", frozenDispatches.size());
// 3. 按设备分组
Map<Long, List<Dispatch>> dispatchByMachine = frozenDispatches.stream()
.collect(Collectors.groupingBy(Dispatch::getEquipId));
// 4. 为每个设备标记占用时间段
int markedCount = 0;
for (Map.Entry<Long, List<Dispatch>> entry : dispatchByMachine.entrySet()) {
Long machineId = entry.getKey();
List<Dispatch> dispatches = entry.getValue();
// 查找对应的Machine对象
Machine machine = machines.stream()
.filter(m -> m.getId() == machineId)
.findFirst()
.orElse(null);
if (machine == null) {
log.warn("未找到设备 {},跳过标记", machineId);
continue;
}
// 为该设备的每个锁定期工单创建占用时间段
for (Dispatch dispatch : dispatches) {
LocalDateTime dispatchStart = dispatch.getBeginTime();
LocalDateTime dispatchEnd = dispatch.getEndTime();
// 只标记结束时间在baseTime之后的工单(这些会占用未来的设备时间)
if (dispatchEnd.isAfter(baseTime)) {
// 如果开始时间在baseTime之前,则从baseTime开始标记
LocalDateTime occupyStart = dispatchStart.isBefore(baseTime) ? baseTime : dispatchStart;
LocalDateTime occupyEnd = dispatchEnd;
// 创建一个不可用的时间段
TimeSegment occupiedSegment = new TimeSegment();
occupiedSegment.setStart(occupyStart);
occupiedSegment.setEnd(occupyEnd);
occupiedSegment.setType(SegmentType.MAINTENANCE); // 标记为不可用
occupiedSegment.setUsed(true); // 标记为已占用
occupiedSegment.setHoliday(false);
occupiedSegment.setEfficiency(1.0);
// 添加到设备的可用时间段列表中
if (machine.getAvailability() == null) {
machine.setAvailability(new CopyOnWriteArrayList<>());
}
machine.getAvailability().add(occupiedSegment);
markedCount++;
log.debug("标记设备 {} 的锁定期占用时间段: {} 到 {}, 订单: {}",
machineId, occupyStart, occupyEnd, dispatch.getMesCode());
}
}
}
log.info("成功标记 {} 个锁定期工单的设备占用时间段", markedCount);
} catch (Exception e) {
log.error("标记锁定期设备占用时间段失败: {}", e.getMessage(), e);
}
}
/**
* 锁定期配置类
*/
private static class LockPeriodConfig {
LocalDateTime baseTime;
long freezeSeconds;
LocalDateTime lockStartTime;
LocalDateTime lockEndTime;
}
/**
* 锁定期工单数据类
*/
private static class LockedOrdersData {
List<GAScheduleResult> results = new ArrayList<>();
Map<String, Entry> entries = new HashMap<>();
Set<Long> machineIds = new HashSet<>();
}
}
\ No newline at end of file
......@@ -3,23 +3,24 @@ package com.aps.service.plan;
import com.aps.common.util.*;
import com.aps.common.util.redis.RedisUtils;
import com.aps.controller.gantt.FileUploadController;
import com.aps.entity.*;
import com.aps.entity.Algorithm.*;
import com.aps.entity.Algorithm.IDAndChildID.GroupResult;
import com.aps.entity.Algorithm.IDAndChildID.NodeInfo;
import com.aps.entity.*;
import com.aps.entity.Gantt.ResourceGanttVO;
import com.aps.entity.Gantt.TaskVO;
import com.aps.entity.Schedule.SceneChromsome;
import com.aps.entity.basic.ScheduleChromosome;
import com.aps.entity.Schedule.GenVO;
import com.aps.entity.Schedule.MachineVO;
import com.aps.entity.Schedule.SceneChromsome;
import com.aps.entity.basic.*;
import com.aps.mapper.*;
import com.aps.service.*;
import com.aps.service.Algorithm.*;
import com.aps.service.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
......@@ -35,8 +36,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.Comparator;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
......@@ -124,6 +123,15 @@ public class PlanResultService {
private MaterialRequirementService materialRequirementService;
@Autowired
private EquipMaintainTaskService _equipMaintainTaskService;
@Autowired
private DispatchService dispatchService;
@Autowired
private ApsTimeConfigService apsTimeConfigService;
@Autowired
private LockedOrderProcessorService lockedOrderProcessorService;
private LocalDateTime baseTime = LocalDateTime.of(2025, 11, 1, 0, 0, 0);
public List<ScheduleChromosome> execute() {
......@@ -137,7 +145,6 @@ public class PlanResultService {
public Chromosome execute2(String SceneId) {
try {
ScheduleParams param = InitScheduleParams();
......@@ -208,6 +215,9 @@ public class PlanResultService {
.map(Material::getId)
.distinct()
.collect(Collectors.toList());
ApsTimeConfig timeConfig = apsTimeConfigService.getOne(new LambdaQueryWrapper<>());
// 4.5 在排产前标记锁定期工单占用的设备时间段
// lockedOrderProcessorService.markLockedOrdersOccupiedTime(machines, timeConfig.getBaseTime());
// 5. 执行调度算法
GeneticAlgorithm scheduler =new GeneticAlgorithm(globalParam,machines,orders,Materials1,materialIds,machineScheduler,entryRel,materialRequirementService,_sceneService,SceneId); //new GeneticAlgorithm(products, machines, orders, machineScheduler);
......@@ -219,6 +229,10 @@ public class PlanResultService {
KpiCalculator kpiCalculator=new KpiCalculator(chromosome);
kpiCalculator.calculatekpi();
// 添加锁定期工单到调度结果中
// lockedOrderProcessorService.addLockedOrdersToResult(chromosome);
_sceneService.saveChromosomeToFile(chromosome, SceneId);
WriteScheduleSummary(chromosome);
......@@ -230,6 +244,809 @@ public class PlanResultService {
}
}
// /**
// * 添加锁定期工单到调度结果中
// * 从上一次排产结果中获取冻结期内的工单,保持时间、数量、设备、Entry等信息不变
// * @param chromosome 染色体对象
// */
// private void addLockedOrdersToResult(Chromosome chromosome) {
// try {
// // 1. 获取时间配置
// ApsTimeConfig timeConfig = apsTimeConfigService.getOne(new LambdaQueryWrapper<>());
// if (timeConfig == null || timeConfig.getBaseTime() == null) {
// log.warn("未找到ApsTimeConfig配置或baseTime为空,无法添加锁定期工单");
// return;
// }
//
// LocalDateTime baseTime = timeConfig.getBaseTime();
// long freezeSeconds = timeConfig.getFreezeDate() != null ? timeConfig.getFreezeDate().longValue() : 0;
//
// // 如果freezeSeconds为0,则不添加锁定期工单
// if (freezeSeconds <= 0) {
// log.info("冻结期秒数为{},跳过添加锁定期工单", freezeSeconds);
// return;
// }
//
// // 锁定期计算:baseTime 到 baseTime + freezeSeconds
// LocalDateTime lockStartTime = baseTime;
// LocalDateTime lockEndTime = baseTime.plusSeconds(freezeSeconds);
//
// log.info("锁定期范围: {} 到 {} (冻结期: {}秒)", lockStartTime, lockEndTime, freezeSeconds);
//
// // 2. 尝试从已下发的排产结果中获取锁定期工单
// List<GAScheduleResult> lockedResults = new ArrayList<>();
// Map<String, Entry> lockedEntries = new HashMap<>();
// Set<Long> lockedMachineIds = new HashSet<>();
//
// try {
// // 从Dispatch表查询锁定期内的工单,获取它们的sceneId
// List<Dispatch> frozenDispatches = dispatchService.lambdaQuery()
// .ge(Dispatch::getBeginTime, lockStartTime)
// .le(Dispatch::getBeginTime, lockEndTime)
// .eq(Dispatch::getIsDeleted, 0L)
// .orderBy(true, true, Dispatch::getMesCode, Dispatch::getTaskSeq)
// .list();
//
// if (frozenDispatches.isEmpty()) {
// log.info("冻结期内没有工单需要添加");
// return;
// }
//
// log.info("查询到冻结期内的工序数: {}", frozenDispatches.size());
//
// // 获取这些工单的所有不同sceneId(可能来自多个已下发的场景)
// Set<String> dispatchSceneIds = frozenDispatches.stream()
// .map(Dispatch::getSceneId)
// .filter(id -> id != null && !id.isEmpty())
// .collect(Collectors.toSet());
//
// if (!dispatchSceneIds.isEmpty()) {
// log.info("锁定期工单来自 {} 个已下发场景: {}", dispatchSceneIds.size(), dispatchSceneIds);
//
// // 遍历每个场景,尝试加载排产结果
// for (String dispatchSceneId : dispatchSceneIds) {
// try {
// log.info("处理场景: {}", dispatchSceneId);
//
// // 尝试加载已下发场景的排产结果
// SceneChromsome dispatchSceneChromsome = (SceneChromsome) redisUtils.get("SceneId." + dispatchSceneId);
// if (dispatchSceneChromsome != null) {
// int dispatchVersion = dispatchSceneChromsome.getVersion();
// File dispatchFile = new File("result", "chromosome_result_" + dispatchSceneId + "_" + dispatchVersion + "_.json");
//
// if (dispatchFile.exists()) {
// ObjectMapper objectMapper = new ObjectMapper();
// objectMapper.registerModule(new JavaTimeModule());
// objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//
// Chromosome dispatchChromosome = objectMapper.readValue(dispatchFile, Chromosome.class);
//
// if (dispatchChromosome.getResult() != null) {
// // 获取已下发场景的baseTime
// LocalDateTime dispatchBaseTime = dispatchChromosome.getBaseTime();
// if (dispatchBaseTime == null) {
// log.warn("场景 {} 的baseTime为空,无法计算时间偏移", dispatchSceneId);
// continue;
// }
//
// log.info("场景 {} - 已下发场景baseTime: {}, 新场景baseTime: {}", dispatchSceneId, dispatchBaseTime, baseTime);
//
// // 筛选属于当前场景的工单
// List<Dispatch> currentSceneDispatches = frozenDispatches.stream()
// .filter(d -> dispatchSceneId.equals(d.getSceneId()))
// .collect(Collectors.toList());
//
// // 第一步:找出所有在锁定期内有工序的订单ID
// Set<String> lockedOrderIds = new HashSet<>();
// log.info("场景 {} 开始分析工序时间,锁定期范围: {} 到 {}", dispatchSceneId, lockStartTime, lockEndTime);
//
// for (GAScheduleResult prevResult : dispatchChromosome.getResult()) {
// LocalDateTime prevStartTime = dispatchBaseTime.plusSeconds(prevResult.getStartTime());
//
// log.debug("分析工序: ExecId={}, OrderId={}, 原始StartTime={}秒, 绝对开始时间={}",
// prevResult.getExecId(), prevResult.getOrderId(), prevResult.getStartTime(), prevStartTime);
//
// // 如果该工序的开始时间在锁定期内,记录其订单ID
// if (!prevStartTime.isBefore(lockStartTime) && !prevStartTime.isAfter(lockEndTime)) {
// log.info("工序在锁定期内: ExecId={}, OrderId={}, 开始时间={}",
// prevResult.getExecId(), prevResult.getOrderId(), prevStartTime);
//
// // 检查是否有对应的Dispatch记录(通过订单号和时间范围匹配,而不是ExecId)
// boolean hasValidDispatchRecord = currentSceneDispatches.stream()
// .anyMatch(d -> d.getMesCode() != null &&
// d.getMesCode().equals(prevResult.getOrderId()) &&
// d.getBeginTime() != null &&
// !d.getBeginTime().isBefore(lockStartTime) &&
// !d.getBeginTime().isAfter(lockEndTime));
//
// if (hasValidDispatchRecord && prevResult.getOrderId() != null) {
// lockedOrderIds.add(prevResult.getOrderId());
// log.info("订单 {} 被标记为锁定期订单(通过订单号匹配)", prevResult.getOrderId());
// } else {
// log.warn("工序 {} 在锁定期内但没有有效的Dispatch记录(订单号: {})",
// prevResult.getExecId(), prevResult.getOrderId());
// }
// } else {
// log.debug("工序不在锁定期内: ExecId={}, 开始时间={}, 锁定期: {} 到 {}",
// prevResult.getExecId(), prevStartTime, lockStartTime, lockEndTime);
// }
// }
//
// log.info("场景 {} 中发现 {} 个订单在锁定期内有工序: {}", dispatchSceneId, lockedOrderIds.size(), lockedOrderIds);
//
// // 第二步:获取这些订单的所有工序(包括锁定期外的工序)
// for (GAScheduleResult prevResult : dispatchChromosome.getResult()) {
// // 如果该工序属于锁定期订单,则保留(不管工序本身是否在锁定期内)
// if (lockedOrderIds.contains(prevResult.getOrderId())) {
// // 检查是否有对应的Dispatch记录(通过订单号匹配)
// boolean hasDispatchRecord = currentSceneDispatches.stream()
// .anyMatch(d -> d.getMesCode() != null &&
// d.getMesCode().equals(prevResult.getOrderId()));
//
// if (hasDispatchRecord) {
// // 将已下发场景的相对时间转换为绝对时间
// LocalDateTime prevStartTime = dispatchBaseTime.plusSeconds(prevResult.getStartTime());
// LocalDateTime prevEndTime = dispatchBaseTime.plusSeconds(prevResult.getEndTime());
//
// // 深拷贝工单信息
// GAScheduleResult lockedResult = copyGAScheduleResult(prevResult);
// lockedResult.setIsLocked(true); // 标记为锁定
//
// // 重新计算相对于新baseTime的时间
// int newStartTime = (int) ChronoUnit.SECONDS.between(baseTime, prevStartTime);
// int newEndTime = (int) ChronoUnit.SECONDS.between(baseTime, prevEndTime);
// lockedResult.setStartTime(newStartTime);
// lockedResult.setEndTime(newEndTime);
//
// lockedResults.add(lockedResult);
// lockedMachineIds.add(prevResult.getMachineId());
//
// boolean isInLockPeriod = !prevStartTime.isBefore(lockStartTime) && !prevStartTime.isAfter(lockEndTime);
// log.info("从场景 {} 获取订单 {} 的工序: ExecId={}, OrderCode={}, MachineId={}, 原始时间=[{} 到 {}], 新相对时间=[{} 到 {}]秒, 是否在锁定期内={}",
// dispatchSceneId, prevResult.getOrderId(), lockedResult.getExecId(), lockedResult.getOrderCode(), lockedResult.getMachineId(),
// prevStartTime, prevEndTime, newStartTime, newEndTime, isInLockPeriod);
// } else {
// log.warn("订单 {} 的工序 {} 没有对应的Dispatch记录", prevResult.getOrderId(), prevResult.getExecId());
// }
// }
// }
//
// // 从已下发场景的排产结果中获取对应的Entry信息
// if (dispatchChromosome.getAllOperations() != null) {
// log.info("场景 {} 中有 {} 个Entry,开始匹配锁定期工单的Entry信息", dispatchSceneId, dispatchChromosome.getAllOperations().size());
//
// for (GAScheduleResult lockedResult : lockedResults) {
// log.debug("处理锁定期工单: ExecId={}, OperationId={}", lockedResult.getExecId(), lockedResult.getOperationId());
//
// if (lockedResult.getOperationId() > 0) {
// Entry prevEntry = dispatchChromosome.getAllOperations().stream()
// .filter(e -> e.getId() == lockedResult.getOperationId())
// .findFirst()
// .orElse(null);
//
// if (prevEntry != null) {
// lockedEntries.put(lockedResult.getExecId(), prevEntry);
// log.debug("找到匹配的Entry: ExecId={}, EntryId={}, RoutingDetailId={}",
// lockedResult.getExecId(), prevEntry.getId(), prevEntry.getRoutingDetailId());
// } else {
// log.warn("未找到OperationId={}对应的Entry", lockedResult.getOperationId());
// }
// } else {
// log.warn("锁定期工单的OperationId为0,无法匹配Entry: ExecId={}", lockedResult.getExecId());
//
// // 尝试通过ExecId匹配Entry
// Entry prevEntry = dispatchChromosome.getAllOperations().stream()
// .filter(e -> e.getExecId().equals(lockedResult.getExecId()))
// .findFirst()
// .orElse(null);
//
// if (prevEntry != null) {
// lockedEntries.put(lockedResult.getExecId(), prevEntry);
// // 同时修正OperationId
// lockedResult.setOperationId(prevEntry.getId());
// log.info("通过ExecId匹配到Entry并修正OperationId: ExecId={}, EntryId={}, RoutingDetailId={}",
// lockedResult.getExecId(), prevEntry.getId(), prevEntry.getRoutingDetailId());
// } else {
// log.warn("通过ExecId也未找到对应的Entry: ExecId={}", lockedResult.getExecId());
// }
// }
// }
//
// log.info("场景 {} 成功匹配 {} 个Entry信息", dispatchSceneId, lockedEntries.size());
// }
//
// } else {
// log.warn("场景 {} 的排产结果为空", dispatchSceneId);
// }
// } else {
// log.warn("场景 {} 的排产结果文件不存在: {}", dispatchSceneId, dispatchFile.getAbsolutePath());
// }
// } else {
// log.warn("未找到场景 {} 的版本信息", dispatchSceneId);
// }
// } catch (Exception ex) {
// log.error("处理场景 {} 的排产结果失败: {}", dispatchSceneId, ex.getMessage(), ex);
// }
// }
//
// log.info("从 {} 个已下发场景排产结果中获取到 {} 个锁定期工单", dispatchSceneIds.size(), lockedResults.size());
// } else {
// log.warn("Dispatch表中的工单没有sceneId信息");
// }
// } catch (Exception ex) {
// log.error("从已下发场景排产结果获取锁定期工单失败: {}", ex.getMessage(), ex);
// }
//
// // 3. 如果无法从上次排产获取,则从Dispatch表查询
// if (lockedResults.isEmpty()) {
// log.info("从Dispatch表查询锁定期工单");
// List<Dispatch> frozenDispatches = dispatchService.lambdaQuery()
// .ge(Dispatch::getBeginTime, lockStartTime)
// .le(Dispatch::getBeginTime, lockEndTime)
// .eq(Dispatch::getIsDeleted, 0L)
// .orderBy(true, true, Dispatch::getMesCode, Dispatch::getTaskSeq)
// .list();
//
// if (frozenDispatches.isEmpty()) {
// log.info("冻结期内没有工单需要添加");
// return;
// }
//
// log.info("查询到冻结期内的工序数: {}", frozenDispatches.size());
//
// for (Dispatch dispatch : frozenDispatches) {
// GAScheduleResult result = new GAScheduleResult();
//
// log.info("处理Dispatch记录: id={}, executeId={}, mesCode={}, equipId={}, beginTime={}, endTime={}",
// dispatch.getId(), dispatch.getExecuteId(), dispatch.getMesCode(),
// dispatch.getEquipId(), dispatch.getBeginTime(), dispatch.getEndTime());
//
// // 设置基本信息
// result.setOperationId(dispatch.getExecuteId() != null ? dispatch.getExecuteId().intValue() : 0);
// result.setExecId(dispatch.getExecuteId() != null ? dispatch.getExecuteId().toString() : "");
// result.setOrderId(dispatch.getMesCode() != null ? dispatch.getMesCode() : "");
// result.setOrderCode(dispatch.getMesCode());
// result.setMachineId(dispatch.getEquipId() != null ? dispatch.getEquipId() : 0L);
// result.setQuantity(dispatch.getQuantity() != null ? dispatch.getQuantity() : 0.0);
//
// // 设置产品信息(从Dispatch表中可能没有,使用默认值)
// result.setProductId("");
// result.setProductName("");
// result.setProductCode("");
//
// log.info("从Dispatch创建锁定期工单: executeId={}, OperationId={}, mesCode={}",
// dispatch.getExecuteId(), result.getOperationId(), dispatch.getMesCode());
//
// // 计算相对时间(相对于baseTime的秒数)
// // 注意:锁定期工单的时间通常在baseTime之前,所以会是负数
// if (dispatch.getBeginTime() != null && dispatch.getEndTime() != null) {
// // 使用Dispatch表中的绝对时间,计算相对于baseTime的偏移(负数表示在baseTime之前)
// int startTime = (int) ChronoUnit.SECONDS.between(baseTime, dispatch.getBeginTime());
// int endTime = (int) ChronoUnit.SECONDS.between(baseTime, dispatch.getEndTime());
//
// log.info("锁定期工单时间计算: ExecId={}, Dispatch时间=[{} 到 {}], baseTime={}, 相对时间=[{} 到 {}]秒",
// dispatch.getExecuteId(), dispatch.getBeginTime(), dispatch.getEndTime(),
// baseTime, startTime, endTime);
//
// result.setStartTime(startTime);
// result.setEndTime(endTime);
// result.setProcessingTime((double) (endTime - startTime) / 60.0); // 转换为分钟
// }
//
// // 设置其他信息
// result.setIsLocked(true); // 标记为锁定
// result.setTeardownTime(0);
// result.setChangeOverTime(0);
// result.setPreTime(0);
// result.setSeq(dispatch.getTaskSeq() != null ? dispatch.getTaskSeq().intValue() : 0);
// result.setBomTime(0);
// result.setDesignatedStartTime(-1);
// result.setLockStartTime(0);
// result.setForcedMachineId(-1L);
//
// // 创建GeneDetails
// List<ScheduleResultDetail> geneDetails = new ArrayList<>();
// ScheduleResultDetail detail = new ScheduleResultDetail();
// detail.setStartTime(result.getStartTime());
// detail.setEndTime(result.getEndTime());
// detail.setQuantity(dispatch.getQuantity() != null ? dispatch.getQuantity() : 0.0);
// geneDetails.add(detail);
// result.setGeneDetails(geneDetails);
//
// lockedResults.add(result);
// lockedMachineIds.add(result.getMachineId());
//
// log.debug("添加锁定期工单: ExecId={}, OrderCode={}, MachineId={}, StartTime={}, EndTime={}",
// result.getExecId(), result.getOrderCode(), result.getMachineId(), result.getStartTime(), result.getEndTime());
// }
// }
//
// // 4. 添加到chromosome的result中
// if (chromosome.getResult() == null) {
// log.warn("chromosome.getResult()为null,创建新的CopyOnWriteArrayList");
// chromosome.setResult(new CopyOnWriteArrayList<>());
// }
//
// int beforeSize = chromosome.getResult().size();
// chromosome.getResult().addAll(lockedResults);
// int afterSize = chromosome.getResult().size();
//
// log.info("成功添加 {} 个锁定期工单到调度结果中,result大小从{}变为{}", lockedResults.size(), beforeSize, afterSize);
//
// // 5. 从已下发场景复制锁定期订单的Order对象
// if (!lockedResults.isEmpty()) {
// if (chromosome.getOrders() == null) {
// chromosome.setOrders(new CopyOnWriteArrayList<>());
// }
//
// int beforeOrderSize = chromosome.getOrders().size();
//
// // 收集锁定期工单的订单ID
// Set<String> lockedOrderIds = lockedResults.stream()
// .map(GAScheduleResult::getOrderId)
// .filter(Objects::nonNull)
// .collect(Collectors.toSet());
//
// log.info("需要复制的锁定期订单ID: {}", lockedOrderIds);
//
// // 从已下发场景中复制对应的Order对象
// try {
// // 获取已下发场景的sceneId
// List<Dispatch> frozenDispatches = dispatchService.lambdaQuery()
// .ge(Dispatch::getBeginTime, lockStartTime)
// .le(Dispatch::getBeginTime, lockEndTime)
// .eq(Dispatch::getIsDeleted, 0L)
// .list();
//
// log.info("查询到 {} 个锁定期Dispatch记录", frozenDispatches.size());
//
// Set<String> dispatchSceneIds = frozenDispatches.stream()
// .map(Dispatch::getSceneId)
// .filter(id -> id != null && !id.isEmpty())
// .collect(Collectors.toSet());
//
// log.info("锁定期Dispatch记录来自 {} 个场景: {}", dispatchSceneIds.size(), dispatchSceneIds);
//
// // 遍历每个已下发场景,复制锁定期订单
// for (String dispatchSceneId : dispatchSceneIds) {
// try {
// log.info("开始从场景 {} 加载Chromosome", dispatchSceneId);
// Chromosome dispatchChromosome = _sceneService.loadChromosomeFromFile(dispatchSceneId);
//
// if (dispatchChromosome != null) {
// log.info("场景 {} 加载成功,Orders数量: {}", dispatchSceneId,
// dispatchChromosome.getOrders() != null ? dispatchChromosome.getOrders().size() : 0);
//
// if (dispatchChromosome.getOrders() != null) {
// // 筛选出锁定期订单
// List<Order> lockedOrders = dispatchChromosome.getOrders().stream()
// .filter(order -> {
// boolean matches = lockedOrderIds.contains(order.getOrderId());
// log.debug("订单 {} 是否匹配锁定期: {}", order.getOrderId(), matches);
// return matches;
// })
// .collect(Collectors.toList());
//
// log.info("场景 {} 中找到 {} 个匹配的锁定期订单", dispatchSceneId, lockedOrders.size());
//
// // 复制到当前场景,避免重复添加
// for (Order lockedOrder : lockedOrders) {
// boolean exists = chromosome.getOrders().stream()
// .anyMatch(order -> lockedOrder.getOrderId().equals(order.getOrderId()));
//
// if (!exists) {
// // 直接添加原Order对象(已包含完整信息)
// chromosome.getOrders().add(lockedOrder);
//
// log.info("从场景 {} 复制锁定期订单: OrderId={}, OrderCode={}",
// dispatchSceneId, lockedOrder.getOrderId(), lockedOrder.getOrderCode());
// } else {
// log.warn("订单 {} 已存在,跳过复制", lockedOrder.getOrderId());
// }
// }
// } else {
// log.warn("场景 {} 的Orders为null", dispatchSceneId);
// }
// } else {
// log.warn("场景 {} 加载失败,Chromosome为null", dispatchSceneId);
// }
// } catch (Exception ex) {
// log.error("从场景 {} 复制锁定期订单失败: {}", dispatchSceneId, ex.getMessage(), ex);
// }
// }
// } catch (Exception e) {
// log.error("复制锁定期订单失败: {}", e.getMessage(), e);
// }
//
// int afterOrderSize = chromosome.getOrders().size();
// log.info("成功复制锁定期订单到Orders列表,大小从{}变为{}", beforeOrderSize, afterOrderSize);
// }
//
// // 5. 添加锁定期Entry到allOperations中
// if (!lockedEntries.isEmpty() && chromosome.getAllOperations() != null) {
// int beforeEntrySize = chromosome.getAllOperations().size();
// chromosome.getAllOperations().addAll(lockedEntries.values());
// log.info("成功添加 {} 个锁定期Entry到allOperations中,大小从{}变为{}",
// lockedEntries.size(), beforeEntrySize, chromosome.getAllOperations().size());
// }
//
// // 5. 确保锁定期工单使用的设备在initMachines中
// // 如果设备在本次排产中没有使用,则从已下发场景中获取设备信息
// if (chromosome.getInitMachines() != null && !lockedMachineIds.isEmpty()) {
// Set<Long> existingMachineIds = chromosome.getInitMachines().stream()
// .map(Machine::getId)
// .collect(Collectors.toSet());
//
// // 筛选出不在本次排产中的设备
// Set<Long> missingMachineIds = lockedMachineIds.stream()
// .filter(id -> id != null && id > 0 && !existingMachineIds.contains(id))
// .collect(Collectors.toSet());
//
// if (!missingMachineIds.isEmpty()) {
// log.info("锁定期工单使用的设备不在本次排产中,需要从已下发场景获取设备信息: {}", missingMachineIds);
//
// // 尝试从已下发场景的排产结果中获取这些设备的信息
// try {
// // 从Dispatch表查询锁定期内的工单,获取它们的所有sceneId
// List<Dispatch> frozenDispatches = dispatchService.lambdaQuery()
// .ge(Dispatch::getBeginTime, lockStartTime)
// .le(Dispatch::getBeginTime, lockEndTime)
// .eq(Dispatch::getIsDeleted, 0L)
// .list();
//
// // 获取所有已下发场景的sceneId
// Set<String> dispatchSceneIds = frozenDispatches.stream()
// .map(Dispatch::getSceneId)
// .filter(id -> id != null && !id.isEmpty())
// .collect(Collectors.toSet());
//
// boolean foundMachines = false;
//
// // 遍历每个场景查找设备信息
// for (String dispatchSceneId : dispatchSceneIds) {
// if (foundMachines) break; // 如果已经找到所有设备,跳出循环
//
// try {
// log.info("从场景 {} 获取设备信息", dispatchSceneId);
//
// // 加载已下发场景的排产结果
// SceneChromsome dispatchSceneChromsome = (SceneChromsome) redisUtils.get("SceneId." + dispatchSceneId);
// if (dispatchSceneChromsome != null) {
// int dispatchVersion = dispatchSceneChromsome.getVersion();
// File dispatchFile = new File("result", "chromosome_result_" + dispatchSceneId + "_" + dispatchVersion + "_.json");
//
// if (dispatchFile.exists()) {
// ObjectMapper objectMapper = new ObjectMapper();
// objectMapper.registerModule(new JavaTimeModule());
// objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//
// Chromosome dispatchChromosome = objectMapper.readValue(dispatchFile, Chromosome.class);
//
// if (dispatchChromosome.getInitMachines() != null) {
// // 从已下发场景的排产结果中查找这些设备
// List<Machine> dispatchMachines = dispatchChromosome.getInitMachines().stream()
// .filter(m -> missingMachineIds.contains(m.getId()))
// .collect(Collectors.toList());
//
// if (!dispatchMachines.isEmpty()) {
// log.info("从场景 {} 的排产结果中找到 {} 个锁定期设备", dispatchSceneId, dispatchMachines.size());
// chromosome.getInitMachines().addAll(dispatchMachines);
//
// // 从缺失列表中移除已找到的设备
// Set<Long> foundMachineIds = dispatchMachines.stream()
// .map(Machine::getId)
// .collect(Collectors.toSet());
// missingMachineIds.removeAll(foundMachineIds);
//
// // 如果所有设备都找到了,标记为完成
// if (missingMachineIds.isEmpty()) {
// foundMachines = true;
// }
// }
// }
// } else {
// log.warn("场景 {} 的排产结果文件不存在: {}", dispatchSceneId, dispatchFile.getAbsolutePath());
// }
// } else {
// log.warn("未找到场景 {} 的版本信息", dispatchSceneId);
// }
// } catch (Exception ex) {
// log.error("从场景 {} 获取设备信息失败: {}", dispatchSceneId, ex.getMessage(), ex);
// }
// }
//
// // 如果还有设备没找到,创建默认设备信息
// if (!missingMachineIds.isEmpty()) {
// log.warn("在所有已下发场景中都没有找到锁定期设备,将创建默认设备信息: {}", missingMachineIds);
// createDefaultMachines(chromosome, missingMachineIds);
// }
// } catch (Exception ex) {
// log.error("从已下发场景排产结果获取设备信息失败: {}", ex.getMessage(), ex);
// createDefaultMachines(chromosome, missingMachineIds);
// }
// }
// }
//
// } catch (Exception e) {
// log.error("添加锁定期工单时发生错误: {}", e.getMessage(), e);
// }
// }
//
// /**
// * 为锁定期工单创建默认设备信息
// * @param chromosome 染色体对象
// * @param machineIds 需要创建的设备ID集合
// */
// private void createDefaultMachines(Chromosome chromosome, Set<Long> machineIds) {
// try {
// // 查询这些设备的信息
// List<PlanResource> planResources = _PlanResourceService.lambdaQuery()
// .eq(PlanResource::getIsdeleted, 0)
// .in(PlanResource::getId, machineIds.stream()
// .map(Long::intValue)
// .collect(Collectors.toList()))
// .list();
//
// // 查询班次信息
// List<MesShiftWorkSched> allShiftWorkScheds = _MesShiftWorkSchedService.lambdaQuery()
// .eq(MesShiftWorkSched::getIsdeleted, 0)
// .list();
//
// // 创建Machine对象并添加到initMachines
// for (Long machineId : machineIds) {
// Machine machine = new Machine();
// machine.setId(machineId);
//
// PlanResource planResource = planResources.stream()
// .filter(pr -> pr.getId() == machineId.intValue())
// .findFirst()
// .orElse(null);
//
// if (planResource != null) {
// machine.setCode(planResource.getReferenceCode());
// machine.setName(planResource.getTitle());
// machine.setDepartment(planResource.getDepartTitle());
//
// log.info("为设备 {} 查询班次信息,workSchedId: {}", machineId, planResource.getWorkSchedId());
//
// // 查询设备的真实班次信息
// List<MesShiftWorkSched> shiftWorkScheds = allShiftWorkScheds.stream()
// .filter(t -> (long) t.getWeekWorkSchedId() == planResource.getWorkSchedId())
// .collect(Collectors.toList());
//
// log.info("设备 {} 找到 {} 个班次记录", machineId, shiftWorkScheds.size());
//
// if (!shiftWorkScheds.isEmpty()) {
// // 使用真实的班次信息
// List<Shift> shifts = mergeShiftData(shiftWorkScheds);
// for (Shift shift : shifts) {
// shift.setMachineId(machineId);
// shift.setSpecial(false);
// shift.setStartDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
// shift.setEndDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
// }
// machine.setShifts(shifts);
// log.info("为设备 {} 设置真实班次信息,共 {} 个班次", machineId, shifts.size());
// } else {
// // 如果没有找到班次信息,使用默认24小时班次
// machine.setShifts(createDefault24HourShift(machineId));
// log.warn("设备 {} 没有找到班次信息,使用默认24小时班次", machineId);
// }
// } else {
// machine.setCode("LOCKED-" + machineId);
// machine.setName("锁定期设备-" + machineId);
// // 使用默认24小时班次
// machine.setShifts(createDefault24HourShift(machineId));
// log.warn("设备 {} 没有找到PlanResource信息,使用默认24小时班次", machineId);
// }
//
// chromosome.getInitMachines().add(machine);
// }
//
// log.info("成功创建 {} 个默认锁定期设备", machineIds.size());
// } catch (Exception e) {
// log.error("创建默认设备信息失败: {}", e.getMessage(), e);
// }
// }
//
// /**
// * 创建默认的24小时班次
// * @param machineId 设备ID
// * @return 24小时班次列表
// */
// private List<Shift> createDefault24HourShift(Long machineId) {
// List<Shift> shifts = new ArrayList<>();
// Shift shift = new Shift();
// shift.setMachineId(machineId);
// shift.setStartTime(LocalTime.of(0, 0, 0));
// shift.setEndTime(LocalTime.of(23, 59, 59));
// HashSet<Integer> days = new HashSet<>();
// for (int i = 0; i <= 6; i++) {
// days.add(i);
// }
// shift.setDays(days);
// shift.setSpecial(false);
// shift.setStartDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
// shift.setEndDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
// shifts.add(shift);
// return shifts;
// }
//
// /**
// * 深拷贝 GAScheduleResult 对象
// *
// * @param source 源对象
// * @return 拷贝后的新对象
// */
// private GAScheduleResult copyGAScheduleResult(GAScheduleResult source) {
// if (source == null) {
// return null;
// }
//
// GAScheduleResult copy = new GAScheduleResult();
//
// // 拷贝基本字段
// copy.setGroupId(source.getGroupId());
// copy.setOperationId(source.getOperationId());
// copy.setExecId(source.getExecId());
// copy.setOrderId(source.getOrderId());
// copy.setOrderCode(source.getOrderCode());
// copy.setProductId(source.getProductId());
// copy.setProductName(source.getProductName());
// copy.setProductCode(source.getProductCode());
// copy.setMachineId(source.getMachineId());
// copy.setStartTime(source.getStartTime());
// copy.setEndTime(source.getEndTime());
// copy.setTeardownTime(source.getTeardownTime());
// copy.setQuantity(source.getQuantity());
// copy.setDesignatedStartTime(source.getDesignatedStartTime());
// copy.setLockStartTime(source.getLockStartTime());
// copy.setForcedMachineId(source.getForcedMachineId());
// copy.setIsLocked(source.isIsLocked());
// copy.setOneTime(source.getOneTime());
// copy.setProcessingTime(source.getProcessingTime());
// copy.setChangeOverTime(source.getChangeOverTime());
// copy.setPreTime(source.getPreTime());
// copy.setSeq(source.getSeq());
// copy.setBomTime(source.getBomTime());
//
// // 深拷贝 GeneDetails 列表
// if (source.getGeneDetails() != null) {
// List<ScheduleResultDetail> detailsCopy = new ArrayList<>();
// for (ScheduleResultDetail detail : source.getGeneDetails()) {
// ScheduleResultDetail detailCopy = new ScheduleResultDetail();
// detailCopy.setKey(detail.getKey());
// detailCopy.setStartTime(detail.getStartTime());
// detailCopy.setEndTime(detail.getEndTime());
// detailCopy.setOneTime(detail.getOneTime());
// detailCopy.setQuantity(detail.getQuantity());
//
// // 深拷贝 usedSegment
// if (detail.getUsedSegment() != null) {
// List<TimeSegment> segmentsCopy = new ArrayList<>(detail.getUsedSegment());
// detailCopy.setUsedSegment(segmentsCopy);
// }
//
// detailsCopy.add(detailCopy);
// }
// copy.setGeneDetails(detailsCopy);
// }
//
// // 深拷贝 TargetFinishedOperationId 列表
// if (source.getTargetFinishedOperationId() != null) {
// copy.setTargetFinishedOperationId(new ArrayList<>(source.getTargetFinishedOperationId()));
// }
//
// return copy;
// }
//
// /**
// * 在排产前标记锁定期工单占用的设备时间段
// * 将锁定期工单占用的设备时间段标记为不可用,避免新工单与锁定期工单冲突
// *
// * @param machines 设备列表
// * @param baseTime 基准时间
// */
// private void markLockedOrdersOccupiedTime(List<Machine> machines, LocalDateTime baseTime) {
// try {
// // 1. 获取时间配置
// ApsTimeConfig timeConfig = apsTimeConfigService.getOne(new LambdaQueryWrapper<>());
// if (timeConfig == null || timeConfig.getBaseTime() == null) {
// log.warn("未找到ApsTimeConfig配置,跳过标记锁定期设备占用");
// return;
// }
//
// long freezeSeconds = timeConfig.getFreezeDate() != null ? timeConfig.getFreezeDate().longValue() : 0;
// if (freezeSeconds <= 0) {
// log.info("冻结期秒数为{},跳过标记锁定期设备占用", freezeSeconds);
// return;
// }
//
// // 2. 计算锁定期范围
// LocalDateTime lockStartTime = baseTime;
// LocalDateTime lockEndTime = baseTime.plusSeconds(freezeSeconds);
//
// log.info("开始标记锁定期设备占用时间段,锁定期范围: {} 到 {}", lockStartTime, lockEndTime);
//
// // 3. 从Dispatch表查询锁定期内的工单
// List<Dispatch> frozenDispatches = dispatchService.lambdaQuery()
// .ge(Dispatch::getBeginTime, lockStartTime)
// .le(Dispatch::getBeginTime, lockEndTime)
// .eq(Dispatch::getIsDeleted, 0L)
// .isNotNull(Dispatch::getEquipId)
// .isNotNull(Dispatch::getBeginTime)
// .isNotNull(Dispatch::getEndTime)
// .list();
//
// if (frozenDispatches.isEmpty()) {
// log.info("没有锁定期工单需要标记设备占用");
// return;
// }
//
// log.info("查询到 {} 个锁定期工单,开始标记设备占用", frozenDispatches.size());
//
// // 4. 按设备分组
// Map<Long, List<Dispatch>> dispatchByMachine = frozenDispatches.stream()
// .collect(Collectors.groupingBy(Dispatch::getEquipId));
//
// // 5. 为每个设备标记占用时间段
// int markedCount = 0;
// for (Map.Entry<Long, List<Dispatch>> entry : dispatchByMachine.entrySet()) {
// Long machineId = entry.getKey();
// List<Dispatch> dispatches = entry.getValue();
//
// // 查找对应的Machine对象
// Machine machine = machines.stream()
// .filter(m -> m.getId() == machineId)
// .findFirst()
// .orElse(null);
//
// if (machine == null) {
// log.warn("未找到设备 {},跳过标记", machineId);
// continue;
// }
//
// // 为该设备的每个锁定期工单创建占用时间段
// for (Dispatch dispatch : dispatches) {
// LocalDateTime dispatchStart = dispatch.getBeginTime();
// LocalDateTime dispatchEnd = dispatch.getEndTime();
//
// // 只标记结束时间在baseTime之后的工单(这些会占用未来的设备时间)
// if (dispatchEnd.isAfter(baseTime)) {
// // 如果开始时间在baseTime之前,则从baseTime开始标记
// LocalDateTime occupyStart = dispatchStart.isBefore(baseTime) ? baseTime : dispatchStart;
// LocalDateTime occupyEnd = dispatchEnd;
//
// // 创建一个不可用的时间段
// TimeSegment occupiedSegment = new TimeSegment();
// occupiedSegment.setStart(occupyStart);
// occupiedSegment.setEnd(occupyEnd);
// occupiedSegment.setType(SegmentType.MAINTENANCE); // 标记为不可用
// occupiedSegment.setUsed(true); // 标记为已占用
// occupiedSegment.setHoliday(false);
// occupiedSegment.setEfficiency(1.0);
//
// // 添加到设备的可用时间段列表中
// if (machine.getAvailability() == null) {
// machine.setAvailability(new CopyOnWriteArrayList<>());
// }
// machine.getAvailability().add(occupiedSegment);
//
// markedCount++;
// log.debug("标记设备 {} 的锁定期占用时间段: {} 到 {}, 订单: {}",
// machineId, occupyStart, occupyEnd, dispatch.getMesCode());
// }
// }
// }
//
// log.info("成功标记 {} 个锁定期工单的设备占用时间段", markedCount);
//
// } catch (Exception e) {
// log.error("标记锁定期设备占用时间段失败: {}", e.getMessage(), e);
// }
// }
public Chromosome editMachineOption(String SceneId, Entry operation,
Long newMachineId) {
......@@ -861,7 +1678,7 @@ public class PlanResultService {
}
}
private String ConvertTime(int minute) {
return baseTime.plusSeconds(minute).format(java.time.format.DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss"));
return baseTime.plusSeconds(minute).format(DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss"));
}
/**
......@@ -1897,13 +2714,13 @@ private GlobalParam InitGlobalParam()
for (int i = 0; i < machineList.size(); i++) {
Machine machine = machineList.get(i);
com.aps.entity.Gantt.ResourceGanttVO resourceGanttVO = new com.aps.entity.Gantt.ResourceGanttVO();
ResourceGanttVO resourceGanttVO = new ResourceGanttVO();
resourceGanttVO.setId(machine.getId());
resourceGanttVO.setName(machine.getName());
resourceGanttVO.setShift(convertToShiftVO(machine));
resourceGanttVO.setCode(machine.getCode());
// 转换任务列表
List<com.aps.entity.Gantt.TaskVO> taskVOList = new ArrayList<>();
List<TaskVO> taskVOList = new ArrayList<>();
if (scheduleChromosome.getResult() != null) {
// 筛选出属于当前设备的任务
List<GAScheduleResult> machineGenes = scheduleChromosome.getResult().stream()
......@@ -1935,10 +2752,22 @@ private GlobalParam InitGlobalParam()
taskVO.setEquipCooling(0); // 默认值
taskVO.setEquipType(resourceGanttVO.getType());
taskVO.setEquipName(resourceGanttVO.getName());
taskVO.setLocked(gene.isIsLocked()); // 默认值
taskVO.setLocked(gene.isIsLocked()); // 设置锁定状态
// 处理锁定期工单(entry为null的情况)
if (entry != null) {
taskVO.setSeq(Math.toIntExact(entry.getTaskSeq())); // 使用工序ID
taskVO.setSeq(Math.toIntExact(entry.getTaskSeq()));
taskVO.setSeqName(entry.getRoutingDetailName());
taskVO.setDetailId(entry.getRoutingDetailId());
taskVO.setHeaderId(entry.getRoutingId());
taskVO.setHeaderName(entry.getRoutingName());
} else {
// 锁定期工单使用 gene 中的信息
taskVO.setSeq(gene.getSeq());
taskVO.setSeqName("锁定期工序");
taskVO.setDetailId(0L);
taskVO.setHeaderId(0);
taskVO.setHeaderName("锁定期工单");
}
if (gene.getDesignatedStartTime()>0) {
......@@ -1957,11 +2786,6 @@ private GlobalParam InitGlobalParam()
taskVO.setShopId(machine.getId());
taskVO.setShopName(resourceGanttVO.getShopName());
taskVO.setStatus(0); // 默认值
taskVO.setDetailId(entry.getRoutingDetailId()); // 将productId和operationID组合为detailId
taskVO.setHeaderId(entry.getRoutingId()); // 默认值
taskVO.setHeaderName(entry.getRoutingName()); // 默认值
taskVO.setSeq(Math.toIntExact(entry.getTaskSeq())); // 使用工序ID
taskVO.setSeqName(entry.getRoutingDetailName());
taskVO.setProcessingTime(gene.getProcessingTime());
taskVOList.add(taskVO);
......@@ -1992,8 +2816,9 @@ private GlobalParam InitGlobalParam()
// 按产品ID和工单ID分组基因
if (scheduleChromosome.getResult() != null) {
// 按工单ID分组
// 按工单ID分组(过滤掉 OrderId 为 null 的记录)
scheduleChromosome.getResult().stream()
.filter(r -> r.getOrderId() != null && !r.getOrderId().isEmpty())
.collect(Collectors.groupingBy(GAScheduleResult::getOrderId))
.forEach((orderId, genes) -> {
if (!genes.isEmpty()) {
......@@ -2031,7 +2856,7 @@ private GlobalParam InitGlobalParam()
productGanttVO.setEndDate(scheduleChromosome.getBaseTime().plusMinutes(maxEndTime));
// 转换任务列表
List<com.aps.entity.Gantt.TaskVO> taskVOList = new ArrayList<>();
List<TaskVO> taskVOList = new ArrayList<>();
// // 按工序顺序排序
// genes.sort((g1, g2) -> Integer.compare(g1.getSequenceId(), g2.getSequenceId()));
......@@ -2041,7 +2866,7 @@ private GlobalParam InitGlobalParam()
Entry entry1 = allOperations.stream()
.filter(t -> t.getId() == gene.getOperationId()).findFirst().orElse(null);
com.aps.entity.Gantt.TaskVO taskVO = new com.aps.entity.Gantt.TaskVO();
TaskVO taskVO = new TaskVO();
taskVO.setId(String.valueOf(gene.getOperationId()));
taskVO.setPlanId(gene.getOrderId());
taskVO.setPlanCode(gene.getOrderCode());
......@@ -2133,9 +2958,46 @@ private GlobalParam InitGlobalParam()
List<ProdEquipment> ProdEquipments= _prodEquipmentService.lambdaQuery()
.eq(ProdEquipment::getSceneId,SceneId)
.list();
List<Long> MachineIds = ProdEquipments.stream()
Set<Long> machineIdSet = ProdEquipments.stream()
.map(ProdEquipment::getEquipId)
.distinct()
.collect(Collectors.toSet());
// 添加锁定期工单使用的设备ID
try {
ApsTimeConfig timeConfig = apsTimeConfigService.getOne(new LambdaQueryWrapper<>());
if (timeConfig != null && timeConfig.getBaseTime() != null && timeConfig.getFreezeDate() != null) {
LocalDateTime baseTime = timeConfig.getBaseTime();
long freezeSeconds = timeConfig.getFreezeDate().longValue();
if (freezeSeconds > 0) {
// 锁定期计算:baseTime 到 baseTime + freezeSeconds
LocalDateTime lockStartTime = baseTime;
LocalDateTime lockEndTime = baseTime.plusSeconds(freezeSeconds);
// 查询锁定期内的工单使用的设备ID
List<Dispatch> frozenDispatches = dispatchService.lambdaQuery()
.ge(Dispatch::getBeginTime, lockStartTime)
.le(Dispatch::getBeginTime, lockEndTime)
.eq(Dispatch::getIsDeleted, 0L)
.isNotNull(Dispatch::getEquipId)
.list();
// 提取设备ID并添加到Set中
for (Dispatch dispatch : frozenDispatches) {
if (dispatch.getEquipId() != null) {
machineIdSet.add(dispatch.getEquipId());
}
}
log.info("锁定期工单使用的所有设备ID: {}", machineIdSet);
}
}
} catch (Exception e) {
log.error("加载锁定期设备ID时发生错误: {}", e.getMessage(), e);
}
// 转换为排序后的List
List<Long> MachineIds = machineIdSet.stream()
.sorted()
.collect(Collectors.toList());
......@@ -2339,6 +3201,12 @@ private GlobalParam InitGlobalParam()
public List<Machine> InitCalendarToAllMachines3(Chromosome chromosome) {
List<Machine> machines = chromosome.getInitMachines();
// 如果initMachines为空,返回空列表
if (machines == null || machines.isEmpty()) {
return new ArrayList<>();
}
Set<Long> machineIds = chromosome.getResult().stream()
.map(GAScheduleResult::getMachineId)
.collect(Collectors.toSet());
......@@ -2350,6 +3218,7 @@ private GlobalParam InitGlobalParam()
{
List<Shift> result = new ArrayList<>();
List<Shift> shifts = machine.getShifts();
if (shifts != null) {
for (Shift shift : shifts) {
// 处理跨天班次(开始时间晚于结束时间的情况,如 7:30 到 3:30)
if (shift.getEndTime().isBefore(shift.getStartTime())) {
......@@ -2377,9 +3246,8 @@ private GlobalParam InitGlobalParam()
// 正常班次直接添加
result.add(shift);
}
}
}
machine.setShifts(result);
}
......
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