倒排冲突

parent 2f7a699b
......@@ -1612,6 +1612,28 @@ if(groupId==7)
.mapToInt(ScheduleResultDetail::getEndTime)
.max()
.orElse(0);
// 不可中断工序不能由多段空档拼接;如果试排结果断开,先归还占用,再倒排寻找最近连续窗口。
if (operation.getIsInterrupt() != 1 && hasDiscontinuousDetails(geneDetails)) {
AddMachineAvailable(machine, geneDetails);
if (isJit && islockMachineTime) {
CopyOnWriteArrayList<ScheduleResultDetail> continuousDetails =
scheduleLatestContinuousJit(machine, operation, earliestStartTime, processingTimeTotal);
if (continuousDetails == null || continuousDetails.isEmpty()) {
return OperationScheduleResult.success(null);
}
geneDetails = continuousDetails;
startTime = geneDetails.stream()
.mapToInt(ScheduleResultDetail::getStartTime)
.min()
.orElse(0);
endTime = geneDetails.stream()
.mapToInt(ScheduleResultDetail::getEndTime)
.max()
.orElse(0);
} else {
return OperationScheduleResult.success(null);
}
}
// if (isJit) {
// FileHelper.writeLogFile(" 半成品 " + operation.getGroupId() + " - " + operation.getSequence() + ",开始时间: " + startTime + ",结束时间: " + endTime + ",处理时间: " + processingTime + ", 后处理: " + teardownTime +
// ", 前处理: " + preTime + ", 换型: " + setupTime + ", 数量: " + operation.getQuantity() + ", 设备: " + machine.getId() + ", 是否可中断: " + operation.getIsInterrupt());
......@@ -1667,6 +1689,202 @@ if(groupId==7)
return OperationScheduleResult.success(result);
}
// 判断排程明细是否存在断档。不可中断工序如果出现断档,页面外层时间会跨住中间任务。
private boolean hasDiscontinuousDetails(CopyOnWriteArrayList<ScheduleResultDetail> geneDetails) {
if (geneDetails == null || geneDetails.size() <= 1) {
return false;
}
List<int[]> ranges = new ArrayList<>();
for (ScheduleResultDetail detail : geneDetails) {
if (detail == null) {
continue;
}
if (detail.getUsedSegment() != null && !detail.getUsedSegment().isEmpty()) {
for (TimeSegment segment : detail.getUsedSegment()) {
if (segment == null || segment.getStart() == null || segment.getEnd() == null) {
continue;
}
int segmentStart = (int) ChronoUnit.SECONDS.between(baseTime, segment.getStart());
int segmentEnd = (int) ChronoUnit.SECONDS.between(baseTime, segment.getEnd());
if (segmentEnd > segmentStart) {
ranges.add(new int[]{segmentStart, segmentEnd});
}
}
} else if (detail.getEndTime() > detail.getStartTime()) {
ranges.add(new int[]{detail.getStartTime(), detail.getEndTime()});
}
}
if (ranges.size() <= 1) {
return false;
}
ranges.sort(Comparator.comparingInt(range -> range[0]));
int lastEnd = ranges.get(0)[1];
for (int i = 1; i < ranges.size(); i++) {
int[] current = ranges.get(i);
if (current[0] > lastEnd + 1) {
return true;
}
lastEnd = Math.max(lastEnd, current[1]);
}
return false;
}
// 倒排不可中断兜底:从锚点往前找最近的一整段连续空闲窗口,避免失败后掉到基准日期正排。
private CopyOnWriteArrayList<ScheduleResultDetail> scheduleLatestContinuousJit(
Machine machine, Entry operation, int latestEndTime, int processingTimeTotal) {
if (machine == null || machine.getAvailability() == null || processingTimeTotal <= 0) {
return null;
}
LocalDateTime latestEnd = baseTime.plusSeconds(latestEndTime);
List<TimeSegment> availableSegments = machine.getAvailability().stream()
.filter(t -> t != null
&& !t.isUsed()
&& t.getStart() != null
&& t.getEnd() != null
&& t.getType() != SegmentType.MAINTENANCE
&& t.getStart().isBefore(latestEnd)
&& t.getEnd().isAfter(baseTime))
.sorted(Comparator.comparing(TimeSegment::getStart))
.collect(Collectors.toList());
List<TimeSegment> group = new ArrayList<>();
LocalDateTime groupStart = null;
LocalDateTime groupEnd = null;
long groupAvailableSeconds = 0L;
for (int i = availableSegments.size() - 1; i >= 0; i--) {
TimeSegment segment = availableSegments.get(i);
LocalDateTime segmentStart = segment.getStart().isBefore(baseTime) ? baseTime : segment.getStart();
LocalDateTime segmentEnd = segment.getEnd().isAfter(latestEnd) ? latestEnd : segment.getEnd();
if (!segmentEnd.isAfter(segmentStart)) {
continue;
}
boolean continuous = group.isEmpty() || !segmentEnd.plusSeconds(1).isBefore(groupStart);
if (!continuous) {
group.clear();
groupAvailableSeconds = 0L;
groupEnd = null;
}
group.add(0, segment);
groupStart = segmentStart;
if (groupEnd == null) {
groupEnd = segmentEnd;
}
groupAvailableSeconds += ChronoUnit.SECONDS.between(segmentStart, segmentEnd);
if (groupAvailableSeconds >= processingTimeTotal) {
return buildContinuousJitDetails(machine, operation, group, groupEnd, processingTimeTotal);
}
}
return null;
}
// 将选中的连续窗口转成明细,并同步占用设备日历。
private CopyOnWriteArrayList<ScheduleResultDetail> buildContinuousJitDetails(
Machine machine, Entry operation, List<TimeSegment> group, LocalDateTime latestEnd, int processingTimeTotal) {
CopyOnWriteArrayList<ScheduleResultDetail> details = new CopyOnWriteArrayList<>();
long remaining = processingTimeTotal;
LocalDateTime cursorEnd = latestEnd;
for (int i = group.size() - 1; i >= 0 && remaining > 0; i--) {
TimeSegment segment = group.get(i);
LocalDateTime useEnd = segment.getEnd().isAfter(cursorEnd) ? cursorEnd : segment.getEnd();
LocalDateTime useStart = segment.getStart();
if (!useEnd.isAfter(useStart)) {
continue;
}
long availableSeconds = ChronoUnit.SECONDS.between(useStart, useEnd);
if (availableSeconds > remaining) {
useStart = useEnd.minusSeconds(remaining);
}
TimeSegment occupied = occupyAvailabilityRange(machine, segment, useStart, useEnd);
if (occupied == null) {
return null;
}
ScheduleResultDetail detail = new ScheduleResultDetail();
detail.setKey(occupied.getKey());
detail.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, useStart));
detail.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, useEnd));
detail.setOneTime(1);
detail.setQuantity(operation.getQuantity());
detail.setEfficiency(occupied.getEfficiency());
detail.setUsedSegment(Collections.singletonList(occupied));
details.add(0, detail);
remaining -= ChronoUnit.SECONDS.between(useStart, useEnd);
cursorEnd = useStart.minusSeconds(1);
}
return remaining <= 0 ? details : null;
}
// 从设备可用片段里切出本次占用范围,保留前后未占用部分。
private TimeSegment occupyAvailabilityRange(
Machine machine, TimeSegment source, LocalDateTime useStart, LocalDateTime useEnd) {
if (machine == null || machine.getAvailability() == null || source == null
|| useStart == null || useEnd == null || !useEnd.isAfter(useStart)) {
return null;
}
int index = machine.getAvailability().stream()
.filter(t -> source.getKey().equals(t.getKey()))
.findFirst()
.map(machine.getAvailability()::indexOf)
.orElse(-1);
if (index < 0) {
return null;
}
TimeSegment current = machine.getAvailability().remove(index);
List<TimeSegment> replacement = new ArrayList<>();
if (current.getStart().isBefore(useStart)) {
TimeSegment before = copyAvailabilitySegment(current, current.getStart(), useStart.minusSeconds(1), false);
if (before.getEnd().isAfter(before.getStart())) {
replacement.add(before);
}
}
TimeSegment occupied = copyAvailabilitySegment(current, useStart, useEnd, true);
replacement.add(occupied);
if (current.getEnd().isAfter(useEnd)) {
TimeSegment after = copyAvailabilitySegment(current, useEnd.plusSeconds(1), current.getEnd(), false);
if (after.getEnd().isAfter(after.getStart())) {
replacement.add(after);
}
}
machine.getAvailability().addAll(replacement);
machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
return occupied;
}
private TimeSegment copyAvailabilitySegment(
TimeSegment source, LocalDateTime start, LocalDateTime end, boolean used) {
TimeSegment copy = new TimeSegment();
copy.setKey(UUID.randomUUID().toString());
copy.setStart(start);
copy.setEnd(end);
copy.setEarliestTime(source.getEarliestTime());
copy.setTotalTaskTime(source.getTotalTaskTime());
copy.setType(source.getType());
copy.setHoliday(source.isHoliday());
copy.setUsed(used);
copy.setEfficiency(source.getEfficiency());
copy.setProcessingTime(source.getProcessingTime());
return copy;
}
private GAScheduleResult CreateResult(Entry operation,long machineId
,int startTime,int endTime,double processingTime
,int setupTime,int preTime,int teardownTime,int bomtime
......
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