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