- Fix incorrect azxs transformation (A0→径向 → A0) - M06_ModelParser returns raw values, not transformed values - Add missing xh (型号) parameter to diagrams and examples (8 params total, not 7) - Remove misleading cross-connections between parameters (jycz/lcfw don't flow from gclj/bkxs) - Fix Mermaid parse error by escaping pipe character (| → 管道符) - Update all example tables to show raw azxs value "A0" instead of "径向" - Add comprehensive two-phase validation architecture documentation Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
30 KiB
RunBOMExtraction 运行机制详解
目录
系统概述
RunBOMExtraction 是BOM自动提取系统的入口函数,用于从产品型号中自动提取参数,匹配BOM库,输出标准BOM清单。
主要功能
- 参数提取: 从复杂的产品型号字符串中解析出8个关键参数
- 智能匹配: 根据参数在BOM库中查找对应的物料
- 特殊处理: 针对"部件"类物料的特殊逻辑(组件与子组件的选择)
- 结果输出: 生成格式化的BOM提取结果表
设计特点
- 模块化: 各功能模块职责清晰,易于维护
- 两阶段验证: 将匹配收集与验证分离,支持跨工作表验证规则
- 容错性: 完善的错误处理机制,区分错误(阻塞)和警告(非阻塞)
- 灵活性: 支持通配符匹配、负向匹配等多种匹配规则
- 可扩展: 易于添加新的物料类型和匹配规则
系统架构
graph TB
subgraph "入口层"
M01[M01_Main.bas<br/>RunBOMExtraction]
end
subgraph "协调层"
M09[M09_BOMExtractor.bas<br/>主协调器]
end
subgraph "处理层"
M06[M06_ModelParser.bas<br/>型号解析器]
M07[M07_BOMMatcher.bas<br/>BOM匹配器]
M08[M08_ComponentProcessor.bas<br/>部件处理器]
end
subgraph "配置层"
M04[M04_Config.bas<br/>配置管理]
Logger[clsErrorLogger.cls<br/>错误日志]
end
subgraph "数据源"
Input[产品型号工作表]
BOMLib[BOM库.xlsx]
end
subgraph "输出"
Output[BOM提取结果工作表]
end
M01 --> M09
M09 --> M06
M09 --> M07
M09 --> M08
M09 --> M04
M09 --> Logger
M06 --> Input
M07 --> BOMLib
M08 --> BOMLib
M09 --> Output
style M01 fill:#e1f5ff
style M09 fill:#fff4e1
style M06 fill:#e8f5e9
style M07 fill:#e8f5e9
style M08 fill:#e8f5e9
style Input fill:#f3e5f5
style BOMLib fill:#f3e5f5
style Output fill:#f3e5f5
数据流图
关键架构:两阶段验证(Two-Phase Validation)
BOM提取系统采用两阶段验证架构,将匹配结果的收集与验证分离:
flowchart LR
subgraph "输入阶段"
A[产品型号<br/>YTHN-100.A0.531.G123.M04.Y3] --> B[M06_ModelParser<br/>型号解析]
end
subgraph "解析阶段"
B --> C0[提取表头<br/>去除管道符后内容]
C0 --> C1[按.分割成段]
C1 --> C2[xh: YTHN]
C1 --> C3[gcwj: 100]
C1 --> C4[azxs: A0]
C1 --> C5[bkxs: 531]
C1 --> C6[gclj: G12<br/>jycz: 3]
C1 --> C7[lcfw: M04]
C1 --> C8[fjgn: Y3]
end
subgraph "Phase 1: 收集阶段(不记录错误)"
C2 & C3 & C4 & C5 & C6 & C7 & C8 --> D[遍历所有BOM库工作表]
D --> E1[接头工作表<br/>MatchBOMRecord]
D --> E2[弹性元件工作表<br/>MatchBOMRecord]
D --> E3[机芯工作表<br/>MatchBOMRecord]
D --> E4[部件工作表<br/>MatchBOMRecord + M08_ComponentProcessor]
E1 --> F1[存储匹配结果<br/>不记录错误]
E2 --> F2[存储匹配结果<br/>不记录错误]
E3 --> F3[存储匹配结果<br/>不记录错误]
E4 --> F4[存储匹配结果<br/>不记录错误]
end
subgraph "Phase 2: 验证阶段(跨工作表验证)"
F1 & F2 & F3 & F4 --> G[ValidateAllMatchResults<br/>统一验证所有结果]
G --> G1{非特殊工作表<br/>必须恰好1条}
G --> G2{部件/接头/弹性元件<br/>特殊规则验证}
G1 --> H1[记录错误/警告]
G2 --> H1
end
subgraph "Phase 3: 生成输出"
H1 --> I[收集验证通过的物料]
I --> J[BOM提取结果表]
end
style A fill:#ffebee
style J fill:#e8f5e9
style D fill:#e3f2fd
style G fill:#fff3e0
style F1 fill:#e8f5e9
style F2 fill:#e8f5e9
style F3 fill:#e8f5e9
style F4 fill:#e8f5e9
核心流程
关键架构:两阶段验证(Two-Phase Validation)
flowchart TD
Start([开始: RunBOMExtraction]) --> Init[初始化<br/>创建错误日志记录器]
Init --> CheckInput{检查输入工作表}
CheckInput -->|不存在| Error1[返回错误:<br/>未找到产品型号工作表]
CheckInput -->|存在| ReadModels[读取产品型号数据]
ReadModels --> CheckBOM{检查BOM库}
CheckBOM -->|不存在| Error2[返回错误:<br/>未找到BOM库.xlsx]
CheckBOM -->|存在| OpenBOM[打开BOM库工作簿]
OpenBOM --> LoopStart{遍历每个产品型号}
LoopStart --> ParseModel[M06_ModelParser<br/>解析产品型号]
ParseModel --> ParseSuccess{解析成功?}
ParseSuccess -->|失败| LogParseError[记录解析错误<br/>继续下一个型号]
ParseSuccess -->|成功| ExtractParams[提取8个参数]
ExtractParams --> Phase1[Phase 1: 收集匹配结果]
Phase1 --> CollectLoop[遍历所有BOM库工作表]
CollectLoop --> MatchBOM[M07_BOMMatcher<br/>匹配BOM记录]
MatchBOM --> IsComponent{是部件工作表?}
IsComponent -->|是| ProcessComp[M08_ComponentProcessor<br/>处理部件特殊逻辑]
IsComponent -->|否| StoreResult[存储匹配结果<br/>不记录错误]
ProcessComp --> StoreCompResult[存储部件结果<br/>不记录错误]
StoreResult --> NextSheet{还有工作表?}
StoreCompResult --> NextSheet
NextSheet -->|是| CollectLoop
NextSheet -->|否| Phase2[Phase 2: 验证匹配结果]
Phase2 --> ValidateAll[ValidateAllMatchResults<br/>跨工作表验证]
ValidateAll --> NonSpecial{验证非特殊工作表}
NonSpecial --> Special{验证部件/接头/弹性元件}
Special --> HasErrors{有错误?}
HasErrors -->|是| RecordErrors[记录错误]
HasErrors -->|否| HasWarnings{有警告?}
HasWarnings -->|是| RecordWarnings[记录警告]
HasWarnings -->|否| Phase3[Phase 3: 生成物料集合]
RecordErrors --> Phase3
RecordWarnings --> Phase3
Phase3 --> CollectMaterials[收集所有物料]
CollectMaterials --> GenerateRows[生成输出行]
GenerateRows --> NextModel{还有型号?}
LogParseError --> NextModel
NextModel -->|是| LoopStart
NextModel -->|否| WriteOutput[M09_BOMExtractor<br/>写入结果]
WriteOutput --> CloseBOM[关闭BOM库工作簿]
CloseBOM --> GenReport{有错误?}
GenReport -->|是| ShowWarning[显示警告:<br/>完成但有错误]
GenReport -->|否| ShowSuccess[显示成功:<br/>提取完成]
Error1 & Error2 --> End([结束])
ShowWarning & ShowSuccess --> End
style Start fill:#c8e6c9
style End fill:#ffcdd2
style ParseModel fill:#e1f5fe
style MatchBOM fill:#fff9c4
style ProcessComp fill:#f8bbd9
style Phase1 fill:#e3f2fd
style Phase2 fill:#fff3e0
style Phase3 fill:#e8f5e9
style ValidateAll fill:#ffe082
style Error1 fill:#ffcdd2
style Error2 fill:#ffcdd2
style LogParseError fill:#ffebee
style RecordErrors fill:#ffcdd2
style RecordWarnings fill:#fff9c4
模块交互时序图
关键架构:两阶段验证(Two-Phase Validation)
sequenceDiagram
participant User as 用户
participant M01 as M01_Main
participant M09 as M09_BOMExtractor
participant M06 as M06_ModelParser
participant M07 as M07_BOMMatcher
participant M08 as M08_ComponentProcessor
participant BOM as BOM库.xlsx
participant Logger as clsErrorLogger
User->>M01: 调用 RunBOMExtraction()
M01->>M09: RunBOMExtraction()
M09->>Logger: 创建错误日志记录器
M09->>M09: 检查产品型号工作表
M09->>M09: 打开BOM库工作簿
loop 遍历每个产品型号
M09->>M06: ParseProductModel(型号字符串)
M06-->>M09: 返回参数字典
alt 解析失败
M09->>Logger: 记录解析错误
else 解析成功
Note over M09: Phase 1: 收集匹配结果(不记录错误)
loop 遍历每个BOM库工作表
M09->>BOM: 读取工作表
alt 工作表 = "部件"
M09->>M07: MatchBOMRecord(工作表, 参数)
M07-->>M09: 返回匹配结果
alt 匹配成功
M09->>M08: ProcessComponentRecord(行数据)
M08-->>M09: 返回组件/子组件
M09->>M09: 存储匹配结果(不记录错误)
end
else 其他工作表
M09->>M07: MatchBOMRecord(工作表, 参数)
M07-->>M09: 返回匹配结果
M09->>M09: 存储匹配结果(不记录错误)
end
end
Note over M09: Phase 2: 统一验证所有结果
M09->>M09: ValidateAllMatchResults(所有结果)
alt 验证非特殊工作表
M09->>M09: 检查rowCount = 1
alt rowCount != 1
M09->>Logger: 记录错误
end
end
alt 验证部件/接头/弹性元件
M09->>M09: 检查跨工作表冲突
alt 有冲突
M09->>Logger: 记录警告
end
alt 组合无效
M09->>Logger: 记录错误
end
end
Note over M09: Phase 3: 生成物料集合
M09->>M09: 收集所有验证通过的物料
end
end
M09->>M09: WriteExtractionResults(结果集)
M09->>BOM: 关闭BOM库工作簿
alt 有错误
M09-->>M01: 返回警告消息
else 无错误
M09-->>M01: 返回成功消息
end
M01-->>User: 显示结果消息框
关键模块详解
1. M01_Main.bas - 入口模块
职责: 系统入口,提供简洁的用户接口
Public Sub RunBOMExtraction()
Dim result As String
result = M09_BOMExtractor.RunBOMExtraction()
MsgBox result, vbInformation, "BOM提取"
End Sub
特点:
- 极简设计,仅作为调用入口
- 结果通过消息框返回
- 错误处理委托给下层模块
2. M09_BOMExtractor.bas - 主协调器
职责: 整体流程控制,模块调度,结果输出
核心函数:
| 函数名 | 职责 |
|---|---|
RunBOMExtraction() |
主流程控制函数 |
ProcessSingleModel() |
处理单个产品型号 |
MatchAllMaterialTypesWithValidation() |
匹配所有物料类型(两阶段验证) |
ValidateAllMatchResults() |
统一验证所有匹配结果(跨工作表规则) |
WriteExtractionResults() |
输出提取结果 |
处理流程:
初始化 → 验证输入 → 打开BOM库 → 循环处理型号(Phase 1收集→Phase 2验证→Phase 3生成) → 输出结果 → 清理资源
两阶段验证架构:
该模块实现了关键的两阶段验证架构,将匹配与验证分离:
-
Phase 1 - 收集阶段 (
MatchAllMaterialTypesWithValidation):- 遍历所有BOM库工作表
- 调用
M07_BOMMatcher.MatchBOMRecord()获取匹配结果 - 对于"部件"工作表,额外调用
M08_ComponentProcessor.ProcessComponentRecord() - 关键点:不记录任何错误,仅收集原始匹配结果
- 存储每个工作表的:success、rowCount、rowNums、materials
-
Phase 2 - 验证阶段 (
ValidateAllMatchResults):- 统一验证所有收集到的匹配结果
- 应用跨工作表验证规则
- 区分错误(blocking)和警告(non-blocking)
- 记录所有错误和警告到Logger
-
Phase 3 - 生成阶段:
- 根据验证结果生成最终物料集合
- 即使验证失败,也返回物料用于错误显示
3. 两阶段验证架构详解
为什么需要两阶段验证?
在BOM提取系统中,"部件"、"接头"、"弹性元件"三个工作表之间存在复杂的互斥和替代关系:
- 部件表可能返回:1个组件 或 1个接头+1个弹性元件
- 接头表可能返回:1个接头
- 弹性元件表可能返回:1个弹性元件
如果立即记录错误,无法判断全局情况。例如:
- 部件表返回了组件,但接头表也匹配到接头 → 这是冲突,应该警告而非错误
- 部件表返回了接头+弹性元件,但独立表也匹配到 → 这是冲突,应该警告而非错误
Phase 1: 收集阶段(不记录错误)
代码位置: M09_BOMExtractor.MatchAllMaterialTypesWithValidation() (lines 387-541)
流程:
For Each ws In bomWb.Worksheets
If ws.Name = "部件" Then
' 1. 标准匹配
Set bomMatchResult = M07_BOMMatcher.MatchBOMRecord(ws, params)
' 2. 部件特殊处理
Set componentMaterials = M08_ComponentProcessor.ProcessComponentRecord(...)
' 3. 存储结果(不记录错误)
matchResult("success") = bomMatchResult("success")
matchResult("rowCount") = bomMatchResult("rowCount")
matchResult("materials") = componentMaterials
Else
' 标准匹配
Set bomMatchResult = M07_BOMMatcher.MatchBOMRecord(ws, params)
' 存储结果(不记录错误)
End If
resultsDict.Add ws.Name, matchResult
Next ws
关键点:
- 即使匹配失败(rowCount=0),也不记录错误
- 即使多重匹配(rowCount>1),也不记录错误
- 只存储原始数据供Phase 2使用
Phase 2: 验证阶段(跨工作表验证)
代码位置: M09_BOMExtractor.ValidateAllMatchResults() (lines 566-760)
验证规则:
1. 基础规则(非特殊工作表)
非特殊工作表必须恰好匹配1条记录:
- rowCount = 0 → 错误
- rowCount = 1 → 正常
- rowCount > 1 → 错误
特殊工作表列表:["部件", "接头", "弹性元件"]
2. 跨工作表规则(部件/接头/弹性元件)
情况A: 部件表返回了组件(1个部件物料)
如果部件表返回了组件:
接头表有匹配 → 警告:"存在[部件]物料,但[接头]工作表也匹配到X条记录,已忽略"
弹性元件表有匹配 → 警告:"存在[部件]物料,但[弹性元件]工作表也匹配到X条记录,已忽略"
情况B: 部件表返回了子件(接头+弹性元件)
如果部件表返回了接头+弹性元件:
接头表有匹配 → 警告:"[部件]工作表已返回接头,但[接头]工作表也匹配到X条记录,已忽略"
弹性元件表有匹配 → 警告:"[部件]工作表已返回弹性元件,但[弹性元件]工作表也匹配到X条记录,已忽略"
情况C: 部件表没有返回物料
如果部件表rowCount=0:
接头表=0 或 弹性元件表=0 → 错误:"部件、接头、弹性元件均未匹配或组合不完整"
接头表>1 → 错误:"[接头]工作表匹配到X条记录"
弹性元件表>1 → 错误:"[弹性元件]工作表匹配到X条记录"
情况D: 部件表多重匹配
部件表rowCount > 1 → 错误:"[部件]工作表匹配到X条记录"
3. 错误与警告的区别
| 类型 | 是否阻塞 | Logger方法 | 颜色 |
|---|---|---|---|
| 错误 | 是 | logger.Record() |
红色 |
| 警告 | 否 | logger.RecordWarning() |
黄色 |
Phase 3: 生成阶段
代码位置: M09_BOMExtractor.MatchAllMaterialTypesWithValidation() (lines 495-525)
流程:
If validationResult("valid") Then
' 验证通过:收集所有物料
For Each result In resultsDict
For Each mat In result("materials")
allMaterials.Add mat
Next mat
Next result
Else
' 验证失败:仍然收集物料(用于错误显示)
For Each result In resultsDict
For Each mat In result("materials")
allMaterials.Add mat
Next mat
Next result
End If
关键点:
- 即使验证失败,仍然返回所有物料
- 错误信息会显示在输出行的"提取备注"列
- 用户可以看到匹配到什么物料以及为什么出错
4. M06_ModelParser.bas - 型号解析器
职责: 从产品型号字符串中提取参数
产品型号格式:
[型号-公称外径].[安装形式].[表壳形式].[过程连接&接液材质].[量程范围].[附加功能]|[扩展信息]
示例: YTHN-100.A0.531.G123.M04.Y3|BP-088.2312.B09.0A3
提取的参数:
| 参数 | 描述 | 示例值 | 转换规则 |
|---|---|---|---|
| xh | 型号 | YTHN | 从YTHN-100提取横线前部分 |
| gcwj | 公称外径 | 100 | 从YTHN-100提取横线后数字 |
| azxs | 安装形式 | A0 | 直接提取,无转换 |
| bkxs | 表壳形式 | 531 | 直接提取 |
| gclj | 过程连接 | G12 | 从G123去除末位 |
| jycz | 接液材质 | 3 | 从G123提取末位 |
| lcfw | 量程范围 | M04 | 直接提取 |
| fjgn | 附加功能 | Y3 | 直接提取(多段用逗号连接) |
核心函数:
Public Function ParseProductModel(ByVal modelStr As String) As Object
' 返回包含8个参数的字典
End Function
5. M07_BOMMatcher.bas - BOM匹配器
职责: 根据参数在BOM库中查找匹配记录
匹配规则:
| 单元格值 | 匹配逻辑 |
|---|---|
| 空白 | 通配符,匹配所有 |
!value |
负向匹配,不等于该值 |
value |
精确匹配 |
fjgn列 |
包含匹配,value包含在参数中 |
匹配逻辑:
对于每条记录:
对于每个参数:
IF 单元格为空 THEN 匹配成功
ELSE IF 单元格以"!"开头 THEN
IF 参数 != 去掉"!"的值 THEN 匹配成功
ELSE 匹配失败
ELSE IF 列名 = "fjgn" THEN
IF 参数包含单元格值 THEN 匹配成功
ELSE 匹配失败
ELSE
IF 参数 = 单元格值 THEN 匹配成功
ELSE 匹配失败
END IF
IF 所有参数都匹配成功 THEN 返回该记录
NEXT
匹配要求:
- 必须有且仅有1条匹配记录
- 0条 = 未找到匹配
- 多条 = 匹配不唯一
6. M08_ComponentProcessor.bas - 部件处理器
职责: 处理"部件"类物料的特殊逻辑
部件结构:
部件记录包含:
- 自身信息 (物料编码A, 数量A)
- 子组件1 - 接头 (物料编码B, 数量B)
- 子组件2 - 弹性元件 (物料编码C, 数量C)
选择策略:
flowchart TD
Start([匹配到部件记录]) --> CheckA{检查组件A}
CheckA -->|有库存| UseA[使用组件A]
CheckA -->|无库存| CheckB{检查子组件B+C}
CheckB -->|都有库存| UseBC[使用子组件B+C]
CheckB -->|任一无库存| Error[标记: 缺货]
UseA --> ValidateA{仅组件A?}
ValidateA -->|是| Valid[✓ 有效组合]
ValidateA -->|否| Error1[✗ 无效组合:<br/>不能同时使用组件和子组件]
UseBC --> ValidateBC{有组件A?}
ValidateBC -->|否| Valid
ValidateBC -->|是| Error1
Error & Error1 --> End([结束: 验证失败])
Valid --> End
style Start fill:#e1f5fe
style End fill:#ffebee
style Valid fill:#c8e6c9
style Error fill:#ffcdd2
style Error1 fill:#ffcdd2
有效组合:
- ✅ 仅组件A (优先级1)
- ✅ 仅子组件B + 子组件C (优先级2)
- ❌ 组件A + 子组件 (无效)
- ❌ 仅部分子组件 (无效)
数据结构
输入数据结构
产品型号工作表:
| 行号 | 列A (型号) | 列B (可选列) |
|---|---|---|
| 1 | 型号 | (表头) |
| 2 | YTHN-100.A0.531.G123.M04.Y3 | ... |
| 3 | YTHN-150.B0.531.G456.M12.Y2 | ... |
BOM库数据结构
BOM库.xlsx 包含多个工作表,每个工作表代表一种物料类型。
通用列结构 (以"接头"为例):
| 列名 | 说明 | 示例值 |
|---|---|---|
| azxs | 安装形式 | A0 |
| bkxs | 表壳形式 | 531 |
| gclj | 过程连接 | G12 |
| jycz | 接液材质 | 3 |
| lcfw | 量程范围 | M04 |
| fjgn | 附加功能 | Y3 |
| 物料编码 | 物料唯一标识 | JT-001 |
| 物料名称 | 物料描述名称 | 卡套式接头 |
| 数量 | 默认数量 | 1 |
"部件"工作表特殊列:
| 列名 | 说明 |
|---|---|
| 物料编码 | 组件A编码 |
| 数量A | 组件A数量 |
| 物料编码B | 子组件B(接头)编码 |
| 数量B | 子组件B数量 |
| 物料编码C | 子组件C(弹性元件)编码 |
| 数量C | 子组件C数量 |
输出数据结构
BOM提取结果工作表 (12列):
| 列号 | 列名 | 说明 | 示例值 |
|---|---|---|---|
| 1 | 原始产品型号 | 输入的完整型号 | YTHN-100...Y3 |
| 2 | azxs | 安装形式 | A0 |
| 3 | bkxs | 表壳形式 | 531 |
| 4 | gclj | 过程连接 | G12 |
| 5 | jycz | 接液材质 | 3 |
| 6 | lcfw | 量程范围 | M04 |
| 7 | fjgn | 附加功能 | Y3 |
| 8 | 物料类型 | 接头/弹性元件/机芯/部件/边 | 接头 |
| 9 | 物料名称 | 物料描述 | 卡套式接头 |
| 10 | 物料编码 | 唯一标识 | JT-001 |
| 11 | 物料数量 | 数量 | 1 |
| 12 | 提取备注 | 错误或警告信息 | (空/错误信息) |
输出格式:
- 每种物料占一行
- 一个产品型号可能对应多行输出
- 行按物料类型分组
内部数据结构
参数字典 (M06_ModelParser输出):
Dictionary {
"xh": "YTHN",
"gcwj": "100",
"azxs": "A0",
"bkxs": "531",
"gclj": "G12",
"jycz": "3",
"lcfw": "M04",
"fjgn": "Y3"
}
列映射字典 (M07_BOMMatcher):
Dictionary {
"azxs": 1,
"bkxs": 2,
"gclj": 3,
...
"物料编码": 10,
"物料名称": 11,
"数量": 12
}
物料信息字典 (M07_BOMMatcher输出):
Dictionary {
"物料编码": "JT-001",
"物料名称": "卡套式接头",
"数量": 1,
"物料类型": "接头"
}
结果集合 (M09_BOMExtractor汇总):
Collection {
Array(型号, azxs, bkxs, gclj, jycz, lcfw, fjgn, 物料类型, 物料名称, 物料编码, 数量, 备注),
Array(...), // 第二条物料
...
}
错误处理机制
错误分类
| 错误类型 | 级别 | 处理方式 | 示例 |
|---|---|---|---|
| 工作表不存在 | 致命 | 立即返回 | 未找到产品型号工作表 |
| BOM库不存在 | 致命 | 立即返回 | 未找到BOM库.xlsx |
| 型号解析失败 | 警告 | 记录错误,跳过 | 型号格式错误 |
| 无匹配记录 | 警告 | 记录错误,继续 | 未找到匹配物料 |
| 多重匹配 | 警告 | 记录错误,继续 | 找到多个匹配 |
| 组件组合无效 | 警告 | 记录错误,继续 | 组件与子组件混用 |
| 跨工作表冲突 | 警告 | 记录警告,继续 | 部件表与接头表同时匹配 |
两阶段验证错误处理
Phase 1: 收集阶段(不记录错误)
在收集阶段,系统不记录任何错误,原因如下:
- 需要全局信息: 判断是否为错误需要看所有工作表的匹配结果
- 避免误报: 部件表返回组件时,接头表也匹配是警告而非错误
- 优先级处理: 部件表的返回优先级高于独立表
示例:
' Phase 1 收集阶段 - 不记录错误
Set matchResult = M07_BOMMatcher.MatchBOMRecord(ws, params)
' 即使 matchResult("rowCount") = 0 或 > 1,也不记录错误
resultsDict.Add ws.Name, matchResult
Phase 2: 验证阶段(记录错误和警告)
在验证阶段,系统根据跨工作表规则统一验证:
错误示例(阻塞,红色):
[接头] 未匹配到记录
[机芯] 匹配到2条记录
部件、接头、弹性元件均未匹配或组合不完整
警告示例(非阻塞,黄色):
存在[部件]物料,但[接头]工作表也匹配到1条记录,已忽略
[部件]工作表已返回弹性元件,但[弹性元件]工作表也匹配到1条记录,已忽略
Logger调用:
' 记录错误(阻塞)
logger.Record 0, "M09.ValidateAllMatchResults", "BOMMatchError", errorMessage, ""
' 记录警告(非阻塞)
logger.RecordWarning 0, "M09.ValidateAllMatchResults", "ComponentConflict", warningMessage, ""
错误日志机制
flowchart LR
subgraph "错误检测"
A[检测到错误/警告]
end
subgraph "两阶段验证"
B1[Phase 1: 收集<br/>不记录错误]
B2[Phase 2: 验证<br/>记录错误和警告]
end
subgraph "错误记录"
C[clsErrorLogger]
C1[logger.Record<br/>错误(红色)]
C2[logger.RecordWarning<br/>警告(黄色)]
end
subgraph "错误信息"
D[错误类型]
E[上下文信息]
F[时间戳]
end
subgraph "错误输出"
G[第12列: 提取备注]
H[红色高亮(错误)]
I[黄色高亮(警告)]
end
A --> B1
B1 --> B2
B2 --> C
C --> C1
C --> C2
C1 & C2 --> D & E & F
D & E & F --> G
G --> H
G --> I
style A fill:#ffebee
style B1 fill:#e3f2fd
style B2 fill:#fff3e0
style C fill:#fff9c4
style G fill:#e8f5e9
style H fill:#ffcdd2
style I fill:#fff59d
clsErrorLogger方法:
' 记录错误(阻塞)
logger.Record rowIndex, sourceModule, errorType, description, context
' 记录警告(非阻塞)
logger.RecordWarning rowIndex, sourceModule, warningType, description, context
错误信息格式:
[错误类型] 详细描述
- 行号: X
- 数据: [具体数据]
错误恢复策略
- 继续处理: 遇到非致命错误时继续处理下一条记录
- 错误累积: 所有错误都记录在日志中
- 最终报告: 处理完成后显示汇总报告
- 部分成功: 部分记录成功时仍然输出结果
- 两阶段验证: Phase 1不中断,Phase 2统一验证
使用示例
示例1: 基本使用
' 在VBA编辑器中运行
Sub TestBOMExtraction()
Call RunBOMExtraction
End Sub
输入数据:
| 型号 |
|---|
| YTHN-100.A0.531.G123.M04.Y3 |
输出结果:
| 原始产品型号 | azxs | bkxs | gclj | jycz | lcfw | fjgn | 物料类型 | 物料名称 | 物料编码 | 数量 | 备注 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| YTHN-100...Y3 | A0 | 531 | G12 | 3 | M04 | Y3 | 接头 | 卡套式接头 | JT-001 | 1 | |
| YTHN-100...Y3 | A0 | 531 | G12 | 3 | M04 | Y3 | 弹性元件 | 膜片 | MH-002 | 1 | |
| YTHN-100...Y3 | A0 | 531 | G12 | 3 | M04 | Y3 | 机芯 | 齿轮机构 | JX-003 | 1 |
示例2: 部件特殊处理
场景: 组件A缺货,使用子组件替代
BOM库记录 ("部件"工作表):
| azxs | bkxs | ... | 物料编码 | 数量A | 物料编码B | 数量B | 物料编码C | 数量C |
|---|---|---|---|---|---|---|---|---|
| A0 | 531 | ... | BJ-001 | 1 | JT-002 | 2 | MH-003 | 1 |
假设: 组件A (BJ-001) 缺货
处理逻辑:
- 检测到组件A缺货
- 检查子组件B (JT-002) 和C (MH-003) 库存
- 如果都有库存,使用子组件替代
- 验证组合: 只有子组件,无组件A ✓
输出结果:
| 物料类型 | 物料名称 | 物料编码 | 数量 | 备注 |
|---|---|---|---|---|
| 接头 | 卡套式接头 | JT-002 | 2 | (子组件B) |
| 弹性元件 | 膜片 | MH-003 | 1 | (子组件C) |
示例3: 错误处理
场景: 型号解析失败
输入:
INVALID.MODEL.FORMAT
处理流程:
- M06_ModelParser尝试解析
- 检测到格式不匹配
- 记录错误到Logger
- 跳过该型号,继续下一个
输出:
| 原始产品型号 | 备注 |
|---|---|
| INVALID.MODEL.FORMAT | [解析错误] 型号格式不符合要求,无法提取参数 |
备注单元格会以红色高亮显示。
附录: 快速参考
常用函数速查
| 模块 | 函数 | 用途 |
|---|---|---|
| M01_Main | RunBOMExtraction() |
系统入口 |
| M09_BOMExtractor | RunBOMExtraction() |
主流程控制 |
| M09_BOMExtractor | ProcessSingleModel() |
处理单个型号 |
| M09_BOMExtractor | MatchAllMaterialTypesWithValidation() |
匹配所有物料类型(两阶段验证) |
| M09_BOMExtractor | ValidateAllMatchResults() |
统一验证所有匹配结果(跨工作表规则) |
| M06_ModelParser | ParseProductModel() |
解析型号参数 |
| M07_BOMMatcher | MatchBOMRecord() |
匹配BOM记录 |
| M07_BOMMatcher | BuildHeaderMapping() |
构建列映射 |
| M08_ComponentProcessor | ProcessComponentRecord() |
处理部件特殊逻辑 |
配置参数
| 配置项 | 值 | 说明 |
|---|---|---|
| 输入工作表名 | "产品型号" | 可含"型号"列 |
| BOM库文件名 | "BOM库.xlsx" | 必须在同一目录 |
| 输出工作表名 | "BOM提取结果" | 自动创建/覆盖 |
| 数据起始行 | 2 | 行1为表头 |
| 支持的物料类型 | 接头, 弹性元件, 机芯, 部件, 边 | 可扩展 |
相关文档
- M03_Logic_Algorithm.md - 条件解析算法详解
- Test_PP_06_FullIntegration_流程详解.md - 预处理系统集成测试
- CLAUDE.md - 项目整体说明
文档版本: 2.0 最后更新: 2026-02-12 作者: Claude Code 状态: 更新完成 - 新增两阶段验证架构文档
版本历史:
- v2.0 (2026-02-12): 重大更新 - 添加两阶段验证架构详解,更新数据流图、核心流程图、模块交互时序图
- v1.0 (2026-02-12): 初稿完成