# 能源分摊(现有实现)与加入“备件/辅料分摊”的接入方案 ## 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)。