Files
AutoBOM/reference_docs/clsBOMManager_LoadData流程分析-v2(整合后).md
Misaka_Company a9b3188d23 refactor: integrate [领料配置] into [平台配置清单] and add category selection conditions
Major changes:
- Remove dependency on separate [领料配置] sheet
- Load all data from [平台配置清单] in a single pass
- Add "类别选用条件" (CategorySelectCondition) field to support dynamic category filtering
- Add "66代码" (Code66) field for 66-system integration
- Refactor completeness check logic to only verify required categories

Data model changes:
- clsMaterialItem: Add CategorySelectCondition and Code66 properties
- clsCategory: Add CategorySelectCondition property and IsRequiredForModel() method
- clsBOMManager: Refactor LoadData() to use single data source
- clsBOMManager: Add GetRequiredCategories() method
- clsBOMManager: Update GetValidMaterialsByModel() to use category selection conditions

New workflow:
- LoadData() now takes only wsPlatform parameter (removed wsConfig)
- Categories are filtered by "类别选用条件" before completeness check
- Categories with empty selection condition are always required
- Categories with non-empty condition are checked against model specifications

Documentation:
- Update CLAUDE.md with new sheet structure
- Add comprehensive refactoring plan document
- Add v2.0 LoadData flow analysis with Mermaid diagrams
- Add platform configuration sheet reference

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

16 KiB
Raw Blame History

clsBOMManager.LoadData 方法流程分析 (v2.0 - 整合后版本)

方法概述

LoadDataclsBOMManager 类的核心方法,负责从 [平台配置清单] 工作表加载 BOM 数据并构建完整的层级数据结构。

v2.0 变更说明

  • 移除了 [领料配置] 表的依赖
  • 所有配置数据统一从 [平台配置清单] 读取
  • 新增"类别选用条件"字段,支持动态判断类别是否需要
  • 新增"66代码"字段

方法签名

Public Sub LoadData(wsPlatform As Worksheet)

参数说明

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

整体流程图

flowchart TD
    Start([开始 LoadData]) --> Step1[第一步: 从平台配置清单加载所有物料和类别信息]
    Step1 --> Step2[第二步: 建立类别层级关系]
    Step2 --> End([结束])

    style Start fill:#e1f5e1
    style End fill:#ffe1e1
    style Step1 fill:#e1f0ff
    style Step2 fill:#fff4e1

详细流程分析

第一步:从平台配置清单加载所有物料和类别信息

flowchart TD
    S1_Start([开始第一步]) --> S1_Init[初始化: 获取最后一行行号]
    S1_Init --> S1_Loop{循环 i = 4 到 lastRow}
    S1_Loop -->|i += 1| S1_ReadMat[读取物料基础信息<br/>C列:代号, D列:名称<br/>E列:数量, F列:选择条件]
    S1_ReadMat --> S1_ReadCat[读取类别信息<br/>H列:类别, I列:上层类别<br/>J列:类别选用条件, K列:66代码]
    S1_ReadCat --> S1_CreateMat[创建 clsMaterialItem 对象]
    S1_CreateMat --> S1_SetMatProps[设置物料属性<br/>code, Name, Quantity, Condition<br/>Category, ParentCategory<br/>CategorySelectCondition, Code66]
    S1_SetMatProps --> S1_SaveMat[保存到 dictAllMaterials]
    S1_SaveMat --> S1_CheckCat{类别字段<br/>是否为空?}
    S1_CheckCat -->|否, 有类别| S1_EnsureCat{类别对象<br/>是否存在?}
    S1_CheckCat -->|是, 无类别| S1_Next
    S1_EnsureCat -->|不存在| S1_CreateCat[创建新类别对象<br/>设置 categoryName, ParentCategoryName<br/>CategorySelectCondition]
    S1_EnsureCat -->|已存在| S1_AddMat
    S1_CreateCat --> S1_AddMat[将物料添加到类别]
    S1_AddMat --> S1_Next
    S1_Next --> S1_Loop
    S1_Loop -->|i > lastRow| S1_End([第一步完成])

    style S1_Start fill:#e1f5e1
    style S1_End fill:#ffe1e1
    style S1_CreateCat fill:#bbdefb
    style S1_AddMat fill:#c8e6c9
    style S1_CheckCat fill:#fff9c4

数据来源[平台配置清单] 工作表

字段 说明
C code 物料代号
D Name 物料名称
E Quantity 物料数量
F Condition 选择条件
H Category 类别名称
I ParentCategoryName 上层类别名称
J CategorySelectCondition 类别选用条件
K Code66 66系统代码

数据结构

dictAllMaterials: Dictionary<String, clsMaterialItem>
├── "01011009557" → clsMaterialItem{
│     code: "01011009557"
│     Name: "径向低压接头部件"
│     Quantity: 1.0
│     Condition: "gclj=M20 AND jycz=1"
│     Category: "部件"
│     ParentCategory: ""
│     CategorySelectCondition: ""
│     Code66: "66021009557"
│   }
└── ...

dictCategories: Dictionary<String, clsCategory>
├── "部件" → clsCategory{
│     categoryName: "部件"
│     ParentCategoryName: ""
│     CategorySelectCondition: ""
│     materials: Collection<clsMaterialItem>
│     SubCategories: Collection<clsCategory>
│   }
└── ...

关键代码

lastRow = wsPlatform.Cells(wsPlatform.Rows.Count, "C").End(xlUp).row

For i = 4 To lastRow
    ' 1. 创建物料对象并读取基础信息
    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 & "")

    ' 2. 读取类别相关字段
    catName = Trim(wsPlatform.Cells(i, "H").value & "")
    parentCatName = Trim(wsPlatform.Cells(i, "I").value & "")
    catSelectCond = Trim(wsPlatform.Cells(i, "J").value & "")
    code66 = Trim(wsPlatform.Cells(i, "K").value & "")

    ' 3. 保存到物料对象
    mat.Category = catName
    mat.ParentCategory = parentCatName
    mat.CategorySelectCondition = catSelectCond
    mat.Code66 = code66

    ' 4. 保存到字典(所有物料都保存)
    If mat.code <> "" Then
        Set dictAllMaterials(mat.code) = mat
    End If

    ' 5. 如果有类别,创建或更新类别对象
    If catName <> "" Then
        If Not dictCategories.Exists(catName) Then
            Set cat = New clsCategory
            cat.categoryName = catName
            cat.ParentCategoryName = parentCatName
            cat.CategorySelectCondition = catSelectCond
            Set dictCategories(catName) = cat
        End If

        dictCategories(catName).AddMaterial mat
    End If
Next i

与 v1.0 的区别

特性 v1.0 (旧版本) v2.0 (新版本)
数据源 [平台配置清单] + [领料配置] 仅 [平台配置清单]
加载步骤 3步 (先物料,后类别,再层级) 2步 (物料类别一起加载,再层级)
参数 wsConfig, wsPlatform wsPlatform
类别选用条件 不支持 支持
66代码 不支持 支持

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

flowchart TD
    S2_Start([开始第二步]) --> S2_Loop{遍历 dictCategories<br/>所有键}
    S2_Loop -->|下一个键| S2_GetCat[获取类别对象 cat]
    S2_GetCat --> S2_CheckParent{ParentCategoryName<br/>是否为空?}
    S2_CheckParent -->|否, 有父类别| S2_ParentExists{父类别<br/>存在?}
    S2_CheckParent -->|是, 无父类别| S2_AddRoot[添加到 rootCategories<br/>作为根类别]
    S2_ParentExists -->|是| S2_AddSub[添加到父类别的<br/>SubCategories 集合]
    S2_ParentExists -->|否| S2_Orphan[父类别不存在<br/>跳过建立关系]
    S2_AddRoot --> S2_Next
    S2_AddSub --> S2_Next
    S2_Orphan --> S2_Next
    S2_Next --> S2_Loop
    S2_Loop -->|遍历完成| S2_End([第二步完成])

    style S2_Start fill:#e1f5e1
    style S2_End fill:#ffe1e1
    style S2_AddRoot fill:#ffccbc
    style S2_AddSub fill:#b2dfdb

数据结构

rootCategories: Collection<clsCategory>
├── "表壳" (根类别)
│   └── CategorySelectCondition: "" (总是需要)
├── "部件" (根类别)
│   └── CategorySelectCondition: "" (总是需要)
│   └── SubCategories:
│       ├── "接头" (子类别)
│       │   └── CategorySelectCondition: "gclj=M20" (条件性需要)
│       └── "弹性元件" (子类别)
│           └── CategorySelectCondition: "lcfw=M02" (条件性需要)
└── "机芯" (根类别)
    └── CategorySelectCondition: "jycz=1" (条件性需要)

关键代码

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

说明:此步骤与 v1.0 版本相同,未发生变化。


数据结构总结

类的私有成员变量

classDiagram
    class clsBOMManager {
        -dictCategories: Dictionary
        -dictAllMaterials: Dictionary
        -rootCategories: Collection
        +LoadData(wsPlatform)
        +GetRootCategories() Collection
        +GetCategory(categoryName) clsCategory
        +GetRequiredCategories(conditions) Collection
        +GetValidMaterialsByModel(modelStr) Collection
    }

    class clsCategory {
        +categoryName: String
        +ParentCategoryName: String
        +CategorySelectCondition: String
        +materials: Collection
        +SubCategories: Collection
        +IsLeafCategory: Boolean
        +AddMaterial(mat)
        +AddSubCategory(cat)
        +IsRequiredForModel(conditions) Boolean
        +HasSubCategories() Boolean
    }

    class clsMaterialItem {
        +code: String
        +Name: String
        +Quantity: Double
        +Condition: String
        +Category: String
        +ParentCategory: String
        +CategorySelectCondition: String
        +Code66: 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 DictMat as dictAllMaterials
    participant DictCat as dictCategories
    participant RootCats as rootCategories

    Caller->>LoadData: LoadData(wsPlatform)

    Note over LoadData, WSPlatform: 第一步: 加载物料和类别信息
    LoadData->>WSPlatform: 读取第4-末行
    WSPlatform-->>LoadData: 返回物料和类别数据
    loop 每一行数据
        LoadData->>DictMat: 创建/添加物料 (包含新字段)
        alt 类别字段不为空
            LoadData->>DictCat: 类别存在?
            alt 类别不存在
                LoadData->>DictCat: 创建新类别(含类别选用条件)
            end
            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. 类别选用条件规则v2.0 新增)

  • 类别选用条件为空 → 该类别总是需要(无条件限制)
  • 类别选用条件不为空 → 需要用型号条件去匹配
    • 匹配成功 → 该类别需要
    • 匹配失败 → 该类别不需要

3. 类别层级规则

  • 根类别:ParentCategoryName 为空字符串 ""
  • 子类别:ParentCategoryName 指向父类别名称
  • 层级深度:无限制(支持任意深度的树形结构)

4. 数据一致性

  • 所有物料必须从 [平台配置清单] 读取
  • 类别字段和类别选用条件字段同时存在
  • 一个物料只能属于一个类别

使用示例

调用 LoadData

Dim bomMgr As New clsBOMManager
Dim wsPlatform As Worksheet

Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单")

' 加载数据 (v2.0 只需要一个参数)
Call bomMgr.LoadData(wsPlatform)

' 获取根类别
Dim rootCats As Collection
Set rootCats = bomMgr.GetRootCategories()

' 遍历所有根类别
Dim i As Long
For i = 1 To rootCats.Count
    Debug.Print "根类别: " & rootCats(i).categoryName
    Debug.Print "类别选用条件: " & rootCats(i).CategorySelectCondition
Next i

使用类别选用条件

' 解析型号并提取条件
Dim conditions As Object
Set conditions = bomMgr.ParseModelAndExtractConditions("YTHN-100.A0.532.M203.M16.Y3")

' 获取需要的类别
Dim requiredCats As Collection
Set requiredCats = bomMgr.GetRequiredCategories(conditions)

' 遍历需要的类别
Dim cat As clsCategory
For Each cat In requiredCats
    Debug.Print "需要的类别: " & cat.categoryName
Next cat

执行后的数据结构示例

假设加载后的数据结构如下:

型号: YTHN-100.A0.532.M203.M16.Y3
提取的条件: lcfw=M16, gclj=M20, jycz=1, azxs=A0

dictAllMaterials:
{
  "01011009557" → {
    code: "01011009557",
    Name: "径向低压接头部件",
    Quantity: 1.0,
    Condition: "gclj=M20 AND jycz=1 AND lcfw=M01",
    Category: "部件",
    ParentCategory: "",
    CategorySelectCondition: "",
    Code66: "66021009557"
  }
}

dictCategories:
{
  "部件" → {
    categoryName: "部件",
    ParentCategoryName: "",
    CategorySelectCondition: "",
    materials: [...],
    SubCategories: ["接头", "弹性元件"]
  },
  "接头" → {
    categoryName: "接头",
    ParentCategoryName: "部件",
    CategorySelectCondition: "gclj=M20",  ← 类别选用条件
    materials: [...],
    SubCategories: []
  },
  "机芯" → {
    categoryName: "机芯",
    ParentCategoryName: "",
    CategorySelectCondition: "jycz=1",  ← 类别选用条件
    materials: [...],
    SubCategories: []
  }
}

判断哪些类别需要:
- "部件" → CategorySelectCondition="" → 总是需要 ✓
- "接头" → CategorySelectCondition="gclj=M20" → 型号有gclj=M20 → 需要 ✓
- "机芯" → CategorySelectCondition="jycz=1" → 型号有jycz=1 → 需要 ✓

requiredCategories = ["部件", "接头", "机芯"]

错误处理

LoadData 方法本身不包含显式的错误处理(On Error),依赖以下机制:

  1. 空值处理:使用 & "" 确保字符串转换不会失败
  2. 类型转换:使用 CDbl() 时没有错误处理,假设数据格式正确
  3. 跳过机制:物料代号为空时,不保存到字典
  4. 存在性检查:使用 Dictionary.Exists() 避免键不存在错误

相关方法

LoadData 执行后,可以使用以下方法访问数据:

方法 说明 v2.0变化
GetRootCategories() 获取所有顶层类别 无变化
GetCategory(categoryName) 根据名称获取类别对象 无变化
GetRequiredCategories(conditions) 获取需要的类别列表 新增
GetValidMaterialsByModel() 获取物料并检查完整性 已重构,使用类别选用条件
GetMaterialsByModel() 根据型号获取物料 无变化
PrintCategoryTree() 打印类别树(调试用) 无变化

迁移指南 (v1.0 → v2.0)

代码变更

旧代码 (v1.0)

Dim wsConfig As Worksheet
Dim wsPlatform As Worksheet
Set wsConfig = ThisWorkbook.Worksheets("领料配置")
Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单")

Call bomMgr.LoadData(wsConfig, wsPlatform)  ' 两个参数

新代码 (v2.0)

Dim wsPlatform As Worksheet
Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单")

Call bomMgr.LoadData(wsPlatform)  ' 一个参数

数据变更

旧表结构

  • [领料配置]: A列=代号, C列=类别, D列=上层类别
  • [平台配置清单]: C列=代号, D列=名称, E列=数量, F列=选择条件

新表结构

  • [平台配置清单]: C列=代号, D列=名称, E列=数量, F列=选择条件 H列=类别, I列=上层类别, J列=类别选用条件, K列=66代码

逻辑变更

完整性检查逻辑

  • v1.0: 所有根类别都必须匹配到物料
  • v2.0: 只检查需要的类别(通过类别选用条件判断)

总结

LoadData 方法v2.0)通过两个阶段构建完整的 BOM 数据结构:

  1. 数据加载:从 [平台配置清单] 一次性加载所有物料和类别信息包括新增的类别选用条件和66代码
  2. 结构构建:构建类别的树形层级关系

v2.0 的主要改进:

  • 简化数据源:从一个表读取所有数据
  • 支持动态类别判断:通过类别选用条件
  • 更精确的完整性检查:只检查需要的类别
  • 支持66系统新增66代码字段

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

  • 快速按代号查找物料
  • 快速按类别查找物料
  • 遍历完整的类别树
  • 根据型号动态确定需要的类别
  • 支持父类别/子类别的领料逻辑