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

13 KiB
Raw Blame History

clsBOMManager.LoadData 方法流程分析

方法概述

LoadDataclsBOMManager 类的核心方法,负责从 Excel 工作表加载 BOM 数据并构建完整的层级数据结构。

方法签名

Public Sub LoadData(wsConfig As Worksheet, wsPlatform As Worksheet)

参数说明

参数 类型 说明
wsConfig Worksheet [领料配置]工作表,包含类别层级和需要领料的物料
wsPlatform Worksheet [平台配置清单]工作表,包含完整的物料信息

整体流程图

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

详细流程分析

第一步:从平台配置清单加载所有物料的基础信息

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{...}
└── ...

关键代码

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

第二步:从领料配置加载类别信息并关联物料

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{...}
└── ...

关键代码

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

业务逻辑说明

  • 只有出现在 [领料配置] 中的物料才会被添加到类别中
  • 未在 [领料配置] 中的物料表示不需要领料

第三步:建立类别层级关系

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:
│       ├── "接头" (子类别)
│       └── "弹性元件" (子类别)
└── "机芯" (根类别)

关键代码

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

数据结构总结

类的私有成员变量

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 遍历完整的类别树结构

流程时序图

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

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. 结构构建:构建类别的树形层级关系

最终形成的数据结构支持:

  • 快速按代号查找物料
  • 快速按类别查找物料
  • 遍历完整的类别树
  • 支持父类别/子类别的领料逻辑