Files
AutoBOM/docs/错误处理机制详解.md
Misaka_Company 68798920d6
All checks were successful
NTFY Notification / notify (push) Successful in 3s
docs: add comprehensive error handling mechanism documentation
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>
2026-02-12 14:35:30 +08:00

30 KiB
Raw Blame History

错误处理机制详解

目录

  1. 系统概述
  2. 错误处理架构
  3. 错误类型与分类
  4. 错误处理流程
  5. 模块错误处理详解
  6. 错误恢复策略
  7. 错误报告生成
  8. 最佳实践
  9. 测试覆盖
  10. 快速参考

系统概述

AutoBOM系统采用集中式日志记录 + 持续处理的错误处理策略确保在批量处理BOM数据时单个记录的错误不会中断整个处理流程。

核心设计原则

  1. 错误隔离: 单个记录错误不影响其他记录处理
  2. 错误累积: 所有错误统一收集,集中展示
  3. 上下文保留: 记录完整的错误上下文信息
  4. 用户友好: 提供清晰的错误描述和定位信息

设计优势

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

错误处理架构

类层次结构

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

模块依赖关系

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

错误类型与分类

错误分类体系

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 🟡 记录并继续 组件与子组件混用

错误处理流程

完整错误处理生命周期

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: 查看错误报告

错误记录数据结构

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 - 条件解析模块

错误场景

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. 系统错误处理

ErrorHandler:
    g_Logger.Record rowIdx, "M03.ParseRule", "System Error", Err.Description, strRule
    Set ParseRule = Nothing

2. 语法错误处理

Else
    ' 无法解析的格式
    If Len(strAtom) > 0 Then
        g_Logger.Record rowIdx, "M03.ParseAtom", "Syntax Error", _
            "No = or != found", strAtom
    End If
End If

3. 逻辑冲突检测

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 - 预处理模块

错误处理流程

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

错误处理代码

映射警告处理

Else
    ' 记录警告但不中断处理
    g_Logger.Record rowIdx, "M05.PreProcessor", "Mapping Warning", _
        "Value not found in mapping table: " & keyName & "=" & originalValue, match.Value
End If

M06_ModelParser.bas - 型号解析模块

错误处理流程

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. 解析错误处理

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. 系统错误处理

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匹配模块

错误处理流程

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. 匹配结果处理

If matchResult("rowCount") = 0 Then
    logger.Record 0, "M09.MatchAllMaterialTypes", "BOMMatchError", _
        sheetName & " " & matchResult("message"), ""
End If

2. 系统错误处理

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 - 部件处理模块

错误处理流程

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

错误处理代码

系统错误处理

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提取模块

错误处理流程

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. 单型号处理错误

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. 匹配错误处理

If matchResult("rowCount") = 0 Then
    logger.Record 0, "M09.MatchAllMaterialTypes", "BOMMatchError", _
        sheetName & " " & matchResult("message"), ""
End If

错误恢复策略

策略分类

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)

适用场景: 语法错误、系统错误、解析错误

' M03_Logic.bas
ErrorHandler:
    g_Logger.Record rowIdx, "M03.ParseRule", "System Error", Err.Description, strRule
    Set ParseRule = Nothing  ' 返回Nothing表示失败
    ' 调用方检测到Nothing后继续处理下一条记录

流程:

错误发生 → 记录错误 → 返回Nothing → 调用方跳过 → 处理下一条记录

2. 优雅降级 (Graceful Degradation)

适用场景: 组件处理失败、物料提取失败

' 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)

适用场景: 映射值缺失、预处理警告

' 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 方法

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

错误报告结构

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

代码实现

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

报告生成调用

' 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. 一致的日志记录器初始化

所有可能产生错误的模块都遵循相同的初始化模式:

' 模块级别声明
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 检查:

If Not g_Logger Is Nothing Then
    g_Logger.Record 0, "M06.ParseProductModel", "SystemError", _
        "解析过程发生错误: " & Err.Description, modelString
End If

优点: 即使日志记录器未初始化也不会崩溃


4. 延迟绑定避免依赖

' 使用 CreateObject 而不是 New
Set params = CreateObject("Scripting.Dictionary")
Set errorMat = CreateObject("Scripting.Dictionary")

优点:

  • 无需添加外部引用
  • 提高兼容性
  • 减少部署问题

5. 批量操作优化

错误报告使用数组批量写入:

' 准备数组
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. 用户友好的错误通知

If logger.HasErrors Then
    logger.PrintReport ActiveWorkbook
    MsgBox "转换完成,但发现部分数据存在逻辑冲突,已生成错误报告。", _
           vbExclamation, "处理完成"
End If

要点:

  • 明确告知有错误
  • 说明已生成报告
  • 使用合适的图标类型

7. 错误级别分类

使用统一的错误类型标识:

' 致命错误 - 红色
"SystemError"
"SyntaxError"
"ModelParseError"

' 警告 - 黄色
"LogicConflict"
"BOMMatchError"
"ValidationError"

' 信息 - 绿色
"MappingWarning"

8. 上下文信息保留

始终记录导致错误的原始数据:

g_Logger.Record rowIdx, "M03.ParseAtom", "Syntax Error", _
    "No = or != found", strAtom  ' 保留原始数据

优点: 便于后续调试和修复


测试覆盖

M99_TestRunner.bas 中的错误测试

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

测试示例

逻辑冲突测试

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

映射值缺失测试

Public Sub Test_PP_MissingValue()
    ' 测试: azxs值未在映射表中
    Dim result As String
    result = M05_PreProcessor.PreprocessCondition("azxs=INVALID", "接头", 10)

    ' 验证: 应该记录警告但继续处理
    Assert result <> "", "即使映射缺失也应返回结果"
End Sub

快速参考

错误处理常用代码片段

1. 初始化日志记录器

' 在主模块中
Dim logger As New clsErrorLogger

' 传递给子模块
M03_Logic.InitLogic logger
M05_PreProcessor.InitPreProcessor logger, wsMapping

2. 记录错误

' 完整格式
g_Logger.Record rowIdx, "Module.Function", "ErrorType", "Description", "Context"

' 示例
g_Logger.Record 125, "M03.ParseAtom", "Syntax Error", _
    "No = or != found", "azxsA0"

3. 检查并报告错误

If logger.HasErrors Then
    logger.PrintReport ActiveWorkbook
    MsgBox "处理完成,但发现错误。", vbExclamation
End If

4. 标准错误处理器

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)
  • 数据行: 默认格式
  • 列宽: 自动调整

相关文档


文档版本: 1.0 最后更新: 2026-02-12 作者: Claude Code 状态: 初稿完成 审核: 待审核