Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
H
HYH.APSJ
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
佟礼
HYH.APSJ
Commits
6f7aeeba
Commit
6f7aeeba
authored
May 08, 2026
by
Tong Li
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
倒排
parent
ef3a51e0
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
966 additions
and
245 deletions
+966
-245
Entry.java
src/main/java/com/aps/entity/basic/Entry.java
+9
-0
GlobalParam.java
src/main/java/com/aps/entity/basic/GlobalParam.java
+5
-0
GeneticDecoder.java
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
+196
-104
GeneticDecoderBom.java
...ain/java/com/aps/service/Algorithm/GeneticDecoderBom.java
+147
-0
MachineCalculator.java
...ain/java/com/aps/service/Algorithm/MachineCalculator.java
+574
-123
MachineSchedulerService.java
...in/java/com/aps/service/plan/MachineSchedulerService.java
+11
-0
PlanResultService.java
src/main/java/com/aps/service/plan/PlanResultService.java
+16
-12
application.yml
src/main/resources/application.yml
+3
-3
PlanResultServiceTest.java
src/test/java/com/aps/demo/PlanResultServiceTest.java
+5
-3
No files found.
src/main/java/com/aps/entity/basic/Entry.java
View file @
6f7aeeba
...
...
@@ -157,6 +157,7 @@ private Long isInterrupt = 1l;
private
String
equipName
;
//设备编码
@Schema
(
description
=
"指定开始时间"
)
@JsonInclude
(
JsonInclude
.
Include
.
ALWAYS
)
private
LocalDateTime
designatedStartTime
;
...
...
@@ -164,4 +165,12 @@ private Long isInterrupt = 1l;
private
LocalDateTime
jitPreferredStartTime
;
private
boolean
jitTemporary
=
false
;
private
String
schedulingMode
=
SchedulingMode
.
FORWARD
.
name
();
private
int
anchorTimeSecond
=
0
;
public
enum
SchedulingMode
{
FORWARD
,
BACKWARD
}
}
src/main/java/com/aps/entity/basic/GlobalParam.java
View file @
6f7aeeba
...
...
@@ -39,6 +39,11 @@ public class GlobalParam {
/// </summary>
private
boolean
IsOverlap
=
false
;
/// <summary>
/// 是否全局倒排
/// </summary>
private
boolean
isJit
=
true
;
private
boolean
_smoothSetup
=
false
;
// 设置时间平滑 工序的前处理是否提前
private
boolean
_smoothChangeOver
=
true
;
// 默认true,设置时间 是否考虑换型时间
...
...
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
View file @
6f7aeeba
...
...
@@ -20,6 +20,7 @@ import org.springframework.stereotype.Component;
import
java.math.BigDecimal
;
import
java.time.Duration
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
import
java.time.temporal.ChronoUnit
;
import
java.util.*
;
import
java.util.concurrent.*
;
...
...
@@ -66,7 +67,7 @@ public class GeneticDecoder {
private
DiscreteParameterMatrixService
discreteParameterMatrixService
;
private
String
sceneId
;
private
boolean
rebuildStructureForCurrentDecode
=
tru
e
;
private
boolean
rebuildStructureForCurrentDecode
=
fals
e
;
...
...
@@ -327,8 +328,10 @@ public class GeneticDecoder {
Entry
entry
=
allOperations
.
stream
()
.
filter
(
t
->
t
.
getGroupId
()==
num
&&
t
.
getSequence
()==
scheduledCount1
)
.
findFirst
().
orElse
(
null
);
entry
.
setSchedulingMode
(
Entry
.
SchedulingMode
.
FORWARD
.
name
());
if
(
entry
!=
null
&&
entry
.
getDependentOnOrderIds
().
size
()>
0
)
{
for
(
int
order
:
entry
.
getDependentOnOrderIds
())
{
for
(
int
num1
:
sfSequence
.
get
(
order
)){
...
...
@@ -358,7 +361,7 @@ public class GeneticDecoder {
Entry
entry
=
allOperations
.
stream
()
.
filter
(
t
->
t
.
getGroupId
()==
orderid
&&
t
.
getSequence
()==
scheduledCount1
)
.
findFirst
().
orElse
(
null
);
entry
.
setSchedulingMode
(
Entry
.
SchedulingMode
.
BACKWARD
.
name
());
if
(
entry
!=
null
&&
entry
.
getDependentOnOrderIds
().
size
()>
0
)
{
for
(
int
order
:
entry
.
getDependentOnOrderIds
())
{
...
...
@@ -411,7 +414,7 @@ public class GeneticDecoder {
public
void
serialDecode
(
Chromosome
chromosome
)
{
long
decodeStart
=
System
.
nanoTime
();
chromosome
.
setScenarioID
(
sceneId
);
boolean
isJit
=
_globalParam
.
isJit
();
if
(
rebuildStructureForCurrentDecode
)
{
long
t1
=
System
.
nanoTime
();
//创建半成品订单
...
...
@@ -486,25 +489,20 @@ public class GeneticDecoder {
opMachineKeyMap
.
put
(
key
,
opMachine
);
}
// 步骤2:按OperationSequencing顺序调度工序
// Map<Integer, Integer> orderProcessCounter = allOperations.stream()
// .collect(Collectors.groupingBy(Entry::getGroupId, Collectors.collectingAndThen(
// Collectors.counting(), Long::intValue)))
// .entrySet().stream()
// .collect(Collectors.toMap(Map.Entry::getKey, e -> 0));
//
// Map<Integer, Integer> orderLastEndTime = allOperations.stream()
// .collect(Collectors.groupingBy(Entry::getGroupId))
// .keySet().stream()
// .collect(Collectors.toMap(k -> k, k -> 0));
// 步骤2:按OperationSequencing顺序调度工序
Map
<
Integer
,
Integer
>
orderProcessCounter
=
new
HashMap
<>();
Map
<
Integer
,
Integer
>
orderLastEndTime
=
new
HashMap
<>();
Map
<
Integer
,
Integer
>
orderDueDate
=
new
HashMap
<>();
Map
<
Integer
,
Entry
>
entryIndexById
=
new
HashMap
<>();
Map
<
Integer
,
List
<
Entry
>>
entrysBygroupId
=
new
HashMap
<>();
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
=
new
ConcurrentHashMap
<>();
for
(
Order
order
:
chromosome
.
getOrders
())
{
int
end
=
(
int
)
ChronoUnit
.
SECONDS
.
between
(
baseTime
,
order
.
getDueDate
());
orderDueDate
.
putIfAbsent
(
order
.
getId
(),
end
);
}
for
(
Entry
op
:
allOperations
)
{
int
groupId
=
op
.
getGroupId
();
orderProcessCounter
.
putIfAbsent
(
groupId
,
0
);
...
...
@@ -525,9 +523,25 @@ public class GeneticDecoder {
for
(
int
groupId
:
chromosome
.
getOperationSequencing
())
{
int
scheduledCount
=
orderProcessCounter
.
get
(
groupId
);
List
<
Entry
>
orderOps
=
entrysBygroupId
.
get
(
groupId
).
stream
()
List
<
Entry
>
orderOps
=
new
ArrayList
<>();
boolean
orderIsJit
=
orderDueDate
.
get
(
groupId
)>
0
;
if
(
isJit
&&
orderIsJit
)
{
orderOps
=
entrysBygroupId
.
get
(
groupId
).
stream
()
.
sorted
(
Comparator
.
comparing
(
Entry:
:
getSequence
).
reversed
())
.
collect
(
Collectors
.
toList
());
orderIsJit
=
true
;
}
else
{
orderOps
=
entrysBygroupId
.
get
(
groupId
).
stream
()
.
sorted
(
Comparator
.
comparing
(
Entry:
:
getSequence
))
.
collect
(
Collectors
.
toList
());
orderIsJit
=
false
;
}
if
(
scheduledCount
>=
orderOps
.
size
())
{
throw
new
IllegalStateException
(
String
.
format
(
...
...
@@ -555,16 +569,11 @@ public class GeneticDecoder {
double
processTime
=
machineOption
.
getProcessingTime
();
long
opStart
=
System
.
nanoTime
();
int
actualEndTime
=
processOperation
(
currentOp
,
machineId
,
processTime
,
machineOption
,
chromosome
,
machineIdMap
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
int
actualEndTime
=
processOperation
(
currentOp
,
machineId
,
processTime
,
machineOption
,
chromosome
,
machineIdMap
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
,(
int
)
orderDueDate
.
get
(
groupId
),
orderIsJit
);
long
opElapsed
=
System
.
nanoTime
()
-
opStart
;
opCount
++;
// if (opElapsed > slowOpThresholdNs) {
// FileHelper.writeLogFile("[PERF] serialDecode 慢工序 opId=" + currentOp.getId()
// + ", groupId=" + groupId + ", seq=" + opSequence
// + ", machineId=" + machineId + ", hasBOM="
// + (currentOp.getMaterialRequirements() != null && currentOp.getMaterialRequirements().size() > 0)
// + ", 耗时=" + fmtMs(opElapsed));
// }
orderProcessCounter
.
put
(
groupId
,
orderProcessCounter
.
get
(
groupId
)
+
1
);
orderLastEndTime
.
put
(
groupId
,
actualEndTime
);
...
...
@@ -649,6 +658,13 @@ public class GeneticDecoder {
Map
<
Integer
,
Entry
>
entryIndexById
=
new
HashMap
<>();
Map
<
Integer
,
List
<
Entry
>>
entrysBygroupId
=
new
HashMap
<>();
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
=
new
ConcurrentHashMap
<>();
Map
<
Integer
,
Integer
>
orderDueDate
=
new
HashMap
<>();
for
(
Order
order
:
chromosome
.
getOrders
())
{
int
end
=
(
int
)
ChronoUnit
.
SECONDS
.
between
(
baseTime
,
order
.
getDueDate
());
orderDueDate
.
putIfAbsent
(
order
.
getId
(),
end
);
}
for
(
Entry
op
:
allOperations
)
{
int
groupId
=
op
.
getGroupId
();
orderProcessCounter
.
putIfAbsent
(
groupId
,
0
);
...
...
@@ -790,11 +806,11 @@ public class GeneticDecoder {
// 工序超过500的设备直接在主线程串行处理
if
(
ops
.
size
()
>
500
)
{
// FileHelper.writeLogFile("设备 " + machineId + " 有 " + ops.size() + " 个工序,直接串行处理");
processMachineOps
(
chromosome
,
machineId
,
ops
,
dependencyGraph
,
opCompleted
,
lock
,
opMachineKeyMap
,
machineIdMap
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
processMachineOps
(
chromosome
,
machineId
,
ops
,
dependencyGraph
,
opCompleted
,
lock
,
opMachineKeyMap
,
machineIdMap
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
,
orderDueDate
);
}
else
{
// 工序少的设备创建线程处理
Thread
thread
=
new
Thread
(()
->
{
processMachineOps
(
chromosome
,
machineId
,
ops
,
dependencyGraph
,
opCompleted
,
lock
,
opMachineKeyMap
,
machineIdMap
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
processMachineOps
(
chromosome
,
machineId
,
ops
,
dependencyGraph
,
opCompleted
,
lock
,
opMachineKeyMap
,
machineIdMap
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
,
orderDueDate
);
});
thread
.
start
();
threads
.
add
(
thread
);
...
...
@@ -824,7 +840,7 @@ public class GeneticDecoder {
*/
private
void
processMachineOps
(
Chromosome
chromosome
,
Long
machineId
,
List
<
Entry
>
ops
,
Map
<
Integer
,
List
<
Integer
>>
dependencyGraph
,
Map
<
Integer
,
Boolean
>
opCompleted
,
Object
lock
,
Map
<
String
,
OpMachine
>
opMachineKeyMap
,
Map
<
Long
,
Machine
>
machineIdMap
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
)
{
Map
<
Integer
,
Boolean
>
opCompleted
,
Object
lock
,
Map
<
String
,
OpMachine
>
opMachineKeyMap
,
Map
<
Long
,
Machine
>
machineIdMap
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
,
Map
<
Integer
,
Integer
>
orderDueDate
)
{
//long machineStartTime = System.currentTimeMillis();
for
(
int
i
=
0
;
i
<
ops
.
size
();
i
++)
{
...
...
@@ -858,9 +874,10 @@ public class GeneticDecoder {
double
processTime
=
machineOption
.
getProcessingTime
();
int
orderDueDate1
=
orderDueDate
.
get
(
op
.
getGroupId
());
// 处理当前工序
// long processStartTime = System.currentTimeMillis();
int
actualEndTime
=
processOperation
(
op
,
machineId
,
processTime
,
machineOption
,
chromosome
,
machineIdMap
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
int
actualEndTime
=
processOperation
(
op
,
machineId
,
processTime
,
machineOption
,
chromosome
,
machineIdMap
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
,
orderDueDate1
,
false
);
// long processEndTime = System.currentTimeMillis();
...
...
@@ -1018,28 +1035,37 @@ public class GeneticDecoder {
private
int
processOperation
(
Entry
currentOp
,
Long
machineId
,
double
processTime
,
OpMachine
machineOption
,
Chromosome
chromosome
,
Map
<
Long
,
Machine
>
machineIdMap
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
)
private
int
processOperation
(
Entry
currentOp
,
Long
machineId
,
double
processTime
,
OpMachine
machineOption
,
Chromosome
chromosome
,
Map
<
Long
,
Machine
>
machineIdMap
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
,
int
orderDueDate
,
boolean
isJit
)
{
Machine
targetMachine
=
machineIdMap
.
get
(
machineId
);
int
prevtime
=
0
;
//后处理时间
int
teardownTime
=
currentOp
.
getTeardownTime
();
// int teardownTime = currentOp.getTeardownTime();
if
(
isJit
)
{
prevtime
=
orderDueDate
;
if
(!
currentOp
.
getNextEntryIds
().
isEmpty
())
{
// 处理多个前工序
prevtime
=
CalNexttime
(
prevtime
,
currentOp
,
chromosome
,
processTime
,
targetMachine
,
entryIndexById
,
scheduleIndexById
);
}
}
else
{
if
(!
currentOp
.
getPrevEntryIds
().
isEmpty
())
{
// 处理多个前工序
prevtime
=
CalPrevtime
(
prevtime
,
currentOp
,
chromosome
,
processTime
,
targetMachine
,
entryIndexById
,
scheduleIndexById
);
prevtime
=
CalPrevtime
(
prevtime
,
currentOp
,
chromosome
,
processTime
,
targetMachine
,
entryIndexById
,
scheduleIndexById
);
}
}
int
prevendtime
=
prevtime
;
Machine
machine
=
machineIdMap
.
get
(
machineId
);
int
actualEndTime
=
processWithSingleMachine
(
currentOp
,
machine
,
processTime
,
prevtime
,
machineOption
,
chromosome
,
false
,
prevendtime
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
int
actualEndTime
=
processWithSingleMachine
(
currentOp
,
machine
,
processTime
,
prevtime
,
machineOption
,
chromosome
,
false
,
prevendtime
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
,
isJit
);
return
actualEndTime
;
}
private
int
processWithSingleMachine
(
Entry
operation
,
Machine
machine
,
double
processingTime
,
int
prevOperationEndTime
,
OpMachine
machineOption
,
Chromosome
chromosome
,
boolean
calbom
,
int
prevendtime
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
)
{
int
prevOperationEndTime
,
OpMachine
machineOption
,
Chromosome
chromosome
,
boolean
calbom
,
int
prevendtime
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
,
boolean
isJit
)
{
long
pwsStart
=
System
.
nanoTime
();
int
processingTimeTotal
=
0
;
int
earliestStartTime
=
prevOperationEndTime
;
...
...
@@ -1097,18 +1123,84 @@ public class GeneticDecoder {
earliestStartTime
=
Math
.
max
(
earliestStartTime
,
jitPreferredStartTime
);
}
if
(
machine
.
getCapacityTypeName
().
equals
(
"Infinite"
))
{
int
endTime
=
0
;
int
startTime
=
0
;
processingTimeTotal
=(
int
)
Math
.
ceil
(
processingTime
);
if
(
isJit
)
{
endTime
=
earliestStartTime
;
startTime
=
endTime
-
processingTimeTotal
;
}
else
{
startTime
=
earliestStartTime
;
endTime
=
startTime
+
processingTimeTotal
;
}
GAScheduleResult
result
=
CreateResult
(
operation
,
machine
.
getId
(),
startTime
,
endTime
,
processingTime
,
0
,
preTime
,
teardownTime
,
0
,
null
,
existingResult
);
chromosome
.
getResult
().
add
(
result
);
machine
.
setLastGene
(
result
);
scheduleIndexById
.
put
(
operation
.
getId
(),
result
);
return
endTime
;
}
// baseEarliestStartTime:不考虑 BOM 推迟时的理论最早开工时间。
// candidateStartTime:固定点迭代时本轮尝试的开工时间。
// bomtime:按当前候选开工时间试算出来的物料最早可开工时间。
int
baseEarliestStartTime
=
earliestStartTime
;
int
candidateStartTime
=
earliestStartTime
;
if
(
operation
.
getTargetFinishedOperationId
()
!=
null
&&
!
operation
.
getTargetFinishedOperationId
().
isEmpty
())
{
// 1. 计算成品可用时间
GeneticDecoderBom
bom
=
new
GeneticDecoderBom
();
int
finishedAvailableTime
=
bom
.
calculateFinishedAvailableTime
(
operation
,
chromosome
,
baseTime
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
if
(
finishedAvailableTime
>
0
)
{
// 2. 计算半成品最晚开工时间(倒排:半成品结束时间 = 成品可用时间,然后往前推加工时间)
// 加上JIT缓冲时间(如果有)
int
semiBufferMinutes
=
_globalParam
.
getSemiJitBufferMinutes
();
int
semiBufferSeconds
=
semiBufferMinutes
*
60
;
// 半成品最晚结束时间 = 成品可用时间 - 缓冲
int
semiLatestEndTime
=
Math
.
max
(
0
,
finishedAvailableTime
-
semiBufferSeconds
);
// 半成品最晚开工时间 = 半成品最晚结束时间 - 加工总时长
int
semiLatestStartTime
=
Math
.
max
(
0
,
semiLatestEndTime
-
processingTimeTotal
);
// 3. 计算半成品物料的BOM齐套时间(正向)
int
semiBomTime
=
getOperationBOMTime
(
operation
,
chromosome
);
// 4. 比较:如果倒排的开工时间早于基准时间或BOM齐套时间,则从基准时间或BOM齐套时间开始正排
int
semiForwardStartTime
=
Math
.
max
(
baseEarliestStartTime
,
semiBomTime
);
if
(
semiLatestStartTime
>=
semiForwardStartTime
)
{
// 倒排可行:使用倒排的最晚开工时间
candidateStartTime
=
semiLatestStartTime
;
}
else
{
// 倒排不可行:使用正排的最早开工时间
candidateStartTime
=
semiForwardStartTime
;
}
// 更新基准最早开工时间
baseEarliestStartTime
=
candidateStartTime
;
}
}
int
setupTime
=
0
;
long
machineId
=
machine
.
getId
();
// 只有存在物料约束(或本次被强制要求重算 BOM)的工序,才需要联立求解“机台何时能排”和“物料何时可用”。
// targetFinishedOperationId != null 的工序通常由前置成品工序驱动,这里不再额外触发一轮 BOM 试算。
boolean
needMaterialCheck
=(
operation
.
getMaterialRequirements
()!=
null
&&
operation
.
getMaterialRequirements
().
size
()>
0
&&
operation
.
getTargetFinishedOperationId
()==
null
)||
calbom
;
boolean
needMaterialCheck
=
false
;
//
(operation.getMaterialRequirements()!=null&&operation.getMaterialRequirements().size()>0&&operation.getTargetFinishedOperationId()==null)||calbom;
// 正式落排后还要再做一次带提交的物料校验,把试算阶段推导出的 BOM 状态真正写回 chromosome。
boolean
commitMaterialCheck
=
needMaterialCheck
;
// baseEarliestStartTime:不考虑 BOM 推迟时的理论最早开工时间。
// candidateStartTime:固定点迭代时本轮尝试的开工时间。
// bomtime:按当前候选开工时间试算出来的物料最早可开工时间。
int
baseEarliestStartTime
=
earliestStartTime
;
int
candidateStartTime
=
earliestStartTime
;
baseEarliestStartTime
=
earliestStartTime
;
candidateStartTime
=
earliestStartTime
;
int
bomtime
=
0
;
// 机台时间和物料时间可能会互相推动,最多迭代 maxSolveIterations 次来找收敛点。
int
maxSolveIterations
=
Math
.
max
(
1
,
_globalParam
.
getMaterialSolveMaxIterations
());
...
...
@@ -1197,44 +1289,8 @@ public class GeneticDecoder {
lastGeneOnMachine
=
getLastMachineTask
(
machineTasks
);
needMaterialCheck
=
false
;
}
// 旧兜底单次试算路径:当前固定点迭代执行完后会把 needMaterialCheck 置为 false,
// 因此这段分支实际上不会再进入。先注释保留,后续若确认无用可直接删除,
// 或按真实意图改成 !converged 时的兜底处理。
// if(needMaterialCheck) {
// int earliestStartTimeold=earliestStartTime;
// if (_globalParam.is_smoothChangeOver()) {
//
// Map<Integer, Object> reslte = calculateSetupTime(lastGeneOnMachine, operation, machine, earliestStartTime, processingTimeTotal, _globalParam.is_smoothChangeOverInWeek(), chromosome.getAllOperations());
// // setupTime = (int) reslte.get(1);//换型时间
// // int setupStartTime = (int) reslte.get(2);//换型开始时间
// //earliestStartTime=(int)reslte.get(3);//上个任务的结束时间
// earliestStartTime = (int) reslte.get(4);//最早开工时间
// }
// LocalDateTime startTime1 = baseTime.plus(earliestStartTime, ChronoUnit.SECONDS);
//
// TimeSegment slot = machineCalculator.GetCurrentOrNextShift(machine, startTime1, "", false);
//
// if(slot!=null)
// {
// earliestStartTime = slot.getStart().isAfter(startTime1)
// ?(int) ChronoUnit.SECONDS.between(baseTime, slot.getStart())
// : earliestStartTime;
//
// }
// bomtime= EditOperationBOMTime(operation,chromosome,earliestStartTime,machineTasksCache, entryIndexById, scheduleIndexById, false);
//
//
// earliestStartTime = Math.max(earliestStartTime, bomtime);
// }
// machineTasks =chromosome.getResult().stream()
// .filter(t -> t.getMachineId() == machine.getId())
// .sorted(Comparator.comparingInt(GAScheduleResult::getStartTime))
// .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
//
// machineTasksCache.put(machine.getId(), machineTasks);
// 正式落排前,再取一次当前机台最后一道工序,保证换型计算基于最新排程结果。
if
(
machineTasks
!=
null
&&
machineTasks
.
size
()>
0
&&
_globalParam
.
is_smoothChangeOver
())
{
...
...
@@ -1243,7 +1299,8 @@ public class GeneticDecoder {
// 下面开始生成正式的 geneDetails。
// 与 buildMachinePreview 的区别是:这里得到的结果会继续向下写入 GAScheduleResult,成为真正排程结果。
if
(
_globalParam
.
is_smoothChangeOver
())
{
//if (_globalParam.is_smoothChangeOver()) {
if
(
false
)
{
//是否考虑换型时间
Map
<
Integer
,
Object
>
reslte
=
calculateSetupTime
(
lastGeneOnMachine
,
operation
,
machine
,
earliestStartTime
,
processingTimeTotal
,
_globalParam
.
is_smoothChangeOverInWeek
(),
chromosome
.
getAllOperations
());
setupTime
=(
int
)
reslte
.
get
(
1
);
//换型时间
...
...
@@ -1253,14 +1310,14 @@ public class GeneticDecoder {
processingTimeTotal
=(
int
)
reslte
.
get
(
5
);
//processingTimeTotal
if
(
setupTime
==
0
)
{
geneDetails
=
machineCalculator
.
getNextAvailableTime
(
machine
,
earliestStartTime
,
-
1
,
processingTimeTotal
,
machineTasks
,
operation
.
getIsInterrupt
()!=
1
,
true
,
processingTime
,
operation
.
getQuantity
(),
true
);
geneDetails
=
machineCalculator
.
getNextAvailableTime
(
machine
,
operation
,
earliestStartTime
,
-
1
,
processingTimeTotal
,
machineTasks
,
operation
.
getIsInterrupt
()!=
1
,
true
,
processingTime
,
operation
.
getQuantity
(),
true
,
isJit
);
}
else
{
CopyOnWriteArrayList
<
TimeSegment
>
AvailableTimeSegment
=
(
CopyOnWriteArrayList
<
TimeSegment
>)
reslte
.
get
(
6
);
Map
<
Integer
,
Object
>
result
=
machineCalculator
.
CreateScheduleResult
(
machine
,
processingTimeTotal
,
earliestStartTime
,
AvailableTimeSegment
,
processingTime
,
operation
.
getQuantity
(),
operation
.
getIsInterrupt
()
!=
1
,
setupTime
,
_globalParam
.
is_smoothChangeOverInWeek
(),
setupStartTime
);
Map
<
Integer
,
Object
>
result
=
machineCalculator
.
CreateScheduleResult
(
machine
,
operation
,
processingTimeTotal
,
earliestStartTime
,
AvailableTimeSegment
,
processingTime
,
operation
.
getQuantity
(),
operation
.
getIsInterrupt
()
!=
1
,
setupTime
,
_globalParam
.
is_smoothChangeOverInWeek
(),
setupStartTime
,
isJit
);
...
...
@@ -1269,8 +1326,8 @@ public class GeneticDecoder {
geneDetails
=(
CopyOnWriteArrayList
<
ScheduleResultDetail
>)
result
.
get
(
2
);
}
}
else
{
geneDetails
=
machineCalculator
.
getNextAvailableTime
(
machine
,
earliestStartTime
,
-
1
,
processingTimeTotal
,
machineTasks
,
operation
.
getIsInterrupt
()!=
1
,
true
,
processingTime
,
operation
.
getQuantity
(),
true
);
geneDetails
=
machineCalculator
.
getNextAvailableTime
(
machine
,
operation
,
earliestStartTime
,
-
1
,
processingTimeTotal
,
machineTasks
,
operation
.
getIsInterrupt
()!=
1
,
true
,
processingTime
,
operation
.
getQuantity
(),
true
,
isJit
);
}
...
...
@@ -1397,7 +1454,8 @@ public class GeneticDecoder {
}
int
processingTimeTotal1
=
0
;
if
(
geneDetails
!=
null
&&
geneDetails
.
size
()>
0
)
{
processingTimeTotal1
=(
int
)
geneDetails
.
stream
().
filter
(
t
->
t
.
getUsedSegment
()==
null
).
mapToDouble
(
ScheduleResultDetail:
:
getProcessingTime
)
// 替换为实际字段名
.
sum
();
...
...
@@ -1413,9 +1471,13 @@ public class GeneticDecoder {
.
sum
();
}
result
.
setProcessingTime
(
processingTimeTotal1
);
result
.
setGeneDetails
(
geneDetails
);
}
else
{
processingTimeTotal1
=
endTime
-
startTime
;
}
result
.
setProcessingTime
(
processingTimeTotal1
);
return
result
;
}
...
...
@@ -1476,22 +1538,22 @@ public class GeneticDecoder {
if
(
setupTime
==
0
)
{
// 没有换型占用时,直接查机台下一段可排的可用窗口。
geneDetails
=
machineCalculator
.
getNextAvailableTime
(
machine
,
previewStart
,
-
1
,
previewProcessingTotal
,
machineTasks
,
operation
.
getIsInterrupt
()!=
1
,
true
,
processingTime
,
operation
.
getQuantity
(),
true
);
geneDetails
=
machineCalculator
.
getNextAvailableTime
(
machine
,
operation
,
previewStart
,
-
1
,
previewProcessingTotal
,
machineTasks
,
operation
.
getIsInterrupt
()!=
1
,
true
,
processingTime
,
operation
.
getQuantity
(),
true
,
false
);
}
else
{
// 有换型占用时,需要把换型段和加工段一起拼成完整的试排结果。
CopyOnWriteArrayList
<
TimeSegment
>
AvailableTimeSegment
=
(
CopyOnWriteArrayList
<
TimeSegment
>)
reslte
.
get
(
6
);
Map
<
Integer
,
Object
>
result
=
machineCalculator
.
CreateScheduleResult
(
machine
,
previewProcessingTotal
,
previewStart
,
AvailableTimeSegment
,
processingTime
,
operation
.
getQuantity
(),
operation
.
getIsInterrupt
()
!=
1
,
setupTime
,
_globalParam
.
is_smoothChangeOverInWeek
(),
setupStartTime
);
Map
<
Integer
,
Object
>
result
=
machineCalculator
.
CreateScheduleResult
(
machine
,
operation
,
previewProcessingTotal
,
previewStart
,
AvailableTimeSegment
,
processingTime
,
operation
.
getQuantity
(),
operation
.
getIsInterrupt
()
!=
1
,
setupTime
,
_globalParam
.
is_smoothChangeOverInWeek
(),
setupStartTime
,
false
);
setupTime
=(
int
)
result
.
get
(
1
);
geneDetails
=(
CopyOnWriteArrayList
<
ScheduleResultDetail
>)
result
.
get
(
2
);
}
}
else
{
// 不考虑平滑换型时,只需要找加工段可用窗口。
geneDetails
=
machineCalculator
.
getNextAvailableTime
(
machine
,
previewStart
,
-
1
,
previewProcessingTotal
,
machineTasks
,
operation
.
getIsInterrupt
()!=
1
,
true
,
processingTime
,
operation
.
getQuantity
(),
true
);
geneDetails
=
machineCalculator
.
getNextAvailableTime
(
machine
,
operation
,
previewStart
,
-
1
,
previewProcessingTotal
,
machineTasks
,
operation
.
getIsInterrupt
()!=
1
,
true
,
processingTime
,
operation
.
getQuantity
(),
true
,
false
);
}
// geneDetails 可能跨多个班次/时段,开始时间取最小值,结束时间取最大值。
...
...
@@ -1648,6 +1710,36 @@ public class GeneticDecoder {
}
/**
* 计算后序结束时间
* @param nexttime
* @param currentOp
* @param chromosome
* @return
*/
private
int
CalNexttime
(
int
nexttime
,
Entry
currentOp
,
Chromosome
chromosome
,
double
processTime
,
Machine
machine
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
)
{
List
<
OperationDependency
>
FsOperations
=
currentOp
.
getNextEntryIds
().
stream
()
.
filter
(
t
->
t
.
getDependencyType
()
==
DependencyType
.
FinishToStart
)
.
collect
(
Collectors
.
toList
());
//串行
if
(
FsOperations
!=
null
&&
FsOperations
.
size
()
>
0
)
{
for
(
OperationDependency
opid
:
FsOperations
)
{
// List<GAScheduleResult> prevOperations = chromosome.getResult().stream()
// .filter(t -> t.getOperationId() == opid.getPrevOperationId())
// .collect(Collectors.toList());//
GAScheduleResult
nextOp
=
scheduleIndexById
.
get
(
opid
.
getNextOperationId
());
// for (GAScheduleResult prevOp : prevOperations) {
if
(
nextOp
!=
null
){
//加上后处理时间
nexttime
=
Math
.
min
(
nexttime
,
nextOp
.
getStartTime
());
}
}
}
return
nexttime
;
}
private
int
CalSSPrevtime
(
List
<
GAScheduleResult
>
newScheduleResult
,
List
<
ScheduleResultDetail
>
newScheduleResultDetails
,
int
prevtime
,
Entry
currentOp
,
Chromosome
chromosome
,
double
processTime
,
Machine
machine
)
{
int
prevperationEndTime
=
newScheduleResult
.
stream
()
...
...
@@ -2021,7 +2113,7 @@ public class GeneticDecoder {
.
findFirst
()
.
orElse
(
null
);
// 缓存机器任务
int
actualEndTime
=
processWithSingleMachine
(
currentOp
,
machine
,
processTime
,
prevtime
,
opMachine
,
chromosome
,
true
,
prevendtime
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
int
actualEndTime
=
processWithSingleMachine
(
currentOp
,
machine
,
processTime
,
prevtime
,
opMachine
,
chromosome
,
true
,
prevendtime
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
,
true
);
}
...
...
src/main/java/com/aps/service/Algorithm/GeneticDecoderBom.java
0 → 100644
View file @
6f7aeeba
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.entity.Algorithm.Chromosome
;
import
com.aps.entity.Algorithm.GAScheduleResult
;
import
com.aps.entity.Algorithm.OperationDependency
;
import
com.aps.entity.Algorithm.OrderMaterialRequirement
;
import
com.aps.entity.basic.Entry
;
import
com.aps.entity.basic.Machine
;
import
java.time.LocalDateTime
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.CopyOnWriteArrayList
;
/**
* 作者:佟礼
* 时间:2026-04-28
*/
public
class
GeneticDecoderBom
{
/**
* 计算成品可用时间(用于半成品排程)
*
* @param semiFinishedOperation 半成品工序
* @param chromosome 染色体
* @param baseTime 基准时间
* @param machineTasksCache 设备任务缓存
* @param entryIndexById 工序索引
* @param scheduleIndexById 排程索引
* @return 成品可用时间(秒)
*/
public
int
calculateFinishedAvailableTime
(
Entry
semiFinishedOperation
,
Chromosome
chromosome
,
LocalDateTime
baseTime
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
)
{
// 如果没有关联的成品工序,返回0
if
(
semiFinishedOperation
.
getTargetFinishedOperationId
()
==
null
||
semiFinishedOperation
.
getTargetFinishedOperationId
().
isEmpty
())
{
return
0
;
}
int
maxFinishedTime
=
0
;
// 遍历所有关联的成品工序,计算每个的可用时间,取最大值
for
(
Integer
finishedOperationId
:
semiFinishedOperation
.
getTargetFinishedOperationId
())
{
Entry
finishedOperation
=
entryIndexById
.
get
(
finishedOperationId
);
if
(
finishedOperation
==
null
)
{
continue
;
}
// 计算该成品工序的可用时间
int
finishedAvailableTime
=
calculateSingleFinishedAvailableTime
(
finishedOperation
,
chromosome
,
baseTime
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
maxFinishedTime
=
Math
.
min
(
maxFinishedTime
,
finishedAvailableTime
);
}
return
maxFinishedTime
;
}
/**
* 计算单个成品工序的可用时间
*
* @param finishedOperation 成品工序
* @param chromosome 染色体
* @param baseTime 基准时间
* @param machineTasksCache 设备任务缓存
* @param entryIndexById 工序索引
* @param scheduleIndexById 排程索引
* @return 成品工序可用时间(秒)
*/
private
int
calculateSingleFinishedAvailableTime
(
Entry
finishedOperation
,
Chromosome
chromosome
,
LocalDateTime
baseTime
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
)
{
int
maxTime
=
0
;
// 1. 计算成品前一序时间
int
prevOperationEndTime
=
0
;
if
(!
finishedOperation
.
getPrevEntryIds
().
isEmpty
())
{
for
(
OperationDependency
prevOp
:
finishedOperation
.
getPrevEntryIds
())
{
GAScheduleResult
prevResult
=
scheduleIndexById
.
get
(
prevOp
.
getPrevOperationId
());
if
(
prevResult
!=
null
)
{
prevOperationEndTime
=
Math
.
max
(
prevOperationEndTime
,
prevResult
.
getEndTime
());
}
}
}
//成品时间一定晚于prevOperationEndTime
//半成品库存只能用
maxTime
=
Math
.
max
(
maxTime
,
prevOperationEndTime
);
// 2. 计算成品当前序所用设备最后一个任务的结束时间
Long
machineId
=
finishedOperation
.
getSelectMachineID
();
if
(
machineId
==
null
&&
finishedOperation
.
getMachineOptions
()
!=
null
&&
!
finishedOperation
.
getMachineOptions
().
isEmpty
())
{
// 如果设备还未选择,使用第一个可用设备
machineId
=
finishedOperation
.
getMachineOptions
().
get
(
0
).
getMachineId
();
}
if
(
machineId
!=
null
)
{
Long
machineId1
=
machineId
;
Machine
machine
=
chromosome
.
getMachines
().
stream
().
filter
(
t
->
t
.
getId
()==
machineId1
).
findFirst
().
orElse
(
null
);
GAScheduleResult
machineTask
=
machine
.
getLastGene
();
if
(
machineTask
!=
null
)
{
int
lastEndTime
=
machineTask
.
getEndTime
();
maxTime
=
Math
.
max
(
maxTime
,
lastEndTime
);
}
}
// 3. 原材料0库存计算齐套最大时间(只计算原材料,不计算半成品)
int
rawMaterialBomTime
=
calculateRawMaterialBomTimeForFinished
(
finishedOperation
,
chromosome
);
maxTime
=
Math
.
max
(
maxTime
,
rawMaterialBomTime
);
return
maxTime
;
}
/**
* 计算成品工序的原材料齐套时间(只计算原材料MP,不计算半成品)
*/
private
int
calculateRawMaterialBomTimeForFinished
(
Entry
finishedOperation
,
Chromosome
chromosome
)
{
List
<
OrderMaterialRequirement
>
materialReqs
=
finishedOperation
.
getMaterialRequirements
();
if
(
materialReqs
==
null
)
{
return
0
;
}
int
maxTime
=
0
;
for
(
OrderMaterialRequirement
req
:
materialReqs
)
{
if
(
"MP"
.
equals
(
req
.
getMaterialTypeName
()))
{
// 只计算原材料
// 计算原材料采购提前期
int
purchaseTime
=
req
.
getPurchaseTime
()
!=
null
?
req
.
getPurchaseTime
()
:
0
;
int
checkLeadTime
=
req
.
getCheckLeadTime
()
!=
null
?
req
.
getCheckLeadTime
()
:
0
;
int
totalDays
=
purchaseTime
+
checkLeadTime
;
int
totalSeconds
=
totalDays
*
24
*
3600
;
maxTime
=
Math
.
max
(
maxTime
,
totalSeconds
);
}
}
return
maxTime
;
}
}
src/main/java/com/aps/service/Algorithm/MachineCalculator.java
View file @
6f7aeeba
...
...
@@ -8,6 +8,7 @@ import com.aps.entity.basic.*;
import
com.aps.service.plan.MachineSchedulerService
;
import
com.baomidou.mybatisplus.core.toolkit.StringUtils
;
import
com.sun.org.apache.xpath.internal.objects.XBoolean
;
import
java.math.BigDecimal
;
import
java.math.RoundingMode
;
...
...
@@ -42,12 +43,12 @@ public class MachineCalculator {
* 获取机器下一个可用时间窗口(考虑班次约束)
*/
// 从 proposedStartTime 开始查找机台下一段可排窗口;必要时会把命中的 availability 临时标记为已占用。
public
CopyOnWriteArrayList
<
ScheduleResultDetail
>
getNextAvailableTime
(
Machine
machine
,
int
proposedStartTime
,
public
CopyOnWriteArrayList
<
ScheduleResultDetail
>
getNextAvailableTime
(
Machine
machine
,
Entry
operation
,
int
proposedStartTime
,
int
prevtime
,
int
processingTime
,
CopyOnWriteArrayList
<
GAScheduleResult
>
existingTasks
,
boolean
isInterrupt
,
boolean
istask
,
double
oneTime
,
double
quantity
,
boolean
islockMachineTime
)
{
boolean
islockMachineTime
,
boolean
isJit
)
{
LocalDateTime
startTime
=
baseTime
.
plus
(
proposedStartTime
,
ChronoUnit
.
SECONDS
);
String
prevtimestr
=
""
;
...
...
@@ -57,8 +58,8 @@ public class MachineCalculator {
}
// 查找合适的班次窗口
return
findEarliestStart
(
machine
,
processingTime
,
startTime
,
prevtimestr
,
existingTasks
,
oneTime
,
quantity
,
istask
,
islockMachineTime
,
isInterrupt
);
return
findEarliestStart
(
machine
,
operation
,
processingTime
,
startTime
,
prevtimestr
,
existingTasks
,
oneTime
,
quantity
,
istask
,
islockMachineTime
,
isInterrupt
,
isJit
);
}
public
CopyOnWriteArrayList
<
TimeSegment
>
getMachineAvailableTime
(
Machine
machine
,
int
proposedStartTime
,
...
...
@@ -73,9 +74,9 @@ public class MachineCalculator {
// 基于已选可用时段组装排程结果,并把换型段/加工段对应的 availability 临时占用。
public
Map
<
Integer
,
Object
>
CreateScheduleResult
(
Machine
machine
,
int
processingTime
,
int
proposedStartTime
,
CopyOnWriteArrayList
<
TimeSegment
>
timeSegments
,
Machine
machine
,
Entry
operation
,
int
processingTime
,
int
proposedStartTime
,
CopyOnWriteArrayList
<
TimeSegment
>
timeSegments
,
double
oneTime
,
double
quantity
,
boolean
isInterrupt
,
int
changeOvertTime
,
boolean
changeOverInWeek
,
int
setupStartTime
)
{
,
boolean
isInterrupt
,
int
changeOvertTime
,
boolean
changeOverInWeek
,
int
setupStartTime
,
boolean
isJit
)
{
LocalDateTime
startTime
=
baseTime
.
plus
(
proposedStartTime
,
ChronoUnit
.
SECONDS
);
...
...
@@ -165,8 +166,8 @@ public class MachineCalculator {
}
times
=
CaldScheduleResult
(
machine
,
processingTime
,
startTime
,
timeSegments
,
oneTime
,
quantity
machine
,
operation
,
processingTime
,
startTime
,
timeSegments
,
oneTime
,
quantity
,
isJit
);
}
else
{
...
...
@@ -236,8 +237,8 @@ public class MachineCalculator {
.
filter
(
t
->
t
.
getStart
().
compareTo
(
startCandidate
)>=
0
)
.
collect
(
Collectors
.
toCollection
(
CopyOnWriteArrayList:
:
new
));
times
=
CaldScheduleResult
(
machine
,
processingTime
,
startTime
,
timeSegments1
,
oneTime
,
quantity
);
machine
,
operation
,
processingTime
,
startTime
,
timeSegments1
,
oneTime
,
quantity
,
isJit
);
}
else
{
double
e
=
(
double
)
processingTime
/
slot
.
getEfficiency
();
...
...
@@ -271,9 +272,9 @@ public class MachineCalculator {
// 查找最早可用开始时间
private
CopyOnWriteArrayList
<
ScheduleResultDetail
>
findEarliestStart
(
Machine
machine
,
int
processingTime
,
LocalDateTime
currentTime
,
Machine
machine
,
Entry
operation
,
int
processingTime
,
LocalDateTime
currentTime
,
String
prevtime
,
CopyOnWriteArrayList
<
GAScheduleResult
>
existingTasks
,
double
oneTime
,
double
quantity
,
boolean
checkprevtime
,
boolean
islockMachineTime
,
boolean
isInterrupt
)
{
,
boolean
isInterrupt
,
boolean
isJit
)
{
CopyOnWriteArrayList
<
GAScheduleResult
>
machineTasks
=
null
;
if
(
existingTasks
!=
null
&&
existingTasks
.
size
()>
0
)
{
machineTasks
=
existingTasks
.
stream
()
...
...
@@ -284,16 +285,29 @@ public class MachineCalculator {
CopyOnWriteArrayList
<
ScheduleResultDetail
>
times
=
new
CopyOnWriteArrayList
<>();
TimeSegment
slot
=
GetCurrentOrNextShift
(
machine
,
currentTime
,
prevtime
,
checkprevtime
);
TimeSegment
slot
=
GetCurrentOrNextShift
(
machine
,
currentTime
,
prevtime
,
checkprevtime
,
isJit
);
if
(
slot
==
null
)
return
times
;
LocalDateTime
startCandidate
=
null
;
LocalDateTime
endCandidate1
=
null
;
LocalDateTime
prevTimeDateTime
=
StringUtils
.
isEmpty
(
prevtime
)
?
null
:
LocalDateTime
.
parse
(
prevtime
);
LocalDateTime
startCandidate
=
slot
.
getStart
().
isAfter
(
prevTimeDateTime
!=
null
?
prevTimeDateTime
:
currentTime
)
if
(
isJit
)
{
startCandidate
=
slot
.
getStart
();
endCandidate1
=
slot
.
getEnd
().
isAfter
(
prevTimeDateTime
!=
null
?
prevTimeDateTime
:
currentTime
)
?
(
prevTimeDateTime
!=
null
?
prevTimeDateTime
:
currentTime
)
:
slot
.
getEnd
();
}
else
{
startCandidate
=
slot
.
getStart
().
isAfter
(
prevTimeDateTime
!=
null
?
prevTimeDateTime
:
currentTime
)
?
slot
.
getStart
()
:
(
prevTimeDateTime
!=
null
?
prevTimeDateTime
:
currentTime
);
endCandidate1
=
slot
.
getEnd
();
}
// LocalDateTime endCandidate = startCandidate.plusSeconds(processingTime);
long
availableSeconds
=
ChronoUnit
.
SECONDS
.
between
(
startCandidate
,
slot
.
getEnd
()
);
long
availableSeconds
=
ChronoUnit
.
SECONDS
.
between
(
startCandidate
,
endCandidate1
);
//实际可用时间
long
availableSeconds_e
=
Math
.
round
(
availableSeconds
*
slot
.
getEfficiency
())
;
...
...
@@ -301,7 +315,7 @@ public class MachineCalculator {
// if (endCandidate.isAfter(slot.getEnd())) {
if
(
processingTime
>
availableSeconds_e
)
{
return
CaldEarliestStart
(
machine
,
processingTime
,
currentTime
,
prevtime
,
machineTasks
,
oneTime
,
quantity
,
checkprevtime
,
islockMachineTime
,
isInterrup
t
);
return
CaldEarliestStart
(
machine
,
operation
,
processingTime
,
currentTime
,
prevtime
,
machineTasks
,
oneTime
,
quantity
,
checkprevtime
,
islockMachineTime
,
isInterrupt
,
isJi
t
);
}
else
{
...
...
@@ -340,7 +354,7 @@ public class MachineCalculator {
List
<
ScheduleResultDetail
>
oldTimes
=
new
ArrayList
<>();
while
(
remainingTime
>
0
)
{
TimeSegment
shift
=
GetCurrentOrNextShift
(
machine
,
currentTime
,
prevtime
,
checkprevtime
);
TimeSegment
shift
=
GetCurrentOrNextShift
(
machine
,
currentTime
,
prevtime
,
checkprevtime
,
false
);
if
(
shift
==
null
)
break
;
LocalDateTime
shiftStart
=
shift
.
getStart
();
...
...
@@ -403,19 +417,19 @@ public class MachineCalculator {
}
private
CopyOnWriteArrayList
<
ScheduleResultDetail
>
CaldEarliestStart
(
Machine
machine
,
int
processingTime
,
LocalDateTime
currentTime
,
Machine
machine
,
Entry
operation
,
int
processingTime
,
LocalDateTime
currentTime
,
String
prevtime
,
CopyOnWriteArrayList
<
GAScheduleResult
>
machineTasks
,
double
oneTime
,
double
quantity
,
boolean
checkprevtime
,
boolean
islockMachineTime
,
boolean
isInterrupt
)
{
,
boolean
isInterrupt
,
boolean
isJit
)
{
int
remainingTime
=
processingTime
;
LocalDateTime
st
=
StringUtils
.
isEmpty
(
prevtime
)
?
currentTime
:
LocalDateTime
.
parse
(
prevtime
);
LocalDateTime
prevEnd
=
LocalDateTime
.
of
(
2000
,
1
,
1
,
0
,
0
,
0
);
CopyOnWriteArrayList
<
ScheduleResultDetail
>
times
=
new
CopyOnWriteArrayList
<>();
CopyOnWriteArrayList
<
TimeSegment
>
timeSegments
=
findAvailableSegments
(
machine
,
currentTime
,
machineTasks
,
remainingTime
,
isInterrupt
);
CopyOnWriteArrayList
<
TimeSegment
>
timeSegments
=
findAvailableSegments
(
machine
,
currentTime
,
machineTasks
,
remainingTime
,
isInterrupt
,
isJit
);
times
=
CaldScheduleResult
(
machine
,
processingTime
,
currentTime
,
timeSegments
,
oneTime
,
quantity
machine
,
operation
,
processingTime
,
currentTime
,
timeSegments
,
oneTime
,
quantity
,
isJit
);
// int estimateIndex= (int) Math.ceil(remainingTime / (double) ONE_DAY_MINUTES);
...
...
@@ -456,18 +470,26 @@ public class MachineCalculator {
}
private
CopyOnWriteArrayList
<
ScheduleResultDetail
>
CaldScheduleResult
(
Machine
machine
,
int
processingTime
,
LocalDateTime
currentTime
,
Machine
machine
,
Entry
operation
,
int
processingTime
,
LocalDateTime
currentTime
,
CopyOnWriteArrayList
<
TimeSegment
>
timeSegments
,
double
oneTime
,
double
quantity
)
{
,
boolean
isJit
)
{
int
remainingTime
=
processingTime
;
CopyOnWriteArrayList
<
ScheduleResultDetail
>
times
=
new
CopyOnWriteArrayList
<>();
int
estimateIndex
=
(
int
)
Math
.
ceil
(
remainingTime
/
(
double
)
ONE_DAY_MINUTES
);
CopyOnWriteArrayList
<
TimeSegment
>
timeSegments1
=
null
;
if
(
estimateIndex
>
10
)
{
timeSegments1
=
getEnoughSegmentsByEstimateIndex
(
timeSegments
,
currentTime
,
remainingTime
);
timeSegments1
=
getEnoughSegmentsByEstimateIndex
(
timeSegments
,
currentTime
,
remainingTime
,
isJit
);
if
(
timeSegments1
.
size
()==
2
)
{
timeSegments1
=
getEnoughSegmentsByEstimateIndex
(
timeSegments
,
currentTime
,
remainingTime
,
isJit
);
int
i
=
0
;
}
}
if
(
timeSegments1
==
null
)
{
...
...
@@ -476,7 +498,7 @@ public class MachineCalculator {
while
(
remainingTime
>
0
)
{
TimeSegment
shift
=
timeSegments
.
get
(
i
);
Map
<
Integer
,
Object
>
outMap
=
CreateScheduleResultDetail
(
shift
,
currentTime
,
remainingTime
,
oneTime
);
Map
<
Integer
,
Object
>
outMap
=
CreateScheduleResultDetail
(
shift
,
currentTime
,
remainingTime
,
oneTime
,
isJit
);
remainingTime
=
(
int
)
outMap
.
get
(
1
);
ScheduleResultDetail
time
=
(
ScheduleResultDetail
)
outMap
.
get
(
2
);
times
.
add
(
time
);
...
...
@@ -494,16 +516,16 @@ public class MachineCalculator {
machine
.
getAvailability
().
sort
(
Comparator
.
comparing
(
TimeSegment:
:
getStart
));
}
}
else
{
times
=
CaldScheduleResultDetail
(
timeSegments1
,
machine
,
currentTime
,
remainingTime
,
oneTime
);
times
=
CaldScheduleResultDetail
(
timeSegments1
,
machine
,
operation
,
currentTime
,
remainingTime
,
oneTime
,
isJit
);
}
return
times
;
}
private
CopyOnWriteArrayList
<
ScheduleResultDetail
>
CaldScheduleResultDetail
(
CopyOnWriteArrayList
<
TimeSegment
>
timeSegments
,
Machine
machine
,
LocalDateTime
st
,
int
remainingTime
,
double
oneTime
)
private
CopyOnWriteArrayList
<
ScheduleResultDetail
>
CaldScheduleResultDetail
(
CopyOnWriteArrayList
<
TimeSegment
>
timeSegments
,
Machine
machine
,
Entry
operation
,
LocalDateTime
st
,
int
remainingTime
,
double
oneTime
,
boolean
isJit
)
{
int
processable1
=(
int
)
calculateTotalAvailableSecond
(
timeSegments
,
st
);
int
processable1
=(
int
)
calculateTotalAvailableSecond
(
timeSegments
,
st
,
isJit
);
CopyOnWriteArrayList
<
TimeSegment
>
usedSegments
=
new
CopyOnWriteArrayList
<>();
...
...
@@ -512,7 +534,7 @@ public class MachineCalculator {
//第一个数据
TimeSegment
shiftfrist
=
timeSegments
.
get
(
0
);
Map
<
Integer
,
Object
>
outMap
=
CreateScheduleResultDetail
(
shiftfrist
,
st
,
remainingTime
,
oneTime
);
Map
<
Integer
,
Object
>
outMap
=
CreateScheduleResultDetail
(
shiftfrist
,
st
,
remainingTime
,
oneTime
,
isJit
);
remainingTime
=(
int
)
outMap
.
get
(
1
);
ScheduleResultDetail
time1
=(
ScheduleResultDetail
)
outMap
.
get
(
2
);
times
.
add
(
time1
);
...
...
@@ -524,13 +546,16 @@ public class MachineCalculator {
//中间的数据
CopyOnWriteArrayList
<
TimeSegment
>
timeSegments2
=
new
CopyOnWriteArrayList
<>(
timeSegments
.
subList
(
1
,
timeSegments
.
size
()-
1
));
if
(
timeSegments2
==
null
||
timeSegments2
.
size
()==
0
)
{
int
i
=
0
;
}
LocalDateTime
effectiveStart
=
timeSegments2
.
get
(
0
).
getStart
();
LocalDateTime
effectiveend
=
timeSegments2
.
get
(
timeSegments2
.
size
()-
1
).
getEnd
();
int
processable
=(
int
)
calculateTotalAvailableSecond
(
timeSegments2
,
st
);
int
processable
=(
int
)
calculateTotalAvailableSecond
(
timeSegments2
,
st
,
isJit
);
ScheduleResultDetail
time
=
new
ScheduleResultDetail
();
time
.
setKey
(
UUID
.
randomUUID
().
toString
());
time
.
setStartTime
((
int
)
ChronoUnit
.
SECONDS
.
between
(
baseTime
,
effectiveStart
));
...
...
@@ -554,7 +579,7 @@ public class MachineCalculator {
//最后的时间段
TimeSegment
shiftlast
=
timeSegments
.
get
(
timeSegments
.
size
()-
1
);
Map
<
Integer
,
Object
>
outMaplast
=
CreateScheduleResultDetail
(
shiftlast
,
st
,
remainingTime
,
oneTime
);
Map
<
Integer
,
Object
>
outMaplast
=
CreateScheduleResultDetail
(
shiftlast
,
st
,
remainingTime
,
oneTime
,
isJit
);
remainingTime
=(
int
)
outMaplast
.
get
(
1
);
ScheduleResultDetail
timelast
=(
ScheduleResultDetail
)
outMaplast
.
get
(
2
);
times
.
add
(
timelast
);
...
...
@@ -571,15 +596,32 @@ public class MachineCalculator {
return
times
;
}
private
Map
<
Integer
,
Object
>
CreateScheduleResultDetail
(
TimeSegment
shift
,
LocalDateTime
st
,
int
remainingTime
,
double
oneTime
)
private
Map
<
Integer
,
Object
>
CreateScheduleResultDetail
(
TimeSegment
shift
,
LocalDateTime
st
,
int
remainingTime
,
double
oneTime
,
boolean
isJit
)
{
LocalDateTime
shiftStart
=
shift
.
getStart
();
LocalDateTime
shiftEnd
=
shift
.
getEnd
();
// 计算有效时间
LocalDateTime
effectiveStart
=
null
;
LocalDateTime
effectiveEnd
=
null
;
if
(
isJit
)
{
effectiveStart
=
shiftStart
;
effectiveEnd
=
st
.
isBefore
(
shiftEnd
)
?
st
:
shiftEnd
;
}
else
{
// 计算有效时间
LocalDateTime
effectiveStart
=
st
.
isAfter
(
shiftStart
)
?
st
:
shiftStart
;
long
availableSeconds
=
ChronoUnit
.
SECONDS
.
between
(
effectiveStart
,
shiftEnd
);
effectiveStart
=
st
.
isAfter
(
shiftStart
)
?
st
:
shiftStart
;
effectiveEnd
=
shiftEnd
;
}
long
availableSeconds
=
ChronoUnit
.
SECONDS
.
between
(
effectiveStart
,
effectiveEnd
);
long
availableSeconds_e
=
Math
.
round
(
availableSeconds
*
shift
.
getEfficiency
())
;
// 处理当前班次
...
...
@@ -610,7 +652,6 @@ public class MachineCalculator {
return
outMap
;
}
/**
* 查找满足时长要求的无冲突可用时段
* @param machine 设备
...
...
@@ -626,6 +667,169 @@ public class MachineCalculator {
CopyOnWriteArrayList
<
GAScheduleResult
>
machineTasks
,
double
requiredMinutes
,
boolean
requireContinuous
)
{
return
findAvailableSegments
(
machine
,
start
,
machineTasks
,
requiredMinutes
,
requireContinuous
,
false
);
}
/**
* 查找满足时长要求的无冲突可用时段
* @param machine 设备
* @param start 起始时间
* @param machineTasks 设备已有任务
* @param requiredMinutes 工单所需总时长(分钟)
* @param requireContinuous 是否不可中断(true=不可中断)
* @return 满足条件的可用片段列表
*/
private
CopyOnWriteArrayList
<
TimeSegment
>
findAvailableSegments
(
Machine
machine
,
LocalDateTime
start
,
CopyOnWriteArrayList
<
GAScheduleResult
>
machineTasks
,
double
requiredMinutes
,
boolean
requireContinuous
,
boolean
isJit
)
{
List
<
TimeSegment
>
availableSegments
=
new
ArrayList
<>();
LocalDateTime
current
=
start
;
// 预先排序设备可用片段,避免后续遍历混乱
// List<TimeSegment> allUseTimeSegment = machine.getAvailability().stream()
// .filter(slot -> !slot.isUsed() && slot.getType() != SegmentType.MAINTENANCE)
// .sorted(Comparator.comparing(TimeSegment::getStart, (a, b) -> a.compareTo(b)))
// .collect(Collectors.toList());
// 替换while(true),增加明确退出条件(原逻辑保留,可根据业务补充退出判断)
while
(
true
)
{
// 统一过滤逻辑:消除重复的FindAll代码
CopyOnWriteArrayList
<
TimeSegment
>
useSegments
=
filterValidUseSegments
(
machine
.
getAvailability
(),
current
,
requireContinuous
,
requiredMinutes
,
isJit
);
if
(
useSegments
!=
null
&&
!
useSegments
.
isEmpty
())
{
// 计算可用时间总和(保留原有逻辑)
double
totalUseTime
=
calculateTotalAvailableSecond
(
useSegments
,
current
,
isJit
);
//倒排,可用时间不够,应该重新正排
if
(
totalUseTime
<
requiredMinutes
&&
isJit
)
{
return
null
;
}
// 不足所需时长时,自动生成未来片段并补充
while
(
totalUseTime
<
requiredMinutes
)
{
// 生成未来1天的片段(基于当前可用片段的最大结束时间)
LocalDateTime
lastSegmentEnd
=
machine
.
getAvailability
().
stream
()
.
max
(
Comparator
.
comparing
(
TimeSegment:
:
getEnd
,
(
a
,
b
)
->
a
.
compareTo
(
b
)))
.
map
(
TimeSegment:
:
getEnd
)
.
orElse
(
current
);
int
days
=((
int
)
((
requiredMinutes
-
totalUseTime
)/
24
/
3600
));
if
(
days
<=
200
)
{
days
=
0
;
}
CopyOnWriteArrayList
<
TimeSegment
>
newSegments
=
machineScheduler
.
generateTimeSegment
(
machine
,
lastSegmentEnd
.
plusDays
(
1
),
days
);
addSegmentsWithDeduplication
(
machine
,
newSegments
);
// 重新过滤可用片段
useSegments
=
filterValidUseSegments
(
machine
.
getAvailability
(),
current
,
requireContinuous
,
requiredMinutes
);
// 重新计算总可用时间
totalUseTime
=
calculateTotalAvailableSecond
(
useSegments
,
current
,
isJit
);
}
// 若总可用时间满足要求,处理冲突
if
(
totalUseTime
>=
requiredMinutes
)
{
// 获取当前可用片段范围内的冲突
LocalDateTime
firstSegmentStart
=
useSegments
.
get
(
0
).
getStart
().
compareTo
(
current
)
<
0
?
current:
useSegments
.
get
(
0
).
getStart
();
LocalDateTime
lastSegmentEnd
=
useSegments
.
get
(
useSegments
.
size
()
-
1
).
getEnd
();
//获取维修和当前任务
CopyOnWriteArrayList
<
TimeSegment
>
conflictSegments
=
getConflictIntervals
(
machine
,
machineTasks
,
firstSegmentStart
,
lastSegmentEnd
);
if
(
conflictSegments
==
null
||
conflictSegments
.
isEmpty
())
{
// 无冲突:直接返回可用片段(保留原有逻辑)
if
(
isJit
)
{
if
(
useSegments
.
get
(
0
).
getEnd
().
compareTo
(
current
)
>
0
)
{
spiltMachineAvailable
(
machine
,
useSegments
.
get
(
0
),
current
,
isJit
);
useSegments
.
get
(
0
).
setEnd
(
current
);
}
}
else
{
if
(
useSegments
.
get
(
0
).
getStart
().
compareTo
(
current
)
<
0
)
{
spiltMachineAvailable
(
machine
,
useSegments
.
get
(
0
),
current
,
isJit
);
useSegments
.
get
(
0
).
setStart
(
current
);
}
}
return
useSegments
;
}
else
{
// 有冲突:可选返回冲突前足够片段或跳过冲突
CopyOnWriteArrayList
<
TimeSegment
>
resultSegments
=
handleConflictsWithSumLogic
(
useSegments
,
conflictSegments
,
current
,
requiredMinutes
,
isJit
);
if
(
resultSegments
!=
null
&&
!
resultSegments
.
isEmpty
())
{
if
(
isJit
)
{
if
(
resultSegments
.
get
(
0
).
getEnd
().
compareTo
(
current
)
>
0
)
{
spiltMachineAvailable
(
machine
,
resultSegments
.
get
(
0
),
current
,
isJit
);
resultSegments
.
get
(
0
).
setEnd
(
current
);
}
}
else
{
if
(
resultSegments
.
get
(
0
).
getStart
().
compareTo
(
current
)
<
0
)
{
spiltMachineAvailable
(
machine
,
resultSegments
.
get
(
0
),
current
,
isJit
);
resultSegments
.
get
(
0
).
setStart
(
current
);
}
}
return
resultSegments
;
}
else
{
// 冲突前片段不足,重置current为最后一个冲突的结束时间,重新查找
if
(
isJit
)
{
LocalDateTime
lastConflictEnd
=
conflictSegments
.
stream
()
.
min
(
Comparator
.
comparing
(
TimeSegment:
:
getEnd
,
(
a
,
b
)
->
a
.
compareTo
(
b
)))
.
map
(
TimeSegment:
:
getStart
)
.
orElse
(
current
);
current
=
lastConflictEnd
;
}
else
{
LocalDateTime
lastConflictEnd
=
conflictSegments
.
stream
()
.
max
(
Comparator
.
comparing
(
TimeSegment:
:
getEnd
,
(
a
,
b
)
->
a
.
compareTo
(
b
)))
.
map
(
TimeSegment:
:
getEnd
)
.
orElse
(
current
);
current
=
lastConflictEnd
;
}
}
}
}
}
else
{
if
(
isJit
)
{
return
null
;
}
// 无可用片段时,生成未来1天的片段
LocalDateTime
lastSegmentEnd
=
machine
.
getAvailability
().
stream
()
.
max
(
Comparator
.
comparing
(
TimeSegment:
:
getEnd
,
(
a
,
b
)
->
a
.
compareTo
(
b
)))
.
map
(
TimeSegment:
:
getEnd
)
.
orElse
(
current
);
CopyOnWriteArrayList
<
TimeSegment
>
newSegments
=
machineScheduler
.
generateTimeSegment
(
machine
,
lastSegmentEnd
.
plusDays
(
1
),
0
);
addSegmentsWithDeduplication
(
machine
,
newSegments
);
}
}
}
/**
* 查找满足时长要求的无冲突可用时段
* @param machine 设备
* @param start 起始时间
* @param machineTasks 设备已有任务
* @param requiredMinutes 工单所需总时长(分钟)
* @param requireContinuous 是否不可中断(true=不可中断)
* @return 满足条件的可用片段列表
*/
private
CopyOnWriteArrayList
<
TimeSegment
>
findAvailableSegments
(
Machine
machine
,
LocalDateTime
start
,
LocalDateTime
end
,
CopyOnWriteArrayList
<
GAScheduleResult
>
machineTasks
,
double
requiredMinutes
,
boolean
requireContinuous
,
boolean
isJit
)
{
List
<
TimeSegment
>
availableSegments
=
new
ArrayList
<>();
LocalDateTime
current
=
start
;
...
...
@@ -642,7 +846,7 @@ public class MachineCalculator {
if
(
useSegments
!=
null
&&
!
useSegments
.
isEmpty
())
{
// 计算可用时间总和(保留原有逻辑)
double
totalUseTime
=
calculateTotalAvailableSecond
(
useSegments
,
current
);
double
totalUseTime
=
calculateTotalAvailableSecond
(
useSegments
,
current
,
isJit
);
// 不足所需时长时,自动生成未来片段并补充
while
(
totalUseTime
<
requiredMinutes
)
{
...
...
@@ -663,7 +867,7 @@ public class MachineCalculator {
// 重新过滤可用片段
useSegments
=
filterValidUseSegments
(
machine
.
getAvailability
(),
current
,
requireContinuous
,
requiredMinutes
);
// 重新计算总可用时间
totalUseTime
=
calculateTotalAvailableSecond
(
useSegments
,
current
);
totalUseTime
=
calculateTotalAvailableSecond
(
useSegments
,
current
,
isJit
);
}
// 若总可用时间满足要求,处理冲突
...
...
@@ -677,16 +881,16 @@ public class MachineCalculator {
if
(
conflictSegments
==
null
||
conflictSegments
.
isEmpty
())
{
// 无冲突:直接返回可用片段(保留原有逻辑)
if
(
useSegments
.
get
(
0
).
getStart
().
compareTo
(
current
)
<
0
)
{
spiltMachineAvailable
(
machine
,
useSegments
.
get
(
0
),
curren
t
);
spiltMachineAvailable
(
machine
,
useSegments
.
get
(
0
),
current
,
isJi
t
);
useSegments
.
get
(
0
).
setStart
(
current
);
}
return
useSegments
;
}
else
{
// 有冲突:可选返回冲突前足够片段或跳过冲突
CopyOnWriteArrayList
<
TimeSegment
>
resultSegments
=
handleConflictsWithSumLogic
(
useSegments
,
conflictSegments
,
current
,
requiredMinutes
);
CopyOnWriteArrayList
<
TimeSegment
>
resultSegments
=
handleConflictsWithSumLogic
(
useSegments
,
conflictSegments
,
current
,
requiredMinutes
,
isJit
);
if
(
resultSegments
!=
null
&&
!
resultSegments
.
isEmpty
())
{
if
(
resultSegments
.
get
(
0
).
getStart
().
compareTo
(
current
)
<
0
)
{
spiltMachineAvailable
(
machine
,
resultSegments
.
get
(
0
),
current
);
spiltMachineAvailable
(
machine
,
resultSegments
.
get
(
0
),
current
,
isJit
);
resultSegments
.
get
(
0
).
setStart
(
current
);
}
return
resultSegments
;
...
...
@@ -712,6 +916,8 @@ public class MachineCalculator {
}
}
private
static
final
int
ONE_DAY_MINUTES
=
24
*
60
*
60
;
// 固定锚点:一天1440分钟,永不改变
/**
...
...
@@ -725,7 +931,7 @@ public class MachineCalculator {
public
CopyOnWriteArrayList
<
TimeSegment
>
getEnoughSegmentsByEstimateIndex
(
CopyOnWriteArrayList
<
TimeSegment
>
availableSegments
,
LocalDateTime
currentTime
,
int
requiredMinutes
)
{
int
requiredMinutes
,
boolean
isJit
)
{
// 基础校验
if
(
availableSegments
==
null
||
availableSegments
.
isEmpty
())
{
throw
new
IllegalArgumentException
(
"可用时段列表不能为空"
);
...
...
@@ -749,13 +955,13 @@ public class MachineCalculator {
int
targetIndex
=
estimateIndex
;
while
(
true
)
{
// 计算当前索引的总有效时长
double
currentTotal
=
calculateTotalMinutesByIndex
(
availableSegments
,
currentTime
,
targetIndex
);
double
currentTotal
=
calculateTotalMinutesByIndex
(
availableSegments
,
currentTime
,
targetIndex
,
isJit
);
if
(
currentTotal
>=
requiredMinutes
)
{
// 总时长满足,尝试往前减索引,找「最小满足索引」(减少后续裁剪的工作量)
if
(
targetIndex
>
0
)
{
double
prevTotal
=
calculateTotalMinutesByIndex
(
availableSegments
,
currentTime
,
targetIndex
-
1
);
double
prevTotal
=
calculateTotalMinutesByIndex
(
availableSegments
,
currentTime
,
targetIndex
-
1
,
isJit
);
if
(
prevTotal
>=
requiredMinutes
)
{
targetIndex
--;
continue
;
...
...
@@ -770,11 +976,11 @@ public class MachineCalculator {
targetIndex
+=
Math
.
max
(
syday
,
5
);
if
(
targetIndex
>=
totalSegmentCount
)
{
// 所有片段总时长不足,抛出异常
double
allTotal
=
calculateTotalMinutesByIndex
(
availableSegments
,
currentTime
,
totalSegmentCount
-
1
);
double
allTotal
=
calculateTotalMinutesByIndex
(
availableSegments
,
currentTime
,
totalSegmentCount
-
1
,
isJit
);
if
(
allTotal
>
requiredMinutes
)
{
double
prevTotal
=
calculateTotalMinutesByIndex
(
availableSegments
,
currentTime
,
targetIndex
-
1
);
double
prevTotal
=
calculateTotalMinutesByIndex
(
availableSegments
,
currentTime
,
targetIndex
-
1
,
isJit
);
if
(
prevTotal
>=
requiredMinutes
)
{
targetIndex
--;
continue
;
...
...
@@ -799,14 +1005,13 @@ public class MachineCalculator {
/**
* 计算从0到指定索引的所有时段的总有效分钟数
*/
private
double
calculateTotalMinutesByIndex
(
CopyOnWriteArrayList
<
TimeSegment
>
segments
,
LocalDateTime
currentTime
,
int
endIndex
)
{
private
double
calculateTotalMinutesByIndex
(
CopyOnWriteArrayList
<
TimeSegment
>
segments
,
LocalDateTime
currentTime
,
int
endIndex
,
boolean
isJit
)
{
return
calculateTotalAvailableSecond
(
new
CopyOnWriteArrayList
(
segments
.
subList
(
0
,
endIndex
)),
currentTime
);
return
calculateTotalAvailableSecond
(
new
CopyOnWriteArrayList
(
segments
.
subList
(
0
,
endIndex
)),
currentTime
,
isJit
);
}
/**
* 统一过滤有效可用片段
*/
...
...
@@ -814,23 +1019,54 @@ public class MachineCalculator {
LocalDateTime
currentTime
,
boolean
requireContinuous
,
double
requiredMinutes
)
{
return
filterValidUseSegments
(
allSegments
,
currentTime
,
requireContinuous
,
requiredMinutes
,
false
);
}
/**
* 统一过滤有效可用片段
*/
private
CopyOnWriteArrayList
<
TimeSegment
>
filterValidUseSegments
(
CopyOnWriteArrayList
<
TimeSegment
>
allSegments
,
LocalDateTime
currentTime
,
boolean
requireContinuous
,
double
requiredMinutes
,
boolean
isJit
)
{
// 空判断
if
(
allSegments
==
null
||
allSegments
.
isEmpty
())
{
return
new
CopyOnWriteArrayList
<>();
}
// 统一过滤条件
CopyOnWriteArrayList
<
TimeSegment
>
baseValidSegments
=
allSegments
.
stream
()
CopyOnWriteArrayList
<
TimeSegment
>
baseValidSegments
=
new
CopyOnWriteArrayList
<>();
if
(
isJit
)
{
baseValidSegments
=
allSegments
.
stream
()
.
filter
(
slot
->
!
slot
.
isUsed
()
// 对应 !slot.IsUsed
&&
slot
.
getType
()
!=
SegmentType
.
MAINTENANCE
// 对应 slot.Type != SegmentType.Maintenance
&&
slot
.
getEnd
().
compareTo
(
currentTime
)
>
0
)
// 对应 slot.End > currentTime
&&
slot
.
getStart
().
compareTo
(
currentTime
)
<
0
)
.
sorted
(
Comparator
.
comparing
(
TimeSegment:
:
getEnd
).
reversed
())
// 对应 slot.End > currentTime
.
collect
(
Collectors
.
toCollection
(
CopyOnWriteArrayList:
:
new
));
}
else
{
baseValidSegments
=
allSegments
.
stream
()
.
filter
(
slot
->
!
slot
.
isUsed
()
// 对应 !slot.IsUsed
&&
slot
.
getType
()
!=
SegmentType
.
MAINTENANCE
// 对应 slot.Type != SegmentType.Maintenance
&&
slot
.
getEnd
().
compareTo
(
currentTime
)
>
0
)
// 对应 slot.End > currentTime
.
collect
(
Collectors
.
toCollection
(
CopyOnWriteArrayList:
:
new
));
}
// 无需不可中断或所需时长无效时,直接返回基础有效片段
if
(!
requireContinuous
||
requiredMinutes
<=
0
)
{
return
baseValidSegments
;
}
if
(
isJit
)
{
return
filterContinuousCompliantSegmentsJit
(
baseValidSegments
,
currentTime
,
requiredMinutes
);
}
// 要求不可中断时,过滤符合连续时长要求的片段
return
filterContinuousCompliantSegments
(
baseValidSegments
,
currentTime
,
requiredMinutes
);
}
...
...
@@ -841,13 +1077,24 @@ public class MachineCalculator {
* @param currentTime 当前时间
* @return 总可用时长(分钟)
*/
private
double
calculateTotalAvailableSecond
(
CopyOnWriteArrayList
<
TimeSegment
>
useSegments
,
LocalDateTime
currentTime
)
{
private
double
calculateTotalAvailableSecond
(
CopyOnWriteArrayList
<
TimeSegment
>
useSegments
,
LocalDateTime
currentTime
,
boolean
isJit
)
{
// 空判断:
if
(
useSegments
==
null
||
useSegments
.
size
()==
0
)
{
return
0.0
;
}
if
(
isJit
)
{
return
useSegments
.
stream
()
.
mapToDouble
(
segment
->
{
// 取片段起始时间和当前时间的最大值,t.End > currentTime ? t.End : currentTime
LocalDateTime
effectiveend
=
segment
.
getEnd
().
compareTo
(
currentTime
)
>
0
?
currentTime
:
segment
.
getEnd
()
;
// 计算单个片段的有效时长(分钟),并乘以效率值,对应C#的 (t.End - effectiveStart).TotalMinutes * t.Efficiency
double
segmentSeconds
=
ChronoUnit
.
SECONDS
.
between
(
segment
.
getStart
(),
effectiveend
);
return
segmentSeconds
*
segment
.
getEfficiency
();
})
.
sum
();
// 累加所有片段的有效时长
}
else
{
return
useSegments
.
stream
()
.
mapToDouble
(
segment
->
{
// 取片段起始时间和当前时间的最大值,t.Start < currentTime ? currentTime : t.Start
...
...
@@ -859,6 +1106,43 @@ public class MachineCalculator {
.
sum
();
// 累加所有片段的有效时长
}
}
/**
* 计算可用片段在指定时间范围内的总有效时长(考虑效率系数)
* @param useSegments 可用片段列表
* @param startTime 起始时间(包含)
* @param endTime 结束时间(包含,可为空表示无上限)
* @return 总可用时长(分钟)
*/
private
double
calculateTotalAvailableSecond
(
CopyOnWriteArrayList
<
TimeSegment
>
useSegments
,
LocalDateTime
startTime
,
LocalDateTime
endTime
)
{
// 空判断:
if
(
useSegments
==
null
||
useSegments
.
size
()==
0
)
{
return
0.0
;
}
return
useSegments
.
stream
()
.
mapToDouble
(
segment
->
{
// 计算有效的起始时间:取 segment.start 和 startTime 的最大值
LocalDateTime
effectiveStart
=
segment
.
getStart
().
compareTo
(
startTime
)
<
0
?
startTime
:
segment
.
getStart
();
// 计算有效的结束时间:取 segment.end 和 endTime 的最小值(如果 endTime 为空,就用 segment.end)
LocalDateTime
effectiveEnd
=
endTime
!=
null
?
(
segment
.
getEnd
().
compareTo
(
endTime
)
>
0
?
endTime
:
segment
.
getEnd
())
:
segment
.
getEnd
();
// 如果有效的起始时间 >= 有效的结束时间,这个片段在范围内没有可用时间
if
(
effectiveStart
.
compareTo
(
effectiveEnd
)
>=
0
)
{
return
0.0
;
}
// 计算单个片段的有效时长(秒),并乘以效率值
double
segmentSeconds
=
ChronoUnit
.
SECONDS
.
between
(
effectiveStart
,
effectiveEnd
);
return
segmentSeconds
*
segment
.
getEfficiency
();
})
.
sum
();
// 累加所有片段的有效时长
}
/**
* 辅助方法:过滤出满足连续时长要求的片段(仅不可中断配置生效时调用)
* 前置剔除零散无效片段,减少后续逻辑处理量
...
...
@@ -922,7 +1206,75 @@ public class MachineCalculator {
}
// 去重并排序(避免重复片段)
return
MergeSegments
(
continuousCompliantSegments
);
return
MergeSegments
(
continuousCompliantSegments
,
false
);
}
/**
* 辅助方法:过滤出满足连续时长要求的片段(仅不可中断配置生效时调用)
* 前置剔除零散无效片段,减少后续逻辑处理量
*/
private
CopyOnWriteArrayList
<
TimeSegment
>
filterContinuousCompliantSegmentsJit
(
CopyOnWriteArrayList
<
TimeSegment
>
baseValidSegments
,
LocalDateTime
currentTime
,
double
requiredContinuous
)
{
// 空判断
if
(
baseValidSegments
==
null
||
baseValidSegments
.
isEmpty
())
{
return
new
CopyOnWriteArrayList
<>();
}
CopyOnWriteArrayList
<
TimeSegment
>
continuousCompliantSegments
=
new
CopyOnWriteArrayList
<>();
CopyOnWriteArrayList
<
TimeSegment
>
tempContinuousGroup
=
new
CopyOnWriteArrayList
<>();
double
tempContinuous
=
0.0
;
LocalDateTime
lastSegmentStart
=
currentTime
;
// baseValidSegments.sort(Comparator.comparing(TimeSegment::getEnd).reversed());
// 遍历基础有效片段,筛选出可拼接成连续时长的片段组
for
(
TimeSegment
segment
:
baseValidSegments
)
{
// 确定有效起始时间:
LocalDateTime
effectiveEnd
=
segment
.
getEnd
().
compareTo
(
currentTime
)
>
0
?
currentTime
:
segment
.
getEnd
();
if
(
effectiveEnd
.
compareTo
(
segment
.
getStart
())
<=
0
)
{
// 该片段无有效时长,跳过,结束时间跑到了开始时间的前面,所以没有可用时长
continue
;
}
// 判断是否与临时连续组无缝衔接
if
(!
tempContinuousGroup
.
isEmpty
()
&&
effectiveEnd
.
compareTo
(
lastSegmentStart
)
!=
0
)
{
// 不衔接:先判断临时组是否满足连续时长,满足则加入结果
if
(
tempContinuous
>=
requiredContinuous
)
{
continuousCompliantSegments
.
addAll
(
tempContinuousGroup
);
}
// 重置临时组
tempContinuousGroup
.
clear
();
tempContinuous
=
0.0
;
}
// 加入临时连续组,累加时长
tempContinuousGroup
.
add
(
segment
);
// 计算当前片段有效时长(分钟)并累加
double
segmentEffective
=
ChronoUnit
.
SECONDS
.
between
(
segment
.
getStart
(),
effectiveEnd
)
*
segment
.
getEfficiency
();
tempContinuous
+=
segmentEffective
;
// 更新最后一个片段开始时间(-1秒)
lastSegmentStart
=
segment
.
getStart
().
plusSeconds
(-
1
);
// 临时组满足连续时长,直接加入结果(提前终止当前组遍历)
if
(
tempContinuous
>=
requiredContinuous
)
{
continuousCompliantSegments
.
addAll
(
tempContinuousGroup
);
// 可选择是否继续遍历(此处继续,获取所有符合条件的片段;也可break直接返回第一个组)
tempContinuousGroup
.
clear
();
tempContinuous
=
0.0
;
}
}
// 遍历结束后,检查最后一个临时组是否满足连续时长
if
(
tempContinuous
>=
requiredContinuous
)
{
continuousCompliantSegments
.
addAll
(
tempContinuousGroup
);
}
// 去重并排序(避免重复片段)
return
MergeSegments
(
continuousCompliantSegments
,
true
);
}
/**
...
...
@@ -989,11 +1341,56 @@ public class MachineCalculator {
CopyOnWriteArrayList
<
TimeSegment
>
useSegments
,
CopyOnWriteArrayList
<
TimeSegment
>
conflictSegments
,
LocalDateTime
currentTime
,
double
requiredMinutes
)
{
double
requiredMinutes
,
boolean
isJit
)
{
if
(
isJit
)
{
// 将冲突片段按结束时间倒序排序(优先处理结束时间晚的冲突)
CopyOnWriteArrayList
<
TimeSegment
>
sortedConflicts
=
new
CopyOnWriteArrayList
<>(
conflictSegments
);
sortedConflicts
.
sort
((
a
,
b
)
->
b
.
getEnd
().
compareTo
(
a
.
getEnd
()));
for
(
TimeSegment
conflict
:
sortedConflicts
)
{
LocalDateTime
currentTime1
=
currentTime
;
//需要获取从conflict.getEnd() 到 currentTime1的
CopyOnWriteArrayList
<
TimeSegment
>
preConflictSegments
=
useSegments
.
stream
()
.
filter
(
slot
->
{
// 情况1: 整个片段完全在 [conflict.getEnd(), currentTime1] 之间
if
(
slot
.
getStart
().
isAfter
(
conflict
.
getEnd
())
&&
slot
.
getEnd
().
isBefore
(
currentTime1
))
{
return
true
;
}
// 情况2: 片段的开始在 currentTime1 之前,但结束在 currentTime1 之后(右端重叠)
if
(
slot
.
getStart
().
isAfter
(
conflict
.
getEnd
())
&&
slot
.
getStart
().
isBefore
(
currentTime1
)
&&
slot
.
getEnd
().
isAfter
(
currentTime1
))
{
return
true
;
}
// 情况3: 片段的开始在 conflict.getEnd() 之前,但结束在 conflict.getEnd() 之后(左端重叠)
if
(
slot
.
getStart
().
isBefore
(
conflict
.
getEnd
())
&&
slot
.
getEnd
().
isAfter
(
conflict
.
getEnd
())
&&
slot
.
getEnd
().
isBefore
(
currentTime1
))
{
return
true
;
}
// 情况4: 片段完全包含整个 [conflict.getEnd(), currentTime1] 范围
if
(
slot
.
getStart
().
isBefore
(
conflict
.
getEnd
())
&&
slot
.
getEnd
().
isAfter
(
currentTime1
))
{
return
true
;
}
return
false
;
})
.
collect
(
Collectors
.
toCollection
(
CopyOnWriteArrayList:
:
new
));
// 计算冲突后片段的总可用时长
double
preConflictTotalTime
=
calculateTotalAvailableSecond
(
preConflictSegments
,
conflict
.
getEnd
(),
currentTime1
);
// 冲突后时长超过所需时长则返回(保留原有判断逻辑),否则更新当前时间跳过冲突
if
(
preConflictTotalTime
>
requiredMinutes
)
{
return
preConflictSegments
;
}
else
{
//更新当前时间为冲突开始时间-1秒
currentTime
=
conflict
.
getStart
().
plusSeconds
(-
1
);
}
}
}
else
{
// 遍历所有冲突片段
for
(
TimeSegment
conflict
:
conflictSegments
)
{
LocalDateTime
currentTime1
=
currentTime
;
LocalDateTime
currentTime1
=
currentTime
;
// 过滤冲突前的可用片段(
CopyOnWriteArrayList
<
TimeSegment
>
preConflictSegments
=
useSegments
.
stream
()
.
filter
(
slot
->
...
...
@@ -1003,7 +1400,7 @@ public class MachineCalculator {
.
collect
(
Collectors
.
toCollection
(
CopyOnWriteArrayList:
:
new
));
// 计算冲突前片段的总可用时长
double
preConflictTotalTime
=
calculateTotalAvailableSecond
(
preConflictSegments
,
currentTime
);
double
preConflictTotalTime
=
calculateTotalAvailableSecond
(
preConflictSegments
,
currentTime
,
isJit
);
// 冲突前时长超过所需时长则返回(保留原有判断逻辑),否则更新当前时间跳过冲突
if
(
preConflictTotalTime
>
requiredMinutes
)
{
...
...
@@ -1013,6 +1410,7 @@ public class MachineCalculator {
currentTime
=
conflict
.
getEnd
().
plusSeconds
(
1
);
}
}
}
// 所有冲突前片段均不足所需时长,返回null(与原C#逻辑一致)
return
null
;
...
...
@@ -1027,7 +1425,7 @@ public class MachineCalculator {
}
machine
.
getAvailability
().
addAll
(
newSegments
);
CopyOnWriteArrayList
<
TimeSegment
>
mergedSegments
=
MergeSegments
(
machine
.
getAvailability
());
CopyOnWriteArrayList
<
TimeSegment
>
mergedSegments
=
MergeSegments
(
machine
.
getAvailability
()
,
false
);
// synchronized (machine.getAvailability()) {
// 合并片段(去重+排序),
...
...
@@ -1062,17 +1460,54 @@ public class MachineCalculator {
/**
* 获取设备当前或下一个有效班次
*/
public
TimeSegment
GetCurrentOrNextShift
(
Machine
machine
,
LocalDateTime
time
,
String
prevtime
,
boolean
checkprevtime
)
{
public
TimeSegment
GetCurrentOrNextShift
(
Machine
machine
,
LocalDateTime
time
,
String
prevtime
,
boolean
checkprevtime
,
boolean
isJit
)
{
TimeSegment
start
=
null
;
if
(
isJit
)
{
if
(!
machine
.
getAvailability
().
isEmpty
())
{
LocalDateTime
machineValidTo
=
machineScheduler
.
GetEndTime
(
machine
.
getId
());
if
(
machineValidTo
.
compareTo
(
time
)<
0
)
{
int
day
=
(
int
)
ChronoUnit
.
DAYS
.
between
(
machineValidTo
,
time
);
List
<
TimeSegment
>
timeSegments
=
machineScheduler
.
generateTimeSegment
(
machine
,
machineValidTo
.
plusDays
(
1
),
day
);
machine
.
getAvailability
().
addAll
(
timeSegments
);
// 更新设备时间线
Machine
originalMachine
=
machines
.
stream
()
.
filter
(
t
->
t
.
getId
()
==
machine
.
getId
())
.
findFirst
()
.
orElse
(
null
);
if
(
originalMachine
!=
null
)
{
MachineTimeline
timeline
=
machineScheduler
.
getOrCreateTimeline
(
originalMachine
);
}
}
start
=
machine
.
getAvailability
().
stream
()
.
filter
(
slot
->
!
slot
.
isUsed
()
&&
slot
.
getType
()
!=
SegmentType
.
MAINTENANCE
)
.
filter
(
slot
->
slot
.
getStart
().
compareTo
(
time
)<
0
)
.
reduce
((
prev
,
current
)
->
current
)
.
orElse
(
null
);
// 没有符合条件的元素时返回null
if
(
start
==
null
)
{
//倒排,没有可用时间
return
null
;
}
}
}
else
{
if
(!
machine
.
getAvailability
().
isEmpty
())
{
start
=
machine
.
getAvailability
().
stream
()
.
filter
(
slot
->
!
slot
.
isUsed
()
&&
slot
.
getType
()
!=
SegmentType
.
MAINTENANCE
)
.
filter
(
slot
->
slot
.
getStart
().
isAfter
(
time
)
||
slot
.
getEnd
().
isAfter
(
time
))
.
findFirst
()
.
orElse
(
null
);
}
else
{
}
else
{
machine
.
setAvailability
(
new
CopyOnWriteArrayList
<>());
}
// 查找有效班次
...
...
@@ -1080,7 +1515,7 @@ public class MachineCalculator {
if
(
start
==
null
)
{
// 生成新时间段
List
<
TimeSegment
>
timeSegments
=
machineScheduler
.
generateTimeSegment
(
machine
,
time
.
plusDays
(
1
),
0
);
List
<
TimeSegment
>
timeSegments
=
machineScheduler
.
generateTimeSegment
(
machine
,
time
.
plusDays
(
1
),
0
);
machine
.
getAvailability
().
addAll
(
timeSegments
);
...
...
@@ -1095,7 +1530,8 @@ public class MachineCalculator {
}
// 递归查找
return
GetCurrentOrNextShift
(
machine
,
time
,
prevtime
,
checkprevtime
);
return
GetCurrentOrNextShift
(
machine
,
time
,
prevtime
,
checkprevtime
,
isJit
);
}
}
return
start
;
...
...
@@ -1446,7 +1882,7 @@ if(keys1!=null&&keys1.size()>0) {
}
}
availabilitySnapshot
=
MergeSegments
(
availabilitySnapshot
);
availabilitySnapshot
=
MergeSegments
(
availabilitySnapshot
,
false
);
synchronized
(
machine
.
getAvailability
())
{
machine
.
setAvailability
(
availabilitySnapshot
);
}
...
...
@@ -1457,7 +1893,7 @@ if(keys1!=null&&keys1.size()>0) {
* @param timeSegment 待分割的时间片段
* @param start 分割起始时间
*/
private
void
spiltMachineAvailable
(
Machine
machine
,
TimeSegment
timeSegment
,
LocalDateTime
start
)
{
private
void
spiltMachineAvailable
(
Machine
machine
,
TimeSegment
timeSegment
,
LocalDateTime
start
,
boolean
isJit
)
{
List
<
TimeSegment
>
timeSegments
=
new
ArrayList
<>();
// 查找待分割片段在设备可用列表中的索引,对应C#的 FindIndex
...
...
@@ -1467,16 +1903,27 @@ if(keys1!=null&&keys1.size()>0) {
.
map
(
machine
.
getAvailability
()::
indexOf
)
.
orElse
(-
1
);
if
(
inx
>
-
1
)
{
// 创建分割后的前半段时间片段,对应原C#逻辑
// 创建分割后的前半段时间片段
TimeSegment
time
=
new
TimeSegment
();
if
(
isJit
)
{
time
.
setStart
(
start
.
plusSeconds
(
1
));
// 对应C#的 start.AddSeconds(-1)
time
.
setEnd
(
timeSegment
.
getEnd
());
}
else
{
time
.
setStart
(
timeSegment
.
getStart
());
// 对应C#的 start.AddSeconds(-1)
time
.
setEnd
(
start
.
plusSeconds
(-
1
));
time
.
setHoliday
(
false
);
// 对应C#的 IsHoliday = false
}
time
.
setHoliday
(
false
);
// IsHoliday = false
// 对应C#的 Guid.NewGuid().ToString(),生成唯一标识
time
.
setKey
(
UUID
.
randomUUID
().
toString
());
time
.
setType
(
SegmentType
.
REGULAR
);
time
.
setUsed
(
false
);
// 对应C#的 IsUsed = false
time
.
setUsed
(
false
);
// IsUsed = false
timeSegments
.
add
(
time
);
// 更新原片段的起始时间为分割时间,对应C#的 machine.Availability[inx].Start = start
...
...
@@ -1488,11 +1935,11 @@ if(keys1!=null&&keys1.size()>0) {
machine
.
getAvailability
().
addAll
(
timeSegments
);
}
// 按起始时间排序
,对应C#的 Sort((a, b) => a.Start.CompareTo(b.Start))
// 按起始时间排序
machine
.
getAvailability
().
sort
((
a
,
b
)
->
a
.
getStart
().
compareTo
(
b
.
getStart
()));
}
private
CopyOnWriteArrayList
<
TimeSegment
>
MergeSegments
(
CopyOnWriteArrayList
<
TimeSegment
>
segments
)
{
private
CopyOnWriteArrayList
<
TimeSegment
>
MergeSegments
(
CopyOnWriteArrayList
<
TimeSegment
>
segments
,
boolean
isJit
)
{
CopyOnWriteArrayList
<
TimeSegment
>
maintenanceSegments
=
segments
.
stream
()
.
filter
(
t
->
t
.
getType
()
==
SegmentType
.
MAINTENANCE
)
.
collect
(
Collectors
.
toCollection
(
CopyOnWriteArrayList:
:
new
));
...
...
@@ -1521,8 +1968,12 @@ if(keys1!=null&&keys1.size()>0) {
CopyOnWriteArrayList
<
TimeSegment
>
result
=
new
CopyOnWriteArrayList
<>(
mergedUnused
);
result
.
addAll
(
usedRegularSegments
);
result
.
addAll
(
maintenanceSegments
);
if
(
isJit
)
{
result
.
sort
(
Comparator
.
comparing
(
TimeSegment:
:
getEnd
).
reversed
());
}
else
{
result
.
sort
(
Comparator
.
comparing
(
TimeSegment:
:
getStart
));
}
return
result
;
}
...
...
src/main/java/com/aps/service/plan/MachineSchedulerService.java
View file @
6f7aeeba
...
...
@@ -58,6 +58,17 @@ public class MachineSchedulerService {
}
public
MachineTimeline
getOrCreateTimeline
(
Machine
machine
)
{
return
getOrCreateTimeline
(
machine
,
true
);
}
public
LocalDateTime
GetEndTime
(
Long
machineId
)
{
MachineTimeline
timeline
=
timelineCache
.
get
(
machineId
);
if
(
timeline
!=
null
)
{
return
timeline
.
getValidTo
();
}
return
null
;
}
private
MachineTimeline
generateTimeline
(
Machine
machine
)
{
...
...
src/main/java/com/aps/service/plan/PlanResultService.java
View file @
6f7aeeba
...
...
@@ -149,6 +149,7 @@ public class PlanResultService {
ScheduleParams
param
=
InitScheduleParams
();
this
.
baseTime
=
param
.
getBaseTime
();
// 1. 读取数据
// List<Machine> machines = loadData("machines.json", Machine.class);
...
...
@@ -240,7 +241,7 @@ public class PlanResultService {
_sceneService
.
saveChromosomeToFile
(
chromosome
,
SceneId
);
//
WriteScheduleSummary(chromosome);
WriteScheduleSummary
(
chromosome
);
return
chromosome
;
...
...
@@ -1909,8 +1910,8 @@ public class PlanResultService {
TargetFinishedOperationIds
));
// 追加基因详情
if
(
job
.
getGeneDetails
()!=
null
)
{
for
(
ScheduleResultDetail
d
:
job
.
getGeneDetails
())
{
sb
.
append
(
String
.
format
(
"\n\t\t\t\t\t\t\t\t\t\t [%d-%d]:[%s-%s] %d"
,
...
...
@@ -1921,6 +1922,9 @@ public class PlanResultService {
d
.
getEndTime
()
-
d
.
getStartTime
()
));
}
}
// 追加基因详情
FileHelper
.
writeLogFile
(
sb
.
toString
());
...
...
src/main/resources/application.yml
View file @
6f7aeeba
...
...
@@ -56,11 +56,11 @@ spring:
oracle
:
driver-class-name
:
oracle.jdbc.OracleDriver
url
:
jdbc:oracle:thin:@//39.100.77.7:1522/ORCLPDB1
# ORCL为你的Oracle实例名
# username: mes # 替换为你的Oracle用户名
# password: root_mes123456 # 替换为你的Oracle密码
# url: jdbc:oracle:thin:@//39.100.78.207:7002/ORCLPDB1 # ORCL为你的Oracle实例名
username
:
mes
# 替换为你的Oracle用户名
password
:
root_mes123456
# 替换为你的Oracle密码
# url: jdbc:oracle:thin:@//39.100.78.207:7002/ORCLPDB1 # ORCL为你的Oracle实例名
# username: mes # 替换为你的Oracle用户名
# password: root_mes123456 # 替换为你的Oracle密码
# sqlserver:
# driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://192.168.0.181:1434;databaseName=mes;encrypt=false
...
...
src/test/java/com/aps/demo/PlanResultServiceTest.java
View file @
6f7aeeba
...
...
@@ -40,7 +40,9 @@ public class PlanResultServiceTest {
// sortService.test1();
// nsgaiiUtils.Test();
planResultService
.
execute2
(
"AD62106303684459949A7323D114BF60"
);
//2000
// planResultService.execute2("AD62106303684459949A7323D114BF60");//2000
planResultService
.
execute2
(
"15210B13B88A453F8B84AAC7F16C7541"
);
//2000
// planResultService.execute2("E29F2B3ADA8149F6B916B5119296A92B");//2000
// planResultService.execute2("E2CD1FC6FF9B4B19A59FEC7F846D4952");//600
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment