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
2275c355
Commit
2275c355
authored
Aug 13, 2026
by
Tong Li
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MP
parent
a1a0557e
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
128 additions
and
94 deletions
+128
-94
MacroPlannerDataConverter.java
.../com/aps/macroplanner/data/MacroPlannerDataConverter.java
+128
-94
No files found.
src/main/java/com/aps/macroplanner/data/MacroPlannerDataConverter.java
View file @
2275c355
...
...
@@ -12,7 +12,7 @@ import com.aps.mapper.ErpPurchaseOrderMapper;
import
com.aps.mapper.MaterialInfoMapper
;
import
com.aps.mapper.MaterialPurchaseMapper
;
import
com.aps.mapper.PlanResourceMapper
;
import
com.aps.mapper.
ProdLaunch
OrderMapper
;
import
com.aps.mapper.
ApsDemand
OrderMapper
;
import
com.aps.mapper.PurchaseReceiptMapper
;
import
com.aps.mapper.RoutingDetailEquipMapper
;
import
com.aps.mapper.RoutingHeaderMapper
;
...
...
@@ -30,6 +30,7 @@ import java.math.BigDecimal;
import
java.time.Duration
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.time.temporal.ChronoUnit
;
import
java.util.*
;
import
java.util.stream.Collectors
;
...
...
@@ -62,7 +63,7 @@ import java.util.stream.Collectors;
* OperationInput ← Routingsupporting (仅 MP 原材料投料)
* InitialInventory ← Material.materialStocks (Stock)
* InTransitSupply ← Material.InTransit (MaterialSupply)
* SalesDemand ←
ProdLaunch
Order
* SalesDemand ←
ApsDemand
Order
* </pre>
*/
@Service
...
...
@@ -78,7 +79,7 @@ public class MacroPlannerDataConverter {
// ==================== 注入的 Mapper ====================
@Autowired
private
ProdLaunchOrderMapper
prodLaunch
OrderMapper
;
private
ApsDemandOrderMapper
apsDemand
OrderMapper
;
@Autowired
private
RoutingHeaderMapper
routingHeaderMapper
;
@Autowired
...
...
@@ -143,15 +144,43 @@ public class MacroPlannerDataConverter {
private
ConvertContext
loadRawData
(
String
sceneId
)
{
ConvertContext
ctx
=
new
ConvertContext
();
//
1. 订单 (按 sceneId 过滤)
ctx
.
prodLaunchOrders
=
prodLaunchOrderMapper
.
selectList
(
new
LambdaQueryWrapper
<
ProdLaunchOrder
>()
.
eq
(
ProdLaunchOrder:
:
getSceneId
,
sceneId
));
log
.
info
(
"加载订单: {} 条"
,
ctx
.
prodLaunchOrders
.
size
()
);
//
0. 读取时间配置, 计算 horizonEnd
// endCount = 期数 (与 periodDimension 结合决定实际天数)
ApsTimeConfig
timeConfig
=
apsTimeConfigService
.
getOne
(
new
LambdaQueryWrapper
<>());
ctx
.
baseTime
=
(
timeConfig
!=
null
&&
timeConfig
.
getBaseTime
()
!=
null
)
?
timeConfig
.
getBaseTime
()
:
LocalDateTime
.
now
(
);
// 2. 收集 materialIds
Set
<
String
>
materialIds
=
ctx
.
prodLaunchOrders
.
stream
()
.
map
(
ProdLaunchOrder:
:
getMaterialId
)
ctx
.
periodDimension
=
"DAY"
;
if
(
timeConfig
!=
null
&&
timeConfig
.
getPeriodDimension
()
!=
null
&&
!
timeConfig
.
getPeriodDimension
().
trim
().
isEmpty
())
{
ctx
.
periodDimension
=
timeConfig
.
getPeriodDimension
().
trim
().
toUpperCase
();
}
int
periodCount
=
DEFAULT_PERIOD_COUNT
;
if
(
timeConfig
!=
null
&&
timeConfig
.
getEndCount
()
!=
null
)
{
int
ec
=
timeConfig
.
getEndCount
().
intValue
();
if
(
ec
>
0
)
{
periodCount
=
ec
;
}
}
ctx
.
periodCount
=
periodCount
;
LocalDate
baseDate
=
ctx
.
baseTime
.
toLocalDate
();
ctx
.
horizonEnd
=
baseDate
.
plusDays
(
calculateTotalDays
(
ctx
.
periodDimension
,
baseDate
,
periodCount
));
LocalDateTime
horizonEndDateTime
=
ctx
.
horizonEnd
.
atStartOfDay
();
log
.
info
(
"排产周期: dimension={}, periodCount={}, baseTime={}, horizonEnd={}"
,
ctx
.
periodDimension
,
periodCount
,
ctx
.
baseTime
,
ctx
.
horizonEnd
);
// 1. 需求订单 (ApsDemandOrder, 按 deliverytime 时间范围过滤)
ctx
.
apsDemandOrders
=
apsDemandOrderMapper
.
selectList
(
new
LambdaQueryWrapper
<
ApsDemandOrder
>()
.
ge
(
ApsDemandOrder:
:
getDeliverytime
,
ctx
.
baseTime
)
.
lt
(
ApsDemandOrder:
:
getDeliverytime
,
horizonEndDateTime
));
log
.
info
(
"加载需求订单: {} 条 (时间范围过滤)"
,
ctx
.
apsDemandOrders
.
size
());
// 2. 收集 materialIds (从 ApsDemandOrder.mmid)
Set
<
String
>
materialIds
=
ctx
.
apsDemandOrders
.
stream
()
.
map
(
ApsDemandOrder:
:
getMmid
)
.
filter
(
Objects:
:
nonNull
)
.
distinct
()
.
collect
(
Collectors
.
toSet
());
...
...
@@ -274,7 +303,7 @@ public class MacroPlannerDataConverter {
}
log
.
info
(
"加载设备资源: {}, 设备信息: {}"
,
ctx
.
planResources
.
size
(),
ctx
.
equipinfos
.
size
());
// 11. 设备产能日历: EquipShiftCapacity (
每天一条, validTimePeriods=有效时间段JSON
)
// 11. 设备产能日历: EquipShiftCapacity (
按时间范围过滤
)
Set
<
Long
>
planResourceIds
=
ctx
.
planResources
.
stream
()
.
map
(
PlanResource:
:
getId
)
.
filter
(
Objects:
:
nonNull
)
...
...
@@ -284,14 +313,11 @@ public class MacroPlannerDataConverter {
ctx
.
equipShiftCapacities
=
equipShiftCapacityMapper
.
selectList
(
new
LambdaQueryWrapper
<
EquipShiftCapacity
>()
.
in
(
EquipShiftCapacity:
:
getPlanResourceId
,
planResourceIds
)
.
ge
(
EquipShiftCapacity:
:
getCapacityDate
,
ctx
.
baseTime
)
.
lt
(
EquipShiftCapacity:
:
getCapacityDate
,
horizonEndDateTime
)
.
eq
(
EquipShiftCapacity:
:
getIsDeleted
,
0
));
}
log
.
info
(
"加载设备产能日历(EquipShiftCapacity): {} 条"
,
ctx
.
equipShiftCapacities
.
size
());
// 12. baseTime
ApsTimeConfig
timeConfig
=
apsTimeConfigService
.
getOne
(
new
LambdaQueryWrapper
<>());
ctx
.
baseTime
=
(
timeConfig
!=
null
&&
timeConfig
.
getBaseTime
()
!=
null
)
?
timeConfig
.
getBaseTime
()
:
LocalDateTime
.
now
();
log
.
info
(
"加载设备产能日历(EquipShiftCapacity): {} 条 (时间范围过滤)"
,
ctx
.
equipShiftCapacities
.
size
());
return
ctx
;
}
...
...
@@ -455,31 +481,8 @@ public class MacroPlannerDataConverter {
* </p>
*/
private
void
buildDailyCapacityByUnitId
(
ConvertContext
ctx
)
{
// 读取时间配置, 获取维度 + 计划周期
ApsTimeConfig
timeConfig
=
apsTimeConfigService
.
getOne
(
new
LambdaQueryWrapper
<>());
LocalDate
baseDate
=
ctx
.
baseTime
.
toLocalDate
();
// 维度: 默认 DAY
ctx
.
periodDimension
=
"DAY"
;
if
(
timeConfig
!=
null
&&
timeConfig
.
getPeriodDimension
()
!=
null
&&
!
timeConfig
.
getPeriodDimension
().
trim
().
isEmpty
())
{
ctx
.
periodDimension
=
timeConfig
.
getPeriodDimension
().
trim
().
toUpperCase
();
}
// 时间范围: horizonSeconds = endCount - startCount (秒)
long
horizonSeconds
=
86400
*
DEFAULT_PERIOD_COUNT
;
if
(
timeConfig
!=
null
&&
timeConfig
.
getStartCount
()
!=
null
&&
timeConfig
.
getEndCount
()
!=
null
)
{
long
diff
=
timeConfig
.
getEndCount
().
longValue
()
-
timeConfig
.
getStartCount
().
longValue
();
if
(
diff
>
0
)
{
horizonSeconds
=
diff
;
}
}
int
totalDays
=
(
int
)
Math
.
max
(
1
,
horizonSeconds
/
86400
);
LocalDate
horizonEnd
=
baseDate
.
plusDays
(
totalDays
);
// 按维度计算 periodCount
ctx
.
periodCount
=
calculatePeriodCount
(
ctx
.
periodDimension
,
baseDate
,
horizonEnd
);
log
.
info
(
"排产周期: dimension={}, periodCount={}, 总天数={}"
,
ctx
.
periodDimension
,
ctx
.
periodCount
,
totalDays
);
log
.
info
(
"排产周期: dimension={}, periodCount={}, horizonEnd={}"
,
ctx
.
periodDimension
,
ctx
.
periodCount
,
ctx
.
horizonEnd
);
// planResourceId → PlanResource.id
Map
<
Long
,
PlanResource
>
prById
=
ctx
.
planResources
.
stream
()
...
...
@@ -557,32 +560,23 @@ public class MacroPlannerDataConverter {
}
/**
* 按维度
计算周期
数。
* 按维度
将期数转换为实际天
数。
*
* @param dimension 维度: DAY / WEEK / MONTH
* @param baseDate 起始日期
* @param
horizonEnd 计划截止日期 (不包含
)
* @return
周期
数
* @param dimension
维度: DAY / WEEK / MONTH
* @param baseDate
起始日期
* @param
periodCount 期数 (endCount
)
* @return
实际天
数
*/
private
static
int
calculate
PeriodCount
(
String
dimension
,
LocalDate
baseDate
,
LocalDate
horizonEnd
)
{
private
static
int
calculate
TotalDays
(
String
dimension
,
LocalDate
baseDate
,
int
periodCount
)
{
switch
(
dimension
)
{
case
"WEEK"
:
// 按周: 从 baseDate 开始, 每7天一周, 不足7天也算一周
long
totalDays
=
java
.
time
.
temporal
.
ChronoUnit
.
DAYS
.
between
(
baseDate
,
horizonEnd
);
return
(
int
)
Math
.
max
(
1
,
Math
.
ceil
(
totalDays
/
7.0
));
return
periodCount
*
7
;
case
"MONTH"
:
// 按月: 从 baseDate 所在月开始, 跨越的自然月数
int
months
=
0
;
LocalDate
cursor
=
baseDate
.
withDayOfMonth
(
1
);
while
(
cursor
.
isBefore
(
horizonEnd
))
{
cursor
=
cursor
.
plusMonths
(
1
);
months
++;
}
return
Math
.
max
(
1
,
months
);
LocalDate
end
=
baseDate
.
plusMonths
(
periodCount
);
return
(
int
)
ChronoUnit
.
DAYS
.
between
(
baseDate
,
end
);
case
"DAY"
:
default
:
long
days
=
java
.
time
.
temporal
.
ChronoUnit
.
DAYS
.
between
(
baseDate
,
horizonEnd
);
return
(
int
)
Math
.
max
(
1
,
days
);
return
periodCount
;
}
}
...
...
@@ -991,18 +985,7 @@ public class MacroPlannerDataConverter {
LocalDate
baseDate
=
ctx
.
baseTime
.
toLocalDate
();
int
periodCount
=
ctx
.
periodCount
;
String
dimension
=
ctx
.
periodDimension
;
// 计算 horizonEnd (与 buildDailyCapacityByUnitId 中一致)
ApsTimeConfig
timeConfig
=
apsTimeConfigService
.
getOne
(
new
LambdaQueryWrapper
<>());
long
horizonSeconds
=
86400
*
DEFAULT_PERIOD_COUNT
;
if
(
timeConfig
!=
null
&&
timeConfig
.
getStartCount
()
!=
null
&&
timeConfig
.
getEndCount
()
!=
null
)
{
long
diff
=
timeConfig
.
getEndCount
().
longValue
()
-
timeConfig
.
getStartCount
().
longValue
();
if
(
diff
>
0
)
{
horizonSeconds
=
diff
;
}
}
int
totalDays
=
(
int
)
Math
.
max
(
1
,
horizonSeconds
/
86400
);
LocalDate
horizonEnd
=
baseDate
.
plusDays
(
totalDays
);
LocalDate
horizonEnd
=
ctx
.
horizonEnd
;
// 按维度创建 Period
switch
(
dimension
)
{
...
...
@@ -1064,8 +1047,8 @@ public class MacroPlannerDataConverter {
unitPeriods
.
add
(
new
UnitPeriod
(
unitId
,
p
,
0.0
,
periodMaxCapacity
,
false
));
}
}
log
.
info
(
"构建 Period: {} (dimension={},
共{}天
), UnitPeriod: {}"
,
periods
.
size
(),
dimension
,
totalDays
,
unitPeriods
.
size
());
log
.
info
(
"构建 Period: {} (dimension={},
horizonEnd={}
), UnitPeriod: {}"
,
periods
.
size
(),
dimension
,
horizonEnd
,
unitPeriods
.
size
());
}
/** DAY 维度: 每天一个 Period */
...
...
@@ -1117,40 +1100,89 @@ public class MacroPlannerDataConverter {
if
(
periods
.
isEmpty
())
{
return
;
}
for
(
ProdLaunchOrder
plo
:
ctx
.
prodLaunchOrders
)
{
if
(
plo
.
getMaterialId
()
==
null
)
{
Period
lastPeriod
=
periods
.
get
(
periods
.
size
()
-
1
);
for
(
ApsDemandOrder
ado
:
ctx
.
apsDemandOrders
)
{
String
materialId
=
ado
.
getMmid
();
if
(
materialId
==
null
)
{
continue
;
}
Product
p
=
ctx
.
productByMaterialId
.
get
(
plo
.
getMaterialId
()
);
Product
p
=
ctx
.
productByMaterialId
.
get
(
materialId
);
if
(
p
==
null
)
{
continue
;
}
StockingPoint
sp
=
ctx
.
finalSpByMaterialId
.
get
(
plo
.
getMaterialId
()
);
StockingPoint
sp
=
ctx
.
finalSpByMaterialId
.
get
(
materialId
);
if
(
sp
==
null
)
{
continue
;
}
Period
targetPeriod
=
null
;
if
(
plo
.
getEndDate
()
!=
null
)
{
LocalDate
dueDate
=
plo
.
getEndDate
().
toLocalDate
();
for
(
Period
per
:
periods
)
{
if
(
per
.
contains
(
dueDate
))
{
targetPeriod
=
per
;
break
;
}
double
qty
=
ado
.
getQuantity
()
!=
null
?
ado
.
getQuantity
().
doubleValue
()
:
0
;
if
(
qty
<=
0
)
{
continue
;
}
double
priority
=
1
;
if
(
ado
.
getPrioritry
()
!=
null
)
{
try
{
priority
=
Double
.
parseDouble
(
ado
.
getPrioritry
().
trim
());
}
catch
(
NumberFormatException
e
)
{
priority
=
1
;
}
}
if
(
targetPeriod
==
null
)
{
// 找不到匹配周期, 用最后一个周期
targetPeriod
=
periods
.
get
(
periods
.
size
()
-
1
);
// 确定需求时间范围: 优先用 [begintime, endtime), 否则用 deliverytime 作为单点
LocalDate
orderStart
,
orderEnd
;
if
(
ado
.
getBegintime
()
!=
null
&&
ado
.
getEndtime
()
!=
null
)
{
orderStart
=
ado
.
getBegintime
().
toLocalDate
();
orderEnd
=
ado
.
getEndtime
().
toLocalDate
();
}
else
if
(
ado
.
getDeliverytime
()
!=
null
)
{
orderStart
=
ado
.
getDeliverytime
().
toLocalDate
();
orderEnd
=
orderStart
.
plusDays
(
1
);
}
else
{
// 无时间信息, 放入最后一个周期
salesDemands
.
add
(
new
SalesDemand
(
p
,
sp
,
lastPeriod
,
qty
,
priority
));
continue
;
}
if
(!
orderStart
.
isBefore
(
orderEnd
))
{
orderEnd
=
orderStart
.
plusDays
(
1
);
}
long
totalRangeDays
=
ChronoUnit
.
DAYS
.
between
(
orderStart
,
orderEnd
);
if
(
totalRangeDays
<=
0
)
{
totalRangeDays
=
1
;
}
double
priority
=
plo
.
getOrderPriority
()
!=
null
?
plo
.
getOrderPriority
()
:
1
;
salesDemands
.
add
(
new
SalesDemand
(
p
,
sp
,
targetPeriod
,
plo
.
getQuantity
(),
priority
));
// 遍历周期, 按重叠天数比例拆分需求量
boolean
matched
=
false
;
for
(
Period
per
:
periods
)
{
long
overlapDays
=
overlappingDays
(
per
,
orderStart
,
orderEnd
);
if
(
overlapDays
>
0
)
{
double
periodQty
=
qty
*
overlapDays
/
totalRangeDays
;
salesDemands
.
add
(
new
SalesDemand
(
p
,
sp
,
per
,
periodQty
,
priority
));
matched
=
true
;
}
}
if
(!
matched
)
{
salesDemands
.
add
(
new
SalesDemand
(
p
,
sp
,
lastPeriod
,
qty
,
priority
));
}
}
log
.
info
(
"构建 SalesDemand: {}"
,
salesDemands
.
size
());
}
/**
* 计算 Period 与日期范围的交集天数。
*/
private
static
long
overlappingDays
(
Period
period
,
LocalDate
rangeStart
,
LocalDate
rangeEnd
)
{
LocalDate
periodStart
=
period
.
getStartDate
();
LocalDate
periodEnd
=
periodStart
.
plusDays
((
long
)
period
.
getDurationInDays
());
LocalDate
overlapStart
=
rangeStart
.
isAfter
(
periodStart
)
?
rangeStart
:
periodStart
;
LocalDate
overlapEnd
=
rangeEnd
.
isBefore
(
periodEnd
)
?
rangeEnd
:
periodEnd
;
if
(!
overlapStart
.
isBefore
(
overlapEnd
))
{
return
0
;
}
return
ChronoUnit
.
DAYS
.
between
(
overlapStart
,
overlapEnd
);
}
// ---------- 步骤9: InventorySpec + SupplySpec (默认宽松) ----------
private
void
fillInventorySpecsAndSupplySpecs
(
ConvertContext
ctx
)
{
...
...
@@ -1223,7 +1255,7 @@ public class MacroPlannerDataConverter {
private
static
class
ConvertContext
{
// 数据库加载的原始实体
List
<
ProdLaunchOrder
>
prodLaunch
Orders
=
new
ArrayList
<>();
List
<
ApsDemandOrder
>
apsDemand
Orders
=
new
ArrayList
<>();
List
<
RoutingHeader
>
routingHeaders
=
new
ArrayList
<>();
List
<
RoutingDetail
>
routingDetails
=
new
ArrayList
<>();
List
<
Routingsupporting
>
routingsupportings
=
new
ArrayList
<>();
...
...
@@ -1238,6 +1270,8 @@ public class MacroPlannerDataConverter {
List
<
PlanResource
>
planResources
=
new
ArrayList
<>();
List
<
EquipShiftCapacity
>
equipShiftCapacities
=
new
ArrayList
<>();
LocalDateTime
baseTime
;
/** 计划截止日期 (不包含), 由 baseTime + periodDimension + periodCount 计算 */
LocalDate
horizonEnd
;
// 转换过程的中间映射
/** materialId → Material 业务对象 */
...
...
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