Add initial implementation of BOM management classes and data structure

- Created clsBOMManager for managing BOM data
- Added clsCategory and clsMaterialItem for category and material representation
- Implemented methods for loading and organizing BOM data from Excel
- Introduced .gitignore to exclude unnecessary files
- Added metadata JSON for module tracking
This commit is contained in:
Misaka_Company
2026-01-20 08:53:01 +08:00
commit 05601ec1fc
12 changed files with 669 additions and 0 deletions

16
.gitignore vendored Normal file
View File

@@ -0,0 +1,16 @@
__pycache__/
.venv
build
dist
log
*.spec
temp
# Claude 临时文件
.claude/
tmpclaude-*
*.log
*workspace*
*.png
data/
*.xlsm

View File

@@ -0,0 +1,356 @@
' ========================================
' 类模块: clsBOMManager
' 用途: 管理整个BOM数据结构
' 功能:
' 1. 加载和组织BOM数据
' 2. 建立类别层级关系
' 3. 提供物料查询接口
' 4. 支持领料逻辑处理
' ========================================
Option Explicit
' ========================================
' 私有成员变量
' ========================================
Private dictCategories As Object ' Dictionary对象: 类别名称 -> clsCategory对象
' 作用: 快速查找任意类别
Private dictAllMaterials As Object ' Dictionary对象: 物料代号 -> clsMaterialItem对象
' 作用: 快速查找任意物料
Private rootCategories As Collection ' Collection: 存储所有顶层类别(无父类别的类别)
' 作用: 遍历完整的类别树结构
' ========================================
' 类初始化
' 说明: 创建BOMManager实例时自动调用
' ========================================
Private Sub Class_Initialize()
Set dictCategories = CreateObject("Scripting.Dictionary")
Set dictAllMaterials = CreateObject("Scripting.Dictionary")
Set rootCategories = New Collection
End Sub
' ========================================
' LoadData 方法
' 功能: 从Excel工作表加载BOM数据并构建数据结构
' 参数:
' wsConfig - [领料配置]工作表对象,包含类别层级和需要领料的物料
' wsPlatform - [平台配置清单]工作表对象,包含完整的物料信息(代号/名称/数量/条件)
' 处理步骤:
' 1. 从[平台配置清单]加载所有物料的基础信息到dictAllMaterials
' 2. 从[领料配置]加载类别信息,筛选需要领料的物料
' 3. 建立类别的父子关系,构建层级树
' 注意:
' - 只有出现在[领料配置]中的物料才会被添加到类别中
' - 未在[领料配置]中的物料表示不需要领料
' ========================================
Public Sub LoadData(wsConfig As Worksheet, wsPlatform As Worksheet)
Dim i As Long, lastRow As Long
Dim mat As clsMaterialItem
Dim cat As clsCategory
' ========================================
' 第一步: 从平台配置清单加载所有物料的基础信息
' 说明:
' - 读取C列(代号)、D列(名称)、E列(数量)、F列(选择条件)
' - 从第4行开始读取(前3行是标题)
' - 所有物料存入dictAllMaterials字典,以代号为键
' 目的: 建立完整的物料信息库,供后续按代号查询
' ========================================
lastRow = wsPlatform.Cells(wsPlatform.Rows.Count, "C").End(xlUp).row
For i = 4 To lastRow ' 4()
Set mat = New clsMaterialItem
mat.code = Trim(wsPlatform.Cells(i, "C").Value & "") ' 物料代号
mat.Name = Trim(wsPlatform.Cells(i, "D").Value & "") ' 物料名称
On Error Resume Next
mat.Quantity = CDbl(wsPlatform.Cells(i, "E").Value) '
On Error GoTo 0
mat.Condition = Trim(wsPlatform.Cells(i, "F").Value & "") ' 选择条件
'
If mat.code <> "" Then
Set dictAllMaterials(mat.code) = mat
End If
Next i
' ========================================
' 第二步: 从领料配置加载类别信息并建立层级
' 说明:
' - 读取A列(代号)、C列(类别)、D列(上层类别)
' - 从第2行开始读取(第1行是标题)
' - 只有出现在此表中的物料才需要领料
' 处理逻辑:
' 1. 为每个类别创建clsCategory对象
' 2. 从dictAllMaterials中查找对应的物料信息
' 3. 将物料添加到对应的类别中
' ========================================
lastRow = wsConfig.Cells(wsConfig.Rows.Count, "A").End(xlUp).row
For i = 2 To lastRow ' 2
Dim code As String, catName As String, parentCatName As String
code = Trim(wsConfig.Cells(i, "A").Value & "") ' 物料代号
catName = Trim(wsConfig.Cells(i, "C").Value & "") ' 类别名称
parentCatName = Trim(wsConfig.Cells(i, "D").Value & "") ' 上层类别名称
'
If code = "" Then GoTo NextRow
' 确保类别对象存在(如果类别不存在则创建)
If Not dictCategories.Exists(catName) Then
Set cat = New clsCategory
cat.categoryName = catName
cat.ParentCategoryName = parentCatName
Set dictCategories(catName) = cat
End If
' 将物料添加到类别
' 注意: 必须先在dictAllMaterials中查找到完整的物料信息
If dictAllMaterials.Exists(code) Then
Set mat = dictAllMaterials(code)
mat.Category = catName ' 设置物料所属类别
mat.ParentCategory = parentCatName ' 设置物料的上层类别
dictCategories(catName).AddMaterial mat ' 将物料添加到类别对象中
End If
NextRow:
Next i
' ========================================
' 第三步: 建立类别层级关系
' 说明:
' - 遍历所有类别,根据ParentCategoryName建立父子关系
' - 如果类别有父类别,将自己添加到父类别的SubCategories中
' - 如果类别没有父类别,则为根类别,添加到rootCategories中
' 结果:
' - 构建完整的树形结构
' - rootCategories包含所有顶层类别
' - 每个类别的SubCategories包含其直接子类别
' ========================================
Dim key As Variant
For Each key In dictCategories.Keys
Set cat = dictCategories(key)
If cat.ParentCategoryName <> "" Then
' 有父类别,建立父子关系
If dictCategories.Exists(cat.ParentCategoryName) Then
Dim parentCat As clsCategory
Set parentCat = dictCategories(cat.ParentCategoryName)
parentCat.AddSubCategory cat ' 将当前类别添加为父类别的子类别
End If
Else
' 无父类别,是根类别
rootCategories.Add cat, cat.categoryName
End If
Next key
End Sub
' ========================================
' GetRootCategories 方法
' 功能: 获取所有顶层类别的集合
' 返回: Collection对象,包含所有无父类别的clsCategory对象
' 用途:
' - 遍历整个BOM结构时的入口点
' - 生成领料清单时遍历所有根类别
' 示例:
' Dim cats As Collection
' Set cats = bomMgr.GetRootCategories()
' For i = 1 To cats.Count
' Debug.Print cats(i).CategoryName
' Next i
' ========================================
Public Function GetRootCategories() As Collection
Set GetRootCategories = rootCategories
End Function
' ========================================
' GetCategory 方法
' 功能: 根据类别名称获取类别对象
' 参数:
' categoryName - 要查询的类别名称(字符串)
' 返回:
' clsCategory对象 - 如果找到
' Nothing - 如果未找到
' 用途: 快速查找特定类别及其下的物料
' 示例:
' Dim cat As clsCategory
' Set cat = bomMgr.GetCategory("部件")
' If Not cat Is Nothing Then
' Debug.Print cat.Materials.Count & " 个物料"
' End If
' ========================================
Public Function GetCategory(categoryName As String) As clsCategory
If dictCategories.Exists(categoryName) Then
Set GetCategory = dictCategories(categoryName)
Else
Set GetCategory = Nothing
End If
End Function
' ========================================
' GetMaterialsForPicking 方法
' 功能: 获取某类别下需要领料的物料清单(考虑层级逻辑)
' 参数:
' categoryName - 类别名称
' useParent - 可选参数,默认True
' True: 使用父类别物料(默认领料方式)
' False: 使用子类别物料(库存不足时的替代方案)
' 返回: Collection对象,包含clsMaterialItem对象
'
' 业务逻辑说明:
' 1. ("低压接头部件")
' 2. ,("接头"+"弹性元件")
' 3. 如果useParent=True但类别有子类别,仍返回父类别物料
' 4. 如果useParent=False,递归获取所有子类别的物料
'
' 1: "部件"()
' Set mats = bomMgr.GetMaterialsForPicking("部件", True)
' ' 返回: 低压接头部件、高压接头部件等组装好的部件
'
' 2: "部件"()
' Set mats = bomMgr.GetMaterialsForPicking("部件", False)
' ' 返回: 径向低压接头、弹簧管、螺旋管等零件
' ========================================
Public Function GetMaterialsForPicking(categoryName As String, _
Optional useParent As Boolean = True) As Collection
Dim result As Collection
Set result = New Collection
' 查找指定类别
Dim cat As clsCategory
Set cat = GetCategory(categoryName)
If cat Is Nothing Then
' 类别不存在,返回空集合
Set GetMaterialsForPicking = result
Exit Function
End If
Dim i As Long
If useParent Then
' ========================================
' 使用父类别物料(默认领料方式)
' 说明:
' - 直接返回当前类别下的所有物料
' - 即使该类别有子类别,也仍然返回父类别物料
' - 这是正常情况下的领料方式(领取组装好的部件)
' ========================================
Dim m As clsMaterialItem
For i = 1 To cat.Materials.Count
Set m = cat.Materials(i)
result.Add m
Next i
Else
' ========================================
' 使用子类别物料(库存不足时的替代方案)
' 说明:
' - 如果当前类别有子类别,递归获取所有子类别的物料
' - 如果当前类别是叶子类别(无子类别),返回本类别物料
' - 这用于父类别库存不足,需要领取零件自行组装的情况
' 示例:
' "低压接头部件"
' "径向低压接头"+"弹簧管"
' ========================================
If cat.HasSubCategories Then
' 有子类别,递归获取所有子类别的物料
Dim subCat As clsCategory
Dim j As Long
For j = 1 To cat.SubCategories.Count
Set subCat = cat.SubCategories(j)
Dim subMats As Collection
' 递归调用,继续展开子类别
Set subMats = GetMaterialsForPicking(subCat.categoryName, False)
Dim k As Long
For k = 1 To subMats.Count
result.Add subMats(k)
Next k
Next j
Else
' 叶子类别,返回本类别物料
For i = 1 To cat.Materials.Count
Set m = cat.Materials(i)
result.Add m
Next i
End If
End If
Set GetMaterialsForPicking = result
End Function
' ========================================
' PrintCategoryTree 方法
' 功能: 将类别树结构打印到工作表(用于调试和查看)
' 参数:
' ws - 输出的目标工作表对象
' 输出格式:
' - 第一列: 类别名称(带缩进显示层级)
' - 第二列: 物料数量信息
' - 第三列: 选择条件
' 说明:
' - 使用缩进显示类别层级(每层2个空格)
' - 递归打印所有子类别和物料
' - 便于验证数据结构是否正确
' 示例输出:
' 表壳 (物料数:1)
' - 01091004312 表壳(本色) 数量:1 条件:
' 部件 (物料数:20)
' - 01011019001 低压接头部件 数量:1 条件:lcfw=M02...
' 接头 (物料数:18)
' - 01081013833 径向低压接头 数量:1 条件:gclj=Z12...
' ========================================
Public Sub PrintCategoryTree(ws As Worksheet)
Dim row As Long
row = 1
ws.Cells(row, 1).Value = "类别层级结构"
row = row + 1
' 遍历所有根类别,递归打印整个树
Dim rootCat As clsCategory
Dim i As Long
For i = 1 To rootCategories.Count
Set rootCat = rootCategories(i)
Call PrintCategory(ws, rootCat, row, 0)
Next i
End Sub
' ========================================
' PrintCategory 方法 (私有方法)
' 功能: 递归打印单个类别及其子类别(供PrintCategoryTree调用)
' 参数:
' ws - 输出的工作表对象
' cat - 要打印的类别对象
' row - 当前输出行号(ByRef,会被修改)
' level - 当前层级深度(0=根类别,1=一级子类别...)
' 说明:
' - 使用递归方式遍历整个类别树
' - 根据level参数计算缩进空格数
' - 先打印类别名,再打印该类别的所有物料,最后递归打印子类别
' ========================================
Private Sub PrintCategory(ws As Worksheet, cat As clsCategory, _
ByRef row As Long, level As Integer)
' (2)
Dim indent As String
indent = String(level * 2, " ")
'
ws.Cells(row, 1).Value = indent & cat.categoryName & _
" (物料数:" & cat.Materials.Count & ")"
row = row + 1
' 打印该类别下的所有物料
Dim mat As clsMaterialItem
Dim i As Long
For i = 1 To cat.Materials.Count
Set mat = cat.Materials(i)
' 2,"- "
ws.Cells(row, 1).Value = indent & " - " & mat.code & " " & mat.Name
ws.Cells(row, 2).Value = "数量:" & mat.Quantity
ws.Cells(row, 3).Value = "条件:" & mat.Condition
row = row + 1
Next i
' 递归打印所有子类别
Dim subCat As clsCategory
Dim j As Long
For j = 1 To cat.SubCategories.Count
Set subCat = cat.SubCategories(j)
' ,1
Call PrintCategory(ws, subCat, row, level + 1)
Next j
End Sub

View File

@@ -0,0 +1,40 @@
' ========================================
' 类模块: clsCategory
' 用途: 表示物料类别及其层级关系
' ========================================
Option Explicit
Public categoryName As String
Public ParentCategoryName As String
Public Materials As Collection ' 存储 clsMaterialItem 对象
Public SubCategories As Collection ' 存储子类别 clsCategory 对象
Public IsLeafCategory As Boolean ' 是否叶子类别(无子类别)
Private Sub Class_Initialize()
Set Materials = New Collection
Set SubCategories = New Collection
IsLeafCategory = True
End Sub
' 添加物料
Public Sub AddMaterial(mat As clsMaterialItem)
Materials.Add mat, mat.code
End Sub
' 添加子类别
Public Sub AddSubCategory(cat As clsCategory)
SubCategories.Add cat, cat.categoryName
IsLeafCategory = False
End Sub
' 获取物料(按代号)
Public Function GetMaterial(code As String) As clsMaterialItem
On Error Resume Next
Set GetMaterial = Materials(code)
On Error GoTo 0
End Function
'
Public Function HasSubCategories() As Boolean
HasSubCategories = (SubCategories.Count > 0)
End Function

View File

@@ -0,0 +1,12 @@
' ========================================
' 类模块: clsMaterialItem
' 用途: 表示单个物料项
' ========================================
Option Explicit
Public code As String ' 代号
Public Name As String ' 名称
Public Quantity As Double ' 数量
Public Condition As String ' 选择条件
Public Category As String ' 类别
Public ParentCategory As String '

View File

View File

View File

View File

View File

View File

View File

@@ -0,0 +1,180 @@
' ========================================
' 模块: modBOMTest
' 用途: 测试和使用BOM数据结构-同步测试2
' ========================================
Option Explicit
Sub TestBOMStructure()
' 初始化BOM管理器
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
' 打印类别树结构到新工作表
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
Dim cats As Collection
Dim i As Integer
Set cats = bomMgr.GetRootCategories()
For i = 1 To cats.Count
Debug.Print cats(i).categoryName
Next i
MsgBox "BOM数据结构加载完成!" & vbCrLf & _
"请查看 'BOM结构' 工作表", vbInformation
End Sub
' 示例: 获取特定类别的物料
Sub GetCategoryMaterials()
Dim bomMgr As New clsBOMManager
Dim wsConfig As Worksheet, wsPlatform As Worksheet
Set wsConfig = ThisWorkbook.Worksheets("领料配置")
Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单")
bomMgr.LoadData wsConfig, wsPlatform
' 获取"部件"类别的物料(使用父类别)
Dim Materials As Collection
Set Materials = bomMgr.GetMaterialsForPicking("部件", True)
Debug.Print "部件类别物料数量(父类别): " & Materials.Count
' 获取"部件"类别的物料(使用子类别)
Set Materials = bomMgr.GetMaterialsForPicking("部件", False)
Debug.Print "部件类别物料数量(子类别展开): " & Materials.Count
' 遍历物料
Dim mat As clsMaterialItem
For Each mat In Materials
Debug.Print mat.code & " - " & mat.Name & _
" | 数量:" & mat.Quantity & _
" | 条件:" & mat.Condition
Next mat
End Sub
' 示例: 根据产品型号生成领料清单
Sub GeneratePickingList()
Dim bomMgr As New clsBOMManager
Dim wsConfig As Worksheet, wsPlatform As Worksheet
Set wsConfig = ThisWorkbook.Worksheets("领料配置")
Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单")
bomMgr.LoadData wsConfig, wsPlatform
' 创建领料清单工作表
Dim wsPickList As Worksheet
On Error Resume Next
Application.DisplayAlerts = False
ThisWorkbook.Worksheets("领料清单").Delete
Application.DisplayAlerts = True
On Error GoTo 0
Set wsPickList = ThisWorkbook.Worksheets.Add
wsPickList.Name = "领料清单"
' 写入表头
Dim row As Long
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
' 遍历所有根类别
Dim rootCats As Collection
Set rootCats = bomMgr.GetRootCategories
Dim cat As clsCategory
Dim Materials As Collection
Dim mat As clsMaterialItem
Dim i As Long, j As Long
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
' 格式化表格
wsPickList.Range("A1:F1").Font.Bold = True
wsPickList.Columns("A:F").AutoFit
MsgBox "领料清单生成完成!", vbInformation
End Sub
' 示例: 查询特定物料信息
Sub QueryMaterialInfo()
Dim bomMgr As New clsBOMManager
Dim wsConfig As Worksheet, wsPlatform As Worksheet
Set wsConfig = ThisWorkbook.Worksheets("领料配置")
Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单")
bomMgr.LoadData wsConfig, wsPlatform
' 查询特定类别
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.SubCategories.Count
Debug.Print "是否叶子类别: " & cat.IsLeafCategory
' 列出所有物料
Dim mat As clsMaterialItem
Dim i As Long
For i = 1 To cat.Materials.Count
Set mat = cat.Materials(i)
Debug.Print " - " & mat.code & ": " & mat.Name
Next i
' 列出所有子类别
Dim subCat As clsCategory
Dim j As Long
For j = 1 To cat.SubCategories.Count
Set subCat = cat.SubCategories(j)
Debug.Print " 子类别: " & subCat.categoryName & _
" (物料数:" & subCat.Materials.Count & ")"
Next j
End If
End Sub

65
VBA/vba_metadata.json Normal file
View File

@@ -0,0 +1,65 @@
{
"source_file": "C:\\Users\\Administrator\\Desktop\\新BOM\\AutoBOM\\YTHN-100.A0.532-BOM-1.2版 Claude.xlsm",
"modules": {
"ThisWorkbook.cls": {
"name": "ThisWorkbook",
"type": "DocumentModules",
"attributes": {},
"file": "DocumentModules\\ThisWorkbook.cls"
},
"Sheet3.cls": {
"name": "Sheet3",
"type": "DocumentModules",
"attributes": {},
"file": "DocumentModules\\Sheet3.cls"
},
"Sheet1.cls": {
"name": "Sheet1",
"type": "DocumentModules",
"attributes": {},
"file": "DocumentModules\\Sheet1.cls"
},
"Sheet2.cls": {
"name": "Sheet2",
"type": "DocumentModules",
"attributes": {},
"file": "DocumentModules\\Sheet2.cls"
},
"Sheet4.cls": {
"name": "Sheet4",
"type": "DocumentModules",
"attributes": {},
"file": "DocumentModules\\Sheet4.cls"
},
"clsCategory.cls": {
"name": "clsCategory",
"type": "ClassModules",
"attributes": {},
"file": "ClassModules\\clsCategory.cls"
},
"clsMaterialItem.cls": {
"name": "clsMaterialItem",
"type": "ClassModules",
"attributes": {},
"file": "ClassModules\\clsMaterialItem.cls"
},
"modBOMProcessor.bas": {
"name": "modBOMProcessor",
"type": "Modules",
"attributes": {},
"file": "Modules\\modBOMProcessor.bas"
},
"clsBOMManager.cls": {
"name": "clsBOMManager",
"type": "ClassModules",
"attributes": {},
"file": "ClassModules\\clsBOMManager.cls"
},
"Sheet6.cls": {
"name": "Sheet6",
"type": "DocumentModules",
"attributes": {},
"file": "DocumentModules\\Sheet6.cls"
}
}
}