Files
AutoBOM/reference_docs/clsBOMManager_LoadData流程分析.md
Misaka_Company fd414f7673 docs: reorganize documentation structure and add analysis guidelines
- Move existing documentation files to reference_docs/ directory
- Add documentation guidelines section to CLAUDE.md
- Add clsBOMManager LoadData flow analysis with Mermaid diagrams

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-29 09:30:29 +08:00

440 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# clsBOMManager.LoadData 方法流程分析
## 方法概述
`LoadData``clsBOMManager` 类的核心方法,负责从 Excel 工作表加载 BOM 数据并构建完整的层级数据结构。
## 方法签名
```vba
Public Sub LoadData(wsConfig As Worksheet, wsPlatform As Worksheet)
```
### 参数说明
| 参数 | 类型 | 说明 |
|------|------|------|
| `wsConfig` | Worksheet | [领料配置]工作表,包含类别层级和需要领料的物料 |
| `wsPlatform` | Worksheet | [平台配置清单]工作表,包含完整的物料信息 |
## 整体流程图
```mermaid
flowchart TD
Start([开始 LoadData]) --> Step1[第一步: 加载物料基础信息]
Step1 --> Step2[第二步: 加载类别信息并关联物料]
Step2 --> Step3[第三步: 建立类别层级关系]
Step3 --> End([结束])
style Start fill:#e1f5e1
style End fill:#ffe1e1
style Step1 fill:#e1f0ff
style Step2 fill:#fff4e1
style Step3 fill:#f0e1ff
```
## 详细流程分析
### 第一步:从平台配置清单加载所有物料的基础信息
```mermaid
flowchart TD
S1_Start([开始第一步]) --> S1_Init[初始化: 获取最后一行行号]
S1_Init --> S1_Loop{循环 i = 4 到 lastRow}
S1_Loop -->|i += 1| S1_Read[读取第 i 行数据]
S1_Read --> S1_Create[创建 clsMaterialItem 对象]
S1_Create --> S1_Assign[赋值: code, Name, Quantity, Condition]
S1_Assign --> S1_Check{code 是否非空?}
S1_Check -->|是| S1_Add[添加到 dictAllMaterials<br/>键: code, 值: mat]
S1_Check -->|否| S1_Next[跳过]
S1_Add --> S1_Next
S1_Next --> S1_Loop
S1_Loop -->|i > lastRow| S1_End([第一步完成])
style S1_Start fill:#e1f5e1
style S1_End fill:#ffe1e1
style S1_Add fill:#c8e6c9
style S1_Check fill:#fff9c4
```
**数据来源**[平台配置清单] 工作表
| 列 | 字段 | 说明 |
|----|------|------|
| C | code | 物料代号 |
| D | Name | 物料名称 |
| E | Quantity | 物料数量 |
| F | Condition | 选择条件 |
**数据结构**
```
dictAllMaterials: Dictionary<String, clsMaterialItem>
├── "01011019001" → clsMaterialItem{code, Name, Quantity, Condition}
├── "01081013833" → clsMaterialItem{...}
└── ...
```
**关键代码**
```vba
lastRow = wsPlatform.Cells(wsPlatform.Rows.Count, "C").End(xlUp).row
For i = 4 To lastRow
Set mat = New clsMaterialItem
mat.code = Trim(wsPlatform.Cells(i, "C").value & "")
mat.Name = Trim(wsPlatform.Cells(i, "D").value & "")
mat.Quantity = CDbl(wsPlatform.Cells(i, "E").value)
mat.Condition = Trim(wsPlatform.Cells(i, "F").value & "")
If mat.code <> "" Then
Set dictAllMaterials(mat.code) = mat
End If
Next i
```
---
### 第二步:从领料配置加载类别信息并关联物料
```mermaid
flowchart TD
S2_Start([开始第二步]) --> S2_Init[初始化: 获取最后一行行号]
S2_Init --> S2_Loop{循环 i = 2 到 lastRow}
S2_Loop -->|i += 1| S2_Read[读取第 i 行数据<br/>code, catName, parentCatName]
S2_Read --> S2_CheckCode{code 是否为空?}
S2_CheckCode -->|是| S2_NextRow[跳到下一行]
S2_CheckCode -->|否| S2_CheckCat{类别是否已存在?}
S2_CheckCat -->|否| S2_CreateCat[创建新的 clsCategory 对象<br/>设置 categoryName 和 ParentCategoryName<br/>添加到 dictCategories]
S2_CheckCat -->|是| S2_Exists[类别已存在]
S2_CreateCat --> S2_CheckMat{物料在<br/>dictAllMaterials?}
S2_Exists --> S2_CheckMat
S2_CheckMat -->|是| S2_UpdateMat[更新物料信息:<br/>mat.Category = catName<br/>mat.ParentCategory = parentCatName<br/>添加到类别 materials 集合]
S2_CheckMat -->|否| S2_SkipMat[物料不在库中,跳过]
S2_UpdateMat --> S2_NextRow
S2_SkipMat --> S2_NextRow
S2_NextRow --> S2_Loop
S2_Loop -->|i > lastRow| S2_End([第二步完成])
style S2_Start fill:#e1f5e1
style S2_End fill:#ffe1e1
style S2_CreateCat fill:#bbdefb
style S2_UpdateMat fill:#c8e6c9
style S2_CheckCat fill:#fff9c4
style S2_CheckMat fill:#fff9c4
```
**数据来源**[领料配置] 工作表
| 列 | 字段 | 说明 |
|----|------|------|
| A | code | 物料代号 |
| C | catName | 类别名称 |
| D | parentCatName | 上层类别名称 |
**数据结构**
```
dictCategories: Dictionary<String, clsCategory>
├── "表壳" → clsCategory{categoryName, materials[], SubCategories[]}
├── "部件" → clsCategory{...}
└── ...
```
**关键代码**
```vba
lastRow = wsConfig.Cells(wsConfig.Rows.Count, "A").End(xlUp).row
For i = 2 To lastRow
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
If dictAllMaterials.Exists(code) Then
Set mat = dictAllMaterials(code)
mat.Category = catName
mat.ParentCategory = parentCatName
dictCategories(catName).AddMaterial mat
End If
Next i
```
**业务逻辑说明**
- 只有出现在 [领料配置] 中的物料才会被添加到类别中
- 未在 [领料配置] 中的物料表示不需要领料
---
### 第三步:建立类别层级关系
```mermaid
flowchart TD
S3_Start([开始第三步]) --> S3_Loop{遍历 dictCategories<br/>所有键}
S3_Loop -->|下一个键| S3_GetCat[获取类别对象 cat]
S3_GetCat --> S3_CheckParent{ParentCategoryName<br/>是否为空?}
S3_CheckParent -->|否, 有父类别| S3_ParentExists{父类别<br/>存在?}
S3_CheckParent -->|是, 无父类别| S3_AddRoot[添加到 rootCategories<br/>作为根类别]
S3_ParentExists -->|是| S3_AddSub[添加到父类别的<br/>SubCategories 集合]
S3_ParentExists -->|否| S3_Orphan[父类别不存在<br/>跳过建立关系]
S3_AddRoot --> S3_Next
S3_AddSub --> S3_Next
S3_Orphan --> S3_Next
S3_Next --> S3_Loop
S3_Loop -->|遍历完成| S3_End([第三步完成])
style S3_Start fill:#e1f5e1
style S3_End fill:#ffe1e1
style S3_AddRoot fill:#ffccbc
style S3_AddSub fill:#b2dfdb
```
**数据结构**
```
rootCategories: Collection<clsCategory>
├── "表壳" (根类别)
├── "部件" (根类别)
│ └── SubCategories:
│ ├── "接头" (子类别)
│ └── "弹性元件" (子类别)
└── "机芯" (根类别)
```
**关键代码**
```vba
For Each key In dictCategories.Keys
Set cat = dictCategories(key)
If cat.ParentCategoryName <> "" Then
If dictCategories.Exists(cat.ParentCategoryName) Then
Set parentCat = dictCategories(cat.ParentCategoryName)
parentCat.AddSubCategory cat
End If
Else
rootCategories.Add cat, cat.categoryName
End If
Next key
```
**层级关系构建逻辑**
1. 遍历所有类别
2. 如果类别有父类别 → 建立父子关系(调用父类别的 `AddSubCategory` 方法)
3. 如果类别无父类别 → 作为根类别,添加到 `rootCategories`
---
## 数据结构总结
### 类的私有成员变量
```mermaid
classDiagram
class clsBOMManager {
-dictCategories: Dictionary
-dictAllMaterials: Dictionary
-rootCategories: Collection
+LoadData(wsConfig, wsPlatform)
+GetRootCategories() Collection
+GetCategory(categoryName) clsCategory
}
class clsCategory {
+categoryName: String
+ParentCategoryName: String
+materials: Collection
+SubCategories: Collection
+AddMaterial(mat)
+AddSubCategory(cat)
+HasSubCategories: Boolean
}
class clsMaterialItem {
+code: String
+Name: String
+Quantity: Double
+Condition: String
+Category: String
+ParentCategory: String
}
clsBOMManager "1" --> "*" clsCategory : 管理
clsCategory "1" --> "*" clsMaterialItem : 包含
clsCategory "1" --> "*" clsCategory : 父子关系
```
### 三个核心数据容器
| 数据容器 | 类型 | 键/索引 | 值 | 用途 |
|---------|------|---------|-----|------|
| `dictAllMaterials` | Dictionary | 物料代号 (String) | clsMaterialItem | 快速查找任意物料的完整信息 |
| `dictCategories` | Dictionary | 类别名称 (String) | clsCategory | 快速查找任意类别 |
| `rootCategories` | Collection | 索引 (Long) | clsCategory | 遍历完整的类别树结构 |
---
## 流程时序图
```mermaid
sequenceDiagram
participant Caller as 调用者
participant LoadData as LoadData方法
participant WSPlatform as [平台配置清单]
participant WSConfig as [领料配置]
participant DictMat as dictAllMaterials
participant DictCat as dictCategories
participant RootCats as rootCategories
Caller->>LoadData: LoadData(wsConfig, wsPlatform)
Note over LoadData, WSPlatform: 第一步: 加载物料库
LoadData->>WSPlatform: 读取第4-末行, C-F列
WSPlatform-->>LoadData: 返回物料数据
loop 每一行物料
LoadData->>DictMat: 添加物料 (代号→对象)
end
Note over LoadData, WSConfig: 第二步: 建立类别与物料关联
LoadData->>WSConfig: 读取第2-末行, A/C/D列
WSConfig-->>LoadData: 返回类别配置
loop 每一行配置
LoadData->>DictCat: 类别存在?
alt 类别不存在
LoadData->>DictCat: 创建新类别
end
LoadData->>DictMat: 查找物料信息
alt 物料存在
LoadData->>DictCat: 添加物料到类别
end
end
Note over LoadData, RootCats: 第三步: 构建层级树
loop 遍历所有类别
LoadData->>DictCat: 获取类别
alt 有父类别
LoadData->>DictCat: 添加到父类别的SubCategories
else 无父类别
LoadData->>RootCats: 添加为根类别
end
end
LoadData-->>Caller: 完成
```
---
## 重要业务规则
### 1. 物料筛选规则
- ✅ 在 [领料配置] 中的物料 → **需要领料**,会被添加到类别中
- ❌ 不在 [领料配置] 中的物料 → **不需要领料**,仅在 `dictAllMaterials`
### 2. 类别层级规则
- 根类别:`ParentCategoryName` 为空字符串 `""`
- 子类别:`ParentCategoryName` 指向父类别名称
- 层级深度:无限制(支持任意深度的树形结构)
### 3. 数据一致性
- 所有物料必须先在 [平台配置清单] 中定义
- [领料配置] 中的物料代号必须在 `dictAllMaterials` 中存在
- 如果不存在,该物料会被跳过(不会报错)
---
## 使用示例
### 调用 LoadData
```vba
Dim bomMgr As New clsBOMManager
Dim wsConfig As Worksheet
Dim wsPlatform As Worksheet
Set wsConfig = ThisWorkbook.Worksheets("领料配置")
Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单")
' 加载数据
Call bomMgr.LoadData(wsConfig, wsPlatform)
' 获取根类别
Dim rootCats As Collection
Set rootCats = bomMgr.GetRootCategories()
' 遍历所有根类别
Dim i As Long
For i = 1 To rootCats.Count
Debug.Print "根类别: " & rootCats(i).categoryName
Next i
```
---
## 执行后的数据结构示例
假设加载后的数据结构如下:
```
dictAllMaterials:
{
"01091004312" → {code: "01091004312", Name: "表壳(本色)", Quantity: 1, Condition: ""},
"01011019001" → {code: "01011019001", Name: "低压接头部件", Quantity: 1, Condition: "lcfw=M02"},
"01081013833" → {code: "01081013833", Name: "径向低压接头", Quantity: 1, Condition: "gclj=Z12"}
}
dictCategories:
{
"表壳" → {categoryName: "表壳", ParentCategoryName: "", materials: [01091004312], SubCategories: []},
"部件" → {categoryName: "部件", ParentCategoryName: "", materials: [01011019001], SubCategories: ["接头", "弹性元件"]},
"接头" → {categoryName: "接头", ParentCategoryName: "部件", materials: [01081013833], SubCategories: []}
}
rootCategories:
[
"表壳" (clsCategory),
"部件" (clsCategory),
"机芯" (clsCategory)
]
```
---
## 错误处理
LoadData 方法本身不包含显式的错误处理(`On Error`),依赖以下机制:
1. **空值处理**:使用 `& ""` 确保字符串转换不会失败
2. **类型转换**:使用 `CDbl()` 时没有错误处理,假设数据格式正确
3. **跳过机制**:物料代号为空时,使用 `GoTo NextRow` 跳过
4. **存在性检查**:使用 `Dictionary.Exists()` 避免键不存在错误
---
## 相关方法
LoadData 执行后,可以使用以下方法访问数据:
| 方法 | 说明 |
|------|------|
| `GetRootCategories()` | 获取所有顶层类别 |
| `GetCategory(categoryName)` | 根据名称获取类别对象 |
| `GetMaterialsByModel()` | 根据型号获取物料 |
| `GetValidMaterialsByModel()` | 获取物料并检查完整性 |
| `PrintCategoryTree()` | 打印类别树(调试用) |
---
## 总结
`LoadData` 方法通过三个阶段构建完整的 BOM 数据结构:
1. **数据收集**:从 [平台配置清单] 收集所有物料基础信息
2. **数据关联**:从 [领料配置] 建立类别与物料的关联
3. **结构构建**:构建类别的树形层级关系
最终形成的数据结构支持:
- 快速按代号查找物料
- 快速按类别查找物料
- 遍历完整的类别树
- 支持父类别/子类别的领料逻辑