# RunBOMExtraction 运行机制详解 ## 目录 1. [系统概述](#系统概述) 2. [系统架构](#系统架构) 3. [数据流图](#数据流图) 4. [核心流程](#核心流程) 5. [模块交互时序图](#模块交互时序图) 6. [关键模块详解](#关键模块详解) 7. [两阶段验证架构详解](#两阶段验证架构详解) 8. [数据结构](#数据结构) 9. [错误处理机制](#错误处理机制) 10. [使用示例](#使用示例) --- ## 系统概述 `RunBOMExtraction` 是BOM自动提取系统的入口函数,用于从产品型号中自动提取参数,匹配BOM库,输出标准BOM清单。 ### 主要功能 - **参数提取**: 从复杂的产品型号字符串中解析出8个关键参数 - **智能匹配**: 根据参数在BOM库中查找对应的物料 - **特殊处理**: 针对"部件"类物料的特殊逻辑(组件与子组件的选择) - **结果输出**: 生成格式化的BOM提取结果表 ### 设计特点 - **模块化**: 各功能模块职责清晰,易于维护 - **两阶段验证**: 将匹配收集与验证分离,支持跨工作表验证规则 - **容错性**: 完善的错误处理机制,区分错误(阻塞)和警告(非阻塞) - **灵活性**: 支持通配符匹配、负向匹配等多种匹配规则 - **可扩展**: 易于添加新的物料类型和匹配规则 --- ## 系统架构 ```mermaid graph TB subgraph "入口层" M01[M01_Main.bas
RunBOMExtraction] end subgraph "协调层" M09[M09_BOMExtractor.bas
主协调器] end subgraph "处理层" M06[M06_ModelParser.bas
型号解析器] M06A[M06A_Mapper.bas
值映射器] M07[M07_BOMMatcher.bas
BOM匹配器] M08[M08_ComponentProcessor.bas
部件处理器] end subgraph "配置层" M04[M04_Config.bas
配置管理] Logger[clsErrorLogger.cls
错误日志] end subgraph "数据源" Input[产品型号工作表] Mapping[对照表工作表] BOMLib[BOM库.xlsx] end subgraph "输出" Output[BOM提取结果工作表] end M01 --> M09 M09 --> M06 M09 --> M06A M09 --> M07 M09 --> M08 M09 --> M04 M09 --> Logger M06 --> Input M06A --> Mapping M06 --> M06A M07 --> BOMLib M08 --> BOMLib M09 --> Output style M01 fill:#e1f5ff style M09 fill:#fff4e1 style M06 fill:#e8f5e9 style M06A fill:#f8bbd9 style M07 fill:#e8f5e9 style M08 fill:#e8f5e9 style Input fill:#f3e5f5 style Mapping fill:#fff9c4 style BOMLib fill:#f3e5f5 style Output fill:#f3e5f5 ``` --- ## 数据流图 **关键架构:两阶段验证(Two-Phase Validation)+ 值映射(Value Mapping)** BOM提取系统采用**两阶段验证架构**,将匹配结果的收集与验证分离,并集成**值映射功能**以支持灵活的参数匹配: ```mermaid flowchart LR subgraph "输入阶段" A[产品型号
YTHN-100.A0.531.G123.M04.Y3] --> B[M06_ModelParser
型号解析] end subgraph "解析阶段" B --> C0[提取表头
去除管道符后内容] C0 --> C1[按.分割成段] C1 --> C2[xh: YTHN] C1 --> C3[gcwj: 100] C1 --> C4[azxs: A0] C1 --> C5[bkxs: 531] C1 --> C6[gclj: G12
jycz: 3] C1 --> C7[lcfw: M04] C1 --> C8[fjgn: Y3] end subgraph "值映射阶段" C4 --> M1[M06A_Mapper.MapAzxs
A0 → A0,径向] C7 --> M2[M06A_Mapper.MapLcfw
M04 → M04,高压] M1 --> P1[azxs: A0,径向
双值格式] M2 --> P2[lcfw: M04,高压
双值格式] end subgraph "Phase 1: 收集阶段(不记录错误)" C2 & C3 & P1 & C5 & C6 & P2 & C8 --> D[遍历所有BOM库工作表] D --> E1[接头工作表
MatchBOMRecord
支持双值匹配] D --> E2[弹性元件工作表
MatchBOMRecord
支持双值匹配] D --> E3[机芯工作表
MatchBOMRecord] D --> E4[部件工作表
MatchBOMRecord + M08_ComponentProcessor] E1 --> F1[存储匹配结果
不记录错误] E2 --> F2[存储匹配结果
不记录错误] E3 --> F3[存储匹配结果
不记录错误] E4 --> F4[存储匹配结果
不记录错误] end subgraph "Phase 2: 验证阶段(跨工作表验证)" F1 & F2 & F3 & F4 --> G[ValidateAllMatchResults
统一验证所有结果] G --> G1{非特殊工作表
必须恰好1条} G --> G2{部件/接头/弹性元件
特殊规则验证} 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 style M1 fill:#f8bbd9 style M2 fill:#f8bbd9 style P1 fill:#fff9c4 style P2 fill:#fff9c4 ``` --- ## 核心流程 **关键架构:两阶段验证(Two-Phase Validation)+ 值映射(Value Mapping)** ```mermaid flowchart TD Start([开始: RunBOMExtraction]) --> Init[初始化
创建错误日志记录器] Init --> CheckInput{检查输入工作表} CheckInput -->|不存在| Error1[返回错误:
未找到产品型号工作表] CheckInput -->|存在| ReadModels[读取产品型号数据] ReadModels --> CheckBOM{检查BOM库} CheckBOM -->|不存在| Error2[返回错误:
未找到BOM库.xlsx] CheckBOM -->|存在| OpenBOM[打开BOM库工作簿] OpenBOM --> InitModules[初始化各模块
M06_ModelParser
M07_BOMMatcher
M08_ComponentProcessor] InitModules --> InitMapper{对照表存在?} InitMapper -->|是| InitMapperYes[初始化M06A_Mapper
加载映射数据] InitMapper -->|否| InitMapperNo[记录警告
仅使用原始值] InitMapperYes --> LoopStart{遍历每个产品型号} InitMapperNo --> LoopStart LoopStart --> ParseModel[M06_ModelParser
解析产品型号] ParseModel --> ParseSuccess{解析成功?} ParseSuccess -->|失败| LogParseError[记录解析错误
继续下一个型号] ParseSuccess -->|成功| ExtractParams[提取原始参数] ExtractParams --> ApplyMapping{映射器已初始化?} ApplyMapping -->|是| MapValues[M06A_Mapper
应用值映射
azxs, lcfw] ApplyMapping -->|否| UseRawValues[使用原始值] MapValues --> Phase1[Phase 1: 收集匹配结果] UseRawValues --> Phase1 Phase1 --> CollectLoop[遍历所有BOM库工作表] CollectLoop --> MatchBOM[M07_BOMMatcher
匹配BOM记录
支持双值匹配] MatchBOM --> IsComponent{是部件工作表?} IsComponent -->|是| ProcessComp[M08_ComponentProcessor
处理部件特殊逻辑] IsComponent -->|否| StoreResult[存储匹配结果
不记录错误] ProcessComp --> StoreCompResult[存储部件结果
不记录错误] StoreResult --> NextSheet{还有工作表?} StoreCompResult --> NextSheet NextSheet -->|是| CollectLoop NextSheet -->|否| Phase2[Phase 2: 验证匹配结果] Phase2 --> ValidateAll[ValidateAllMatchResults
跨工作表验证] 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
写入结果] WriteOutput --> CloseBOM[关闭BOM库工作簿] CloseBOM --> GenReport{有错误?} GenReport -->|是| ShowWarning[显示警告:
完成但有错误] GenReport -->|否| ShowSuccess[显示成功:
提取完成] Error1 & Error2 --> End([结束]) ShowWarning & ShowSuccess --> End style Start fill:#c8e6c9 style End fill:#ffcdd2 style ParseModel fill:#e1f5fe style MapValues fill:#f8bbd9 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 style InitMapperYes fill:#e8f5e9 style InitMapperNo fill:#fff9c4 ``` --- ## 模块交互时序图 **关键架构:两阶段验证(Two-Phase Validation)** ```mermaid sequenceDiagram participant User as 用户 participant M01 as M01_Main participant M09 as M09_BOMExtractor participant M06 as M06_ModelParser participant M06A as M06A_Mapper participant M07 as M07_BOMMatcher participant M08 as M08_ComponentProcessor participant BOM as BOM库.xlsx participant Mapping as 对照表.xlsx participant Logger as clsErrorLogger User->>M01: 调用 RunBOMExtraction() M01->>M09: RunBOMExtraction() M09->>Logger: 创建错误日志记录器 M09->>M09: 检查产品型号工作表 M09->>M09: 打开BOM库工作簿 M09->>M06: InitModelParser(logger) M09->>M07: InitBOMMatcher(logger) M09->>M08: InitComponentProcessor(logger) alt 对照表存在 M09->>Mapping: 获取对照表工作表 M09->>M06A: InitMapper(logger, wsMapping) M06A->>Mapping: 加载映射数据
azxs: A0→径向, etc.
lcfw: M01→低压, etc. Mapping-->>M06A: 映射数据加载完成 M06A-->>M09: 映射器初始化完成 else 对照表不存在 M09->>Logger: 记录警告
"未找到对照表工作表" end loop 遍历每个产品型号 M09->>M06: ParseProductModel(型号字符串) M06->>M06: 提取原始参数
azxs="A0", lcfw="M04" alt 映射器已初始化 M06->>M06A: MapAzxs("A0") M06A-->>M06: "A0,径向" M06->>M06A: MapLcfw("M04") M06A-->>M06: "M04,高压" M06->>M06: 组装双值参数 end M06-->>M09: 返回参数字典
(含映射值) alt 解析失败 M09->>Logger: 记录解析错误 else 解析成功 Note over M09: Phase 1: 收集匹配结果(不记录错误) loop 遍历每个BOM库工作表 M09->>BOM: 读取工作表 alt 工作表 = "部件" M09->>M07: MatchBOMRecord(工作表, 参数) Note over M07: 支持双值匹配
azxs="A0,径向" 可匹配 "A0" 或 "径向" M07-->>M09: 返回匹配结果 alt 匹配成功 M09->>M08: ProcessComponentRecord(行数据) M08-->>M09: 返回组件/子组件 M09->>M09: 存储匹配结果(不记录错误) end else 其他工作表 M09->>M07: MatchBOMRecord(工作表, 参数) Note over M07: 支持双值匹配 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 - 入口模块 **职责**: 系统入口,提供简洁的用户接口 ```vba 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生成) → 输出结果 → 清理资源 ``` **两阶段验证架构**: 该模块实现了关键的**两阶段验证架构**,将匹配与验证分离: 1. **Phase 1 - 收集阶段** (`MatchAllMaterialTypesWithValidation`): - 遍历所有BOM库工作表 - 调用 `M07_BOMMatcher.MatchBOMRecord()` 获取匹配结果 - 对于"部件"工作表,额外调用 `M08_ComponentProcessor.ProcessComponentRecord()` - **关键点:不记录任何错误**,仅收集原始匹配结果 - 存储每个工作表的:success、rowCount、rowNums、materials 2. **Phase 2 - 验证阶段** (`ValidateAllMatchResults`): - 统一验证所有收集到的匹配结果 - 应用跨工作表验证规则 - 区分错误(blocking)和警告(non-blocking) - 记录所有错误和警告到Logger 3. **Phase 3 - 生成阶段**: - 根据验证结果生成最终物料集合 - 即使验证失败,也返回物料用于错误显示 --- ### 3. 两阶段验证架构详解 #### 为什么需要两阶段验证? 在BOM提取系统中,"部件"、"接头"、"弹性元件"三个工作表之间存在复杂的互斥和替代关系: - **部件表**可能返回:1个组件 或 1个接头+1个弹性元件 - **接头表**可能返回:1个接头 - **弹性元件表**可能返回:1个弹性元件 如果立即记录错误,无法判断全局情况。例如: - 部件表返回了组件,但接头表也匹配到接头 → 这是冲突,应该警告而非错误 - 部件表返回了接头+弹性元件,但独立表也匹配到 → 这是冲突,应该警告而非错误 #### Phase 1: 收集阶段(不记录错误) **代码位置**: `M09_BOMExtractor.MatchAllMaterialTypesWithValidation()` (lines 387-541) **流程**: ```vba 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) **流程**: ```vba 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. M06A_Mapper.bas - 值映射器 **职责**: 为参数值添加映射值,支持双值匹配 **映射表配置** (M04_Config): | 配置项 | 值 | 说明 | |--------|-----|------| | `MAPPING_SHEET_NAME` | "对照表" | 映射表工作表名称 | | `MAPPING_COL_LCFW_KEY` | 1 (A列) | lcfw原始值列 | | `MAPPING_COL_LCFW_VAL` | 2 (B列) | lcfw映射值列 | | `MAPPING_COL_AZXS_KEY` | 4 (D列) | azxs原始值列 | | `MAPPING_COL_AZXS_VAL` | 5 (E列) | azxs映射值列 | | `MAPPING_START_ROW` | 3 | 数据起始行 | **映射数据结构**: **对照表** 工作表格式: | 行号 | A列 (lcfw key) | B列 (lcfw val) | D列 (azxs key) | E列 (azxs val) | |------|----------------|----------------|----------------|----------------| | 1-2 | (表头) | (表头) | (表头) | (表头) | | 3 | M01 | 低压 | A0 | 径向 | | 4 | M12 | 高压 | AT | 径向 | | 5 | - | - | B0 | 下轴向 | **核心功能**: ```vba ' 初始化映射器 Public Sub InitMapper(logger As clsErrorLogger, wsMapping As Worksheet) ' 映射azxs值 Public Function MapAzxs(ByVal rawValue As String) As String ' 输入: "A0" ' 输出: "A0,径向" ' 映射lcfw值 Public Function MapLcfw(ByVal rawValue As String) As String ' 输入: "M01" ' 输出: "M01,低压" ``` **双值格式匹配**: 参数存储为双值格式后,在BOM匹配时支持灵活匹配: | 参数值 | BOM库值 | 匹配结果 | 原因 | |--------|---------|----------|------| | `azxs="A0,径向"` | `azxs=A0` | ✅ 匹配 | 参数包含"A0" | | `azxs="A0,径向"` | `azxs=径向` | ✅ 匹配 | 参数包含"径向" | | `azxs="A0,径向"` | `azxs=AT` | ❌ 不匹配 | 参数不包含"AT" | **优雅降级**: 如果"对照表"工作表不存在: - 系统记录警告(非阻塞) - 继续使用原始值进行匹配 - 功能正常运行,仅失去映射增强 **未映射值处理**: 如果值在映射表中不存在: - 仅返回原始值(无逗号) - 匹配时退化为精确匹配 - 不影响其他参数的匹配 **示例流程**: ``` 1. 产品型号: YTHN-100.A0.531.G123.M04.Y3 2. M06_ModelParser提取: azxs="A0", lcfw="M04" 3. M06A_Mapper映射: - azxs: "A0" → "A0,径向" - lcfw: "M04" → "M04,高压" 4. BOM库匹配: - BOM库有azxs="径向" → 匹配成功 - BOM库有lcfw="高压" → 匹配成功 ``` --- ### 5. M06_ModelParser.bas - 型号解析器 **职责**: 从产品型号字符串中提取参数 **产品型号格式**: ``` [型号-公称外径].[安装形式].[表壳形式].[过程连接&接液材质].[量程范围].[附加功能]|[扩展信息] ``` **示例**: `YTHN-100.A0.531.G123.M04.Y3|BP-088.2312.B09.0A3` **提取的参数**: | 参数 | 描述 | 原始值 | 映射后值 | 转换规则 | |------|------|--------|----------|----------| | xh | 型号 | YTHN | YTHN | 从YTHN-100提取横线前部分(无映射) | | gcwj | 公称外径 | 100 | 100 | 从YTHN-100提取横线后数字(无映射) | | azxs | 安装形式 | A0 | A0,径向 | 直接提取,然后应用M06A_Mapper映射 | | bkxs | 表壳形式 | 531 | 531 | 直接提取(无映射) | | gclj | 过程连接 | G12 | G12 | 从G123去除末位(无映射) | | jycz | 接液材质 | 3 | 3 | 从G123提取末位(无映射) | | lcfw | 量程范围 | M04 | M04,高压 | 直接提取,然后应用M06A_Mapper映射 | | fjgn | 附加功能 | Y3 | Y3 | 直接提取,多段用逗号连接(无映射) | **值映射集成**: ```vba ' 1. 提取原始值 azxsRaw = ExtractAzxs(segments(1)) ' "A0" lcfwRaw = ExtractLcfw(segments(4)) ' "M04" ' 2. 应用映射(如果映射器已初始化) If M06A_Mapper.IsInitialized() Then params("azxs") = M06A_Mapper.MapAzxs(azxsRaw) ' "A0,径向" params("lcfw") = M06A_Mapper.MapLcfw(lcfwRaw) ' "M04,高压" Else ' 映射器未初始化,使用原始值 params("azxs") = azxsRaw ' "A0" params("lcfw") = lcfwRaw ' "M04" End If ``` **核心函数**: ```vba Public Function ParseProductModel(ByVal modelStr As String) As Object ' 返回包含8个参数的字典 ' 如果M06A_Mapper已初始化,azxs和lcfw将包含映射值 End Function ``` --- ### 6. M07_BOMMatcher.bas - BOM匹配器 **职责**: 根据参数在BOM库中查找匹配记录 **匹配规则**: | 单元格值 | 匹配逻辑 | |----------|----------| | 空白 | 通配符,匹配所有 | | `!value` | 负向匹配,不等于该值 | | `value` | 精确匹配或双值匹配 | | `fjgn`列 | 包含匹配,value包含在参数中 | **双值匹配** (新增功能): 当参数包含映射值时(如`azxs="A0,径向"`),支持灵活匹配: ``` ' EvaluateCellCondition函数逻辑 IF paramValue包含逗号 THEN ' 拆分为多个值 paramValues = Split(paramValue, ",") ' 只要任意一个值匹配单元格值,即认为匹配 FOR EACH pv IN paramValues IF pv = cellStr THEN RETURN True ' 匹配成功 END IF NEXT RETURN False ' 所有值都不匹配 ELSE ' 单值精确匹配 RETURN (paramValue = cellStr) END IF ``` **双值匹配示例**: | 参数值 | BOM库单元格值 | 匹配结果 | 说明 | |--------|---------------|----------|------| | `azxs="A0,径向"` | `azxs=A0` | ✅ 匹配 | 参数包含"A0" | | `azxs="A0,径向"` | `azxs=径向` | ✅ 匹配 | 参数包含"径向" | | `azxs="A0,径向"` | `azxs=AT` | ❌ 不匹配 | 参数不包含"AT" | | `lcfw="M01,低压"` | `lcfw=M01` | ✅ 匹配 | 参数包含"M01" | | `lcfw="M01,低压"` | `lcfw=低压` | ✅ 匹配 | 参数包含"低压" | | `lcfw="M01,低压"` | `lcfw=高压` | ❌ 不匹配 | 参数不包含"高压" | **匹配逻辑**: ``` 对于每条记录: 对于每个参数: IF 单元格为空 THEN 匹配成功 ELSE IF 单元格以"!"开头 THEN IF 参数 != 去掉"!"的值 THEN 匹配成功 ELSE 匹配失败 ELSE IF 列名 = "fjgn" THEN IF 参数包含单元格值 THEN 匹配成功 ELSE 匹配失败 ELSE IF 参数包含逗号 THEN ' 双值匹配:检查任意一个值是否匹配 FOR EACH pv IN Split(参数, ",") IF pv = 单元格值 THEN 匹配成功 NEXT 匹配失败 ELSE ' 单值精确匹配 IF 参数 = 单元格值 THEN 匹配成功 ELSE 匹配失败 END IF IF 所有参数都匹配成功 THEN 返回该记录 NEXT ``` **匹配要求**: - 必须有且仅有1条匹配记录 - 0条 = 未找到匹配 - 多条 = 匹配不唯一 **向后兼容**: - 单值参数(无逗号)退化为精确匹配 - 不影响现有的非映射参数 --- ### 7. M08_ComponentProcessor.bas - 部件处理器 **职责**: 处理"部件"类物料的特殊逻辑 **部件结构**: ``` 部件记录包含: - 自身信息 (物料编码A, 数量A) - 子组件1 - 接头 (物料编码B, 数量B) - 子组件2 - 弹性元件 (物料编码C, 数量C) ``` **选择策略**: ```mermaid 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[✗ 无效组合:
不能同时使用组件和子组件] 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 ``` **有效组合**: 1. ✅ 仅组件A (优先级1) 2. ✅ 仅子组件B + 子组件C (优先级2) 3. ❌ 组件A + 子组件 (无效) 4. ❌ 仅部分子组件 (无效) --- ## 数据结构 ### 输入数据结构 **产品型号工作表**: | 行号 | 列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输出): ```vba Dictionary { "xh": "YTHN", "gcwj": "100", "azxs": "A0,径向", // 双值格式(原始值,映射值) "bkxs": "531", "gclj": "G12", "jycz": "3", "lcfw": "M04,高压", // 双值格式(原始值,映射值) "fjgn": "Y3" } ``` **注意**: 如果M06A_Mapper未初始化或值未找到映射,则退化为单值格式。 **列映射字典** (M07_BOMMatcher): ```vba Dictionary { "azxs": 1, "bkxs": 2, "gclj": 3, ... "物料编码": 10, "物料名称": 11, "数量": 12 } ``` **物料信息字典** (M07_BOMMatcher输出): ```vba Dictionary { "物料编码": "JT-001", "物料名称": "卡套式接头", "数量": 1, "物料类型": "接头" } ``` **结果集合** (M09_BOMExtractor汇总): ```vba Collection { Array(型号, azxs, bkxs, gclj, jycz, lcfw, fjgn, 物料类型, 物料名称, 物料编码, 数量, 备注), Array(...), // 第二条物料 ... } ``` --- ## 错误处理机制 ### 错误分类 | 错误类型 | 级别 | 处理方式 | 示例 | |----------|------|----------|------| | 工作表不存在 | 致命 | 立即返回 | 未找到产品型号工作表 | | BOM库不存在 | 致命 | 立即返回 | 未找到BOM库.xlsx | | 型号解析失败 | 警告 | 记录错误,跳过 | 型号格式错误 | | 无匹配记录 | 警告 | 记录错误,继续 | 未找到匹配物料 | | 多重匹配 | 警告 | 记录错误,继续 | 找到多个匹配 | | 组件组合无效 | 警告 | 记录错误,继续 | 组件与子组件混用 | | 跨工作表冲突 | 警告 | 记录警告,继续 | 部件表与接头表同时匹配 | --- ### 两阶段验证错误处理 #### Phase 1: 收集阶段(不记录错误) 在收集阶段,系统**不记录任何错误**,原因如下: 1. **需要全局信息**: 判断是否为错误需要看所有工作表的匹配结果 2. **避免误报**: 部件表返回组件时,接头表也匹配是警告而非错误 3. **优先级处理**: 部件表的返回优先级高于独立表 示例: ```vba ' Phase 1 收集阶段 - 不记录错误 Set matchResult = M07_BOMMatcher.MatchBOMRecord(ws, params) ' 即使 matchResult("rowCount") = 0 或 > 1,也不记录错误 resultsDict.Add ws.Name, matchResult ``` #### Phase 2: 验证阶段(记录错误和警告) 在验证阶段,系统根据**跨工作表规则**统一验证: **错误示例**(阻塞,红色): ``` [接头] 未匹配到记录 [机芯] 匹配到2条记录 部件、接头、弹性元件均未匹配或组合不完整 ``` **警告示例**(非阻塞,黄色): ``` 存在[部件]物料,但[接头]工作表也匹配到1条记录,已忽略 [部件]工作表已返回弹性元件,但[弹性元件]工作表也匹配到1条记录,已忽略 ``` **Logger调用**: ```vba ' 记录错误(阻塞) logger.Record 0, "M09.ValidateAllMatchResults", "BOMMatchError", errorMessage, "" ' 记录警告(非阻塞) logger.RecordWarning 0, "M09.ValidateAllMatchResults", "ComponentConflict", warningMessage, "" ``` --- ### 错误日志机制 ```mermaid flowchart LR subgraph "错误检测" A[检测到错误/警告] end subgraph "两阶段验证" B1[Phase 1: 收集
不记录错误] B2[Phase 2: 验证
记录错误和警告] end subgraph "错误记录" C[clsErrorLogger] C1[logger.Record
错误(红色)] C2[logger.RecordWarning
警告(黄色)] 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方法**: ```vba ' 记录错误(阻塞) logger.Record rowIndex, sourceModule, errorType, description, context ' 记录警告(非阻塞) logger.RecordWarning rowIndex, sourceModule, warningType, description, context ``` **错误信息格式**: ``` [错误类型] 详细描述 - 行号: X - 数据: [具体数据] ``` --- ### 错误恢复策略 1. **继续处理**: 遇到非致命错误时继续处理下一条记录 2. **错误累积**: 所有错误都记录在日志中 3. **最终报告**: 处理完成后显示汇总报告 4. **部分成功**: 部分记录成功时仍然输出结果 5. **两阶段验证**: Phase 1不中断,Phase 2统一验证 --- ## 使用示例 ### 示例1: 基本使用 ```vba ' 在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) 缺货 **处理逻辑**: 1. 检测到组件A缺货 2. 检查子组件B (JT-002) 和C (MH-003) 库存 3. 如果都有库存,使用子组件替代 4. 验证组合: 只有子组件,无组件A ✓ **输出结果**: | 物料类型 | 物料名称 | 物料编码 | 数量 | 备注 | |----------|----------|----------|------|------| | 接头 | 卡套式接头 | JT-002 | 2 | (子组件B) | | 弹性元件 | 膜片 | MH-003 | 1 | (子组件C) | --- ### 示例3: 错误处理 **场景**: 型号解析失败 **输入**: ``` INVALID.MODEL.FORMAT ``` **处理流程**: 1. M06_ModelParser尝试解析 2. 检测到格式不匹配 3. 记录错误到Logger 4. 跳过该型号,继续下一个 **输出**: | 原始产品型号 | 备注 | |--------------|------| | INVALID.MODEL.FORMAT | [解析错误] 型号格式不符合要求,无法提取参数 | 备注单元格会以红色高亮显示。 --- ## 附录: 快速参考 ### 常用函数速查 | 模块 | 函数 | 用途 | |------|------|------| | M01_Main | `RunBOMExtraction()` | 系统入口 | | M09_BOMExtractor | `RunBOMExtraction()` | 主流程控制 | | M09_BOMExtractor | `ProcessSingleModel()` | 处理单个型号 | | M09_BOMExtractor | `MatchAllMaterialTypesWithValidation()` | 匹配所有物料类型(两阶段验证) | | M09_BOMExtractor | `ValidateAllMatchResults()` | 统一验证所有匹配结果(跨工作表规则) | | M06_ModelParser | `ParseProductModel()` | 解析型号参数 | | M06A_Mapper | `InitMapper()` | 初始化值映射器 | | M06A_Mapper | `MapAzxs()` | 映射azxs参数值 | | M06A_Mapper | `MapLcfw()` | 映射lcfw参数值 | | M07_BOMMatcher | `MatchBOMRecord()` | 匹配BOM记录(支持双值匹配) | | M07_BOMMatcher | `EvaluateCellCondition()` | 评估单元格条件(支持双值匹配) | | M07_BOMMatcher | `BuildHeaderMapping()` | 构建列映射 | | M08_ComponentProcessor | `ProcessComponentRecord()` | 处理部件特殊逻辑 | --- ### 配置参数 | 配置项 | 值 | 说明 | |--------|-----|------| | 输入工作表名 | "产品型号" | 可含"型号"列 | | 映射表工作表名 | "对照表" | 可选,用于值映射 | | BOM库文件名 | "BOM库.xlsx" | 必须在同一目录 | | 输出工作表名 | "BOM提取结果" | 自动创建/覆盖 | | 数据起始行 | 2 | 行1为表头 | | 映射表数据起始行 | 3 | 行1-2为表头 | | 支持的物料类型 | 接头, 弹性元件, 机芯, 部件, 边 | 可扩展 | | 支持的映射参数 | azxs, lcfw | 从对照表加载映射 | --- ### 相关文档 - [M03_Logic_Algorithm.md](./M03_Logic_Algorithm.md) - 条件解析算法详解 - [Test_PP_06_FullIntegration_流程详解.md](./Test_PP_06_FullIntegration_流程详解.md) - 预处理系统集成测试 - [CLAUDE.md](../CLAUDE.md) - 项目整体说明 --- **文档版本**: 3.0 **最后更新**: 2026-02-12 **作者**: Claude Code **状态**: 更新完成 - 新增值映射功能文档 **版本历史**: - v3.0 (2026-02-12): 重大更新 - 添加值映射(M06A_Mapper)功能文档,更新架构图、数据流图、核心流程图、模块交互时序图 - v2.0 (2026-02-12): 重大更新 - 添加两阶段验证架构详解,更新数据流图、核心流程图、模块交互时序图 - v1.0 (2026-02-12): 初稿完成