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
baed89e8
Commit
baed89e8
authored
Sep 22, 2026
by
Tong Li
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MP-将kpi设置接入,优化器
parent
da795079
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
85 additions
and
38 deletions
+85
-38
MacroPlannerResultController.java
...java/com/aps/controller/MacroPlannerResultController.java
+3
-2
MacroPlannerDataConverter.java
.../com/aps/macroplanner/data/MacroPlannerDataConverter.java
+82
-36
No files found.
src/main/java/com/aps/controller/MacroPlannerResultController.java
View file @
baed89e8
...
@@ -532,7 +532,8 @@ public class MacroPlannerResultController {
...
@@ -532,7 +532,8 @@ public class MacroPlannerResultController {
description
=
"执行数据库转换→数据验证→MIP建模→分层求解→JSON结果保存的完整流程。"
description
=
"执行数据库转换→数据验证→MIP建模→分层求解→JSON结果保存的完整流程。"
+
"耗时通常数秒到数分钟, 取决于数据规模。"
)
+
"耗时通常数秒到数分钟, 取决于数据规模。"
)
public
R
<
Map
<
String
,
Object
>>
runOptimization
(
public
R
<
Map
<
String
,
Object
>>
runOptimization
(
@RequestParam
(
"sceneId"
)
@Parameter
(
description
=
"场景ID"
,
required
=
true
)
String
sceneId
)
{
@RequestParam
(
"sceneId"
)
@Parameter
(
description
=
"场景ID"
,
required
=
true
)
String
sceneId
,
@RequestParam
(
"sceneId"
)
@Parameter
(
description
=
"场景ID"
,
required
=
true
)
Integer
sceneI
)
{
if
(
sceneId
==
null
||
sceneId
.
trim
().
isEmpty
())
{
if
(
sceneId
==
null
||
sceneId
.
trim
().
isEmpty
())
{
return
R
.
failed
(
"sceneId不能为空"
);
return
R
.
failed
(
"sceneId不能为空"
);
}
}
...
@@ -543,7 +544,7 @@ public class MacroPlannerResultController {
...
@@ -543,7 +544,7 @@ public class MacroPlannerResultController {
try
{
try
{
// 1. 数据转换: 数据库工艺物料类 → macroplanner 实体
// 1. 数据转换: 数据库工艺物料类 → macroplanner 实体
TestDataBuilder
data
=
macroPlannerDataConverter
.
convert
(
sid
);
TestDataBuilder
data
=
macroPlannerDataConverter
.
convert
(
sid
,
sceneI
);
result
.
put
(
"dataSummary"
,
buildDataSummary
(
data
));
result
.
put
(
"dataSummary"
,
buildDataSummary
(
data
));
// 2. 数据验证
// 2. 数据验证
...
...
src/main/java/com/aps/macroplanner/data/MacroPlannerDataConverter.java
View file @
baed89e8
...
@@ -2,10 +2,13 @@ package com.aps.macroplanner.data;
...
@@ -2,10 +2,13 @@ package com.aps.macroplanner.data;
import
com.aps.common.util.ParamValidator
;
import
com.aps.common.util.ParamValidator
;
import
com.aps.entity.*
;
import
com.aps.entity.*
;
import
com.aps.macroplanner.objective.KpiSetting
;
import
com.aps.macroplanner.scene.MacroSceneContext
;
import
com.aps.macroplanner.scene.MacroSceneContext
;
import
com.aps.entity.basic.Material
;
import
com.aps.entity.basic.Material
;
import
com.aps.entity.basic.MaterialSupply
;
import
com.aps.entity.basic.MaterialSupply
;
import
com.aps.mapper.EquipShiftCapacityMapper
;
import
com.aps.mapper.EquipShiftCapacityMapper
;
import
com.aps.service.KpiCategoryItemService
;
import
com.aps.service.PlanPeriodService
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.fasterxml.jackson.core.type.TypeReference
;
import
com.fasterxml.jackson.core.type.TypeReference
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
...
@@ -127,8 +130,12 @@ public class MacroPlannerDataConverter {
...
@@ -127,8 +130,12 @@ public class MacroPlannerDataConverter {
// ==================== 注入的 Service ====================
// ==================== 注入的 Service ====================
@Autowired
@Autowired
private
LanuchService
lanuchService
;
private
LanuchService
lanuchService
;
@Autowired
private
PlanPeriodService
planPeriodService
;
@Autowired
@Autowired
private
ApsTimeConfigService
apsTimeConfig
Service
;
private
KpiCategoryItemService
kpiCategoryItem
Service
;
// ==================== 公开入口 ====================
// ==================== 公开入口 ====================
...
@@ -138,16 +145,16 @@ public class MacroPlannerDataConverter {
...
@@ -138,16 +145,16 @@ public class MacroPlannerDataConverter {
* @param sceneId 场景ID
* @param sceneId 场景ID
* @return 填充好的 TestDataBuilder, 可直接传给 MacroPlannerOptimizer
* @return 填充好的 TestDataBuilder, 可直接传给 MacroPlannerOptimizer
*/
*/
public
TestDataBuilder
convert
(
String
sceneId
)
{
public
TestDataBuilder
convert
(
String
sceneId
,
Integer
kpiSetting
)
{
return
MacroSceneContext
.
execute
(
sceneId
,
()
->
convertScoped
(
sceneId
));
return
MacroSceneContext
.
execute
(
sceneId
,
()
->
convertScoped
(
sceneId
,
kpiSetting
));
}
}
private
TestDataBuilder
convertScoped
(
String
sceneId
)
{
private
TestDataBuilder
convertScoped
(
String
sceneId
,
Integer
kpiSetting
)
{
log
.
info
(
"开始转换场景数据到 macroplanner: sceneId={}"
,
sceneId
);
log
.
info
(
"开始转换场景数据到 macroplanner: sceneId={}"
,
sceneId
);
ConvertContext
ctx
=
loadRawData
(
sceneId
);
ConvertContext
ctx
=
loadRawData
(
sceneId
,
kpiSetting
);
buildMaterials
(
ctx
);
buildMaterials
(
ctx
);
buildDailyCapacityByUnitId
(
ctx
);
buildDailyCapacityByUnitId
(
ctx
);
...
@@ -219,28 +226,28 @@ public class MacroPlannerDataConverter {
...
@@ -219,28 +226,28 @@ public class MacroPlannerDataConverter {
return
new
ArrayList
<>(
headers
.
keySet
());
return
new
ArrayList
<>(
headers
.
keySet
());
}
}
private
ConvertContext
loadRawData
(
String
sceneId
)
{
private
ConvertContext
loadRawData
(
String
sceneId
,
Integer
kpiSetting
)
{
ConvertContext
ctx
=
new
ConvertContext
();
ConvertContext
ctx
=
new
ConvertContext
();
// 0. 读取时间配置, 计算 horizonEnd
// 0. 读取时间配置, 计算 horizonEnd
// endCount = 期数 (与 periodDimension 结合决定实际天数)
// endCount = 期数 (与 periodDimension 结合决定实际天数)
LambdaQueryWrapper
<
ApsTimeConfig
>
wrapper
=
new
LambdaQueryWrapper
<
ApsTimeConfig
>();
LambdaQueryWrapper
<
PlanPeriod
>
wrapper
=
new
LambdaQueryWrapper
<
PlanPeriod
>();
if
(
sceneId
!=
null
&&
!
sceneId
.
isEmpty
())
wrapper
.
eq
(
PlanPeriod:
:
getIsplan
,
1
);
{
wrapper
.
eq
(
PlanPeriod:
:
getIsdeleted
,
0
);
// wrapper.eq(ApsTimeConfig::getMpSceneId,sceneId);
wrapper
.
eq
(
PlanPeriod:
:
getMpSceneId
,
sceneId
);
}
PlanPeriod
timeConfig
=
planPeriodService
.
getOne
(
wrapper
);
ApsTimeConfig
timeConfig
=
apsTimeConfigService
.
getOne
(
wrapper
);
ctx
.
baseTime
=
LocalDateTime
.
of
(
2026
,
9
,
28
,
0
,
0
,
0
);
ctx
.
periodDimension
=
"WEEK"
;
ctx
.
periodDimension
=
"WEEK"
;
if
(
timeConfig
!=
null
&&
timeConfig
.
getPeriodDimension
()
!=
null
if
(
timeConfig
!=
null
&&
timeConfig
.
getTimeunit
()
!=
null
&&
!
timeConfig
.
getPeriodDimension
().
trim
().
isEmpty
())
{
&&
!
timeConfig
.
getTimeunit
().
trim
().
isEmpty
())
{
ctx
.
periodDimension
=
timeConfig
.
getPeriodDimension
().
trim
().
toUpperCase
();
ctx
.
baseTime
=
timeConfig
.
getBasetime
();
ctx
.
periodDimension
=
toPeriodType
(
timeConfig
.
getTimeunitid
().
toString
())
;
}
}
int
periodCount
=
DEFAULT_PERIOD_COUNT
;
int
periodCount
=
DEFAULT_PERIOD_COUNT
;
if
(
timeConfig
!=
null
&&
timeConfig
.
get
EndCount
()
!=
null
)
{
if
(
timeConfig
!=
null
&&
timeConfig
.
get
Future
()
!=
null
)
{
int
ec
=
timeConfig
.
get
EndCount
().
intValue
();
int
ec
=
timeConfig
.
get
Future
().
intValue
();
if
(
ec
>
0
)
{
if
(
ec
>
0
)
{
periodCount
=
ec
;
periodCount
=
ec
;
}
}
...
@@ -251,6 +258,7 @@ public class MacroPlannerDataConverter {
...
@@ -251,6 +258,7 @@ public class MacroPlannerDataConverter {
ctx
.
horizonEnd
=
calculateHorizonEnd
(
ctx
.
periodDimension
,
baseDate
,
periodCount
);
ctx
.
horizonEnd
=
calculateHorizonEnd
(
ctx
.
periodDimension
,
baseDate
,
periodCount
);
LocalDateTime
horizonEndDateTime
=
ctx
.
horizonEnd
.
atStartOfDay
();
LocalDateTime
horizonEndDateTime
=
ctx
.
horizonEnd
.
atStartOfDay
();
log
.
info
(
"排产周期: dimension={}, periodCount={}, baseTime={}, horizonEnd={}"
,
log
.
info
(
"排产周期: dimension={}, periodCount={}, baseTime={}, horizonEnd={}"
,
ctx
.
periodDimension
,
periodCount
,
ctx
.
baseTime
,
ctx
.
horizonEnd
);
log
.
info
(
"排产周期: dimension={}, periodCount={}, baseTime={}, horizonEnd={}"
,
ctx
.
periodDimension
,
periodCount
,
ctx
.
baseTime
,
ctx
.
horizonEnd
);
ctx
.
periodDimension
,
periodCount
,
ctx
.
baseTime
,
ctx
.
horizonEnd
);
// 1. 需求订单 (ApsDemandOrder, 按 deliverytime 时间范围过滤)
// 1. 需求订单 (ApsDemandOrder, 按 deliverytime 时间范围过滤)
...
@@ -402,7 +410,10 @@ public class MacroPlannerDataConverter {
...
@@ -402,7 +410,10 @@ public class MacroPlannerDataConverter {
.
eq
(
EquipShiftCapacity:
:
getIsDeleted
,
0
));
.
eq
(
EquipShiftCapacity:
:
getIsDeleted
,
0
));
}
}
log
.
info
(
"加载设备产能日历(EquipShiftCapacity): {} 条 (时间范围过滤)"
,
ctx
.
equipShiftCapacities
.
size
());
log
.
info
(
"加载设备产能日历(EquipShiftCapacity): {} 条 (时间范围过滤)"
,
ctx
.
equipShiftCapacities
.
size
());
ctx
.
kpiCategoryItems
=
kpiCategoryItemService
.
list
(
new
LambdaQueryWrapper
<
KpiCategoryItem
>()
.
eq
(
KpiCategoryItem:
:
getIsDeleted
,
0
)
.
eq
(
KpiCategoryItem:
:
getCategoryId
,
kpiSetting
));
return
ctx
;
return
ctx
;
}
}
...
@@ -661,12 +672,36 @@ public class MacroPlannerDataConverter {
...
@@ -661,12 +672,36 @@ public class MacroPlannerDataConverter {
// 自然月: 从 baseDate 所在月的1号开始, periodCount 个月后
// 自然月: 从 baseDate 所在月的1号开始, periodCount 个月后
LocalDate
monthStart
=
baseDate
.
withDayOfMonth
(
1
);
LocalDate
monthStart
=
baseDate
.
withDayOfMonth
(
1
);
return
monthStart
.
plusMonths
(
periodCount
);
return
monthStart
.
plusMonths
(
periodCount
);
case
"YEAR"
:
// 自然年: 从 baseDate 所在月的1号开始, periodCount 个月后
LocalDate
yearStart
=
baseDate
.
withDayOfYear
(
1
);
return
yearStart
.
plusYears
(
periodCount
);
case
"QUARTER"
:
// 自然季度: 从 baseDate 所在季度的首月1号开始, periodCount 个季度后
int
month
=
baseDate
.
getMonthValue
();
// 计算当前属于第几季度(1~4),整数除法自动取整
int
quarter
=
(
month
-
1
)
/
3
+
1
;
// 计算该季度的首月月份
int
quarterStartMonth
=
(
quarter
-
1
)
*
3
+
1
;
// 构造季度起始日期(首月1号)
LocalDate
quarterStart
=
baseDate
.
withMonth
(
quarterStartMonth
).
withDayOfMonth
(
1
);
// 加上 periodCount 个季度(每个季度3个月)
return
quarterStart
.
plusMonths
((
long
)
periodCount
*
3
);
case
"DAY"
:
case
"DAY"
:
default
:
default
:
return
baseDate
.
plusDays
(
periodCount
);
return
baseDate
.
plusDays
(
periodCount
);
}
}
}
}
public
static
String
toPeriodType
(
String
code
)
{
switch
(
code
)
{
case
"2"
:
return
"WEEK"
;
case
"3"
:
return
"MONTH"
;
case
"4"
:
return
"QUARTER"
;
case
"5"
:
return
"YEAR"
;
case
"1"
:
default
:
return
"DAY"
;
}
}
/**
/**
* 计算给定日期范围内的有效工作日数 (不含周日)。
* 计算给定日期范围内的有效工作日数 (不含周日)。
*/
*/
...
@@ -702,7 +737,7 @@ public class MacroPlannerDataConverter {
...
@@ -702,7 +737,7 @@ public class MacroPlannerDataConverter {
fillPeriodsAndUnitPeriods
(
ctx
);
fillPeriodsAndUnitPeriods
(
ctx
);
fillSalesDemands
(
ctx
);
fillSalesDemands
(
ctx
);
fillInventorySpecsAndSupplySpecs
(
ctx
);
fillInventorySpecsAndSupplySpecs
(
ctx
);
fillKpiWeights
();
fillKpiWeights
(
ctx
);
}
}
// ---------- 步骤3: Product + StockingPoint ----------
// ---------- 步骤3: Product + StockingPoint ----------
...
@@ -1415,23 +1450,32 @@ public class MacroPlannerDataConverter {
...
@@ -1415,23 +1450,32 @@ public class MacroPlannerDataConverter {
}
}
// ---------- 步骤10: KPIWeights (默认值, 复用 RoutingTestDataBuilder) ----------
// ---------- 步骤10: KPIWeights (默认值, 复用 RoutingTestDataBuilder) ----------
private
void
fillKpiWeights
(
ConvertContext
ctx
)
{
private
void
fillKpiWeights
()
{
List
<
KpiSetting
>
kpis
=
new
ArrayList
<>();
kpiWeights
=
new
KPIWeights
(
for
(
KpiCategoryItem
item:
ctx
.
kpiCategoryItems
)
{
100.0
,
// fulfillmentWeight
KpiSetting
kpi
=
new
KpiSetting
(
item
.
getKpiName
(),
item
.
getKpiCode
(),
item
.
getWeight
().
doubleValue
(),
item
.
getSort
().
intValue
());
10.0
,
// lotSizeWeight
kpis
.
add
(
kpi
);
5.0
,
// maxInventoryLevelWeight
}
5.0
,
// minInventoryLevelWeight
8.0
,
// targetInventoryLevelWeight
kpiSettings
=
kpis
;
3.0
,
// unitCapacityWeight
8.0
,
// supplyTargetWeight
5.0
,
// minSupplyWeight
5.0
,
// maxSupplyWeight
1.0
,
// salesDemandPriorityWeight
20.0
,
// postponementPenaltyWeight
5.0
// processMaxQuantityWeight
);
}
}
// private void fillKpiWeights() {
// kpiWeights = new KPIWeights(
// 100.0, // fulfillmentWeight
// 10.0, // lotSizeWeight
// 5.0, // maxInventoryLevelWeight
// 5.0, // minInventoryLevelWeight
// 8.0, // targetInventoryLevelWeight
// 3.0, // unitCapacityWeight
// 8.0, // supplyTargetWeight
// 5.0, // minSupplyWeight
// 5.0, // maxSupplyWeight
// 1.0, // salesDemandPriorityWeight
// 20.0, // postponementPenaltyWeight
// 5.0 // processMaxQuantityWeight
// );
// }
// ---------- 工具方法 ----------
// ---------- 工具方法 ----------
...
@@ -1495,5 +1539,7 @@ public class MacroPlannerDataConverter {
...
@@ -1495,5 +1539,7 @@ public class MacroPlannerDataConverter {
Set
<
String
>
unlimitedUnitIds
=
new
HashSet
<>();
Set
<
String
>
unlimitedUnitIds
=
new
HashSet
<>();
/** 排产周期数, 从 ApsTimeConfig 计算, 维度为 DAY 时是天数, WEEK 时是周数, MONTH 时是月数 */
/** 排产周期数, 从 ApsTimeConfig 计算, 维度为 DAY 时是天数, WEEK 时是周数, MONTH 时是月数 */
int
periodCount
=
7
;
int
periodCount
=
7
;
List
<
KpiCategoryItem
>
kpiCategoryItems
=
new
ArrayList
<>();
}
}
}
}
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