kpi修改

parent c6774944
...@@ -1023,8 +1023,8 @@ public class MacroPlannerResultController { ...@@ -1023,8 +1023,8 @@ public class MacroPlannerResultController {
Map<String, String> entryMap = new LinkedHashMap<>(); Map<String, String> entryMap = new LinkedHashMap<>();
entryMap.put("name", e.name); entryMap.put("name", e.name);
entryMap.put("rawValue", String.format("%.2f", e.rawValue)); entryMap.put("rawValue", String.format("%.2f", e.rawValue));
entryMap.put("weight", String.format("%.1f", e.weight)); entryMap.put("weight", e.weight == null ? null : String.format("%.1f", e.weight));
entryMap.put("penalty", String.format("%.2f", e.penalty)); entryMap.put("penalty", e.penalty == null ? null : String.format("%.2f", e.penalty));
kpiList.add(entryMap); kpiList.add(entryMap);
} }
kpiData.put("entries", kpiList); kpiData.put("entries", kpiList);
......
...@@ -260,7 +260,6 @@ public class MacroPlannerDataConverter { ...@@ -260,7 +260,6 @@ 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 时间范围过滤)
......
...@@ -4,6 +4,7 @@ import com.aps.common.util.FileHelper; ...@@ -4,6 +4,7 @@ import com.aps.common.util.FileHelper;
import com.aps.common.util.FlatParquetUtil; import com.aps.common.util.FlatParquetUtil;
import com.aps.macroplanner.data.*; import com.aps.macroplanner.data.*;
import com.aps.macroplanner.model.MacroPlannerModel; import com.aps.macroplanner.model.MacroPlannerModel;
import com.aps.macroplanner.objective.KpiLib;
import com.aps.macroplanner.output.dto.*; import com.aps.macroplanner.output.dto.*;
import com.aps.service.plan.SceneService; import com.aps.service.plan.SceneService;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
...@@ -230,6 +231,12 @@ public class ResultWriter { ...@@ -230,6 +231,12 @@ public class ResultWriter {
// BOM 结构持久化 (供 getProductNetwork 按需组装) // BOM 结构持久化 (供 getProductNetwork 按需组装)
writeLog("writeBomStructure"); writeLog("writeBomStructure");
writeBomStructure(sceneId); writeBomStructure(sceneId);
// KPI 汇总通过 summary 接口从 JSON 读取,这里同步保存完整结果。
File jsonFile = getOptimizationFile(sceneId);
objectMapper.writeValue(jsonFile, result);
writeLog("writeOptimizationResultJson: " + jsonFile.getAbsolutePath());
// 工序×物料×周期消耗量持久化 // 工序×物料×周期消耗量持久化
// writeLog("writeOperationDemands"); // writeLog("writeOperationDemands");
// List<OperationDemandResult> opDemands = buildOperationDemandResults(); // List<OperationDemandResult> opDemands = buildOperationDemandResults();
...@@ -535,7 +542,7 @@ public class ResultWriter { ...@@ -535,7 +542,7 @@ public class ResultWriter {
// KPI + 统计 // KPI + 统计
writeLog("Kpi"); writeLog("Kpi");
// result.setKpis(buildKpis()); result.setKpis(buildKpis());
// result.setStatistics(buildStatistics()); // result.setStatistics(buildStatistics());
return result; return result;
...@@ -1486,49 +1493,24 @@ public class ResultWriter { ...@@ -1486,49 +1493,24 @@ public class ResultWriter {
private KpiResult buildKpis() { private KpiResult buildKpis() {
KpiResult kr = new KpiResult(); KpiResult kr = new KpiResult();
KPIWeights w = data.getKpiWeights();
double objValue = model.getSolver().objective().value(); double objValue = model.getSolver().objective().value();
kr.setObjectiveValue(objValue); kr.setObjectiveValue(objValue);
kr.addEntry("需求缺口(Fulfillment)", for (KpiLib kpi : KpiLib.values()) {
model.getTotalFulfillment().solutionValue(), kr.addEntry(kpi.getCn(),
w.getFulfillmentWeight(), false); model.getKpi(kpi.getEn()).solutionValue(),
kr.addEntry("需求满足数(FulfilledDemands)", null,
countFulfilledDemands(), 0.0, true); kpi == KpiLib.SalesDemandPriority);
kr.addEntry("批次偏差(LotSize)", }
model.getTotalLotSize().solutionValue(),
w.getLotSizeWeight(), false); // // 这几个指标暂未纳入 KpiLib,保留原有结果字段,但不返回权重。
kr.addEntry("超库存(MaxInventory)", // kr.addEntry("需求满足数(FulfilledDemands)",
model.getTotalMaxInventoryLevel().solutionValue(), // countFulfilledDemands(), null, true);
w.getMaxInventoryLevelWeight(), false); // kr.addEntry("推迟惩罚(Postponement)",
kr.addEntry("欠库存(MinInventory)", // model.getTotalPostponementPenalty().solutionValue(), null, false);
model.getTotalMinInventoryLevel().solutionValue(), // kr.addEntry("过程最大量(ProcessMax)",
w.getMinInventoryLevelWeight(), false); // model.getTotalProcessMaxQuantity().solutionValue(), null, false);
kr.addEntry("目标库存偏差(TargetInv)",
model.getTotalTargetInvLevel().solutionValue(),
w.getTargetInventoryLevelWeight(), false);
kr.addEntry("产能超载(UnitCapacity)",
model.getTotalUnitCapacity().solutionValue(),
w.getUnitCapacityWeight(), false);
kr.addEntry("供应目标偏差(SupplyTarget)",
model.getTotalSupplyTarget().solutionValue(),
w.getSupplyTargetWeight(), false);
kr.addEntry("最小供应不足(MinSupply)",
model.getTotalMinSupply().solutionValue(),
w.getMinSupplyWeight(), false);
kr.addEntry("最大供应超出(MaxSupply)",
model.getTotalMaxSupply().solutionValue(),
w.getMaxSupplyWeight(), false);
kr.addEntry("销售优先级(SalesPriority)",
model.getTotalSalesDemandPriority().solutionValue(),
w.getSalesDemandPriorityWeight(), true);
kr.addEntry("推迟惩罚(Postponement)",
model.getTotalPostponementPenalty().solutionValue(),
w.getPostponementPenaltyWeight(), false);
kr.addEntry("过程最大量(ProcessMax)",
model.getTotalProcessMaxQuantity().solutionValue(),
w.getProcessMaxQuantityWeight(), false);
return kr; return kr;
} }
...@@ -1714,8 +1696,8 @@ public class ResultWriter { ...@@ -1714,8 +1696,8 @@ public class ResultWriter {
jb.obj() jb.obj()
.key("name").val(e.name) .key("name").val(e.name)
.key("rawValue").val(e.rawValue) .key("rawValue").val(e.rawValue)
.key("weight").val(e.weight) .key("weight").valOpt(e.weight)
.key("penalty").val(e.penalty) .key("penalty").valOpt(e.penalty)
.key("isBenefit").val(e.isBenefit) .key("isBenefit").val(e.isBenefit)
.endObj(); .endObj();
} }
......
...@@ -22,10 +22,10 @@ public class KpiResult { ...@@ -22,10 +22,10 @@ public class KpiResult {
public String name; public String name;
/** KPI 原始值 (松弛量总和) */ /** KPI 原始值 (松弛量总和) */
public double rawValue; public double rawValue;
/** 权重 */ /** 权重;结果展示暂不提供权重时为 null */
public double weight; public Double weight;
/** 加权惩罚 = rawValue × weight */ /** 加权惩罚;权重为空时为 null */
public double penalty; public Double penalty;
/** 是否为收益项 (越大越好, 正系数) */ /** 是否为收益项 (越大越好, 正系数) */
public boolean isBenefit; public boolean isBenefit;
} }
...@@ -37,13 +37,13 @@ public class KpiResult { ...@@ -37,13 +37,13 @@ public class KpiResult {
public List<KpiEntry> getEntries() { return entries; } public List<KpiEntry> getEntries() { return entries; }
public void addEntry(String name, double rawValue, double weight, boolean isBenefit) { public void addEntry(String name, double rawValue, Double weight, boolean isBenefit) {
KpiEntry e = new KpiEntry(); KpiEntry e = new KpiEntry();
e.name = name; e.name = name;
e.rawValue = rawValue; e.rawValue = rawValue;
e.weight = weight; e.weight = weight;
e.isBenefit = isBenefit; e.isBenefit = isBenefit;
e.penalty = isBenefit ? -rawValue * weight : rawValue * weight; e.penalty = weight == null ? null : (isBenefit ? -rawValue * weight : rawValue * weight);
entries.add(e); entries.add(e);
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment