Files
klp-oa/ems-cost-allocation-notes.md

226 lines
11 KiB
Markdown
Raw Permalink Normal View History

# 能源分摊(现有实现)与加入“备件/辅料分摊”的接入方案
## 0. 时间线(用于交接,持续更新)
- **2026-01-20**
- **已改动(代码)**
- `klp-ems/src/main/java/com/klp/ems/domain/vo/CoilTotalCostVo.java`:新增 `auxCost/spareCost` 字段,`totalCost` 注释更新。
- `klp-ems/src/main/java/com/klp/ems/domain/vo/CoilTotalMergedExportVo.java`:新增导出列 `auxCost/spareCost`
- `klp-ems/src/main/resources/mapper/WmsEnergyCoilDailyMapper.xml``selectCoilTotalMerged``selectCoilTotalMergedExport` 已加入 `auxCost/spareCost` 计算与 join并更新 `totalCost` 公式。
- `klp-ems/src/main/java/com/klp/ems/controller/EnergyCostReportController.java`:导出接口已补充 `auxCost/spareCost` 赋值。
- `klp-ui/src/views/ems/cost/cost.vue`:列表新增列展示 `auxCost/spareCost`;顶部卡片展示 `materialSummary`(当前按列表行求和);总成本计算加入备件/辅料。
- **2026-01-26**
- **新增(前端页面)**:按数据库路由方式新增两个独立页面(不在前端代码写路由)。
- `klp-ui/src/views/ems/cost/auxAllocation.vue`:辅料成本分摊页面(按入场卷号汇总),包含“分摊明细”弹窗与导出;并新增“辅料消耗构成(分摊口径)”区域(展示用了哪些辅料、几种、数量与金额)。
- `klp-ui/src/views/ems/cost/spareAllocation.vue`:备件成本分摊页面(按入场卷号汇总),包含“分摊明细”弹窗与导出;并新增“备件消耗构成(分摊口径)”区域(展示用了哪些备件、几种、数量与金额)。
- **路由 component 配置建议(写入数据库)**
- 辅料:`ems/cost/auxAllocation`
- 备件:`ems/cost/spareAllocation`
- **接口复用说明**
- 汇总:两个页面均复用 `GET /ems/energy/report/coilTotal/merged``GET /ems/energy/report/coilTotal/merged/export`,分别取字段 `auxCost` / `spareCost`
- 构成:新增两个接口返回“按物料/备件聚合后的分摊构成”(数量与金额均按日分摊系数切分):
- `GET /ems/energy/report/material/aux/breakdown`
- `GET /ems/energy/report/material/spare/breakdown`
- **口径(构成)**
- 全厂按日聚合消耗(`eqp_*_change``change_type='减少'`,金额取 `ABS(amount)`,数量取 `ABS(change_quantity)`
- 当日卷分摊系数:`coil_minutes_day / total_minutes_day`(分钟基于 `wms_coil_pending_action.create_time ~ complete_time/now`
- 最终按物料/备件汇总:`allocatedQty = Σ_D (day_item_qty * factor_day)``allocatedAmount = Σ_D (day_item_amount * factor_day)`
- **重要说明**
- merged 仍不返回按日池/分钟明细;页面“分摊明细”弹窗仍为汇总占位。
- 构成接口可在不强制 enterCoilNo 的情况下使用:不传 enterCoilNo 时可用于查看全厂消耗构成allocated≈total
- **2026-01-20**
- **口径确认**:备件/辅料分摊池按**全厂**聚合(不按库区/设备/产线拆分)。
- **过滤规则确认**
- `wms_coil_pending_action`:按 `pa.create_time` 落在 `[startDate, endDate]` 过滤。
- `eqp_*_change`:按 `change_time` 落在同一 `[startDate, endDate]` 过滤。
- 仅统计 `change_type = '减少'`(消耗)。
- **金额按天切分规则确认**:采用 **A 方案**(按 `DATE(pa.create_time)` 归属到某一天;不做跨天拆分时长)。消耗金额按天形成日池(例如 3 天形成 3 个日池、5 天形成 5 个日池),再在当日内按钢卷时长占比分摊。
- **跨库可达性确认**EMS/WMS 可以直接查询到 MES 的 `eqp_auxiliary_material_change``eqp_spare_parts_change` 两张变动表(可在 EMS 侧 SQL 直接使用)。
- **已完成**:梳理前端 `klp-ui/src/views/ems/cost/cost.vue` 的查询/展示/接口调用。
- **已完成**:定位后端 `EnergyCostReportController``WmsEnergyCoilDailyMapper.xml`
- **已修正**:早期将能源分摊概括为“库区时间窗”会误导备件/辅料接入;备件/辅料分摊以 `wms_coil_pending_action` 的待操作时间窗为中心(见本时间线确认项)。
- **已确认MES 成本记账规则)**
- 台账表(`eqp_spare_part``eqp_auxiliary_material`)补充 `unit_price/total_amount`
- 入库单价来源:**前端必传**(老接口与前端一并改造)。
- 入库/增加时采用移动加权平均价:`new_unit_price = (old_unit_price*old_qty + in_unit_price*in_qty) / (old_qty+in_qty)`
- 消耗/减少时在变动表写入 `unit_price_snapshot` 并计算 `amount`**有符号**;减少为负:`-unit_price_snapshot * change_quantity`)。
- 分摊侧聚合消耗金额使用 `ABS(amount)`
> 范围:
> - 前端页面:`klp-ui/src/views/ems/cost/cost.vue`
> - 后端接口:`klp-ems/src/main/java/com/klp/ems/controller/EnergyCostReportController.java`
> - 主要 SQL`klp-ems/src/main/resources/mapper/WmsEnergyCoilDailyMapper.xml`
> - MES 表结构:`script/sql/mysql/eqp_auxiliary_material.sql`
## 1. 现有页面做了什么(前端)
页面名称:`CoilTotalCost`(钢卷成本汇总)
### 1.1 查询条件
`queryParams`
- `enterCoilNo`:入场卷号(页面标记 required支持模糊
- `currentCoilNo`:当前卷号(支持模糊)
- `startDate`开始日期yyyy-MM-dd
- `endDate`结束日期yyyy-MM-dd
点击“查询”会同时触发三块数据加载:
- **能源成本汇总 + 明细**EMS
- **囤积成本明细/汇总**WMS
- **能源+囤积 合并汇总**EMS 聚合接口)
### 1.2 页面展示结构
- **顶部 4 个卡片**
- **能源成本**:来自 `energySummary.totalEnergyCost`,并展示耗能、时长
- **本日囤积成本**:来自 `stockSummary.todayCost`,并展示净重/毛重
- **辅料成本**:当前写死 `0.00``暂不计`
- **总成本**`能源 + 囤积 + 辅料(当前为 0)`
- **表格:成本汇总(按入场卷号)**
- 数据源:`mergedRows`
- 列:入场卷号、当前卷号、能源成本、囤积成本(当日)、总成本、净重、毛重
- 操作:查看详情
- **详情弹窗**
- 能源分摊明细(按待操作时间跨度分摊)
- 囤积成本(单行汇总)
### 1.3 前端调用的接口
能源相关(同一模块 `@/api/ems/energyCostReport`
- `fetchCoilTotalEnergySummary(params)`
- 对应后端:`GET /ems/energy/report/coilTotal/summary`
- `fetchCoilTotalEnergyDetail(params)`
- 对应后端:`GET /ems/energy/report/coilTotal/detail`
- `fetchCoilTotalMerged(params)`
- 对应后端:`GET /ems/energy/report/coilTotal/merged`
- `exportCoilTotalMerged(params)`
- 对应后端:`GET /ems/energy/report/coilTotal/merged/export`
囤积成本WMS 模块 `@/api/wms/cost`
- `getStockpileCostList(params)`
## 2. 现有“能源分摊”后端是怎么做的(与备件/辅料接入相关的部分)
核心 Controller`EnergyCostReportController`
- `GET /ems/energy/report/coilTotal/summary`
- `GET /ems/energy/report/coilTotal/detail`
- `GET /ems/energy/report/coilTotal/merged`
- `GET /ems/energy/report/coilTotal/merged/export`
入参对象:`CoilTotalCostBo``enterCoilNo/currentCoilNo/startDate/endDate`
当前实现中,`coilTotal/*` 相关 SQL 主要围绕 `wms_coil_pending_action` 的时间跨度计算(分钟/小时),并将能耗/成本按占比分配到卷。
## 3. 备件/辅料分摊:最新确认的正确口径(可直接实现)
### 3.1 总体思路
- 备件/辅料成本池:按**全厂**聚合。
- 成本池按**日**切分:以 `DATE(change_time)` 形成每日消耗金额池。
- 分摊权重按**日**切分:以 `DATE(pa.create_time)` 形成每日钢卷“待操作时长”池。
- 当天内按“入场卷号的总时长 / 全厂总时长”占比,将当日消耗金额分摊到各入场卷号。
### 3.2 关键定义A 方案:不拆跨天时长)
#### (1) 当日消耗金额池(仅减少)
- `aux_pool_day(D) = SUM(eqp_auxiliary_material_change.amount)`
- `spare_pool_day(D) = SUM(eqp_spare_parts_change.amount)`
过滤:
- `change_type = '减少'`
- `DATE(change_time) = D`
-`change_time``[startDate, endDate]` 范围内(与查询一致)
#### (2) 当日全厂总时长池
- `minutes(pa) = TIMESTAMPDIFF(MINUTE, pa.create_time, COALESCE(pa.complete_time, NOW()))`
- `total_minutes_day(D) = SUM(minutes(pa))`
过滤:
- `pa.create_time``[startDate, endDate]`
- `DATE(pa.create_time) = D`
#### (3) 当日按入场卷号的时长
- `coil_minutes_day(D, enter_coil_no) = SUM(minutes(pa))`
其中 `enter_coil_no` 通过:
- `wms_coil_pending_action.pa.coil_id -> wms_material_coil.coil_id -> wms_material_coil.enter_coil_no`
#### (4) 当日分摊与汇总
- `aux_cost_day = aux_pool_day(D) * coil_minutes_day / total_minutes_day`
- `spare_cost_day = spare_pool_day(D) * coil_minutes_day / total_minutes_day`
最终:
- `auxCost = Σ_D aux_cost_day`
- `spareCost = Σ_D spare_cost_day`
### 3.3 SQL 接入点(在 EMS merged 中 join
建议在 `WmsEnergyCoilDailyMapper.xml`
- `selectCoilTotalMerged`
- `selectCoilTotalMergedExport`
新增 join 结构:
1. 先构造“按入场卷号的每日分钟数”子查询:`coil_day_minutes`
2. 再构造“全厂每日总分钟数”子查询:`total_day_minutes`
3. 再构造“全厂每日消耗金额池(备件/辅料)”子查询:`aux_day_amount` / `spare_day_amount`
4. 通过 `day` 将以上子查询 join 起来,得到 `Σ( day_amount * coil_day_minutes / total_day_minutes )`
5. 最终在 `merged` 的 select 列表中补充:
- `IFNULL(x.aux_cost, 0) AS auxCost`
- `IFNULL(x.spare_cost, 0) AS spareCost`
- `totalCost = energy_cost + stock_cost + aux_cost + spare_cost`
> 注意:实现时需要防止分母为 0`CASE WHEN total_day_minutes > 0 THEN ... ELSE 0 END`。
## 4. 需要改动的后端/前端文件清单(待实现)
### 4.1 EMS 后端klp-ems
- `klp-ems/src/main/java/com/klp/ems/domain/vo/CoilTotalCostVo.java`
- 增加字段:`auxCost``spareCost`(以及 `totalCost` 公式更新)
- `klp-ems/src/main/resources/mapper/WmsEnergyCoilDailyMapper.xml`
- 修改:`selectCoilTotalMerged``selectCoilTotalMergedExport`
- `klp-ems/src/main/java/com/klp/ems/controller/EnergyCostReportController.java`
- 导出映射:`coilTotalMergedExport` 增加导出字段赋值
- `klp-ems/src/main/java/com/klp/ems/domain/vo/CoilTotalMergedExportVo.java`
- 增加列:备件成本、辅料成本(以及总成本)
### 4.2 前端klp-ui
- `klp-ui/src/views/ems/cost/cost.vue`
- 顶部卡片:“辅料成本”从 0 改为接口返回(或新增 summary 聚合)
- 表格增加两列:`auxCost``spareCost`
- 总成本公式更新:能源 + 囤积 + 备件 + 辅料
---
## 5. 当前状态(给新 agent 的交接结论)
- 分摊口径已最终确认并记录:**全厂池 + 按天切分 + A 方案(按 `DATE(pa.create_time)` 归属)**。
- EMS/WMS 可直接查询 MES 的 change 表,允许在 `WmsEnergyCoilDailyMapper.xml` 内直接 join 实现。
- 尚未开始实际代码改造;下一步按第 4 节清单逐项实现,并在每次提交后回写本文件时间线(记录修改了哪些文件/字段/SQL