# 重构计划:整合 [领料配置] 到 [平台配置清单] ## 一、背景概述 ### 1.1 重构目标 将原有的 [领料配置] 表格的功能整合到 [平台配置清单] 中,简化数据结构,统一管理。 ### 1.2 变化原因 - 原有设计:物料基础信息在 [平台配置清单],类别配置在 [领料配置],数据分散 - 新设计:所有信息集中在 [平台配置清单] 一张表,便于维护 --- ## 二、新工作表结构分析 ### 2.1 新表结构 **[平台配置清单] 表结构**(第3行标题): | 列 | 字段名 | 说明 | 示例 | |---|--------|------|------| | A | 行号 | 数据行序号 | 10, 20, 30 | | B | 模块 | 模块分类 | 316L部件 | | C | 代号 | 物料代号 | 01011009557 | | D | 名称 | 物料名称 | 径向低压接头部件 | | E | 数量 | 物料数量 | 1.0 | | F | 选择条件 | 物料选用条件 | gclj=M20 AND jycz=1 | | G | 备注 | 备注信息 | | | **H** | **类别** | ⭐ 新增:物料所属类别 | 部件 | | **I** | **上层类别** | ⭐ 新增:父类别名称 | | | **J** | **类别选用条件** | ⭐ 新增:判断该类别是否需要 | lcfw=M02 | | **K** | **66代码** | ⭐ 新增:66系统代码 | 66021009557 | ### 2.2 字段说明 #### 新增字段详解 1. **类别(H列)** - 类型:字符串 - 说明:物料所属的类别名称 - 示例:`部件`、`表壳`、`接头`、`机芯` - 为空:表示该物料不属于任何类别(不需要领料) 2. **上层类别(I列)** - 类型:字符串 - 说明:父类别的名称,用于构建类别层级树 - 示例:`接头` 的上层类别是 `部件` - 为空:表示该类别是根类别 3. **类别选用条件(J列)** ⭐ **关键字段** - 类型:字符串(逻辑表达式) - 说明:用于判断该类别是否需要被选用 - 格式:与"选择条件"字段相同的逻辑表达式 - 判断规则: - **为空**:该类别总是需要(无条件) - **不为空**:需要用型号提取的条件去匹配,匹配成功才需要 - 示例: - `lcfw=M02`:只有当量程是 M02 时才需要这个类别 - `gclj=M20 AND jycz=1`:只有当过程连接是 M20 且接液材质是 1 时才需要 4. **66代码(K列)** - 类型:字符串 - 说明:66系统使用的代码(具体用途待补充) - 示例:`66021009557` --- ## 三、核心业务逻辑变化 ### 3.1 旧逻辑(重构前) ``` 有效性检查规则: - 所有根类别都必须匹配到至少1个物料 - 每个根类别(或其子类别)必须有且仅有1个物料匹配 - 如果有任何一个类别不满足,则物料集合不完整 ``` **问题**: - 无法表达"某些型号不需要某些类别"的情况 - 例如:某些型号可能不需要"机芯"类别 ### 3.2 新逻辑(重构后) ``` 有效性检查规则: - 第一步:确定哪些类别是该型号需要的 - 遍历所有有物料的类别 - 如果"类别选用条件"为空 → 该类别总是需要 - 如果"类别选用条件"不为空 → 用型号条件去匹配,匹配成功才需要 - 第二步:只检查需要的类别是否有物料匹配 - 对于需要的类别,必须有且仅有1个物料匹配 - 不需要的类别不参与完整性检查 ``` **示例场景**: 型号:`YTHN-100.A0.532.M203.M16.Y3` (量程 M16) | 类别 | 类别选用条件 | 是否需要 | 说明 | |------|-------------|---------|------| | 表壳 | (空) | ✅ 需要 | 无条件,总是需要 | | 部件 | lcfw=M02 | ❌ 不需要 | 型号量程是 M16,不满足条件 | | 接头 | lcfw=M16 | ✅ 需要 | 型号量程是 M16,满足条件 | | 机芯 | gclj=M20 | ❌ 不需要 | 型号过程连接不是 M20 | **结果**:只需要检查 `表壳` 和 `接头` 类别的物料完整性 --- ## 四、代码影响分析 ### 4.1 需要修改的模块和方法 #### 1. clsBOMManager 类 ⭐ **核心改动** **1.1 LoadData 方法** ```vba ' 旧签名 Public Sub LoadData(wsConfig As Worksheet, wsPlatform As Worksheet) ' 新签名 Public Sub LoadData(wsPlatform As Worksheet) ``` **变化**: - ❌ 移除 `wsConfig` 参数(不再需要 [领料配置] 表) - ✅ 所有数据从 [平台配置清单] 读取 - ✅ 读取列数增加:从 A-F 扩展到 A-K **读取列对应**: ```vba ' 第一步:加载物料和类别信息(一次性完成) For i = 4 To lastRow ' 基础信息 mat.code = Trim(wsPlatform.Cells(i, "C").value) ' 代号 mat.Name = Trim(wsPlatform.Cells(i, "D").value) ' 名称 mat.Quantity = CDbl(wsPlatform.Cells(i, "E").value) ' 数量 mat.Condition = Trim(wsPlatform.Cells(i, "F").value) ' 选择条件 ' ⭐ 新增:类别相关字段 catName = Trim(wsPlatform.Cells(i, "H").value) ' 类别 parentCatName = Trim(wsPlatform.Cells(i, "I").value) ' 上层类别 catSelectCond = Trim(wsPlatform.Cells(i, "J").value) ' 类别选用条件 code66 = Trim(wsPlatform.Cells(i, "K").value) ' 66代码 Next i ``` **流程变化**: ``` 旧流程(三步): 1. 从 [平台配置清单] 加载物料基础信息 2. 从 [领料配置] 加载类别信息 3. 建立类别层级关系 新流程(两步): 1. 从 [平台配置清单] 加载物料和类别信息(一次性) 2. 建立类别层级关系 ``` --- **1.2 GetValidMaterialsByModel 方法** **变化**: - ✅ 需要先判断哪些类别是该型号需要的 - ✅ 只检查需要的类别的完整性 **新逻辑**: ```vba Public Function GetValidMaterialsByModel(modelStr As String) As collection ' 1. 解析型号并提取条件 Set conditions = ParseModelAndExtractConditions(modelStr) ' 2. ⭐ 新增:确定需要的类别列表 Dim requiredCategories As collection Set requiredCategories = GetRequiredCategories(conditions) ' 3. 只检查需要的类别 For Each cat In requiredCategories Set catResult = CheckCategoryCompleteness(cat, matcher, conditions) ' ... Next cat End Function ``` --- **1.3 GetRequiredCategories 方法(新增)** **功能**:根据型号条件,确定哪些类别是需要的 ```vba Private Function GetRequiredCategories(conditions As Object) As collection ' 遍历所有类别 ' - 类别选用条件为空 → 添加到需要列表 ' - 类别选用条件不为空 → 用 conditions 去匹配 ' - 匹配成功 → 添加到需要列表 ' - 匹配失败 → 不添加 End Function ``` --- **1.4 CheckCategoryCompleteness 方法** **变化**: - 无需修改,因为调用者已经过滤了不需要的类别 - 逻辑保持不变:检查需要的类别是否有且仅有1个物料匹配 --- #### 2. clsCategory 类 ⭐ **需要扩展** **新增属性**: ```vba Public CategorySelectCondition As String ' ⭐ 新增:类别选用条件 Public IsRequired As Boolean ' ⭐ 新增:是否需要(计算属性) ``` **新增方法**: ```vba ' 检查该类别是否需要(根据型号条件) Public Function IsRequiredForModel(conditions As Object) As Boolean If Me.CategorySelectCondition = "" Then ' 选用条件为空,总是需要 IsRequiredForModel = True Else ' 需要用 conditions 去匹配 CategorySelectCondition Dim matcher As New clsConditionMatcher IsRequiredForModel = matcher.IsMatch(Me.CategorySelectCondition, conditions) End If End Function ``` --- #### 3. clsMaterialItem 类 ⭐ **需要扩展** **新增属性**: ```vba Public CategorySelectCondition As String ' ⭐ 新增:类别选用条件 Public Code66 As String ' ⭐ 新增:66代码 ``` **说明**: - 物料需要保存所属类别的"类别选用条件" - 便于后续判断该物料是否需要 --- ### 4.2 不需要修改的方法 以下方法不受影响,无需修改: - ✅ `GetRootCategories()` - 获取根类别 - ✅ `GetCategory(categoryName)` - 获取类别对象 - ✅ `GetMaterialsByModel()` - 根据型号获取物料(不涉及完整性检查) - ✅ `GetMaterialsForPicking()` - 获取领料物料 - ✅ `ParseModelAndExtractConditions()` - 解析型号 - ✅ `FilterCategoryWithSubcategories()` - 类别筛选 - ✅ `CollectAllMaterials()` - 收集物料 - ✅ `PrintCategoryTree()` - 打印类别树 --- ## 五、重构实施计划 ### 5.1 实施步骤 #### 阶段一:数据模型扩展(1-2小时) **任务清单**: 1. ✅ **修改 clsMaterialItem 类** - [ ] 添加 `CategorySelectCondition` 属性 - [ ] 添加 `Code66` 属性 - [ ] 更新类注释 2. ✅ **修改 clsCategory 类** - [ ] 添加 `CategorySelectCondition` 属性 - [ ] 添加 `IsRequiredForModel()` 方法 - [ ] 更新类注释 3. ✅ **添加测试用例** - [ ] 测试类别选用条件的匹配逻辑 - [ ] 测试空条件和非空条件的情况 --- #### 阶段二:LoadData 方法重构(2-3小时) **任务清单**: 1. ✅ **修改方法签名** ```vba ' 旧 Public Sub LoadData(wsConfig As Worksheet, wsPlatform As Worksheet) ' 新 Public Sub LoadData(wsPlatform As Worksheet) ``` 2. ✅ **重写加载逻辑** - [ ] 移除第二步(从 [领料配置] 加载) - [ ] 合并第一步和第二步(一次性从 [平台配置清单] 加载所有字段) - [ ] 更新列索引映射: - H列:类别 - I列:上层类别 - J列:类别选用条件 - K列:66代码 3. ✅ **更新类别创建逻辑** - [ ] 创建类别时,设置 `CategorySelectCondition` 属性 - [ ] 创建物料时,设置 `CategorySelectCondition` 和 `Code66` 属性 4. ✅ **更新文档** - [ ] 更新 `clsBOMManager_LoadData流程分析.md` - [ ] 更新方法注释 --- #### 阶段三:完整性检查逻辑重构(2-3小时) **任务清单**: 1. ✅ **新增 GetRequiredCategories 方法** ```vba Private Function GetRequiredCategories(conditions As Object) As collection ' 遍历所有类别,判断是否需要 ' 返回需要的类别列表 End Function ``` 2. ✅ **修改 GetValidMaterialsByModel 方法** - [ ] 在检查完整性前,先调用 `GetRequiredCategories()` - [ ] 只对需要的类别调用 `CheckCategoryCompleteness()` - [ ] 更新方法注释 3. ✅ **测试完整性检查** - [ ] 测试所有类别都需要的情况(向后兼容) - [ ] 测试部分类别不需要的情况(新逻辑) - [ ] 测试边界情况(所有类别都不需要) --- #### 阶段四:测试与验证(2-3小时) **任务清单**: 1. ✅ **单元测试** - [ ] 测试 `LoadData` 加载新表结构 - [ ] 测试 `IsRequiredForModel()` 方法 - [ ] 测试 `GetRequiredCategories()` 方法 - [ ] 测试 `GetValidMaterialsByModel()` 新逻辑 2. ✅ **集成测试** - [ ] 使用真实数据测试完整流程 - [ ] 验证结果与预期一致 3. ✅ **回归测试** - [ ] 运行 `modModelParserTest` 中的所有测试 - [ ] 确保旧功能不受影响 --- #### 阶段五:文档更新(1小时) **任务清单**: 1. ✅ **更新 CLAUDE.md** - [ ] 更新 [平台配置清单] 表结构说明 - [ ] 移除 [领料配置] 相关说明 - [ ] 更新"类别选用条件"业务逻辑说明 2. ✅ **更新参考文档** - [ ] 更新 `clsBOMManager使用说明.md` - [ ] 更新 `clsBOMManager_LoadData流程分析.md` 3. ✅ **添加迁移指南** - [ ] 创建 `数据迁移指南.md` - [ ] 说明如何将旧数据迁移到新结构 --- ### 5.2 风险评估 | 风险项 | 风险等级 | 缓解措施 | |--------|---------|---------| | 数据结构变化导致现有代码报错 | 🔴 高 | 充分的单元测试和回归测试 | | 类别选用条件逻辑理解偏差 | 🟡 中 | 详细的业务场景测试 | | 向后兼容性问题 | 🟡 中 | 保留旧版本的 LoadData 方法(重命名为 LoadDataV1) | | 性能影响 | 🟢 低 | 新逻辑只增加一次类别过滤,影响极小 | --- ### 5.3 时间估算 | 阶段 | 预计时间 | 负责人 | |------|---------|--------| | 阶段一:数据模型扩展 | 1-2 小时 | | | 阶段二:LoadData 重构 | 2-3 小时 | | | 阶段三:完整性检查重构 | 2-3 小时 | | | 阶段四:测试与验证 | 2-3 小时 | | | 阶段五:文档更新 | 1 小时 | | | **总计** | **8-12 小时** | | --- ## 六、数据迁移方案 ### 6.1 从旧表到新表 **旧 [领料配置] 结构**: | A列 | B列 | C列 | D列 | |-----|-----|-----|-----| | 物料代号 | 物料名称 | 类别 | 上层类别 | **新 [平台配置清单] 结构**: | ... | H列 | I列 | J列 | K列 | |-----|-----|-----|-----|-----| | ... | 类别 | 上层类别 | 类别选用条件 | 66代码 | **迁移步骤**: 1. **在 [平台配置清单] 中添加新列**: - H列:类别 - I列:上层类别 - J列:类别选用条件 - K列:66代码 2. **从 [领料配置] 复制数据**: ``` H2 = [领料配置]!A2 ' 物料代号 → 类别(需要匹配) I2 = [领料配置]!C2 ' 类别 J2 = [领料配置]!D2 ' 上层类别 ``` 3. **使用 VLOOKUP 匹配物料**: ```excel H4 = VLOOKUP(C4, [领料配置]!A:D, 3, FALSE) ' 类别 I4 = VLOOKUP(C4, [领料配置]!A:D, 4, FALSE) ' 上层类别 ``` 4. **手动填写类别选用条件和66代码** --- ## 七、测试用例设计 ### 7.1 类别选用条件测试 | 测试场景 | 类别选用条件 | 型号条件 | 预期结果 | |---------|-------------|---------|---------| | 无条件(总是需要) | (空) | 任意 | ✅ 需要 | | 量程匹配 | lcfw=M02 | lcfw=M02 | ✅ 需要 | | 量程不匹配 | lcfw=M02 | lcfw=M16 | ❌ 不需要 | | 复杂条件匹配 | gclj=M20 AND jycz=1 | gclj=M20, jycz=1 | ✅ 需要 | | 复杂条件不匹配 | gclj=M20 AND jycz=1 | gclj=M20, jycz=2 | ❌ 不需要 | | OR 条件匹配 | lcfw=M02 OR lcfw=M16 | lcfw=M16 | ✅ 需要 | ### 7.2 完整性检查测试 | 测试场景 | 需要的类别 | 匹配结果 | 预期 IsComplete | |---------|-----------|---------|-----------------| | 全部匹配 | 表壳, 部件, 接头 | 全部有1个 | ✅ True | | 缺失一个 | 表壳, 部件, 接头 | 部件缺失 | ❌ False | | 部分类别不需要 | 表壳, 部件 | 表壳有, 部件无(但部件不需要) | ✅ True | | 多于一个匹配 | 表壳, 部件 | 部件有2个 | ❌ False | --- ## 八、向后兼容性策略 ### 8.1 保留旧版本方法 ```vba ' 旧版本(保留但不推荐使用) Public Sub LoadDataV1(wsConfig As Worksheet, wsPlatform As Worksheet) ' 保留原有实现 End Sub ' 新版本(推荐使用) Public Sub LoadData(wsPlatform As Worksheet) ' 新实现 End Sub ``` ### 8.2 迁移期支持 在迁移期间,两个版本同时存在: - 新代码使用 `LoadData(wsPlatform)` - 旧代码可以继续使用 `LoadDataV1(wsConfig, wsPlatform)` 迁移完成后,可以移除 `LoadDataV1` 方法。 --- ## 九、检查清单 ### 重构前 - [ ] 备份现有代码 - [ ] 备份 [领料配置] 和 [平台配置清单] 表 - [ ] 确认测试环境可用 ### 重构中 - [ ] 按阶段顺序执行 - [ ] 每个阶段完成后进行测试 - [ ] 及时更新文档 ### 重构后 - [ ] 运行完整的测试套件 - [ ] 验证所有功能正常 - [ ] 更新用户文档 - [ ] 通知团队成员变更内容 --- ## 十、后续优化建议 1. **性能优化** - 缓存类别选用条件的匹配结果 - 避免重复解析型号 2. **功能扩展** - 支持类别优先级(当多个类别都匹配时,优先选择哪个) - 支持类别别名(一个类别多个名称) 3. **用户体验** - 在 Excel 中添加类别选用条件的验证工具 - 提供类别选用条件的构建器(图形化界面) --- ## 附录:关键代码示例 ### A. 修改后的 LoadData 方法(伪代码) ```vba Public Sub LoadData(wsPlatform As Worksheet) Dim i As Long, lastRow As Long Dim mat As clsMaterialItem Dim cat As clsCategory ' 读取数据 lastRow = wsPlatform.Cells(wsPlatform.Rows.Count, "C").End(xlUp).row For i = 4 To lastRow ' 1. 创建物料对象 Set mat = New clsMaterialItem mat.code = Trim(wsPlatform.Cells(i, "C").value) mat.Name = Trim(wsPlatform.Cells(i, "D").value) mat.Quantity = CDbl(wsPlatform.Cells(i, "E").value) mat.Condition = Trim(wsPlatform.Cells(i, "F").value) ' ⭐ 读取类别相关字段 Dim catName As String Dim parentCatName As String Dim catSelectCond As String Dim code66 As String catName = Trim(wsPlatform.Cells(i, "H").value & "") parentCatName = Trim(wsPlatform.Cells(i, "I").value & "") catSelectCond = Trim(wsPlatform.Cells(i, "J").value & "") code66 = Trim(wsPlatform.Cells(i, "K").value & "") ' ⭐ 保存到物料对象 mat.Category = catName mat.ParentCategory = parentCatName mat.CategorySelectCondition = catSelectCond mat.Code66 = code66 ' 保存到字典 If mat.code <> "" Then Set dictAllMaterials(mat.code) = mat End If ' ⭐ 创建或更新类别对象 If catName <> "" Then If Not dictCategories.Exists(catName) Then Set cat = New clsCategory cat.categoryName = catName cat.ParentCategoryName = parentCatName cat.CategorySelectCondition = catSelectCond ' ⭐ 新增 Set dictCategories(catName) = cat End If ' 将物料添加到类别 dictCategories(catName).AddMaterial mat End If Next i ' 建立类别层级关系(逻辑不变) ' ... End Sub ``` ### B. 新增 GetRequiredCategories 方法(伪代码) ```vba Private Function GetRequiredCategories(conditions As Object) As collection Dim result As New collection Dim matcher As New clsConditionMatcher ' 遍历所有类别 Dim key As Variant For Each key In dictCategories.Keys Dim cat As clsCategory Set cat = dictCategories(key) ' 检查该类别是否需要 If cat.IsRequiredForModel(conditions) Then result.Add cat End If Next key Set GetRequiredCategories = result End Function ``` ### C. 新增 clsCategory.IsRequiredForModel 方法(伪代码) ```vba Public Function IsRequiredForModel(conditions As Object) As Boolean If Me.CategorySelectCondition = "" Then ' 选用条件为空,总是需要 IsRequiredForModel = True Else ' 需要用 conditions 去匹配 CategorySelectCondition Dim matcher As New clsConditionMatcher IsRequiredForModel = matcher.IsMatch(Me.CategorySelectCondition, conditions) End If End Function ``` --- **文档版本**:v1.0 **创建日期**:2026-01-29 **最后更新**:2026-01-29