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
ee581dc1
Commit
ee581dc1
authored
Nov 26, 2025
by
Tong Li
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
遗传算法
parent
4d69e6bd
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
2412 additions
and
1829078 deletions
+2412
-1829078
pom.xml
pom.xml
+1
-0
schedule_log.txt
schedule_log.txt
+1055
-1829018
ResourceGanttController.java
...ava/com/aps/controller/gantt/ResourceGanttController.java
+11
-0
Chromosome.java
src/main/java/com/aps/entity/Algorithm/Chromosome.java
+28
-2
GAScheduleResult.java
src/main/java/com/aps/entity/Algorithm/GAScheduleResult.java
+6
-1
OpMachine.java
src/main/java/com/aps/entity/Algorithm/OpMachine.java
+29
-0
Pair.java
src/main/java/com/aps/entity/Algorithm/Pair.java
+23
-0
ScheduleParams.java
src/main/java/com/aps/entity/Algorithm/ScheduleParams.java
+3
-5
MachineOption.java
src/main/java/com/aps/entity/basic/MachineOption.java
+1
-1
Order.java
src/main/java/com/aps/entity/basic/Order.java
+2
-0
FitnessCalculator.java
...ain/java/com/aps/service/Algorithm/FitnessCalculator.java
+31
-0
GeneticAlgorithm.java
...main/java/com/aps/service/Algorithm/GeneticAlgorithm.java
+149
-2
GeneticDecoder.java
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
+376
-0
GeneticOperations.java
...ain/java/com/aps/service/Algorithm/GeneticOperations.java
+243
-0
Initialization.java
src/main/java/com/aps/service/Algorithm/Initialization.java
+32
-21
MachineCalculator.java
...ain/java/com/aps/service/Algorithm/MachineCalculator.java
+301
-0
PlanResultService.java
src/main/java/com/aps/service/plan/PlanResultService.java
+107
-16
application.yml
src/main/resources/application.yml
+12
-12
machines.json
src/main/resources/machines.json
+2
-0
No files found.
pom.xml
View file @
ee581dc1
...
...
@@ -91,6 +91,7 @@
<artifactId>
spring-boot-starter-test
</artifactId>
<scope>
test
</scope>
</dependency>
</dependencies>
<build>
...
...
schedule_log.txt
View file @
ee581dc1
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/main/java/com/aps/controller/gantt/ResourceGanttController.java
View file @
ee581dc1
package
com
.
aps
.
controller
.
gantt
;
import
com.aps.entity.Algorithm.Chromosome
;
import
com.aps.entity.basic.ScheduleChromosome
;
import
com.aps.entity.Gantt.ProductGanttVO
;
import
com.aps.entity.Gantt.ResourceGanttVO
;
...
...
@@ -102,6 +103,16 @@ public class ResourceGanttController {
.
map
(
ScheduleChromosome:
:
getSceneId
)
.
collect
(
Collectors
.
toList
());
}
@GetMapping
(
"/getScene"
)
@Operation
(
summary
=
"获取所有场景ID"
,
description
=
"获取所有场景ID"
)
public
List
<
Chromosome
>
getScene
()
{
// 调用 PlanResultService 获取 ScheduleChromosome 列表
List
<
Chromosome
>
scheduleChromosomes
=
planResultService
.
execute1
();
// 提取所有场景ID
return
scheduleChromosomes
;
}
/**
* 将 ScheduleChromosome 转换为 ResourceGanttVO 列表
...
...
src/main/java/com/aps/entity/Algorithm/Chromosome.java
View file @
ee581dc1
package
com
.
aps
.
entity
.
Algorithm
;
import
com.aps.entity.Algorithm.ScheduleResult
;
import
com.aps.entity.basic.Machine
;
import
lombok.Data
;
import
java.util.List
;
import
java.util.UUID
;
import
java.util.stream.Collectors
;
/**
* 作者:佟礼
...
...
@@ -12,16 +13,41 @@ import java.util.List;
*/
@Data
public
class
Chromosome
{
private
String
ID
=
UUID
.
randomUUID
().
toString
();
/// <summary>
/// 机器选择部分(可选机器集中的顺序号)
/// </summary>
private
List
<
Integer
>
MachineSelection
;
/// <summary>
/// 工序排序部分(工件/订单ID)
/// </summary>
private
String
MachineStr
;
public
String
getMachineStr
()
{
return
MachineSelection
.
stream
()
.
map
(
String:
:
valueOf
)
// 将每个 Integer 转换为 String
.
collect
(
Collectors
.
joining
(
","
));
};
/// <summary>
/// 工序排序部分(工件/订单ID)
/// </summary>
private
List
<
Integer
>
OperationSequencing
;
/// <summary>
/// 工序排序部分(工件/订单ID)
/// </summary>
private
String
OperationStr
;
public
String
getOperationStr
()
{
return
OperationSequencing
.
stream
()
.
map
(
String:
:
valueOf
)
// 将每个 Integer 转换为 String
.
collect
(
Collectors
.
joining
(
"|"
));
};
/// <summary>
/// 适应度值
/// </summary>
...
...
@@ -35,7 +61,7 @@ public class Chromosome {
/// <summary>
/// 解码后的调度结果
/// </summary>
private
List
<
ScheduleResult
>
Result
;
private
List
<
GA
ScheduleResult
>
Result
;
/// <summary>
/// 最早完工时间
...
...
src/main/java/com/aps/entity/Algorithm/ScheduleResult.java
→
src/main/java/com/aps/entity/Algorithm/
GA
ScheduleResult.java
View file @
ee581dc1
...
...
@@ -9,7 +9,7 @@ import java.util.List;
* 时间:2025-11-21
*/
@Data
public
class
ScheduleResult
{
public
class
GA
ScheduleResult
{
private
int
GroupId
;
private
int
ProductId
;
private
int
OperationId
;
...
...
@@ -21,4 +21,9 @@ public class ScheduleResult {
private
int
OneTime
;
// 单件工时
private
int
ProcessingTime
;
// 绝对处理时间(分钟)
private
int
ChangeoverTime
;
public
int
getFlowTime
()
{
return
EndTime
-
StartTime
;
};
}
src/main/java/com/aps/entity/Algorithm/OpMachine.java
0 → 100644
View file @
ee581dc1
package
com
.
aps
.
entity
.
Algorithm
;
import
lombok.Data
;
/**
* 作者:佟礼
* 时间:2025-11-25
*/
@Data
public
class
OpMachine
{
/**
* 所属组ID
*/
private
int
GroupId
;
/**
* 订单内工序顺序号
*/
private
int
Sequence
;
/**
* 设备ID
*/
private
int
machineId
;
/**
* 单件工时
*/
private
int
processingTime
;
// 加工时间
}
src/main/java/com/aps/entity/Algorithm/Pair.java
0 → 100644
View file @
ee581dc1
package
com
.
aps
.
entity
.
Algorithm
;
/**
* 作者:佟礼
* 时间:2025-11-24
*/
public
class
Pair
<
A
,
B
>
{
private
final
A
first
;
private
final
B
second
;
public
Pair
(
A
first
,
B
second
)
{
this
.
first
=
first
;
this
.
second
=
second
;
}
public
A
getFirst
()
{
return
first
;
}
public
B
getSecond
()
{
return
second
;
}
}
src/main/java/com/aps/entity/Algorithm/ScheduleParams.java
View file @
ee581dc1
...
...
@@ -3,6 +3,7 @@ package com.aps.entity.Algorithm;
import
com.aps.entity.basic.Entry
;
import
lombok.Data
;
import
java.time.LocalDateTime
;
import
java.util.Date
;
/**
...
...
@@ -11,12 +12,9 @@ import java.util.Date;
*/
@Data
public
class
ScheduleParams
{
private
Date
BaseTime
=
new
Date
();
// 当前基准时间
private
LocalDateTime
BaseTime
;
// 当前基准时间
/// <summary>
/// 设备总数
/// </summary>
private
int
MachineCount
;
// 设备总数
/// <summary>
/// 交叉概率
...
...
src/main/java/com/aps/entity/basic/MachineOption.java
View file @
ee581dc1
...
...
@@ -8,7 +8,7 @@ import lombok.Data;
@Data
public
class
MachineOption
{
private
int
machineId
;
private
int
processingTime
;
// 加工时间
private
int
processingTime
;
// 加工时间
(秒)
private
int
setupTime
;
// 换型时间(如果与前一个产品不同)
private
int
teardownTime
;
// 收尾时间(后处理时间)
private
int
contantTime
;
// 常数时间
...
...
src/main/java/com/aps/entity/basic/Order.java
View file @
ee581dc1
...
...
@@ -13,6 +13,8 @@ public class Order {
private
int
id
;
private
int
productId
;
private
int
quantity
=
100
;
// 100个
private
int
sYQuantity
;
private
OffsetDateTime
dueDate
;
private
LocalDateTime
orderCompletion
;
private
double
tardiness
;
...
...
src/main/java/com/aps/service/Algorithm/FitnessCalculator.java
0 → 100644
View file @
ee581dc1
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.entity.Algorithm.Chromosome
;
/**
* 作者:佟礼
* 时间:2025-11-24
*/
public
class
FitnessCalculator
{
/**
* 多目标适应度计算(加权求和)
*/
public
double
calculateFitness
(
Chromosome
chromosome
)
{
// 权重可根据实际需求调整
double
w1
=
0.3
;
// 最早完工时间(越小越好,归一化后取反)
double
w2
=
0.2
;
// 总流程时间(越小越好)
double
w3
=
0.15
;
// 总换型时间(越小越好)
double
w4
=
0.2
;
// 机器负载均衡(标准差越小越好)
double
w5
=
0.15
;
// 交付期延迟(越小越好)
// 归一化(假设最大可能值,实际应根据问题规模调整)
double
normMakespan
=
1
/
(
1
+(
double
)
chromosome
.
getMakespan
());
double
normFlowTime
=
1
/
(
1
+
(
double
)
chromosome
.
getTotalFlowTime
()
);
double
normChangeover
=
1
/
(
1
+
(
double
)
chromosome
.
getTotalChangeoverTime
());
double
normLoadStd
=
chromosome
.
getMachineLoadStd
();
double
normDelay
=
1
/
(
1
+
(
double
)
chromosome
.
getDelayTime
()
);
// 适应度值(越大越好)
return
w1
*
normMakespan
+
w2
*
normFlowTime
+
w3
*
normChangeover
+
w4
*
normLoadStd
+
w5
*
normDelay
;
}
}
src/main/java/com/aps/service/Algorithm/GeneticAlgorithm.java
View file @
ee581dc1
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.common.util.DeepCopyUtil
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.Chromosome
;
import
com.aps.entity.Algorithm.GlobalOperationInfo
;
import
com.aps.entity.Algorithm.Pair
;
import
com.aps.entity.Algorithm.ScheduleParams
;
import
com.aps.entity.basic.Entry
;
import
com.aps.entity.basic.Machine
;
import
com.aps.entity.basic.Material
;
import
com.aps.entity.basic.Order
;
import
com.aps.service.plan.MachineSchedulerService
;
import
java.util.*
;
import
java.util.stream.Collectors
;
/**
* 作者:佟礼
* 时间:2025-11-21
*/
public
class
GeneticAlgorithm
{
public
void
Run
()
{
System
.
out
.
println
(
""
);
private
final
Random
rnd
=
new
Random
();
private
final
List
<
Machine
>
machines
;
private
final
MachineSchedulerService
machineScheduler
;
private
final
List
<
Order
>
orders
;
private
final
List
<
Material
>
materials
;
public
GeneticAlgorithm
(
List
<
Machine
>
machines
,
List
<
Order
>
orders
,
List
<
Material
>
materials
,
MachineSchedulerService
machineScheduler
)
{
this
.
machines
=
machines
;
this
.
orders
=
orders
;
this
.
materials
=
materials
;
this
.
machineScheduler
=
machineScheduler
;
}
public
List
<
Chromosome
>
Run
(
ScheduleParams
param
,
List
<
Entry
>
allOperations
)
{
System
.
out
.
println
(
"开始"
);
Initialization
initialization
=
new
Initialization
(
allOperations
);
GeneticOperations
geneticOps
=
new
GeneticOperations
(
allOperations
);
// 预生成全局工序列表(所有初始化方法共享同一顺序)
List
<
GlobalOperationInfo
>
globalOpList
=
initialization
.
generateGlobalOpList
();
// 步骤1:初始化种群
List
<
Chromosome
>
population
=
initialization
.
generateInitialPopulation
(
param
,
globalOpList
);
Chromosomedecode
(
param
,
allOperations
,
globalOpList
,
population
);
int
ordercount
=
globalOpList
.
stream
()
.
mapToInt
(
GlobalOperationInfo:
:
getGroupId
)
.
max
()
.
orElse
(
0
);
Chromosome
best
=
new
Chromosome
();
double
bestFitness
=
0
;
int
Iteration
=
0
;
// 步骤2:迭代进化
for
(
int
iter
=
0
;
iter
<
param
.
getMaxIterations
();
iter
++)
{
// 解码并计算适应度
// 检查终止条件(此处简化为迭代次数)
if
(
iter
==
param
.
getMaxIterations
()
-
1
)
{
break
;
}
// 选择操作
List
<
Chromosome
>
selected
=
geneticOps
.
tournamentSelection
(
population
);
// 交叉操作
List
<
Chromosome
>
nextPopulation
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
selected
.
size
();
i
+=
2
)
{
if
(
i
+
1
>=
selected
.
size
())
{
nextPopulation
.
add
(
selected
.
get
(
i
));
break
;
}
Chromosome
parent1
=
selected
.
get
(
i
);
Chromosome
parent2
=
selected
.
get
(
i
+
1
);
if
(
rnd
.
nextDouble
()
<
param
.
getCrossoverProb
())
{
// 假设PoxCrossover返回包含两个子染色体的数组
Pair
<
Chromosome
,
Chromosome
>
children
=
geneticOps
.
poxCrossover
(
parent1
,
parent2
,
ordercount
);
nextPopulation
.
add
(
children
.
getFirst
());
nextPopulation
.
add
(
children
.
getSecond
());
}
else
{
nextPopulation
.
add
(
parent1
);
nextPopulation
.
add
(
parent2
);
}
}
// 变异操作
for
(
Chromosome
chromosome
:
nextPopulation
)
{
if
(
rnd
.
nextDouble
()
<
param
.
getMutationProb
())
{
geneticOps
.
mutate
(
chromosome
,
globalOpList
);
}
}
// 精英保留
List
<
Chromosome
>
population1
=
population
.
stream
()
.
sorted
((
c1
,
c2
)
->
Double
.
compare
(
c2
.
getFitness
(),
c1
.
getFitness
()))
.
collect
(
Collectors
.
toList
());
// 降序排序
List
<
Chromosome
>
elites
=
population1
.
subList
(
0
,
param
.
getElitismCount
());
List
<
Chromosome
>
newPopulation
=
new
ArrayList
<>();
newPopulation
.
addAll
(
elites
);
newPopulation
.
addAll
(
nextPopulation
);
// 更新种群
population
=
newPopulation
.
stream
()
.
limit
(
param
.
getPopulationSize
()
)
.
collect
(
Collectors
.
toList
());
Chromosomedecode
(
param
,
allOperations
,
globalOpList
,
population
);
best
=
population
.
stream
()
.
max
(
Comparator
.
comparingDouble
(
Chromosome:
:
getFitness
))
.
orElse
(
null
);
if
(
bestFitness
<
best
.
getFitness
())
{
bestFitness
=
best
.
getFitness
();
}
else
{
Iteration
++;
}
if
(
Iteration
>
20
)
{
break
;
}
}
// 步骤3:返回最优解
return
population
.
stream
()
.
sorted
((
c1
,
c2
)
->
Double
.
compare
(
c2
.
getFitness
(),
c1
.
getFitness
()))
.
limit
(
10
)
.
collect
(
Collectors
.
toList
());
}
private
void
Chromosomedecode
(
ScheduleParams
param
,
List
<
Entry
>
allOperations
,
List
<
GlobalOperationInfo
>
globalOpList
,
List
<
Chromosome
>
population
)
{
GeneticDecoder
decoder
=
new
GeneticDecoder
(
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
);
FitnessCalculator
fitnessCalc
=
new
FitnessCalculator
();
population
.
parallelStream
().
forEach
(
chromosome
->
{
chromosome
.
setResult
(
new
ArrayList
<>());
// 假设Machine类有拷贝方法,或使用MapStruct等工具进行映射
chromosome
.
setMachines
(
ProductionDeepCopyUtil
.
deepCopyList
(
machines
));
// 简单拷贝,实际可能需要深拷贝
decoder
.
decodeChromosomeWithCache
(
chromosome
,
globalOpList
,
allOperations
);
chromosome
.
setFitness
(
fitnessCalc
.
calculateFitness
(
chromosome
));
});
}
}
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
0 → 100644
View file @
ee581dc1
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.entity.basic.*
;
import
com.aps.service.plan.MachineSchedulerService
;
import
java.time.LocalDateTime
;
import
java.time.temporal.ChronoUnit
;
import
java.util.*
;
import
java.util.stream.Collectors
;
import
java.util.concurrent.locks.ReentrantLock
;
/**
* 作者:佟礼
* 时间:2025-11-24
*/
public
class
GeneticDecoder
{
private
final
Map
<
String
,
Chromosome
>
decodingCache
=
new
HashMap
<>();
// 缓存大小限制
private
static
final
int
MAX_CACHE_SIZE
=
1000
;
// 线程安全锁:避免多线程下缓存操作冲突(可选,若单线程可移除)
private
final
ReentrantLock
cacheLock
=
new
ReentrantLock
();
private
LocalDateTime
baseTime
;
private
final
List
<
Machine
>
machines
;
private
final
MachineSchedulerService
machineScheduler
;
private
final
List
<
Order
>
orders
;
private
int
orderMaxID
;
private
final
List
<
Material
>
materials
;
public
GeneticDecoder
(
LocalDateTime
baseTime
,
List
<
Machine
>
machines
,
List
<
Order
>
orders
,
List
<
Material
>
materials
,
MachineSchedulerService
machineScheduler
)
{
this
.
baseTime
=
baseTime
;
this
.
machines
=
machines
;
this
.
orders
=
orders
;
this
.
orders
.
forEach
(
t
->
t
.
setSYQuantity
(
t
.
getQuantity
()));
this
.
materials
=
materials
;
this
.
machineScheduler
=
machineScheduler
;
this
.
orderMaxID
=
orders
.
stream
().
mapToInt
(
Order:
:
getId
).
max
().
orElse
(
0
);
}
public
void
decodeChromosomeWithCache
(
Chromosome
chromosome
,
List
<
GlobalOperationInfo
>
globalOpList
,
List
<
Entry
>
allOperations
)
{
// 1. 创建缓存键
String
cacheKey
=
createCacheKey
(
chromosome
);
// 2. 尝试从缓存获取(加锁保证线程安全)
cacheLock
.
lock
();
try
{
if
(
decodingCache
.
containsKey
(
cacheKey
))
{
// 缓存命中:复用缓存结果
Chromosome
cachedResult
=
decodingCache
.
get
(
cacheKey
);
// 赋值给染色体
String
ID
=
chromosome
.
getID
();
chromosome
=
ProductionDeepCopyUtil
.
deepCopy
(
cachedResult
);
chromosome
.
setID
(
ID
);
return
;
}
}
finally
{
cacheLock
.
unlock
();
// 确保锁释放
}
// 3. 缓存未命中:执行解码逻辑
decode
(
chromosome
,
globalOpList
,
allOperations
);
// 4. 将解码结果存入缓存(加锁保证线程安全)
cacheLock
.
lock
();
try
{
// 存储缓存:封装为 CacheValue 对象
decodingCache
.
put
(
cacheKey
,
chromosome
);
// 5. 限制缓存大小(超过 1000 移除最早插入的键)
if
(
decodingCache
.
size
()
>
MAX_CACHE_SIZE
)
{
Iterator
<
String
>
keyIterator
=
decodingCache
.
keySet
().
iterator
();
if
(
keyIterator
.
hasNext
())
{
keyIterator
.
next
();
// 获取首个键
keyIterator
.
remove
();
// 移除首个键(对应 C# _decodingCache.Keys.First())
}
}
}
finally
{
cacheLock
.
unlock
();
}
}
/**
* 染色体解码为调度方案
*/
public
void
decode
(
Chromosome
chromosome
,
List
<
GlobalOperationInfo
>
globalOpList
,
List
<
Entry
>
allOperations
)
{
Map
<
Integer
,
GlobalOperationInfo
>
globalOpMap
=
globalOpList
.
stream
()
.
collect
(
Collectors
.
toMap
(
GlobalOperationInfo:
:
getGlobalOpId
,
g
->
g
));
// 验证:MachineSelection长度必须与全局工序数一致
if
(
chromosome
.
getMachineSelection
().
size
()
!=
globalOpList
.
size
())
{
throw
new
IllegalArgumentException
(
String
.
format
(
"MachineSelection长度(%d)与全局工序数(%d)不匹配!"
,
chromosome
.
getMachineSelection
().
size
(),
globalOpList
.
size
()));
}
// 步骤1:生成“工序→机器/加工时间”映射
List
<
OpMachine
>
opMachineMap
=
new
ArrayList
<>();
for
(
GlobalOperationInfo
globalOp
:
globalOpList
)
{
int
globalOpId
=
globalOp
.
getGlobalOpId
();
Entry
op
=
globalOp
.
getOp
();
int
groupId
=
globalOp
.
getGroupId
();
int
sequence
=
globalOp
.
getSequence
();
// 从MachineSelection中获取当前工序的机器选择顺序号
int
machineSeq
=
chromosome
.
getMachineSelection
().
get
(
globalOpId
);
List
<
MachineOption
>
optionalMachines
=
op
.
getMachineOptions
();
// 验证:机器顺序号必须在可选范围内
if
(
machineSeq
<
1
||
machineSeq
>
optionalMachines
.
size
())
{
throw
new
IllegalStateException
(
String
.
format
(
"全局工序%d(订单%d工序%d)的机器顺序号%d超出范围(1-%d)"
,
globalOpId
,
groupId
,
sequence
,
machineSeq
,
optionalMachines
.
size
()));
}
// 获取选择的设备ID和加工时间
MachineOption
selectedMachine
=
optionalMachines
.
get
(
machineSeq
-
1
);
OpMachine
opMachine
=
new
OpMachine
();
opMachine
.
setGroupId
(
groupId
);
opMachine
.
setSequence
(
sequence
);
opMachine
.
setMachineId
(
selectedMachine
.
getMachineId
());
opMachine
.
setProcessingTime
(
selectedMachine
.
getProcessingTime
());
opMachineMap
.
add
(
opMachine
);
}
// 步骤2:按OperationSequencing顺序调度工序
Map
<
Integer
,
Integer
>
orderProcessCounter
=
allOperations
.
stream
()
.
collect
(
Collectors
.
groupingBy
(
Entry:
:
getGroupId
,
Collectors
.
collectingAndThen
(
Collectors
.
counting
(),
Long:
:
intValue
)))
.
entrySet
().
stream
()
.
collect
(
Collectors
.
toMap
(
Map
.
Entry
::
getKey
,
e
->
0
));
Map
<
Integer
,
Integer
>
orderLastEndTime
=
allOperations
.
stream
()
.
collect
(
Collectors
.
groupingBy
(
Entry:
:
getGroupId
))
.
keySet
().
stream
()
.
collect
(
Collectors
.
toMap
(
k
->
k
,
k
->
0
));
Map
<
Integer
,
String
>
machineState
=
chromosome
.
getMachines
().
stream
()
.
collect
(
Collectors
.
toMap
(
Machine:
:
getId
,
m
->
""
));
List
<
Entry
>
allScheduledOps
=
new
ArrayList
<>();
for
(
int
groupId
:
chromosome
.
getOperationSequencing
())
{
int
scheduledCount
=
orderProcessCounter
.
get
(
groupId
);
List
<
Entry
>
orderOps
=
allOperations
.
stream
()
.
filter
(
t
->
t
.
getGroupId
()
==
groupId
)
.
collect
(
Collectors
.
toList
());
if
(
scheduledCount
>=
orderOps
.
size
())
{
throw
new
IllegalStateException
(
String
.
format
(
"订单%d的工序已全部调度(共%d道),无需重复处理!"
,
groupId
,
orderOps
.
size
()));
}
Entry
currentOp
=
orderOps
.
get
(
scheduledCount
);
int
opSequence
=
currentOp
.
getSequence
();
// 从映射表中获取机器和加工时间
OpMachine
machineInfo
=
opMachineMap
.
stream
()
.
filter
(
m
->
m
.
getGroupId
()
==
groupId
&&
m
.
getSequence
()==
opSequence
)
.
findFirst
()
.
orElse
(
null
);
int
machineId
=
machineInfo
.
getMachineId
();
int
processTime
=
machineInfo
.
getProcessingTime
();
Machine
targetMachine
=
chromosome
.
getMachines
().
stream
()
.
filter
(
m
->
m
.
getId
()
==
machineId
)
.
findFirst
()
.
orElse
(
null
);
int
prevtime
=
0
;
if
(!
currentOp
.
getPrevEntryIds
().
isEmpty
())
{
// 处理多个前工序
for
(
int
opid
:
currentOp
.
getPrevEntryIds
())
{
List
<
GAScheduleResult
>
prevOperations
=
chromosome
.
getResult
().
stream
()
.
filter
(
t
->
t
.
getGroupId
()
==
groupId
&&
t
.
getOperationId
()
==
opid
)
.
collect
(
Collectors
.
toList
());
for
(
GAScheduleResult
prevOp
:
prevOperations
)
{
prevtime
=
Math
.
max
(
prevtime
,
prevOp
.
getEndTime
());
}
}
}
// 上个离散参数
String
lastDiscreteParameter
=
machineState
.
get
(
machineId
);
int
bomtime
=
0
;
prevtime
=
Math
.
max
(
prevtime
,
bomtime
);
Machine
machine
=
chromosome
.
getMachines
().
stream
()
.
filter
(
m
->
m
.
getId
()
==
machineId
)
.
findFirst
()
.
orElse
(
null
);
int
changeoverTime
=
0
;
//(lastDiscreteParameter.isEmpty() ||
// lastDiscreteParameter.equals(currentOp.getDiscreteParameter())) ? 0 : 0;
int
actualEndTime
=
processWithSingleMachine
(
currentOp
,
machine
,
processTime
,
prevtime
,
chromosome
);
orderProcessCounter
.
put
(
groupId
,
orderProcessCounter
.
get
(
groupId
)
+
1
);
orderLastEndTime
.
put
(
groupId
,
actualEndTime
);
machineState
.
put
(
machineId
,
currentOp
.
getDiscreteParameter
());
}
// 步骤4:计算调度指标
calculateScheduleResult
(
chromosome
);
}
private
int
processWithSingleMachine
(
Entry
operation
,
Machine
machine
,
int
processingTime
,
int
prevtime
,
Chromosome
chromosome
)
{
int
processingTimeTotal
=
processingTime
*
operation
.
getQuantity
();
MachineCalculator
machineCalculator
=
new
MachineCalculator
(
baseTime
,
machines
,
machineScheduler
);
List
<
ScheduleResultDetail
>
geneDetails
=
machineCalculator
.
getNextAvailableTime
(
machine
,
prevtime
,
-
1
,
processingTimeTotal
,
chromosome
.
getResult
(),
false
,
true
,
true
);
int
startTime
=
geneDetails
.
stream
()
.
mapToInt
(
ScheduleResultDetail:
:
getStartTime
)
.
min
()
.
orElse
(
0
);
int
endTime
=
geneDetails
.
stream
()
.
mapToInt
(
ScheduleResultDetail:
:
getEndTime
)
.
max
()
.
orElse
(
0
);
GAScheduleResult
result
=
new
GAScheduleResult
();
result
.
setGroupId
(
operation
.
getGroupId
());
result
.
setOperationId
(
operation
.
getId
());
result
.
setMachineId
(
machine
.
getId
());
result
.
setQuantity
(
operation
.
getQuantity
());
result
.
setStartTime
(
startTime
);
result
.
setEndTime
(
endTime
);
result
.
setOneTime
(
processingTime
);
result
.
setProcessingTime
(
processingTimeTotal
);
result
.
setGeneDetails
(
geneDetails
);
chromosome
.
getResult
().
add
(
result
);
return
endTime
;
}
private
void
calculateScheduleResult
(
Chromosome
chromosome
)
{
// 1. 最早完工时间(最小化)
double
makespan
=
chromosome
.
getResult
().
stream
()
.
mapToInt
(
GAScheduleResult:
:
getEndTime
)
.
max
()
.
orElse
(
0
);
// 2. 交付期满足情况(最小化延迟)
double
tardiness
=
0
;
Map
<
Integer
,
List
<
GAScheduleResult
>>
orderGroups
=
chromosome
.
getResult
().
stream
()
.
collect
(
Collectors
.
groupingBy
(
GAScheduleResult:
:
getGroupId
));
for
(
Map
.
Entry
<
Integer
,
List
<
GAScheduleResult
>>
group
:
orderGroups
.
entrySet
())
{
int
groupId
=
group
.
getKey
();
int
orderCompletion
=
group
.
getValue
().
stream
()
.
mapToInt
(
GAScheduleResult:
:
getEndTime
)
.
max
()
.
orElse
(
0
);
Order
order
=
orders
.
stream
()
.
filter
(
t
->
t
.
getId
()
==
groupId
)
.
findFirst
()
.
orElse
(
null
);
LocalDateTime
completionTime
=
baseTime
.
plusMinutes
(
orderCompletion
);
// 修复:正确处理OffsetDateTime到LocalDateTime的转换
LocalDateTime
dueDateTime
=
order
.
getDueDate
().
toLocalDateTime
();
if
(
completionTime
.
isAfter
(
dueDateTime
))
{
// 计算延迟小时数(修复时间计算)
long
hours
=
ChronoUnit
.
HOURS
.
between
(
dueDateTime
,
completionTime
);
long
minutes
=
ChronoUnit
.
MINUTES
.
between
(
dueDateTime
,
completionTime
)
%
60
;
tardiness
+=
hours
*
60
+
(
double
)
minutes
;
}
}
// 3. 最小总换型时间
double
totalSetupTime
=
calculateTotalSetupTime
(
chromosome
);
// 4. 最小化总流程时间
double
totalFlowTime
=
calculateTotalFlowTime
(
chromosome
);
// 5. 机器负载均衡
double
machineLoadBalance
=
calculateMachineLoadBalance
(
chromosome
);
// 存储各目标值
chromosome
.
setMakespan
(
makespan
);
chromosome
.
setTotalFlowTime
(
totalFlowTime
);
chromosome
.
setTotalChangeoverTime
(
totalSetupTime
);
chromosome
.
setMachineLoadStd
(
machineLoadBalance
);
chromosome
.
setDelayTime
(
tardiness
);
// 加权求和作为适应度(权重可根据需求调整)
// chromosome.setFitness(0.4 * (1.0 / (1 + makespan)) +
// 0.3 * (1.0 / (1 + tardiness)) +
// 0.1 * (1.0 / (1 + totalSetupTime)) +
// 0.1 * (1.0 / (1 + totalFlowTime)) +
// 0.1 * machineLoadBalance);
}
private
double
calculateTotalFlowTime
(
Chromosome
chromosome
)
{
return
chromosome
.
getResult
().
stream
()
.
mapToDouble
(
GAScheduleResult:
:
getFlowTime
)
.
sum
();
}
// 计算总换型时间
private
double
calculateTotalSetupTime
(
Chromosome
chromosome
)
{
return
chromosome
.
getResult
().
stream
()
.
mapToDouble
(
GAScheduleResult:
:
getChangeoverTime
)
.
sum
();
}
// 计算机器负载均衡指标
private
double
calculateMachineLoadBalance
(
Chromosome
chromosome
)
{
Map
<
Integer
,
Double
>
machineUtilization
=
new
HashMap
<>();
int
maxEndTime
=
chromosome
.
getResult
().
stream
()
.
mapToInt
(
GAScheduleResult:
:
getEndTime
)
.
max
()
.
orElse
(
0
);
if
(
maxEndTime
==
0
)
return
0
;
for
(
Machine
machine
:
chromosome
.
getMachines
())
{
List
<
GAScheduleResult
>
machineGenes
=
chromosome
.
getResult
().
stream
()
.
filter
(
g
->
g
.
getMachineId
()
==
machine
.
getId
())
.
collect
(
Collectors
.
toList
());
double
busyTime
=
machineGenes
.
stream
()
.
mapToInt
(
g
->
g
.
getEndTime
()
-
g
.
getStartTime
())
.
sum
();
machineUtilization
.
put
(
machine
.
getId
(),
busyTime
/
maxEndTime
);
}
double
avgUtilization
=
machineUtilization
.
values
().
stream
()
.
mapToDouble
(
Double:
:
doubleValue
)
.
average
()
.
orElse
(
0
);
double
variance
=
machineUtilization
.
values
().
stream
()
.
mapToDouble
(
u
->
Math
.
pow
(
u
-
avgUtilization
,
2
))
.
sum
()
/
chromosome
.
getMachines
().
size
();
// 方差越小,负载越均衡
return
1.0
/
(
1
+
variance
);
}
/**
* 补全:创建缓存键(核心逻辑,需与原 C# CreateCacheKey 一致)
* 思路:将染色体的核心特征(机器选择+工序排序)拼接为字符串,确保相同染色体生成相同键
*/
private
String
createCacheKey
(
Chromosome
chromosome
)
{
// 拼接机器选择:用 "," 分隔(例:1,3,2,4)
String
machineStr
=
chromosome
.
getMachineStr
();
// 拼接工序排序:用 "|" 分隔(例:2|1|3|4)
String
operationStr
=
chromosome
.
getOperationStr
();
// 组合最终键(用 "_" 分隔两部分,避免冲突)
return
machineStr
+
"_"
+
operationStr
;
}
}
src/main/java/com/aps/service/Algorithm/GeneticOperations.java
0 → 100644
View file @
ee581dc1
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.Chromosome
;
import
com.aps.entity.Algorithm.GlobalOperationInfo
;
import
com.aps.entity.Algorithm.OperationSequencingWeight
;
import
com.aps.entity.Algorithm.Pair
;
import
com.aps.entity.basic.Entry
;
import
com.aps.entity.basic.GlobalParam
;
import
com.aps.entity.basic.MachineOption
;
import
java.util.*
;
import
java.util.stream.Collectors
;
/**
* 作者:佟礼
* 时间:2025-11-24
*/
public
class
GeneticOperations
{
private
final
Random
rnd
=
new
Random
();
private
static
List
<
Entry
>
allOperations
;
public
GeneticOperations
(
List
<
Entry
>
allOperations
)
{
GeneticOperations
.
allOperations
=
allOperations
;
}
/**
* 锦标赛选择
*/
public
List
<
Chromosome
>
tournamentSelection
(
List
<
Chromosome
>
population
,
int
tournamentSize
)
{
List
<
Chromosome
>
selected
=
new
ArrayList
<>();
while
(
selected
.
size
()
<
population
.
size
())
{
// 随机选择k个个体
// List<Chromosome> candidates = population.stream()
// .sorted((a, b) -> rnd.nextInt())
// .limit(tournamentSize)
// .collect(Collectors.toList());
// 步骤1: 创建一个临时列表用于存放候选者
List
<
Chromosome
>
candidates
=
new
ArrayList
<>(
population
);
// 步骤2: 随机打乱候选者列表
Collections
.
shuffle
(
candidates
,
rnd
);
// 步骤3: 截取前 tournamentSize 个元素作为本次锦标赛的参与者
if
(
tournamentSize
<
candidates
.
size
())
{
candidates
=
candidates
.
subList
(
0
,
tournamentSize
);
}
// 步骤4: 从参与者中选择适应度最高的个体
Chromosome
best
=
candidates
.
stream
()
.
max
(
Comparator
.
comparingDouble
(
Chromosome:
:
getFitness
))
.
orElseThrow
(()
->
new
IllegalStateException
(
"候选列表为空,无法选择最佳个体。"
));
// 复制个体(假设Chromosome有复制方法或通过构造函数复制)
selected
.
add
(
ProductionDeepCopyUtil
.
deepCopy
(
best
));
}
return
selected
;
}
// 重载,使用默认锦标赛大小3
public
List
<
Chromosome
>
tournamentSelection
(
List
<
Chromosome
>
population
)
{
return
tournamentSelection
(
population
,
3
);
}
/**
* 改进POX交叉(工序排序部分)
*/
public
Pair
<
Chromosome
,
Chromosome
>
poxCrossover
(
Chromosome
parent1
,
Chromosome
parent2
,
int
orderCount
)
{
// 步骤1:随机划分工件集
List
<
Integer
>
jobset1
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
orderCount
;
i
++)
{
jobset1
.
add
(
i
);
}
Collections
.
shuffle
(
jobset1
,
rnd
);
jobset1
=
jobset1
.
subList
(
0
,
orderCount
/
2
);
Set
<
Integer
>
jobset1Set
=
new
HashSet
<>(
jobset1
);
List
<
Integer
>
jobset2
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
orderCount
;
i
++)
{
if
(!
jobset1Set
.
contains
(
i
))
{
jobset2
.
add
(
i
);
}
}
// 步骤2:生成子代1
List
<
Integer
>
child1Os
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
parent1
.
getOperationSequencing
().
size
();
i
++)
{
int
op1
=
parent1
.
getOperationSequencing
().
get
(
i
);
int
op2
=
parent2
.
getOperationSequencing
().
get
(
i
);
if
(
jobset1Set
.
contains
(
op1
)
||
jobset1Set
.
contains
(
op2
))
{
child1Os
.
add
(
op1
);
}
else
{
child1Os
.
add
(
op2
);
}
}
// 步骤3:生成子代2
List
<
Integer
>
child2Os
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
parent2
.
getOperationSequencing
().
size
();
i
++)
{
int
op1
=
parent1
.
getOperationSequencing
().
get
(
i
);
int
op2
=
parent2
.
getOperationSequencing
().
get
(
i
);
if
(
jobset1Set
.
contains
(
op2
)
||
jobset1Set
.
contains
(
op1
))
{
child2Os
.
add
(
op2
);
}
else
{
child2Os
.
add
(
op1
);
}
}
// 机器选择部分交叉
List
<
Integer
>
child1Ms
=
new
ArrayList
<>();
List
<
Integer
>
child2Ms
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
parent1
.
getMachineSelection
().
size
();
i
++)
{
int
m1
=
parent1
.
getMachineSelection
().
get
(
i
);
int
m2
=
parent2
.
getMachineSelection
().
get
(
i
);
if
(
rnd
.
nextDouble
()
<
0.5
)
{
child1Ms
.
add
(
m1
);
child2Ms
.
add
(
m2
);
}
else
{
child1Ms
.
add
(
m2
);
child2Ms
.
add
(
m1
);
}
}
Chromosome
child1
=
new
Chromosome
();
child1
.
setMachineSelection
(
child1Ms
);
child1
.
setOperationSequencing
(
child1Os
);
Chromosome
child2
=
new
Chromosome
();
child2
.
setMachineSelection
(
child2Ms
);
child2
.
setOperationSequencing
(
child2Os
);
return
new
Pair
<>(
child1
,
child2
);
}
/**
* 变异操作
*/
public
void
mutate
(
Chromosome
chromosome
,
List
<
GlobalOperationInfo
>
globalOpList
,
double
baseMutationProb
)
{
// 1. 机器选择部分变异
mutateMachineSelection
(
chromosome
,
globalOpList
,
baseMutationProb
);
// 2. 工序排序部分变异
mutateOperationSequencing
(
chromosome
);
}
// 重载,使用默认变异概率
public
void
mutate
(
Chromosome
chromosome
,
List
<
GlobalOperationInfo
>
globalOpList
)
{
mutate
(
chromosome
,
globalOpList
,
0.1
);
}
private
void
mutateMachineSelection
(
Chromosome
chromosome
,
List
<
GlobalOperationInfo
>
globalOpList
,
double
baseMutationProb
)
{
// 计算变异位置数量
int
r
=
Math
.
max
(
1
,
(
int
)
(
chromosome
.
getMachineSelection
().
size
()
*
baseMutationProb
));
int
i
=
0
;
while
(
i
<
r
)
{
int
pos
=
rnd
.
nextInt
(
chromosome
.
getMachineSelection
().
size
());
// 获取对应工序
GlobalOperationInfo
opInfo
=
globalOpList
.
get
(
pos
);
Entry
operation
=
opInfo
.
getOp
();
int
machineSeq
=
chromosome
.
getMachineSelection
().
get
(
pos
);
if
(
operation
.
getMachineOptions
().
size
()
==
1
)
{
continue
;
}
else
{
// 选择当前所选设备外最短加工时间的机器
List
<
MachineOption
>
optionalMachines
=
operation
.
getMachineOptions
();
// 找到当前选中的机器
MachineOption
currentMachine
=
optionalMachines
.
get
(
machineSeq
-
1
);
// 筛选其他机器并找到加工时间最短的
MachineOption
minLoadMachine
=
optionalMachines
.
stream
()
.
filter
(
m
->
m
.
getMachineId
()
!=
currentMachine
.
getMachineId
())
.
min
(
Comparator
.
comparingInt
(
m
->
m
.
getProcessingTime
()))
.
orElse
(
currentMachine
);
// 如果没有其他机器,保持当前
machineSeq
=
optionalMachines
.
indexOf
(
minLoadMachine
)
+
1
;
chromosome
.
getMachineSelection
().
set
(
pos
,
machineSeq
);
i
++;
}
}
}
/**
* 低优先级优先的工序排序变异
*/
private
void
mutateOperationSequencing
(
Chromosome
chromosome
)
{
Random
rnd
=
new
Random
();
// 选择变异方式(交换或反转)
if
(
rnd
.
nextDouble
()
<
0.5
)
{
// 交换:优先选择高优先级工序的索引
OperationSequencingWeight
os1
=
selectHighPriorityIndex
(
chromosome
.
getOperationSequencing
(),
0
);
int
idx1
=
os1
.
getIndex
();
OperationSequencingWeight
os2
=
selectHighPriorityIndex
(
chromosome
.
getOperationSequencing
(),
os1
.
getWeight
());
int
idx2
=
os2
.
getIndex
();
// 交换位置
List
<
Integer
>
os
=
chromosome
.
getOperationSequencing
();
Collections
.
swap
(
os
,
idx1
,
idx2
);
}
else
{
// 反转:仅对高优先级工序集中的子序列反转
OperationSequencingWeight
osStart
=
selectHighPriorityIndex
(
chromosome
.
getOperationSequencing
(),
0
);
int
start
=
osStart
.
getIndex
();
OperationSequencingWeight
osEnd
=
selectHighPriorityIndex
(
chromosome
.
getOperationSequencing
(),
osStart
.
getWeight
());
int
end
=
osEnd
.
getIndex
();
if
(
start
>
end
)
{
int
temp
=
start
;
start
=
end
;
end
=
temp
;
}
// 执行反转
List
<
Integer
>
os
=
chromosome
.
getOperationSequencing
();
for
(
int
i
=
0
;
i
<
(
end
-
start
+
1
)
/
2
;
i
++)
{
int
pos1
=
start
+
i
;
int
pos2
=
end
-
i
;
Collections
.
swap
(
os
,
pos1
,
pos2
);
}
}
}
/**
* 优先选择高优先级工序的索引(用于变异)
*/
private
OperationSequencingWeight
selectHighPriorityIndex
(
List
<
Integer
>
os
,
int
weight
)
{
Random
rnd
=
new
Random
();
List
<
OperationSequencingWeight
>
indexWeights
=
CommonCalculator
.
getOsw
(
os
,
allOperations
);
if
(!
GlobalParam
.
IsBreakPriority
)
{
if
(
weight
==
0
)
{
return
indexWeights
.
get
(
rnd
.
nextInt
(
indexWeights
.
size
()));
}
else
{
List
<
OperationSequencingWeight
>
filtered
=
indexWeights
.
stream
()
.
filter
(
t
->
t
.
getWeight
()
==
weight
)
.
collect
(
Collectors
.
toList
());
return
filtered
.
get
(
rnd
.
nextInt
(
filtered
.
size
()));
}
}
return
indexWeights
.
get
(
CommonCalculator
.
getOsIndex
(
indexWeights
));
}
}
src/main/java/com/aps/service/Algorithm/Initialization.java
View file @
ee581dc1
...
...
@@ -43,33 +43,42 @@ public class Initialization {
*/
public
List
<
Chromosome
>
generateInitialPopulation
(
ScheduleParams
param
,
List
<
GlobalOperationInfo
>
globalOpList
)
{
List
<
Chromosome
>
population
=
new
ArrayList
<>();
// 按比例生成不同类型个体(GS:40%, LS:40%, RS:20%)
int
gsCount
=
(
int
)
(
param
.
getPopulationSize
()
*
param
.
getGsRatio
());
int
lsCount
=
(
int
)
(
param
.
getPopulationSize
()
*
param
.
getLsRatio
());
int
lsCount
=
gsCount
+
(
int
)
(
param
.
getPopulationSize
()
*
param
.
getLsRatio
());
int
rsCount
=
param
.
getPopulationSize
()
-
gsCount
-
lsCount
;
int
populationSize
=
param
.
getPopulationSize
();
// 并行循环:对应 Parallel.For(0, PopulationSize, i => { ... })
IntStream
.
range
(
0
,
populationSize
)
.
parallel
()
// 开启并行
.
forEach
(
i
->
{
Chromosome
chromo
=
new
Chromosome
();
// 初始化染色体
// 全局选择(GS):按GlobalOpId顺序生成MachineSelection
if
(
i
<
gsCount
)
{
generateGSChromosome
(
chromo
,
globalOpList
);
// 对应 C# GenerateGSChromosome
}
else
if
(
i
<
lsCount
)
{
// 局部选择(LS):按GlobalOpId顺序生成MachineSelection(仅负载计算范围不同)
generateLSChromosome
(
chromo
,
globalOpList
);
}
else
{
// 随机选择(RS):按GlobalOpId顺序生成MachineSelection(仅机器选择随机)
generateRSChromosome
(
chromo
,
globalOpList
);
}
population
.
add
(
chromo
);
// 赋值到数组,线程安全(数组索引唯一)
});
// 全局选择(GS):按GlobalOpId顺序生成MachineSelection
for
(
int
i
=
0
;
i
<
gsCount
;
i
++)
{
population
.
add
(
generateGSChromosome
(
globalOpList
,
param
.
getMachineCount
()));
}
// 局部选择(LS):按GlobalOpId顺序生成MachineSelection(仅负载计算范围不同)
for
(
int
i
=
0
;
i
<
lsCount
;
i
++)
{
population
.
add
(
generateLSChromosome
(
globalOpList
,
param
.
getMachineCount
()));
}
// 随机选择(RS):按GlobalOpId顺序生成MachineSelection(仅机器选择随机)
for
(
int
i
=
0
;
i
<
rsCount
;
i
++)
{
population
.
add
(
generateRSChromosome
(
globalOpList
,
param
.
getMachineCount
()));
}
return
population
;
}
/**
* 全局选择(GS)生成染色体(按GlobalOpId顺序生成MachineSelection)
*/
private
Chromosome
generateGSChromosome
(
List
<
GlobalOperationInfo
>
globalOpList
,
int
machineCount
)
{
Chromosome
chromosome
=
new
Chromosome
();
private
Chromosome
generateGSChromosome
(
Chromosome
chromosome
,
List
<
GlobalOperationInfo
>
globalOpList
)
{
Map
<
Integer
,
Integer
>
machineLoad
=
new
HashMap
<>();
// int[] machineLoad = new int[machineCount + 1]; // 设备负载(1-based,设备ID从1开始)
List
<
Integer
>
ms
=
new
ArrayList
<>();
// MachineSelection(顺序=GlobalOpId顺序)
...
...
@@ -106,7 +115,7 @@ public class Initialization {
.
findFirst
();
// 计算该机器在“可选机器列表”中的顺序号(1-based)
int
machineSeq
=
index
.
orElse
(
0
)
;
//findIndex(optionalMachines, minLoadMachine.getMachineId()) + 1;
int
machineSeq
=
index
.
orElse
(
0
)
+
1
;
//findIndex(optionalMachines, minLoadMachine.getMachineId()) + 1;
ms
.
add
(
machineSeq
);
// 更新设备负载
...
...
@@ -132,8 +141,9 @@ public class Initialization {
/**
* 局部选择(LS)生成染色体(按GlobalOpId顺序,每个订单重新初始化负载)
*/
private
Chromosome
generateLSChromosome
(
List
<
GlobalOperationInfo
>
globalOpList
,
int
machineCount
)
{
Chromosome
chromosome
=
new
Chromosome
();
private
Chromosome
generateLSChromosome
(
Chromosome
chromosome
,
List
<
GlobalOperationInfo
>
globalOpList
)
{
List
<
Integer
>
ms
=
new
ArrayList
<>();
List
<
Integer
>
os
=
new
ArrayList
<>();
Random
rnd
=
new
Random
();
...
...
@@ -199,8 +209,9 @@ public class Initialization {
/**
* 随机选择(RS)生成染色体(按GlobalOpId顺序,随机选择机器)
*/
private
Chromosome
generateRSChromosome
(
List
<
GlobalOperationInfo
>
globalOpList
,
int
machineCount
)
{
Chromosome
chromosome
=
new
Chromosome
();
private
Chromosome
generateRSChromosome
(
Chromosome
chromosome
,
List
<
GlobalOperationInfo
>
globalOpList
)
{
List
<
Integer
>
ms
=
new
ArrayList
<>();
List
<
Integer
>
os
=
new
ArrayList
<>();
Random
rnd
=
new
Random
();
...
...
src/main/java/com/aps/service/Algorithm/MachineCalculator.java
0 → 100644
View file @
ee581dc1
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.GAScheduleResult
;
import
com.aps.entity.Algorithm.ScheduleResultDetail
;
import
com.aps.entity.basic.*
;
import
com.aps.service.plan.MachineSchedulerService
;
import
com.baomidou.mybatisplus.core.toolkit.StringUtils
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
import
java.time.temporal.ChronoUnit
;
import
java.util.*
;
import
java.util.stream.Collectors
;
/**
* 作者:佟礼
* 时间:2025-11-24
*/
public
class
MachineCalculator
{
private
LocalDateTime
baseTime
;
private
final
List
<
Machine
>
machines
;
private
final
MachineSchedulerService
machineScheduler
;
public
MachineCalculator
(
LocalDateTime
baseTime
,
List
<
Machine
>
machines
,
MachineSchedulerService
machineScheduler
)
{
this
.
baseTime
=
baseTime
;
this
.
machines
=
machines
;
this
.
machineScheduler
=
machineScheduler
;
}
/**
* 获取机器下一个可用时间窗口(考虑班次约束)
*/
public
List
<
ScheduleResultDetail
>
getNextAvailableTime
(
Machine
machine
,
int
proposedStartTime
,
int
prevtime
,
double
processingTime
,
List
<
GAScheduleResult
>
existingTasks
,
boolean
isInterrupt
,
boolean
istask
,
boolean
islockMachineTime
)
{
LocalDateTime
startTime
=
baseTime
.
plus
(
proposedStartTime
,
ChronoUnit
.
MINUTES
);
String
prevtimestr
=
""
;
if
(
prevtime
>
-
1
)
{
prevtimestr
=
baseTime
.
plus
(
prevtime
,
ChronoUnit
.
MINUTES
)
.
format
(
DateTimeFormatter
.
ofPattern
(
"yyyy-MM-dd HH:mm:ss"
));
}
// 查找合适的班次窗口
return
findEarliestStart
(
machine
,
processingTime
,
startTime
,
prevtimestr
,
existingTasks
,
istask
,
islockMachineTime
);
}
// 查找最早可用开始时间
private
List
<
ScheduleResultDetail
>
findEarliestStart
(
Machine
machine
,
double
processingTime
,
LocalDateTime
currentTime
,
String
prevtime
,
List
<
GAScheduleResult
>
existingTasks
,
boolean
checkprevtime
,
boolean
islockMachineTime
)
{
// 获取设备上已有任务
List
<
GAScheduleResult
>
machineTasks
=
existingTasks
.
stream
()
.
filter
(
t
->
t
.
getMachineId
()
==
machine
.
getId
())
.
sorted
(
Comparator
.
comparingInt
(
GAScheduleResult:
:
getStartTime
))
.
collect
(
Collectors
.
toList
());
List
<
ScheduleResultDetail
>
times
=
new
ArrayList
<>();
TimeSegment
slot
=
GetCurrentOrNextShift
(
machine
,
currentTime
,
prevtime
,
checkprevtime
);
LocalDateTime
startCandidate
=
slot
.
getStart
().
isAfter
(
(
prevtime
.
isEmpty
()
?
currentTime
:
LocalDateTime
.
parse
(
prevtime
,
DateTimeFormatter
.
ofPattern
(
"yyyy-MM-dd HH:mm:ss"
)))
)
?
slot
.
getStart
()
:
(
prevtime
.
isEmpty
()
?
currentTime
:
LocalDateTime
.
parse
(
prevtime
,
DateTimeFormatter
.
ofPattern
(
"yyyy-MM-dd HH:mm:ss"
)));
LocalDateTime
endCandidate
=
startCandidate
.
plus
((
long
)
processingTime
,
ChronoUnit
.
MINUTES
);
// 检查是否在可用时间段内
if
(
endCandidate
.
isAfter
(
slot
.
getEnd
()))
{
// 放不下,继续寻找后续可用时间
return
CaldEarliestStart
(
machine
,
processingTime
,
currentTime
,
prevtime
,
machineTasks
,
checkprevtime
,
islockMachineTime
);
}
else
{
ScheduleResultDetail
time
=
new
ScheduleResultDetail
();
time
.
setKey
(
slot
.
getKey
());
time
.
setStartTime
((
int
)
ChronoUnit
.
MINUTES
.
between
(
baseTime
,
startCandidate
));
time
.
setEndTime
((
int
)
ChronoUnit
.
MINUTES
.
between
(
baseTime
,
endCandidate
));
times
.
add
(
time
);
if
(
islockMachineTime
)
{
RemoveMachineAvailable
(
machine
,
time
);
}
return
times
;
}
}
private
List
<
ScheduleResultDetail
>
CaldEarliestStart
(
Machine
machine
,
double
processingTime
,
LocalDateTime
currentTime
,
String
prevtime
,
List
<
GAScheduleResult
>
machineTasks
,
boolean
checkprevtime
,
boolean
islockMachineTime
)
{
double
remainingTime
=
processingTime
;
LocalDateTime
st
=
StringUtils
.
isEmpty
(
prevtime
)
?
currentTime
:
LocalDateTime
.
parse
(
prevtime
);
LocalDateTime
prevEnd
=
LocalDateTime
.
of
(
2000
,
1
,
1
,
0
,
0
,
0
);
List
<
ScheduleResultDetail
>
times
=
new
ArrayList
<>();
List
<
ScheduleResultDetail
>
oldTimes
=
new
ArrayList
<>();
while
(
remainingTime
>
0
)
{
TimeSegment
shift
=
GetCurrentOrNextShift
(
machine
,
currentTime
,
prevtime
,
checkprevtime
);
if
(
shift
==
null
)
break
;
LocalDateTime
shiftStart
=
shift
.
getStart
();
LocalDateTime
shiftEnd
=
shift
.
getEnd
();
// 检查班次间冲突
if
(!
prevEnd
.
isEqual
(
LocalDateTime
.
of
(
2000
,
1
,
1
,
0
,
0
,
0
)))
{
if
(
prevEnd
.
isBefore
(
currentTime
))
{
// 检查班次间任务
LocalDateTime
finalPrevEnd
=
prevEnd
;
boolean
hasTask
=
machineTasks
.
stream
()
.
anyMatch
(
t
->
{
LocalDateTime
taskStart
=
baseTime
.
plusMinutes
(
t
.
getStartTime
());
return
taskStart
.
isAfter
(
finalPrevEnd
)
&&
taskStart
.
isBefore
(
shiftStart
);
});
if
(
hasTask
)
{
// 重置状态
currentTime
=
shiftStart
;
st
=
shiftStart
;
remainingTime
=
processingTime
;
prevEnd
=
LocalDateTime
.
of
(
2000
,
1
,
1
,
0
,
0
,
0
);
oldTimes
.
addAll
(
ProductionDeepCopyUtil
.
deepCopyList
(
times
));
times
.
clear
();
continue
;
}
// 检查班次间维修窗口
if
(
machine
.
getMaintenanceWindows
()
!=
null
)
{
LocalDateTime
finalPrevEnd1
=
prevEnd
;
boolean
hasMaintenance
=
machine
.
getMaintenanceWindows
().
stream
()
.
anyMatch
(
w
->
w
.
getStartTime
().
isAfter
(
finalPrevEnd1
)
&&
w
.
getStartTime
().
isBefore
(
shiftStart
));
if
(
hasMaintenance
)
{
currentTime
=
shiftStart
;
st
=
shiftStart
;
remainingTime
=
processingTime
;
prevEnd
=
LocalDateTime
.
of
(
2000
,
1
,
1
,
0
,
0
,
0
);
times
.
clear
();
continue
;
}
}
}
}
prevEnd
=
shiftEnd
;
// 计算有效时间
LocalDateTime
effectiveStart
=
st
.
isAfter
(
shiftStart
)
?
st
:
shiftStart
;
long
availableMinutes
=
ChronoUnit
.
MINUTES
.
between
(
effectiveStart
,
shiftEnd
);
// 处理当前班次
double
processable
=
Math
.
min
(
remainingTime
,
(
int
)
availableMinutes
);
remainingTime
-=
processable
;
currentTime
=
effectiveStart
.
plusMinutes
((
long
)
processable
);
// 添加时间详情
ScheduleResultDetail
time
=
new
ScheduleResultDetail
();
time
.
setKey
(
shift
.
getKey
());
time
.
setStartTime
((
int
)
ChronoUnit
.
MINUTES
.
between
(
baseTime
,
effectiveStart
));
time
.
setEndTime
((
int
)
ChronoUnit
.
MINUTES
.
between
(
baseTime
,
currentTime
));
times
.
add
(
time
);
if
(
islockMachineTime
)
{
RemoveMachineAvailable
(
machine
,
time
);
}
}
if
(
islockMachineTime
)
{
// 还原未使用的时间段
AddMachineAvailable
(
machine
,
oldTimes
);
}
return
times
;
}
/**
* 获取设备当前或下一个有效班次
*/
private
TimeSegment
GetCurrentOrNextShift
(
Machine
machine
,
LocalDateTime
time
,
String
prevtime
,
boolean
checkprevtime
)
{
TimeSegment
start
=
null
;
// 查找有效班次
start
=
machine
.
getAvailability
().
stream
()
.
filter
(
slot
->
!
slot
.
isUsed
()
&&
slot
.
getType
()
!=
SegmentType
.
MAINTENANCE
)
.
filter
(
slot
->
slot
.
getStart
().
isAfter
(
time
)
||
slot
.
getEnd
().
isAfter
(
time
))
.
findFirst
()
.
orElse
(
null
);
if
(
start
==
null
)
{
// 生成新时间段
List
<
TimeSegment
>
timeSegments
=
machineScheduler
.
generateTimeSegment
(
machine
,
time
);
machine
.
getAvailability
().
addAll
(
timeSegments
);
// 更新设备时间线
Machine
originalMachine
=
machines
.
stream
()
.
filter
(
t
->
t
.
getId
()
==
machine
.
getId
())
.
findFirst
()
.
orElse
(
null
);
if
(
originalMachine
!=
null
)
{
MachineTimeline
timeline
=
machineScheduler
.
getOrCreateTimeline
(
originalMachine
);
}
// 递归查找
return
GetCurrentOrNextShift
(
machine
,
time
,
prevtime
,
checkprevtime
);
}
return
start
;
}
private
void
RemoveMachineAvailable
(
Machine
machine
,
ScheduleResultDetail
geneDetails
)
{
List
<
TimeSegment
>
timeSegments
=
new
ArrayList
<>();
int
index
=
machine
.
getAvailability
().
stream
()
.
filter
(
t
->
t
.
getKey
().
equals
(
geneDetails
.
getKey
()))
.
findFirst
()
.
map
(
machine
.
getAvailability
()::
indexOf
)
.
orElse
(-
1
);
if
(
index
>
-
1
)
{
TimeSegment
targetSegment
=
machine
.
getAvailability
().
get
(
index
);
LocalDateTime
geneEndTime
=
baseTime
.
plusMinutes
(
geneDetails
.
getEndTime
());
if
(
targetSegment
.
getEnd
().
isAfter
(
geneEndTime
))
{
TimeSegment
usedSegment
=
new
TimeSegment
();
usedSegment
.
setStart
(
baseTime
.
plusMinutes
(
geneDetails
.
getStartTime
()));
usedSegment
.
setEnd
(
geneEndTime
);
usedSegment
.
setHoliday
(
false
);
usedSegment
.
setKey
(
UUID
.
randomUUID
().
toString
());
usedSegment
.
setType
(
SegmentType
.
REGULAR
);
usedSegment
.
setUsed
(
true
);
timeSegments
.
add
(
usedSegment
);
geneDetails
.
setKey
(
usedSegment
.
getKey
());
targetSegment
.
setStart
(
geneEndTime
);
}
else
{
targetSegment
.
setUsed
(
true
);
}
}
if
(!
timeSegments
.
isEmpty
())
{
machine
.
getAvailability
().
addAll
(
timeSegments
);
}
machine
.
getAvailability
().
sort
(
Comparator
.
comparing
(
TimeSegment:
:
getStart
));
}
private
void
AddMachineAvailable
(
Machine
machine
,
List
<
ScheduleResultDetail
>
geneDetails
)
{
if
(
geneDetails
==
null
||
geneDetails
.
isEmpty
())
return
;
for
(
ScheduleResultDetail
detail
:
geneDetails
)
{
machine
.
getAvailability
().
stream
()
.
filter
(
t
->
t
.
getKey
().
equals
(
detail
.
getKey
()))
.
findFirst
()
.
ifPresent
(
t
->
t
.
setUsed
(
false
));
}
machine
.
setAvailability
(
MergeSegments
(
machine
.
getAvailability
()));
}
private
List
<
TimeSegment
>
MergeSegments
(
List
<
TimeSegment
>
segments
)
{
List
<
TimeSegment
>
maintenanceSegments
=
segments
.
stream
()
.
filter
(
t
->
t
.
getType
()
==
SegmentType
.
MAINTENANCE
)
.
collect
(
Collectors
.
toList
());
List
<
TimeSegment
>
unusedRegularSegments
=
segments
.
stream
()
.
filter
(
t
->
t
.
getType
()
!=
SegmentType
.
MAINTENANCE
&&
!
t
.
isUsed
())
.
collect
(
Collectors
.
toList
());
List
<
TimeSegment
>
usedRegularSegments
=
segments
.
stream
()
.
filter
(
t
->
t
.
getType
()
!=
SegmentType
.
MAINTENANCE
&&
t
.
isUsed
())
.
collect
(
Collectors
.
toList
());
unusedRegularSegments
.
sort
(
Comparator
.
comparing
(
TimeSegment:
:
getStart
));
Deque
<
TimeSegment
>
mergedUnused
=
new
ArrayDeque
<>();
for
(
TimeSegment
seg
:
unusedRegularSegments
)
{
if
(!
mergedUnused
.
isEmpty
()
&&
mergedUnused
.
peekLast
().
getEnd
().
isAfter
(
seg
.
getStart
()))
{
TimeSegment
last
=
mergedUnused
.
pollLast
();
last
.
setEnd
(
last
.
getEnd
().
isAfter
(
seg
.
getEnd
())
?
last
.
getEnd
()
:
seg
.
getEnd
());
mergedUnused
.
offerLast
(
last
);
}
else
{
mergedUnused
.
offerLast
(
seg
);
}
}
List
<
TimeSegment
>
result
=
new
ArrayList
<>(
mergedUnused
);
result
.
addAll
(
usedRegularSegments
);
result
.
addAll
(
maintenanceSegments
);
result
.
sort
(
Comparator
.
comparing
(
TimeSegment:
:
getStart
));
return
result
;
}
}
src/main/java/com/aps/service/plan/PlanResultService.java
View file @
ee581dc1
package
com
.
aps
.
service
.
plan
;
import
com.aps.common.util.FileHelper
;
import
com.aps.common.util.JsonFileReader
;
import
com.aps.controller.gantt.FileUploadController
;
import
com.aps.entity.Algorithm.Chromosome
;
import
com.aps.entity.Algorithm.GAScheduleResult
;
import
com.aps.entity.Algorithm.ScheduleParams
;
import
com.aps.entity.Algorithm.ScheduleResultDetail
;
import
com.aps.entity.basic.ScheduleChromosome
;
import
com.aps.entity.Schedule.GenVO
;
import
com.aps.entity.Schedule.MachineVO
;
...
...
@@ -13,9 +18,7 @@ import org.springframework.stereotype.Service;
import
java.io.IOException
;
import
java.math.BigDecimal
;
import
java.time.LocalDateTime
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.*
;
import
java.util.stream.Collectors
;
@Service
...
...
@@ -92,10 +95,9 @@ public class PlanResultService {
}
}
public
List
<
ScheduleChromosome
>
execute1
()
{
public
List
<
Chromosome
>
execute1
()
{
try
{
Entry
entry
=
new
Entry
();
// 1. 读取数据
List
<
Machine
>
machines
=
loadData
(
"machines.json"
,
Machine
.
class
);
...
...
@@ -122,6 +124,11 @@ public class PlanResultService {
}
}
}
ScheduleParams
param
=
new
ScheduleParams
();
param
.
setBaseTime
(
LocalDateTime
.
of
(
2025
,
10
,
1
,
0
,
0
,
0
));
param
.
setPopulationSize
(
50
);
param
.
setMaxIterations
(
100
);
// 创建节假日
List
<
Holiday
>
holidays
=
Arrays
.
asList
(
...
...
@@ -134,34 +141,118 @@ public class PlanResultService {
// 3. 创建调度服务
MachineSchedulerService
machineScheduler
=
new
MachineSchedulerService
(
holidays
,
LocalDateTime
.
of
(
2025
,
10
,
1
,
0
,
0
,
0
));
holidays
,
param
.
getBaseTime
(
));
// 4. 初始化机器时间线
for
(
Machine
machine
:
machines
)
{
MachineTimeline
timeline
=
machineScheduler
.
getOrCreateTimeline
(
machine
);
machine
.
setAvailability
(
timeline
.
getSegments
());
}
// 3. 构建订单-工序数据
List
<
Entry
>
allOperations
=
new
ArrayList
<>();
Random
rnd
=
new
Random
();
// 注意:此处变量声明但未使用,可根据实际需求保留或移除
// 5. 执行调度算法
GeneticAlgorithm
scheduler
=
new
GeneticAlgorithm
();
//new GeneticAlgorithm(products, machines, orders, machineScheduler);
List
<
ScheduleChromosome
>
scheduleChromosomes
=
null
;
scheduler
.
Run
();
int
id
=
1
;
for
(
Order
order
:
orders
)
{
// 假设products是一个List<Product>,根据Product的Id查找对应的产品
Product
product
=
products
.
stream
()
.
filter
(
p
->
p
.
getId
()
==
order
.
getProductId
())
.
findFirst
()
.
orElseThrow
(()
->
new
IllegalArgumentException
(
"未找到对应产品: "
+
order
.
getProductId
()));
int
sequence
=
1
;
for
(
Operation
o
:
product
.
getOperations
())
{
// 假设Product类有getOperations()方法返回工序列表
Entry
entry
=
new
Entry
();
entry
.
setId
(
id
);
entry
.
setGroupId
(
order
.
getId
());
entry
.
setSequence
(
sequence
);
entry
.
setMachineOptions
(
o
.
getMachineOptions
());
// 假设Operation类有获取机器选项的方法
entry
.
setPriority
(
order
.
getPriority
());
entry
.
setQuantity
(
order
.
getQuantity
());
// entry.setMaterialRequirements(o.getMaterialRequirements()); // 假设Operation类有获取物料需求的方法
// 对调度结果按照 fitness 由高到低排序
scheduleChromosomes
.
sort
((
c1
,
c2
)
->
Double
.
compare
(
c2
.
getFitness
(),
c1
.
getFitness
()));
if
(
sequence
!=
1
)
{
entry
.
getPrevEntryIds
().
add
(
id
-
1
);
// 假设Entry类有getPrevEntryIds()返回List<Integer>
}
// 为每个 ScheduleChromosome 分配场景ID(基于排序后的位置)
for
(
int
i
=
0
;
i
<
scheduleChromosomes
.
size
();
i
++)
{
scheduleChromosomes
.
get
(
i
).
setSceneId
(
i
+
1
);
// 场景ID从1开始
allOperations
.
add
(
entry
);
sequence
++;
id
++;
}
}
// 5. 执行调度算法
GeneticAlgorithm
scheduler
=
new
GeneticAlgorithm
(
machines
,
orders
,
null
,
machineScheduler
);
//new GeneticAlgorithm(products, machines, orders, machineScheduler);
List
<
Chromosome
>
Chromosomes
=
scheduler
.
Run
(
param
,
allOperations
);
return
scheduleChromosomes
;
Chromosomes
.
forEach
(
this
::
WriteScheduleSummary
);
return
Chromosomes
;
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"调度执行失败"
,
e
);
}
}
public
void
WriteScheduleSummary
(
Chromosome
schedule
)
{
// 写入日志
FileHelper
.
writeLogFile
(
String
.
format
(
"\n=== Schedule Summary === %f"
,
schedule
.
getFitness
()));
FileHelper
.
writeLogFile
(
String
.
format
(
"Operation: %s"
,
schedule
.
getOperationStr
()));
FileHelper
.
writeLogFile
(
String
.
format
(
"Makespan: %f minutes"
,
schedule
.
getMakespan
()));
FileHelper
.
writeLogFile
(
String
.
format
(
"Total Tardiness: %f hours"
,
schedule
.
getDelayTime
()));
FileHelper
.
writeLogFile
(
String
.
format
(
"Setup Time: %f minutes"
,
schedule
.
getTotalChangeoverTime
()));
FileHelper
.
writeLogFile
(
String
.
format
(
"Flow Time: %f minutes"
,
schedule
.
getTotalFlowTime
()));
FileHelper
.
writeLogFile
(
String
.
format
(
"Machine Load Balance: %.2f%%"
,
schedule
.
getMachineLoadStd
()
*
100
));
FileHelper
.
writeLogFile
(
"-------------------------"
);
// 按订单分组写入
Map
<
Integer
,
List
<
GAScheduleResult
>>
orderGroups
=
schedule
.
getResult
().
stream
()
.
collect
(
Collectors
.
groupingBy
(
GAScheduleResult:
:
getGroupId
));
for
(
Map
.
Entry
<
Integer
,
List
<
GAScheduleResult
>>
group
:
orderGroups
.
entrySet
())
{
List
<
GAScheduleResult
>
sortedJobs
=
group
.
getValue
().
stream
()
.
sorted
(
Comparator
.
comparingInt
(
GAScheduleResult:
:
getOperationId
))
.
collect
(
Collectors
.
toList
());
for
(
GAScheduleResult
job
:
sortedJobs
)
{
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
String
.
format
(
"[%d-%d]:[%s-%s] Order %d, Machine %d, Operation %d, Batch %d, processingTime %d"
,
job
.
getStartTime
(),
job
.
getEndTime
(),
ConvertTime
(
job
.
getStartTime
()),
ConvertTime
(
job
.
getEndTime
()),
job
.
getGroupId
(),
job
.
getMachineId
(),
job
.
getOperationId
(),
job
.
getQuantity
(),
job
.
getProcessingTime
()
));
// 追加基因详情
for
(
ScheduleResultDetail
d
:
job
.
getGeneDetails
())
{
sb
.
append
(
String
.
format
(
"\n\t\t\t\t\t\t\t\t\t\t [%d-%d]:[%s-%s] %d"
,
d
.
getStartTime
(),
d
.
getEndTime
(),
ConvertTime
(
d
.
getStartTime
()),
ConvertTime
(
d
.
getEndTime
()),
d
.
getEndTime
()
-
d
.
getStartTime
()
));
}
FileHelper
.
writeLogFile
(
sb
.
toString
());
}
FileHelper
.
writeLogFile
(
""
);
}
}
private
String
ConvertTime
(
int
minute
)
{
return
baseTime
.
plusMinutes
(
minute
).
format
(
java
.
time
.
format
.
DateTimeFormatter
.
ofPattern
(
"MM-dd HH:mm"
));
}
/**
* 加载数据,优先从上传文件夹加载,如果不存在则从resources加载
...
...
src/main/resources/application.yml
View file @
ee581dc1
...
...
@@ -23,23 +23,23 @@ spring:
# 默认数据源
strict
:
false
# 关闭严格模式
datasource
:
# MySQL数据源
mysql
:
driver-class-name
:
com.mysql.cj.jdbc.Driver
url
:
jdbc:mysql://192.168.0.181:3310/mes?useSSL=false&serverTimezone=UTC
username
:
root
# 替换为你的MySQL用户名
password
:
root_mes@123456~
# 替换为你的MySQL密码
#
# MySQL数据源
#
mysql:
#
driver-class-name: com.mysql.cj.jdbc.Driver
#
url: jdbc:mysql://192.168.0.181:3310/mes?useSSL=false&serverTimezone=UTC
#
username: root # 替换为你的MySQL用户名
#
password: root_mes@123456~ # 替换为你的MySQL密码
# Oracle数据源
oracle
:
driver-class-name
:
oracle.jdbc.OracleDriver
url
:
jdbc:oracle:thin:@//
192.168.0.181:152
2/ORCLPDB1
# ORCL为你的Oracle实例名
url
:
jdbc:oracle:thin:@//
39.100.78.207:700
2/ORCLPDB1
# ORCL为你的Oracle实例名
username
:
mes
# 替换为你的Oracle用户名
password
:
root_mes123456
# 替换为你的Oracle密码
sqlserver
:
driver-class-name
:
com.microsoft.sqlserver.jdbc.SQLServerDriver
url
:
jdbc:sqlserver://192.168.0.181:1434;databaseName=mes;encrypt=false
username
:
sa
password
:
root_mes123456
#
sqlserver:
#
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
#
url: jdbc:sqlserver://192.168.0.181:1434;databaseName=mes;encrypt=false
#
username: sa
#
password: root_mes123456
# 文件上传配置
...
...
src/main/resources/machines.json
View file @
ee581dc1
...
...
@@ -5,6 +5,8 @@
"startTime"
:
"08:00:00"
,
"endTime"
:
"18:00:00"
,
"days"
:
[
1
,
2
,
3
,
4
,
5
],
"startDate"
:
"2025-10-10T00:00:00"
,
"endDate"
:
"2025-11-10T00:00:00"
,
"shiftDate"
:
"0001-01-01T00:00:00"
,
"temporaryShift"
:
false
,
"priority"
:
0
,
...
...
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