Files
AutoBOM/reference_docs/重构计划-整合领料配置到平台配置清单.md
Misaka_Company a9b3188d23 refactor: integrate [领料配置] into [平台配置清单] and add category selection conditions
Major changes:
- Remove dependency on separate [领料配置] sheet
- Load all data from [平台配置清单] in a single pass
- Add "类别选用条件" (CategorySelectCondition) field to support dynamic category filtering
- Add "66代码" (Code66) field for 66-system integration
- Refactor completeness check logic to only verify required categories

Data model changes:
- clsMaterialItem: Add CategorySelectCondition and Code66 properties
- clsCategory: Add CategorySelectCondition property and IsRequiredForModel() method
- clsBOMManager: Refactor LoadData() to use single data source
- clsBOMManager: Add GetRequiredCategories() method
- clsBOMManager: Update GetValidMaterialsByModel() to use category selection conditions

New workflow:
- LoadData() now takes only wsPlatform parameter (removed wsConfig)
- Categories are filtered by "类别选用条件" before completeness check
- Categories with empty selection condition are always required
- Categories with non-empty condition are checked against model specifications

Documentation:
- Update CLAUDE.md with new sheet structure
- Add comprehensive refactoring plan document
- Add v2.0 LoadData flow analysis with Mermaid diagrams
- Add platform configuration sheet reference

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-29 10:25:28 +08:00

651 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 重构计划:整合 [领料配置] 到 [平台配置清单]
## 一、背景概述
### 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