# clsBOMManager 类使用说明 ## 概述 `clsBOMManager` 是 AutoBOM 系统的核心控制器类,负责管理整个 BOM(物料清单)数据结构。它从 Excel 工作表加载数据,构建层级化的类别树,并提供物料查询和领料逻辑处理功能。 --- ## 类初始化 ```vba Dim bomMgr As New clsBOMManager ``` 创建实例时,会自动初始化以下内部数据结构: - `dictCategories` - 类别字典(类别名称 → clsCategory 对象) - `dictAllMaterials` - 物料字典(物料代号 → clsMaterialItem 对象) - `rootCategories` - 根类别集合(顶层类别) --- ## 公开方法 ### 1. LoadData 方法 **功能**:从 Excel 工作表加载 BOM 数据并构建数据结构 **语法**: ```vba Public Sub LoadData(wsConfig As Worksheet, wsPlatform As Worksheet) ``` **参数**: | 参数 | 类型 | 说明 | |------|------|------| | wsConfig | Worksheet | 领料配置工作表,定义类别层级和需要领料的物料 | | wsPlatform | Worksheet | 平台配置清单工作表,包含完整的物料信息 | **数据要求**: **领料配置** 工作表格式: - **第 1 行**:标题行 - **第 2 行起**:数据行 - A 列:物料代号 - C 列:类别名称 - D 列:上层类别名称 **平台配置清单** 工作表格式: - **第 1-3 行**:标题行 - **第 4 行起**:数据行 - C 列:物料代号 - D 列:物料名称 - E 列:物料数量 - F 列:选择条件 **处理逻辑**: 1. 从"平台配置清单"加载所有物料的基础信息到 `dictAllMaterials` 2. 从"领料配置"加载类别信息,筛选需要领料的物料 3. 建立类别的父子关系,构建层级树 **重要说明**: - 只有出现在"领料配置"中的物料才会被添加到类别中 - 未在"领料配置"中的物料表示不需要领料,但仍存在于物料字典中 **使用示例**: ```vba Dim bomMgr As New clsBOMManager Dim wsConfig As Worksheet Dim wsPlatform As Worksheet Set wsConfig = ThisWorkbook.Worksheets("领料配置") Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单") bomMgr.LoadData wsConfig, wsPlatform ``` --- ### 2. GetRootCategories 方法 **功能**:获取所有顶层类别的集合 **语法**: ```vba Public Function GetRootCategories() As Collection ``` **返回值**: - `Collection` 对象,包含所有无父类别的 `clsCategory` 对象 **用途**: - 遍历整个 BOM 结构时的入口点 - 生成领料清单时遍历所有根类别 **使用示例**: ```vba Dim rootCats As Collection Dim cat As clsCategory Dim i As Long Set rootCats = bomMgr.GetRootCategories() For i = 1 To rootCats.Count Set cat = rootCats(i) Debug.Print "根类别: " & cat.categoryName Debug.Print " 物料数: " & cat.Materials.Count Debug.Print " 子类别数: " & cat.SubCategories.Count Next i ``` --- ### 3. GetCategory 方法 **功能**:根据类别名称获取类别对象 **语法**: ```vba Public Function GetCategory(categoryName As String) As clsCategory ``` **参数**: | 参数 | 类型 | 说明 | |------|------|------| | categoryName | String | 要查询的类别名称 | **返回值**: - 找到时:返回 `clsCategory` 对象 - 未找到时:返回 `Nothing` **用途**:快速查找特定类别及其下的物料 **使用示例**: ```vba Dim cat As clsCategory Set cat = bomMgr.GetCategory("部件") If Not cat Is Nothing Then Debug.Print "类别: " & cat.categoryName Debug.Print "父类别: " & cat.ParentCategoryName Debug.Print "物料数: " & cat.Materials.Count Debug.Print "是否叶子类别: " & cat.IsLeafCategory End If ``` --- ### 4. GetMaterialsForPicking 方法 **功能**:获取某类别下需要领料的物料清单(支持层级逻辑) **语法**: ```vba Public Function GetMaterialsForPicking(categoryName As String, _ Optional useParent As Boolean = True) As Collection ``` **参数**: | 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | categoryName | String | - | 类别名称 | | useParent | Boolean | True | 领料方式:True=父类别物料,False=子类别物料 | **返回值**: - `Collection` 对象,包含 `clsMaterialItem` 对象 **业务逻辑说明**: #### 父类别模式 (useParent=True) - 这是**默认的领料方式** - 直接返回当前类别下的所有物料 - 即使该类别有子类别,也仍然返回父类别物料 - 用于领取组装好的部件 **示例**: ```vba ' 获取"部件"类别的父类别物料 Set materials = bomMgr.GetMaterialsForPicking("部件", True) ' 返回:低压接头部件、高压接头部件等组装好的部件 ``` #### 子类别模式 (useParent=False) - 这是**库存不足时的替代方案** - 如果当前类别有子类别,递归获取所有子类别的物料 - 如果当前类别是叶子类别(无子类别),返回本类别物料 - 用于父类别库存不足,需要领取零件自行组装的情况 **示例**: ```vba ' 获取"部件"类别的子类别展开物料 Set materials = bomMgr.GetMaterialsForPicking("部件", False) ' 返回:径向低压接头、弹簧管、螺旋管等零件 ``` **层级结构示例**: ``` 部件 (父类别) ├── 低压接头部件 (物料) ├── 高压接头部件 (物料) └── 接头 (子类别) ├── 径向低压接头 (物料) ├── 轴向高压接头 (物料) └── 弹性元件 (孙类别) └── 弹簧管 (物料) ``` **使用示例**: ```vba Dim materials As Collection Dim mat As clsMaterialItem Dim i As Long ' 默认使用父类别物料 Set materials = bomMgr.GetMaterialsForPicking("部件", True) Debug.Print "父类别物料数: " & materials.Count For i = 1 To materials.Count Set mat = materials(i) Debug.Print mat.code & " - " & mat.Name & _ " | 数量:" & mat.Quantity & _ " | 条件:" & mat.Condition Next i ' 库存不足时,使用子类别物料 Set materials = bomMgr.GetMaterialsForPicking("部件", False) Debug.Print "子类别展开物料数: " & materials.Count ``` --- ### 5. PrintCategoryTree 方法 **功能**:将类别树结构打印到工作表(用于调试和查看) **语法**: ```vba Public Sub PrintCategoryTree(ws As Worksheet) ``` **参数**: | 参数 | 类型 | 说明 | |------|------|------| | ws | Worksheet | 输出的目标工作表对象 | **输出格式**: - 第 1 列:类别名称(带缩进显示层级) - 第 2 列:物料数量信息 - 第 3 列:选择条件 **缩进规则**:每层级 2 个空格 **输出示例**: ``` 表壳 (物料数:1) - 01091004312 表壳(本色) 数量:1 条件: 部件 (物料数:20) - 01011019001 低压接头部件 数量:1 条件:lcfw=M02... 接头 (物料数:18) - 01081013833 径向低压接头 数量:1 条件:gclj=Z12... ``` **使用示例**: ```vba Dim wsOutput As Worksheet ' 创建新工作表 On Error Resume Next Application.DisplayAlerts = False ThisWorkbook.Worksheets("BOM结构").Delete Application.DisplayAlerts = True On Error GoTo 0 Set wsOutput = ThisWorkbook.Worksheets.Add wsOutput.Name = "BOM结构" ' 打印类别树 bomMgr.PrintCategoryTree wsOutput ``` --- ## 典型使用场景 ### 场景 1:生成领料清单 ```vba Sub GeneratePickingList() Dim bomMgr As New clsBOMManager Dim wsConfig As Worksheet, wsPlatform As Worksheet Dim wsPickList As Worksheet Dim rootCats As Collection Dim cat As clsCategory Dim materials As Collection Dim mat As clsMaterialItem Dim row As Long Dim i As Long, j As Long ' 1. 加载数据 Set wsConfig = ThisWorkbook.Worksheets("领料配置") Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单") bomMgr.LoadData wsConfig, wsPlatform ' 2. 创建输出工作表 Application.DisplayAlerts = False On Error Resume Next ThisWorkbook.Worksheets("领料清单").Delete On Error GoTo 0 Application.DisplayAlerts = True Set wsPickList = ThisWorkbook.Worksheets.Add wsPickList.Name = "领料清单" ' 3. 写入表头 row = 1 wsPickList.Cells(row, 1).Value = "代号" wsPickList.Cells(row, 2).Value = "名称" wsPickList.Cells(row, 3).Value = "类别" wsPickList.Cells(row, 4).Value = "数量" wsPickList.Cells(row, 5).Value = "选择条件" wsPickList.Cells(row, 6).Value = "领料方式" row = row + 1 ' 4. 遍历所有根类别并生成清单 Set rootCats = bomMgr.GetRootCategories For i = 1 To rootCats.Count Set cat = rootCats(i) ' 默认使用父类别物料 Set materials = bomMgr.GetMaterialsForPicking(cat.categoryName, True) For j = 1 To materials.Count Set mat = materials(j) wsPickList.Cells(row, 1).Value = mat.code wsPickList.Cells(row, 2).Value = mat.Name wsPickList.Cells(row, 3).Value = mat.Category wsPickList.Cells(row, 4).Value = mat.Quantity wsPickList.Cells(row, 5).Value = mat.Condition wsPickList.Cells(row, 6).Value = "父类别" row = row + 1 Next j Next i ' 5. 格式化表格 wsPickList.Range("A1:F1").Font.Bold = True wsPickList.Columns("A:F").AutoFit MsgBox "领料清单生成完成!", vbInformation End Sub ``` ### 场景 2:查询特定类别信息 ```vba Sub QueryCategoryInfo() Dim bomMgr As New clsBOMManager Dim wsConfig As Worksheet, wsPlatform As Worksheet Dim cat As clsCategory Dim mat As clsMaterialItem Dim subCat As clsCategory Dim i As Long ' 加载数据 Set wsConfig = ThisWorkbook.Worksheets("领料配置") Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单") bomMgr.LoadData wsConfig, wsPlatform ' 查询特定类别 Set cat = bomMgr.GetCategory("部件") If Not cat Is Nothing Then Debug.Print "========== 类别信息 ==========" Debug.Print "类别名称: " & cat.categoryName Debug.Print "父类别: " & cat.ParentCategoryName Debug.Print "物料数量: " & cat.Materials.Count Debug.Print "子类别数量: " & cat.SubCategories.Count Debug.Print "是否叶子类别: " & cat.IsLeafCategory Debug.Print "" ' 列出所有物料 Debug.Print "---------- 物料列表 ----------" For i = 1 To cat.Materials.Count Set mat = cat.Materials(i) Debug.Print " " & mat.code & ": " & mat.Name & _ " (数量:" & mat.Quantity & _ ", 条件:" & mat.Condition & ")" Next i Debug.Print "" ' 列出所有子类别 Debug.Print "---------- 子类别列表 ----------" For i = 1 To cat.SubCategories.Count Set subCat = cat.SubCategories(i) Debug.Print " " & subCat.categoryName & _ " (物料数:" & subCat.Materials.Count & ")" Next i Else Debug.Print "类别不存在" End If End Sub ``` ### 场景 3:根据库存情况选择领料方式 ```vba Sub SmartPicking() Dim bomMgr As New clsBOMManager Dim materials As Collection Dim mat As clsMaterialItem Dim categoryName As String Dim i As Long ' 加载数据 bomMgr.LoadData _ ThisWorkbook.Worksheets("领料配置"), _ ThisWorkbook.Worksheets("平台配置清单") categoryName = "部件" ' 尝试获取父类别物料 Set materials = bomMgr.GetMaterialsForPicking(categoryName, True) ' 检查库存是否充足(这里需要连接实际的库存系统) Dim isStockSufficient As Boolean isStockSufficient = CheckStock(materials) ' 假设的库存检查函数 If isStockSufficient Then Debug.Print "使用父类别领料方式" Else Debug.Print "父类别库存不足,改用子类别领料方式" Set materials = bomMgr.GetMaterialsForPicking(categoryName, False) End If ' 输出物料清单 For i = 1 To materials.Count Set mat = materials(i) Debug.Print mat.code & " " & mat.Name Next i End Sub ``` --- ## 辅助类说明 ### clsCategory 类 表示物料类别及其层级关系。 **公共属性**: | 属性 | 类型 | 说明 | |------|------|------| | categoryName | String | 类别名称 | | ParentCategoryName | String | 父类别名称 | | Materials | Collection | 该类别下的物料集合 | | SubCategories | Collection | 子类别集合 | | IsLeafCategory | Boolean | 是否为叶子类别(无子类别) | **公共方法**: - `AddMaterial(mat As clsMaterialItem)` - 添加物料 - `AddSubCategory(cat As clsCategory)` - 添加子类别 - `GetMaterial(code As String) As clsMaterialItem` - 获取指定代号的物料 - `HasSubCategories() As Boolean` - 检查是否有子类别 ### clsMaterialItem 类 表示单个物料项。 **公共属性**: | 属性 | 类型 | 说明 | |------|------|------| | code | String | 物料代号 | | Name | String | 物料名称 | | Quantity | Double | 物料数量 | | Condition | String | 选择条件 | | Category | String | 所属类别 | | ParentCategory | String | 上层类别 | --- ## 注意事项 1. **数据加载顺序**:必须先调用 `LoadData()` 方法,才能使用其他查询方法 2. **工作表名称**:确保工作表名称与代码中的名称一致: - "领料配置" - "平台配置清单" 3. **空值处理**:使用 `GetCategory()` 方法时,务必检查返回值是否为 `Nothing` 4. **领料方式选择**: - 正常情况使用 `useParent=True`(领取组装好的部件) - 仅在库存不足时使用 `useParent=False`(领取零件自行组装) 5. **数据一致性**:修改 Excel 数据后,需要重新调用 `LoadData()` 重新加载数据 6. **内存管理**:使用完毕后,VBA 会自动清理对象,无需手动释放 --- ## 常见问题 ### Q1: 如何判断某个类别是否存在? ```vba Dim cat As clsCategory Set cat = bomMgr.GetCategory("类别名") If Not cat Is Nothing Then ' 类别存在 Else ' 类别不存在 End If ``` ### Q2: 如何获取所有类别的名称? ```vba Sub ListAllCategories() ' 需要递归遍历所有类别 ' 可以使用 PrintCategoryTree 方法输出到工作表查看 End Sub ``` ### Q3: 父类别和子类别物料有什么区别? - **父类别物料**:组装好的成品部件,如"低压接头部件" - **子类别物料**:组成部件的零件,如"径向低压接头"、"弹簧管"等 ### Q4: 如何处理物料选择条件? ```vba Dim mat As clsMaterialItem ' ... If mat.Condition <> "" Then ' 根据条件选择合适的物料 ' 条件格式如:lcfw=M02;gclj=Z12 ' 需要根据产品配置解析这些条件 End If ``` --- ## 版本信息 - **类名称**:clsBOMManager - **版本**:1.0 - **最后更新**:2025 - **依赖类**:clsCategory, clsMaterialItem