All checks were successful
NTFY Notification / notify (push) Successful in 3s
Add detailed documentation for error handling system including: - Error handling architecture with class diagrams - Error type classification (7 types) - Complete error handling lifecycle sequence diagrams - Module-specific error handling patterns (M01/M03/M05/M06/M07/M08/M09) - Error recovery strategies (continue, graceful degradation, warning only) - Error report generation process - Best practices with code examples - Test coverage overview - Quick reference guide Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1204 lines
30 KiB
Markdown
1204 lines
30 KiB
Markdown
# 错误处理机制详解
|
||
|
||
## 目录
|
||
|
||
1. [系统概述](#系统概述)
|
||
2. [错误处理架构](#错误处理架构)
|
||
3. [错误类型与分类](#错误类型与分类)
|
||
4. [错误处理流程](#错误处理流程)
|
||
5. [模块错误处理详解](#模块错误处理详解)
|
||
6. [错误恢复策略](#错误恢复策略)
|
||
7. [错误报告生成](#错误报告生成)
|
||
8. [最佳实践](#最佳实践)
|
||
9. [测试覆盖](#测试覆盖)
|
||
10. [快速参考](#快速参考)
|
||
|
||
---
|
||
|
||
## 系统概述
|
||
|
||
AutoBOM系统采用**集中式日志记录 + 持续处理**的错误处理策略,确保在批量处理BOM数据时,单个记录的错误不会中断整个处理流程。
|
||
|
||
### 核心设计原则
|
||
|
||
1. **错误隔离**: 单个记录错误不影响其他记录处理
|
||
2. **错误累积**: 所有错误统一收集,集中展示
|
||
3. **上下文保留**: 记录完整的错误上下文信息
|
||
4. **用户友好**: 提供清晰的错误描述和定位信息
|
||
|
||
### 设计优势
|
||
|
||
```mermaid
|
||
graph LR
|
||
subgraph "传统错误处理"
|
||
A1[遇到错误] --> B1[停止处理]
|
||
B1 --> C1[用户修复]
|
||
C1 --> D1[重新运行]
|
||
D1 --> E1[下一个错误<br/>再次停止]
|
||
end
|
||
|
||
subgraph "AutoBOM错误处理"
|
||
A2[遇到错误] --> B2[记录错误]
|
||
B2 --> C2[继续处理]
|
||
C2 --> D2[处理完成]
|
||
D2 --> E2[一次性查看<br/>所有错误]
|
||
end
|
||
|
||
style A2 fill:#c8e6c9
|
||
style B2 fill:#c8e6c9
|
||
style C2 fill:#c8e6c9
|
||
style D2 fill:#c8e6c9
|
||
style E2 fill:#c8e6c9
|
||
style A1 fill:#ffcdd2
|
||
style E1 fill:#ffcdd2
|
||
```
|
||
|
||
---
|
||
|
||
## 错误处理架构
|
||
|
||
### 类层次结构
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class clsErrorLogger {
|
||
-Collection pErrors
|
||
+Record(rowIdx, sourceFunc, errorType, desc, context)
|
||
+HasErrors() Boolean
|
||
+PrintReport(targetWb)
|
||
+Class_Initialize()
|
||
}
|
||
|
||
class M01_Main {
|
||
+RunBOMConversion()
|
||
+GeneratePreprocessingReport()
|
||
}
|
||
|
||
class M03_Logic {
|
||
-clsErrorLogger g_Logger
|
||
+InitLogic(logger)
|
||
+ParseRule(strRule, rowIdx)
|
||
-ConflictDetection()
|
||
}
|
||
|
||
class M05_PreProcessor {
|
||
-clsErrorLogger g_Logger
|
||
+InitPreProcessor(logger, wsMapping)
|
||
+PreprocessCondition(strCond, strCat, rowIdx)
|
||
}
|
||
|
||
class M06_ModelParser {
|
||
-clsErrorLogger g_Logger
|
||
+InitModelParser(logger)
|
||
+ParseProductModel(modelString)
|
||
}
|
||
|
||
class M07_BOMMatcher {
|
||
-clsErrorLogger g_Logger
|
||
+InitBOMMatcher(logger)
|
||
+MatchBOMRecord(ws, params)
|
||
}
|
||
|
||
class M08_ComponentProcessor {
|
||
-clsErrorLogger g_Logger
|
||
+InitComponentProcessor(logger)
|
||
+ProcessComponentRecord(row)
|
||
}
|
||
|
||
class M09_BOMExtractor {
|
||
-clsErrorLogger g_Logger
|
||
+RunBOMExtraction()
|
||
+ProcessSingleModel(modelString)
|
||
}
|
||
|
||
clsErrorLogger <-- M01_Main : uses
|
||
clsErrorLogger <-- M03_Logic : uses
|
||
clsErrorLogger <-- M05_PreProcessor : uses
|
||
clsErrorLogger <-- M06_ModelParser : uses
|
||
clsErrorLogger <-- M07_BOMMatcher : uses
|
||
clsErrorLogger <-- M08_ComponentProcessor : uses
|
||
clsErrorLogger <-- M09_BOMExtractor : uses
|
||
```
|
||
|
||
### 模块依赖关系
|
||
|
||
```mermaid
|
||
graph TB
|
||
Logger[clsErrorLogger.cls<br/>错误日志记录器]
|
||
|
||
M01[M01_Main.bas<br/>主入口]
|
||
|
||
M03[M03_Logic.bas<br/>条件解析]
|
||
M05[M05_PreProcessor.bas<br/>预处理]
|
||
M06[M06_ModelParser.bas<br/>型号解析]
|
||
M07[M07_BOMMatcher.bas<br/>BOM匹配]
|
||
M08[M08_ComponentProcessor.bas<br/>部件处理]
|
||
|
||
M09[M09_BOMExtractor.bas<br/>BOM提取]
|
||
|
||
M01 --> Logger
|
||
M01 --> M03
|
||
M01 --> M05
|
||
M09 --> Logger
|
||
M09 --> M06
|
||
M09 --> M07
|
||
M09 --> M08
|
||
|
||
M03 -.记录错误.-> Logger
|
||
M05 -.记录错误.-> Logger
|
||
M06 -.记录错误.-> Logger
|
||
M07 -.记录错误.-> Logger
|
||
M08 -.记录错误.-> Logger
|
||
|
||
Logger -.生成报告.-> M01
|
||
Logger -.生成报告.-> M09
|
||
|
||
style Logger fill:#e1f5fe
|
||
style M01 fill:#fff4e1
|
||
style M09 fill:#fff4e1
|
||
```
|
||
|
||
---
|
||
|
||
## 错误类型与分类
|
||
|
||
### 错误分类体系
|
||
|
||
```mermaid
|
||
graph TD
|
||
Root[错误类型]
|
||
|
||
Root --> Sys[系统错误<br/>SystemError]
|
||
Root --> Syn[语法错误<br/>SyntaxError]
|
||
Root --> Log[逻辑冲突<br/>LogicConflict]
|
||
Root --> Map[映射警告<br/>MappingWarning]
|
||
Root --> Mod[型号解析错误<br/>ModelParseError]
|
||
Root --> Mat[BOM匹配错误<br/>BOMMatchError]
|
||
Root --> Val[验证错误<br/>ValidationError]
|
||
|
||
Sys --> Sys1[运行时异常]
|
||
Sys --> Sys2[空引用错误]
|
||
Sys --> Sys3[类型转换错误]
|
||
|
||
Syn --> Syn1[缺少运算符]
|
||
Syn --> Syn2[括号不匹配]
|
||
Syn --> Syn3[非法字符]
|
||
|
||
Log --> Log1[相等与不等冲突]
|
||
Log --> Log2[互斥值冲突]
|
||
|
||
Map --> Map1[azxs映射缺失]
|
||
Map --> Map2[lcfw映射缺失]
|
||
|
||
Mod --> Mod1[表头为空]
|
||
Mod --> Mod2[格式不匹配]
|
||
|
||
Mat --> Mat1[无匹配记录]
|
||
Mat --> Mat2[多重匹配]
|
||
|
||
Val --> Val1[组件组合无效]
|
||
Val --> Val2[数据不完整]
|
||
|
||
style Root fill:#e1f5fe
|
||
style Sys fill:#ffcdd2
|
||
style Syn fill:#fff9c4
|
||
style Log fill:#ffe0b2
|
||
style Map fill:#c8e6c9
|
||
style Mod fill:#c8e6c9
|
||
style Mat fill:#c8e6c9
|
||
style Val fill:#c8e6c9
|
||
```
|
||
|
||
### 错误类型详细说明
|
||
|
||
| 错误类型 | 英文标识 | 严重级别 | 处理策略 | 示例 |
|
||
|----------|----------|----------|----------|------|
|
||
| 系统错误 | SystemError / System Error | 🔴 高 | 记录并跳过 | 运行时异常、对象为空 |
|
||
| 语法错误 | SyntaxError | 🔴 高 | 记录并跳过 | 条件缺少"="或"!=" |
|
||
| 逻辑冲突 | LogicConflict | 🟡 中 | 记录并跳过 | `azxs=1 AND azxs=2` |
|
||
| 映射警告 | MappingWarning | 🟢 低 | 记录并继续 | 值未在映射表中找到 |
|
||
| 型号解析错误 | ModelParseError | 🔴 高 | 记录并跳过 | 型号格式不匹配 |
|
||
| BOM匹配错误 | BOMMatchError | 🟡 中 | 记录并继续 | 无匹配/多重匹配 |
|
||
| 验证错误 | ValidationError | 🟡 中 | 记录并继续 | 组件与子组件混用 |
|
||
|
||
---
|
||
|
||
## 错误处理流程
|
||
|
||
### 完整错误处理生命周期
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant User as 用户
|
||
participant Main as M01/M09
|
||
participant Logger as clsErrorLogger
|
||
participant Module as 业务模块
|
||
participant Excel as Excel工作表
|
||
|
||
User->>Main: 启动处理
|
||
Main->>Logger: 创建错误日志记录器
|
||
Main->>Main: 初始化各模块
|
||
|
||
loop 遍历数据行
|
||
Main->>Module: 处理单条记录
|
||
Module->>Module: 执行业务逻辑
|
||
|
||
alt 处理成功
|
||
Module-->>Main: 返回成功结果
|
||
else 发生错误
|
||
Module->>Logger: Record(rowIdx, source, type, desc, context)
|
||
Logger->>Logger: 存储错误信息到集合
|
||
Logger-->>Module: 确认记录
|
||
Module-->>Main: 返回Nothing/空结果
|
||
Main->>Main: 继续处理下一条记录
|
||
end
|
||
end
|
||
|
||
Main->>Logger: HasErrors?
|
||
alt 有错误
|
||
Logger-->>Main: True
|
||
Main->>Logger: PrintReport(targetWb)
|
||
Logger->>Excel: 创建"错误报告_hhmmss"工作表
|
||
Logger->>Excel: 写入表头(红色背景)
|
||
Logger->>Excel: 批量写入错误数据
|
||
Logger->>Excel: 自动调整列宽
|
||
Main->>User: 显示警告消息框
|
||
else 无错误
|
||
Logger-->>Main: False
|
||
Main->>User: 显示成功消息
|
||
end
|
||
|
||
User-->>Main: 查看错误报告
|
||
```
|
||
|
||
### 错误记录数据结构
|
||
|
||
```mermaid
|
||
graph LR
|
||
subgraph "错误记录数组"
|
||
A[0: 行号<br/>RowIndex]
|
||
B[1: 来源模块<br/>SourceFunc]
|
||
C[2: 错误类型<br/>ErrorType]
|
||
D[3: 详细描述<br/>Description]
|
||
E[4: 原始数据<br/>Context]
|
||
end
|
||
|
||
subgraph "示例"
|
||
F[<table><tr><td>125</td></tr><tr><td>M03.ParseAtom</td></tr><tr><td>SyntaxError</td></tr><tr><td>No = or != found</td></tr><tr><td>azxsA0</td></tr></table>]
|
||
end
|
||
|
||
A & B & C & D & E --> F
|
||
|
||
style A fill:#e1f5fe
|
||
style B fill:#fff4e1
|
||
style C fill:#ffe0b2
|
||
style D fill:#c8e6c9
|
||
style E fill:#f3e5f5
|
||
style F fill:#fafafa
|
||
```
|
||
|
||
---
|
||
|
||
## 模块错误处理详解
|
||
|
||
### M03_Logic.bas - 条件解析模块
|
||
|
||
#### 错误场景
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start[M03_Logic.ParseRule] --> CheckSyntax{检查语法}
|
||
|
||
CheckSyntax -->|无效| SyntaxErr[语法错误]
|
||
CheckSyntax -->|有效| ProcessLogic[处理逻辑]
|
||
|
||
ProcessLogic --> CheckConflict{检测冲突}
|
||
|
||
CheckConflict -->|冲突| ConflictErr[逻辑冲突]
|
||
CheckConflict -->|无冲突| SystemCheck{系统检查}
|
||
|
||
SystemCheck -->|异常| SystemErr[系统错误]
|
||
SystemCheck -->|正常| Success[解析成功]
|
||
|
||
SyntaxErr --> LogSyntax[记录: SyntaxError]
|
||
ConflictErr --> LogConflict[记录: LogicConflict]
|
||
SystemErr --> LogSystem[记录: System Error]
|
||
|
||
LogSyntax --> Return[返回Nothing]
|
||
LogConflict --> Return
|
||
LogSystem --> Return
|
||
Success --> ReturnResult[返回结果集]
|
||
|
||
style SyntaxErr fill:#ffcdd2
|
||
style ConflictErr fill:#ffe0b2
|
||
style SystemErr fill:#ffcdd2
|
||
style LogSyntax fill:#fff9c4
|
||
style LogConflict fill:#ffe0b2
|
||
style LogSystem fill:#ffe0b2
|
||
style Return fill:#ffebee
|
||
```
|
||
|
||
#### 错误处理代码
|
||
|
||
**1. 系统错误处理**
|
||
```vba
|
||
ErrorHandler:
|
||
g_Logger.Record rowIdx, "M03.ParseRule", "System Error", Err.Description, strRule
|
||
Set ParseRule = Nothing
|
||
```
|
||
|
||
**2. 语法错误处理**
|
||
```vba
|
||
Else
|
||
' 无法解析的格式
|
||
If Len(strAtom) > 0 Then
|
||
g_Logger.Record rowIdx, "M03.ParseAtom", "Syntax Error", _
|
||
"No = or != found", strAtom
|
||
End If
|
||
End If
|
||
```
|
||
|
||
**3. 逻辑冲突检测**
|
||
```vba
|
||
If v1 = Mid(v2, 3) Then
|
||
' 等于一个不允许的值
|
||
g_Logger.Record rowIdx, "M03.Conflict", "Logic Conflict", _
|
||
"Equals disallowed value", k & ": " & v1 & " AND " & v2
|
||
Set MergeDictionaries = Nothing: Exit Function
|
||
ElseIf v1 = v2 Then
|
||
' 相同,无视
|
||
ElseIf Left(v1, 2) = "!=" And Left(v2, 2) = "!=" Then
|
||
' 都是不等于,合并
|
||
res(k) = v1 & "," & v2
|
||
Else
|
||
' 都是等于,但值不同 → 互斥
|
||
g_Logger.Record rowIdx, "M03.Conflict", "Logic Conflict", _
|
||
"Mutually Exclusive", k & "=" & v1 & " AND " & v2
|
||
Set MergeDictionaries = Nothing: Exit Function
|
||
End If
|
||
```
|
||
|
||
---
|
||
|
||
### M05_PreProcessor.bas - 预处理模块
|
||
|
||
#### 错误处理流程
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start[PreprocessCondition] --> CheckCategory{检查类别}
|
||
|
||
CheckCategory -->|接头/部件| LoadMapping[加载映射表]
|
||
CheckCategory -->|其他| Bypass[跳过预处理]
|
||
|
||
LoadMapping --> CheckMapping{检查映射}
|
||
|
||
CheckMapping -->|找到映射| ApplyMapping[应用映射]
|
||
CheckMapping -->|未找到| LogWarning[记录映射警告]
|
||
|
||
ApplyMapping --> MergeOR[合并OR条件]
|
||
LogWarning --> MergeOR
|
||
|
||
MergeOR --> Simplify[简化括号]
|
||
Simplify --> Success[返回转换结果]
|
||
|
||
style CheckMapping fill:#fff9c4
|
||
style LogWarning fill:#c8e6c9
|
||
style Success fill:#e8f5e9
|
||
```
|
||
|
||
#### 错误处理代码
|
||
|
||
**映射警告处理**
|
||
```vba
|
||
Else
|
||
' 记录警告但不中断处理
|
||
g_Logger.Record rowIdx, "M05.PreProcessor", "Mapping Warning", _
|
||
"Value not found in mapping table: " & keyName & "=" & originalValue, match.Value
|
||
End If
|
||
```
|
||
|
||
---
|
||
|
||
### M06_ModelParser.bas - 型号解析模块
|
||
|
||
#### 错误处理流程
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start[ParseProductModel] --> ExtractHeader[提取表头部分]
|
||
|
||
ExtractHeader --> CheckEmpty{检查是否为空}
|
||
|
||
CheckEmpty -->|为空| ParseError[解析错误]
|
||
CheckEmpty -->|有值| ParseParams[解析参数]
|
||
|
||
ParseError --> LogError1[记录: ModelParseError]
|
||
LogError1 --> ReturnEmpty[返回空字典]
|
||
|
||
ParseParams --> SystemCheck{系统检查}
|
||
|
||
SystemCheck -->|异常| SysError[系统错误]
|
||
SystemCheck -->|正常| Success[解析成功]
|
||
|
||
SysError --> LogError2[记录: SystemError]
|
||
LogError2 --> ReturnEmpty2[返回空字典]
|
||
Success --> ReturnParams[返回参数字典]
|
||
|
||
style ParseError fill:#ffcdd2
|
||
style SysError fill:#ffcdd2
|
||
style LogError1 fill:#ffe0b2
|
||
style LogError2 fill:#ffe0b2
|
||
style ReturnEmpty fill:#ffebee
|
||
style ReturnEmpty2 fill:#ffebee
|
||
```
|
||
|
||
#### 错误处理代码
|
||
|
||
**1. 解析错误处理**
|
||
```vba
|
||
If Len(headerPart) = 0 Then
|
||
If Not g_Logger Is Nothing Then
|
||
g_Logger.Record 0, "M06.ParseProductModel", "ModelParseError", _
|
||
"无法提取表头部分,型号可能为空或格式错误", modelString
|
||
End If
|
||
Set ParseProductModel = params
|
||
Exit Function
|
||
End If
|
||
```
|
||
|
||
**2. 系统错误处理**
|
||
```vba
|
||
ErrorHandler:
|
||
If Not g_Logger Is Nothing Then
|
||
g_Logger.Record 0, "M06.ParseProductModel", "SystemError", _
|
||
"解析过程发生错误: " & Err.Description, modelString
|
||
End If
|
||
Set ParseProductModel = CreateObject("Scripting.Dictionary")
|
||
```
|
||
|
||
---
|
||
|
||
### M07_BOMMatcher.bas - BOM匹配模块
|
||
|
||
#### 错误处理流程
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start[MatchBOMRecord] --> BuildMapping[构建列映射]
|
||
|
||
BuildMapping --> LoopRows[遍历行]
|
||
|
||
LoopRows --> Evaluate{评估匹配}
|
||
|
||
Evaluate -->|匹配| CheckCount{检查数量}
|
||
Evaluate -->|不匹配| NextRow[下一行]
|
||
|
||
CheckCount -->|0条| NoMatch[无匹配]
|
||
CheckCount -->|1条| Success[唯一匹配]
|
||
CheckCount -->|多条| MultiMatch[多重匹配]
|
||
|
||
NoMatch --> LogNoMatch[记录: BOMMatchError<br/>未找到匹配]
|
||
MultiMatch --> LogMulti[记录: BOMMatchError<br/>多重匹配]
|
||
|
||
LogNoMatch --> ReturnFail[返回失败结果]
|
||
LogMulti --> ReturnFail
|
||
|
||
Success --> ExtractInfo[提取物料信息]
|
||
|
||
ExtractInfo --> ExtractErr{提取异常?}
|
||
|
||
ExtractErr -->|是| LogSysError[记录: SystemError]
|
||
ExtractErr -->|否| ReturnSuccess[返回物料信息]
|
||
|
||
LogSysError --> ReturnEmptyDict[返回空字典]
|
||
|
||
style NoMatch fill:#ffe0b2
|
||
style MultiMatch fill:#ffe0b2
|
||
style ExtractErr fill:#ffcdd2
|
||
style LogNoMatch fill:#fff9c4
|
||
style LogMulti fill:#fff9c4
|
||
style LogSysError fill:#ffe0b2
|
||
style ReturnFail fill:#ffebee
|
||
```
|
||
|
||
#### 错误处理代码
|
||
|
||
**1. 匹配结果处理**
|
||
```vba
|
||
If matchResult("rowCount") = 0 Then
|
||
logger.Record 0, "M09.MatchAllMaterialTypes", "BOMMatchError", _
|
||
sheetName & " " & matchResult("message"), ""
|
||
End If
|
||
```
|
||
|
||
**2. 系统错误处理**
|
||
```vba
|
||
ErrorHandler:
|
||
If Not g_Logger Is Nothing Then
|
||
g_Logger.Record 0, "M07.MatchBOMRecord", "SystemError", _
|
||
"匹配过程发生错误: " & Err.Description, ws.Name
|
||
End If
|
||
|
||
result("success") = False
|
||
result("rowCount") = 0
|
||
Set result("rowNums") = New Collection
|
||
result("message") = "系统错误: " & Err.Description
|
||
Set MatchBOMRecord = result
|
||
```
|
||
|
||
---
|
||
|
||
### M08_ComponentProcessor.bas - 部件处理模块
|
||
|
||
#### 错误处理流程
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start[ProcessComponentRecord] --> ValidateCombination[验证组件组合]
|
||
|
||
ValidateCombination --> CheckValid{验证结果}
|
||
|
||
CheckValid -->|无效| ValidationError[验证错误]
|
||
CheckValid -->|有效| ExtractComponent[提取组件信息]
|
||
|
||
ValidationError --> LogError[记录: ValidationError<br/>无效组合]
|
||
LogError --> ReturnError[返回错误物料]
|
||
|
||
ExtractComponent --> ExtractErr{提取异常?}
|
||
|
||
ExtractErr -->|是| SystemError[系统错误]
|
||
ExtractErr -->|否| ReturnSuccess[返回组件信息]
|
||
|
||
SystemError --> LogSysError[记录: SystemError]
|
||
LogSysError --> ReturnError2[返回错误物料]
|
||
|
||
style ValidationError fill:#ffe0b2
|
||
style SystemError fill:#ffcdd2
|
||
style LogError fill:#fff9c4
|
||
style LogSysError fill:#ffe0b2
|
||
style ReturnError fill:#ffebee
|
||
style ReturnError2 fill:#ffebee
|
||
```
|
||
|
||
#### 错误处理代码
|
||
|
||
**系统错误处理**
|
||
```vba
|
||
ErrorHandler:
|
||
If Not logger Is Nothing Then
|
||
logger.Record 0, "M08.ProcessComponentRecord", "SystemError", _
|
||
"处理部件记录失败: " & Err.Description, ""
|
||
End If
|
||
|
||
' 返回错误物料信息
|
||
Dim errorMat As Object
|
||
Set errorMat = CreateObject("Scripting.Dictionary")
|
||
errorMat("materialType") = "部件"
|
||
errorMat("materialName") = ""
|
||
errorMat("materialCode") = ""
|
||
errorMat("materialQty") = 0
|
||
errorMat("remarks") = "系统错误: " & Err.Description
|
||
```
|
||
|
||
---
|
||
|
||
### M09_BOMExtractor.bas - BOM提取模块
|
||
|
||
#### 错误处理流程
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start[ProcessSingleModel] --> ParseModel[解析型号]
|
||
|
||
ParseModel --> ParseOK{解析成功?}
|
||
|
||
ParseOK -->|失败| LogParseError[记录: ModelParseError]
|
||
ParseOK -->|成功| MatchLoop[匹配所有物料类型]
|
||
|
||
LogParseError --> GenerateErrorRow[生成错误行]
|
||
GenerateErrorRow --> Continue[继续下一个型号]
|
||
|
||
MatchLoop --> MatchCheck{匹配检查}
|
||
|
||
MatchCheck -->|匹配失败| LogMatchError[记录: BOMMatchError]
|
||
MatchCheck -->|匹配成功| SaveResult[保存结果]
|
||
|
||
LogMatchError --> Continue
|
||
SaveResult --> Continue
|
||
|
||
Continue --> End[结束]
|
||
|
||
style LogParseError fill:#ffe0b2
|
||
style LogMatchError fill:#ffe0b2
|
||
style GenerateErrorRow fill:#ffebee
|
||
```
|
||
|
||
#### 错误处理代码
|
||
|
||
**1. 单型号处理错误**
|
||
```vba
|
||
ErrorHandler:
|
||
If Not logger Is Nothing Then
|
||
logger.Record 0, "M09.ProcessSingleModel", "SystemError", _
|
||
"处理型号[" & modelString & "]失败: " & Err.Description, ""
|
||
End If
|
||
|
||
results.Add GenerateErrorRow(modelString, "系统错误: " & Err.Description)
|
||
Set ProcessSingleModel = results
|
||
```
|
||
|
||
**2. 匹配错误处理**
|
||
```vba
|
||
If matchResult("rowCount") = 0 Then
|
||
logger.Record 0, "M09.MatchAllMaterialTypes", "BOMMatchError", _
|
||
sheetName & " " & matchResult("message"), ""
|
||
End If
|
||
```
|
||
|
||
---
|
||
|
||
## 错误恢复策略
|
||
|
||
### 策略分类
|
||
|
||
```mermaid
|
||
graph TD
|
||
subgraph "错误恢复策略"
|
||
A[策略选择]
|
||
|
||
A --> B[继续处理<br/>Continue Processing]
|
||
A --> C[优雅降级<br/>Graceful Degradation]
|
||
A --> D[仅警告<br/>Warning Only]
|
||
end
|
||
|
||
subgraph "继续处理"
|
||
B1[记录错误]
|
||
B2[返回Nothing/空值]
|
||
B3[处理下一条记录]
|
||
end
|
||
|
||
subgraph "优雅降级"
|
||
C1[检测组件失败]
|
||
C2[返回错误物料]
|
||
C3[保存部分结果]
|
||
end
|
||
|
||
subgraph "仅警告"
|
||
D1[记录警告信息]
|
||
D2[继续正常流程]
|
||
D3[不中断处理]
|
||
end
|
||
|
||
B --> B1 --> B2 --> B3
|
||
C --> C1 --> C2 --> C3
|
||
D --> D1 --> D2 --> D3
|
||
|
||
style B fill:#c8e6c9
|
||
style C fill:#fff9c4
|
||
style D fill:#e1f5fe
|
||
style B3 fill:#e8f5e9
|
||
style C3 fill:#ffe0b2
|
||
style D3 fill:#e8f5e9
|
||
```
|
||
|
||
### 策略详解
|
||
|
||
#### 1. 继续处理 (Continue Processing)
|
||
|
||
**适用场景**: 语法错误、系统错误、解析错误
|
||
|
||
```vba
|
||
' M03_Logic.bas
|
||
ErrorHandler:
|
||
g_Logger.Record rowIdx, "M03.ParseRule", "System Error", Err.Description, strRule
|
||
Set ParseRule = Nothing ' 返回Nothing表示失败
|
||
' 调用方检测到Nothing后继续处理下一条记录
|
||
```
|
||
|
||
**流程**:
|
||
```
|
||
错误发生 → 记录错误 → 返回Nothing → 调用方跳过 → 处理下一条记录
|
||
```
|
||
|
||
---
|
||
|
||
#### 2. 优雅降级 (Graceful Degradation)
|
||
|
||
**适用场景**: 组件处理失败、物料提取失败
|
||
|
||
```vba
|
||
' M08_ComponentProcessor.bas
|
||
ErrorHandler:
|
||
' 返回错误物料信息而不是崩溃
|
||
Dim errorMat As Object
|
||
Set errorMat = CreateObject("Scripting.Dictionary")
|
||
errorMat("materialType") = "部件"
|
||
errorMat("materialName") = ""
|
||
errorMat("materialCode") = ""
|
||
errorMat("materialQty") = 0
|
||
errorMat("remarks") = "系统错误: " & Err.Description
|
||
```
|
||
|
||
**流程**:
|
||
```
|
||
错误发生 → 构造错误对象 → 返回部分信息 → 用户看到部分结果
|
||
```
|
||
|
||
---
|
||
|
||
#### 3. 仅警告 (Warning Only)
|
||
|
||
**适用场景**: 映射值缺失、预处理警告
|
||
|
||
```vba
|
||
' M05_PreProcessor.bas
|
||
Else
|
||
' 记录警告但继续使用原始值
|
||
g_Logger.Record rowIdx, "M05.PreProcessor", "Mapping Warning", _
|
||
"Value not found in mapping table: " & keyName & "=" & originalValue, match.Value
|
||
End If
|
||
' 继续处理,使用原始值
|
||
```
|
||
|
||
**流程**:
|
||
```
|
||
检测问题 → 记录警告 → 使用原始值 → 继续正常流程
|
||
```
|
||
|
||
---
|
||
|
||
### 策略对比
|
||
|
||
| 策略 | 严重级别 | 结果处理 | 用户体验 | 适用场景 |
|
||
|------|----------|----------|----------|----------|
|
||
| 继续处理 | 🔴 高 | 跳过当前记录 | 部分数据缺失 | 语法/系统/解析错误 |
|
||
| 优雅降级 | 🟡 中 | 返回部分数据 | 看到错误标记 | 组件/物料提取失败 |
|
||
| 仅警告 | 🟢 低 | 使用原始值 | 无明显影响 | 映射值缺失 |
|
||
|
||
---
|
||
|
||
## 错误报告生成
|
||
|
||
### clsErrorLogger.PrintReport 方法
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start[PrintReport] --> CheckCount{检查错误数量}
|
||
|
||
CheckCount -->|0个错误| Exit[退出, 不生成报告]
|
||
CheckCount -->|有错误| CreateSheet[创建新工作表]
|
||
|
||
CreateSheet --> SetName[设置名称:<br/>错误报告_hhmmss]
|
||
|
||
SetName --> WriteHeader[写入表头]
|
||
|
||
WriteHeader --> FormatHeader[格式化表头:<br/>粗体+红色背景]
|
||
|
||
FormatHeader --> PrepareArray[准备输出数组]
|
||
|
||
PrepareArray --> LoopErrors[遍历错误集合]
|
||
|
||
LoopErrors --> PopulateArray[填充数组数据]
|
||
|
||
PopulateArray --> CheckEnd{还有错误?}
|
||
|
||
CheckEnd -->|是| LoopErrors
|
||
CheckEnd -->|否| WriteData[批量写入数据]
|
||
|
||
WriteData --> AutoFit[自动调整列宽]
|
||
|
||
AutoFit --> End[结束]
|
||
|
||
style CheckCount fill:#fff9c4
|
||
style Exit fill:#c8e6c9
|
||
style FormatHeader fill:#ffe0b2
|
||
style End fill:#e8f5e9
|
||
```
|
||
|
||
### 错误报告结构
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "错误报告工作表"
|
||
Header[第1行: 表头<br/>红色背景+粗体]
|
||
Data[第2行-N: 数据]
|
||
end
|
||
|
||
subgraph "列结构"
|
||
ColA[列A: 原表行号]
|
||
ColB[列B: 来源模块]
|
||
ColC[列C: 错误类型]
|
||
ColD[列D: 详细描述]
|
||
ColE[列E: 原始数据]
|
||
end
|
||
|
||
subgraph "示例数据"
|
||
Row2[<table><tr><td>125</td><td>M03.ParseAtom</td><td>SyntaxError</td><td>No = or != found</td><td>azxsA0</td></tr></table>]
|
||
Row3[<table><tr><td>138</td><td>M03.Conflict</td><td>LogicConflict</td><td>Mutually Exclusive</td><td>azxs=径向 AND azxs=下轴向</td></tr></table>]
|
||
end
|
||
|
||
Header --> ColA & ColB & ColC & ColD & ColE
|
||
Data --> Row2 & Row3
|
||
|
||
style Header fill:#ffcdd2
|
||
style Row2 fill:#fafafa
|
||
style Row3 fill:#fafafa
|
||
```
|
||
|
||
### 代码实现
|
||
|
||
```vba
|
||
Public Sub PrintReport(targetWb As Workbook)
|
||
If pErrors.count = 0 Then Exit Sub
|
||
|
||
' 1. 创建新工作表
|
||
Dim ws As Worksheet
|
||
Set ws = targetWb.Worksheets.Add(After:=targetWb.Worksheets(targetWb.Worksheets.count))
|
||
ws.Name = "错误报告_" & Format(Now, "hhmmss")
|
||
|
||
' 2. 写入表头(红色背景,粗体)
|
||
ws.Range("A1:E1").Value = Array("原表行号", "来源模块", "错误类型", "详细描述", "原始数据")
|
||
ws.Range("A1:E1").Font.Bold = True
|
||
ws.Range("A1:E1").Interior.Color = RGB(255, 200, 200)
|
||
|
||
' 3. 准备输出数组(批量写入提高性能)
|
||
Dim arrOutput() As Variant
|
||
ReDim arrOutput(1 To pErrors.count, 1 To 5)
|
||
|
||
Dim i As Long
|
||
Dim vItem As Variant
|
||
|
||
For i = 1 To pErrors.count
|
||
vItem = pErrors(i)
|
||
arrOutput(i, 1) = vItem(0) ' 行号
|
||
arrOutput(i, 2) = vItem(1) ' 来源模块
|
||
arrOutput(i, 3) = vItem(2) ' 错误类型
|
||
arrOutput(i, 4) = vItem(3) ' 描述
|
||
arrOutput(i, 5) = vItem(4) ' 上下文
|
||
Next i
|
||
|
||
' 4. 批量写入数据
|
||
ws.Range("A2").Resize(UBound(arrOutput, 1), 5).Value = arrOutput
|
||
|
||
' 5. 自动调整列宽
|
||
ws.Columns.AutoFit
|
||
End Sub
|
||
```
|
||
|
||
### 报告生成调用
|
||
|
||
```vba
|
||
' M01_Main.bas - BOM转换系统
|
||
If logger.HasErrors Then
|
||
logger.PrintReport ActiveWorkbook
|
||
MsgBox "转换完成,但发现部分数据存在逻辑冲突,已生成错误报告。", vbExclamation
|
||
End If
|
||
|
||
' M09_BOMExtractor.bas - BOM提取系统
|
||
If g_Logger.HasErrors Then
|
||
g_Logger.PrintReport ActiveWorkbook
|
||
result = "BOM提取完成,但发现部分错误,已生成错误报告。"
|
||
Else
|
||
result = "BOM提取成功完成!"
|
||
End If
|
||
```
|
||
|
||
---
|
||
|
||
## 最佳实践
|
||
|
||
### 1. 一致的日志记录器初始化
|
||
|
||
所有可能产生错误的模块都遵循相同的初始化模式:
|
||
|
||
```vba
|
||
' 模块级别声明
|
||
Private g_Logger As clsErrorLogger
|
||
|
||
' 公共初始化方法
|
||
Public Sub Init[ModuleName](logger As clsErrorLogger)
|
||
Set g_Logger = logger
|
||
End Sub
|
||
```
|
||
|
||
**优点**:
|
||
- 统一的接口
|
||
- 依赖注入模式
|
||
- 易于测试和维护
|
||
|
||
---
|
||
|
||
### 2. 结构化的错误信息
|
||
|
||
每条错误记录都包含5个关键信息:
|
||
|
||
| 字段 | 类型 | 用途 | 示例 |
|
||
|------|------|------|------|
|
||
| 行号 | Long | 定位Excel行 | 125 |
|
||
| 来源模块 | String | 定位代码位置 | "M03.ParseAtom" |
|
||
| 错误类型 | String | 错误分类 | "SyntaxError" |
|
||
| 详细描述 | String | 人类可读的描述 | "No = or != found" |
|
||
| 原始数据 | String | 调试上下文 | "azxsA0" |
|
||
|
||
---
|
||
|
||
### 3. 防御性编程
|
||
|
||
**使用 `Nothing` 检查**:
|
||
```vba
|
||
If Not g_Logger Is Nothing Then
|
||
g_Logger.Record 0, "M06.ParseProductModel", "SystemError", _
|
||
"解析过程发生错误: " & Err.Description, modelString
|
||
End If
|
||
```
|
||
|
||
**优点**: 即使日志记录器未初始化也不会崩溃
|
||
|
||
---
|
||
|
||
### 4. 延迟绑定避免依赖
|
||
|
||
```vba
|
||
' 使用 CreateObject 而不是 New
|
||
Set params = CreateObject("Scripting.Dictionary")
|
||
Set errorMat = CreateObject("Scripting.Dictionary")
|
||
```
|
||
|
||
**优点**:
|
||
- 无需添加外部引用
|
||
- 提高兼容性
|
||
- 减少部署问题
|
||
|
||
---
|
||
|
||
### 5. 批量操作优化
|
||
|
||
错误报告使用数组批量写入:
|
||
|
||
```vba
|
||
' 准备数组
|
||
ReDim arrOutput(1 To pErrors.count, 1 To 5)
|
||
|
||
' 填充数组
|
||
For i = 1 To pErrors.count
|
||
arrOutput(i, 1) = ...
|
||
Next i
|
||
|
||
' 一次性写入
|
||
ws.Range("A2").Resize(UBound(arrOutput, 1), 5).Value = arrOutput
|
||
```
|
||
|
||
**优点**: 比逐单元格写入快10-100倍
|
||
|
||
---
|
||
|
||
### 6. 用户友好的错误通知
|
||
|
||
```vba
|
||
If logger.HasErrors Then
|
||
logger.PrintReport ActiveWorkbook
|
||
MsgBox "转换完成,但发现部分数据存在逻辑冲突,已生成错误报告。", _
|
||
vbExclamation, "处理完成"
|
||
End If
|
||
```
|
||
|
||
**要点**:
|
||
- 明确告知有错误
|
||
- 说明已生成报告
|
||
- 使用合适的图标类型
|
||
|
||
---
|
||
|
||
### 7. 错误级别分类
|
||
|
||
使用统一的错误类型标识:
|
||
|
||
```vba
|
||
' 致命错误 - 红色
|
||
"SystemError"
|
||
"SyntaxError"
|
||
"ModelParseError"
|
||
|
||
' 警告 - 黄色
|
||
"LogicConflict"
|
||
"BOMMatchError"
|
||
"ValidationError"
|
||
|
||
' 信息 - 绿色
|
||
"MappingWarning"
|
||
```
|
||
|
||
---
|
||
|
||
### 8. 上下文信息保留
|
||
|
||
始终记录导致错误的原始数据:
|
||
|
||
```vba
|
||
g_Logger.Record rowIdx, "M03.ParseAtom", "Syntax Error", _
|
||
"No = or != found", strAtom ' 保留原始数据
|
||
```
|
||
|
||
**优点**: 便于后续调试和修复
|
||
|
||
---
|
||
|
||
## 测试覆盖
|
||
|
||
### M99_TestRunner.bas 中的错误测试
|
||
|
||
```mermaid
|
||
graph TD
|
||
subgraph "错误测试用例"
|
||
T1[Test_LogicConflict01<br/>相等与不等冲突]
|
||
T2[Test_LogicConflict02<br/>互斥值冲突]
|
||
T3[Test_SysError01<br/>空条件处理]
|
||
T4[Test_PP_MissingValue<br/>映射值缺失]
|
||
end
|
||
|
||
subgraph "验证内容"
|
||
V1[错误被正确记录]
|
||
V2[返回Nothing/空值]
|
||
V3[处理继续不中断]
|
||
V4[错误报告正确生成]
|
||
end
|
||
|
||
T1 --> V1 & V2 & V3
|
||
T2 --> V1 & V2 & V3
|
||
T3 --> V1 & V2 & V3
|
||
T4 --> V1 & V3 & V4
|
||
|
||
style T1 fill:#ffe0b2
|
||
style T2 fill:#ffe0b2
|
||
style T3 fill:#ffcdd2
|
||
style T4 fill:#c8e6c9
|
||
```
|
||
|
||
### 测试示例
|
||
|
||
**逻辑冲突测试**
|
||
```vba
|
||
Public Sub Test_LogicConflict01()
|
||
' 测试: azxs=1 AND azxs!=1
|
||
Dim result As Collection
|
||
Set result = M03_Logic.ParseRule("azxs=1 AND azxs!=1", 10)
|
||
|
||
' 验证: 应该返回Nothing并记录错误
|
||
Assert result Is Nothing, "应该检测到相等与不等冲突"
|
||
End Sub
|
||
```
|
||
|
||
**映射值缺失测试**
|
||
```vba
|
||
Public Sub Test_PP_MissingValue()
|
||
' 测试: azxs值未在映射表中
|
||
Dim result As String
|
||
result = M05_PreProcessor.PreprocessCondition("azxs=INVALID", "接头", 10)
|
||
|
||
' 验证: 应该记录警告但继续处理
|
||
Assert result <> "", "即使映射缺失也应返回结果"
|
||
End Sub
|
||
```
|
||
|
||
---
|
||
|
||
## 快速参考
|
||
|
||
### 错误处理常用代码片段
|
||
|
||
#### 1. 初始化日志记录器
|
||
|
||
```vba
|
||
' 在主模块中
|
||
Dim logger As New clsErrorLogger
|
||
|
||
' 传递给子模块
|
||
M03_Logic.InitLogic logger
|
||
M05_PreProcessor.InitPreProcessor logger, wsMapping
|
||
```
|
||
|
||
#### 2. 记录错误
|
||
|
||
```vba
|
||
' 完整格式
|
||
g_Logger.Record rowIdx, "Module.Function", "ErrorType", "Description", "Context"
|
||
|
||
' 示例
|
||
g_Logger.Record 125, "M03.ParseAtom", "Syntax Error", _
|
||
"No = or != found", "azxsA0"
|
||
```
|
||
|
||
#### 3. 检查并报告错误
|
||
|
||
```vba
|
||
If logger.HasErrors Then
|
||
logger.PrintReport ActiveWorkbook
|
||
MsgBox "处理完成,但发现错误。", vbExclamation
|
||
End If
|
||
```
|
||
|
||
#### 4. 标准错误处理器
|
||
|
||
```vba
|
||
ErrorHandler:
|
||
If Not g_Logger Is Nothing Then
|
||
g_Logger.Record rowIdx, "Module.Function", "SystemError", _
|
||
Err.Description, contextData
|
||
End If
|
||
Set FunctionResult = Nothing
|
||
```
|
||
|
||
---
|
||
|
||
### 错误类型速查表
|
||
|
||
| 类型标识 | 显示名称 | 严重级别 | 通用模块 |
|
||
|----------|----------|----------|----------|
|
||
| `SystemError` | System Error | 🔴 高 | 所有模块 |
|
||
| `System Error` | System Error | 🔴 高 | M03_Logic |
|
||
| `SyntaxError` | Syntax Error | 🔴 高 | M03_Logic |
|
||
| `LogicConflict` | Logic Conflict | 🟡 中 | M03_Logic |
|
||
| `MappingWarning` | Mapping Warning | 🟢 低 | M05_PreProcessor |
|
||
| `ModelParseError` | Model Parse Error | 🔴 高 | M06_ModelParser |
|
||
| `BOMMatchError` | BOM Match Error | 🟡 中 | M07_BOMMatcher, M09_BOMExtractor |
|
||
| `ValidationError` | Validation Error | 🟡 中 | M08_ComponentProcessor |
|
||
|
||
---
|
||
|
||
### 错误报告格式
|
||
|
||
**工作表名称**: `错误报告_hhmmss` (例如: `错误报告_143025`)
|
||
|
||
**列结构**:
|
||
|
||
| 列 | 宽度 | 对齐 | 说明 |
|
||
|----|------|------|------|
|
||
| A | 自动 | 左对齐 | 原表行号 |
|
||
| B | 自动 | 左对齐 | 来源模块 |
|
||
| C | 自动 | 左对齐 | 错误类型 |
|
||
| D | 自动 | 左对齐 | 详细描述 |
|
||
| E | 自动 | 左对齐 | 原始数据 |
|
||
|
||
**格式**:
|
||
- 第1行: 粗体 + 红色背景 (RGB 255, 200, 200)
|
||
- 数据行: 默认格式
|
||
- 列宽: 自动调整
|
||
|
||
---
|
||
|
||
### 相关文档
|
||
|
||
- [RunBOMExtraction_运行机制详解.md](./RunBOMExtraction_运行机制详解.md) - BOM提取系统文档
|
||
- [M03_Logic_Algorithm.md](./M03_Logic_Algorithm.md) - 条件解析算法详解
|
||
- [Test_PP_06_FullIntegration_流程详解.md](./Test_PP_06_FullIntegration_流程详解.md) - 预处理系统集成测试
|
||
- [CLAUDE.md](../CLAUDE.md) - 项目整体说明
|
||
|
||
---
|
||
|
||
**文档版本**: 1.0
|
||
**最后更新**: 2026-02-12
|
||
**作者**: Claude Code
|
||
**状态**: 初稿完成
|
||
**审核**: 待审核
|