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
be4b7722
Commit
be4b7722
authored
Sep 20, 2026
by
Tong Li
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MP
parent
d1745f27
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
1593 additions
and
406 deletions
+1593
-406
MacroPlannerResultController.java
...java/com/aps/controller/MacroPlannerResultController.java
+4
-4
DemandSlackLinkageConstraint.java
...macroplanner/constraint/DemandSlackLinkageConstraint.java
+0
-1
ResultWriter.java
src/main/java/com/aps/macroplanner/output/ResultWriter.java
+66
-65
BomStructureData.java
...ava/com/aps/macroplanner/output/dto/BomStructureData.java
+1
-0
TraceNode.java
src/main/java/com/aps/macroplanner/output/dto/TraceNode.java
+190
-0
TraceOutput.java
...ain/java/com/aps/macroplanner/output/dto/TraceOutput.java
+35
-0
MacroPlannerProductNetworkService.java
...va/com/aps/service/MacroPlannerProductNetworkService.java
+852
-336
MacroPlannerProductNetworkService1.java
...a/com/aps/service/MacroPlannerProductNetworkService1.java
+445
-0
No files found.
src/main/java/com/aps/controller/MacroPlannerResultController.java
View file @
be4b7722
package
com
.
aps
.
controller
;
package
com
.
aps
.
controller
;
import
com.aps.common.util.FlatParquetUtil
;
import
com.aps.common.util.FlatParquetUtil
;
import
com.aps.common.util.ParamValidator
;
import
com.aps.common.util.R
;
import
com.aps.common.util.R
;
import
com.aps.entity.ApsDemandOrder
;
import
com.aps.entity.ApsDemandOrder
;
import
com.aps.entity.MaterialInfo
;
import
com.aps.entity.MaterialInfo
;
...
@@ -13,8 +12,9 @@ import com.aps.macroplanner.data.MacroPlannerDataConverter;
...
@@ -13,8 +12,9 @@ import com.aps.macroplanner.data.MacroPlannerDataConverter;
import
com.aps.macroplanner.data.TestDataBuilder
;
import
com.aps.macroplanner.data.TestDataBuilder
;
import
com.aps.macroplanner.output.ResultWriter
;
import
com.aps.macroplanner.output.ResultWriter
;
import
com.aps.macroplanner.output.dto.*
;
import
com.aps.macroplanner.output.dto.*
;
import
com.aps.service.MacroPlannerResultService
;
import
com.aps.service.MacroPlannerProductNetworkService
;
import
com.aps.service.MacroPlannerProductNetworkService
;
import
com.aps.service.MacroPlannerResultService
;
import
com.aps.service.MacroPlannerProductNetworkService1
;
import
com.aps.service.MpPispipResultPersistenceService
;
import
com.aps.service.MpPispipResultPersistenceService
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.google.ortools.Loader
;
import
com.google.ortools.Loader
;
...
@@ -456,7 +456,7 @@ public class MacroPlannerResultController {
...
@@ -456,7 +456,7 @@ public class MacroPlannerResultController {
description
=
"成品→半成品→原材料完整BOM供应链树。"
description
=
"成品→半成品→原材料完整BOM供应链树。"
+
"包含各层级的供应来源(含每周期产量)、消耗者、BOM子物料(含每周期消耗量)。"
+
"包含各层级的供应来源(含每周期产量)、消耗者、BOM子物料(含每周期消耗量)。"
+
"支持按 productId / spId / unitId / periodIndex 可选过滤。"
)
+
"支持按 productId / spId / unitId / periodIndex 可选过滤。"
)
public
R
<
SupplyChain
Node
>
getProductNetwork
(
public
R
<
Trace
Node
>
getProductNetwork
(
@RequestParam
(
"sceneId"
)
@Parameter
(
description
=
"场景ID"
,
required
=
true
)
String
sceneId
,
@RequestParam
(
"sceneId"
)
@Parameter
(
description
=
"场景ID"
,
required
=
true
)
String
sceneId
,
@RequestParam
(
value
=
"productId"
,
required
=
false
)
@Parameter
(
description
=
"按产品ID过滤成品根节点(可选)"
)
String
productId
,
@RequestParam
(
value
=
"productId"
,
required
=
false
)
@Parameter
(
description
=
"按产品ID过滤成品根节点(可选)"
)
String
productId
,
@RequestParam
(
value
=
"spId"
,
required
=
false
)
@Parameter
(
description
=
"按库存点ID过滤(可选)"
)
String
spId
,
@RequestParam
(
value
=
"spId"
,
required
=
false
)
@Parameter
(
description
=
"按库存点ID过滤(可选)"
)
String
spId
,
...
@@ -464,7 +464,7 @@ public class MacroPlannerResultController {
...
@@ -464,7 +464,7 @@ public class MacroPlannerResultController {
if
(
productId
==
null
||
productId
.
trim
().
isEmpty
()
||
spId
==
null
||
spId
.
trim
().
isEmpty
())
{
if
(
productId
==
null
||
productId
.
trim
().
isEmpty
()
||
spId
==
null
||
spId
.
trim
().
isEmpty
())
{
return
R
.
failed
(
"productId 和 spId 不能为空"
);
return
R
.
failed
(
"productId 和 spId 不能为空"
);
}
}
SupplyChain
Node
node
=
macroPlannerProductNetworkService
.
buildProductNetwork
(
Trace
Node
node
=
macroPlannerProductNetworkService
.
buildProductNetwork
(
sceneId
,
productId
.
trim
(),
spId
.
trim
(),
period
);
sceneId
,
productId
.
trim
(),
spId
.
trim
(),
period
);
if
(
node
==
null
)
{
if
(
node
==
null
)
{
return
R
.
failed
(
"未找到场景 "
+
sceneId
+
" 中 "
+
productId
+
"@"
+
spId
+
" 的产品网络"
);
return
R
.
failed
(
"未找到场景 "
+
sceneId
+
" 中 "
+
productId
+
"@"
+
spId
+
" 的产品网络"
);
...
...
src/main/java/com/aps/macroplanner/constraint/DemandSlackLinkageConstraint.java
View file @
be4b7722
...
@@ -36,7 +36,6 @@ import java.util.Map;
...
@@ -36,7 +36,6 @@ import java.util.Map;
* 求解器被激励去增加生产来满足需求,而非简单地降低销售量。</p>
* 求解器被激励去增加生产来满足需求,而非简单地降低销售量。</p>
*
*
* @see BalanceConstraint 物料平衡约束(DemandSlack 在流入侧)
* @see BalanceConstraint 物料平衡约束(DemandSlack 在流入侧)
* @see DemandVariableBuilder 需求变量定义(SalesDemandQty, DemandSlack)
*/
*/
public
class
DemandSlackLinkageConstraint
{
public
class
DemandSlackLinkageConstraint
{
...
...
src/main/java/com/aps/macroplanner/output/ResultWriter.java
View file @
be4b7722
...
@@ -323,81 +323,82 @@ public class ResultWriter {
...
@@ -323,81 +323,82 @@ public class ResultWriter {
private
BomStructureData
buildBomStructureData
()
{
private
BomStructureData
buildBomStructureData
()
{
BomStructureData
s
=
new
BomStructureData
();
BomStructureData
s
=
new
BomStructureData
();
for
(
Product
p
:
data
.
getProducts
())
{
//
for (Product p : data.getProducts()) {
BomStructureData
.
ProductInfo
pi
=
new
BomStructureData
.
ProductInfo
();
//
BomStructureData.ProductInfo pi = new BomStructureData.ProductInfo();
pi
.
id
=
p
.
getId
();
//
pi.id = p.getId();
pi
.
name
=
p
.
getName
();
//
pi.name = p.getName();
pi
.
code
=
p
.
getCode
();
//
pi.code = p.getCode();
s
.
products
.
add
(
pi
);
//
s.products.add(pi);
}
//
}
for
(
StockingPoint
sp
:
data
.
getStockingPoints
())
{
//
for (StockingPoint sp : data.getStockingPoints()) {
BomStructureData
.
StockingPointInfo
si
=
new
BomStructureData
.
StockingPointInfo
();
//
BomStructureData.StockingPointInfo si = new BomStructureData.StockingPointInfo();
si
.
id
=
sp
.
getId
();
//
si.id = sp.getId();
si
.
name
=
sp
.
getName
();
//
si.name = sp.getName();
s
.
stockingPoints
.
add
(
si
);
//
s.stockingPoints.add(si);
}
//
}
// 产品→库存点映射 (通过 getStockingPointsForProduct 反推)
// 产品→库存点映射 (通过 getStockingPointsForProduct 反推)
for
(
Product
p
:
data
.
getProducts
())
{
//
for (Product p : data.getProducts()) {
for
(
StockingPoint
sp
:
data
.
getStockingPointsForProduct
(
p
.
getId
()))
{
//
for (StockingPoint sp : data.getStockingPointsForProduct(p.getId())) {
BomStructureData
.
ProductSpMappingInfo
mi
=
new
BomStructureData
.
ProductSpMappingInfo
();
//
BomStructureData.ProductSpMappingInfo mi = new BomStructureData.ProductSpMappingInfo();
mi
.
productId
=
p
.
getId
();
//
mi.productId = p.getId();
mi
.
spId
=
sp
.
getId
();
//
mi.spId = sp.getId();
s
.
productSpMappings
.
add
(
mi
);
//
s.productSpMappings.add(mi);
}
//
}
}
//
}
for
(
Operation
op
:
data
.
getOperations
())
{
//
for (Operation op : data.getOperations()) {
BomStructureData
.
OperationInfo
oi
=
new
BomStructureData
.
OperationInfo
();
//
BomStructureData.OperationInfo oi = new BomStructureData.OperationInfo();
oi
.
id
=
op
.
getId
();
//
oi.id = op.getId();
oi
.
name
=
op
.
getName
();
//
oi.name = op.getName();
oi
.
leadTimeDays
=
op
.
getLeadTimeDays
();
//
oi.leadTimeDays = op.getLeadTimeDays();
oi
.
hasLotSize
=
op
.
hasLotSize
();
//
oi.hasLotSize = op.hasLotSize();
oi
.
lotSize
=
op
.
hasLotSize
()
?
op
.
getLotSize
()
:
null
;
//
oi.lotSize = op.hasLotSize() ? op.getLotSize() : null;
for
(
OperationOutput
oo
:
op
.
getOutputs
())
{
//
for (OperationOutput oo : op.getOutputs()) {
BomStructureData
.
OperationOutputInfo
ooi
=
new
BomStructureData
.
OperationOutputInfo
();
//
BomStructureData.OperationOutputInfo ooi = new BomStructureData.OperationOutputInfo();
ooi
.
productId
=
oo
.
getProductId
();
//
ooi.productId = oo.getProductId();
ooi
.
spId
=
oo
.
getSpId
();
//
ooi.spId = oo.getSpId();
oi
.
outputs
.
add
(
ooi
);
//
oi.outputs.add(ooi);
}
//
}
for
(
UnitOperation
uo
:
op
.
getUnitOperations
())
{
//
for (UnitOperation uo : op.getUnitOperations()) {
BomStructureData
.
UnitOperationInfo
uoi
=
new
BomStructureData
.
UnitOperationInfo
();
//
BomStructureData.UnitOperationInfo uoi = new BomStructureData.UnitOperationInfo();
uoi
.
unitId
=
uo
.
getUnitId
();
//
uoi.unitId = uo.getUnitId();
uoi
.
unitName
=
uo
.
getUnitName
();
//
uoi.unitName = uo.getUnitName();
uoi
.
capacityCoeff
=
uo
.
getCapacityCoeff
();
//
uoi.capacityCoeff = uo.getCapacityCoeff();
oi
.
unitOperations
.
add
(
uoi
);
//
oi.unitOperations.add(uoi);
}
//
}
s
.
operations
.
add
(
oi
);
//
s.operations.add(oi);
}
//
}
for
(
OperationInput
input
:
data
.
getOperationInputs
())
{
for
(
OperationInput
input
:
data
.
getOperationInputs
())
{
BomStructureData
.
OperationInputInfo
ii
=
new
BomStructureData
.
OperationInputInfo
();
BomStructureData
.
OperationInputInfo
ii
=
new
BomStructureData
.
OperationInputInfo
();
ii
.
operationId
=
input
.
getOperation
().
getId
();
ii
.
operationId
=
input
.
getOperation
().
getId
();
ii
.
inputProductId
=
input
.
getInputProduct
().
getId
();
ii
.
inputProductId
=
input
.
getInputProduct
().
getId
();
ii
.
inputProductCode
=
input
.
getInputProduct
().
getCode
();
ii
.
inputSpId
=
input
.
getInputSp
().
getId
();
ii
.
inputSpId
=
input
.
getInputSp
().
getId
();
ii
.
inputSpName
=
input
.
getInputSp
().
getName
();
ii
.
inputSpName
=
input
.
getInputSp
().
getName
();
ii
.
factor
=
input
.
getFactor
();
ii
.
factor
=
input
.
getFactor
();
s
.
operationInputs
.
add
(
ii
);
s
.
operationInputs
.
add
(
ii
);
}
}
for
(
Period
p
:
data
.
getPeriods
())
{
//
for (Period p : data.getPeriods()) {
BomStructureData
.
PeriodInfo
pi
=
new
BomStructureData
.
PeriodInfo
();
//
BomStructureData.PeriodInfo pi = new BomStructureData.PeriodInfo();
pi
.
index
=
p
.
getIndex
();
//
pi.index = p.getIndex();
pi
.
name
=
p
.
getName
();
//
pi.name = p.getName();
pi
.
startDate
=
p
.
getStartDate
()
==
null
?
null
:
p
.
getStartDate
().
toString
();
//
pi.startDate = p.getStartDate() == null ? null : p.getStartDate().toString();
s
.
periods
.
add
(
pi
);
//
s.periods.add(pi);
}
//
}
for
(
InitialInventory
inv
:
data
.
getInitialInventories
())
{
//
for (InitialInventory inv : data.getInitialInventories()) {
BomStructureData
.
InitialInventoryInfo
ii
=
new
BomStructureData
.
InitialInventoryInfo
();
//
BomStructureData.InitialInventoryInfo ii = new BomStructureData.InitialInventoryInfo();
ii
.
productId
=
inv
.
getProduct
().
getId
();
//
ii.productId = inv.getProduct().getId();
ii
.
spId
=
inv
.
getStockingPoint
().
getId
();
//
ii.spId = inv.getStockingPoint().getId();
ii
.
quantity
=
inv
.
getQuantity
();
//
ii.quantity = inv.getQuantity();
s
.
initialInventories
.
add
(
ii
);
//
s.initialInventories.add(ii);
}
//
}
for
(
InTransitSupply
its
:
data
.
getInTransitSupplies
())
{
//
for (InTransitSupply its : data.getInTransitSupplies()) {
BomStructureData
.
InTransitSupplyInfo
ti
=
new
BomStructureData
.
InTransitSupplyInfo
();
//
BomStructureData.InTransitSupplyInfo ti = new BomStructureData.InTransitSupplyInfo();
ti
.
productId
=
its
.
getProduct
().
getId
();
//
ti.productId = its.getProduct().getId();
ti
.
spId
=
its
.
getStockingPoint
().
getId
();
//
ti.spId = its.getStockingPoint().getId();
ti
.
arrivalDate
=
its
.
getArrivalDate
()
==
null
?
null
:
its
.
getArrivalDate
().
toString
();
//
ti.arrivalDate = its.getArrivalDate() == null ? null : its.getArrivalDate().toString();
ti
.
quantity
=
its
.
getQuantity
();
//
ti.quantity = its.getQuantity();
s
.
inTransitSupplies
.
add
(
ti
);
//
s.inTransitSupplies.add(ti);
}
//
}
return
s
;
return
s
;
}
}
...
...
src/main/java/com/aps/macroplanner/output/dto/BomStructureData.java
View file @
be4b7722
...
@@ -64,6 +64,7 @@ public class BomStructureData {
...
@@ -64,6 +64,7 @@ public class BomStructureData {
public
static
class
OperationInputInfo
{
public
static
class
OperationInputInfo
{
public
String
operationId
;
public
String
operationId
;
public
String
inputProductId
;
public
String
inputProductId
;
public
String
inputProductCode
;
public
String
inputSpId
;
public
String
inputSpId
;
public
String
inputSpName
;
public
String
inputSpName
;
public
double
factor
;
public
double
factor
;
...
...
src/main/java/com/aps/macroplanner/output/dto/TraceNode.java
0 → 100644
View file @
be4b7722
package
com
.
aps
.
macroplanner
.
output
.
dto
;
/**
* 作者:佟礼
* 时间:2026-09-20
*/
import
java.util.ArrayList
;
import
java.util.List
;
/**
* 产品数量追溯网络节点。
*
* <pre>
* Product + Warehouse
* |
* | demand
* v
* Unit
* |
* | productionQty
* v
* BOM
* |
* v
* Product + Warehouse
* |
* v
* 最近历史 Output
* </pre>
*/
public
class
TraceNode
{
/**
* 产品 ID
*/
public
String
productId
;
/**
* 产品编码
*/
public
String
productCode
;
/**
* 库房 / SP
*/
public
String
warehouseId
;
/**
* 库房名称
*/
public
String
warehouseName
;
/**
* 当前节点需求数量。
*
* 根节点:
* 成品需求量
*
* 子节点:
* Unit生产量 × BOM factor
*/
public
double
quantity
;
/**
* BOM factor。
*
* 根节点一般为 1。
*/
public
double
factor
=
1.0
;
/**
* 当前节点匹配到的 Output 总数量。
*
* 注意:
* outputQty 可以 > quantity。
*/
public
double
outputQty
;
/**
* 当前节点库存/库房已有供应量。
*
* 这里表示没有通过生产 Output 继续追溯的数量。
*/
public
double
inventorySupplyQty
;
/**
* 当前节点匹配到的生产 Output。
*
* 一个产品可能对应多个 Output。
*/
// public final List<OutputNode> outputs = new ArrayList<>();
/**
* 当前节点对应的 Unit。
*
* 不同 Unit 必须独立。
*/
public
final
List
<
UnitNode
>
units
=
new
ArrayList
<>();
/**
* 实际生产 Output 节点。
*/
public
static
class
OutputNode
{
/**
* Output 对应的 dataKey。
*/
public
String
dataKey
;
/**
* 产品 ID。
*/
public
String
productId
;
/**
* 产品 Code。
*/
public
String
productCode
;
/**
* 库房。
*/
public
String
warehouseId
;
public
String
warehouseName
;
/**
* Output 日期/期间。
*/
public
Integer
periodIndex
;
/**
* Output 日期。
*
* 如果项目实际使用 LocalDate/LocalDateTime,
* 可以替换这里的类型。
*/
public
String
outputDate
;
/**
* Output 实际数量。
*
* 可以大于当前 demand。
*/
public
double
outputQty
;
/**
* 对应生产 Unit。
*/
public
UnitNode
unit
;
}
/**
* 独立生产 Unit 节点。
*
* 每个 Unit 单独展开 BOM。
*/
public
static
class
UnitNode
{
public
String
unitId
;
public
String
unitName
;
/**
* 当前 Unit 的实际生产量。
*/
public
double
productionQty
;
/**
* 产能占用。
*/
public
double
capacityUsed
;
/**
* 工序。
*/
public
String
operationId
;
public
String
operationName
;
/**
* 当前 Unit 的 BOM 上游节点。
*/
public
final
List
<
TraceNode
>
children
=
new
ArrayList
<>();
}
}
src/main/java/com/aps/macroplanner/output/dto/TraceOutput.java
0 → 100644
View file @
be4b7722
package
com
.
aps
.
macroplanner
.
output
.
dto
;
/**
* 作者:佟礼
* 时间:2026-09-20
* 数量追溯用的实际生产Output。
*
* OutputInfo + PeriodTaskResult 合并。
*/
public
class
TraceOutput
{
public
String
productId
;
public
String
warehouseId
;
public
String
warehouseName
;
public
String
dataKey
;
public
Integer
periodIndex
;
public
double
outputQty
;
public
String
outputDate
;
public
String
operationId
;
public
String
operationName
;
public
String
unitId
;
public
String
unitName
;
public
double
capacityUsed
;
}
src/main/java/com/aps/service/MacroPlannerProductNetworkService.java
View file @
be4b7722
This diff is collapsed.
Click to expand it.
src/main/java/com/aps/service/MacroPlannerProductNetworkService1.java
0 → 100644
View file @
be4b7722
This diff is collapsed.
Click to expand it.
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