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
7e5a24bf
Commit
7e5a24bf
authored
May 20, 2026
by
DESKTOP-VKRD9QF\Administration
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
KPI优化
parent
365ed564
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
315 additions
and
60 deletions
+315
-60
Chromosome.java
src/main/java/com/aps/entity/Algorithm/Chromosome.java
+3
-0
GlobalParam.java
src/main/java/com/aps/entity/basic/GlobalParam.java
+209
-2
GeneticDecoder.java
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
+0
-25
PlanResultService.java
src/main/java/com/aps/service/plan/PlanResultService.java
+78
-33
ScheduleStrategyService.java
...in/java/com/aps/service/plan/ScheduleStrategyService.java
+25
-0
No files found.
src/main/java/com/aps/entity/Algorithm/Chromosome.java
View file @
7e5a24bf
...
@@ -2,6 +2,7 @@ package com.aps.entity.Algorithm;
...
@@ -2,6 +2,7 @@ package com.aps.entity.Algorithm;
import
com.aps.entity.Algorithm.IDAndChildID.GroupResult
;
import
com.aps.entity.Algorithm.IDAndChildID.GroupResult
;
import
com.aps.entity.basic.Entry
;
import
com.aps.entity.basic.Entry
;
import
com.aps.entity.basic.GlobalParam
;
import
com.aps.entity.basic.Machine
;
import
com.aps.entity.basic.Machine
;
import
com.aps.entity.basic.Material
;
import
com.aps.entity.basic.Material
;
import
com.aps.entity.basic.Order
;
import
com.aps.entity.basic.Order
;
...
@@ -127,6 +128,8 @@ public class Chromosome {
...
@@ -127,6 +128,8 @@ public class Chromosome {
private
ObjectiveWeights
objectiveWeights
;
private
ObjectiveWeights
objectiveWeights
;
private
GlobalParam
globalParamSnapshot
;
private
TreeMap
<
String
,
Material
>
materials
=
new
TreeMap
<>();
private
TreeMap
<
String
,
Material
>
materials
=
new
TreeMap
<>();
// private List<Material> materials = new ArrayList<>();
// private List<Material> materials = new ArrayList<>();
...
...
src/main/java/com/aps/entity/basic/GlobalParam.java
View file @
7e5a24bf
...
@@ -80,7 +80,6 @@ public class GlobalParam {
...
@@ -80,7 +80,6 @@ public class GlobalParam {
public
static
final
String
OBJECTIVE_SETUP_TIME
=
"setupTime"
;
// 总换型时间
public
static
final
String
OBJECTIVE_SETUP_TIME
=
"setupTime"
;
// 总换型时间
public
static
final
String
OBJECTIVE_MACHINE_LOAD
=
"machineLoad"
;
// 机器负载均衡
public
static
final
String
OBJECTIVE_MACHINE_LOAD
=
"machineLoad"
;
// 机器负载均衡
public
static
final
String
OBJECTIVE_TARDINESS
=
"tardiness"
;
// 延迟时间
public
static
final
String
OBJECTIVE_TARDINESS
=
"tardiness"
;
// 延迟时间
public
static
final
String
OBJECTIVE_SEMI_JIT
=
"semiJitSlack"
;
// 半成品提前完工惩罚
/// <summary>
/// <summary>
/// 构造函数,初始化默认值
/// 构造函数,初始化默认值
...
@@ -93,7 +92,6 @@ public class GlobalParam {
...
@@ -93,7 +92,6 @@ public class GlobalParam {
objectiveConfigs
.
add
(
createMinimizeObjectiveConfig
(
OBJECTIVE_SETUP_TIME
,
2
,
0.39
));
objectiveConfigs
.
add
(
createMinimizeObjectiveConfig
(
OBJECTIVE_SETUP_TIME
,
2
,
0.39
));
objectiveConfigs
.
add
(
createMinimizeObjectiveConfig
(
OBJECTIVE_MACHINE_LOAD
,
1
,
0.3
));
objectiveConfigs
.
add
(
createMinimizeObjectiveConfig
(
OBJECTIVE_MACHINE_LOAD
,
1
,
0.3
));
objectiveConfigs
.
add
(
createMinimizeObjectiveConfig
(
OBJECTIVE_TARDINESS
,
1
,
0.3
));
objectiveConfigs
.
add
(
createMinimizeObjectiveConfig
(
OBJECTIVE_TARDINESS
,
1
,
0.3
));
objectiveConfigs
.
add
(
createMinimizeObjectiveConfig
(
OBJECTIVE_SEMI_JIT
,
2
,
0.01
));
objectiveConfigs
.
sort
(
Comparator
.
comparing
((
ObjectiveConfig
op
)
->
op
.
getLevel
()));
objectiveConfigs
.
sort
(
Comparator
.
comparing
((
ObjectiveConfig
op
)
->
op
.
getLevel
()));
}
}
...
@@ -191,4 +189,213 @@ public class GlobalParam {
...
@@ -191,4 +189,213 @@ public class GlobalParam {
public
void
removeObjectiveConfig
(
String
name
)
{
public
void
removeObjectiveConfig
(
String
name
)
{
objectiveConfigs
.
removeIf
(
config
->
config
.
getName
().
equals
(
name
));
objectiveConfigs
.
removeIf
(
config
->
config
.
getName
().
equals
(
name
));
}
}
public
void
applyKpiConfig
(
Object
rawConfig
)
{
List
<?>
kpiList
=
extractKpiList
(
rawConfig
);
if
(
kpiList
.
isEmpty
())
{
return
;
}
List
<
ObjectiveConfig
>
configs
=
new
ArrayList
<>();
int
sequence
=
1
;
for
(
Object
item
:
kpiList
)
{
ObjectiveConfig
config
=
toObjectiveConfig
(
item
,
sequence
++);
if
(
config
!=
null
)
{
configs
.
add
(
config
);
}
}
if
(!
configs
.
isEmpty
())
{
configs
.
sort
(
Comparator
.
comparing
((
ObjectiveConfig
op
)
->
op
.
getLevel
()));
objectiveConfigs
=
configs
;
}
}
public
GlobalParam
copy
()
{
GlobalParam
target
=
new
GlobalParam
();
target
.
IsBreakPriority
=
this
.
IsBreakPriority
;
target
.
IsMultipleMachine
=
this
.
IsMultipleMachine
;
target
.
IsUseCalendar
=
this
.
IsUseCalendar
;
target
.
IsCheckMp
=
this
.
IsCheckMp
;
target
.
IsCheckSf
=
this
.
IsCheckSf
;
target
.
IsOverlap
=
this
.
IsOverlap
;
target
.
isJit
=
this
.
isJit
;
target
.
_smoothSetup
=
this
.
_smoothSetup
;
target
.
_smoothChangeOver
=
this
.
_smoothChangeOver
;
target
.
_smoothChangeOverInWeek
=
this
.
_smoothChangeOverInWeek
;
target
.
pureNSGAIIMode
=
this
.
pureNSGAIIMode
;
target
.
semiJitBufferMinutes
=
this
.
semiJitBufferMinutes
;
target
.
materialSolveMaxIterations
=
this
.
materialSolveMaxIterations
;
target
.
objectiveConfigs
=
copyObjectiveConfigs
(
this
.
objectiveConfigs
);
return
target
;
}
private
List
<?>
extractKpiList
(
Object
rawConfig
)
{
if
(
rawConfig
instanceof
List
)
{
return
(
List
<?>)
rawConfig
;
}
if
(
rawConfig
instanceof
Map
)
{
Map
<?,
?>
map
=
(
Map
<?,
?>)
rawConfig
;
Object
kpiConfig
=
map
.
get
(
"kpiConfig"
);
if
(
kpiConfig
instanceof
List
)
{
return
(
List
<?>)
kpiConfig
;
}
Object
kpiList
=
map
.
get
(
"kpiList"
);
if
(
kpiList
instanceof
List
)
{
return
(
List
<?>)
kpiList
;
}
}
return
Collections
.
emptyList
();
}
private
ObjectiveConfig
toObjectiveConfig
(
Object
raw
,
int
sequence
)
{
if
(
raw
instanceof
ObjectiveConfig
)
{
ObjectiveConfig
source
=
(
ObjectiveConfig
)
raw
;
ObjectiveConfig
copy
=
copyObjectiveConfig
(
source
);
copy
.
setName
(
normalizeObjectiveName
(
copy
.
getName
()));
return
isKnownObjective
(
copy
.
getName
())
?
copy
:
null
;
}
if
(!(
raw
instanceof
Map
))
{
return
null
;
}
Map
<?,
?>
map
=
(
Map
<?,
?>)
raw
;
String
name
=
normalizeObjectiveName
(
asString
(
firstValue
(
map
,
"name"
,
"code"
,
"fieldName"
)));
if
(!
isKnownObjective
(
name
))
{
return
null
;
}
ObjectiveConfig
fallback
=
getObjectiveConfig
(
name
);
ObjectiveConfig
config
=
fallback
==
null
?
createMinimizeObjectiveConfig
(
name
,
sequence
,
1
D
)
:
copyObjectiveConfig
(
fallback
);
config
.
setName
(
name
);
config
.
setEnabled
(
asBoolean
(
firstValue
(
map
,
"enabled"
,
"value"
),
config
.
isEnabled
()));
config
.
setMinimize
(
asBoolean
(
firstValue
(
map
,
"isMinimize"
,
"minimize"
),
config
.
isMinimize
()));
config
.
setLevel
(
asInt
(
firstValue
(
map
,
"level"
,
"sort"
),
config
.
getLevel
()));
config
.
setWeight
(
asDouble
(
firstValue
(
map
,
"weight"
),
config
.
getWeight
()));
config
.
setVal
(
asDouble
(
firstValue
(
map
,
"val"
,
"valueNumber"
),
config
.
getVal
()));
return
config
;
}
private
List
<
ObjectiveConfig
>
copyObjectiveConfigs
(
List
<
ObjectiveConfig
>
source
)
{
if
(
source
==
null
)
{
return
new
ArrayList
<>();
}
List
<
ObjectiveConfig
>
copy
=
new
ArrayList
<>();
for
(
ObjectiveConfig
config
:
source
)
{
ObjectiveConfig
copied
=
copyObjectiveConfig
(
config
);
if
(
isKnownObjective
(
copied
.
getName
()))
{
copy
.
add
(
copied
);
}
}
return
copy
;
}
private
ObjectiveConfig
copyObjectiveConfig
(
ObjectiveConfig
source
)
{
ObjectiveConfig
copy
=
new
ObjectiveConfig
();
if
(
source
!=
null
)
{
copy
.
setName
(
source
.
getName
());
copy
.
setEnabled
(
source
.
isEnabled
());
copy
.
setMinimize
(
source
.
isMinimize
());
copy
.
setLevel
(
source
.
getLevel
());
copy
.
setWeight
(
source
.
getWeight
());
copy
.
setVal
(
source
.
getVal
());
}
return
copy
;
}
private
Object
firstValue
(
Map
<?,
?>
map
,
String
...
keys
)
{
for
(
String
key
:
keys
)
{
if
(
map
.
containsKey
(
key
))
{
return
map
.
get
(
key
);
}
}
return
null
;
}
private
String
normalizeObjectiveName
(
String
name
)
{
if
(
name
==
null
)
{
return
null
;
}
String
normalized
=
name
.
trim
().
replace
(
"_"
,
""
).
replace
(
"-"
,
""
).
replace
(
" "
,
""
).
toLowerCase
(
Locale
.
ROOT
);
switch
(
normalized
)
{
case
"makespan"
:
return
OBJECTIVE_MAKESPAN
;
case
"flowtime"
:
case
"totalflowtime"
:
return
OBJECTIVE_FLOW_TIME
;
case
"setuptime"
:
case
"totalsetuptime"
:
case
"changeovertime"
:
return
OBJECTIVE_SETUP_TIME
;
case
"machineload"
:
case
"machineloadbalance"
:
case
"loadbalance"
:
return
OBJECTIVE_MACHINE_LOAD
;
case
"tardiness"
:
case
"delaytime"
:
return
OBJECTIVE_TARDINESS
;
default
:
return
name
.
trim
();
}
}
private
boolean
isKnownObjective
(
String
name
)
{
return
OBJECTIVE_MAKESPAN
.
equals
(
name
)
||
OBJECTIVE_FLOW_TIME
.
equals
(
name
)
||
OBJECTIVE_SETUP_TIME
.
equals
(
name
)
||
OBJECTIVE_MACHINE_LOAD
.
equals
(
name
)
||
OBJECTIVE_TARDINESS
.
equals
(
name
);
}
private
String
asString
(
Object
value
)
{
return
value
==
null
?
null
:
String
.
valueOf
(
value
);
}
private
boolean
asBoolean
(
Object
value
,
boolean
defaultValue
)
{
if
(
value
==
null
)
{
return
defaultValue
;
}
if
(
value
instanceof
Boolean
)
{
return
(
Boolean
)
value
;
}
if
(
value
instanceof
Number
)
{
return
((
Number
)
value
).
intValue
()
!=
0
;
}
String
text
=
String
.
valueOf
(
value
).
trim
();
if
(
"1"
.
equals
(
text
))
{
return
true
;
}
if
(
"0"
.
equals
(
text
))
{
return
false
;
}
return
text
.
isEmpty
()
?
defaultValue
:
Boolean
.
parseBoolean
(
text
);
}
private
int
asInt
(
Object
value
,
int
defaultValue
)
{
if
(
value
==
null
)
{
return
defaultValue
;
}
if
(
value
instanceof
Number
)
{
return
((
Number
)
value
).
intValue
();
}
try
{
return
Integer
.
parseInt
(
String
.
valueOf
(
value
).
trim
());
}
catch
(
Exception
e
)
{
return
defaultValue
;
}
}
private
double
asDouble
(
Object
value
,
double
defaultValue
)
{
if
(
value
==
null
)
{
return
defaultValue
;
}
if
(
value
instanceof
Number
)
{
return
((
Number
)
value
).
doubleValue
();
}
try
{
return
Double
.
parseDouble
(
String
.
valueOf
(
value
).
trim
());
}
catch
(
Exception
e
)
{
return
defaultValue
;
}
}
}
}
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
View file @
7e5a24bf
...
@@ -2799,11 +2799,6 @@ if(geneDetails!=null&&geneDetails.size()>0)
...
@@ -2799,11 +2799,6 @@ if(geneDetails!=null&&geneDetails.size()>0)
chromosome
.
setMachineLoadStd
(
machineLoadBalance
);
chromosome
.
setMachineLoadStd
(
machineLoadBalance
);
Objectives
[
i
]
=
machineLoadBalance
;
Objectives
[
i
]
=
machineLoadBalance
;
}
}
if
(
GlobalParam
.
OBJECTIVE_SEMI_JIT
.
equals
(
config
.
getName
()))
{
double
semiJitSlack
=
calculateSemiJitSlack
(
chromosome
);
chromosome
.
setSemiJitSlack
(
semiJitSlack
);
Objectives
[
i
]
=
semiJitSlack
;
}
i
++;
i
++;
}
}
}
}
...
@@ -2863,26 +2858,6 @@ if(geneDetails!=null&&geneDetails.size()>0)
...
@@ -2863,26 +2858,6 @@ if(geneDetails!=null&&geneDetails.size()>0)
return
Math
.
sqrt
(
variance
)/
avgUtilization
;
return
Math
.
sqrt
(
variance
)/
avgUtilization
;
}
}
private
double
calculateSemiJitSlack
(
Chromosome
chromosome
)
{
Map
<
Integer
,
GAScheduleResult
>
resultByOperation
=
chromosome
.
getResult
().
stream
()
.
collect
(
Collectors
.
toMap
(
GAScheduleResult:
:
getOperationId
,
t
->
t
,
(
left
,
right
)
->
left
));
double
semiJitSlack
=
0
;
for
(
Entry
operation
:
chromosome
.
getAllOperations
())
{
if
(
operation
.
getLatestCompletionTime
()
==
null
)
{
continue
;
}
GAScheduleResult
result
=
resultByOperation
.
get
(
operation
.
getId
());
if
(
result
==
null
)
{
continue
;
}
LocalDateTime
completionTime
=
baseTime
.
plusSeconds
(
result
.
getEndTime
());
if
(
completionTime
.
isBefore
(
operation
.
getLatestCompletionTime
()))
{
semiJitSlack
+=
ChronoUnit
.
MINUTES
.
between
(
completionTime
,
operation
.
getLatestCompletionTime
());
}
}
return
semiJitSlack
;
}
/**
/**
* 补全:创建缓存键(核心逻辑,需与原 C# CreateCacheKey 一致)
* 补全:创建缓存键(核心逻辑,需与原 C# CreateCacheKey 一致)
* 思路:将染色体的核心特征(机器选择+工序排序)拼接为字符串,确保相同染色体生成相同键
* 思路:将染色体的核心特征(机器选择+工序排序)拼接为字符串,确保相同染色体生成相同键
...
...
src/main/java/com/aps/service/plan/PlanResultService.java
View file @
7e5a24bf
...
@@ -167,10 +167,19 @@ public class PlanResultService {
...
@@ -167,10 +167,19 @@ public class PlanResultService {
// 兼容旧调用:前端只传 sceneId 时,仍然会在内部根据场景创建人查找用户策略。
// 兼容旧调用:前端只传 sceneId 时,仍然会在内部根据场景创建人查找用户策略。
/**
* 只传场景ID时的排产入口。
* 这里不强制要求前端传 userId / baseRuleId / userRuleId,
* 后续会按场景创建人自动回退到可用的策略配置。
*/
public
Chromosome
execute2
(
String
SceneId
)
{
public
Chromosome
execute2
(
String
SceneId
)
{
return
execute2
(
SceneId
,
null
,
null
,
null
);
return
execute2
(
SceneId
,
null
,
null
,
null
);
}
}
/**
* 完整排产入口。
* 传入的用户策略参数可选,缺省时会根据场景信息去找当前有效策略。
*/
public
Chromosome
execute2
(
String
SceneId
,
Long
userId
,
Long
baseRuleId
,
String
userRuleId
)
{
public
Chromosome
execute2
(
String
SceneId
,
Long
userId
,
Long
baseRuleId
,
String
userRuleId
)
{
try
{
try
{
...
@@ -195,7 +204,7 @@ public class PlanResultService {
...
@@ -195,7 +204,7 @@ public class PlanResultService {
List
<
ProdLaunchOrder
>
ProdLaunchOrders
=
_prodLaunchOrderService
.
lambdaQuery
()
List
<
ProdLaunchOrder
>
ProdLaunchOrders
=
_prodLaunchOrderService
.
lambdaQuery
()
.
eq
(
ProdLaunchOrder:
:
getSceneId
,
SceneId
)
.
eq
(
ProdLaunchOrder:
:
getSceneId
,
SceneId
)
.
list
();
.
list
();
GlobalParam
globalParam
=
InitGlobalParam
(
);
GlobalParam
globalParam
=
buildInitialGlobalParam
(
SceneId
,
effectiveUserId
,
baseRuleId
,
userRuleId
);
// 3. 创建调度服务
// 3. 创建调度服务
MachineSchedulerService
machineScheduler
=
new
MachineSchedulerService
(
MachineSchedulerService
machineScheduler
=
new
MachineSchedulerService
(
...
@@ -274,6 +283,7 @@ public class PlanResultService {
...
@@ -274,6 +283,7 @@ public class PlanResultService {
// 这里会从 Dispatch 表加载锁定期工单,并添加到 chromosome.result 中
// 这里会从 Dispatch 表加载锁定期工单,并添加到 chromosome.result 中
lockedOrderProcessorService
.
addLockedOrdersToResult
(
chromosome
);
lockedOrderProcessorService
.
addLockedOrdersToResult
(
chromosome
);
saveGlobalParamSnapshot
(
chromosome
,
globalParam
);
boolean
saved
=
_sceneService
.
saveChromosomeToFile
(
chromosome
,
SceneId
);
boolean
saved
=
_sceneService
.
saveChromosomeToFile
(
chromosome
,
SceneId
);
if
(!
saved
)
{
if
(!
saved
)
{
throw
new
BusinessException
(
"排产计算结果保存失败,请稍后重试或联系管理员"
);
throw
new
BusinessException
(
"排产计算结果保存失败,请稍后重试或联系管理员"
);
...
@@ -1118,7 +1128,7 @@ public class PlanResultService {
...
@@ -1118,7 +1128,7 @@ public class PlanResultService {
.
forEach
(
opInfo
->
opInfo
.
setOp
(
operation
));
.
forEach
(
opInfo
->
opInfo
.
setOp
(
operation
));
}
}
}
}
GlobalParam
globalParam
=
new
GlobalParam
(
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
// Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
// Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
...
@@ -1213,7 +1223,7 @@ public class PlanResultService {
...
@@ -1213,7 +1223,7 @@ public class PlanResultService {
.
filter
(
opInfo
->
opInfo
.
getOp
()
!=
null
&&
opInfo
.
getOp
().
getId
()
==
operation
.
getId
())
.
filter
(
opInfo
->
opInfo
.
getOp
()
!=
null
&&
opInfo
.
getOp
().
getId
()
==
operation
.
getId
())
.
forEach
(
opInfo
->
opInfo
.
setOp
(
operation
));
.
forEach
(
opInfo
->
opInfo
.
setOp
(
operation
));
}
}
GlobalParam
globalParam
=
new
GlobalParam
(
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
ScheduleOperationService
ScheduleOperation
=
new
ScheduleOperationService
(
materialRequirementService
,
this
);
ScheduleOperationService
ScheduleOperation
=
new
ScheduleOperationService
(
materialRequirementService
,
this
);
ScheduleOperation
.
editMachineOption
(
chromosome
,
operation
,
operation
.
getSelectMachineID
(),
globalParam
);
ScheduleOperation
.
editMachineOption
(
chromosome
,
operation
,
operation
.
getSelectMachineID
(),
globalParam
);
...
@@ -1303,7 +1313,7 @@ public class PlanResultService {
...
@@ -1303,7 +1313,7 @@ public class PlanResultService {
* 重新解码染色体
* 重新解码染色体
*/
*/
private
Chromosome
redecodeChromosome
(
Chromosome
chromosome
,
String
SceneId
)
{
private
Chromosome
redecodeChromosome
(
Chromosome
chromosome
,
String
SceneId
)
{
GlobalParam
globalParam
=
new
GlobalParam
(
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
ScheduleOperationService
scheduleOperation
=
new
ScheduleOperationService
(
materialRequirementService
,
this
);
ScheduleOperationService
scheduleOperation
=
new
ScheduleOperationService
(
materialRequirementService
,
this
);
scheduleOperation
.
redecode
(
chromosome
,
chromosome
.
getBaseTime
(),
globalParam
);
scheduleOperation
.
redecode
(
chromosome
,
chromosome
.
getBaseTime
(),
globalParam
);
// _sceneService.saveChromosomeToFile(chromosome, SceneId);
// _sceneService.saveChromosomeToFile(chromosome, SceneId);
...
@@ -1319,7 +1329,7 @@ public class PlanResultService {
...
@@ -1319,7 +1329,7 @@ public class PlanResultService {
chromosome
.
setBaseTime
(
BaseTime
);
chromosome
.
setBaseTime
(
BaseTime
);
ScheduleOperationService
ScheduleOperation
=
new
ScheduleOperationService
(
materialRequirementService
,
this
);
ScheduleOperationService
ScheduleOperation
=
new
ScheduleOperationService
(
materialRequirementService
,
this
);
GlobalParam
globalParam
=
new
GlobalParam
(
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
ScheduleOperation
.
redecode
(
chromosome
,
chromosome
.
getBaseTime
(),
globalParam
);
ScheduleOperation
.
redecode
(
chromosome
,
chromosome
.
getBaseTime
(),
globalParam
);
return
chromosome
;
return
chromosome
;
...
@@ -1328,8 +1338,8 @@ public class PlanResultService {
...
@@ -1328,8 +1338,8 @@ public class PlanResultService {
Long
newMachineId
)
{
Long
newMachineId
)
{
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
// 拖拽前清理历史工单在设备上的静态占位段,确保历史工单移动后可释放产能
// 拖拽前清理历史工单在设备上的静态占位段,确保历史工单移动后可释放产能
int
releasedCount
=
releaseLockedOccupancyForDrag
(
chromosome
);
int
releasedCount
=
releaseLockedOccupancyForDrag
(
chromosome
);
...
@@ -1470,7 +1480,7 @@ public class PlanResultService {
...
@@ -1470,7 +1480,7 @@ public class PlanResultService {
LocalDateTime
anchorTime
=
baseTime
.
plusSeconds
(
Math
.
max
(
freezeSeconds
,
0L
));
LocalDateTime
anchorTime
=
baseTime
.
plusSeconds
(
Math
.
max
(
freezeSeconds
,
0L
));
// 5. 自动插单(占位后推 + 空挡前移)
// 5. 自动插单(占位后推 + 空挡前移)
GlobalParam
globalParam
=
InitGlobalParam
(
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
sceneId
,
chromosome
,
true
);
ScheduleOperationService
scheduleOperation
=
new
ScheduleOperationService
(
materialRequirementService
,
this
);
ScheduleOperationService
scheduleOperation
=
new
ScheduleOperationService
(
materialRequirementService
,
this
);
scheduleOperation
.
InsertOrderAuto
(
scheduleOperation
.
InsertOrderAuto
(
chromosome
,
chromosome
,
...
@@ -1493,8 +1503,8 @@ public class PlanResultService {
...
@@ -1493,8 +1503,8 @@ public class PlanResultService {
Long
newMachineId
,
int
lockStartTime
)
{
Long
newMachineId
,
int
lockStartTime
)
{
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
// WriteScheduleSummary(chromosome);
// WriteScheduleSummary(chromosome);
...
@@ -1514,7 +1524,7 @@ public class PlanResultService {
...
@@ -1514,7 +1524,7 @@ public class PlanResultService {
Long
newMachineId
,
int
lockStartTime
)
{
Long
newMachineId
,
int
lockStartTime
)
{
GlobalParam
globalParam
=
new
GlobalParam
(
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
chromosome
);
...
@@ -1535,7 +1545,7 @@ public class PlanResultService {
...
@@ -1535,7 +1545,7 @@ public class PlanResultService {
// WriteScheduleSummary(chromosome);
// WriteScheduleSummary(chromosome);
GlobalParam
globalParam
=
new
GlobalParam
(
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
ScheduleOperation
.
redecode
(
chromosome
,
chromosome
.
getBaseTime
(),
globalParam
);
ScheduleOperation
.
redecode
(
chromosome
,
chromosome
.
getBaseTime
(),
globalParam
);
// WriteScheduleSummary(chromosome);
// WriteScheduleSummary(chromosome);
}
}
...
@@ -1544,9 +1554,8 @@ public class PlanResultService {
...
@@ -1544,9 +1554,8 @@ public class PlanResultService {
public
Chromosome
SpiltOperation
(
String
SceneId
,
int
opId
,
Double
[]
splitCounts
)
{
public
Chromosome
SpiltOperation
(
String
SceneId
,
int
opId
,
Double
[]
splitCounts
)
{
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
//this.baseTime=param.getBaseTime();
//this.baseTime=param.getBaseTime();
// WriteScheduleSummary(chromosome);
// WriteScheduleSummary(chromosome);
...
@@ -1561,9 +1570,8 @@ public class PlanResultService {
...
@@ -1561,9 +1570,8 @@ public class PlanResultService {
public
Chromosome
DelOperation
(
String
SceneId
,
int
opId
)
{
public
Chromosome
DelOperation
(
String
SceneId
,
int
opId
)
{
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
//this.baseTime=param.getBaseTime();
//this.baseTime=param.getBaseTime();
// WriteScheduleSummary(chromosome);
// WriteScheduleSummary(chromosome);
...
@@ -1578,9 +1586,8 @@ public class PlanResultService {
...
@@ -1578,9 +1586,8 @@ public class PlanResultService {
public
Chromosome
DelOrder
(
String
SceneId
,
String
orderId
)
{
public
Chromosome
DelOrder
(
String
SceneId
,
String
orderId
)
{
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
//this.baseTime=param.getBaseTime();
//this.baseTime=param.getBaseTime();
// WriteScheduleSummary(chromosome);
// WriteScheduleSummary(chromosome);
...
@@ -1598,9 +1605,8 @@ public class PlanResultService {
...
@@ -1598,9 +1605,8 @@ public class PlanResultService {
public
Chromosome
LockOperation
(
String
SceneId
,
int
opId
,
boolean
isLocked
)
{
public
Chromosome
LockOperation
(
String
SceneId
,
int
opId
,
boolean
isLocked
)
{
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
//this.baseTime=param.getBaseTime();
//this.baseTime=param.getBaseTime();
// WriteScheduleSummary(chromosome);
// WriteScheduleSummary(chromosome);
...
@@ -1615,9 +1621,8 @@ public class PlanResultService {
...
@@ -1615,9 +1621,8 @@ public class PlanResultService {
public
Chromosome
SpiltOrder
(
String
SceneId
,
String
orderId
,
Double
[]
splitCounts
)
{
public
Chromosome
SpiltOrder
(
String
SceneId
,
String
orderId
,
Double
[]
splitCounts
)
{
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
//this.baseTime=param.getBaseTime();
//this.baseTime=param.getBaseTime();
// WriteScheduleSummary(chromosome);
// WriteScheduleSummary(chromosome);
...
@@ -1678,8 +1683,8 @@ public class PlanResultService {
...
@@ -1678,8 +1683,8 @@ public class PlanResultService {
// 这里需要重新加载场景,因为数据库已经有新订单了
// 这里需要重新加载场景,因为数据库已经有新订单了
// 然后使用类似复制的逻辑,将新订单排在afterOrderId后面
// 然后使用类似复制的逻辑,将新订单排在afterOrderId后面
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
// 从数据库加载新插入的订单及其工序
// 从数据库加载新插入的订单及其工序
ProdLaunchOrder
newLaunchOrder
=
_prodLaunchOrderService
.
lambdaQuery
()
ProdLaunchOrder
newLaunchOrder
=
_prodLaunchOrderService
.
lambdaQuery
()
...
@@ -1717,9 +1722,8 @@ public class PlanResultService {
...
@@ -1717,9 +1722,8 @@ public class PlanResultService {
public
Chromosome
MergeOrder
(
String
SceneId
,
String
sourceorderId
,
String
targetorderId
)
{
public
Chromosome
MergeOrder
(
String
SceneId
,
String
sourceorderId
,
String
targetorderId
)
{
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
//this.baseTime=param.getBaseTime();
//this.baseTime=param.getBaseTime();
// WriteScheduleSummary(chromosome);
// WriteScheduleSummary(chromosome);
...
@@ -1733,9 +1737,8 @@ public class PlanResultService {
...
@@ -1733,9 +1737,8 @@ public class PlanResultService {
public
Chromosome
AddMaintenanceWindow
(
String
SceneId
,
Long
machineId
,
MaintenanceWindow
maintenanceWindow
)
{
public
Chromosome
AddMaintenanceWindow
(
String
SceneId
,
Long
machineId
,
MaintenanceWindow
maintenanceWindow
)
{
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
...
@@ -1750,9 +1753,8 @@ public class PlanResultService {
...
@@ -1750,9 +1753,8 @@ public class PlanResultService {
public
Chromosome
DelMaintenanceWindow
(
String
SceneId
,
Long
machineId
,
String
maintenanceId
)
{
public
Chromosome
DelMaintenanceWindow
(
String
SceneId
,
Long
machineId
,
String
maintenanceId
)
{
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
...
@@ -1766,8 +1768,8 @@ public class PlanResultService {
...
@@ -1766,8 +1768,8 @@ public class PlanResultService {
}
}
public
Chromosome
DelMaintenanceWindowBatch
(
String
SceneId
,
Long
machineId
,
List
<
String
>
maintenanceIds
)
{
public
Chromosome
DelMaintenanceWindowBatch
(
String
SceneId
,
Long
machineId
,
List
<
String
>
maintenanceIds
)
{
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
ScheduleOperationService
ScheduleOperation
=
new
ScheduleOperationService
(
materialRequirementService
,
this
);
ScheduleOperationService
ScheduleOperation
=
new
ScheduleOperationService
(
materialRequirementService
,
this
);
...
@@ -1780,9 +1782,8 @@ public class PlanResultService {
...
@@ -1780,9 +1782,8 @@ public class PlanResultService {
public
List
<
MaintenanceWindow
>
GetMaintenanceWindow
(
String
SceneId
,
Long
machineId
,
MaintenanceWindow
maintenanceWindow
)
{
public
List
<
MaintenanceWindow
>
GetMaintenanceWindow
(
String
SceneId
,
Long
machineId
,
MaintenanceWindow
maintenanceWindow
)
{
GlobalParam
globalParam
=
new
GlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
GlobalParam
globalParam
=
buildGlobalParamFromSnapshot
(
SceneId
,
chromosome
);
...
@@ -1850,7 +1851,7 @@ public class PlanResultService {
...
@@ -1850,7 +1851,7 @@ public class PlanResultService {
List
<
ProdEquipment
>
ProdEquipments
=
_prodEquipmentService
.
lambdaQuery
()
List
<
ProdEquipment
>
ProdEquipments
=
_prodEquipmentService
.
lambdaQuery
()
.
eq
(
ProdEquipment:
:
getSceneId
,
SceneId
)
.
eq
(
ProdEquipment:
:
getSceneId
,
SceneId
)
.
list
();
.
list
();
GlobalParam
globalParam
=
InitGlobalParam
(
);
GlobalParam
globalParam
=
buildInitialGlobalParam
(
SceneId
,
null
,
null
,
null
);
List
<
ProdLaunchOrder
>
ProdLaunchOrders
=
_prodLaunchOrderService
.
lambdaQuery
()
List
<
ProdLaunchOrder
>
ProdLaunchOrders
=
_prodLaunchOrderService
.
lambdaQuery
()
.
eq
(
ProdLaunchOrder:
:
getSceneId
,
SceneId
)
.
eq
(
ProdLaunchOrder:
:
getSceneId
,
SceneId
)
.
list
();
.
list
();
...
@@ -1887,6 +1888,7 @@ public class PlanResultService {
...
@@ -1887,6 +1888,7 @@ public class PlanResultService {
chromosomes
.
setBaseTime
(
param
.
getBaseTime
());
chromosomes
.
setBaseTime
(
param
.
getBaseTime
());
// chromosomes.setOperatRel(new CopyOnWriteArrayList<>(entryRel));
// chromosomes.setOperatRel(new CopyOnWriteArrayList<>(entryRel));
// 保存chromosomes到文件
// 保存chromosomes到文件
saveGlobalParamSnapshot
(
chromosomes
,
globalParam
);
boolean
saved
=
_sceneService
.
saveChromosomeToFile
(
chromosomes
,
SceneId
);
boolean
saved
=
_sceneService
.
saveChromosomeToFile
(
chromosomes
,
SceneId
);
if
(!
saved
)
{
if
(!
saved
)
{
throw
new
BusinessException
(
"排产计算结果保存失败,请稍后重试或联系管理员"
);
throw
new
BusinessException
(
"排产计算结果保存失败,请稍后重试或联系管理员"
);
...
@@ -1916,7 +1918,6 @@ public class PlanResultService {
...
@@ -1916,7 +1918,6 @@ public class PlanResultService {
FileHelper
.
writeLogFile
(
String
.
format
(
"Setup Time: %f minutes"
,
schedule
.
getTotalChangeoverTime
()));
FileHelper
.
writeLogFile
(
String
.
format
(
"Setup Time: %f minutes"
,
schedule
.
getTotalChangeoverTime
()));
FileHelper
.
writeLogFile
(
String
.
format
(
"Flow Time: %f minutes"
,
schedule
.
getTotalFlowTime
()));
FileHelper
.
writeLogFile
(
String
.
format
(
"Flow Time: %f minutes"
,
schedule
.
getTotalFlowTime
()));
FileHelper
.
writeLogFile
(
String
.
format
(
"Machine Load Balance: %.2f%%"
,
schedule
.
getMachineLoadStd
()
*
100
));
FileHelper
.
writeLogFile
(
String
.
format
(
"Machine Load Balance: %.2f%%"
,
schedule
.
getMachineLoadStd
()
*
100
));
FileHelper
.
writeLogFile
(
String
.
format
(
"Semi JIT Slack: %f minutes"
,
schedule
.
getSemiJitSlack
()));
FileHelper
.
writeLogFile
(
"-------------------------"
);
FileHelper
.
writeLogFile
(
"-------------------------"
);
// 按订单分组写入
// 按订单分组写入
...
@@ -2172,6 +2173,47 @@ if(job.getGeneDetails()!=null)
...
@@ -2172,6 +2173,47 @@ if(job.getGeneDetails()!=null)
FileHelper
.
writeLogFile
(
"初始化约束-----------结束-------"
);
FileHelper
.
writeLogFile
(
"初始化约束-----------结束-------"
);
return
globalParam
;
return
globalParam
;
}
}
private
GlobalParam
buildInitialGlobalParam
(
String
sceneId
,
Long
userId
,
Long
baseRuleId
,
String
userRuleId
)
{
// 先拿到基础约束参数,再叠加保存的 KPI 配置,形成本次排产实际使用的 GlobalParam。
GlobalParam
globalParam
=
InitGlobalParam
();
Object
kpiConfig
=
scheduleStrategyService
.
loadEffectiveKpiConfig
(
userId
,
baseRuleId
,
sceneId
,
userRuleId
);
globalParam
.
applyKpiConfig
(
kpiConfig
);
return
globalParam
;
}
private
GlobalParam
buildGlobalParamFromSnapshot
(
Chromosome
chromosome
)
{
return
buildGlobalParamFromSnapshot
(
null
,
chromosome
);
}
private
GlobalParam
buildGlobalParamFromSnapshot
(
String
sceneId
,
Chromosome
chromosome
)
{
// 局部排产优先复用染色体里保存的参数快照,避免重新读取数据库或回退到默认值。
if
(
chromosome
!=
null
&&
chromosome
.
getGlobalParamSnapshot
()
!=
null
)
{
return
chromosome
.
getGlobalParamSnapshot
().
copy
();
}
// 没有快照时才创建默认参数,并把它补回快照,保证后续局部操作还能复用。
GlobalParam
globalParam
=
new
GlobalParam
();
if
(
chromosome
!=
null
)
{
chromosome
.
setGlobalParamSnapshot
(
globalParam
.
copy
());
}
return
globalParam
;
}
private
GlobalParam
buildGlobalParamFromSnapshot
(
Chromosome
chromosome
,
boolean
initConstraintFallback
)
{
return
buildGlobalParamFromSnapshot
(
null
,
chromosome
);
}
private
GlobalParam
buildGlobalParamFromSnapshot
(
String
sceneId
,
Chromosome
chromosome
,
boolean
initConstraintFallback
)
{
return
buildGlobalParamFromSnapshot
(
sceneId
,
chromosome
);
}
private
void
saveGlobalParamSnapshot
(
Chromosome
chromosome
,
GlobalParam
globalParam
)
{
if
(
chromosome
!=
null
&&
globalParam
!=
null
)
{
chromosome
.
setGlobalParamSnapshot
(
globalParam
.
copy
());
}
}
private
List
<
Order
>
InitOrder
(
List
<
ProdLaunchOrder
>
ProdLaunchOrders
)
private
List
<
Order
>
InitOrder
(
List
<
ProdLaunchOrder
>
ProdLaunchOrders
)
{
{
return
InitOrder
(
ProdLaunchOrders
,
Collections
.
emptyList
());
return
InitOrder
(
ProdLaunchOrders
,
Collections
.
emptyList
());
...
@@ -3201,7 +3243,10 @@ if(job.getGeneDetails()!=null)
...
@@ -3201,7 +3243,10 @@ if(job.getGeneDetails()!=null)
public
List
<
Machine
>
InitCalendarToAllMachines2
(
String
SceneId
)
{
public
List
<
Machine
>
InitCalendarToAllMachines2
(
String
SceneId
)
{
GlobalParam
globalParam
=
InitGlobalParam
();
Chromosome
chromosome
=
_sceneService
.
loadChromosomeFromFile
(
SceneId
);
GlobalParam
globalParam
=
(
chromosome
!=
null
&&
chromosome
.
getGlobalParamSnapshot
()
!=
null
)
?
chromosome
.
getGlobalParamSnapshot
().
copy
()
:
InitGlobalParam
();
boolean
IsUseCalendar
=
globalParam
.
isIsUseCalendar
();
boolean
IsUseCalendar
=
globalParam
.
isIsUseCalendar
();
// 按设备分组
// 按设备分组
...
...
src/main/java/com/aps/service/plan/ScheduleStrategyService.java
View file @
7e5a24bf
...
@@ -14,9 +14,11 @@ import org.springframework.stereotype.Service;
...
@@ -14,9 +14,11 @@ import org.springframework.stereotype.Service;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.Comparator
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Locale
;
import
java.util.Locale
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
import
java.util.stream.Collectors
;
...
@@ -65,6 +67,29 @@ public class ScheduleStrategyService {
...
@@ -65,6 +67,29 @@ public class ScheduleStrategyService {
}
}
}
}
public
Object
loadEffectiveKpiConfig
(
Long
userId
,
Long
baseRuleId
,
String
sceneId
,
String
userRuleId
)
{
try
{
Map
<
String
,
Object
>
params
=
new
HashMap
<>();
Long
effectiveUserId
=
resolveScheduleUserId
(
sceneId
,
userId
);
if
(
effectiveUserId
!=
null
)
{
params
.
put
(
"userId"
,
effectiveUserId
);
}
if
(
baseRuleId
!=
null
)
{
params
.
put
(
"baseRuleId"
,
baseRuleId
);
}
if
(
userRuleId
!=
null
&&
!
userRuleId
.
trim
().
isEmpty
())
{
params
.
put
(
"userRuleId"
,
userRuleId
);
}
Map
<
String
,
Object
>
effectiveRule
=
userStrategyRuleService
.
getEffectiveRule
(
params
);
return
effectiveRule
==
null
?
null
:
effectiveRule
.
get
(
"kpiConfig"
);
}
catch
(
Exception
e
)
{
log
.
warn
(
"Load KPI strategy failed, use GlobalParam default KPI. sceneId={}, userId={}, baseRuleId={}, userRuleId={}"
,
sceneId
,
userId
,
baseRuleId
,
userRuleId
,
e
);
return
null
;
}
}
public
OrderSortRule
createMultiConditionRule
(
List
<
Order
>
orders
)
{
public
OrderSortRule
createMultiConditionRule
(
List
<
Order
>
orders
)
{
return
createMultiConditionRule
(
orders
,
Collections
.
emptyList
());
return
createMultiConditionRule
(
orders
,
Collections
.
emptyList
());
}
}
...
...
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