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
25c58c5b
Commit
25c58c5b
authored
Apr 01, 2026
by
Tong Li
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
算法优化
parent
9d08cc4f
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
2278 additions
and
617 deletions
+2278
-617
ResourceGanttController.java
...ava/com/aps/controller/gantt/ResourceGanttController.java
+1
-1
ScheduleParams.java
src/main/java/com/aps/entity/Algorithm/ScheduleParams.java
+1
-1
GeneticAlgorithm.java
...main/java/com/aps/service/Algorithm/GeneticAlgorithm.java
+7
-7
GeneticDecoder.java
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
+96
-94
HillClimbing.java
src/main/java/com/aps/service/Algorithm/HillClimbing.java
+165
-133
HybridAlgorithm.java
src/main/java/com/aps/service/Algorithm/HybridAlgorithm.java
+3
-3
MachineCalculator.java
...ain/java/com/aps/service/Algorithm/MachineCalculator.java
+3
-0
OrderSortService.java
...main/java/com/aps/service/Algorithm/OrderSortService.java
+10
-10
SimulatedAnnealing.java
...in/java/com/aps/service/Algorithm/SimulatedAnnealing.java
+533
-48
TabuSearch.java
src/main/java/com/aps/service/Algorithm/TabuSearch.java
+2
-0
PlanResultService.java
src/main/java/com/aps/service/plan/PlanResultService.java
+1454
-317
PlanResultServiceTest.java
src/test/java/com/aps/demo/PlanResultServiceTest.java
+3
-3
No files found.
src/main/java/com/aps/controller/gantt/ResourceGanttController.java
View file @
25c58c5b
...
...
@@ -465,7 +465,7 @@ public class ResourceGanttController {
ParamValidator
.
validateSceneExists
(
sceneService
,
sceneId
);
planResultService
.
InsertOrderAuto
(
sceneId
,
newOrderData
);
//
planResultService.InsertOrderAuto(sceneId, newOrderData);
return
R
.
ok
(
"自动插单成功"
);
}
...
...
src/main/java/com/aps/entity/Algorithm/ScheduleParams.java
View file @
25c58c5b
...
...
@@ -17,7 +17,7 @@ public class ScheduleParams {
private
static
final
int
MIN_POPULATION_SIZE
=
10
;
private
static
final
int
MAX_POPULATION_SIZE
=
50
;
private
static
final
int
MIN_MAX_ITERATIONS
=
50
;
private
static
final
int
MAX_MAX_ITERATIONS
=
25
0
;
private
static
final
int
MAX_MAX_ITERATIONS
=
10
0
;
private
static
final
float
MIN_CROSSOVER_PROB
=
0.6f
;
private
static
final
float
MAX_CROSSOVER_PROB
=
0.9f
;
private
static
final
float
MIN_MUTATION_PROB
=
0.2f
;
...
...
src/main/java/com/aps/service/Algorithm/GeneticAlgorithm.java
View file @
25c58c5b
...
...
@@ -417,13 +417,13 @@ public class GeneticAlgorithm {
}
// 加载锁定工单到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
<>());
}
//
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
)
{
...
...
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
View file @
25c58c5b
...
...
@@ -471,10 +471,14 @@ if(finishedOrder==null||finishedOrder.size()==0)
// 步骤2:按OperationSequencing顺序调度工序
Map
<
Integer
,
Integer
>
orderProcessCounter
=
new
HashMap
<>();
Map
<
Integer
,
Integer
>
orderLastEndTime
=
new
HashMap
<>();
Map
<
Integer
,
Entry
>
entryIndexById
=
new
HashMap
<>();
Map
<
Integer
,
List
<
Entry
>>
entrysBygroupId
=
new
HashMap
<>();
for
(
Entry
op
:
allOperations
)
{
int
groupId
=
op
.
getGroupId
();
orderProcessCounter
.
putIfAbsent
(
groupId
,
0
);
orderLastEndTime
.
putIfAbsent
(
groupId
,
0
);
entryIndexById
.
put
(
op
.
getId
(),
op
);
entrysBygroupId
.
computeIfAbsent
(
groupId
,
k
->
new
ArrayList
<>()).
add
(
op
);
}
// Map<Long, String> machineState = chromosome.getMachines().stream()
...
...
@@ -483,10 +487,12 @@ if(finishedOrder==null||finishedOrder.size()==0)
// List<Entry> allScheduledOps = new ArrayList<>();
// 缓存机器任务
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
=
new
HashMap
<>();
for
(
Entry
op
:
allOperations
)
{
}
for
(
int
groupId
:
chromosome
.
getOperationSequencing
())
{
int
scheduledCount
=
orderProcessCounter
.
get
(
groupId
);
List
<
Entry
>
orderOps
=
allOperations
.
stream
()
.
filter
(
t
->
t
.
getGroupId
()
==
groupId
)
List
<
Entry
>
orderOps
=
entrysBygroupId
.
get
(
groupId
).
stream
()
.
sorted
(
Comparator
.
comparing
(
Entry:
:
getSequence
))
.
collect
(
Collectors
.
toList
());
...
...
@@ -1243,12 +1249,12 @@ return actualEndTime;
}
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
);
//
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
())
{
...
...
@@ -1385,7 +1391,9 @@ return actualEndTime;
// FileHelper.writeLogFile(" 结束 "+ConvertTime(startTime)+"--"+ConvertTime(endTime)+" "+operation.getGroupId()+" : "+operation.getId()+",处理时间: " + processingTime + ", 后处理: " + teardownTime +
// ", 前处理: " + preTime + ", 换型: " + setupTime+ ", 数量: " + operation.getQuantity()+ ", 设备: "+machine.getId()+ ", 是否可中断: "+operation.getIsInterrupt());
machineTasksCache
.
remove
(
machine
.
getId
());
if
(
machineTasks
!=
null
)
{
machineTasks
.
add
(
result
);
}
return
endTime
;
}
...
...
@@ -2399,24 +2407,21 @@ if(MaterialRequirements==null||MaterialRequirements.size()==0)
private
void
calculateScheduleResult
(
Chromosome
chromosome
)
{
double
[]
Objectives
=
new
double
[
_globalParam
.
getObjectiveWeights
().
size
()];
double
[]
Objectives
=
new
double
[
_globalParam
.
getObjectiveWeights
().
size
()];
int
i
=
0
;
int
i
=
0
;
for
(
ObjectiveConfig
config
:
_globalParam
.
getObjectiveConfigs
())
{
if
(
config
.
isEnabled
())
{
if
(
config
.
getName
()==
GlobalParam
.
OBJECTIVE_MAKESPAN
)
{
if
(
config
.
isEnabled
())
{
if
(
config
.
getName
()
==
GlobalParam
.
OBJECTIVE_MAKESPAN
)
{
// 1. 最早完工时间(最小化)
double
makespan
=
chromosome
.
getResult
().
stream
()
.
mapToInt
(
GAScheduleResult:
:
getEndTime
)
.
max
()
.
orElse
(
0
);
Objectives
[
i
]=
makespan
;
Objectives
[
i
]
=
makespan
;
chromosome
.
setMakespan
(
makespan
);
}
if
(
config
.
getName
()==
GlobalParam
.
OBJECTIVE_TARDINESS
)
{
if
(
config
.
getName
()
==
GlobalParam
.
OBJECTIVE_TARDINESS
)
{
// 2. 交付期满足情况(最小化延迟)
double
tardiness
=
0
;
...
...
@@ -2435,60 +2440,57 @@ if(MaterialRequirements==null||MaterialRequirements.size()==0)
.
sorted
()
.
collect
(
Collectors
.
toList
());
Order
order
=
chromosome
.
getOrders
().
stream
()
.
filter
(
t
->
orderIds
.
contains
(
t
.
getOrderId
()))
.
filter
(
t
->
orderIds
.
contains
(
t
.
getOrderId
()))
.
max
(
Comparator
.
comparing
(
Order:
:
getDueDate
))
.
orElse
(
null
);
if
(
order
.
isNewCreate
())
{
continue
;}
LocalDateTime
dueDateTime
=
order
.
getDueDate
();
if
(
order
.
isNewCreate
())
{
continue
;
}
LocalDateTime
dueDateTime
=
order
.
getDueDate
();
LocalDateTime
completionTime
=
baseTime
.
plusSeconds
(
orderCompletion
);
LocalDateTime
completionTime
=
baseTime
.
plusSeconds
(
orderCompletion
);
if
(
completionTime
.
isAfter
(
dueDateTime
))
{
// 计算延迟小时数(修复时间计算)
long
hours
=
ChronoUnit
.
HOURS
.
between
(
dueDateTime
,
completionTime
);
long
minutes
=
ChronoUnit
.
MINUTES
.
between
(
dueDateTime
,
completionTime
)
%
60
;
tardiness
+=
hours
*
60
+
(
double
)
minutes
;
tardiness
+=
hours
*
60
+
(
double
)
minutes
;
}
}
Objectives
[
i
]=
tardiness
;
Objectives
[
i
]
=
tardiness
;
chromosome
.
setDelayTime
(
tardiness
);
}
if
(
config
.
getName
()==
GlobalParam
.
OBJECTIVE_SETUP_TIME
)
{
if
(
config
.
getName
()
==
GlobalParam
.
OBJECTIVE_SETUP_TIME
)
{
// 3. 最小总换型时间
double
totalSetupTime
=
calculateTotalSetupTime
(
chromosome
);
chromosome
.
setTotalChangeoverTime
(
totalSetupTime
);
Objectives
[
i
]=
totalSetupTime
;
Objectives
[
i
]
=
totalSetupTime
;
}
if
(
config
.
getName
()==
GlobalParam
.
OBJECTIVE_FLOW_TIME
)
{
if
(
config
.
getName
()
==
GlobalParam
.
OBJECTIVE_FLOW_TIME
)
{
// 4. 最小化总流程时间 所有工序加工时间的总和
double
totalFlowTime
=
calculateTotalFlowTime
(
chromosome
);
chromosome
.
setTotalFlowTime
(
totalFlowTime
);
Objectives
[
i
]=
totalFlowTime
;
Objectives
[
i
]
=
totalFlowTime
;
}
if
(
config
.
getName
()==
GlobalParam
.
OBJECTIVE_MACHINE_LOAD
)
{
if
(
config
.
getName
()
==
GlobalParam
.
OBJECTIVE_MACHINE_LOAD
)
{
// 5. 机器负载均衡
double
machineLoadBalance
=
calculateMachineLoadBalance
(
chromosome
);
chromosome
.
setMachineLoadStd
(
machineLoadBalance
);
Objectives
[
i
]=
machineLoadBalance
;
Objectives
[
i
]
=
machineLoadBalance
;
}
i
++;
}
}
chromosome
.
setObjectives
(
Objectives
);
FitnessCalculator
fitnessCalculator
=
new
FitnessCalculator
();
if
(
chromosome
.
getFitnessLevel
()==
null
)
{
FitnessCalculator
fitnessCalculator
=
new
FitnessCalculator
();
chromosome
.
setFitnessLevel
(
fitnessCalculator
.
calculateFitness
(
chromosome
,
_globalParam
));
}
}
private
double
calculateTotalFlowTime
(
Chromosome
chromosome
)
{
...
...
src/main/java/com/aps/service/Algorithm/HillClimbing.java
View file @
25c58c5b
...
...
@@ -11,6 +11,7 @@ import java.util.concurrent.CompletableFuture;
import
java.util.concurrent.CopyOnWriteArrayList
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.stream.Collectors
;
/**
* 爬山法算法
...
...
@@ -38,7 +39,7 @@ public class HillClimbing {
// 按优先级从高到低处理
sortedPriorities
=
new
ArrayList
<>(
priorityGroups
.
keySet
());
Collections
.
sort
(
sortedPriorities
);
entrys
=
buildEntryKey
();
}
...
...
@@ -71,13 +72,54 @@ public class HillClimbing {
// 构建位置到Entry的映射:position -> Entry
Map
<
Integer
,
Entry
>
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
boolean
improved
=
true
;
for
(
Double
priority
:
sortedPriorities
)
{
List
<
Entry
>
priorityOps
=
priorityGroups
.
get
(
priority
);
if
(
priorityOps
.
isEmpty
())
{
continue
;
}
// 1. 优先处理有多设备选项的工序(最有可能带来改进)
List
<
Entry
>
multiMachineOps
=
priorityOps
.
stream
()
.
filter
(
op
->
op
.
getMachineOptions
().
size
()
>
1
)
.
collect
(
Collectors
.
toList
());
if
(!
multiMachineOps
.
isEmpty
())
{
for
(
Entry
op
:
multiMachineOps
)
{
String
key
=
op
.
getGroupId
()
+
"_"
+
op
.
getSequence
();
Integer
maPos
=
MachinePositionIndex
.
get
(
key
);
if
(
maPos
==
null
)
continue
;
Chromosome
machineChange
=
generateMachineChange
(
current
,
op
.
getMachineOptions
(),
maPos
);
if
(
machineChange
!=
null
)
{
decode
(
decoder
,
machineChange
);
if
(
isBetter
(
machineChange
,
current
))
{
current
=
machineChange
;
if
(
isBetter
(
current
,
best
))
{
best
=
current
;
}
improved
=
true
;
positionIndex
=
buildPositionIndex
(
current
);
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
MachinePositionIndex
=
buildEntryMachinePositionIndex
(
current
);
break
;
}
}
}
if
(
improved
)
break
;
}
if
(
improved
)
continue
;
// 2. 检查是否是单一订单(如果只有一个订单,不需要交换位置
Set
<
Integer
>
groupIds
=
priorityOps
.
stream
()
.
map
(
Entry:
:
getGroupId
)
.
collect
(
Collectors
.
toSet
());
if
(
groupIds
.
size
()
<=
1
)
{
continue
;
}
// 根据当前优先级的工序数确定迭代次数和step
int
priorityIterations
=
Math
.
max
(
5
,
priorityOps
.
size
()
/
2
);
// 200/10 =20
...
...
@@ -109,13 +151,7 @@ public class HillClimbing {
List
<
Chromosome
>
candidates
=
new
ArrayList
<>();
List
<
Chromosome
>
candidates1
=
new
ArrayList
<>();
if
(
MachineOptions
.
size
()
>
1
)
{
Chromosome
machineChange
=
generateMachineChange
(
current
,
MachineOptions
,
maPos
);
if
(
machineChange
!=
null
)
{
candidates
.
add
(
machineChange
);
candidates1
.
add
(
machineChange
);
}
}
// 向左多次移动(step 1, 2, 3...)
for
(
int
s
=
1
;
s
<=
stepCount
;
s
++)
{
...
...
@@ -197,185 +233,161 @@ public class HillClimbing {
Chromosome
best
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
// 构建位置索引映射:groupId_sequence -> position
Map
<
String
,
Integer
>
positionIndex
=
buildPositionIndex
(
current
);
Map
<
String
,
Integer
>
MachinePositionIndex
=
buildEntryMachinePositionIndex
(
current
);
int
totalCount
=
0
;
int
noImproveCount
=
0
;
int
maxNoImprove
=
50
;
// 连续50次没改进就提前停止
// 构建位置到Entry的映射:position -> Entry
Map
<
Integer
,
Entry
>
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
boolean
improved
=
tru
e
;
Map
<
Integer
,
Entry
>
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
boolean
improved
=
fals
e
;
for
(
Double
priority
:
sortedPriorities
)
{
List
<
Entry
>
priorityOps
=
priorityGroups
.
get
(
priority
);
if
(
priorityOps
.
isEmpty
())
{
continue
;
}
// 1. 优先处理有多设备选项的工序(最有可能带来改进)
List
<
Entry
>
multiMachineOps
=
priorityOps
.
stream
()
.
filter
(
op
->
op
.
getMachineOptions
().
size
()
>
1
)
.
collect
(
Collectors
.
toList
());
if
(!
multiMachineOps
.
isEmpty
())
{
for
(
Entry
op
:
multiMachineOps
)
{
String
key
=
op
.
getGroupId
()
+
"_"
+
op
.
getSequence
();
Integer
maPos
=
MachinePositionIndex
.
get
(
key
);
if
(
maPos
==
null
)
continue
;
Chromosome
machineChange
=
generateMachineChange
(
current
,
op
.
getMachineOptions
(),
maPos
);
if
(
machineChange
!=
null
)
{
decode
(
decoder
,
machineChange
);
if
(
isBetter
(
machineChange
,
current
))
{
current
=
machineChange
;
if
(
isBetter
(
current
,
best
))
{
best
=
ProductionDeepCopyUtil
.
deepCopy
(
current
,
Chromosome
.
class
);
}
improved
=
true
;
noImproveCount
=
0
;
positionIndex
=
buildPositionIndex
(
current
);
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
MachinePositionIndex
=
buildEntryMachinePositionIndex
(
current
);
break
;
}
}
}
if
(
improved
)
break
;
}
if
(
improved
)
continue
;
// 2. 检查是否是单一订单(如果只有一个订单,不需要交换位置
Set
<
Integer
>
groupIds
=
priorityOps
.
stream
()
.
map
(
Entry:
:
getGroupId
)
.
collect
(
Collectors
.
toSet
());
if
(
groupIds
.
size
()
<=
1
)
{
continue
;
}
// 根据当前优先级的工序数确定迭代次数和step
int
priorityIterations
=
Math
.
max
(
5
,
priorityOps
.
size
()
/
2
);
int
priorityIterations
=
Math
.
max
(
5
,
priorityOps
.
size
()
/
2
);
// 200/10 =20
// 1
int
step
=
Math
.
max
(
1
,
(
int
)
Math
.
ceil
(
priorityOps
.
size
()
/
10.0
));
// 200/20=10;
//
int
stepCount
=
Math
.
max
(
1
,
(
int
)
Math
.
ceil
(
priorityOps
.
size
()
/
step
));
Set
<
Integer
>
Groupid
=
new
HashSet
<>();
int
noImproveCount
=
0
;
int
maxNoImprove
=
20
;
// 连续50次没改进就提前停止
Set
<
Integer
>
processedGroupIds
=
new
HashSet
<>();
for
(
int
pi
=
0
;
pi
<
priorityIterations
;
pi
++)
{
improved
=
false
;
// 随机取该优先级的工序
Entry
randomOp
=
priorityOps
.
get
(
rnd
.
nextInt
(
priorityOps
.
size
()));
if
(
processedGroupIds
.
contains
(
randomOp
.
getGroupId
()))
{
continue
;
}
processedGroupIds
.
add
(
randomOp
.
getGroupId
());
// 从索引中快速查找位置(O(1)复杂度)
String
key
=
randomOp
.
getGroupId
()
+
"_"
+
randomOp
.
getSequence
();
Integer
opPos
=
positionIndex
.
get
(
key
);
Integer
maPos
=
MachinePositionIndex
.
get
(
key
);
List
<
MachineOption
>
MachineOptions
=
randomOp
.
getMachineOptions
();
if
(
opPos
==
null
)
{
continue
;
}
List
<
Integer
>
os
=
current
.
getOperationSequencing
();
// 生成多个候选方案
List
<
Chromosome
>
candidates
=
new
ArrayList
<>();
if
(
MachineOptions
.
size
()>
1
)
{
Chromosome
machineChange
=
generateMachineChange
(
current
,
MachineOptions
,
maPos
);
if
(
machineChange
!=
null
)
{
candidates
.
add
(
machineChange
);
}
}
boolean
foundBetter
=
false
;
// 向左
多次移动(step 1, 2, 3...)
// 向左
逐步尝试
for
(
int
s
=
1
;
s
<=
stepCount
;
s
++)
{
int
targetPos
=
opPos
-
s
*
step
;
Entry
leftOp
=
entryIndex
.
get
(
targetPos
);
Entry
leftOp
=
entryIndex
.
get
(
opPos
-
s
*
step
);
if
(
leftOp
!=
null
&&
randomOp
.
getGroupId
()!=
leftOp
.
getGroupId
()
&&
Math
.
abs
(
leftOp
.
getPriority
()
-
priority
)
<=
0.001
)
{
Chromosome
newChromosome
=
swapAtDistance
(
current
,
opPos
,
-
s
*
step
);
candidates
.
add
(
newChromosome
);
if
(
MachineOptions
.
size
()>
1
)
{
Chromosome
machineChange
=
generateMachineChange
(
newChromosome
,
MachineOptions
,
maPos
);
if
(
machineChange
!=
null
)
{
candidates
.
add
(
machineChange
);
}
if
(
leftOp
==
null
||
randomOp
.
getGroupId
()
==
leftOp
.
getGroupId
()
||
Math
.
abs
(
leftOp
.
getPriority
()
-
priority
)
>
0.001
)
{
break
;
}
Chromosome
newChromosome
=
swapAtDistance
(
current
,
opPos
,
-
s
*
step
);
decode
(
decoder
,
newChromosome
);
}
else
{
break
;
if
(
isBetter
(
newChromosome
,
current
))
{
current
=
newChromosome
;
if
(
isBetter
(
current
,
best
))
{
best
=
ProductionDeepCopyUtil
.
deepCopy
(
current
,
Chromosome
.
class
);
}
if
(
candidates
.
size
()
>
5
)
{
batchDecode
(
decoder
,
candidates
,
machines
);
int
bestidx
=
Getbest
(
candidates
,
best
);
if
(
bestidx
>-
1
)
{
best
=
candidates
.
get
(
bestidx
);
current
=
ProductionDeepCopyUtil
.
deepCopy
(
best
,
Chromosome
.
class
);;
improved
=
true
;
// 更新索引
improved
=
true
;
foundBetter
=
true
;
noImproveCount
=
0
;
positionIndex
=
buildPositionIndex
(
current
);
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
break
;
}
candidates
.
clear
();
}
}
if
(
improved
)
{
break
;
}
if
(
foundBetter
)
break
;
// 向右
多次移动(step 1, 2, 3...)
// 向右
逐步尝试
for
(
int
s
=
1
;
s
<=
stepCount
;
s
++)
{
int
targetPos
=
opPos
+
s
*
step
;
Entry
rightOp
=
entryIndex
.
get
(
targetPos
);
Entry
rightOp
=
entryIndex
.
get
(
opPos
+
s
*
step
);
if
(
rightOp
!=
null
&&
randomOp
.
getGroupId
()
!=
rightOp
.
getGroupId
()
&&
Math
.
abs
(
rightOp
.
getPriority
()
-
priority
)
<=
0.001
)
{
Chromosome
newChromosome
=
swapAtDistance
(
current
,
opPos
,
s
*
step
);
candidates
.
add
(
newChromosome
);
if
(
MachineOptions
.
size
()>
1
)
{
Chromosome
machineChange
=
generateMachineChange
(
newChromosome
,
MachineOptions
,
maPos
);
if
(
machineChange
!=
null
)
{
candidates
.
add
(
machineChange
);
}
if
(
rightOp
==
null
||
randomOp
.
getGroupId
()
==
rightOp
.
getGroupId
()
||
Math
.
abs
(
rightOp
.
getPriority
()
-
priority
)
>
0.001
)
{
break
;
}
}
else
{
break
;
Chromosome
newChromosome
=
swapAtDistance
(
current
,
opPos
,
s
*
step
);
decode
(
decoder
,
newChromosome
);
if
(
isBetter
(
newChromosome
,
current
))
{
current
=
newChromosome
;
if
(
isBetter
(
current
,
best
))
{
best
=
ProductionDeepCopyUtil
.
deepCopy
(
current
,
Chromosome
.
class
);
}
if
(
candidates
.
size
()
>
5
)
{
batchDecode
(
decoder
,
candidates
,
machines
);
int
bestidx
=
Getbest
(
candidates
,
best
);
if
(
bestidx
>-
1
)
{
best
=
candidates
.
get
(
bestidx
);
current
=
ProductionDeepCopyUtil
.
deepCopy
(
best
,
Chromosome
.
class
);;
// 更新索引
improved
=
true
;
foundBetter
=
true
;
noImproveCount
=
0
;
positionIndex
=
buildPositionIndex
(
current
);
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
improved
=
true
;
break
;
}
candidates
.
clear
();
}
}
if
(
improved
)
{
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
break
;
}
if
(
candidates
.
size
()==
0
)
{
break
;
}
else
{
batchDecode
(
decoder
,
candidates
,
machines
);
}
int
bestidx
=
Getbest
(
candidates
,
best
);
if
(
bestidx
>-
1
)
if
(
foundBetter
)
break
;
noImproveCount
++;
totalCount
++;
if
(
noImproveCount
>
maxNoImprove
)
{
best
=
candidates
.
get
(
bestidx
);
current
=
ProductionDeepCopyUtil
.
deepCopy
(
best
,
Chromosome
.
class
);;
// 更新索引
noImproveCount
=
0
;
positionIndex
=
buildPositionIndex
(
current
);
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
FileHelper
.
writeLogFile
(
String
.
format
(
"爬山法 - 提前停止:迭代%d次"
,
totalCount
));
improved
=
true
;
break
;
}
if
(
noImproveCount
>=
maxNoImprove
)
{
FileHelper
.
writeLogFile
(
String
.
format
(
"爬山法 - 提前停止:连续未优化 迭代%d次"
,
pi
+
1
));
noImproveCount
=
0
;
}
noImproveCount
++;
}
if
(
improved
)
break
;
}
return
best
;
}
...
...
@@ -497,7 +509,27 @@ boolean improved = true;
double
priority
=
op
.
getPriority
();
groups
.
computeIfAbsent
(
priority
,
k
->
new
ArrayList
<>()).
add
(
op
);
}
return
groups
;
// 过滤掉:设备只有一个且只有一个GroupId的优先级组
Map
<
Double
,
List
<
Entry
>>
filteredGroups
=
new
HashMap
<>();
for
(
Map
.
Entry
<
Double
,
List
<
Entry
>>
entry
:
groups
.
entrySet
())
{
List
<
Entry
>
ops
=
entry
.
getValue
();
// 检查是否所有工序都只有一个设备选项
boolean
allSingleMachine
=
ops
.
stream
()
.
allMatch
(
op
->
op
.
getMachineOptions
().
size
()
<=
1
);
// 检查是否只有一个GroupId
Set
<
Integer
>
groupIds
=
ops
.
stream
()
.
map
(
Entry:
:
getGroupId
)
.
collect
(
Collectors
.
toSet
());
// 如果两个条件都满足,过滤掉这个优先级组
if
(!(
allSingleMachine
&&
groupIds
.
size
()
<=
1
))
{
filteredGroups
.
put
(
entry
.
getKey
(),
ops
);
}
}
return
filteredGroups
;
}
/**
...
...
src/main/java/com/aps/service/Algorithm/HybridAlgorithm.java
View file @
25c58c5b
...
...
@@ -111,7 +111,7 @@ int opcount=allOperations.size();
// 初始化变邻域搜索
_vns
=
new
VariableNeighborhoodSearch
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeights
);
_hillClimbing
=
new
HillClimbing
(
allOperations
);
_simulatedAnnealing
=
new
SimulatedAnnealing
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeight
s
);
_simulatedAnnealing
=
new
SimulatedAnnealing
(
allOperation
s
);
_parallelLocalSearch
=
new
ParallelLocalSearch
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeights
);
_tabuSearch
=
new
TabuSearch
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeights
);
_tabuSearchWithSA
=
new
TabuSearchWithSA
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeights
);
...
...
@@ -142,7 +142,7 @@ int opcount=allOperations.size();
// 步骤2:对初始种群进行爬山法局部优化
if
(
population
.
size
()<
5
||
opcount
<
1
0
)
{
if
(
opcount
<
2
0
)
{
FileHelper
.
writeLogFile
(
"爬山法局部优化-----------开始-------"
);
GeneticDecoder
hillClimbingDecoder
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
...
...
@@ -156,7 +156,7 @@ int opcount=allOperations.size();
// 步骤2:对初始种群进行模拟退火+爬山法优化
GeneticDecoder
saDecoder1
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
if
(
population
.
size
()>
5
||
opcount
<
20
00
)
{
if
(
opcount
<
8
00
)
{
FileHelper
.
writeLogFile
(
"模拟退火+爬山法优化-----------开始-------"
);
Chromosome
saHcOptimized
=
_simulatedAnnealing
.
batchSearchGetMax
(
population
,
saDecoder1
,
machines
);
FileHelper
.
writeLogFile
(
"模拟退火+爬山法优化-----------结束-------"
);
...
...
src/main/java/com/aps/service/Algorithm/MachineCalculator.java
View file @
25c58c5b
...
...
@@ -934,6 +934,9 @@ public class MachineCalculator {
LocalDateTime
end
)
{
CopyOnWriteArrayList
<
TimeSegment
>
conflictIntervals
=
new
CopyOnWriteArrayList
<>();
// 1. 维护窗口冲突(优化重叠判断,更严谨)
if
(
machine
.
getMaintenanceWindows
()
!=
null
&&
!
machine
.
getMaintenanceWindows
().
isEmpty
())
{
// 过滤重叠的维护窗口并转换为TimeSegment
...
...
src/main/java/com/aps/service/Algorithm/OrderSortService.java
View file @
25c58c5b
...
...
@@ -474,18 +474,18 @@ public class OrderSortService {
if
(!
Objects
.
equals
(
prev
.
getSerie
(),
order
.
getSerie
()))
flags
.
append
(
"serie变 "
);
if
(!
Objects
.
equals
(
prev
.
getMaterialCode
(),
order
.
getMaterialCode
()))
flags
.
append
(
"material变"
);
}
costLog
.
append
(
String
.
format
(
" %2d. %s, routingId=%s, serie=%s, materialCode=%s, cost=%.0f %s\n"
,
(
i
+
1
),
order
.
getOrderCode
(),
order
.
getRoutingId
(),
order
.
getSerie
(),
order
.
getMaterialCode
(),
costToPrev
,
flags
.
toString
()));
//
costLog.append(String.format(" %2d. %s, routingId=%s, serie=%s, materialCode=%s, cost=%.0f %s\n",
//
(i + 1),
//
order.getOrderCode(),
//
order.getRoutingId(),
//
order.getSerie(),
//
order.getMaterialCode(),
//
costToPrev,
//
flags.toString()));
totalCost
+=
costToPrev
;
}
costLog
.
append
(
String
.
format
(
"[换线明细] 总换线成本 = %.0f\n"
,
totalCost
));
log
.
debug
(
costLog
.
toString
());
//
costLog.append(String.format("[换线明细] 总换线成本 = %.0f\n", totalCost));
//
log.debug(costLog.toString());
// ==================================
// 为最小化换线后的订单分配层级序号
...
...
src/main/java/com/aps/service/Algorithm/SimulatedAnnealing.java
View file @
25c58c5b
...
...
@@ -6,27 +6,32 @@ import com.aps.entity.Algorithm.*;
import
com.aps.entity.basic.Entry
;
import
com.aps.entity.basic.GlobalParam
;
import
com.aps.entity.basic.Machine
;
import
com.aps.entity.basic.MachineOption
;
import
java.util.*
;
import
java.util.concurrent.*
;
import
java.util.stream.Collectors
;
/**
* 模拟退火算法
*/
public
class
SimulatedAnnealing
{
private
final
Random
rnd
=
new
Random
();
private
GlobalParam
globalParam
;
private
List
<
Entry
>
allOperations
;
private
List
<
GlobalOperationInfo
>
globalOpList
;
private
FitnessCalculator
fitnessCalculator
;
private
ObjectiveWeights
objectiveWeights
;
public
SimulatedAnnealing
(
GlobalParam
globalParam
,
List
<
Entry
>
allOperations
,
List
<
GlobalOperationInfo
>
globalOpList
,
FitnessCalculator
fitnessCalculator
,
ObjectiveWeights
objectiveWeights
)
{
this
.
globalParam
=
globalParam
;
private
Map
<
String
,
Entry
>
entrys
;
private
Map
<
Integer
,
Entry
>
entrybyids
;
public
SimulatedAnnealing
(
List
<
Entry
>
allOperations
)
{
this
.
allOperations
=
allOperations
;
this
.
globalOpList
=
globalOpList
;
this
.
fitnessCalculator
=
fitnessCalculator
;
this
.
objectiveWeights
=
objectiveWeights
;
Map
<
Integer
,
Object
>
mp
=
buildEntryKey
();
entrys
=(
Map
<
String
,
Entry
>)
mp
.
get
(
1
);
entrybyids
=(
Map
<
Integer
,
Entry
>)
mp
.
get
(
2
);
}
private
final
ExecutorService
decodeExecutor
=
new
ThreadPoolExecutor
(
Runtime
.
getRuntime
().
availableProcessors
()
-
1
,
// 核心线程数=CPU-1,无切换开销
...
...
@@ -47,7 +52,7 @@ public class SimulatedAnnealing {
for
(
Chromosome
chromosome:
chromosomes
)
{
Chromosome
optimized
=
searchWithHillClimbing
(
chromosome
,
decoder
,
machines
);
saHcOptimized
.
add
(
optimized
);
break
;
}
return
saHcOptimized
;
}
...
...
@@ -63,57 +68,63 @@ public class SimulatedAnnealing {
}
/**
* 模拟退火搜索,当温度降低到一定程度后切换到爬山法
* 流程:模拟退火迭代 → 随机生成新排产 → 按概率接受 → 降温 → 温度低时爬山法
求精 → 输出最优
* 流程:模拟退火全局探索(按概率接受劣解)→ 降温 → 温度低时爬山法局部
求精 → 输出最优
*/
public
Chromosome
searchWithHillClimbing
(
Chromosome
chromosome
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 开始执行"
);
Chromosome
current
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
best
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
writeKpi
(
best
);
// 初始化解码
Map
<
String
,
Entry
>
Entrys
=
buildEntryKey
(
current
);
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 初始化索引完成"
);
// FileHelper.writeLogFile("模拟退火+爬山法 - 初始化解码完成");
// 初始化温度
- 优化速度:更快降温,更快切换到爬山法
// 初始化温度
double
temperature
=
100.0
;
double
coolingRate
=
0.95
;
double
temperatureThreshold
=
1.0
;
// 提高阈值,更快切换到爬山法
int
maxIterations
=
300
;
// 减少最大迭代次数
double
temperatureThreshold
=
1.0
;
int
maxIterations
=
300
;
int
noImproveCount
=
0
;
int
maxNoImprove
=
50
;
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 参数配置:温度=%.1f, 降温率=%.2f, 阈值=%.1f, 最大迭代=%d"
,
temperature
,
coolingRate
,
temperatureThreshold
,
maxIterations
));
int
noImproveCount
=
0
;
int
maxNoImprove
=
50
;
// 连续50次没改进就提前停止
int
acceptCount
=
0
;
int
improveCount
=
0
;
for
(
int
i
=
0
;
i
<
maxIterations
;
i
++)
{
boolean
improved
=
false
;
// 1.
随机生成新排产(邻域解
)
Chromosome
neighbor
=
generateNeighbor
(
current
,
Entrys
);
// 1.
使用智能策略生成邻域解(找瓶颈工序/设备
)
Chromosome
neighbor
=
generateNeighbor
(
current
);
// 2. 解码
并计算适应度(只解码neighbor,current已经解码过了)
decode
(
decoder
,
neighbor
,
machines
);
// 2. 解码
decode
(
decoder
,
neighbor
,
machines
);
// 3. 计算能量差
(fitness差)
// 3. 计算能量差
double
energyDifference
=
calculateEnergyDifference
(
neighbor
,
current
);
// 4. 按概率接受新解
// - 更优:直接接受
// - 较差:概率接受(高温更容易接受)
// 4. 按概率接受新解(模拟退火核心:有概率接受劣解)
boolean
accepted
=
false
;
if
(
energyDifference
>
0
||
rnd
.
nextDouble
()
<
Math
.
exp
(
energyDifference
/
temperature
))
{
current
=
neighbor
;
accepted
=
true
;
acceptCount
++;
// 更新全局最优
if
(
isBetter
(
current
,
best
))
{
best
=
ProductionDeepCopyUtil
.
deepCopy
(
current
,
Chromosome
.
class
);
writeKpi
(
best
);
improved
=
true
;
improveCount
++;
noImproveCount
=
0
;
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 迭代%d:找到更优解,fitness=%.4f"
,
i
,
best
.
getFitness
()));
}
}
...
...
@@ -123,10 +134,13 @@ public class SimulatedAnnealing {
// 5. 降温
temperature
*=
coolingRate
;
if
((
i
+
1
)
%
10
==
0
)
{
// 每50次迭代输出一次状态
if
((
i
+
1
)
%
50
==
0
)
{
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 迭代%d/%d:温度=%.4f, 接受数=%d, 改进数=%d, 无改进连续=%d"
,
i
+
1
,
maxIterations
,
temperature
,
acceptCount
,
improveCount
,
noImproveCount
));
}
// 6. 提前停止条件:温度低于阈值 或 连续多次没改进
if
(
temperature
<
temperatureThreshold
||
noImproveCount
>=
maxNoImprove
)
{
String
stopReason
=
temperature
<
temperatureThreshold
?
"温度低于阈值"
:
"连续无改进达到上限"
;
...
...
@@ -134,20 +148,31 @@ public class SimulatedAnnealing {
stopReason
,
i
+
1
,
temperature
));
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 切换到爬山法求精"
);
HillClimbing
hillClimbing
=
new
HillClimbing
(
allOperations
);
Chromosome
refined
=
hillClimbing
.
search
(
best
,
decoder
,
machines
);
HillClimbing
hillClimbing
=
new
HillClimbing
(
allOperations
);
Chromosome
refined
=
hillClimbing
.
search
(
best
,
decoder
,
machines
);
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 爬山法求精完成"
);
// 返回爬山法求精后的结果
return
refined
;
}
}
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 完成所有%d次迭代,最终fitness=%.4f"
,
maxIterations
,
best
.
getFitness
()));
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 完成所有%d次迭代,最终fitness=%.4f"
,
maxIterations
,
best
.
getFitness
()));
// 7. 输出全局最优排产
return
best
;
}
private
void
writeKpi
(
Chromosome
chromosome
)
{
String
fitness
=
""
;
double
[]
fitness1
=
chromosome
.
getFitnessLevel
();
for
(
int
i
=
0
;
i
<
fitness1
.
length
;
i
++)
{
fitness
+=
fitness1
[
i
]
+
","
;
}
FileHelper
.
writeLogFile
(
String
.
format
(
"爬山法 - kpi:%s"
,
fitness
));
}
/**
* 计算能量差(基于fitnessLevel数组的比较)
...
...
@@ -163,6 +188,77 @@ public class SimulatedAnnealing {
}
return
diff
;
}
/**
* 按优先级分组工序
*/
private
Map
<
Double
,
List
<
Entry
>>
groupOperationsByPriority
()
{
Map
<
Double
,
List
<
Entry
>>
groups
=
new
HashMap
<>();
for
(
Entry
op
:
allOperations
)
{
double
priority
=
op
.
getPriority
();
groups
.
computeIfAbsent
(
priority
,
k
->
new
ArrayList
<>()).
add
(
op
);
}
// 过滤掉:设备只有一个且只有一个GroupId的优先级组
Map
<
Double
,
List
<
Entry
>>
filteredGroups
=
new
HashMap
<>();
for
(
Map
.
Entry
<
Double
,
List
<
Entry
>>
entry
:
groups
.
entrySet
())
{
List
<
Entry
>
ops
=
entry
.
getValue
();
// 检查是否所有工序都只有一个设备选项
boolean
allSingleMachine
=
ops
.
stream
()
.
allMatch
(
op
->
op
.
getMachineOptions
().
size
()
<=
1
);
// 检查是否只有一个GroupId
Set
<
Integer
>
groupIds
=
ops
.
stream
()
.
map
(
Entry:
:
getGroupId
)
.
collect
(
Collectors
.
toSet
());
// 如果两个条件都满足,过滤掉这个优先级组
if
(!(
allSingleMachine
&&
groupIds
.
size
()
<=
1
))
{
filteredGroups
.
put
(
entry
.
getKey
(),
ops
);
}
}
return
filteredGroups
;
}
/**
* 构建位置索引:groupId_sequence -> position
*/
private
Map
<
String
,
Integer
>
buildPositionIndex
(
Chromosome
chromosome
)
{
Map
<
String
,
Integer
>
index
=
new
HashMap
<>();
List
<
Integer
>
os
=
chromosome
.
getOperationSequencing
();
Map
<
Integer
,
Integer
>
orderProcessCounter
=
new
HashMap
<>();
for
(
int
i
=
0
;
i
<
os
.
size
();
i
++)
{
int
groupId
=
os
.
get
(
i
);
int
count
=
orderProcessCounter
.
getOrDefault
(
groupId
,
0
)
+
1
;
orderProcessCounter
.
put
(
groupId
,
count
);
String
key
=
groupId
+
"_"
+
count
;
index
.
put
(
key
,
i
);
}
return
index
;
}
/**
* 构建位置索引:groupId_sequence -> Machines position
*/
private
Map
<
String
,
Integer
>
buildEntryMachinePositionIndex
(
Chromosome
chromosome
)
{
Map
<
String
,
Integer
>
index
=
new
HashMap
<>();
List
<
GlobalOperationInfo
>
globalOpList
=
chromosome
.
getGlobalOpList
();
for
(
int
i
=
0
;
i
<
globalOpList
.
size
();
i
++)
{
GlobalOperationInfo
globalOp
=
globalOpList
.
get
(
i
);
Entry
op
=
globalOp
.
getOp
();
int
groupId
=
op
.
getGroupId
();
int
count
=
op
.
getSequence
();
String
key
=
groupId
+
"_"
+
count
;
index
.
put
(
key
,
i
);
}
return
index
;
}
/**
* 构建位置->Entry索引
*/
...
...
@@ -188,39 +284,428 @@ public class SimulatedAnnealing {
/**
* 构建Entry索引:op.getGroupId() + "_" + op.getSequence() -> Entry
*/
private
Map
<
String
,
Entry
>
buildEntryKey
(
Chromosome
chromosome
)
{
private
Map
<
Integer
,
Object
>
buildEntryKey
()
{
Map
<
Integer
,
Object
>
index0
=
new
HashMap
<>();
Map
<
String
,
Entry
>
index
=
new
HashMap
<>();
List
<
Entry
>
allOps
=
chromosome
.
getAllOperations
()
;
Map
<
Integer
,
Entry
>
index2
=
new
HashMap
<>();
List
<
Entry
>
allOps
=
this
.
allOperations
;
for
(
Entry
op
:
allOps
)
{
String
key
=
op
.
getGroupId
()
+
"_"
+
op
.
getSequence
();
index
.
put
(
key
,
op
);
index2
.
put
(
op
.
getId
(),
op
);
}
index0
.
put
(
1
,
index
);
index0
.
put
(
2
,
index2
);
return
index0
;
}
return
index
;
/**
* 生成邻域解 - 智能策略:优先处理瓶颈工序/设备
* 策略:
* 1. 优先处理瓶颈设备上的工序(换设备)
* 2. 瓶颈设备上的工序往前移动
* 3. 非瓶颈设备上的工序往后移动(给瓶颈工序腾位置)
*/
private
Chromosome
generateNeighbor
(
Chromosome
chromosome
)
{
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
if
(
results
==
null
||
results
.
isEmpty
())
{
return
generateRandomNeighbor
(
chromosome
,
entrys
);
}
// 构建位置索引
Map
<
String
,
Integer
>
positionIndex
=
buildPositionIndex
(
chromosome
);
Map
<
Integer
,
Entry
>
positionToEntryIndex
=
buildPositionToEntryIndex
(
chromosome
,
entrys
);
Map
<
String
,
Integer
>
MachinePositionIndex
=
buildEntryMachinePositionIndex
(
chromosome
);
// 1. 找出瓶颈设备
Long
bottleneckMachineId
=
findBottleneckMachine
(
chromosome
);
if
(
bottleneckMachineId
!=
null
)
{
// 找出瓶颈设备上的工序
List
<
GAScheduleResult
>
bottleneckOps
=
findOpsOnBottleneckMachine
(
chromosome
,
bottleneckMachineId
);
if
(!
bottleneckOps
.
isEmpty
())
{
// 70%概率优先处理瓶颈设备
if
(
rnd
.
nextDouble
()
<
0.7
)
{
int
strategy
=
rnd
.
nextInt
(
10
);
if
(
strategy
<=
3
)
{
// 策略1:瓶颈设备上的工序换设备
return
tryChangeMachineForBottleneckOp
(
chromosome
,
bottleneckOps
,
entrys
,
MachinePositionIndex
);
}
else
if
(
strategy
<=
8
)
{
// 策略2:瓶颈设备上的工序往前移动
return
tryMoveBottleneckOpForward
(
chromosome
,
bottleneckOps
,
positionIndex
,
positionToEntryIndex
,
entrys
);
}
else
if
(
strategy
<=
10
)
{
// 策略3:非瓶颈设备上的工序往后移动
return
tryMoveNonBottleneckOpBackward
(
chromosome
,
bottleneckMachineId
,
positionIndex
,
positionToEntryIndex
,
entrys
);
}
}
}
}
// 默认策略:随机邻域
return
generateRandomNeighbor
(
chromosome
,
entrys
);
}
/**
* 识别瓶颈设备(利用率最高的设备)
*/
private
Long
findBottleneckMachine
(
Chromosome
chromosome
)
{
Map
<
Long
,
Double
>
utilization
=
calculateMachineUtilization
(
chromosome
);
if
(
utilization
.
isEmpty
())
{
return
null
;
}
return
utilization
.
entrySet
().
stream
()
.
max
(
Map
.
Entry
.
comparingByValue
())
.
map
(
Map
.
Entry
::
getKey
)
.
orElse
(
null
);
}
/**
* 查找在瓶颈设备上的工序
*/
private
List
<
GAScheduleResult
>
findOpsOnBottleneckMachine
(
Chromosome
chromosome
,
Long
bottleneckMachineId
)
{
if
(
bottleneckMachineId
==
null
)
{
return
new
ArrayList
<>();
}
return
chromosome
.
getResult
().
stream
()
.
filter
(
r
->
r
.
getMachineId
()
==
bottleneckMachineId
)
.
collect
(
Collectors
.
toList
());
}
/**
* 计算设备利用率
*/
private
Map
<
Long
,
Double
>
calculateMachineUtilization
(
Chromosome
chromosome
)
{
Map
<
Long
,
Double
>
utilization
=
new
HashMap
<>();
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
if
(
results
==
null
||
results
.
isEmpty
())
{
return
utilization
;
}
int
maxEndTime
=
results
.
stream
()
.
mapToInt
(
GAScheduleResult:
:
getEndTime
)
.
max
()
.
orElse
(
1
);
Map
<
Long
,
List
<
GAScheduleResult
>>
machineResults
=
results
.
stream
()
.
collect
(
Collectors
.
groupingBy
(
GAScheduleResult:
:
getMachineId
));
for
(
Map
.
Entry
<
Long
,
List
<
GAScheduleResult
>>
entry
:
machineResults
.
entrySet
())
{
long
machineId
=
entry
.
getKey
();
List
<
GAScheduleResult
>
machineOps
=
entry
.
getValue
();
int
totalProcessingTime
=
machineOps
.
stream
()
.
mapToInt
(
r
->
r
.
getEndTime
()
-
r
.
getStartTime
())
.
sum
();
double
util
=
(
double
)
totalProcessingTime
/
maxEndTime
;
utilization
.
put
(
machineId
,
util
);
}
return
utilization
;
}
/**
* 尝试给瓶颈设备上的工序换设备
*/
private
Chromosome
tryChangeMachineForBottleneckOp
(
Chromosome
chromosome
,
List
<
GAScheduleResult
>
bottleneckOps
,
Map
<
String
,
Entry
>
entrys
,
Map
<
String
,
Integer
>
MachinePositionIndex
)
{
// 优先选择有多设备选项的工序
List
<
GAScheduleResult
>
candidates
=
bottleneckOps
.
stream
()
.
filter
(
op
->
{
Entry
entry
=
entrybyids
.
get
(
op
.
getOperationId
());
return
entry
!=
null
&&
entry
.
getMachineOptions
().
size
()
>
1
;
})
.
collect
(
Collectors
.
toList
());
if
(
candidates
.
isEmpty
())
{
return
generateRandomNeighbor
(
chromosome
,
entrys
);
}
// 从候选中随机选择一个工序,给它换设备
GAScheduleResult
selectedOp
=
candidates
.
get
(
rnd
.
nextInt
(
candidates
.
size
()));
// 找到这个工序在globalOpList中的位置
int
maPos
=
-
1
;
Entry
entry
=
entrybyids
.
get
(
selectedOp
.
getOperationId
());
if
(
entry
!=
null
&&
entry
.
getMachineOptions
().
size
()
>
1
)
{
maPos
=
MachinePositionIndex
.
get
(
entry
.
getGroupId
()
+
"_"
+
entry
.
getSequence
());
if
(
maPos
>=
0
)
{
return
generateMachineChangeForSpecificOp
(
chromosome
,
entry
.
getMachineOptions
(),
maPos
);
}
}
// 直接换设备
return
generateMachineChangeNeighbor
(
chromosome
);
}
/**
* 给指定位置的工序换设备
*/
private
Chromosome
generateMachineChangeForSpecificOp
(
Chromosome
chromosome
,
List
<
MachineOption
>
machineOptions
,
int
idx
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
ms
=
neighbor
.
getMachineSelection
();
if
(!
ms
.
isEmpty
()
&&
idx
>=
0
&&
idx
<
ms
.
size
())
{
if
(
machineOptions
.
size
()
>
1
)
{
int
currentMachineSeq
=
ms
.
get
(
idx
);
List
<
Integer
>
availableMachines
=
new
ArrayList
<>();
for
(
int
i
=
1
;
i
<=
machineOptions
.
size
();
i
++)
{
if
(
i
!=
currentMachineSeq
)
{
availableMachines
.
add
(
i
);
}
}
if
(!
availableMachines
.
isEmpty
())
{
int
newMachineSeq
=
availableMachines
.
get
(
rnd
.
nextInt
(
availableMachines
.
size
()));
ms
.
set
(
idx
,
newMachineSeq
);
neighbor
.
setMachineSelection
(
ms
);
}
}
}
return
neighbor
;
}
/**
* 尝试将瓶颈设备上的工序往前移动
*/
private
Chromosome
tryMoveBottleneckOpForward
(
Chromosome
chromosome
,
List
<
GAScheduleResult
>
bottleneckOps
,
Map
<
String
,
Integer
>
positionIndex
,
Map
<
Integer
,
Entry
>
positionToEntryIndex
,
Map
<
String
,
Entry
>
entrys
)
{
if
(
bottleneckOps
.
isEmpty
())
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
}
// 随机选择一个瓶颈工序
// GAScheduleResult randomOp = bottleneckOps.get(rnd.nextInt(bottleneckOps.size()));
// 计算所有订单的完成时间
List
<
GAScheduleResult
>
allResults
=
chromosome
.
getResult
();
Map
<
Integer
,
Integer
>
orderCompletionTimes
=
calculateOrderCompletionTimes
(
allResults
);
// 找出最晚完成的订单(延期候选)
int
latestCompletionTime
=
orderCompletionTimes
.
values
().
stream
()
.
mapToInt
(
Integer:
:
intValue
)
.
max
()
.
orElse
(
0
);
// 按优先级和订单完成时间排序:优先选择高优先级+延期订单的工序
List
<
GAScheduleResult
>
sortedBottleneckOps
=
new
ArrayList
<>(
bottleneckOps
);
sortedBottleneckOps
.
sort
((
a
,
b
)
->
{
Entry
entryA
=
entrybyids
.
get
(
a
.
getOperationId
());
Entry
entryB
=
entrybyids
.
get
(
b
.
getOperationId
());
if
(
entryA
!=
null
&&
entryB
!=
null
)
{
// 首先比较优先级(高优先级在前)
int
priorityCompare
=
Double
.
compare
(
entryB
.
getPriority
(),
entryA
.
getPriority
());
if
(
priorityCompare
!=
0
)
{
return
priorityCompare
;
}
// 优先级相同,比较订单完成时间(晚完成的在前,即更可能延期)
int
endTimeA
=
orderCompletionTimes
.
getOrDefault
(
a
.
getGroupId
(),
0
);
int
endTimeB
=
orderCompletionTimes
.
getOrDefault
(
b
.
getGroupId
(),
0
);
return
Integer
.
compare
(
endTimeB
,
endTimeA
);
}
return
0
;
});
GAScheduleResult
selectedOp
=
sortedBottleneckOps
.
get
(
rnd
.
nextInt
(
Math
.
min
(
5
,
sortedBottleneckOps
.
size
())));
Entry
entry
=
entrybyids
.
get
(
selectedOp
.
getOperationId
())
;
String
key
=
entry
.
getGroupId
()
+
"_"
+
entry
.
getSequence
();
Integer
opPos
=
positionIndex
.
get
(
key
);
if
(
opPos
==
null
||
opPos
<=
0
)
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
}
// 往前移动1-3步
// int steps = rnd.nextInt(3) + 1;
// return moveOperationForward(chromosome,positionToEntryIndex, opPos, steps);
// 使用插入方式往前移动(1-5步)
int
steps
=
rnd
.
nextInt
(
5
)
+
1
;
return
insertOperationForward
(
chromosome
,
opPos
,
steps
,
entrys
);
}
/**
* 计算每个订单的最后完成时间
*/
private
Map
<
Integer
,
Integer
>
calculateOrderCompletionTimes
(
List
<
GAScheduleResult
>
allResults
)
{
Map
<
Integer
,
Integer
>
orderEndTimes
=
new
HashMap
<>();
for
(
GAScheduleResult
result
:
allResults
)
{
int
groupId
=
result
.
getGroupId
();
int
endTime
=
result
.
getEndTime
();
orderEndTimes
.
put
(
groupId
,
Math
.
max
(
orderEndTimes
.
getOrDefault
(
groupId
,
0
),
endTime
));
}
return
orderEndTimes
;
}
/**
* 尝试将非瓶颈设备上的工序往后移动(给瓶颈工序腾位置)
*/
private
Chromosome
tryMoveNonBottleneckOpBackward
(
Chromosome
chromosome
,
Long
bottleneckMachineId
,
Map
<
String
,
Integer
>
positionIndex
,
Map
<
Integer
,
Entry
>
positionToEntryIndex
,
Map
<
String
,
Entry
>
entrys
)
{
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
if
(
results
==
null
)
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
}
// 找出非瓶颈设备上的工序
List
<
GAScheduleResult
>
nonBottleneckOps
=
results
.
stream
()
.
filter
(
r
->
r
.
getMachineId
()
!=
bottleneckMachineId
)
.
collect
(
Collectors
.
toList
());
if
(
nonBottleneckOps
.
isEmpty
())
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
}
// 随机选择一个非瓶颈工序
GAScheduleResult
randomOp
=
nonBottleneckOps
.
get
(
rnd
.
nextInt
(
nonBottleneckOps
.
size
()));
Entry
entry
=
entrybyids
.
get
(
randomOp
.
getOperationId
());
String
key
=
entry
.
getGroupId
()+
"_"
+
entry
.
getSequence
();
Integer
opPos
=
positionIndex
.
get
(
key
);
if
(
opPos
==
null
||
opPos
>=
chromosome
.
getOperationSequencing
().
size
()
-
1
)
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
}
// 往后移动1-3步
int
steps
=
rnd
.
nextInt
(
3
)
+
1
;
return
moveOperationBackward
(
chromosome
,
positionToEntryIndex
,
opPos
,
steps
);
}
/**
*
生成邻域解
*
将工序往前移动
*/
private
Chromosome
generateNeighbor
(
Chromosome
chromosome
,
Map
<
String
,
Entry
>
entrys
)
{
private
Chromosome
moveOperationForward
(
Chromosome
chromosome
,
Map
<
Integer
,
Entry
>
originalPositionIndex
,
int
pos
,
int
steps
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
pos
<=
0
||
pos
>=
os
.
size
())
{
return
neighbor
;
}
// 获取要移动的工序和目标位置的工序(基于原始chromosome)
Entry
opToMove
=
originalPositionIndex
.
get
(
pos
);
if
(
opToMove
==
null
)
{
return
neighbor
;
}
int
targetPos
=
Math
.
max
(
0
,
pos
-
steps
);
Entry
targetOp
=
originalPositionIndex
.
get
(
targetPos
);
// 检查是否可以交换
if
(
targetOp
!=
null
&&
opToMove
.
getGroupId
()
==
targetOp
.
getGroupId
())
{
return
neighbor
;
}
if
(
targetOp
!=
null
&&
Math
.
abs
(
targetOp
.
getPriority
()
-
opToMove
.
getPriority
())
>
0.001
)
{
return
neighbor
;
}
// 直接交换到目标位置
java
.
util
.
Collections
.
swap
(
os
,
pos
,
targetPos
);
neighbor
.
setOperationSequencing
(
os
);
return
neighbor
;
}
/**
* 将工序往后移动
*/
private
Chromosome
moveOperationBackward
(
Chromosome
chromosome
,
Map
<
Integer
,
Entry
>
originalPositionIndex
,
int
pos
,
int
steps
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
pos
<
0
||
pos
>=
os
.
size
()
-
1
)
{
return
neighbor
;
}
// 获取要移动的工序和目标位置的工序(基于原始chromosome)
Entry
opToMove
=
originalPositionIndex
.
get
(
pos
);
if
(
opToMove
==
null
)
{
return
neighbor
;
}
int
targetPos
=
Math
.
min
(
os
.
size
()
-
1
,
pos
+
steps
);
Entry
targetOp
=
originalPositionIndex
.
get
(
targetPos
);
// 检查是否可以交换
if
(
targetOp
!=
null
&&
opToMove
.
getGroupId
()
==
targetOp
.
getGroupId
())
{
return
neighbor
;
}
if
(
targetOp
!=
null
&&
Math
.
abs
(
targetOp
.
getPriority
()
-
opToMove
.
getPriority
())
>
0.001
)
{
return
neighbor
;
}
// 直接交换到目标位置
java
.
util
.
Collections
.
swap
(
os
,
pos
,
targetPos
);
neighbor
.
setOperationSequencing
(
os
);
return
neighbor
;
}
/**
* 将工序往前插入(不交换,直接插入到目标位置)
*/
private
Chromosome
insertOperationForward
(
Chromosome
chromosome
,
int
pos
,
int
steps
,
Map
<
String
,
Entry
>
entrys
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
pos
<=
0
||
pos
>=
os
.
size
())
{
return
neighbor
;
}
// 获取要移动的工序(基于原始chromosome)
Map
<
Integer
,
Entry
>
originalPositionIndex
=
buildPositionToEntryIndex
(
chromosome
,
entrys
);
Entry
opToMove
=
originalPositionIndex
.
get
(
pos
);
if
(
opToMove
==
null
)
{
return
neighbor
;
}
// 找到最远可以插入的位置(不打破优先级)
int
targetPos
=
Math
.
max
(
0
,
pos
-
steps
);
int
finalTargetPos
=
pos
;
for
(
int
i
=
pos
-
1
;
i
>=
targetPos
;
i
--)
{
Entry
leftOp
=
originalPositionIndex
.
get
(
i
);
if
(
leftOp
!=
null
&&
opToMove
.
getGroupId
()
==
leftOp
.
getGroupId
())
{
break
;
}
if
(
leftOp
!=
null
&&
Math
.
abs
(
leftOp
.
getPriority
()
-
opToMove
.
getPriority
())
>
0.001
)
{
break
;
}
finalTargetPos
=
i
;
}
if
(
finalTargetPos
==
pos
)
{
return
neighbor
;
}
// 执行插入:移除原位置,插入到目标位置
int
value
=
os
.
remove
(
pos
);
os
.
add
(
finalTargetPos
,
value
);
neighbor
.
setOperationSequencing
(
os
);
return
neighbor
;
}
/**
* 随机生成邻域解(兜底策略)
*/
private
Chromosome
generateRandomNeighbor
(
Chromosome
chromosome
,
Map
<
String
,
Entry
>
entrys
)
{
int
neighborType
=
rnd
.
nextInt
(
4
);
switch
(
neighborType
)
{
case
0
:
return
generateSwapNeighbor
(
chromosome
,
entrys
);
return
generateSwapNeighbor
(
chromosome
,
entrys
);
case
1
:
return
generateReverseNeighbor
(
chromosome
,
entrys
);
return
generateReverseNeighbor
(
chromosome
,
entrys
);
case
2
:
return
generateInsertNeighbor
(
chromosome
,
entrys
);
return
generateInsertNeighbor
(
chromosome
,
entrys
);
case
3
:
return
generateMachineChangeNeighbor
(
chromosome
);
default
:
return
generateSwapNeighbor
(
chromosome
,
entrys
);
return
generateSwapNeighbor
(
chromosome
,
entrys
);
}
}
/**
* 生成交换邻域解 - 只在相同优先级的工序之间交换
*/
...
...
@@ -332,7 +817,7 @@ public class SimulatedAnnealing {
List
<
Integer
>
ms
=
neighbor
.
getMachineSelection
();
if
(!
ms
.
isEmpty
())
{
int
idx
=
rnd
.
nextInt
(
ms
.
size
());
GlobalOperationInfo
globalOp
=
globalOpList
.
get
(
idx
);
GlobalOperationInfo
globalOp
=
chromosome
.
getGlobalOpList
()
.
get
(
idx
);
Entry
op
=
globalOp
.
getOp
();
if
(
op
.
getMachineOptions
().
size
()
>
1
)
{
...
...
src/main/java/com/aps/service/Algorithm/TabuSearch.java
View file @
25c58c5b
...
...
@@ -29,6 +29,8 @@ public class TabuSearch {
this
.
fitnessCalculator
=
fitnessCalculator
;
this
.
objectiveWeights
=
objectiveWeights
;
this
.
tabuList
=
new
ArrayList
<>();
// 工序越多,禁忌表越长(适配1000+工序)
this
.
tabuListSize
=
Math
.
min
(
50
,
allOperations
.
size
()
/
30
);
}
/**
...
...
src/main/java/com/aps/service/plan/PlanResultService.java
View file @
25c58c5b
...
...
@@ -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
...
...
@@ -99,6 +98,8 @@ public class PlanResultService {
@Autowired
private
OrderSortService
orderSortService
;
@Autowired
private
LanuchService
lanuchService
;
@Autowired
private
MaterialInfoMapper
materialInfoMapper
;
...
...
@@ -124,6 +125,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 +147,6 @@ public class PlanResultService {
public
Chromosome
execute2
(
String
SceneId
)
{
try
{
ScheduleParams
param
=
InitScheduleParams
();
...
...
@@ -208,18 +217,25 @@ public class PlanResultService {
.
map
(
Material:
:
getId
)
.
distinct
()
.
collect
(
Collectors
.
toList
());
globalParam
.
setPureNSGAIIMode
(
false
);
ApsTimeConfig
timeConfig
=
apsTimeConfigService
.
getOne
(
new
LambdaQueryWrapper
<>());
// 4.5 在排产前标记锁定期工单占用的设备时间段
lockedOrderProcessorService
.
markLockedOrdersOccupiedTime
(
machines
,
timeConfig
.
getBaseTime
());
// 5. 执行调度算法
HybridAlgorithm
scheduler
=
new
Hybrid
Algorithm
(
globalParam
,
machines
,
orders
,
Materials1
,
materialIds
,
machineScheduler
,
entryRel
,
materialRequirementService
,
_sceneService
,
SceneId
);
//new GeneticAlgorithm(products, machines, orders, machineScheduler);
GeneticAlgorithm
scheduler
=
new
Genetic
Algorithm
(
globalParam
,
machines
,
orders
,
Materials1
,
materialIds
,
machineScheduler
,
entryRel
,
materialRequirementService
,
_sceneService
,
SceneId
);
//new GeneticAlgorithm(products, machines, orders, machineScheduler);
param
.
initAdaptiveParams
(
entrys
.
size
());
double
[]
customWeights
=
new
double
[]
{
0.4
,
0.1
,
0.1
,
0.1
,
0.3
};
// 延迟时间权重提升到0.5
//完工时间、总流程时间、总换型时间、机器负载标准差、延迟时间
scheduler
.
Init
();
// scheduler.Init(customWeights,false);
Chromosome
chromosome
=
scheduler
.
Run
(
param
,
entrys
);
KpiCalculator
kpiCalculator
=
new
KpiCalculator
(
chromosome
);
kpiCalculator
.
calculatekpi
();
// 添加锁定期工单到调度结果中
// 这里会从 Dispatch 表加载锁定期工单,并添加到 chromosome.result 中
lockedOrderProcessorService
.
addLockedOrdersToResult
(
chromosome
);
_sceneService
.
saveChromosomeToFile
(
chromosome
,
SceneId
);
WriteScheduleSummary
(
chromosome
);
...
...
@@ -231,6 +247,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.debug("冻结期秒数为{},跳过添加锁定期工单", 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
)
{
...
...
@@ -424,6 +1243,17 @@ public class PlanResultService {
entry
.
setPriority
(
order
.
getActualPriority
());
});
}
// 更新调度结果中的数量(关键:处理锁定期工单)
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
if
(
results
!=
null
)
{
results
.
stream
()
.
filter
(
result
->
result
.
getOrderId
()
!=
null
&&
result
.
getOrderId
().
equals
(
order
.
getOrderId
()))
.
forEach
(
result
->
{
result
.
setQuantity
(
order
.
getQuantity
());
log
.
info
(
"更新调度结果中的订单数量: OrderId={}, 新数量={}"
,
order
.
getOrderId
(),
order
.
getQuantity
());
});
}
}
/**
...
...
@@ -458,6 +1288,10 @@ public class PlanResultService {
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
// 拖拽前清理历史工单在设备上的静态占位段,确保历史工单移动后可释放产能
int
releasedCount
=
releaseLockedOccupancyForDrag
(
chromosome
);
// WriteScheduleSummary(chromosome);
ScheduleOperationService
ScheduleOperation
=
new
ScheduleOperationService
(
materialRequirementService
,
this
);
...
...
@@ -468,6 +1302,150 @@ public class PlanResultService {
_sceneService
.
saveChromosomeToFile
(
chromosome
,
SceneId
);
return
chromosome
;
}
/**
* 释放历史工单占用段(拖拽前调用)
*/
private
int
releaseLockedOccupancyForDrag
(
Chromosome
chromosome
)
{
if
(
chromosome
==
null
||
chromosome
.
getInitMachines
()
==
null
||
chromosome
.
getInitMachines
().
isEmpty
())
{
return
0
;
}
int
releasedCount
=
0
;
for
(
Machine
machine
:
chromosome
.
getInitMachines
())
{
if
(
machine
==
null
||
machine
.
getAvailability
()
==
null
||
machine
.
getAvailability
().
isEmpty
())
{
continue
;
}
for
(
TimeSegment
segment
:
machine
.
getAvailability
())
{
if
(
segment
==
null
)
{
continue
;
}
boolean
lockedOccupyKey
=
segment
.
getKey
()
!=
null
&&
segment
.
getKey
().
startsWith
(
"LOCKED_OCCUPY_"
);
boolean
usedRegularOrMaintenance
=
segment
.
isUsed
()
&&
(
segment
.
getType
()
==
SegmentType
.
REGULAR
||
segment
.
getType
()
==
SegmentType
.
MAINTENANCE
);
if
(
lockedOccupyKey
||
usedRegularOrMaintenance
)
{
releasedCount
++;
segment
.
setUsed
(
false
);
segment
.
setType
(
SegmentType
.
REGULAR
);
if
(
lockedOccupyKey
)
{
segment
.
setKey
(
UUID
.
randomUUID
().
toString
());
}
}
}
machine
.
getAvailability
().
sort
(
Comparator
.
comparing
(
TimeSegment:
:
getStart
));
}
return
releasedCount
;
}
public
Chromosome
InsertOrderAuto
(
String
sceneId
,
Map
<
String
,
Object
>
newOrderData
)
{
if
(
newOrderData
==
null
)
{
throw
new
RuntimeException
(
"newOrder 不能为空"
);
}
String
orderCode
=
String
.
valueOf
(
newOrderData
.
get
(
"orderCode"
));
String
materialId
=
String
.
valueOf
(
newOrderData
.
get
(
"materialId"
));
Object
qtyObj
=
newOrderData
.
get
(
"quantity"
);
if
(
orderCode
==
null
||
orderCode
.
trim
().
isEmpty
())
{
throw
new
RuntimeException
(
"orderCode 不能为空"
);
}
if
(
materialId
==
null
||
materialId
.
trim
().
isEmpty
())
{
throw
new
RuntimeException
(
"materialId 不能为空"
);
}
if
(
qtyObj
==
null
)
{
throw
new
RuntimeException
(
"quantity 不能为空"
);
}
Double
quantity
=
Double
.
valueOf
(
String
.
valueOf
(
qtyObj
));
// 1. 创建新订单(沿用现有创建逻辑)
R
<
String
>
insertResp
=
lanuchService
.
insertOrder
(
sceneId
,
orderCode
,
materialId
,
null
,
null
,
1
,
quantity
);
String
insertMsg
=
insertResp
!=
null
?
insertResp
.
getData
()
:
null
;
if
(
insertMsg
==
null
||
insertMsg
.
trim
().
isEmpty
())
{
throw
new
RuntimeException
(
"创建订单失败:未返回订单ID"
);
}
String
newOrderId
=
insertMsg
;
if
(
insertMsg
.
contains
(
"订单ID:"
))
{
newOrderId
=
insertMsg
.
substring
(
insertMsg
.
indexOf
(
"订单ID:"
)
+
5
).
trim
();
}
// 2. 读取场景排产结果
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
sceneId
);
if
(
chromosome
==
null
)
{
throw
new
RuntimeException
(
"场景不存在或排产结果未初始化"
);
}
// 3. 查询新订单及其工序
ProdLaunchOrder
newLaunchOrder
=
_prodLaunchOrderService
.
lambdaQuery
()
.
eq
(
ProdLaunchOrder:
:
getSceneId
,
sceneId
)
.
eq
(
ProdLaunchOrder:
:
getOrderId
,
newOrderId
)
.
one
();
if
(
newLaunchOrder
==
null
)
{
throw
new
RuntimeException
(
"新订单不存在:"
+
newOrderId
);
}
List
<
ProdProcessExec
>
newProcessExecs
=
_prodProcessExecService
.
lambdaQuery
()
.
eq
(
ProdProcessExec:
:
getSceneId
,
sceneId
)
.
eq
(
ProdProcessExec:
:
getOrderId
,
newOrderId
)
.
orderByAsc
(
ProdProcessExec:
:
getTaskSeq
)
.
list
();
if
(
newProcessExecs
==
null
||
newProcessExecs
.
isEmpty
())
{
throw
new
RuntimeException
(
"新订单没有工序:"
+
newOrderId
);
}
// 3.1 查询新工序对应设备(与InitEntrys对齐:execId -> prod_equipment)
List
<
String
>
execIds
=
newProcessExecs
.
stream
()
.
map
(
ProdProcessExec:
:
getExecId
)
.
filter
(
Objects:
:
nonNull
)
.
distinct
()
.
collect
(
Collectors
.
toList
());
List
<
ProdEquipment
>
newProdEquipments
=
execIds
.
isEmpty
()
?
new
ArrayList
<>()
:
_prodEquipmentService
.
lambdaQuery
()
.
eq
(
ProdEquipment:
:
getSceneId
,
sceneId
)
.
in
(
ProdEquipment:
:
getExecId
,
execIds
)
.
list
();
if
(
newProdEquipments
==
null
||
newProdEquipments
.
isEmpty
())
{
throw
new
RuntimeException
(
"自动插单失败:新工单未生成可选设备,请检查PROD_EQUIPMENT"
);
}
// 4. 计算锚点时间:基准时间 + 冻结期
LocalDateTime
baseTime
=
chromosome
.
getBaseTime
();
LambdaQueryWrapper
<
ApsTimeConfig
>
queryWrapper
=
new
LambdaQueryWrapper
<>();
ApsTimeConfig
apsTimeConfig
=
apsTimeConfigMapper
.
selectOne
(
queryWrapper
);
long
freezeSeconds
=
0L
;
if
(
apsTimeConfig
!=
null
&&
apsTimeConfig
.
getFreezeDate
()
!=
null
)
{
freezeSeconds
=
apsTimeConfig
.
getFreezeDate
().
longValue
();
}
if
(
apsTimeConfig
!=
null
&&
apsTimeConfig
.
getBaseTime
()
!=
null
)
{
baseTime
=
apsTimeConfig
.
getBaseTime
();
}
LocalDateTime
anchorTime
=
baseTime
.
plusSeconds
(
Math
.
max
(
freezeSeconds
,
0L
));
// 5. 自动插单(占位后推 + 空挡前移)
GlobalParam
globalParam
=
InitGlobalParam
();
ScheduleOperationService
scheduleOperation
=
new
ScheduleOperationService
(
materialRequirementService
,
this
);
scheduleOperation
.
InsertOrderAuto
(
chromosome
,
newOrderId
,
newLaunchOrder
,
newProcessExecs
,
newProdEquipments
,
anchorTime
,
globalParam
);
// 6. 保存
WriteScheduleSummary
(
chromosome
);
_sceneService
.
saveChromosomeToFile
(
chromosome
,
sceneId
);
return
chromosome
;
}
public
Chromosome
Move
(
String
SceneId
,
List
<
Integer
>
opId
,
LocalDateTime
newStartTime
,
Long
newMachineId
,
int
lockStartTime
)
{
...
...
@@ -608,6 +1586,92 @@ public class PlanResultService {
_sceneService
.
saveChromosomeToFile
(
chromosome
,
SceneId
);
return
chromosome
;
}
/**
* 插单功能:在指定订单后插入新订单
* 步骤1:先将新订单数据插入数据库
* 步骤2:使用类似复制订单的方式将新订单加入排产
*
* @param SceneId 场景ID
* @param afterOrderId 插入位置订单ID(新订单将排在此订单后面)
* @param newOrderData 新订单数据
* @return 更新后的Chromosome
*/
public
Chromosome
InsertOrder
(
String
SceneId
,
String
afterOrderId
,
Map
<
String
,
Object
>
newOrderData
)
{
// 步骤1:调用LanuchService的insertOrder方法,将新订单插入数据库
String
orderCode
=
(
String
)
newOrderData
.
get
(
"orderCode"
);
String
materialId
=
(
String
)
newOrderData
.
get
(
"materialId"
);
Double
quantity
=
((
Number
)
newOrderData
.
get
(
"quantity"
)).
doubleValue
();
LocalDateTime
startDate
=
null
;
LocalDateTime
endDate
=
null
;
Integer
priority
=
1
;
if
(
newOrderData
.
containsKey
(
"startDate"
))
{
startDate
=
LocalDateTime
.
parse
((
String
)
newOrderData
.
get
(
"startDate"
));
}
if
(
newOrderData
.
containsKey
(
"endDate"
))
{
endDate
=
LocalDateTime
.
parse
((
String
)
newOrderData
.
get
(
"endDate"
));
}
if
(
newOrderData
.
containsKey
(
"priority"
))
{
priority
=
((
Number
)
newOrderData
.
get
(
"priority"
)).
intValue
();
}
// 调用insertOrder插入数据库
R
<
String
>
insertResult
=
lanuchService
.
insertOrder
(
SceneId
,
orderCode
,
materialId
,
startDate
,
endDate
,
priority
,
quantity
);
// if (!insertResult.isSuccess()) {
// throw new RuntimeException("插单失败: " + insertResult.getMsg());
// }
//
// 从返回消息中提取新订单ID
String
message
=
insertResult
.
getData
();
String
newOrderId
=
message
.
substring
(
message
.
indexOf
(
"订单ID: "
)
+
6
);
log
.
info
(
"新订单已插入数据库,订单ID: {}"
,
newOrderId
);
// 步骤2:使用类似SpiltOrder的方式,将新订单加入排产
// 这里需要重新加载场景,因为数据库已经有新订单了
// 然后使用类似复制的逻辑,将新订单排在afterOrderId后面
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
// 从数据库加载新插入的订单及其工序
ProdLaunchOrder
newLaunchOrder
=
_prodLaunchOrderService
.
lambdaQuery
()
.
eq
(
ProdLaunchOrder:
:
getSceneId
,
SceneId
)
.
eq
(
ProdLaunchOrder:
:
getOrderId
,
newOrderId
)
.
one
();
if
(
newLaunchOrder
==
null
)
{
throw
new
RuntimeException
(
"未找到新插入的订单: "
+
newOrderId
);
}
// 加载新订单的工序
List
<
ProdProcessExec
>
newProcessExecs
=
_prodProcessExecService
.
lambdaQuery
()
.
eq
(
ProdProcessExec:
:
getSceneId
,
SceneId
)
.
eq
(
ProdProcessExec:
:
getOrderId
,
newOrderId
)
.
orderBy
(
true
,
true
,
ProdProcessExec:
:
getTaskSeq
)
.
list
();
if
(
newProcessExecs
.
isEmpty
())
{
throw
new
RuntimeException
(
"新订单没有工序: "
+
newOrderId
);
}
log
.
info
(
"加载新订单: OrderId={}, OrderCode={}, 工序数={}"
,
newOrderId
,
newLaunchOrder
.
getOrderCode
(),
newProcessExecs
.
size
());
// 调用ScheduleOperationService的方法将新订单加入排产
// 设备配置将从插入位置的订单复制,不需要单独加载
ScheduleOperationService
scheduleOperation
=
new
ScheduleOperationService
(
materialRequirementService
,
this
);
scheduleOperation
.
InsertOrder
(
chromosome
,
afterOrderId
,
newOrderId
,
newLaunchOrder
,
newProcessExecs
,
globalParam
);
WriteScheduleSummary
(
chromosome
);
_sceneService
.
saveChromosomeToFile
(
chromosome
,
SceneId
);
return
chromosome
;
}
public
Chromosome
MergeOrder
(
String
SceneId
,
String
sourceorderId
,
String
targetorderId
)
{
...
...
@@ -771,7 +1835,6 @@ public class PlanResultService {
param
.
initAdaptiveParams
(
entrys
.
size
());
double
[]
customWeights
=
new
double
[]
{
0.4
,
0.1
,
0.1
,
0.1
,
0.3
};
// 延迟时间权重提升到0.5
//完工时间、总流程时间、总换型时间、机器负载标准差、延迟时间
// scheduler.Init(customWeights,false);
scheduler
.
Init
();
Chromosome
chromosomes
=
scheduler
.
Run
(
param
,
entrys
);
KpiCalculator
kpiCalculator
=
new
KpiCalculator
(
chromosomes
);
...
...
@@ -863,7 +1926,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"
));
}
/**
...
...
@@ -979,8 +2042,8 @@ public class PlanResultService {
FileHelper
.
writeLogFile
(
"初始化排产参数-----------结束-------"
);
return
param
;
}
private
GlobalParam
InitGlobalParam
()
{
private
GlobalParam
InitGlobalParam
()
{
FileHelper
.
writeLogFile
(
"初始化约束-----------开始-------"
);
GlobalParam
globalParam
=
new
GlobalParam
();
...
...
@@ -1035,7 +2098,7 @@ private GlobalParam InitGlobalParam()
}
FileHelper
.
writeLogFile
(
"初始化约束-----------结束-------"
);
return
globalParam
;
}
}
private
List
<
Order
>
InitOrder
(
List
<
ProdLaunchOrder
>
ProdLaunchOrders
)
{
orderSortService
.
initializeFieldExtractors
();
...
...
@@ -1435,13 +2498,19 @@ private GlobalParam InitGlobalParam()
// 找到上一道工序的结束时间
LocalDateTime
lastEntryEndTime
=
getEntryEndTime
(
lastEntry
,
results
,
baseTime
);
Order
fromOrder1
=
orders
!=
null
?
orders
.
stream
().
filter
(
o
->
o
.
getOrderId
()
!=
null
&&
o
.
getOrderId
().
equals
(
lastEntry
.
getOrderId
())).
findFirst
().
orElse
(
null
)
:
null
;
Order
toOrder1
=
orders
!=
null
?
orders
.
stream
().
filter
(
o
->
o
.
getOrderId
()
!=
null
&&
o
.
getOrderId
().
equals
(
currentEntry
.
getOrderId
())).
findFirst
().
orElse
(
null
)
:
null
;
long
fromEquipId1
=
results
.
stream
().
filter
(
r
->
r
.
getOperationId
()
==
lastEntry
.
getId
()).
mapToLong
(
r
->
r
.
getMachineId
()).
findFirst
().
orElse
(-
1L
);
long
toEquipId1
=
results
.
stream
().
filter
(
r
->
r
.
getOperationId
()
==
currentEntry
.
getId
()).
mapToLong
(
r
->
r
.
getMachineId
()).
findFirst
().
orElse
(-
1L
);
Map
<
String
,
Object
>
item
=
new
HashMap
<>();
item
.
put
(
"taskIdFrom"
,
String
.
valueOf
(
lastEntry
.
getOrderId
()));
item
.
put
(
"taskIdTo"
,
String
.
valueOf
(
currentEntry
.
getOrderId
()));
item
.
put
(
"fromId"
,
String
.
valueOf
(
lastEntry
.
getId
()));
item
.
put
(
"fromPlanId"
,
fromOrder1
!=
null
?
String
.
valueOf
(
fromOrder1
.
getId
())
:
""
);
item
.
put
(
"fromEquipId"
,
String
.
valueOf
(
fromEquipId1
));
item
.
put
(
"fromTime"
,
lastEntryEndTime
!=
null
?
lastEntryEndTime
.
toString
()
:
"2025-12-13"
);
item
.
put
(
"toId"
,
String
.
valueOf
(
currentEntry
.
getId
()));
item
.
put
(
"toPlanId"
,
toOrder1
!=
null
?
String
.
valueOf
(
toOrder1
.
getId
())
:
""
);
item
.
put
(
"toEquipId"
,
String
.
valueOf
(
toEquipId1
));
item
.
put
(
"toTime"
,
currentStartTime
!=
null
?
currentStartTime
.
toString
()
:
"2026-12-13"
);
item
.
put
(
"fromIdFrom"
,
String
.
valueOf
(
lastEntry
.
getId
()));
item
.
put
(
"toIdTo"
,
currentEntry
.
getId
());
supplyRelations
.
add
(
item
);
// 递归检查上一个订单的依赖关系
...
...
@@ -1461,15 +2530,21 @@ private GlobalParam InitGlobalParam()
// 找到目标工序的开始时间
LocalDateTime
targetStartTime
=
getEntryStartTime
(
targetEntry
,
results
,
baseTime
);
Order
fromOrder2
=
orders
!=
null
?
orders
.
stream
().
filter
(
o
->
o
.
getOrderId
()
!=
null
&&
o
.
getOrderId
().
equals
(
currentEntry
.
getOrderId
())).
findFirst
().
orElse
(
null
)
:
null
;
Order
toOrder2
=
orders
!=
null
?
orders
.
stream
().
filter
(
o
->
o
.
getOrderId
()
!=
null
&&
o
.
getOrderId
().
equals
(
targetEntry
.
getOrderId
())).
findFirst
().
orElse
(
null
)
:
null
;
long
fromEquipId2
=
results
.
stream
().
filter
(
r
->
r
.
getOperationId
()
==
currentEntry
.
getId
()).
mapToLong
(
r
->
r
.
getMachineId
()).
findFirst
().
orElse
(-
1L
);
long
toEquipId2
=
results
.
stream
().
filter
(
r
->
r
.
getOperationId
()
==
targetEntry
.
getId
()).
mapToLong
(
r
->
r
.
getMachineId
()).
findFirst
().
orElse
(-
1L
);
Map
<
String
,
Object
>
item
=
new
HashMap
<>();
item
.
put
(
"taskIdFrom"
,
String
.
valueOf
(
currentEntry
.
getOrderId
()));
item
.
put
(
"taskIdTo"
,
String
.
valueOf
(
targetEntry
.
getOrderId
()));
item
.
put
(
"fromId"
,
String
.
valueOf
(
currentEntry
.
getId
()));
item
.
put
(
"fromPlanId"
,
fromOrder2
!=
null
?
String
.
valueOf
(
fromOrder2
.
getId
())
:
""
);
item
.
put
(
"fromEquipId"
,
String
.
valueOf
(
fromEquipId2
));
item
.
put
(
"fromTime"
,
currentEndTime
!=
null
?
currentEndTime
.
toString
()
:
"2025-12-13"
);
item
.
put
(
"toId"
,
String
.
valueOf
(
targetEntry
.
getId
()));
item
.
put
(
"toPlanId"
,
toOrder2
!=
null
?
String
.
valueOf
(
toOrder2
.
getId
())
:
""
);
item
.
put
(
"toEquipId"
,
String
.
valueOf
(
toEquipId2
));
item
.
put
(
"toTime"
,
targetStartTime
!=
null
?
targetStartTime
.
toString
()
:
"2026-12-13"
);
item
.
put
(
"fromIdFrom"
,
String
.
valueOf
(
currentEntry
.
getId
()));
item
.
put
(
"toIdTo"
,
targetEntry
.
getId
());
supplyRelations
.
add
(
item
);
checkAndAddTargetRelations
(
entries
,
results
,
baseTime
,
targetEntry
,
supplyRelations
);
// 检查后置工序
checkAndAddTargetRelations
(
entries
,
orders
,
results
,
baseTime
,
targetEntry
,
supplyRelations
);
// 检查后置工序
}
}
}
...
...
@@ -1558,13 +2633,19 @@ private GlobalParam InitGlobalParam()
// 找到上一道工序的结束时间
LocalDateTime
lastEntryEndTime
=
getEntryEndTime
(
lastEntry
,
results
,
baseTime
);
Order
fromOrder3
=
orders
!=
null
?
orders
.
stream
().
filter
(
o
->
o
.
getOrderId
()
!=
null
&&
o
.
getOrderId
().
equals
(
lastEntry
.
getOrderId
())).
findFirst
().
orElse
(
null
)
:
null
;
Order
toOrder3
=
orders
!=
null
?
orders
.
stream
().
filter
(
o
->
o
.
getOrderId
()
!=
null
&&
o
.
getOrderId
().
equals
(
currentEntry
.
getOrderId
())).
findFirst
().
orElse
(
null
)
:
null
;
long
fromEquipId3
=
results
.
stream
().
filter
(
r
->
r
.
getOperationId
()
==
lastEntry
.
getId
()).
mapToLong
(
r
->
r
.
getMachineId
()).
findFirst
().
orElse
(-
1L
);
long
toEquipId3
=
results
.
stream
().
filter
(
r
->
r
.
getOperationId
()
==
currentEntry
.
getId
()).
mapToLong
(
r
->
r
.
getMachineId
()).
findFirst
().
orElse
(-
1L
);
Map
<
String
,
Object
>
item
=
new
HashMap
<>();
item
.
put
(
"taskIdFrom"
,
String
.
valueOf
(
lastEntry
.
getId
()));
item
.
put
(
"taskIdTo"
,
String
.
valueOf
(
currentEntry
.
getId
()));
item
.
put
(
"fromId"
,
String
.
valueOf
(
lastEntry
.
getId
()));
item
.
put
(
"fromPlanId"
,
fromOrder3
!=
null
?
String
.
valueOf
(
fromOrder3
.
getId
())
:
""
);
item
.
put
(
"fromEquipId"
,
String
.
valueOf
(
fromEquipId3
));
item
.
put
(
"fromTime"
,
lastEntryEndTime
!=
null
?
lastEntryEndTime
.
toString
()
:
"2025-12-13"
);
item
.
put
(
"toId"
,
String
.
valueOf
(
currentEntry
.
getId
()));
item
.
put
(
"toPlanId"
,
toOrder3
!=
null
?
String
.
valueOf
(
toOrder3
.
getId
())
:
""
);
item
.
put
(
"toEquipId"
,
String
.
valueOf
(
toEquipId3
));
item
.
put
(
"toTime"
,
currentStartTime
!=
null
?
currentStartTime
.
toString
()
:
"2026-12-13"
);
item
.
put
(
"fromIdFrom"
,
String
.
valueOf
(
lastEntry
.
getId
()));
item
.
put
(
"toIdTo"
,
currentEntry
.
getId
());
supplyRelations
.
add
(
item
);
// 递归调用,处理上一个订单的最后一道工序的依赖关系
...
...
@@ -1584,7 +2665,7 @@ private GlobalParam InitGlobalParam()
* @param currentEntry 当前工序
* @param supplyRelations 供给关系列表
*/
private
void
checkAndAddTargetRelations
(
List
<
Entry
>
entries
,
List
<
GAScheduleResult
>
results
,
LocalDateTime
baseTime
,
Entry
currentEntry
,
List
<
Object
>
supplyRelations
)
{
private
void
checkAndAddTargetRelations
(
List
<
Entry
>
entries
,
List
<
Order
>
orders
,
List
<
GAScheduleResult
>
results
,
LocalDateTime
baseTime
,
Entry
currentEntry
,
List
<
Object
>
supplyRelations
)
{
if
(
currentEntry
.
getTargetFinishedOperationId
()
!=
null
&&
!
currentEntry
.
getTargetFinishedOperationId
().
isEmpty
())
{
for
(
Integer
targetId
:
currentEntry
.
getTargetFinishedOperationId
())
{
Entry
targetEntry
=
entries
.
stream
().
filter
(
e
->
e
.
getId
()
==
targetId
).
findFirst
().
orElse
(
null
);
...
...
@@ -1593,16 +2674,21 @@ private GlobalParam InitGlobalParam()
LocalDateTime
currentEndTime
=
getEntryEndTime
(
currentEntry
,
results
,
baseTime
);
// 找到目标工序的开始时间
LocalDateTime
targetStartTime
=
getEntryStartTime
(
targetEntry
,
results
,
baseTime
);
Order
fromOrder
=
orders
!=
null
?
orders
.
stream
().
filter
(
o
->
o
.
getOrderId
()
!=
null
&&
o
.
getOrderId
().
equals
(
currentEntry
.
getOrderId
())).
findFirst
().
orElse
(
null
)
:
null
;
Order
toOrder
=
orders
!=
null
?
orders
.
stream
().
filter
(
o
->
o
.
getOrderId
()
!=
null
&&
o
.
getOrderId
().
equals
(
targetEntry
.
getOrderId
())).
findFirst
().
orElse
(
null
)
:
null
;
long
fromEquipId4
=
results
.
stream
().
filter
(
r
->
r
.
getOperationId
()
==
currentEntry
.
getId
()).
mapToLong
(
r
->
r
.
getMachineId
()).
findFirst
().
orElse
(-
1L
);
long
toEquipId4
=
results
.
stream
().
filter
(
r
->
r
.
getOperationId
()
==
targetEntry
.
getId
()).
mapToLong
(
r
->
r
.
getMachineId
()).
findFirst
().
orElse
(-
1L
);
Map
<
String
,
Object
>
item
=
new
HashMap
<>();
item
.
put
(
"taskIdFrom"
,
String
.
valueOf
(
currentEntry
.
getId
()));
item
.
put
(
"taskIdTo"
,
String
.
valueOf
(
targetEntry
.
getId
()));
item
.
put
(
"fromId"
,
String
.
valueOf
(
currentEntry
.
getId
()));
item
.
put
(
"fromPlanId"
,
fromOrder
!=
null
?
String
.
valueOf
(
fromOrder
.
getId
())
:
""
);
item
.
put
(
"fromEquipId"
,
String
.
valueOf
(
fromEquipId4
));
item
.
put
(
"fromTime"
,
currentEndTime
!=
null
?
currentEndTime
.
toString
()
:
"2025-12-13"
);
item
.
put
(
"toId"
,
String
.
valueOf
(
targetEntry
.
getId
()));
item
.
put
(
"toPlanId"
,
toOrder
!=
null
?
String
.
valueOf
(
toOrder
.
getId
())
:
""
);
item
.
put
(
"toEquipId"
,
String
.
valueOf
(
toEquipId4
));
item
.
put
(
"toTime"
,
targetStartTime
!=
null
?
targetStartTime
.
toString
()
:
"2026-12-13"
);
item
.
put
(
"fromIdFrom"
,
String
.
valueOf
(
currentEntry
.
getId
()));
item
.
put
(
"toIdTo"
,
targetEntry
.
getId
());
supplyRelations
.
add
(
item
);
checkAndAddTargetRelations
(
entries
,
results
,
baseTime
,
targetEntry
,
supplyRelations
);
// 递归调用
checkAndAddTargetRelations
(
entries
,
orders
,
results
,
baseTime
,
targetEntry
,
supplyRelations
);
// 递归调用
}
}
}
...
...
@@ -1909,13 +2995,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
()
...
...
@@ -1947,10 +3033,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
)
{
...
...
@@ -1969,11 +3067,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
);
...
...
@@ -2004,8 +3097,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
())
{
...
...
@@ -2039,11 +3133,11 @@ private GlobalParam InitGlobalParam()
.
max
()
.
orElse
(
0
);
productGanttVO
.
setStartDate
(
scheduleChromosome
.
getBaseTime
().
plus
Minute
s
(
minStartTime
));
productGanttVO
.
setEndDate
(
scheduleChromosome
.
getBaseTime
().
plus
Minute
s
(
maxEndTime
));
productGanttVO
.
setStartDate
(
scheduleChromosome
.
getBaseTime
().
plus
Second
s
(
minStartTime
));
productGanttVO
.
setEndDate
(
scheduleChromosome
.
getBaseTime
().
plus
Second
s
(
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()));
...
...
@@ -2053,7 +3147,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
());
...
...
@@ -2145,9 +3239,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
());
...
...
@@ -2351,6 +3482,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
());
...
...
@@ -2362,6 +3499,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
()))
{
...
...
@@ -2389,9 +3527,8 @@ private GlobalParam InitGlobalParam()
// 正常班次直接添加
result
.
add
(
shift
);
}
}
}
machine
.
setShifts
(
result
);
}
...
...
src/test/java/com/aps/demo/PlanResultServiceTest.java
View file @
25c58c5b
...
...
@@ -39,8 +39,8 @@ public class PlanResultServiceTest {
// TestSortService sortService=new TestSortService();
// sortService.test1();
// nsgaiiUtils.Test();
//
planResultService.execute2("0428340BB4F540938F1FB5599F03E8A4");//2000
planResultService
.
execute2
(
"C8B533BD8944405B9A2F8823C575C204"
);
//500
planResultService
.
execute2
(
"0428340BB4F540938F1FB5599F03E8A4"
);
//2000
//
planResultService.execute2("C8B533BD8944405B9A2F8823C575C204");//500
// planResultService.execute2("EFDD34E4B5BC434BAEAE6A84DFCD4E7B");//20
// planResultService.execute2("00E0C5D3E4AD4F36B56C39395906618D");
...
...
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