Files
MES/yawei-mes/.tasks/2026-03-27_v2.0.014_BOM单多级优化.md
2026-04-02 10:39:03 +08:00

10 KiB
Raw Blame History

BOM单多级优化开发文档

一、现状分析

1.1 现有系统架构

当前 md_new_bom 模块为单层BOM结构每个BOM主表记录md_new_bom对应一个产品的物料信息其下挂多条BOM明细md_new_bom_item),每条明细直接对应具体物料。

现有表字段中,parent_idhas_children 已预置,但未真正实现多级递归展开。

现有数据模型:

md_new_bom (1) --< md_new_bom_item (N)
                        └─ materialId (直接指向物料表)

1.2 关键代码现状

层面 文件 现状
实体-主表 NewBom.java parentIdhasChildrenchildren(非持久化)字段
实体-明细 NewBomItem.java subBomId 引用字段明细不能挂子BOM
Mapper NewBomMapper.xml selectNewBomTree 仅取一层子节点,无递归
Service NewBomServiceImpl.java calculateBomCost 仅计算直接子项成本,未递归
前端 newBom/index.vue 已有树形表格外壳,但展开逻辑不完整

二、需求定义什么是本系统的多级BOM

本系统面向离散制造业多级BOM的核心诉求是支持子装配Sub-Assembly层级

产品BOM的明细物料中一部分为采购/消耗的原材料,另一部分为半成品组件子装配件。这些组件本身也有BOM。

目标结构(示例):

产品: A (整机BOM V1.0)
├── 物料: 螺丝 M3 x 100 pcs      (直接材料)
├── 物料: 外壳组件 x 1 pcs        (子装配BOM)
│   ├── 物料: 外壳塑料件 x 1      (孙子层)
│   └── 物料: 卡扣 x 4           (孙子层)
└── 物料: PCB主板 x 1            (子装配BOM)
    ├── 物料: 芯片 xxx x 2
    └── 物料: PCB板 x 1

三、方案设计

3.1 总体思路

不动数据库表结构md_new_bom 主表不变),仅做以下扩展:

  1. md_new_bom_item 新增 sub_bom_id 字段标识该明细行是否引用了另一个BOM
  2. 在 Service 层新增递归成本计算方法
  3. 前端增强树形展开展示和子BOM展开功能
  4. 提供多级BOM展开视图可一键将多层BOM展开为单层物料清单物料去重合并用量

3.2 数据库变更

ALTER TABLE md_new_bom_item

ALTER TABLE `md_new_bom_item`
  ADD COLUMN `sub_bom_id` bigint(20) DEFAULT NULL COMMENT '引用的子BOM ID多级BOM用' AFTER `process_route`,
  ADD COLUMN `is_sub_bom` tinyint(1) DEFAULT '0' COMMENT '是否子BOM项 0-否 1-是' AFTER `sub_bom_id`,
  ADD COLUMN `level` int(11) DEFAULT '0' COMMENT 'BOM层级深度' AFTER `is_sub_bom`,
  ADD KEY `idx_sub_bom_id` (`sub_bom_id`);

说明: 保留原 materialId 字段,但当 is_sub_bom=1 时,materialId 指向子装配件的物料IDsub_bom_id 指向该物料对应的BOM ID。


四、后端改造

4.1 实体类变更

NewBomItem.java 新增字段:

/** 引用的子BOM ID多级BOM用 */
private Long subBomId;

/** 是否子BOM项 0-否 1-是 */
private Boolean isSubBom;

/** BOM层级深度 */
private Integer level;

NewBom.java 新增非持久化字段(用于前端展开):

/** 多级展开后的子层BOM列表仅在多级查询时填充 */
@TableField(exist = false)
private List<NewBom> expandedChildren;

/** 多级成本(递归计算结果) */
@TableField(exist = false)
private BigDecimal expandedMaterialCost;

4.2 Service 层新增方法

INewBomService.javaNewBomServiceImpl.java 中新增:

4.2.1 递归成本计算

/**
 * 递归计算多级BOM成本支持无限层级
 * @param bomId BOM主键
 * @param topQuantity 顶层需求量(用于按比例缩放子级用量)
 * @return 包含多级明细的成本分析
 */
Map<String, Object> calculateMultiLevelBomCost(Long bomId, BigDecimal topQuantity);

核心算法:

calculateMultiLevelBomCost(bomId, quantity):
  bom = selectNewBomById(bomId)
  totalMaterialCost = 0
  totalLaborCost = bom.laborCost
  totalManufacturingCost = bom.manufacturingCost

  for each item in bom.bomItems:
    scaleFactor = quantity / bom.baseQuantity
    if item.isSubBom == true:
      childCost = calculateMultiLevelBomCost(item.subBomId, item.quantity * scaleFactor)
      totalMaterialCost += childCost.materialCost
    else:
      itemCost = item.quantity * scaleFactor * item.unitPrice * (1 + item.lossRate/100)
      totalMaterialCost += itemCost

  return { materialCost, laborCost, manufacturingCost, totalCost, itemDetails }

4.2.2 完整BOM树查询

/**
 * 查询BOM多级展开树递归向下查询指定层级
 * @param bomId 起始BOM ID
 * @param maxLevel 最大展开层级默认3层防止性能问题
 * @return 带完整子级结构的BOM树
 */
NewBom selectBomFullTree(Long bomId, Integer maxLevel);

4.2.3 BOM展开清单物料去重合并

/**
 * 将多级BOM展开为单层物料清单含去重合并用量
 * @param bomId 起始BOM ID
 * @param quantity 需求量
 * @return 扁平化物料列表(含各层汇总用量)
 */
List<Map<String, Object>> expandBomToFlatList(Long bomId, BigDecimal quantity);

展开合并算法:

expandBomToFlatList(bomId, quantity):
  flatList = []
  recursiveCollect(bomId, quantity, visitedBomIds):
    bom = selectBomById(bomId)
    if bom.id in visitedBomIds: return  // 防止循环引用
    add bom.id to visitedBomIds
    scale = quantity / bom.baseQuantity
    for each item in bom.items:
      if item.isSubBom:
        recursiveCollect(item.subBomId, item.quantity * scale, visitedBomIds)
      else:
        merge into flatList: 物料ID -> 累加用量
  return flatList

4.3 Controller 层新增接口

NewBomController.java 新增端点:

方法 路径 说明
GET /masterdata/newBom/multiLevel/{id} 获取BOM多级展开树
GET /masterdata/newBom/cost/multiLevel/{id} 多级递归成本计算
GET /masterdata/newBom/expand/{id} 展开为扁平物料清单

4.4 多级展开时需防止的问题

  1. 循环引用检测: A->B->A 的情况,在递归入口处用 Set<Long> visitedBomIds 记录已访问的BOM ID
  2. 最大层级限制: 默认限制 10 层,超出则提示用户"BOM层级过深"
  3. 性能: 超过 3 层时前端应显示加载状态,后端加缓存(可选)

五、前端改造

5.1 BOM管理页增强

文件:mes-ui/src/views/mes/masterdata/newBom/index.vue

5.1.1 新增"子BOM物料"输入模式

在新增/编辑BOM明细行时增加一个切换

  • 普通物料行(默认):选择物料,填写用量、损耗率
  • 子BOM行:选择"子装配物料" + 选择该物料对应的BOM版本

前端在选择物料时,如果该物料在 md_new_bom 中有已发布的BOM则自动提示可挂子BOM。

5.1.2 明细行组件增强

在现有的 BOM 明细表格中,每行增加:

  • 列:类型 — 显示「普通」或「子BOM」不同颜色标签区分
  • 列:引用BOM — 当类型为子BOM时显示引用的BOM编号
  • 操作:展开按钮 — 仅子BOM行可用点击后在该行下方嵌入子BOM明细表格

5.2 新增多级BOM视图页

新增 mes-ui/src/views/mes/masterdata/newBom/multiLevel.vue

  • 输入BOM选择 + 需求量
  • 展示:树形结构,多级展开/折叠
  • 每行显示:层级缩进、物料编码、物料名称、用量、成本、是否关键件
  • 底部显示:多级总成本汇总
  • 按钮:「展开为清单」— 切换到扁平视图(物料去重合并)

5.3 API 层新增

文件:mes-ui/src/api/mes/masterdata/newBom.js

// 多级BOM查询
export const getBomMultiLevel = (id, maxLevel) => {
  return request({ url: `/masterdata/newBom/multiLevel/${id}`, params: { maxLevel } })
}
// 多级成本计算
export const getBomMultiLevelCost = (id, quantity) => {
  return request({ url: `/masterdata/newBom/cost/multiLevel/${id}`, params: { quantity } })
}
// BOM展开清单
export const expandBom = (id, quantity) => {
  return request({ url: `/masterdata/newBom/expand/${id}`, params: { quantity } })
}

六、实现计划(分三个阶段)

第一阶段基础设施1-2天

  • 执行 ALTER TABLE 新增字段
  • 修改 NewBomItem.java 实体,添加 subBomIdisSubBomlevel 字段
  • 修改 NewBom.java 添加非持久化展开字段
  • 修改 NewBomMapper.xml 新增字段映射
  • 单元测试验证字段变更不影响现有CRUD

第二阶段核心逻辑2-3天

  • INewBomService.java 新增 3 个接口方法声明
  • NewBomServiceImpl.java 实现 calculateMultiLevelBomCost(递归)
  • NewBomServiceImpl.java 实现 selectBomFullTree(递归树查询)
  • NewBomServiceImpl.java 实现 expandBomToFlatList(去重合并)
  • NewBomController.java 新增 3 个API端点
  • 循环引用和最大层级检测逻辑

第三阶段前端改造2-3天

  • 前端 API 层新增 3 个接口调用
  • 修改 BOM 明细行组件支持子BOM行类型
  • 新增 multiLevel.vue 多级BOM视图页
  • 树形展开/折叠交互
  • 扁平化展开清单视图(物料去重合并展示)

七、风险与注意事项

  1. 循环引用: A BOM -> B BOM -> A BOM 必须被检测并阻止,递归时用 visitedIds 集合
  2. 性能: 深层BOM>5层成本计算较慢考虑异步计算或后台任务
  3. 数据迁移: 已有的 BOM 明细数据 is_sub_bom=0level=0,无需迁移
  4. 版本一致性: 子BOM引用时限定只能引用"已发布"状态的BOM
  5. 兼容旧数据: 新字段 sub_bom_id 允许 NULL向下兼容

八、预期效果

角色 收益
工艺人员 一个页面管理整机BOM可挂子装配BOM无需分开维护多张独立BOM
成本会计 一键计算整机(含所有子级)的真实材料成本
生产计划 展开清单可直接输出为生产领料参考清单
系统 复用现有表结构,改动小,风险可控