All checks were successful
NTFY Notification / notify (push) Successful in 3s
Implement edge material validation logic that behaves differently based on azxs value: - When azxs is A0, Z0, or B0: Edge material is NOT required (0 matches = OK, 1+ matches = ERROR) - When azxs is AH, AT, BH, BT, BZ, ZH, ZT, or ZZ: Standard validation applies (exactly 1 match required) - Supports dual-value azxs format (e.g., "A0,径向" extracts "A0" for validation) Changes: - M09_BOMExtractor.bas: - Update MatchAllMaterialTypesWithValidation to pass params to validation - Update ValidateAllMatchResults signature to accept params parameter - Add "边" to special sheets array - Implement Phase 3.5: Edge material validation with azxs-based rules - Update function header comments - docs/BOM匹配错误判断机制详解.md: - Add section 6.5: Edge material special handling - Update error type table with EdgeMaterialError - Update function index and version history Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1445 lines
47 KiB
Markdown
1445 lines
47 KiB
Markdown
# BOM匹配错误判断机制详解
|
||
|
||
## 目录
|
||
1. [系统概述](#1-系统概述)
|
||
2. [核心匹配算法 (M07_BOMMatcher)](#2-核心匹配算法-m07_bommatcher)
|
||
3. [错误类型与检测](#3-错误类型与检测)
|
||
4. [决策树与流程图](#4-决策树与流程图)
|
||
5. [错误场景实例](#5-错误场景实例)
|
||
6. [部件特殊处理](#6-部件特殊处理)
|
||
7. [错误报告机制](#7-错误报告机制)
|
||
8. [快速参考](#8-快速参考)
|
||
|
||
---
|
||
|
||
**重大更新 (v2.1 - 2025-02-12):**
|
||
- ✅ 新增边材料特殊验证(基于azxs参数)
|
||
- ✅ 支持A0/Z0/B0不需要边的规则
|
||
- ✅ 支持AH/AT/BH/BT/BZ/ZH/ZT/ZZ需要边的规则
|
||
|
||
**重大更新 (v2.0 - 2025-02-12):**
|
||
- ✅ 实施两阶段验证机制(收集 → 验证)
|
||
- ✅ 新增警告类型(非阻断性错误)
|
||
- ✅ 部件/接头/弹性元件交叉验证增强
|
||
- ✅ 错误报告增加"类型"列(错误/警告)
|
||
|
||
---
|
||
|
||
## 1. 系统概述
|
||
|
||
### 1.1 什么是BOM匹配?
|
||
|
||
BOM匹配是AutoBOM系统的核心功能,它根据产品型号中提取的参数(如`azxs`、`bkxs`、`gclj`、`jycz`、`lcfw`、`fjgn`等),在BOM库中查找**恰好1条**匹配的物料记录。
|
||
|
||
**核心目标:精确匹配(1:1匹配)**
|
||
|
||
| 匹配结果 | 状态 | 说明 |
|
||
|---------|------|------|
|
||
| 0条记录 | ❌ 失败 | 未找到匹配物料 |
|
||
| 1条记录 | ✅ 成功 | 唯一匹配,可提取物料信息 |
|
||
| 2+条记录 | ❌ 失败 | 模糊匹配,无法确定唯一物料 |
|
||
|
||
### 1.2 为什么错误判断至关重要?
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ 错误判断的业务价值 │
|
||
├─────────────────────────────────────────────────────────┤
|
||
│ ✓ 防止错误物料流入生产环节 │
|
||
│ ✓ 避免停工待料(库存不足) │
|
||
│ ✓ 减少人工纠错成本 │
|
||
│ ✓ 保证BOM准确性(可追溯性) │
|
||
│ ✓ 提高生产效率和产品质量 │
|
||
└─────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 1.3 匹配哲学:精确匹配原则
|
||
|
||
AutoBOM系统采用**严格的一对一匹配原则**,并采用**两阶段验证机制**:
|
||
|
||
```mermaid
|
||
graph LR
|
||
A[产品型号参数] --> B{阶段1: 收集<br/>所有工作表匹配结果}
|
||
B --> C{阶段2: 统一验证}
|
||
C -->|0条匹配| D[❌ 失败<br/>记录错误]
|
||
C -->|1条匹配| E[✅ 成功<br/>提取物料]
|
||
C -->|2+条匹配| F[❌ 失败<br/>记录错误]
|
||
C -->|特殊情况| G[⚠️ 警告<br/>记录但不阻断]
|
||
|
||
style D fill:#ff6b6b
|
||
style E fill:#51cf66
|
||
style F fill:#ff6b6b
|
||
style G fill:#ffd43b
|
||
```
|
||
|
||
**两阶段验证的优势:**
|
||
- **阶段1(收集)**: 不立即判断错误,保留所有匹配结果
|
||
- **阶段2(验证)**: 统一分析,支持交叉验证
|
||
- **警告机制**: 非阻断性问题(如部件与子件共存)记录警告但不停止处理
|
||
|
||
**拒绝"模糊匹配"的原因:**
|
||
- 0条匹配 → 可能遗漏关键参数或BOM库不完整
|
||
- 2+条匹配 → 存在歧义,可能导致发错料
|
||
|
||
---
|
||
|
||
## 2. 核心匹配算法 (M07_BOMMatcher)
|
||
|
||
### 2.1 MatchBOMRecord() 函数详解
|
||
|
||
`MatchBOMRecord()` 是BOM匹配的主入口函数,位于 `M07_BOMMatcher.bas` 模块。
|
||
|
||
**函数签名:**
|
||
```vba
|
||
Public Function MatchBOMRecord( _
|
||
ByVal ws As Worksheet, _
|
||
ByVal params As Object _
|
||
) As Object
|
||
```
|
||
|
||
**输入参数:**
|
||
- `ws`: BOM库工作表对象(如"接头"、"弹性元件"等)
|
||
- `params`: 从产品型号中提取的参数字典
|
||
|
||
**输出结构:**
|
||
```vba
|
||
' 返回字典包含以下键:
|
||
result("success") ' Boolean - 是否恰好匹配1条
|
||
result("rowCount") ' Long - 匹配到的记录数量
|
||
result("rowNums") ' Collection - 匹配到的行号集合
|
||
result("message") ' String - 结果描述
|
||
```
|
||
|
||
### 2.2 匹配流程图
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start([开始匹配]) --> InputValidate{验证输入}
|
||
InputValidate -->|ws为空| Error1[返回: 工作表为空]
|
||
InputValidate -->|params为空| Error2[返回: 参数字典为空]
|
||
InputValidate -->|验证通过| ReadData[读取工作表数据到数组]
|
||
|
||
ReadData --> CheckEmpty{是否有数据?}
|
||
CheckEmpty -->|无数据| Error3[返回: 工作表无数据]
|
||
CheckEmpty -->|有数据| BuildMap[构建表头映射]
|
||
|
||
BuildMap --> LoopStart[遍历数据行]
|
||
LoopStart --> EvalRow{评估该行<br/>是否匹配?}
|
||
EvalRow -->|匹配| AddRow[添加到匹配集合]
|
||
EvalRow -->|不匹配| NextRow{下一行?}
|
||
AddRow --> NextRow
|
||
|
||
NextRow -->|是| LoopStart
|
||
NextRow -->|否| CheckCount{检查匹配数量}
|
||
|
||
CheckCount -->|0条| Error4[返回: 未找到匹配记录]
|
||
CheckCount -->|1条| Success[返回: 匹配成功]
|
||
CheckCount -->|2+条| Error5[返回: 匹配到N条记录]
|
||
|
||
style Success fill:#51cf66
|
||
style Error1 fill:#ff6b6b
|
||
style Error2 fill:#ff6b6b
|
||
style Error3 fill:#ff6b6b
|
||
style Error4 fill:#ff6b6b
|
||
style Error5 fill:#ff6b6b
|
||
```
|
||
|
||
### 2.3 EvaluateCellCondition() 单元格匹配规则
|
||
|
||
`EvaluateCellCondition()` 是最核心的判断逻辑,决定单个单元格是否满足匹配条件。
|
||
|
||
**函数签名:**
|
||
```vba
|
||
Public Function EvaluateCellCondition( _
|
||
ByVal cellValue As Variant, _
|
||
ByVal paramValue As String, _
|
||
ByVal fieldName As String _
|
||
) As Boolean
|
||
```
|
||
|
||
#### 2.3.1 匹配规则优先级
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[评估单元格条件] --> B{单元格为空?}
|
||
B -->|是| C[✅ 通配符匹配<br/>返回True]
|
||
|
||
B -->|否| D{以!=开头?}
|
||
D -->|是| E[否定匹配<br/>paramValue ≠ notValue?]
|
||
|
||
D -->|否| F{字段是fjgn?}
|
||
F -->|是| G[包含匹配<br/>InStr判断]
|
||
|
||
F -->|否| H[精确匹配<br/>paramValue = cellValue?]
|
||
|
||
E --> I{条件满足?}
|
||
G --> I
|
||
H --> I
|
||
|
||
I -->|是| J[返回True]
|
||
I -->|否| K[返回False]
|
||
|
||
style C fill:#51cf66
|
||
style J fill:#51cf66
|
||
style K fill:#ff6b6b
|
||
```
|
||
|
||
#### 2.3.2 详细规则说明
|
||
|
||
| 规则类型 | BOM库单元格值 | 提取参数值 | 匹配结果 | 说明 |
|
||
|---------|--------------|-----------|---------|------|
|
||
| **空单元格** | `(空)` | 任意值 | ✅ 匹配 | 空单元格作为通配符,匹配所有值 |
|
||
| **否定匹配** | `!=A0` | `A0` | ❌ 不匹配 | 参数值等于否定值时失败 |
|
||
| **否定匹配** | `!=A0` | `AT` | ✅ 匹配 | 参数值不等于否定值时成功 |
|
||
| **fjgn包含** | `N1` | `N1,N2,N3` | ✅ 匹配 | 使用`InStr()`判断包含关系 |
|
||
| **fjgn包含** | `N4` | `N1,N2,N3` | ❌ 不匹配 | 不包含时失败 |
|
||
| **精确匹配** | `A0` | `A0` | ✅ 匹配 | 字符串完全相等 |
|
||
| **精确匹配** | `A0` | `AT` | ❌ 不匹配 | 字符串不相等 |
|
||
|
||
**代码实现:**
|
||
```vba
|
||
' 1. 空单元格:通配符
|
||
If IsEmpty(cellValue) Or Len(Trim(CStr(cellValue))) = 0 Then
|
||
EvaluateCellCondition = True
|
||
Exit Function
|
||
End If
|
||
|
||
' 2. 否定条件 (!=开头)
|
||
If Left(cellStr, 2) = "!=" Then
|
||
notValue = Trim(Mid(cellStr, 3))
|
||
EvaluateCellCondition = (paramValue <> notValue)
|
||
Exit Function
|
||
End If
|
||
|
||
' 3. fjgn字段:包含匹配
|
||
If LCase(fieldName) = "fjgn" Then
|
||
EvaluateCellCondition = CheckFjgnMatch(cellStr, paramValue)
|
||
Exit Function
|
||
End If
|
||
|
||
' 4. 精确匹配
|
||
EvaluateCellCondition = (paramValue = cellStr)
|
||
```
|
||
|
||
### 2.4 AND逻辑要求
|
||
|
||
匹配算法采用**AND逻辑**:所有参数列必须同时满足条件,该行才匹配成功。
|
||
|
||
```mermaid
|
||
graph LR
|
||
A[参数1: azxs=A0] --> B{匹配?}
|
||
B -->|否| C[❌ 整行不匹配]
|
||
|
||
B -->|是| D[参数2: gclj=M20]
|
||
D --> E{匹配?}
|
||
E -->|否| C
|
||
|
||
E -->|是| F[参数3: jycz=1]
|
||
F --> G{匹配?}
|
||
G -->|否| C
|
||
G -->|是| H[✅ 整行匹配]
|
||
|
||
style C fill:#ff6b6b
|
||
style H fill:#51cf66
|
||
```
|
||
|
||
**代码实现:**
|
||
```vba
|
||
Private Function EvaluateConditionRow( _
|
||
ByRef bomData As Variant, _
|
||
ByVal rowIdx As Long, _
|
||
ByVal headerMap As Object, _
|
||
ByVal params As Object _
|
||
) As Boolean
|
||
Dim paramKey As Variant
|
||
|
||
' 遍历所有参数
|
||
For Each paramKey In params.keys
|
||
Dim paramValue As String
|
||
paramValue = CStr(params(paramKey))
|
||
|
||
' 检查BOM库中是否有该列
|
||
If headerMap.Exists(CStr(paramKey)) Then
|
||
Dim colIdx As Long
|
||
colIdx = headerMap(CStr(paramKey))
|
||
|
||
' 获取单元格值
|
||
Dim cellValue As Variant
|
||
cellValue = bomData(rowIdx, colIdx)
|
||
|
||
' 评估单元格条件
|
||
If Not EvaluateCellCondition(cellValue, paramValue, CStr(paramKey)) Then
|
||
' 只要有一个条件不满足,该行就不匹配
|
||
EvaluateConditionRow = False
|
||
Exit Function
|
||
End If
|
||
End If
|
||
Next paramKey
|
||
|
||
' 所有条件都满足
|
||
EvaluateConditionRow = True
|
||
End Function
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 错误类型与检测
|
||
|
||
### 3.1 错误类型总览
|
||
|
||
```mermaid
|
||
graph TD
|
||
A[BOM匹配错误] --> B[匹配数量错误]
|
||
A --> C[系统错误]
|
||
A --> D[部件验证错误]
|
||
|
||
B --> B1[0条匹配<br/>No Match]
|
||
B --> B2[2+条匹配<br/>Multiple Match]
|
||
|
||
C --> C1[工作表为空]
|
||
C --> C2[参数字典为空]
|
||
C --> C3[工作表无数据]
|
||
C --> C4[运行时异常]
|
||
|
||
D --> D1[部件+子件共存]
|
||
D --> D2[接头数量≠弹性元件数量]
|
||
D --> D3[缺少部件和子件]
|
||
|
||
style B1 fill:#ff6b6b
|
||
style B2 fill:#ff6b6b
|
||
style C1 fill:#ffa94d
|
||
style C2 fill:#ffa94d
|
||
style C3 fill:#ffa94d
|
||
style C4 fill:#ffa94d
|
||
style D1 fill:#845ef7
|
||
style D2 fill:#845ef7
|
||
style D3 fill:#845ef7
|
||
```
|
||
|
||
### 3.2 匹配数量错误
|
||
|
||
#### 3.2.1 0条匹配 (No Match)
|
||
|
||
**触发条件:** 在BOM库中未找到任何满足条件的记录
|
||
|
||
**错误信息:** `"未找到匹配记录"`
|
||
|
||
**常见原因:**
|
||
1. BOM库中确实没有该配置的物料
|
||
2. 产品型号解析错误(参数提取不正确)
|
||
3. BOM库配置条件过于严格
|
||
4. 参数值拼写错误
|
||
|
||
**检测位置:** `M07_BOMMatcher.bas:128-130`
|
||
```vba
|
||
If matchingRows.count = 0 Then
|
||
result("success") = False
|
||
result("message") = "未找到匹配记录"
|
||
End If
|
||
```
|
||
|
||
#### 3.2.2 2+条匹配 (Multiple Match)
|
||
|
||
**触发条件:** 在BOM库中找到多条满足条件的记录
|
||
|
||
**错误信息:** `"匹配到N条记录(需要恰好1条)"`
|
||
|
||
**常见原因:**
|
||
1. BOM库中存在重复记录
|
||
2. 配置条件不够细化(列数不足或值过于宽泛)
|
||
3. 空单元格过多(通配符导致模糊匹配)
|
||
|
||
**检测位置:** `M07_BOMMatcher.bas:134-137`
|
||
```vba
|
||
Else
|
||
result("success") = False
|
||
result("message") = "匹配到" & matchingRows.count & "条记录(需要恰好1条)"
|
||
End If
|
||
```
|
||
|
||
### 3.3 系统错误
|
||
|
||
| 错误类型 | 错误信息 | 触发条件 | 检测位置 |
|
||
|---------|---------|---------|---------|
|
||
| 工作表为空 | `"工作表为空"` | `ws Is Nothing` | `M07_BOMMatcher.bas:62-68` |
|
||
| 参数字典为空 | `"参数字典为空"` | `params Is Nothing Or params.count = 0` | `M07_BOMMatcher.bas:71-78` |
|
||
| 工作表无数据 | `"工作表无数据"` | `lastRow < BOMLIB_START_ROW` | `M07_BOMMatcher.bas:90-96` |
|
||
| 运行时异常 | `"系统错误: {Err.Description}"` | `Err.Number <> 0` | `M07_BOMMatcher.bas:142-152` |
|
||
|
||
### 3.4 部件验证错误
|
||
|
||
部件物料有特殊的组合验证规则,详见[第6章:部件特殊处理](#6-部件特殊处理)。
|
||
|
||
---
|
||
|
||
## 4. 决策树与流程图
|
||
|
||
### 4.1 完整匹配流程决策树(两阶段验证)
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[开始: 接收产品型号] --> B[解析型号提取参数]
|
||
B --> C{参数提取成功?}
|
||
C -->|否| Err1[记录错误: 型号解析失败]
|
||
C -->|是| D[阶段1: 收集所有工作表匹配结果]
|
||
|
||
D --> E{是'部件'工作表?}
|
||
E -->|是| F[调用M08_ComponentProcessor<br/>存入resultsDict]
|
||
E -->|否| G[调用M07_BOMMatcher<br/>存入resultsDict]
|
||
|
||
F --> H{更多工作表?}
|
||
G --> H
|
||
H -->|是| D
|
||
H -->|否| I[阶段2: 统一验证所有结果]
|
||
|
||
I --> J{基础验证<br/>非特殊工作表}
|
||
J --> K{特殊验证<br/>部件/接头/弹性元件}
|
||
|
||
K --> L{验证通过?}
|
||
L -->|否| ErrV[记录验证错误]
|
||
L -->|是| M{有警告?}
|
||
|
||
M -->|是| Warn[记录警告<br/>不阻断流程]
|
||
M -->|否| N[生成输出行]
|
||
Warn --> N
|
||
|
||
Err1 --> O[写入错误报告]
|
||
ErrV --> O
|
||
Warn --> O
|
||
N --> P[写入结果工作表]
|
||
|
||
style Err1 fill:#ff6b6b
|
||
style ErrV fill:#ff6b6b
|
||
style Warn fill:#ffd43b
|
||
style N fill:#51cf66
|
||
```
|
||
|
||
### 4.2 错误检测决策树
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start([匹配结果检测]) --> CheckCount{匹配数量?}
|
||
|
||
CheckCount -->|0| TypeA[No Match<br/>未找到匹配记录]
|
||
CheckCount -->|1| Success[Success<br/>匹配成功]
|
||
CheckCount -->|2+| TypeB[Multiple Match<br/>匹配到N条记录]
|
||
|
||
TypeA --> AnalyzeA[分析原因]
|
||
TypeB --> AnalyzeB[分析原因]
|
||
|
||
AnalyzeA --> CauseA1{BOM库缺失?}
|
||
CauseA1 -->|是| FixA1[补充BOM库记录]
|
||
CauseA1 -->|否| CauseA2{解析错误?}
|
||
CauseA2 -->|是| FixA2[检查型号解析逻辑]
|
||
CauseA2 -->|否| FixA3[检查配置条件]
|
||
|
||
AnalyzeB --> CauseB1{重复记录?}
|
||
CauseB1 -->|是| FixB1[删除重复记录]
|
||
CauseB1 -->|否| CauseB2{条件过宽?}
|
||
CauseB2 -->|是| FixB2[细化配置列]
|
||
CauseB2 -->|否| FixB3[减少空单元格]
|
||
|
||
style Success fill:#51cf66
|
||
style TypeA fill:#ff6b6b
|
||
style TypeB fill:#ff6b6b
|
||
style FixA1 fill:#4dabf7
|
||
style FixA2 fill:#4dabf7
|
||
style FixA3 fill:#4dabf7
|
||
style FixB1 fill:#4dabf7
|
||
style FixB2 fill:#4dabf7
|
||
style FixB3 fill:#4dabf7
|
||
```
|
||
|
||
### 4.3 EvaluateCellCondition 逻辑流程
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[开始评估单元格] --> B{cellValue为空<br/>或IsEmpty?}
|
||
|
||
B -->|是| C[返回True<br/>通配符匹配]
|
||
|
||
B -->|否| D[转换cellValue为字符串]
|
||
D --> E{以'!='开头?}
|
||
|
||
E -->|是| F[提取notValue]
|
||
F --> G{paramValue <> notValue?}
|
||
G -->|是| H[返回True]
|
||
G -->|否| I[返回False]
|
||
|
||
E -->|否| J{fieldName是'fjgn'?}
|
||
|
||
J -->|是| K[调用CheckFjgnMatch]
|
||
K --> L{InStr包含判断}
|
||
L -->|是| H
|
||
L -->|否| I
|
||
|
||
J -->|否| M[精确匹配]
|
||
M --> N{paramValue = cellStr?}
|
||
N -->|是| H
|
||
N -->|否| I
|
||
|
||
style C fill:#51cf66
|
||
style H fill:#51cf66
|
||
style I fill:#ff6b6b
|
||
```
|
||
|
||
### 4.4 部件验证流程
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[验证部件组合] --> B{物料集合为空?}
|
||
|
||
B -->|是| Err1[返回: 物料列表为空]
|
||
|
||
B -->|否| C[统计各类型物料数量]
|
||
|
||
C --> D{有1个部件<br/>且无子件?}
|
||
D -->|是| Success1[验证通过: 1个部件]
|
||
|
||
D -->|否| E{无部件<br/>且有1个接头+1个弹性元件?}
|
||
E -->|是| Success2[验证通过: 1个接头+1个弹性元件]
|
||
|
||
E -->|否| F[组合异常判断]
|
||
|
||
F --> G{部件>1?}
|
||
G -->|是| Err2[部件数量为N(应为1)]
|
||
|
||
G -->|否| H{有部件且存在子件?}
|
||
H -->|是| Err3[同时存在部件和子件]
|
||
|
||
H -->|否| I{接头数≠弹性元件数?}
|
||
I -->|是| Err4[接头数N ≠ 弹性元件数M]
|
||
|
||
I -->|否| J{无部件且无子件?}
|
||
J -->|是| Err5[缺少部件和子件]
|
||
|
||
J -->|否| Err6[未知异常组合]
|
||
|
||
style Success1 fill:#51cf66
|
||
style Success2 fill:#51cf66
|
||
style Err1 fill:#ff6b6b
|
||
style Err2 fill:#ff6b6b
|
||
style Err3 fill:#ff6b6b
|
||
style Err4 fill:#ff6b6b
|
||
style Err5 fill:#ff6b6b
|
||
style Err6 fill:#ff6b6b
|
||
```
|
||
|
||
### 4.5 错误报告序列图
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant User as 用户
|
||
participant M09 as M09_BOMExtractor
|
||
participant M07 as M07_BOMMatcher
|
||
participant M08 as M08_ComponentProcessor
|
||
participant Logger as clsErrorLogger
|
||
|
||
User->>M09: 运行BOM提取
|
||
M09->>M07: MatchBOMRecord(ws, params)
|
||
|
||
alt 匹配失败
|
||
M07-->>M09: {success:False, message:"..."}
|
||
M09->>Logger: Record(0, "M09...", "BOMMatchError", message)
|
||
else 匹配成功
|
||
M07-->>M09: {success:True, rowNums:Collection}
|
||
end
|
||
|
||
M09->>M08: ValidateComponentCombination(materials)
|
||
|
||
alt 验证失败
|
||
M08-->>M09: {valid:False, message:"..."}
|
||
M09->>Logger: Record(0, "M09...", "ValidationError", message)
|
||
end
|
||
|
||
M09->>M09: 生成输出行(包含remarks)
|
||
M09->>Logger: HasErrors?
|
||
|
||
alt 有错误
|
||
Logger-->>M09: True
|
||
M09->>Logger: PrintReport(Workbook)
|
||
Logger->>Logger: 创建"错误报告_"工作表
|
||
end
|
||
|
||
M09-->>User: 返回处理结果消息
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 错误场景实例
|
||
|
||
### 5.1 场景1:0条匹配 - BOM库缺失
|
||
|
||
**输入条件:**
|
||
- 产品型号:`YTHN-100 M20 A0 1 M01 N1`
|
||
- 提取参数:`{azxs: "A0", gclj: "M20", jycz: "1", lcfw: "M01", fjgn: "N1"}`
|
||
- BOM库"接头"工作表:
|
||
| azxs | gclj | jycz | lcfw | 物料名称 |
|
||
|------|------|------|------|----------|
|
||
| AT | M20 | 1 | M01 | 接头AT |
|
||
| AH | M20 | 1 | M01 | 接头AH |
|
||
|
||
**匹配过程:**
|
||
```vba
|
||
' 第1行: azxs=AT vs param="A0"
|
||
EvaluateCellCondition("AT", "A0", "azxs") → False (精确匹配失败)
|
||
' 整行不匹配
|
||
|
||
' 第2行: azxs=AH vs param="A0"
|
||
EvaluateCellCondition("AH", "A0", "azxs") → False (精确匹配失败)
|
||
' 整行不匹配
|
||
|
||
' 最终结果: matchingRows.count = 0
|
||
```
|
||
|
||
**错误输出:**
|
||
```javascript
|
||
{
|
||
success: false,
|
||
rowCount: 0,
|
||
rowNums: [],
|
||
message: "未找到匹配记录"
|
||
}
|
||
```
|
||
|
||
**解决方案:**
|
||
1. 检查是否需要添加 `azxs=A0` 的记录到BOM库
|
||
2. 确认型号解析是否正确(A0是否应为AT)
|
||
|
||
### 5.2 场景2:0条匹配 - 否定条件不满足
|
||
|
||
**输入条件:**
|
||
- 提取参数:`{azxs: "A0", gclj: "M20"}`
|
||
- BOM库"接头"工作表:
|
||
| azxs | gclj | 物料名称 |
|
||
|------|------|----------|
|
||
| !=A0 | M20 | 接头非A0 |
|
||
|
||
**匹配过程:**
|
||
```vba
|
||
' azxs列: cellValue="!=A0", paramValue="A0"
|
||
EvaluateCellCondition("!=A0", "A0", "azxs") → False (否定匹配: "A0" = "A0")
|
||
' 整行不匹配
|
||
|
||
' 最终结果: matchingRows.count = 0
|
||
```
|
||
|
||
**错误输出:**
|
||
```javascript
|
||
{
|
||
success: false,
|
||
rowCount: 0,
|
||
message: "未找到匹配记录"
|
||
}
|
||
```
|
||
|
||
**解决方案:**
|
||
- 该记录明确排除 `azxs=A0`,这是预期行为
|
||
- 如需支持 `A0`,需添加新记录或修改否定条件
|
||
|
||
### 5.3 场景3:2+条匹配 - 重复记录
|
||
|
||
**输入条件:**
|
||
- 提取参数:`{azxs: "A0", gclj: "M20"}`
|
||
- BOM库"接头"工作表:
|
||
| azxs | gclj | lcfw | 物料名称 | 物料编码 |
|
||
|------|------|------|----------|----------|
|
||
| A0 | M20 | | 接头A0-1 | JT-001 |
|
||
| A0 | M20 | | 接头A0-2 | JT-002 |
|
||
|
||
**匹配过程:**
|
||
```vba
|
||
' 第1行:
|
||
' azxs: "A0" = "A0" → True
|
||
' gclj: "M20" = "M20" → True
|
||
' lcfw: "" (空) → True (通配符)
|
||
' → 匹配成功
|
||
|
||
' 第2行:
|
||
' azxs: "A0" = "A0" → True
|
||
' gclj: "M20" = "M20" → True
|
||
' lcfw: "" (空) → True (通配符)
|
||
' → 匹配成功
|
||
|
||
' 最终结果: matchingRows.count = 2
|
||
```
|
||
|
||
**错误输出:**
|
||
```javascript
|
||
{
|
||
success: false,
|
||
rowCount: 2,
|
||
rowNums: [2, 3],
|
||
message: "匹配到2条记录(需要恰好1条)"
|
||
}
|
||
```
|
||
|
||
**解决方案:**
|
||
1. 删除重复记录
|
||
2. 细化配置条件(如添加`lcfw`列区分)
|
||
|
||
### 5.4 场景4:2+条匹配 - 空单元格过多
|
||
|
||
**输入条件:**
|
||
- 提取参数:`{azxs: "A0", gclj: "M20"}`
|
||
- BOM库"接头"工作表:
|
||
| azxs | gclj | jycz | lcfw | fjgn | 物料名称 |
|
||
|------|------|------|------|------|----------|
|
||
| A0 | M20 | | | | 接头配置1 |
|
||
| A0 | M20 | | | | 接头配置2 |
|
||
| A0 | M20 | | | | 接头配置3 |
|
||
|
||
**匹配过程:**
|
||
```vba
|
||
' 所有3行的 jycz、lcfw、fjgn 都是空单元格
|
||
' 空单元格 → 通配符 → 全部返回True
|
||
' 导致3行都匹配
|
||
|
||
' 最终结果: matchingRows.count = 3
|
||
```
|
||
|
||
**错误输出:**
|
||
```javascript
|
||
{
|
||
success: false,
|
||
rowCount: 3,
|
||
rowNums: [2, 3, 4],
|
||
message: "匹配到3条记录(需要恰好1条)"
|
||
}
|
||
```
|
||
|
||
**解决方案:**
|
||
1. 补充缺失的配置列值
|
||
2. 添加新的区分列(如`bkxs`、`特殊要求`等)
|
||
|
||
### 5.5 场景5:fjgn包含匹配
|
||
|
||
**输入条件:**
|
||
- 提取参数:`{azxs: "A0", fjgn: "N1,N2,N3"}`
|
||
- BOM库"接头"工作表:
|
||
| azxs | fjgn | 物料名称 |
|
||
|------|------|----------|
|
||
| A0 | N1 | 带N1功能 |
|
||
| A0 | N4 | 带N4功能 |
|
||
|
||
**匹配过程:**
|
||
```vba
|
||
' 第1行:
|
||
' azxs: "A0" = "A0" → True
|
||
' fjgn: CheckFjgnMatch("N1", "N1,N2,N3")
|
||
' → InStr("N1,N2,N3", "N1") > 0 → True
|
||
' → 匹配成功
|
||
|
||
' 第2行:
|
||
' azxs: "A0" = "A0" → True
|
||
' fjgn: CheckFjgnMatch("N4", "N1,N2,N3")
|
||
' → InStr("N1,N2,N3", "N4") = 0 → False
|
||
' → 不匹配
|
||
|
||
' 最终结果: matchingRows.count = 1, success = true
|
||
```
|
||
|
||
**正确输出:**
|
||
```javascript
|
||
{
|
||
success: true,
|
||
rowCount: 1,
|
||
rowNums: [2],
|
||
message: "匹配成功"
|
||
}
|
||
```
|
||
|
||
### 5.6 场景6:部件验证错误
|
||
|
||
**输入条件:**
|
||
- 提取参数:`{azxs: "A0", gclj: "M20"}`
|
||
- 匹配结果物料集合:
|
||
```javascript
|
||
[
|
||
{materialType: "接头", materialName: "接头A0", ...},
|
||
{materialType: "接头", materialName: "接头AT", ...}, // 重复
|
||
{materialType: "弹性元件", materialName: "元件M20", ...}
|
||
]
|
||
```
|
||
|
||
**验证过程:**
|
||
```vba
|
||
' 统计:
|
||
' componentCount = 0
|
||
' jointCount = 2
|
||
' elementCount = 1
|
||
|
||
' 验证规则: jointCount (2) ≠ elementCount (1)
|
||
' → 验证失败
|
||
```
|
||
|
||
**验证结果:**
|
||
```javascript
|
||
{
|
||
valid: false,
|
||
message: "部件组合异常: 接头数量(2)≠弹性元件数量(1)"
|
||
}
|
||
```
|
||
|
||
**错误输出行:**
|
||
| 原始产品型号 | azxs | ... | 物料类型 | 物料名称 | 提取备注 |
|
||
|-------------|------|-----|----------|----------|----------|
|
||
| YTHN-100... | A0 | ... | 接头 | 接头A0 | 部件组合异常: 接头数量(2)≠弹性元件数量(1) |
|
||
|
||
**解决方案:**
|
||
1. 检查BOM库配置是否导致多次匹配
|
||
2. 确保接头和弹性元件一对一配对
|
||
|
||
---
|
||
|
||
## 6. 部件特殊处理
|
||
|
||
### 6.1 部件物料特性
|
||
|
||
部件物料在AutoBOM系统中具有特殊地位:
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────┐
|
||
│ 部件物料结构 │
|
||
├──────────────────────────────────────────────────────────┤
|
||
│ 1条"部件"记录 = { │
|
||
│ - 部件本体(优先选择) │
|
||
│ - 子件1: 接头(备选方案) │
|
||
│ - 子件2: 弹性元件(备选方案) │
|
||
│ } │
|
||
│ │
|
||
│ 选择逻辑: │
|
||
│ ✓ 有库存 → 返回部件 │
|
||
│ ✗ 无库存 → 返回接头 + 弹性元件 │
|
||
└──────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 6.2 部件处理流程
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[开始处理'部件'工作表] --> B[调用MatchBOMRecord]
|
||
|
||
B --> C{匹配成功?}
|
||
C -->|否| Err[记录匹配错误<br/>添加错误物料]
|
||
|
||
C -->|是| D[获取匹配行号]
|
||
D --> E[构建表头映射]
|
||
|
||
E --> F{检查部件库存}
|
||
F -->|有库存| G[提取部件物料信息]
|
||
F -->|无库存| H[提取子件信息]
|
||
|
||
G --> I[返回部件物料集合]
|
||
|
||
H --> J[提取接头信息]
|
||
H --> K[提取弹性元件信息]
|
||
J --> L[返回子件集合]
|
||
K --> L
|
||
|
||
style Err fill:#ff6b6b
|
||
style G fill:#51cf66
|
||
style L fill:#51cf66
|
||
```
|
||
|
||
### 6.3 部件组合验证规则(两阶段验证)
|
||
|
||
#### ✅ 正确组合(验证通过)
|
||
|
||
| 组合类型 | 部件数 | 接头数 | 弹性元件数 | 状态 | 说明 |
|
||
|---------|-------|-------|-----------|------|------|
|
||
| 纯部件 | 1 | 0 | 0 | ✅ 有效 | [部件]工作表返回1个部件 |
|
||
| 纯子件 | 0 | 1 | 1 | ✅ 有效 | [部件]工作表返回1个接头+1个弹性元件 |
|
||
| 独立子件 | 0 | 1 | 1 | ✅ 有效 | [接头]和[弹性元件]工作表各返回1条 |
|
||
|
||
#### ⚠️ 警告组合(验证通过,记录警告)
|
||
|
||
| 组合类型 | 部件数 | 接头数 | 弹性元件数 | 警告类型 | 说明 |
|
||
|---------|-------|-------|-----------|---------|------|
|
||
| 部件+接头 | 1 | 1+ | 任意 | ComponentConflict | 存在[部件]物料,但[接头]工作表也匹配到,已忽略 |
|
||
| 部件+弹性元件 | 1 | 任意 | 1+ | ComponentConflict | 存在[部件]物料,但[弹性元件]工作表也匹配到,已忽略 |
|
||
| 子件+独立接头 | 0 | 2+ | 1+ | ComponentConflict | [部件]工作表已返回接头,但[接头]工作表也匹配到,已忽略 |
|
||
| 子件+独立元件 | 0 | 1+ | 2+ | ComponentConflict | [部件]工作表已返回弹性元件,但[弹性元件]工作表也匹配到,已忽略 |
|
||
|
||
#### ❌ 异常组合(验证失败)
|
||
|
||
| 异常类型 | 部件数 | 接头数 | 弹性元件数 | 错误信息 |
|
||
|---------|-------|-------|-----------|---------|
|
||
| 部件过多(部件表) | >1 | - | - | [部件]工作表匹配到N条记录 |
|
||
| 部件过多(总计数) | >1 | - | - | 部件数量为N(应为1) |
|
||
| 接头过多(部件表) | 0 | 2+ | 任意 | [部件]工作表匹配到2+个接头 |
|
||
| 接头过多(接头表) | 0 | 2+ | 任意 | [接头]工作表匹配到N条记录 |
|
||
| 弹性元件过多(部件表) | 0 | 任意 | 2+ | [部件]工作表匹配到2+个弹性元件 |
|
||
| 弹性元件过多(元件表) | 0 | 任意 | 2+ | [弹性元件]工作表匹配到N条记录 |
|
||
| 接头弹性不匹配 | 0 | N | M (N≠M) | 接头数量N ≠ 弹性元件数量M |
|
||
| 完全缺失 | 0 | 0 | 0 | 部件、接头、弹性元件均未匹配或组合不完整 |
|
||
| 数量不对称 | 0 | 1 | 0 | 接头和弹性元件数量不匹配 |
|
||
| 数量不对称 | 0 | 0 | 1 | 接头和弹性元件数量不匹配 |
|
||
|
||
### 6.4 ValidateComponentCombination() 代码逻辑
|
||
|
||
```vba
|
||
Public Function ValidateComponentCombination(ByVal materials As Collection) As Object
|
||
Dim componentCount As Long, jointCount As Long, elementCount As Long
|
||
|
||
' 统计各类型物料数量
|
||
For Each mat In materials
|
||
Select Case mat("materialType")
|
||
Case "部件": componentCount = componentCount + 1
|
||
Case "接头": jointCount = jointCount + 1
|
||
Case "弹性元件": elementCount = elementCount + 1
|
||
End Select
|
||
Next mat
|
||
|
||
' 规则1: 只有1个部件
|
||
If componentCount = 1 And jointCount = 0 And elementCount = 0 Then
|
||
result("valid") = True
|
||
result("message") = "验证通过:1个部件"
|
||
Exit Function
|
||
End If
|
||
|
||
' 规则2: 没有部件,恰好1个接头和1个弹性元件
|
||
If componentCount = 0 And jointCount = 1 And elementCount = 1 Then
|
||
result("valid") = True
|
||
result("message") = "验证通过:1个接头+1个弹性元件"
|
||
Exit Function
|
||
End If
|
||
|
||
' 其他情况都是异常
|
||
result("valid") = False
|
||
result("message") = BuildErrorMessage(componentCount, jointCount, elementCount)
|
||
End Function
|
||
```
|
||
|
||
### 6.5 库存检查接口(预留)
|
||
|
||
当前版本的库存检查函数默认返回 `True`(库存充足),预留接口供未来扩展:
|
||
|
||
```vba
|
||
Private Function CheckComponentInventory( _
|
||
ByVal wsComponent As Worksheet, _
|
||
ByVal rowNum As Long, _
|
||
ByVal headerMap As Object _
|
||
) As Boolean
|
||
' TODO: 连接库存系统查询实际库存
|
||
' 示例扩展:
|
||
' If headerMap.Exists("库存数量") Then
|
||
' stockQty = CLng(wsComponent.Cells(rowNum, headerMap("库存数量")).Value)
|
||
' CheckComponentInventory = (stockQty > 0)
|
||
' End If
|
||
|
||
CheckComponentInventory = True ' 当前默认有库存
|
||
End Function
|
||
```
|
||
|
||
**未来扩展方向:**
|
||
1. 查询ERP系统API
|
||
2. 读取库存Excel表
|
||
3. 连接数据库库存表
|
||
|
||
### 6.5 边特殊处理
|
||
|
||
#### 6.5.1 边物料特性
|
||
|
||
边物料在AutoBOM系统中具有特殊规则:根据`azxs`(安装形式)参数值决定是否需要边物料。
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────┐
|
||
│ 边物料规则 │
|
||
├──────────────────────────────────────────────────────────┤
|
||
│ azxs = A0, Z0, B0 → 不需要边(0条=OK,1+条=ERROR) │
|
||
│ azxs = AH, AT, BH, BT, BZ, ZH, ZT, ZZ → 需要边(1条=OK) │
|
||
│ 其他azxs值 → 按常规验证(1条=OK) │
|
||
└──────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
#### 6.5.2 边验证流程
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[验证边材料] --> B{获取azxs参数}
|
||
B --> C{提取rawAzxs值<br/>处理双值格式}
|
||
|
||
C --> D{azxs in A0/Z0/B0?}
|
||
D -->|是| E[不需要边模式]
|
||
E --> F{边匹配数>0?}
|
||
F -->|是| G[❌ 错误: 不应有边]
|
||
F -->|否| H[✅ 通过: 无边物料]
|
||
|
||
D -->|否| I{azxs in AH/AT/<br/>BH/BT/BZ/ZH/ZT/ZZ?}
|
||
I -->|是| J[需要边模式]
|
||
J --> K{边匹配数=1?}
|
||
K -->|是| L[✅ 通过: 有边物料]
|
||
K -->|否| M[❌ 错误: 0条或2+条]
|
||
|
||
I -->|否| N[常规验证模式]
|
||
N --> O{边匹配数=1?}
|
||
O -->|是| L
|
||
O -->|否| M
|
||
|
||
style H fill:#51cf66
|
||
style L fill:#51cf66
|
||
style G fill:#ff6b6b
|
||
style M fill:#ff6b6b
|
||
```
|
||
|
||
#### 6.5.3 边验证规则表
|
||
|
||
| azxs值 | 需要边? | 0条匹配 | 1条匹配 | 2+条匹配 |
|
||
|--------|---------|---------|---------|----------|
|
||
| A0 | ❌ 不需要 | ✅ OK | ❌ ERROR | ❌ ERROR |
|
||
| Z0 | ❌ 不需要 | ✅ OK | ❌ ERROR | ❌ ERROR |
|
||
| B0 | ❌ 不需要 | ✅ OK | ❌ ERROR | ❌ ERROR |
|
||
| AH | ✅ 需要 | ❌ ERROR | ✅ OK | ❌ ERROR |
|
||
| AT | ✅ 需要 | ❌ ERROR | ✅ OK | ❌ ERROR |
|
||
| BH | ✅ 需要 | ❌ ERROR | ✅ OK | ❌ ERROR |
|
||
| BT | ✅ 需要 | ❌ ERROR | ✅ OK | ❌ ERROR |
|
||
| BZ | ✅ 需要 | ❌ ERROR | ✅ OK | ❌ ERROR |
|
||
| ZH | ✅ 需要 | ❌ ERROR | ✅ OK | ❌ ERROR |
|
||
| ZT | ✅ 需要 | ❌ ERROR | ✅ OK | ❌ ERROR |
|
||
| ZZ | ✅ 需要 | ❌ ERROR | ✅ OK | ❌ ERROR |
|
||
| 其他 | ❓ 常规 | ❌ ERROR | ✅ OK | ❌ ERROR |
|
||
|
||
#### 6.5.4 ValidateEdgeMaterial() 代码逻辑
|
||
|
||
边材料验证集成在 `M09_BOMExtractor.ValidateAllMatchResults()` 函数的 Phase 3.5:
|
||
|
||
```vba
|
||
' ========================================
|
||
' 3.5. 特殊验证:边 (Edge) 材料
|
||
' ========================================
|
||
Dim edgeResult As Object
|
||
Set edgeResult = Nothing
|
||
|
||
If resultsDict.Exists(BOMLIB_SHEET_EDGE) Then
|
||
Set edgeResult = resultsDict(BOMLIB_SHEET_EDGE)
|
||
End If
|
||
|
||
' 检查azxs参数值
|
||
Dim azxsValue As String
|
||
Dim rawAzxs As String
|
||
azxsValue = ""
|
||
|
||
If params.Exists("azxs") Then
|
||
azxsValue = CStr(params("azxs"))
|
||
' 提取原始azxs值(处理双值格式如"A0,径向")
|
||
If InStr(azxsValue, ",") > 0 Then
|
||
rawAzxs = Trim(CStr(Split(azxsValue, ",")(0)))
|
||
Else
|
||
rawAzxs = Trim(azxsValue)
|
||
End If
|
||
End If
|
||
|
||
' 定义不需要边的azxs值
|
||
Dim noEdgeAzxs As Variant
|
||
noEdgeAzxs = Array("A0", "Z0", "B0")
|
||
|
||
' 定义需要边的azxs值(有后缀H/T/Z的值)
|
||
Dim hasEdgeAzxs As Variant
|
||
hasEdgeAzxs = Array("AH", "AT", "BH", "BT", "BZ", "ZH", "ZT", "ZZ")
|
||
|
||
' 情况A: azxs为A0/Z0/B0,不应该有边
|
||
' ...(验证逻辑见完整代码)
|
||
|
||
' 情况B: azxs为AH/AT/BH/BT/BZ/ZH/ZT/ZZ,走常规判断
|
||
' ...(验证逻辑见完整代码)
|
||
```
|
||
|
||
#### 6.5.5 边验证错误类型
|
||
|
||
| 错误类型 | 错误信息 | 触发条件 | 检测位置 |
|
||
|---------|---------|---------|---------|
|
||
| **EdgeMaterialError** | `[边]工作表匹配到N条记录,但azxs=X不需要边物料` | azxs为A0/Z0/B0且边匹配数>0 | `M09_BOMExtractor.bas:763-766` |
|
||
| **No Match** | `[边]未匹配到记录` | azxs为AH/AT等且边匹配数=0 | `M09_BOMExtractor.bas:789-792` |
|
||
| **Multiple Match** | `[边]匹配到N条记录` | azxs为AH/AT等且边匹配数>1 | `M09_BOMExtractor.bas:793-795` |
|
||
|
||
#### 6.5.6 设计决策:为什么边需要特殊处理?
|
||
|
||
**业务背景:**
|
||
- **边材料的作用**:某些产品配置需要在表盘边缘添加边框或装饰条
|
||
- **azxs依赖性**:边的需求取决于安装形式(azxs参数)
|
||
- **A0/Z0/B0(基础安装形式)**:产品设计上不需要边
|
||
- **AH/AT/BH/BT/BZ/ZH/ZT/ZZ(带后缀的安装形式)**:需要边作为装饰或功能性部件
|
||
|
||
**技术实现考量:**
|
||
1. **避免误报**:如果对A0/Z0/B0型号使用标准验证,0条匹配会被误判为错误
|
||
2. **精确控制**:对于AH/AT等型号,仍然需要严格执行1条匹配规则
|
||
3. **双值兼容**:支持`"A0,径向"`格式的azxs参数,提取原始值进行判断
|
||
|
||
**可扩展性:**
|
||
本实现建立的模式可复用于其他需要参数依赖验证的物料类型:
|
||
```vba
|
||
' 未来可扩展为:
|
||
Function GetAzxsCategory(params As Object) As String
|
||
' 返回: NO_EDGE_REQUIRED / EDGE_REQUIRED / STANDARD
|
||
End Function
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 错误报告机制
|
||
|
||
### 7.1 clsErrorLogger 类模块(v2.0)
|
||
|
||
`clsErrorLogger` 是系统的错误日志记录器,负责收集、存储和报告所有匹配错误和警告。
|
||
|
||
**类结构(v2.0):**
|
||
```vba
|
||
' 私有变量
|
||
Private pErrors As Collection ' 错误集合
|
||
Private pWarnings As Collection ' 警告集合
|
||
|
||
' 公开方法
|
||
Public Sub Record(RowIndex As Long, SourceFunc As String, ErrorType As String, Desc As String, Context As String)
|
||
Public Sub RecordWarning(RowIndex As Long, SourceFunc As String, WarningType As String, Desc As String, Context As String)
|
||
Public Property Get HasErrors() As Boolean
|
||
Public Property Get HasWarnings() As Boolean
|
||
Public Property Get HasIssues() As Boolean ' 有错误或警告
|
||
Public Sub PrintReport(targetWb As Workbook)
|
||
```
|
||
|
||
**v2.0 新增功能:**
|
||
- ✅ 支持警告类型(`RecordWarning`方法)
|
||
- ✅ 区分错误和警告(`HasErrors`、`HasWarnings`、`HasIssues`属性)
|
||
- ✅ 错误报告增加"类型"列(错误/警告)
|
||
- ✅ 警告行黄色高亮,错误行红色高亮
|
||
|
||
### 7.2 错误和警告记录结构
|
||
|
||
#### 7.2.1 错误记录(Record方法)
|
||
|
||
每条错误记录包含5个字段:
|
||
|
||
| 字段名 | 类型 | 说明 | 示例 |
|
||
|--------|------|------|------|
|
||
| RowIndex | Long | 发生错误的行号 | 0(无特定行) |
|
||
| SourceFunc | String | 来源模块/函数 | "M09.ValidateAllMatchResults" |
|
||
| ErrorType | String | 错误类型 | "BOMMatchError" |
|
||
| Desc | String | 详细描述 | "接头 未找到匹配记录" |
|
||
| Context | String | 原始数据上下文 | ""(可选) |
|
||
|
||
**错误类型枚举:**
|
||
- `BOMMatchError`: BOM库匹配错误(0条或多条)
|
||
- `ValidationError`: 部件组合验证错误
|
||
- `SystemError`: 系统运行时异常
|
||
|
||
#### 7.2.2 警告记录(RecordWarning方法)
|
||
|
||
每条警告记录包含5个字段:
|
||
|
||
| 字段名 | 类型 | 说明 | 示例 |
|
||
|--------|------|------|------|
|
||
| RowIndex | Long | 发生警告的行号 | 0(无特定行) |
|
||
| SourceFunc | String | 来源模块/函数 | "M09.ValidateAllMatchResults" |
|
||
| WarningType | String | 警告类型 | "ComponentConflict" |
|
||
| Desc | String | 详细描述 | "存在[部件]物料,但[接头]工作表也匹配到1条记录,已忽略" |
|
||
| Context | String | 原始数据上下文 | ""(可选) |
|
||
|
||
**警告类型枚举:**
|
||
- `ComponentConflict`: 部件与子件冲突(非阻断性)
|
||
|
||
### 7.3 错误记录流程
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant Func as 业务函数
|
||
participant Logger as clsErrorLogger
|
||
participant Collection as pErrors Collection
|
||
participant WB as Workbook
|
||
|
||
Func->>Logger: Record(0, "M09...", "BOMMatchError", "接头 未匹配", "")
|
||
activate Logger
|
||
Logger->>Collection: Add Array(0, "M09...", "BOMMatchError", "接头 未匹配", "")
|
||
Note over Collection: 存储到内存集合
|
||
Collection--xLogger: 确认添加
|
||
deactivate Logger
|
||
|
||
Note over Func: 继续处理其他物料...
|
||
|
||
Func->>Logger: HasErrors?
|
||
Logger->>Logger: pErrors.count > 0
|
||
Logger-->>Func: True
|
||
|
||
Func->>Logger: PrintReport(Workbook)
|
||
activate Logger
|
||
Logger->>WB: Worksheets.Add()
|
||
Logger->>WB: 写入表头 (A1:E1)
|
||
Logger->>Collection: 遍历所有错误
|
||
loop 每条错误记录
|
||
Collection-->>Logger: Array(RowIndex, SourceFunc, ErrorType, Desc, Context)
|
||
Logger->>WB: 写入到数据行
|
||
end
|
||
Logger->>WB: Columns.AutoFit()
|
||
Logger--xFunc: 完成
|
||
deactivate Logger
|
||
```
|
||
|
||
### 7.4 错误报告格式(v2.0)
|
||
|
||
生成的错误报告工作表包含**6列**:
|
||
|
||
| 类型 | 原表行号 | 来源模块 | 错误类型 | 详细描述 | 原始数据 |
|
||
|------|---------|---------|---------|---------|---------|
|
||
| 错误 | 0 | M09.ValidateAllMatchResults | BOMMatchError | 接头 未找到匹配记录 | |
|
||
| 错误 | 0 | M09.ValidateAllMatchResults | BOMMatchError | 弹性元件 未找到匹配记录 | |
|
||
| 警告 | 0 | M09.ValidateAllMatchResults | ComponentConflict | 存在[部件]物料,但[接头]工作表也匹配到1条记录,已忽略 | |
|
||
| 错误 | 0 | M09.ProcessSingleModel | ValidationError | 部件组合异常: 接头数量(2)≠弹性元件数量(1) | |
|
||
|
||
**格式化特性(v2.0):**
|
||
- ✅ 表头加粗、灰色背景
|
||
- ✅ 错误行红色背景
|
||
- ✅ 警告行黄色背景
|
||
- ✅ 自动列宽调整
|
||
- ✅ 工作表命名: `"错误报告_" & Format(Now, "hhmmss")`
|
||
|
||
### 7.5 错误和警告信息传播路径(v2.0)
|
||
|
||
```mermaid
|
||
graph LR
|
||
A[M07_BOMMatcher.MatchBOMRecord] -->|返回结果| B[M09_BOMExtractor.MatchAllMaterialTypesWithValidation]
|
||
B -->|存入resultsDict| C[ValidateAllMatchResults]
|
||
|
||
C -->|检测到错误| D[clsErrorLogger.Record]
|
||
C -->|检测到警告| E[clsErrorLogger.RecordWarning]
|
||
|
||
D --> F[存储到pErrors集合]
|
||
E --> G[存储到pWarnings集合]
|
||
|
||
F --> H{HasIssues?}
|
||
G --> H
|
||
H -->|True| I[Logger.PrintReport]
|
||
H -->|False| J[跳过报告生成]
|
||
|
||
I --> K[生成错误和警告报告工作表]
|
||
```
|
||
|
||
### 7.6 用户通知机制(v2.0)
|
||
|
||
在 `M09_BOMExtractor.RunBOMExtraction()` 函数中,通过返回消息通知用户:
|
||
|
||
```vba
|
||
Dim msg As String
|
||
msg = "BOM提取完成!" & vbCrLf & _
|
||
"处理型号数: " & totalModels & vbCrLf & _
|
||
"提取物料数: " & allResults.count & vbCrLf & _
|
||
"成功数: " & successCount & vbCrLf & _
|
||
"异常数: " & errorCount
|
||
|
||
If g_Logger.HasErrors Then
|
||
msg = msg & vbCrLf & vbCrLf & "发现错误,已生成错误报告工作表。"
|
||
ElseIf g_Logger.HasWarnings Then
|
||
msg = msg & vbCrLf & vbCrLf & "发现警告,已生成错误报告工作表。"
|
||
End If
|
||
|
||
RunBOMExtraction = msg
|
||
```
|
||
|
||
**示例消息(有错误):**
|
||
```
|
||
BOM提取完成!
|
||
处理型号数: 100
|
||
提取物料数: 350
|
||
成功数: 320
|
||
异常数: 30
|
||
|
||
发现错误,已生成错误报告工作表。
|
||
```
|
||
|
||
**示例消息(仅警告):**
|
||
```
|
||
BOM提取完成!
|
||
处理型号数: 100
|
||
提取物料数: 350
|
||
成功数: 350
|
||
异常数: 0
|
||
|
||
发现警告,已生成错误报告工作表。
|
||
```
|
||
|
||
**示例消息(无问题):**
|
||
```
|
||
BOM提取完成!
|
||
处理型号数: 100
|
||
提取物料数: 350
|
||
成功数: 350
|
||
异常数: 0
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 快速参考
|
||
|
||
### 8.1 匹配规则速查表
|
||
|
||
| 规则类型 | BOM库单元格 | 提取参数 | 匹配结果 | 代码位置 |
|
||
|---------|------------|---------|---------|---------|
|
||
| **通配符** | `(空)` | 任意值 | ✅ 匹配 | `M07_BOMMatcher.bas:237-241` |
|
||
| **否定** | `!=A0` | `A0` | ❌ 不匹配 | `M07_BOMMatcher.bas:247-252` |
|
||
| **否定** | `!=A0` | `AT` | ✅ 匹配 | `M07_BOMMatcher.bas:247-252` |
|
||
| **fjgn包含** | `N1` | `N1,N2` | ✅ 匹配 | `M07_BOMMatcher.bas:282-301` |
|
||
| **精确** | `A0` | `A0` | ✅ 匹配 | `M07_BOMMatcher.bas:261-262` |
|
||
| **精确** | `A0` | `AT` | ❌ 不匹配 | `M07_BOMMatcher.bas:261-262` |
|
||
|
||
### 8.2 错误和警告类型速查表(v2.0)
|
||
|
||
#### 错误类型
|
||
|
||
| 错误类型 | 错误信息 | 触发条件 | 处理建议 |
|
||
|---------|---------|---------|---------|
|
||
| **No Match** | `未找到匹配记录` | 匹配0条 | 补充BOM库或检查参数 |
|
||
| **Multiple Match** | `匹配到N条记录(需要恰好1条)` | 匹配2+条 | 删除重复或细化条件 |
|
||
| **工作表为空** | `工作表为空` | `ws Is Nothing` | 检查BOM库文件 |
|
||
| **参数字典为空** | `参数字典为空` | `params.count = 0` | 检查型号解析 |
|
||
| **工作表无数据** | `工作表无数据` | `lastRow < START_ROW` | 检查BOM库数据 |
|
||
| **部件组合异常** | `同时存在部件和子件` | 验证失败 | 检查部件处理逻辑 |
|
||
| **部件、接头、弹性元件均未匹配** | `部件、接头、弹性元件均未匹配或组合不完整` | 特殊验证失败 | 检查BOM库配置 |
|
||
| **接头和弹性元件数量不匹配** | `接头和弹性元件数量不匹配` | 特殊验证失败 | 确保接头和弹性元件一对一 |
|
||
| **EdgeMaterialError** | `[边]工作表匹配到N条记录,但azxs=X不需要边物料` | azxs为A0/Z0/B0且边匹配数>0 | 检查BOM库配置或产品型号 |
|
||
| **边未匹配到记录** | `[边]未匹配到记录` | azxs为AH/AT等且边匹配数=0 | 补充BOM库边记录 |
|
||
| **边匹配多条记录** | `[边]匹配到N条记录` | azxs为AH/AT等且边匹配数>1 | 删除重复或细化边配置条件 |
|
||
|
||
#### 警告类型(v2.0新增)
|
||
|
||
| 警告类型 | 警告信息 | 触发条件 | 影响 |
|
||
|---------|---------|---------|------|
|
||
| **ComponentConflict** | `存在[部件]物料,但[接头]工作表也匹配到N条记录,已忽略` | 部件表返回部件,接头表也有匹配 | ⚠️ 非阻断,仅记录 |
|
||
| **ComponentConflict** | `[部件]工作表已返回接头,但[接头]工作表也匹配到N条记录,已忽略` | 部件表返回子件,接头表也有匹配 | ⚠️ 非阻断,仅记录 |
|
||
|
||
### 8.3 部件验证规则速查(v2.0)
|
||
|
||
#### 验证结果分类
|
||
|
||
| 部件数 | 接头数 | 弹性元件数 | 验证结果 | 说明 |
|
||
|-------|-------|-----------|---------|------|
|
||
| 1 | 0 | 0 | ✅ 有效 | 纯部件组合 |
|
||
| 0 | 1 | 1 | ✅ 有效 | 纯子件组合 |
|
||
| 1 | 1+ | 任意 | ⚠️ 警告 | 部件+接头冲突 |
|
||
| 1 | 任意 | 1+ | ⚠️ 警告 | 部件+弹性元件冲突 |
|
||
| >1 | - | - | ❌ 异常 | 部件过多 |
|
||
| 1 | >0 | >0 | ❌ 异常 | 部件子件共存(旧逻辑) |
|
||
| 0 | N | M (N≠M) | ❌ 异常 | 数量不匹配 |
|
||
| 0 | 0 | 0 | ❌ 异常 | 完全缺失 |
|
||
|
||
#### 警告场景详解(v2.0新增)
|
||
|
||
| 场景 | [部件]工作表 | [接头]工作表 | [弹性元件]工作表 | 结果 |
|
||
|------|------------|------------|---------------|------|
|
||
| 部件+接头冲突 | 返回1个部件 | 返回1+个接头 | 任意或无 | ⚠️ 使用部件,忽略接头表 |
|
||
| 部件+元件冲突 | 返回1个部件 | 任意或无 | 返回1+个弹性元件 | ⚠️ 使用部件,忽略弹性元件表 |
|
||
| 子件+独立接头 | 返回1个接头+1个弹性元件 | 返回1+个接头 | 返回1+个弹性元件 | ⚠️ 使用部件表的子件,忽略独立表 |
|
||
| 子件+独立元件 | 返回1个接头+1个弹性元件 | 返回1+个接头 | 返回1+个弹性元件 | ⚠️ 使用部件表的子件,忽略独立表 |
|
||
|
||
### 8.4 故障排查指南
|
||
|
||
#### 问题:未找到匹配记录
|
||
|
||
**排查步骤:**
|
||
1. ✅ 检查型号解析是否正确
|
||
2. ✅ 确认BOM库中是否有对应记录
|
||
3. ✅ 检查配置条件是否过于严格
|
||
4. ✅ 验证否定条件(`!=`)是否误排除
|
||
|
||
#### 问题:匹配到多条记录
|
||
|
||
**排查步骤:**
|
||
1. ✅ 检查是否有重复记录
|
||
2. ✅ 统计空单元格数量(过多会导致模糊匹配)
|
||
3. ✅ 评估是否需要添加区分列
|
||
4. ✅ 确认配置列值是否足够细化
|
||
|
||
#### 问题:部件组合验证失败
|
||
|
||
**排查步骤:**
|
||
1. ✅ 确认BOM库"接头"和"弹性元件"是否都匹配
|
||
2. ✅ 检查是否存在重复匹配(如接头匹配到2条)
|
||
3. ✅ 验证部件库存检查逻辑(如已实现)
|
||
4. ✅ 审查M08_ComponentProcessor日志输出
|
||
|
||
### 8.5 关键函数位置索引(v2.0)
|
||
|
||
| 函数名 | 模块 | 行号 | 功能描述 |
|
||
|--------|------|------|---------|
|
||
| `MatchBOMRecord` | M07_BOMMatcher | 55-153 | BOM库匹配主入口 |
|
||
| `EvaluateCellCondition` | M07_BOMMatcher | 230-266 | 单元格条件评估 |
|
||
| `CheckFjgnMatch` | M07_BOMMatcher | 282-301 | fjgn包含匹配 |
|
||
| `ProcessComponentRecord` | M08_ComponentProcessor | 58-137 | 部件处理主入口 |
|
||
| `ValidateComponentCombination` | M08_ComponentProcessor | 423-507 | 部件组合验证(已弃用,移至M09) |
|
||
| `ProcessSingleModel` | M09_BOMExtractor | 304-365 | 单型号处理流程 |
|
||
| `MatchAllMaterialTypesWithValidation` | M09_BOMExtractor | 387-550 | **新增** 两阶段匹配(收集→验证) |
|
||
| `ValidateAllMatchResults` | M09_BOMExtractor | 581-815 | **新增** 统一验证所有匹配结果,包含边材料特殊验证 |
|
||
| `ToArray` | M09_BOMExtractor | 816-826 | **新增** Collection转数组辅助函数 |
|
||
| `Record` | clsErrorLogger | 16-19 | 错误记录 |
|
||
| `RecordWarning` | clsErrorLogger | 37-39 | **新增** 警告记录 |
|
||
| `HasWarnings` | clsErrorLogger | 27-29 | **新增** 是否有警告 |
|
||
| `HasIssues` | clsErrorLogger | 32-34 | **新增** 是否有问题(错误或警告) |
|
||
| `PrintReport` | clsErrorLogger | 42-105 | 生成错误报告(支持警告) |
|
||
|
||
### 8.6 调试技巧
|
||
|
||
#### 1. 启用调试输出
|
||
|
||
在VBA编辑器中设置**立即窗口**可见(Ctrl+G),查看调试输出:
|
||
|
||
```vba
|
||
Debug.Print "=== 处理工作表: [" & sheetName & "] ==="
|
||
Debug.Print " -> 匹配结果: " & matchResult("success") & ", 行数: " & matchResult("rowCount")
|
||
Debug.Print " -> 匹配行号: " & rowNum
|
||
```
|
||
|
||
#### 2. 断点设置
|
||
|
||
在关键位置设置断点,逐步执行:
|
||
- `M07_BOMMatcher.MatchBOMRecord` - 观察匹配过程
|
||
- `M09_BOMExtractor.MatchAllMaterialTypes` - 观察错误记录
|
||
- `clsErrorLogger.Record` - 观察错误捕获
|
||
|
||
#### 3. 监视变量
|
||
|
||
添加监视变量:
|
||
- `params` - 查看提取的参数字典
|
||
- `matchingRows` - 查看匹配行集合
|
||
- `result("message")` - 查看错误消息
|
||
|
||
#### 4. 单元测试
|
||
|
||
参考 `M99_TestRunner.bas` 编写单元测试:
|
||
|
||
```vba
|
||
Sub Test_BOMMatcher_NoMatch()
|
||
Dim params As Object
|
||
Set params = CreateObject("Scripting.Dictionary")
|
||
params.Add "azxs", "INVALID"
|
||
|
||
Dim result As Object
|
||
Set result = M07_BOMMatcher.MatchBOMRecord(wsJoint, params)
|
||
|
||
Debug.Assert result("success") = False
|
||
Debug.Assert result("rowCount") = 0
|
||
Debug.Assert InStr(result("message"), "未找到") > 0
|
||
End Sub
|
||
```
|
||
|
||
---
|
||
|
||
## 附录A:相关文档
|
||
|
||
- [M06_ModelParser 型号解析机制](./M06_ModelParser_型号解析机制.md) - 了解参数提取过程
|
||
- [M08_ComponentProcessor 部件处理逻辑](./M08_ComponentProcessor_部件处理逻辑.md) - 深入理解部件特殊处理
|
||
- [RunBOMExtraction 完整流程](./RunBOMExtraction_流程详解.md) - 端到端流程说明
|
||
|
||
---
|
||
|
||
## 附录B:修订历史
|
||
|
||
| 版本 | 日期 | 作者 | 修订内容 |
|
||
|------|------|------|---------|
|
||
| 1.0 | 2025-02-12 | Claude | 初始版本,完整覆盖错误判断机制 |
|
||
| 2.0 | 2025-02-12 | Claude | **重大更新**:实施两阶段验证机制,新增警告类型,更新部件/接头/弹性元件交叉验证 |
|
||
| 2.1 | 2025-02-12 | Claude | **新增**:边材料特殊验证逻辑(基于azxs参数的条件验证) |
|
||
|
||
---
|
||
|
||
**文档状态:** ✅ 完成
|
||
**最后更新:** 2025-02-12(v2.1 - 边材料特殊验证)
|
||
**维护者:** AutoBOM开发团队
|