docs: expand AutoBOM architecture and implementation details
Refine project overview to include specific business context (Blaidy Company) and the main workbook file. Restructure the architecture section into a layered object-oriented design (Data, Processing, Application layers) and define the responsibilities of core VBA classes. Add new technical documentation sections covering: - Model number format parsing structure - Condition expression language syntax - Category hierarchy logic and picking strategies - Material matching pipeline flow Include VBA code examples for key methods such as CollectAllMaterials and GetMaterialsByCategoryAndModel to illustrate recursive traversal and material retrieval logic. Clarify the structure of key Excel configuration sheets.
This commit is contained in:
165
CLAUDE.md
165
CLAUDE.md
@@ -4,84 +4,135 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
AutoBOM is an Excel VBA-based Bill of Materials (BOM) Management System for manufacturing environments. It manages material hierarchies and procurement logic, supporting both assembled components and individual parts sourcing strategies.
|
**AutoBOM** is an automated Bill of Materials (BOM) management system for industrial pressure gauge products at 布莱迪公司 (Blaidy Company). The system parses complex product model numbers, extracts material requirements based on specifications, and generates picking lists for manufacturing.
|
||||||
|
|
||||||
|
The main Excel file is `YTHN-100.A0.532-BOM-1.2版 Claude.xlsm` (macro-enabled workbook), which contains both the VBA code and the business data.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
### Core Classes (VBA/ClassModules/)
|
### Core Components (Layered Object-Oriented Design)
|
||||||
|
|
||||||
- **clsBOMManager** - Central controller managing the entire BOM data structure
|
**Data Layer** (Class Modules)
|
||||||
- Loads data from two Excel worksheets: "领料配置" (Configuration) and "平台配置清单" (Platform Configuration)
|
- `clsMaterialItem` - Individual material entity
|
||||||
- Builds hierarchical category trees with parent-child relationships
|
- `clsCategory` - Hierarchical category container with parent-child relationships
|
||||||
- Provides material querying interfaces
|
- `clsBOMManager` - Central controller managing the entire BOM data structure
|
||||||
- Key methods: `LoadData()`, `GetMaterialsForPicking()`, `GetCategory()`
|
|
||||||
|
|
||||||
- **clsCategory** - Represents material categories with hierarchical relationships
|
**Processing Layer** (Class Modules)
|
||||||
- Contains collections of materials and sub-categories
|
- `clsModelParser` - Parses complex product model strings into structured components
|
||||||
- Tracks parent category for tree navigation
|
- `clsConditionExtractor` - Extracts selection conditions from parsed models
|
||||||
- Properties: `categoryName`, `ParentCategoryName`, `Materials`, `SubCategories`, `IsLeafCategory`
|
- `clsConditionMatcher` - Evaluates logical expressions for material matching
|
||||||
|
|
||||||
- **clsMaterialItem** - Represents individual material items
|
**Application Layer** (Standard Modules)
|
||||||
- Properties: `code` (物料代号), `Name` (物料名称), `Quantity`, `Condition` (选择条件), `Category`, `ParentCategory`
|
- `modBOMProcessor` - BOM operations and usage examples
|
||||||
|
- `modModelParserTest` - Comprehensive test suite (6 test functions)
|
||||||
|
- `modModelParserExamples` - Real-world usage examples
|
||||||
|
|
||||||
### Data Structure Design
|
### Model Number Format
|
||||||
|
|
||||||
The system uses a dual-layer approach:
|
Product models follow this structure:
|
||||||
1. **dictAllMaterials** - Complete material database loaded from platform configuration sheet
|
```
|
||||||
2. **dictCategories** - Hierarchical category structure with materials filtered by configuration sheet
|
[Model]-[Diameter].[Install].[Shell].[Connection].[Range].[Char]|[Dial]|[Accessory]|[Flange]
|
||||||
|
```
|
||||||
|
|
||||||
Only materials appearing in the "领料配置" worksheet are marked for procurement. Materials in the platform database but not in configuration are ignored.
|
Example: `YTHN-100.A0.532.M203.M16.Y3|BP-095.2312.M16.PA3`
|
||||||
|
|
||||||
### Business Logic
|
The parser uses recursive descent parsing with structure validation.
|
||||||
|
|
||||||
**Dual-Sourcing Strategy** (via `GetMaterialsForPicking(categoryName, useParent)`):
|
### Condition Expression Language
|
||||||
|
|
||||||
- **Parent Mode** (`useParent=True`): Retrieves parent category materials (assembled components)
|
Materials are selected using logical expressions with variables:
|
||||||
- Default procurement method
|
- `gclj` (过程连接 - process connection)
|
||||||
- Example: "低压接头部件" (Low-pressure connector assembly)
|
- `jycz` (接液材质 - liquid contact material)
|
||||||
|
- `lcfw` (量程范围 - range)
|
||||||
|
|
||||||
- **Child Mode** (`useParent=False`): Retrieves child category materials (individual parts)
|
Supported operators: `AND`, `OR`, `!=`, parentheses
|
||||||
- Used when parent materials are insufficient
|
|
||||||
- Recursively expands all sub-categories
|
|
||||||
- Example: "径向低压接头" + "弹簧管" + "螺旋管" (individual components)
|
|
||||||
|
|
||||||
## Running the Code
|
Example: `lcfw=M16 AND gclj!=M20 OR (lcfw=M02 AND gclj=Z12)`
|
||||||
|
|
||||||
1. Open `YTHN-100.A0.532-BOM-1.2版 Claude.xlsm` in Microsoft Excel
|
### Category Hierarchy Logic
|
||||||
2. Enable macros when prompted
|
|
||||||
3. Press Alt+F8 to open the Macro dialog
|
|
||||||
4. Run procedures from modBOMProcessor.bas:
|
|
||||||
- `TestBOMStructure` - Test data loading and verify structure
|
|
||||||
- `GeneratePickingList` - Generate procurement lists to new worksheet
|
|
||||||
- `GetCategoryMaterials` - Demo material retrieval logic
|
|
||||||
- `QueryMaterialInfo` - Query specific category information
|
|
||||||
|
|
||||||
## Data Worksheet Format
|
The system supports two picking strategies:
|
||||||
|
1. **Parent Category Mode** (default): Pick assembled components
|
||||||
|
2. **Child Category Mode** (fallback): Pick individual parts for assembly
|
||||||
|
|
||||||
**领料配置** (Configuration):
|
Recursive tree traversal is used for material collection through the category hierarchy.
|
||||||
- Column A: 物料代号 (Material Code)
|
|
||||||
- Column C: 类别 (Category)
|
|
||||||
- Column D: 上层类别 (Parent Category)
|
|
||||||
- Row 1: Header, data starts from row 2
|
|
||||||
|
|
||||||
**平台配置清单** (Platform Configuration):
|
### Material Matching Pipeline
|
||||||
- Column C: 代号 (Code)
|
|
||||||
- Column D: 名称 (Name)
|
|
||||||
- Column E: 数量 (Quantity)
|
|
||||||
- Column F: 选择条件 (Selection Condition)
|
|
||||||
- Rows 1-3: Headers, data starts from row 4
|
|
||||||
|
|
||||||
## VBA Metadata
|
```
|
||||||
|
Model String → Parser → Extractor → Conditions Dictionary → Matcher → Filtered Materials
|
||||||
|
```
|
||||||
|
|
||||||
The VBA module structure is tracked in `VBA/vba_metadata.json`. This file is automatically maintained and should not be manually edited.
|
## Data Sheets Structure
|
||||||
|
|
||||||
## Code Style
|
The Excel workbook contains two key sheets:
|
||||||
|
|
||||||
- All comments are in Chinese, explaining business logic and data structures
|
**领料配置** (Picking Configuration)
|
||||||
- Extensive inline documentation for complex logic
|
- Defines category hierarchy
|
||||||
- Dictionary objects used for O(1) lookups by category name and material code
|
- Specifies which materials require picking
|
||||||
- Collection objects used for ordered iteration of materials and categories
|
- Columns: 物料代号, 类别名称, 上层类别名称
|
||||||
|
|
||||||
## Version Control
|
**平台配置清单** (Platform Configuration)
|
||||||
|
- Complete material database
|
||||||
|
- Rows 1-3: Headers
|
||||||
|
- Row 4+: Data
|
||||||
|
|
||||||
The `.gitignore` excludes `.xlsm` files from version control. Only VBA source code and metadata files are tracked in Git.
|
## Testing
|
||||||
|
|
||||||
|
Run tests from the VBA editor or Excel macros:
|
||||||
|
|
||||||
|
- **All tests**: `RunAllTests()` in `modModelParserTest`
|
||||||
|
- **Individual tests**: Test1-Test6 functions in `modModelParserTest`
|
||||||
|
- Test1: Model parser basic functionality
|
||||||
|
- Test2: Condition extractor
|
||||||
|
- Test3: Condition matcher (14 test cases)
|
||||||
|
- Test4: Full workflow test
|
||||||
|
- Test5: All categories matching
|
||||||
|
- Test6: Extraction rules display
|
||||||
|
|
||||||
|
## Development Workflow
|
||||||
|
|
||||||
|
1. Edit VBA code in Excel VBA Editor (Alt+F11)
|
||||||
|
2. Export modules to `VBA/` directory
|
||||||
|
3. Update `VBA/vba_metadata.json` when adding/removing modules
|
||||||
|
4. Commit changes to git
|
||||||
|
|
||||||
|
**Note**: The main Excel workbook (*.xlsm) is excluded from git by .gitignore.
|
||||||
|
|
||||||
|
## Code Conventions
|
||||||
|
|
||||||
|
**Naming**
|
||||||
|
- Classes: `cls` prefix (e.g., `clsBOMManager`)
|
||||||
|
- Modules: `mod` prefix (e.g., `modBOMProcessor`)
|
||||||
|
- Public properties: PascalCase
|
||||||
|
- Local variables: camelCase
|
||||||
|
|
||||||
|
**Comments**
|
||||||
|
- Section headers: `' ========================================`
|
||||||
|
- Chinese comments for business logic (domain-specific)
|
||||||
|
- English comments for technical implementation
|
||||||
|
- Detailed parameter/return value documentation
|
||||||
|
|
||||||
|
**Error Handling**
|
||||||
|
- `On Error GoTo ErrorHandler` pattern
|
||||||
|
- Conservative: return `Nothing` or `False` on error
|
||||||
|
|
||||||
|
## Key Business Logic
|
||||||
|
|
||||||
|
- Materials have "selection conditions" expressed as logical formulas
|
||||||
|
- Not all materials in platform config require picking (filtered by "领料配置" sheet)
|
||||||
|
- Supports "部件" (component) vs "零件" (part) picking strategies
|
||||||
|
- Condition extraction is data-driven (new variables can be added)
|
||||||
|
- Category tree can have arbitrary depth
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
- `布莱迪公司压力表产品选型大表.md` - Complete product model numbering system (716 lines, Chinese)
|
||||||
|
- `VBA/clsBOMManager使用说明.md` - API documentation and usage examples for clsBOMManager (546 lines, Chinese)
|
||||||
|
|
||||||
|
## Module Registry
|
||||||
|
|
||||||
|
`VBA/vba_metadata.json` maps VBA module names to their file locations in the repository. Update this file when:
|
||||||
|
- Adding new class modules or standard modules
|
||||||
|
- Renaming existing modules
|
||||||
|
- Reorganizing the directory structure
|
||||||
|
|||||||
464
Example1_GeneratePickingListByModel_时序图.md
Normal file
464
Example1_GeneratePickingListByModel_时序图.md
Normal file
@@ -0,0 +1,464 @@
|
|||||||
|
# Example1_GeneratePickingListByModel 过程时序图
|
||||||
|
|
||||||
|
## 过程说明
|
||||||
|
|
||||||
|
本时序图展示 `Example1_GeneratePickingListByModel` 过程的详细执行流程,该过程根据产品型号生成完整的领料清单。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 简略版时序图(概览)
|
||||||
|
|
||||||
|
此版本展示主要流程和关键交互,适合快速了解整体架构。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
participant Main as Example1_Sub
|
||||||
|
participant BOMMgr as clsBOMManager
|
||||||
|
participant Excel as Excel工作表
|
||||||
|
participant PickList as 型号领料清单表
|
||||||
|
participant Parser as 型号解析组件
|
||||||
|
participant DataStore as 数据集合
|
||||||
|
|
||||||
|
%% ==================== 初始化 ====================
|
||||||
|
Note over Main: 1. 初始化与加载数据
|
||||||
|
Main->>BOMMgr: 创建并初始化 BOMManager
|
||||||
|
Main->>Excel: 获取配置工作表<br/>(领料配置、平台配置清单)
|
||||||
|
Main->>BOMMgr: LoadData(wsConfig, wsPlatform)
|
||||||
|
activate BOMMgr
|
||||||
|
BOMMgr->>Excel: 读取类别层级和物料数据
|
||||||
|
BOMMgr->>DataStore: 构建内存数据结构<br/>(dictCategories, dictAllMaterials)
|
||||||
|
deactivate BOMMgr
|
||||||
|
|
||||||
|
%% ==================== 创建输出表 ====================
|
||||||
|
Note over Main: 2. 创建输出工作表
|
||||||
|
Main->>Main: modelStr = "YTHN-100.A0.532.M203.M16.Y3|..."
|
||||||
|
Main->>Excel: 删除旧工作表(如存在)
|
||||||
|
Main->>Excel: 创建新工作表 "型号领料清单"
|
||||||
|
Excel-->>Main: PickList 工作表对象
|
||||||
|
|
||||||
|
%% ==================== 解析型号 ====================
|
||||||
|
Note over Main: 3. 解析型号并提取条件
|
||||||
|
Main->>PickList: 写入产品型号标题
|
||||||
|
Main->>Parser: ParseModelAndExtractConditions(modelStr)
|
||||||
|
activate Parser
|
||||||
|
Parser->>Parser: 解析表头型号(YTHN-100...)<br/>解析表盘型号(BP-095...)
|
||||||
|
Parser->>DataStore: 提取选择条件<br/>(gclj, jycz, lcfw)
|
||||||
|
Parser-->>Main: Conditions Dictionary
|
||||||
|
deactivate Parser
|
||||||
|
|
||||||
|
Main->>PickList: 写入提取条件到工作表
|
||||||
|
|
||||||
|
%% ==================== 写入表头 ====================
|
||||||
|
Note over Main: 4. 写入数据表头
|
||||||
|
Main->>PickList: 写入列标题<br/>(类别, 代号, 名称, 数量, 选择条件, 匹配状态)
|
||||||
|
|
||||||
|
%% ==================== 处理物料 ====================
|
||||||
|
Note over Main: 5. 遍历类别并匹配物料
|
||||||
|
Main->>BOMMgr: GetRootCategories()
|
||||||
|
BOMMgr-->>Main: 根类别集合
|
||||||
|
|
||||||
|
loop 每个根类别
|
||||||
|
Main->>BOMMgr: GetMaterialsByModel(modelStr, categoryName)
|
||||||
|
activate BOMMgr
|
||||||
|
BOMMgr->>DataStore: 获取类别对象
|
||||||
|
BOMMgr->>Parser: 匹配物料选择条件
|
||||||
|
Parser-->>BOMMgr: 匹配结果集合
|
||||||
|
BOMMgr-->>Main: Materials Collection
|
||||||
|
deactivate BOMMgr
|
||||||
|
|
||||||
|
Note over Main: 写入该类别的所有物料
|
||||||
|
loop 每个匹配的物料
|
||||||
|
Main->>PickList: 写入物料详细信息<br/>(代号, 名称, 数量, 条件)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ==================== 完成输出 ====================
|
||||||
|
Note over Main: 6. 格式化并完成
|
||||||
|
Main->>PickList: AutoFit 格式化
|
||||||
|
Main->>Main: 显示完成消息框
|
||||||
|
```
|
||||||
|
|
||||||
|
**简略版特点**:
|
||||||
|
- **6个参与者**(相比详细版的11个)
|
||||||
|
- **6个主要阶段**(相比详细版的14个步骤)
|
||||||
|
- **合并了内部细节**:解析器、提取器、匹配器的内部操作合并为一个组件
|
||||||
|
- **简化循环展示**:不展示条件判断、分支逻辑等细节
|
||||||
|
- **适合**:快速理解整体流程和架构
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 详细版时序图(完整流程)
|
||||||
|
|
||||||
|
此版本展示每个方法的调用细节、内部逻辑和数据流向,适合深入理解实现。
|
||||||
|
|
||||||
|
## 时序图
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
participant Main as Example1_Sub
|
||||||
|
participant BOMMgr as clsBOMManager
|
||||||
|
participant Workbooks as Excel.Worksheets
|
||||||
|
participant ConfigWS as 领料配置表
|
||||||
|
participant PlatformWS as 平台配置清单表
|
||||||
|
participant Parser as clsModelParser
|
||||||
|
participant Extractor as clsConditionExtractor
|
||||||
|
participant Matcher as clsConditionMatcher
|
||||||
|
participant PickListWS as 型号领料清单表
|
||||||
|
participant RootCats as 根类别Collection
|
||||||
|
participant Cat as clsCategory
|
||||||
|
participant Materials as 物料Collection
|
||||||
|
participant Conditions as 条件Dictionary
|
||||||
|
|
||||||
|
%% ==================== 初始化阶段 ====================
|
||||||
|
Note over Main: 1. 初始化 BOM 管理器
|
||||||
|
Main->>BOMMgr: New clsBOMManager
|
||||||
|
activate BOMMgr
|
||||||
|
BOMMgr->>BOMMgr: 初始化 dictCategories<br/>初始化 dictAllMaterials<br/>初始化 rootCategories
|
||||||
|
deactivate BOMMgr
|
||||||
|
|
||||||
|
%% ==================== 加载配置阶段 ====================
|
||||||
|
Note over Main: 2. 获取工作表对象
|
||||||
|
Main->>Workbooks: Worksheets("领料配置")
|
||||||
|
Workbooks-->>Main: ConfigWS
|
||||||
|
Main->>Workbooks: Worksheets("平台配置清单")
|
||||||
|
Workbooks-->>Main: PlatformWS
|
||||||
|
|
||||||
|
Note over Main: 3. 加载 BOM 数据
|
||||||
|
Main->>BOMMgr: LoadData(ConfigWS, PlatformWS)
|
||||||
|
activate BOMMgr
|
||||||
|
|
||||||
|
BOMMgr->>ConfigWS: 读取类别配置数据<br/>(第2行起:物料代号、类别名称、上层类别)
|
||||||
|
ConfigWS-->>BOMMgr: 类别层级数据
|
||||||
|
|
||||||
|
BOMMgr->>BOMMgr: 构建类别树结构<br/>创建 clsCategory 对象<br/>建立父子关系
|
||||||
|
|
||||||
|
BOMMgr->>PlatformWS: 读取物料清单数据<br/>(第4行起)
|
||||||
|
PlatformWS-->>BOMMgr: 完整物料数据
|
||||||
|
|
||||||
|
BOMMgr->>BOMMgr: 创建 clsMaterialItem 对象<br/>填充 dictAllMaterials 字典
|
||||||
|
BOMMgr->>BOMMgr: 将物料分配到对应类别<br/>建立 rootCategories 集合
|
||||||
|
deactivate BOMMgr
|
||||||
|
|
||||||
|
%% ==================== 准备型号数据 ====================
|
||||||
|
Note over Main: 4. 定义产品型号
|
||||||
|
Main->>Main: modelStr = "YTHN-100.A0.532.M203.M16.Y3|BP-095.2312.M16.PA3"
|
||||||
|
|
||||||
|
%% ==================== 创建输出工作表 ====================
|
||||||
|
Note over Main: 5. 删除旧的领料清单表
|
||||||
|
Main->>Workbooks: Worksheets("型号领料清单")
|
||||||
|
alt 工作表存在
|
||||||
|
Workbooks-->>Main: 工作表对象
|
||||||
|
Main->>PickListWS: Delete
|
||||||
|
else 工作表不存在
|
||||||
|
Workbooks-->>Main: 错误
|
||||||
|
Main->>Main: On Error Resume Next (忽略错误)
|
||||||
|
end
|
||||||
|
|
||||||
|
Note over Main: 6. 创建新工作表
|
||||||
|
Main->>Workbooks: Worksheets.Add()
|
||||||
|
Workbooks-->>Main: PickListWS
|
||||||
|
Main->>PickListWS: Name = "型号领料清单"
|
||||||
|
|
||||||
|
%% ==================== 写入标题行 ====================
|
||||||
|
Note over Main: 7. 写入产品型号
|
||||||
|
Main->>Main: row = 1
|
||||||
|
Main->>PickListWS: Cells(row, 1).value = "产品型号"
|
||||||
|
Main->>PickListWS: Cells(row, 2).value = modelStr
|
||||||
|
Main->>Main: row = row + 1
|
||||||
|
|
||||||
|
%% ==================== 解析型号并提取条件 ====================
|
||||||
|
Note over Main: 8. 解析型号提取条件
|
||||||
|
Main->>BOMMgr: ParseModelAndExtractConditions(modelStr)
|
||||||
|
activate BOMMgr
|
||||||
|
|
||||||
|
BOMMgr->>Parser: New clsModelParser
|
||||||
|
activate Parser
|
||||||
|
BOMMgr->>Parser: ParseModel(modelStr)
|
||||||
|
|
||||||
|
Note over Parser: 解析表头型号
|
||||||
|
Parser->>Parser: 提取型号前缀: "YTHN"
|
||||||
|
Parser->>Parser: 提取公称外径: "100"
|
||||||
|
Parser->>Parser: 提取安装形式: "A0"
|
||||||
|
Parser->>Parser: 提取壳体形式: "532"
|
||||||
|
Parser->>Parser: 提取过程连接: "M203"
|
||||||
|
Parser->>Parser: 提取量程范围: "M16"
|
||||||
|
Parser->>Parser: 提取仪表特性: "Y3"
|
||||||
|
|
||||||
|
Note over Parser: 解析表盘型号
|
||||||
|
Parser->>Parser: 提取表盘型号: "BP-095"
|
||||||
|
Parser->>Parser: 提取表盘规格: "2312"
|
||||||
|
Parser->>Parser: 提取表盘连接: "M16"
|
||||||
|
Parser->>Parser: 提取表盘特性: "PA3"
|
||||||
|
|
||||||
|
Parser-->>BOMMgr: True (解析成功)
|
||||||
|
deactivate Parser
|
||||||
|
|
||||||
|
BOMMgr->>Extractor: New clsConditionExtractor
|
||||||
|
activate Extractor
|
||||||
|
BOMMgr->>Extractor: ExtractConditions(Parser)
|
||||||
|
|
||||||
|
Note over Extractor: 应用提取规则
|
||||||
|
Extractor->>Extractor: 规则1: gclj = 过程连接 = "M203"
|
||||||
|
Extractor->>Extractor: 规则2: jycz = 接液材质 = "M16"
|
||||||
|
Extractor->>Extractor: 规则3: lcfw = 量程范围 = "M16"
|
||||||
|
Extractor->>Extractor: 创建条件字典
|
||||||
|
|
||||||
|
Extractor-->>BOMMgr: Conditions Dictionary
|
||||||
|
deactivate Extractor
|
||||||
|
|
||||||
|
BOMMgr-->>Main: Conditions Dictionary
|
||||||
|
deactivate BOMMgr
|
||||||
|
|
||||||
|
%% ==================== 写入提取条件 ====================
|
||||||
|
Note over Main: 9. 写入提取条件行
|
||||||
|
Main->>PickListWS: Cells(row, 1).value = "提取条件"
|
||||||
|
|
||||||
|
Note over Main: 遍历条件字典拼接字符串
|
||||||
|
Main->>Conditions: 遍历 Keys
|
||||||
|
loop 每个条件键值对
|
||||||
|
Conditions-->>Main: key, value
|
||||||
|
Main->>Main: 拼接条件字符串到 condStr
|
||||||
|
end
|
||||||
|
|
||||||
|
Main->>PickListWS: Cells(row, 2).value = condStr
|
||||||
|
Main->>Main: row = row + 2
|
||||||
|
|
||||||
|
%% ==================== 写入表头 ====================
|
||||||
|
Note over Main: 10. 写入数据表头
|
||||||
|
Main->>PickListWS: Cells(row, 1).value = "类别"
|
||||||
|
Main->>PickListWS: Cells(row, 2).value = "代号"
|
||||||
|
Main->>PickListWS: Cells(row, 3).value = "名称"
|
||||||
|
Main->>PickListWS: Cells(row, 4).value = "数量"
|
||||||
|
Main->>PickListWS: Cells(row, 5).value = "选择条件"
|
||||||
|
Main->>PickListWS: Cells(row, 6).value = "匹配状态"
|
||||||
|
Main->>PickListWS: 设置表头字体为粗体 (Range A-F)
|
||||||
|
Main->>Main: row = row + 1
|
||||||
|
|
||||||
|
%% ==================== 获取根类别 ====================
|
||||||
|
Note over Main: 11. 获取根类别集合
|
||||||
|
Main->>BOMMgr: GetRootCategories()
|
||||||
|
BOMMgr-->>Main: RootCats Collection
|
||||||
|
|
||||||
|
%% ==================== 外层循环:遍历根类别 ====================
|
||||||
|
Note over Main: 12. 遍历每个根类别
|
||||||
|
loop 每个根类别 i = 1 To RootCats.Count
|
||||||
|
|
||||||
|
Main->>RootCats: Item(i)
|
||||||
|
RootCats-->>Main: Cat
|
||||||
|
|
||||||
|
Note over Main: 获取类别名称
|
||||||
|
Main->>Cat: .categoryName
|
||||||
|
Cat-->>Main: categoryName
|
||||||
|
|
||||||
|
Note over Main: 获取该类别符合条件的物料
|
||||||
|
Main->>BOMMgr: GetMaterialsByModel(modelStr, categoryName)
|
||||||
|
activate BOMMgr
|
||||||
|
|
||||||
|
BOMMgr->>Matcher: New clsConditionMatcher
|
||||||
|
activate Matcher
|
||||||
|
|
||||||
|
Note over BOMMgr: 从 dictCategories 获取类别
|
||||||
|
BOMMgr->>BOMMgr: dictCategories(categoryName)
|
||||||
|
BOMMgr-->>BOMMgr: Category 对象
|
||||||
|
|
||||||
|
Note over BOMMgr: 遍历类别下的所有物料
|
||||||
|
BOMMgr->>Cat: .materials (Collection)
|
||||||
|
|
||||||
|
loop 每个物料
|
||||||
|
Cat-->>BOMMgr: MaterialItem
|
||||||
|
|
||||||
|
Note over BOMMgr: 检查物料选择条件
|
||||||
|
BOMMgr->>MaterialItem: .Condition
|
||||||
|
|
||||||
|
alt 物料有选择条件
|
||||||
|
MaterialItem-->>BOMMgr: conditionStr
|
||||||
|
|
||||||
|
Note over BOMMgr,Matcher: 匹配条件
|
||||||
|
BOMMgr->>Matcher: Match(conditionStr, Conditions)
|
||||||
|
|
||||||
|
Matcher->>Matcher: 解析条件表达式<br/>(AND, OR, !=, 括号)
|
||||||
|
Matcher->>Conditions: 获取变量值
|
||||||
|
Conditions-->>Matcher: 变量值
|
||||||
|
|
||||||
|
Matcher->>Matcher: 评估逻辑表达式
|
||||||
|
Matcher-->>BOMMgr: True/False (匹配结果)
|
||||||
|
|
||||||
|
alt 匹配成功
|
||||||
|
BOMMgr->>BOMMgr: 添加到结果集合
|
||||||
|
end
|
||||||
|
else 物料无条件
|
||||||
|
MaterialItem-->>BOMMgr: ""
|
||||||
|
BOMMgr->>BOMMgr: 直接添加到结果集合
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
BOMMgr-->>Main: Materials Collection
|
||||||
|
deactivate Matcher
|
||||||
|
deactivate BOMMgr
|
||||||
|
|
||||||
|
%% ==================== 内层循环:遍历物料写入 ====================
|
||||||
|
Note over Main: 写入该类别的所有物料
|
||||||
|
loop 每个物料 j = 1 To Materials.Count
|
||||||
|
|
||||||
|
Main->>Materials: Item(j)
|
||||||
|
Materials-->>Main: mat (clsMaterialItem)
|
||||||
|
|
||||||
|
Note over Main: 写入物料详细信息
|
||||||
|
Main->>PickListWS: Cells(row, 1).value = categoryName
|
||||||
|
Main->>PickListWS: Cells(row, 2).value = mat.code
|
||||||
|
Main->>PickListWS: Cells(row, 3).value = mat.Name
|
||||||
|
Main->>PickListWS: Cells(row, 4).value = mat.Quantity
|
||||||
|
|
||||||
|
Main->>mat: .Condition
|
||||||
|
mat-->>Main: condition
|
||||||
|
|
||||||
|
alt condition = ""
|
||||||
|
Main->>PickListWS: Cells(row, 5).value = "(无条件)"
|
||||||
|
else condition <> ""
|
||||||
|
Main->>PickListWS: Cells(row, 5).value = condition
|
||||||
|
end
|
||||||
|
|
||||||
|
Main->>PickListWS: Cells(row, 6).value = "✓"
|
||||||
|
Main->>Main: row = row + 1
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ==================== 格式化输出 ====================
|
||||||
|
Note over Main: 13. 格式化工作表
|
||||||
|
Main->>PickListWS: Columns("A:F").AutoFit
|
||||||
|
|
||||||
|
%% ==================== 显示完成消息 ====================
|
||||||
|
Note over Main: 14. 显示完成消息框
|
||||||
|
Main->>Main: MsgBox("领料清单生成完成!\n请查看工作表: 型号领料清单")
|
||||||
|
|
||||||
|
Note over Main: 过程结束
|
||||||
|
```
|
||||||
|
|
||||||
|
## 流程阶段说明
|
||||||
|
|
||||||
|
### 阶段 1: 初始化与数据加载 (步骤 1-3)
|
||||||
|
- 创建 BOM 管理器实例
|
||||||
|
- 从 Excel 获取配置工作表
|
||||||
|
- 加载类别层级和物料数据,构建内存数据结构
|
||||||
|
|
||||||
|
### 阶段 2: 工作表准备 (步骤 4-7)
|
||||||
|
- 定义产品型号字符串
|
||||||
|
- 删除旧的输出工作表(带错误处理)
|
||||||
|
- 创建新的"型号领料清单"工作表
|
||||||
|
- 写入产品型号标题
|
||||||
|
|
||||||
|
### 阶段 3: 型号解析与条件提取 (步骤 8-9)
|
||||||
|
- 使用 ModelParser 解析复杂型号字符串
|
||||||
|
- 表头型号:YTHN-100.A0.532.M203.M16.Y3
|
||||||
|
- 表盘型号:BP-095.2312.M16.PA3
|
||||||
|
- 使用 ConditionExtractor 提取物料选择条件
|
||||||
|
- 将条件字典写入输出表
|
||||||
|
|
||||||
|
### 阶段 4: 数据表头 (步骤 10-11)
|
||||||
|
- 写入数据列标题:类别、代号、名称、数量、选择条件、匹配状态
|
||||||
|
- 获取根类别集合
|
||||||
|
|
||||||
|
### 阶段 5: 物料匹配与写入 (步骤 12)
|
||||||
|
- **外层循环**:遍历每个根类别
|
||||||
|
- **物料匹配**:对每个类别调用 GetMaterialsByModel
|
||||||
|
- 遍历类别下所有物料
|
||||||
|
- 使用 ConditionMatcher 评估每个物料的选择条件
|
||||||
|
- 筛选符合条件的物料
|
||||||
|
- **内层循环**:遍历匹配的物料集合
|
||||||
|
- 写入物料的详细信息(代号、名称、数量等)
|
||||||
|
- 显示选择条件和匹配状态
|
||||||
|
|
||||||
|
### 阶段 6: 格式化与完成 (步骤 13-14)
|
||||||
|
- 自动调整列宽
|
||||||
|
- 显示完成消息框
|
||||||
|
|
||||||
|
## 关键数据结构
|
||||||
|
|
||||||
|
### 输入数据
|
||||||
|
- **产品型号**: "YTHN-100.A0.532.M203.M16.Y3|BP-095.2312.M16.PA3"
|
||||||
|
- **配置工作表**: "领料配置"、"平台配置清单"
|
||||||
|
|
||||||
|
### 中间数据
|
||||||
|
- **Conditions Dictionary**: {gclj: "M203", jycz: "M16", lcfw: "M16"}
|
||||||
|
- **RootCategories Collection**: 所有顶层类别
|
||||||
|
- **Materials Collection**: 每个类别匹配的物料
|
||||||
|
|
||||||
|
### 输出数据
|
||||||
|
- **型号领料清单表**: 包含产品型号、提取条件、物料清单
|
||||||
|
|
||||||
|
## 性能考虑
|
||||||
|
|
||||||
|
- 使用 Dictionary 和 Collection 提高查找效率
|
||||||
|
- 嵌套循环结构:根类别 × 物料
|
||||||
|
- 大量 Excel 单元格写入操作(可考虑批量写入优化)
|
||||||
|
|
||||||
|
## 扩展建议
|
||||||
|
|
||||||
|
1. **批量写入优化**: 将数据先存入数组,一次性写入工作表
|
||||||
|
2. **进度显示**: 添加处理进度条
|
||||||
|
3. **错误处理**: 增强型号解析失败、数据缺失等异常处理
|
||||||
|
4. **参数化**: 将型号作为参数传入,增加灵活性
|
||||||
|
5. **日志记录**: 记录处理过程和匹配统计信息
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 两个版本的对比
|
||||||
|
|
||||||
|
### 复杂度对比
|
||||||
|
|
||||||
|
| 特性 | 简略版 | 详细版 |
|
||||||
|
|------|--------|--------|
|
||||||
|
| **参与者数量** | 6个 | 11个 |
|
||||||
|
| **主要阶段** | 6个 | 14个步骤 |
|
||||||
|
| **交互步骤** | 约35步 | 约80步 |
|
||||||
|
| **循环展开** | 简化展示 | 完整展示内部逻辑 |
|
||||||
|
| **条件分支** | 隐藏 | 详细展示 (alt/opt/loop) |
|
||||||
|
| **内部方法调用** | 合并展示 | 逐个展开 |
|
||||||
|
|
||||||
|
### 适用场景
|
||||||
|
|
||||||
|
#### 简略版适用于:
|
||||||
|
- 📌 **初次了解**:快速掌握整体流程和架构
|
||||||
|
- 📌 **高层汇报**:向非技术人员展示系统工作原理
|
||||||
|
- 📌 **文档概览**:作为技术文档的目录或概述部分
|
||||||
|
- 📌 **快速参考**:复习主要步骤和组件关系
|
||||||
|
|
||||||
|
#### 详细版适用于:
|
||||||
|
- 🔍 **代码调试**:理解具体实现细节和数据流向
|
||||||
|
- 🔍 **代码审查**:检查逻辑错误和性能瓶颈
|
||||||
|
- 🔍 **新人培训**:深入讲解系统实现机制
|
||||||
|
- 🔍 **维护文档**:作为详细技术文档保存
|
||||||
|
|
||||||
|
### 组件对应关系
|
||||||
|
|
||||||
|
| 简略版组件 | 详细版组件 |
|
||||||
|
|------------|------------|
|
||||||
|
| Excel工作表 | Workbooks + ConfigWS + PlatformWS + PickListWS |
|
||||||
|
| 型号解析组件 | Parser + Extractor + Matcher |
|
||||||
|
| 数据集合 | RootCats + Cat + Materials + Conditions |
|
||||||
|
|
||||||
|
### 阶段对应关系
|
||||||
|
|
||||||
|
| 简略版阶段 | 详细版步骤 |
|
||||||
|
|------------|------------|
|
||||||
|
| 1. 初始化与加载数据 | 1-3: 初始化、获取工作表、加载数据 |
|
||||||
|
| 2. 创建输出工作表 | 4-7: 定义型号、删除旧表、创建新表、写入标题 |
|
||||||
|
| 3. 解析型号并提取条件 | 8-9: 解析型号、提取条件、写入条件行 |
|
||||||
|
| 4. 写入数据表头 | 10-11: 写入列标题、获取根类别 |
|
||||||
|
| 5. 遍历类别并匹配物料 | 12: 外层循环(类别)、内层循环(物料)、条件匹配 |
|
||||||
|
| 6. 格式化并完成 | 13-14: 格式化工作表、显示消息框 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用建议
|
||||||
|
|
||||||
|
1. **学习路径**:先看简略版建立整体概念,再看详细版理解实现细节
|
||||||
|
2. **文档组织**:简略版放在文档开头作为概述,详细版放在后面作为参考
|
||||||
|
3. **演示场景**:简略版适合PPT演示,详细版适合技术讲解
|
||||||
|
4. **版本维护**:代码变更时,优先更新详细版,然后同步更新简略版的主要流程
|
||||||
@@ -16,7 +16,7 @@ Private dictCategories As Object ' Dictionary对象: 类别名称 -> clsCateg
|
|||||||
' 作用: 快速查找任意类别
|
' 作用: 快速查找任意类别
|
||||||
Private dictAllMaterials As Object ' Dictionary对象: 物料代号 -> clsMaterialItem对象
|
Private dictAllMaterials As Object ' Dictionary对象: 物料代号 -> clsMaterialItem对象
|
||||||
' 作用: 快速查找任意物料
|
' 作用: 快速查找任意物料
|
||||||
Private rootCategories As Collection ' Collection: 存储所有顶层类别(无父类别的类别)
|
Private rootCategories As collection ' Collection: 存储所有顶层类别(无父类别的类别)
|
||||||
' 作用: 遍历完整的类别树结构
|
' 作用: 遍历完整的类别树结构
|
||||||
|
|
||||||
' ========================================
|
' ========================================
|
||||||
@@ -26,7 +26,7 @@ Private rootCategories As Collection ' Collection: 存储所有顶层类别(无
|
|||||||
Private Sub Class_Initialize()
|
Private Sub Class_Initialize()
|
||||||
Set dictCategories = CreateObject("Scripting.Dictionary")
|
Set dictCategories = CreateObject("Scripting.Dictionary")
|
||||||
Set dictAllMaterials = CreateObject("Scripting.Dictionary")
|
Set dictAllMaterials = CreateObject("Scripting.Dictionary")
|
||||||
Set rootCategories = New Collection
|
Set rootCategories = New collection
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
' ========================================
|
' ========================================
|
||||||
@@ -59,12 +59,12 @@ Public Sub LoadData(wsConfig As Worksheet, wsPlatform As Worksheet)
|
|||||||
lastRow = wsPlatform.Cells(wsPlatform.Rows.Count, "C").End(xlUp).row
|
lastRow = wsPlatform.Cells(wsPlatform.Rows.Count, "C").End(xlUp).row
|
||||||
For i = 4 To lastRow ' 从第4行开始(跳过标题)
|
For i = 4 To lastRow ' 从第4行开始(跳过标题)
|
||||||
Set mat = New clsMaterialItem
|
Set mat = New clsMaterialItem
|
||||||
mat.code = Trim(wsPlatform.Cells(i, "C").Value & "") ' 物料代号
|
mat.code = Trim(wsPlatform.Cells(i, "C").value & "") ' 物料代号
|
||||||
mat.Name = Trim(wsPlatform.Cells(i, "D").Value & "") ' 物料名称
|
mat.Name = Trim(wsPlatform.Cells(i, "D").value & "") ' 物料名称
|
||||||
On Error Resume Next
|
On Error Resume Next
|
||||||
mat.Quantity = CDbl(wsPlatform.Cells(i, "E").Value) ' 物料数量
|
mat.Quantity = CDbl(wsPlatform.Cells(i, "E").value) ' 物料数量
|
||||||
On Error GoTo 0
|
On Error GoTo 0
|
||||||
mat.Condition = Trim(wsPlatform.Cells(i, "F").Value & "") ' 选择条件
|
mat.Condition = Trim(wsPlatform.Cells(i, "F").value & "") ' 选择条件
|
||||||
|
|
||||||
' 只保存代号非空的物料
|
' 只保存代号非空的物料
|
||||||
If mat.code <> "" Then
|
If mat.code <> "" Then
|
||||||
@@ -86,9 +86,9 @@ Public Sub LoadData(wsConfig As Worksheet, wsPlatform As Worksheet)
|
|||||||
lastRow = wsConfig.Cells(wsConfig.Rows.Count, "A").End(xlUp).row
|
lastRow = wsConfig.Cells(wsConfig.Rows.Count, "A").End(xlUp).row
|
||||||
For i = 2 To lastRow ' 从第2行开始
|
For i = 2 To lastRow ' 从第2行开始
|
||||||
Dim code As String, catName As String, parentCatName As String
|
Dim code As String, catName As String, parentCatName As String
|
||||||
code = Trim(wsConfig.Cells(i, "A").Value & "") ' 物料代号
|
code = Trim(wsConfig.Cells(i, "A").value & "") ' 物料代号
|
||||||
catName = Trim(wsConfig.Cells(i, "C").Value & "") ' 类别名称
|
catName = Trim(wsConfig.Cells(i, "C").value & "") ' 类别名称
|
||||||
parentCatName = Trim(wsConfig.Cells(i, "D").Value & "") ' 上层类别名称
|
parentCatName = Trim(wsConfig.Cells(i, "D").value & "") ' 上层类别名称
|
||||||
|
|
||||||
' 跳过空行
|
' 跳过空行
|
||||||
If code = "" Then GoTo NextRow
|
If code = "" Then GoTo NextRow
|
||||||
@@ -155,7 +155,7 @@ End Sub
|
|||||||
' Debug.Print cats(i).CategoryName
|
' Debug.Print cats(i).CategoryName
|
||||||
' Next i
|
' Next i
|
||||||
' ========================================
|
' ========================================
|
||||||
Public Function GetRootCategories() As Collection
|
Public Function GetRootCategories() As collection
|
||||||
Set GetRootCategories = rootCategories
|
Set GetRootCategories = rootCategories
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
@@ -208,9 +208,9 @@ End Function
|
|||||||
' ' 返回: 径向低压接头、弹簧管、螺旋管等零件
|
' ' 返回: 径向低压接头、弹簧管、螺旋管等零件
|
||||||
' ========================================
|
' ========================================
|
||||||
Public Function GetMaterialsForPicking(categoryName As String, _
|
Public Function GetMaterialsForPicking(categoryName As String, _
|
||||||
Optional useParent As Boolean = True) As Collection
|
Optional useParent As Boolean = True) As collection
|
||||||
Dim result As Collection
|
Dim result As collection
|
||||||
Set result = New Collection
|
Set result = New collection
|
||||||
|
|
||||||
' 查找指定类别
|
' 查找指定类别
|
||||||
Dim cat As clsCategory
|
Dim cat As clsCategory
|
||||||
@@ -232,8 +232,8 @@ Public Function GetMaterialsForPicking(categoryName As String, _
|
|||||||
' - 这是正常情况下的领料方式(领取组装好的部件)
|
' - 这是正常情况下的领料方式(领取组装好的部件)
|
||||||
' ========================================
|
' ========================================
|
||||||
Dim m As clsMaterialItem
|
Dim m As clsMaterialItem
|
||||||
For i = 1 To cat.Materials.Count
|
For i = 1 To cat.materials.Count
|
||||||
Set m = cat.Materials(i)
|
Set m = cat.materials(i)
|
||||||
result.Add m
|
result.Add m
|
||||||
Next i
|
Next i
|
||||||
Else
|
Else
|
||||||
@@ -253,7 +253,7 @@ Public Function GetMaterialsForPicking(categoryName As String, _
|
|||||||
Dim j As Long
|
Dim j As Long
|
||||||
For j = 1 To cat.SubCategories.Count
|
For j = 1 To cat.SubCategories.Count
|
||||||
Set subCat = cat.SubCategories(j)
|
Set subCat = cat.SubCategories(j)
|
||||||
Dim subMats As Collection
|
Dim subMats As collection
|
||||||
' 递归调用,继续展开子类别
|
' 递归调用,继续展开子类别
|
||||||
Set subMats = GetMaterialsForPicking(subCat.categoryName, False)
|
Set subMats = GetMaterialsForPicking(subCat.categoryName, False)
|
||||||
Dim k As Long
|
Dim k As Long
|
||||||
@@ -263,8 +263,8 @@ Public Function GetMaterialsForPicking(categoryName As String, _
|
|||||||
Next j
|
Next j
|
||||||
Else
|
Else
|
||||||
' 叶子类别,返回本类别物料
|
' 叶子类别,返回本类别物料
|
||||||
For i = 1 To cat.Materials.Count
|
For i = 1 To cat.materials.Count
|
||||||
Set m = cat.Materials(i)
|
Set m = cat.materials(i)
|
||||||
result.Add m
|
result.Add m
|
||||||
Next i
|
Next i
|
||||||
End If
|
End If
|
||||||
@@ -297,7 +297,7 @@ End Function
|
|||||||
Public Sub PrintCategoryTree(ws As Worksheet)
|
Public Sub PrintCategoryTree(ws As Worksheet)
|
||||||
Dim row As Long
|
Dim row As Long
|
||||||
row = 1
|
row = 1
|
||||||
ws.Cells(row, 1).Value = "类别层级结构"
|
ws.Cells(row, 1).value = "类别层级结构"
|
||||||
row = row + 1
|
row = row + 1
|
||||||
|
|
||||||
' 遍历所有根类别,递归打印整个树
|
' 遍历所有根类别,递归打印整个树
|
||||||
@@ -329,19 +329,19 @@ Private Sub PrintCategory(ws As Worksheet, cat As clsCategory, _
|
|||||||
indent = String(level * 2, " ")
|
indent = String(level * 2, " ")
|
||||||
|
|
||||||
' 打印类别名称和物料数量统计
|
' 打印类别名称和物料数量统计
|
||||||
ws.Cells(row, 1).Value = indent & cat.categoryName & _
|
ws.Cells(row, 1).value = indent & cat.categoryName & _
|
||||||
" (物料数:" & cat.Materials.Count & ")"
|
" (物料数:" & cat.materials.Count & ")"
|
||||||
row = row + 1
|
row = row + 1
|
||||||
|
|
||||||
' 打印该类别下的所有物料
|
' 打印该类别下的所有物料
|
||||||
Dim mat As clsMaterialItem
|
Dim mat As clsMaterialItem
|
||||||
Dim i As Long
|
Dim i As Long
|
||||||
For i = 1 To cat.Materials.Count
|
For i = 1 To cat.materials.Count
|
||||||
Set mat = cat.Materials(i)
|
Set mat = cat.materials(i)
|
||||||
' 物料行额外缩进2个空格,并加上"- "前缀
|
' 物料行额外缩进2个空格,并加上"- "前缀
|
||||||
ws.Cells(row, 1).Value = indent & " - " & mat.code & " " & mat.Name
|
ws.Cells(row, 1).value = indent & " - " & mat.code & " " & mat.Name
|
||||||
ws.Cells(row, 2).Value = "数量:" & mat.Quantity
|
ws.Cells(row, 2).value = "数量:" & mat.Quantity
|
||||||
ws.Cells(row, 3).Value = "条件:" & mat.Condition
|
ws.Cells(row, 3).value = "条件:" & mat.Condition
|
||||||
row = row + 1
|
row = row + 1
|
||||||
Next i
|
Next i
|
||||||
|
|
||||||
@@ -353,4 +353,181 @@ Private Sub PrintCategory(ws As Worksheet, cat As clsCategory, _
|
|||||||
' 递归调用,层级加1
|
' 递归调用,层级加1
|
||||||
Call PrintCategory(ws, subCat, row, level + 1)
|
Call PrintCategory(ws, subCat, row, level + 1)
|
||||||
Next j
|
Next j
|
||||||
End Sub
|
End Sub
|
||||||
|
' ========================================
|
||||||
|
' GetMaterialsByModel 方法
|
||||||
|
' 功能: 根据产品型号获取符合条件的物料清单
|
||||||
|
' 参数:
|
||||||
|
' modelStr - 产品型号字符串
|
||||||
|
' categoryName - 可选,指定类别名称。为空则返回所有类别的物料
|
||||||
|
' 返回: Collection对象,包含符合条件的clsMaterialItem对象
|
||||||
|
' 示例:
|
||||||
|
' Set materials = bomMgr.GetMaterialsByModel("YTHN-100.A0.532.M203.M16.Y3")
|
||||||
|
' Set materials = bomMgr.GetMaterialsByModel("YTHN-100.A0.532.M203.M16.Y3", "部件")
|
||||||
|
' ========================================
|
||||||
|
Public Function GetMaterialsByModel(modelStr As String, _
|
||||||
|
Optional categoryName As String = "") As collection
|
||||||
|
Dim result As collection
|
||||||
|
Set result = New collection
|
||||||
|
|
||||||
|
' 1. 解析型号
|
||||||
|
Dim parser As New clsModelParser
|
||||||
|
If Not parser.ParseModel(modelStr) Then
|
||||||
|
Debug.Print "型号解析失败: " & parser.ErrorMessage
|
||||||
|
Set GetMaterialsByModel = result
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 2. 提取条件
|
||||||
|
Dim extractor As New clsConditionExtractor
|
||||||
|
Dim conditions As Object
|
||||||
|
Set conditions = extractor.ExtractConditions(parser)
|
||||||
|
|
||||||
|
' 调试输出
|
||||||
|
Debug.Print "【型号】: " & modelStr
|
||||||
|
Debug.Print "【提取的条件】:"
|
||||||
|
Dim key As Variant
|
||||||
|
For Each key In conditions.Keys
|
||||||
|
Debug.Print " " & key & " = " & conditions(key)
|
||||||
|
Next key
|
||||||
|
Debug.Print ""
|
||||||
|
|
||||||
|
' 3. 创建条件匹配器
|
||||||
|
Dim matcher As New clsConditionMatcher
|
||||||
|
|
||||||
|
' 4. 获取要筛选的物料范围
|
||||||
|
Dim materialsToFilter As collection
|
||||||
|
Set materialsToFilter = New collection
|
||||||
|
|
||||||
|
If categoryName <> "" Then
|
||||||
|
' 指定类别:获取该类别的所有物料
|
||||||
|
Dim cat As clsCategory
|
||||||
|
Set cat = GetCategory(categoryName)
|
||||||
|
If Not cat Is Nothing Then
|
||||||
|
Dim i As Long
|
||||||
|
For i = 1 To cat.materials.Count
|
||||||
|
materialsToFilter.Add cat.materials(i)
|
||||||
|
Next i
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
' 未指定类别:获取所有根类别的物料
|
||||||
|
Dim rootCat As clsCategory
|
||||||
|
Dim j As Long
|
||||||
|
For j = 1 To rootCategories.Count
|
||||||
|
Set rootCat = rootCategories(j)
|
||||||
|
' 递归获取所有物料
|
||||||
|
Call CollectAllMaterials(rootCat, materialsToFilter)
|
||||||
|
Next j
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 5. 筛选符合条件的物料
|
||||||
|
Dim mat As clsMaterialItem
|
||||||
|
Dim matchCount As Long
|
||||||
|
matchCount = 0
|
||||||
|
|
||||||
|
For Each mat In materialsToFilter
|
||||||
|
' 使用条件匹配器判断
|
||||||
|
If matcher.IsMatch(mat.Condition, conditions) Then
|
||||||
|
result.Add mat
|
||||||
|
matchCount = matchCount + 1
|
||||||
|
|
||||||
|
' 调试输出
|
||||||
|
Debug.Print "【匹配】 " & mat.code & " - " & mat.Name & _
|
||||||
|
" | 条件: " & IIf(mat.Condition = "", "(无)", mat.Condition)
|
||||||
|
End If
|
||||||
|
Next mat
|
||||||
|
|
||||||
|
Debug.Print "共匹配 " & matchCount & " 个物料"
|
||||||
|
Debug.Print String(60, "=")
|
||||||
|
|
||||||
|
Set GetMaterialsByModel = result
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' CollectAllMaterials 方法 (私有)
|
||||||
|
' 功能: 递归收集类别及其所有子类别的物料
|
||||||
|
' 参数:
|
||||||
|
' cat - 类别对象
|
||||||
|
' collection - 用于存储物料的Collection
|
||||||
|
' ========================================
|
||||||
|
Private Sub CollectAllMaterials(cat As clsCategory, collection As collection)
|
||||||
|
Dim i As Long
|
||||||
|
|
||||||
|
' 添加当前类别的所有物料
|
||||||
|
For i = 1 To cat.materials.Count
|
||||||
|
collection.Add cat.materials(i)
|
||||||
|
Next i
|
||||||
|
|
||||||
|
' 递归处理子类别
|
||||||
|
Dim subCat As clsCategory
|
||||||
|
Dim j As Long
|
||||||
|
For j = 1 To cat.SubCategories.Count
|
||||||
|
Set subCat = cat.SubCategories(j)
|
||||||
|
Call CollectAllMaterials(subCat, collection)
|
||||||
|
Next j
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' GetMaterialsByCategoryAndModel 方法
|
||||||
|
' 功能: 根据类别和型号获取物料(使用父类别或子类别逻辑)
|
||||||
|
' 参数:
|
||||||
|
' modelStr - 产品型号字符串
|
||||||
|
' categoryName - 类别名称
|
||||||
|
' useParent - True=使用父类别物料,False=使用子类别物料
|
||||||
|
' 返回: Collection对象,包含符合条件的clsMaterialItem对象
|
||||||
|
' 说明: 这是 GetMaterialsForPicking 和 GetMaterialsByModel 的结合
|
||||||
|
' ========================================
|
||||||
|
Public Function GetMaterialsByCategoryAndModel(modelStr As String, _
|
||||||
|
categoryName As String, _
|
||||||
|
Optional useParent As Boolean = True) As collection
|
||||||
|
Dim result As collection
|
||||||
|
Set result = New collection
|
||||||
|
|
||||||
|
' 1. 解析型号并提取条件
|
||||||
|
Dim parser As New clsModelParser
|
||||||
|
If Not parser.ParseModel(modelStr) Then
|
||||||
|
Set GetMaterialsByCategoryAndModel = result
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
Dim extractor As New clsConditionExtractor
|
||||||
|
Dim conditions As Object
|
||||||
|
Set conditions = extractor.ExtractConditions(parser)
|
||||||
|
|
||||||
|
' 2. 获取类别的物料(根据 useParent 参数)
|
||||||
|
Dim materialsToFilter As collection
|
||||||
|
Set materialsToFilter = GetMaterialsForPicking(categoryName, useParent)
|
||||||
|
|
||||||
|
' 3. 筛选符合条件的物料
|
||||||
|
Dim matcher As New clsConditionMatcher
|
||||||
|
Dim mat As clsMaterialItem
|
||||||
|
|
||||||
|
For Each mat In materialsToFilter
|
||||||
|
If matcher.IsMatch(mat.Condition, conditions) Then
|
||||||
|
result.Add mat
|
||||||
|
End If
|
||||||
|
Next mat
|
||||||
|
|
||||||
|
Set GetMaterialsByCategoryAndModel = result
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' ParseModelAndExtractConditions 方法
|
||||||
|
' 功能: 解析型号并返回条件字典(工具方法)
|
||||||
|
' 参数: modelStr - 产品型号字符串
|
||||||
|
' 返回: Dictionary对象,包含提取的条件
|
||||||
|
' 用途: 供外部调用,用于查看提取的条件
|
||||||
|
' ========================================
|
||||||
|
Public Function ParseModelAndExtractConditions(modelStr As String) As Object
|
||||||
|
Dim parser As New clsModelParser
|
||||||
|
Dim extractor As New clsConditionExtractor
|
||||||
|
Dim conditions As Object
|
||||||
|
|
||||||
|
If parser.ParseModel(modelStr) Then
|
||||||
|
Set conditions = extractor.ExtractConditions(parser)
|
||||||
|
Else
|
||||||
|
Set conditions = CreateObject("Scripting.Dictionary")
|
||||||
|
End If
|
||||||
|
|
||||||
|
Set ParseModelAndExtractConditions = conditions
|
||||||
|
End Function
|
||||||
@@ -6,19 +6,19 @@ Option Explicit
|
|||||||
|
|
||||||
Public categoryName As String
|
Public categoryName As String
|
||||||
Public ParentCategoryName As String
|
Public ParentCategoryName As String
|
||||||
Public Materials As Collection ' 存储 clsMaterialItem 对象
|
Public materials As collection ' 存储 clsMaterialItem 对象
|
||||||
Public SubCategories As Collection ' 存储子类别 clsCategory 对象
|
Public SubCategories As collection ' 存储子类别 clsCategory 对象
|
||||||
Public IsLeafCategory As Boolean ' 是否叶子类别(无子类别)
|
Public IsLeafCategory As Boolean ' 是否叶子类别(无子类别)
|
||||||
|
|
||||||
Private Sub Class_Initialize()
|
Private Sub Class_Initialize()
|
||||||
Set Materials = New Collection
|
Set materials = New collection
|
||||||
Set SubCategories = New Collection
|
Set SubCategories = New collection
|
||||||
IsLeafCategory = True
|
IsLeafCategory = True
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
' 添加物料
|
' 添加物料
|
||||||
Public Sub AddMaterial(mat As clsMaterialItem)
|
Public Sub AddMaterial(mat As clsMaterialItem)
|
||||||
Materials.Add mat, mat.code
|
materials.Add mat, mat.code
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
' 添加子类别
|
' 添加子类别
|
||||||
@@ -30,7 +30,7 @@ End Sub
|
|||||||
' 获取物料(按代号)
|
' 获取物料(按代号)
|
||||||
Public Function GetMaterial(code As String) As clsMaterialItem
|
Public Function GetMaterial(code As String) As clsMaterialItem
|
||||||
On Error Resume Next
|
On Error Resume Next
|
||||||
Set GetMaterial = Materials(code)
|
Set GetMaterial = materials(code)
|
||||||
On Error GoTo 0
|
On Error GoTo 0
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
|
|||||||
234
VBA/ClassModules/clsConditionExtractor.cls
Normal file
234
VBA/ClassModules/clsConditionExtractor.cls
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
' ========================================
|
||||||
|
' 类模块: clsConditionExtractor
|
||||||
|
' 用途: 从型号解析器中提取物料选择条件
|
||||||
|
' ========================================
|
||||||
|
Option Explicit
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 私有成员变量
|
||||||
|
' ========================================
|
||||||
|
Private m_Conditions As Object ' Dictionary: 变量名 -> 条件值
|
||||||
|
Private m_ExtractionRules As Object ' Dictionary: 提取规则配置
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 类初始化
|
||||||
|
' ========================================
|
||||||
|
Private Sub Class_Initialize()
|
||||||
|
Set m_Conditions = CreateObject("Scripting.Dictionary")
|
||||||
|
Set m_ExtractionRules = CreateObject("Scripting.Dictionary")
|
||||||
|
|
||||||
|
' 初始化提取规则
|
||||||
|
InitializeRules
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' InitializeRules 方法 (私有)
|
||||||
|
' 功能: 初始化条件提取规则
|
||||||
|
' 说明: 这里配置所有需要提取的条件及其提取方法
|
||||||
|
' ========================================
|
||||||
|
Private Sub InitializeRules()
|
||||||
|
' 规则格式: Dictionary(变量名) = Array(源字段, 提取方法)
|
||||||
|
|
||||||
|
' 规则1: 过程连接 (gclj)
|
||||||
|
' 从 ConnectionCode 中提取,去掉最后一位数字
|
||||||
|
m_ExtractionRules("gclj") = Array("ConnectionCode", "RemoveLastDigit")
|
||||||
|
|
||||||
|
' 规则2: 接液材质 (jycz)
|
||||||
|
' 从 ConnectionCode 中提取,取最后一位数字
|
||||||
|
m_ExtractionRules("jycz") = Array("ConnectionCode", "GetLastDigit")
|
||||||
|
|
||||||
|
' 规则3: 量程范围 (lcfw)
|
||||||
|
' 从 RangeCode 中直接提取
|
||||||
|
m_ExtractionRules("lcfw") = Array("RangeCode", "Direct")
|
||||||
|
|
||||||
|
' 未来可以在这里添加更多提取规则...
|
||||||
|
' 例如:
|
||||||
|
' m_ExtractionRules("bplx") = Array("DialCode", "Direct") ' 表盘类型
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' ExtractConditions 方法
|
||||||
|
' 功能: 从型号解析器中提取所有条件
|
||||||
|
' 参数: parser - clsModelParser对象
|
||||||
|
' 返回: Dictionary对象,包含所有提取的条件
|
||||||
|
' ========================================
|
||||||
|
Public Function ExtractConditions(parser As clsModelParser) As Object
|
||||||
|
' 清空现有条件
|
||||||
|
Set m_Conditions = CreateObject("Scripting.Dictionary")
|
||||||
|
|
||||||
|
' 验证解析器有效性
|
||||||
|
If Not parser.IsValid Then
|
||||||
|
Set ExtractConditions = m_Conditions
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 遍历所有提取规则
|
||||||
|
Dim varName As Variant
|
||||||
|
For Each varName In m_ExtractionRules.Keys
|
||||||
|
Dim ruleInfo As Variant
|
||||||
|
ruleInfo = m_ExtractionRules(varName)
|
||||||
|
|
||||||
|
Dim sourceField As String
|
||||||
|
Dim extractMethod As String
|
||||||
|
sourceField = ruleInfo(0)
|
||||||
|
extractMethod = ruleInfo(1)
|
||||||
|
|
||||||
|
' 提取条件值
|
||||||
|
Dim conditionValue As String
|
||||||
|
conditionValue = ExtractValue(parser, sourceField, extractMethod)
|
||||||
|
|
||||||
|
' 添加到条件字典
|
||||||
|
If conditionValue <> "" Then
|
||||||
|
m_Conditions(CStr(varName)) = conditionValue
|
||||||
|
End If
|
||||||
|
Next varName
|
||||||
|
|
||||||
|
Set ExtractConditions = m_Conditions
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' ExtractValue 方法 (私有)
|
||||||
|
' 功能: 根据规则从解析器中提取单个值
|
||||||
|
' 参数:
|
||||||
|
' parser - clsModelParser对象
|
||||||
|
' sourceField - 源字段名称
|
||||||
|
' extractMethod - 提取方法名称
|
||||||
|
' 返回: 提取的条件值
|
||||||
|
' ========================================
|
||||||
|
Private Function ExtractValue(parser As clsModelParser, _
|
||||||
|
sourceField As String, _
|
||||||
|
extractMethod As String) As String
|
||||||
|
Dim sourceValue As String
|
||||||
|
|
||||||
|
' 获取源字段值
|
||||||
|
Select Case sourceField
|
||||||
|
Case "ConnectionCode"
|
||||||
|
sourceValue = parser.ConnectionCode
|
||||||
|
Case "RangeCode"
|
||||||
|
sourceValue = parser.RangeCode
|
||||||
|
Case "ModelType"
|
||||||
|
sourceValue = parser.ModelType
|
||||||
|
Case "Diameter"
|
||||||
|
sourceValue = parser.Diameter
|
||||||
|
Case "InstallForm"
|
||||||
|
sourceValue = parser.InstallForm
|
||||||
|
Case "ShellForm"
|
||||||
|
sourceValue = parser.ShellForm
|
||||||
|
Case "Characteristics"
|
||||||
|
sourceValue = parser.Characteristics
|
||||||
|
Case Else
|
||||||
|
sourceValue = ""
|
||||||
|
End Select
|
||||||
|
|
||||||
|
' 应用提取方法
|
||||||
|
Select Case extractMethod
|
||||||
|
Case "Direct"
|
||||||
|
' 直接使用
|
||||||
|
ExtractValue = sourceValue
|
||||||
|
|
||||||
|
Case "RemoveLastDigit"
|
||||||
|
' 去掉最后一位字符
|
||||||
|
If Len(sourceValue) > 1 Then
|
||||||
|
ExtractValue = Left(sourceValue, Len(sourceValue) - 1)
|
||||||
|
Else
|
||||||
|
ExtractValue = sourceValue
|
||||||
|
End If
|
||||||
|
|
||||||
|
Case "GetLastDigit"
|
||||||
|
' 取最后一位字符
|
||||||
|
If Len(sourceValue) > 0 Then
|
||||||
|
ExtractValue = Right(sourceValue, 1)
|
||||||
|
Else
|
||||||
|
ExtractValue = ""
|
||||||
|
End If
|
||||||
|
|
||||||
|
Case "GetFirstChar"
|
||||||
|
' 取第一个字符
|
||||||
|
If Len(sourceValue) > 0 Then
|
||||||
|
ExtractValue = Left(sourceValue, 1)
|
||||||
|
Else
|
||||||
|
ExtractValue = ""
|
||||||
|
End If
|
||||||
|
|
||||||
|
Case Else
|
||||||
|
' 未知方法,返回空
|
||||||
|
ExtractValue = ""
|
||||||
|
End Select
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' GetConditionValue 方法
|
||||||
|
' 功能: 获取单个条件值
|
||||||
|
' 参数: varName - 变量名
|
||||||
|
' 返回: 条件值,如果不存在返回空字符串
|
||||||
|
' ========================================
|
||||||
|
Public Function GetConditionValue(varName As String) As String
|
||||||
|
If m_Conditions.Exists(varName) Then
|
||||||
|
GetConditionValue = m_Conditions(varName)
|
||||||
|
Else
|
||||||
|
GetConditionValue = ""
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' AddCondition 方法
|
||||||
|
' 功能: 手动添加条件 (用于特殊情况)
|
||||||
|
' 参数:
|
||||||
|
' varName - 变量名
|
||||||
|
' value - 条件值
|
||||||
|
' ========================================
|
||||||
|
Public Sub AddCondition(varName As String, value As String)
|
||||||
|
m_Conditions(varName) = value
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' GetConditions 属性
|
||||||
|
' 功能: 获取所有条件的Dictionary对象
|
||||||
|
' ========================================
|
||||||
|
Public Property Get conditions() As Object
|
||||||
|
Set conditions = m_Conditions
|
||||||
|
End Property
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' ToString 方法
|
||||||
|
' 功能: 返回条件的字符串表示 (用于调试)
|
||||||
|
' ========================================
|
||||||
|
Public Function ToString() As String
|
||||||
|
Dim result As String
|
||||||
|
result = "【提取的条件】" & vbCrLf
|
||||||
|
|
||||||
|
If m_Conditions.Count = 0 Then
|
||||||
|
result = result & " (无条件)" & vbCrLf
|
||||||
|
Else
|
||||||
|
Dim key As Variant
|
||||||
|
For Each key In m_Conditions.Keys
|
||||||
|
result = result & " " & key & " = " & m_Conditions(key) & vbCrLf
|
||||||
|
Next key
|
||||||
|
End If
|
||||||
|
|
||||||
|
ToString = result
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' AddExtractionRule 方法
|
||||||
|
' 功能: 动态添加新的提取规则 (用于扩展)
|
||||||
|
' 参数:
|
||||||
|
' varName - 变量名
|
||||||
|
' sourceField - 源字段名称
|
||||||
|
' extractMethod - 提取方法名称
|
||||||
|
' 示例: extractor.AddExtractionRule "bplx", "DialCode", "Direct"
|
||||||
|
' ========================================
|
||||||
|
Public Sub AddExtractionRule(varName As String, _
|
||||||
|
sourceField As String, _
|
||||||
|
extractMethod As String)
|
||||||
|
m_ExtractionRules(varName) = Array(sourceField, extractMethod)
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' GetExtractionRules 方法
|
||||||
|
' 功能: 获取当前所有提取规则 (用于调试)
|
||||||
|
' 返回: Dictionary对象
|
||||||
|
' ========================================
|
||||||
|
Public Function GetExtractionRules() As Object
|
||||||
|
Set GetExtractionRules = m_ExtractionRules
|
||||||
|
End Function
|
||||||
250
VBA/ClassModules/clsConditionMatcher.cls
Normal file
250
VBA/ClassModules/clsConditionMatcher.cls
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
' ========================================
|
||||||
|
' 类模块: clsConditionMatcher
|
||||||
|
' 用途: 解析物料的选择条件表达式,并判断是否匹配
|
||||||
|
' 支持: AND, OR, NOT(!=), 括号优先级
|
||||||
|
' ========================================
|
||||||
|
Option Explicit
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' IsMatch 方法
|
||||||
|
' 功能: 判断条件表达式是否匹配
|
||||||
|
' 参数:
|
||||||
|
' conditionExpr - 条件表达式字符串
|
||||||
|
' conditions - Dictionary对象,包含变量名->值的映射
|
||||||
|
' 返回: Boolean - 是否匹配
|
||||||
|
' 示例:
|
||||||
|
' IsMatch("lcfw=M16 AND gclj=M20", conditions) -> True/False
|
||||||
|
' ========================================
|
||||||
|
Public Function IsMatch(conditionExpr As String, conditions As Object) As Boolean
|
||||||
|
On Error GoTo ErrorHandler
|
||||||
|
|
||||||
|
' 空条件表示无条件,始终匹配
|
||||||
|
If Trim(conditionExpr) = "" Then
|
||||||
|
IsMatch = True
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 解析并计算表达式
|
||||||
|
IsMatch = EvaluateExpression(Trim(conditionExpr), conditions)
|
||||||
|
Exit Function
|
||||||
|
|
||||||
|
ErrorHandler:
|
||||||
|
' 出错时返回False(保守处理)
|
||||||
|
Debug.Print "条件匹配出错: " & conditionExpr & " - " & Err.description
|
||||||
|
IsMatch = False
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' EvaluateExpression 方法 (私有)
|
||||||
|
' 功能: 递归计算逻辑表达式
|
||||||
|
' 优先级: 括号 > NOT(!=) > AND > OR
|
||||||
|
' ========================================
|
||||||
|
Private Function EvaluateExpression(expr As String, conditions As Object) As Boolean
|
||||||
|
expr = Trim(expr)
|
||||||
|
|
||||||
|
' 处理括号 (最高优先级)
|
||||||
|
If InStr(expr, "(") > 0 Then
|
||||||
|
EvaluateExpression = EvaluateWithParentheses(expr, conditions)
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 处理 OR (最低优先级)
|
||||||
|
If InStr(expr, " OR ") > 0 Then
|
||||||
|
EvaluateExpression = EvaluateOR(expr, conditions)
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 处理 AND (中等优先级)
|
||||||
|
If InStr(expr, " AND ") > 0 Then
|
||||||
|
EvaluateExpression = EvaluateAND(expr, conditions)
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 处理单个条件 (最高优先级)
|
||||||
|
EvaluateExpression = EvaluateSimpleCondition(expr, conditions)
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' EvaluateWithParentheses 方法 (私有)
|
||||||
|
' 功能: 处理包含括号的表达式
|
||||||
|
' 策略: 找到最内层括号,递归计算,然后替换为结果
|
||||||
|
' ========================================
|
||||||
|
Private Function EvaluateWithParentheses(expr As String, conditions As Object) As Boolean
|
||||||
|
Dim pos As Long, level As Long, startPos As Long
|
||||||
|
Dim i As Long
|
||||||
|
Dim innerExpr As String
|
||||||
|
Dim innerResult As Boolean
|
||||||
|
Dim newExpr As String
|
||||||
|
|
||||||
|
' 查找最内层的括号对
|
||||||
|
startPos = 0
|
||||||
|
level = 0
|
||||||
|
|
||||||
|
For i = 1 To Len(expr)
|
||||||
|
If Mid(expr, i, 1) = "(" Then
|
||||||
|
If level = 0 Then startPos = i
|
||||||
|
level = level + 1
|
||||||
|
ElseIf Mid(expr, i, 1) = ")" Then
|
||||||
|
level = level - 1
|
||||||
|
If level = 0 And startPos > 0 Then
|
||||||
|
' 找到一对括号
|
||||||
|
innerExpr = Mid(expr, startPos + 1, i - startPos - 1)
|
||||||
|
innerResult = EvaluateExpression(innerExpr, conditions)
|
||||||
|
|
||||||
|
' 替换括号部分为结果
|
||||||
|
newExpr = Left(expr, startPos - 1) & _
|
||||||
|
IIf(innerResult, "TRUE", "FALSE") & _
|
||||||
|
Mid(expr, i + 1)
|
||||||
|
|
||||||
|
' 递归处理剩余部分
|
||||||
|
EvaluateWithParentheses = EvaluateExpression(newExpr, conditions)
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
End If
|
||||||
|
Next i
|
||||||
|
|
||||||
|
' 如果没有找到有效括号,直接计算
|
||||||
|
EvaluateWithParentheses = EvaluateExpression(expr, conditions)
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' EvaluateOR 方法 (私有)
|
||||||
|
' 功能: 处理 OR 逻辑运算
|
||||||
|
' 规则: 任一为真则为真
|
||||||
|
' ========================================
|
||||||
|
Private Function EvaluateOR(expr As String, conditions As Object) As Boolean
|
||||||
|
Dim parts() As String
|
||||||
|
Dim part As Variant
|
||||||
|
|
||||||
|
' 按 OR 分割
|
||||||
|
parts = Split(expr, " OR ")
|
||||||
|
|
||||||
|
' 任一部分为真则返回真
|
||||||
|
For Each part In parts
|
||||||
|
If EvaluateExpression(Trim(CStr(part)), conditions) Then
|
||||||
|
EvaluateOR = True
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
Next part
|
||||||
|
|
||||||
|
EvaluateOR = False
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' EvaluateAND 方法 (私有)
|
||||||
|
' 功能: 处理 AND 逻辑运算
|
||||||
|
' 规则: 全部为真才为真
|
||||||
|
' ========================================
|
||||||
|
Private Function EvaluateAND(expr As String, conditions As Object) As Boolean
|
||||||
|
Dim parts() As String
|
||||||
|
Dim part As Variant
|
||||||
|
|
||||||
|
' 按 AND 分割
|
||||||
|
parts = Split(expr, " AND ")
|
||||||
|
|
||||||
|
' 全部部分为真才返回真
|
||||||
|
For Each part In parts
|
||||||
|
If Not EvaluateExpression(Trim(CStr(part)), conditions) Then
|
||||||
|
EvaluateAND = False
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
Next part
|
||||||
|
|
||||||
|
EvaluateAND = True
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' EvaluateSimpleCondition 方法 (私有)
|
||||||
|
' 功能: 计算单个条件表达式
|
||||||
|
' 支持: = (等于), != (不等于)
|
||||||
|
' 格式: varName=value 或 varName!=value
|
||||||
|
' ========================================
|
||||||
|
Private Function EvaluateSimpleCondition(cond As String, conditions As Object) As Boolean
|
||||||
|
cond = Trim(cond)
|
||||||
|
|
||||||
|
' 处理特殊值 TRUE/FALSE (括号计算的结果)
|
||||||
|
If UCase(cond) = "TRUE" Then
|
||||||
|
EvaluateSimpleCondition = True
|
||||||
|
Exit Function
|
||||||
|
ElseIf UCase(cond) = "FALSE" Then
|
||||||
|
EvaluateSimpleCondition = False
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
Dim varName As String
|
||||||
|
Dim expectedValue As String
|
||||||
|
Dim actualValue As String
|
||||||
|
Dim isNotEqual As Boolean
|
||||||
|
|
||||||
|
' 判断是 != 还是 =
|
||||||
|
If InStr(cond, "!=") > 0 Then
|
||||||
|
isNotEqual = True
|
||||||
|
Dim parts1() As String
|
||||||
|
parts1 = Split(cond, "!=")
|
||||||
|
If UBound(parts1) < 1 Then
|
||||||
|
EvaluateSimpleCondition = False
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
varName = Trim(parts1(0))
|
||||||
|
expectedValue = Trim(parts1(1))
|
||||||
|
ElseIf InStr(cond, "=") > 0 Then
|
||||||
|
isNotEqual = False
|
||||||
|
Dim parts2() As String
|
||||||
|
parts2 = Split(cond, "=")
|
||||||
|
If UBound(parts2) < 1 Then
|
||||||
|
EvaluateSimpleCondition = False
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
varName = Trim(parts2(0))
|
||||||
|
expectedValue = Trim(parts2(1))
|
||||||
|
Else
|
||||||
|
' 无效的条件格式
|
||||||
|
EvaluateSimpleCondition = False
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 获取实际值
|
||||||
|
If conditions.Exists(varName) Then
|
||||||
|
actualValue = Trim(CStr(conditions(varName)))
|
||||||
|
Else
|
||||||
|
actualValue = ""
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 比较值 (不区分大小写)
|
||||||
|
Dim isEqual As Boolean
|
||||||
|
isEqual = (UCase(actualValue) = UCase(expectedValue))
|
||||||
|
|
||||||
|
' 返回结果
|
||||||
|
If isNotEqual Then
|
||||||
|
EvaluateSimpleCondition = Not isEqual
|
||||||
|
Else
|
||||||
|
EvaluateSimpleCondition = isEqual
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' TestExpression 方法
|
||||||
|
' 功能: 测试表达式是否有效 (用于调试)
|
||||||
|
' 参数: expr - 表达式字符串
|
||||||
|
' 返回: String - "有效" 或 错误信息
|
||||||
|
' ========================================
|
||||||
|
Public Function TestExpression(expr As String) As String
|
||||||
|
On Error GoTo ErrorHandler
|
||||||
|
|
||||||
|
' 创建测试条件
|
||||||
|
Dim testConditions As Object
|
||||||
|
Set testConditions = CreateObject("Scripting.Dictionary")
|
||||||
|
testConditions("gclj") = "M20"
|
||||||
|
testConditions("jycz") = "3"
|
||||||
|
testConditions("lcfw") = "M16"
|
||||||
|
|
||||||
|
' 尝试计算
|
||||||
|
Dim result As Boolean
|
||||||
|
result = IsMatch(expr, testConditions)
|
||||||
|
|
||||||
|
TestExpression = "有效 (结果: " & IIf(result, "True", "False") & ")"
|
||||||
|
Exit Function
|
||||||
|
|
||||||
|
ErrorHandler:
|
||||||
|
TestExpression = "无效: " & Err.description
|
||||||
|
End Function
|
||||||
229
VBA/ClassModules/clsModelParser.cls
Normal file
229
VBA/ClassModules/clsModelParser.cls
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
' ========================================
|
||||||
|
' 类模块: clsModelParser
|
||||||
|
' 用途: 解析产品型号,提取各部分代码
|
||||||
|
' 示例: YTHN-100.A0.532.M203.M16.Y3|BP-095.2312.M16.PA3
|
||||||
|
' ========================================
|
||||||
|
Option Explicit
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 公共属性
|
||||||
|
' ========================================
|
||||||
|
Public RawModel As String ' 原始完整型号
|
||||||
|
Public HeaderModel As String ' 表头型号部分
|
||||||
|
Public DialModel As String ' 表盘型号部分
|
||||||
|
Public AccessoryModel As String ' 附件型号部分
|
||||||
|
Public FlangeModel As String ' 法兰隔膜型号部分
|
||||||
|
|
||||||
|
' 表头各部分
|
||||||
|
Public ModelType As String ' 型号 (如 YTHN)
|
||||||
|
Public Diameter As String ' 公称外径 (如 100)
|
||||||
|
Public InstallForm As String ' 安装形式 (如 A0)
|
||||||
|
Public ShellForm As String ' 壳体形式 (如 532)
|
||||||
|
Public ConnectionCode As String ' 过程连接&材质代码 (如 M203)
|
||||||
|
Public RangeCode As String ' 量程范围代码 (如 M16)
|
||||||
|
Public Characteristics As String ' 仪表特性 (如 Y3)
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 私有变量
|
||||||
|
' ========================================
|
||||||
|
Private m_IsValid As Boolean ' 解析是否成功
|
||||||
|
Private m_ErrorMessage As String ' 错误信息
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' ParseModel 方法
|
||||||
|
' 功能: 解析产品型号字符串
|
||||||
|
' 参数: modelStr - 完整的产品型号字符串
|
||||||
|
' 返回: Boolean - 解析是否成功
|
||||||
|
' 示例: parser.ParseModel("YTHN-100.A0.532.M203.M16.Y3|BP-095.2312.M16.PA3")
|
||||||
|
' ========================================
|
||||||
|
Public Function ParseModel(modelStr As String) As Boolean
|
||||||
|
On Error GoTo ErrorHandler
|
||||||
|
|
||||||
|
' 初始化
|
||||||
|
m_IsValid = False
|
||||||
|
m_ErrorMessage = ""
|
||||||
|
RawModel = Trim(modelStr)
|
||||||
|
|
||||||
|
' 验证输入
|
||||||
|
If RawModel = "" Then
|
||||||
|
m_ErrorMessage = "型号字符串为空"
|
||||||
|
ParseModel = False
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 第一步: 按 | 分割各部分
|
||||||
|
Dim parts() As String
|
||||||
|
parts = Split(RawModel, "|")
|
||||||
|
|
||||||
|
If UBound(parts) >= 0 Then HeaderModel = Trim(parts(0))
|
||||||
|
If UBound(parts) >= 1 Then DialModel = Trim(parts(1))
|
||||||
|
If UBound(parts) >= 2 Then AccessoryModel = Trim(parts(2))
|
||||||
|
If UBound(parts) >= 3 Then FlangeModel = Trim(parts(3))
|
||||||
|
|
||||||
|
' 第二步: 解析表头部分 (必须存在)
|
||||||
|
If HeaderModel = "" Then
|
||||||
|
m_ErrorMessage = "表头型号为空"
|
||||||
|
ParseModel = False
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 解析表头
|
||||||
|
If Not ParseHeader(HeaderModel) Then
|
||||||
|
ParseModel = False
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
m_IsValid = True
|
||||||
|
ParseModel = True
|
||||||
|
Exit Function
|
||||||
|
|
||||||
|
ErrorHandler:
|
||||||
|
m_ErrorMessage = "解析出错: " & Err.description
|
||||||
|
m_IsValid = False
|
||||||
|
ParseModel = False
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' ParseHeader 方法 (私有)
|
||||||
|
' 功能: 解析表头型号部分
|
||||||
|
' 格式: [型号]-[公称外径].[安装形式].[壳体形式].[过程连接&材质].[量程范围].[仪表特性]
|
||||||
|
' 示例: YTHN-100.A0.532.M203.M16.Y3
|
||||||
|
' ========================================
|
||||||
|
Private Function ParseHeader(headerStr As String) As Boolean
|
||||||
|
On Error GoTo ErrorHandler
|
||||||
|
|
||||||
|
' 按 - 分割型号和参数部分
|
||||||
|
Dim mainParts() As String
|
||||||
|
mainParts = Split(headerStr, "-")
|
||||||
|
|
||||||
|
If UBound(mainParts) < 1 Then
|
||||||
|
m_ErrorMessage = "表头格式错误: 缺少 - 分隔符"
|
||||||
|
ParseHeader = False
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 提取型号
|
||||||
|
ModelType = Trim(mainParts(0))
|
||||||
|
|
||||||
|
' 按 . 分割参数部分
|
||||||
|
Dim params() As String
|
||||||
|
params = Split(mainParts(1), ".")
|
||||||
|
|
||||||
|
' 验证参数数量 (至少应该有5个部分)
|
||||||
|
If UBound(params) < 4 Then
|
||||||
|
m_ErrorMessage = "表头参数不足: 需要至少5个参数段"
|
||||||
|
ParseHeader = False
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 提取各参数
|
||||||
|
Diameter = Trim(params(0)) ' 公称外径
|
||||||
|
InstallForm = Trim(params(1)) ' 安装形式
|
||||||
|
ShellForm = Trim(params(2)) ' 壳体形式
|
||||||
|
ConnectionCode = Trim(params(3)) ' 过程连接&材质
|
||||||
|
RangeCode = Trim(params(4)) ' 量程范围
|
||||||
|
|
||||||
|
' 仪表特性 (可选)
|
||||||
|
If UBound(params) >= 5 Then
|
||||||
|
Characteristics = Trim(params(5))
|
||||||
|
Else
|
||||||
|
Characteristics = ""
|
||||||
|
End If
|
||||||
|
|
||||||
|
ParseHeader = True
|
||||||
|
Exit Function
|
||||||
|
|
||||||
|
ErrorHandler:
|
||||||
|
m_ErrorMessage = "解析表头出错: " & Err.description
|
||||||
|
ParseHeader = False
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' GetThreadCode 方法
|
||||||
|
' 功能: 从过程连接代码中提取螺纹代码
|
||||||
|
' 规则: 去掉最后一位数字
|
||||||
|
' 示例: M203 -> M20
|
||||||
|
' ========================================
|
||||||
|
Public Function GetThreadCode() As String
|
||||||
|
If ConnectionCode = "" Then
|
||||||
|
GetThreadCode = ""
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 去掉最后一位字符 (假设最后一位是材质代码)
|
||||||
|
If Len(ConnectionCode) > 1 Then
|
||||||
|
GetThreadCode = Left(ConnectionCode, Len(ConnectionCode) - 1)
|
||||||
|
Else
|
||||||
|
GetThreadCode = ConnectionCode
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' GetMaterialCode 方法
|
||||||
|
' 功能: 从过程连接代码中提取材质代码
|
||||||
|
' 规则: 取最后一位数字
|
||||||
|
' 示例: M203 -> 3
|
||||||
|
' ========================================
|
||||||
|
Public Function GetMaterialCode() As String
|
||||||
|
If ConnectionCode = "" Then
|
||||||
|
GetMaterialCode = ""
|
||||||
|
Exit Function
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 取最后一位字符
|
||||||
|
GetMaterialCode = Right(ConnectionCode, 1)
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' GetRangeCode 方法
|
||||||
|
' 功能: 获取量程代码
|
||||||
|
' 规则: 直接返回
|
||||||
|
' 示例: M16 -> M16
|
||||||
|
' ========================================
|
||||||
|
Public Function GetRangeCode() As String
|
||||||
|
GetRangeCode = RangeCode
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' IsValid 属性
|
||||||
|
' 功能: 返回解析是否成功
|
||||||
|
' ========================================
|
||||||
|
Public Property Get IsValid() As Boolean
|
||||||
|
IsValid = m_IsValid
|
||||||
|
End Property
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' ErrorMessage 属性
|
||||||
|
' 功能: 返回错误信息
|
||||||
|
' ========================================
|
||||||
|
Public Property Get ErrorMessage() As String
|
||||||
|
ErrorMessage = m_ErrorMessage
|
||||||
|
End Property
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' ToString 方法
|
||||||
|
' 功能: 返回解析结果的字符串表示 (用于调试)
|
||||||
|
' ========================================
|
||||||
|
Public Function ToString() As String
|
||||||
|
Dim result As String
|
||||||
|
result = "【型号解析结果】" & vbCrLf
|
||||||
|
result = result & "原始型号: " & RawModel & vbCrLf
|
||||||
|
result = result & "表头型号: " & HeaderModel & vbCrLf
|
||||||
|
result = result & "表盘型号: " & DialModel & vbCrLf
|
||||||
|
result = result & vbCrLf
|
||||||
|
result = result & "【表头各部分】" & vbCrLf
|
||||||
|
result = result & " 型号: " & ModelType & vbCrLf
|
||||||
|
result = result & " 公称外径: " & Diameter & vbCrLf
|
||||||
|
result = result & " 安装形式: " & InstallForm & vbCrLf
|
||||||
|
result = result & " 壳体形式: " & ShellForm & vbCrLf
|
||||||
|
result = result & " 过程连接&材质: " & ConnectionCode & vbCrLf
|
||||||
|
result = result & " 量程范围: " & RangeCode & vbCrLf
|
||||||
|
result = result & " 仪表特性: " & Characteristics & vbCrLf
|
||||||
|
result = result & vbCrLf
|
||||||
|
result = result & "【提取代码】" & vbCrLf
|
||||||
|
result = result & " 螺纹代码: " & GetThreadCode() & vbCrLf
|
||||||
|
result = result & " 材质代码: " & GetMaterialCode() & vbCrLf
|
||||||
|
result = result & " 量程代码: " & GetRangeCode() & vbCrLf
|
||||||
|
|
||||||
|
ToString = result
|
||||||
|
End Function
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
' ========================================
|
' ========================================
|
||||||
' 模块: modBOMTest
|
' 模块: modBOMTest
|
||||||
' 用途: 测试和使用BOM数据结构-同步测试2
|
' 用途: 测试和使用BOM数据结构
|
||||||
' ========================================
|
' ========================================
|
||||||
Option Explicit
|
Option Explicit
|
||||||
|
|
||||||
@@ -19,19 +19,19 @@ Sub TestBOMStructure()
|
|||||||
bomMgr.LoadData wsConfig, wsPlatform
|
bomMgr.LoadData wsConfig, wsPlatform
|
||||||
|
|
||||||
' 打印类别树结构到新工作表
|
' 打印类别树结构到新工作表
|
||||||
' Dim wsOutput As Worksheet
|
Dim wsOutput As Worksheet
|
||||||
' On Error Resume Next
|
On Error Resume Next
|
||||||
' Application.DisplayAlerts = False
|
Application.DisplayAlerts = False
|
||||||
' ThisWorkbook.Worksheets("BOM结构").Delete
|
ThisWorkbook.Worksheets("BOM结构").Delete
|
||||||
' Application.DisplayAlerts = True
|
Application.DisplayAlerts = True
|
||||||
' On Error GoTo 0
|
On Error GoTo 0
|
||||||
'
|
|
||||||
' Set wsOutput = ThisWorkbook.Worksheets.Add
|
Set wsOutput = ThisWorkbook.Worksheets.Add
|
||||||
' wsOutput.Name = "BOM结构"
|
wsOutput.Name = "BOM结构"
|
||||||
|
|
||||||
'bomMgr.PrintCategoryTree wsOutput
|
'bomMgr.PrintCategoryTree wsOutput
|
||||||
|
|
||||||
Dim cats As Collection
|
Dim cats As collection
|
||||||
Dim i As Integer
|
Dim i As Integer
|
||||||
Set cats = bomMgr.GetRootCategories()
|
Set cats = bomMgr.GetRootCategories()
|
||||||
For i = 1 To cats.Count
|
For i = 1 To cats.Count
|
||||||
@@ -40,7 +40,7 @@ Sub TestBOMStructure()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
'MsgBox "BOM数据结构加载完成!" & vbCrLf & _
|
MsgBox "BOM数据结构加载完成!" & vbCrLf & _
|
||||||
"请查看 'BOM结构' 工作表", vbInformation
|
"请查看 'BOM结构' 工作表", vbInformation
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
@@ -55,19 +55,19 @@ Sub GetCategoryMaterials()
|
|||||||
bomMgr.LoadData wsConfig, wsPlatform
|
bomMgr.LoadData wsConfig, wsPlatform
|
||||||
|
|
||||||
' 获取"部件"类别的物料(使用父类别)
|
' 获取"部件"类别的物料(使用父类别)
|
||||||
Dim Materials As Collection
|
Dim materials As collection
|
||||||
Set Materials = bomMgr.GetMaterialsForPicking("部件", True)
|
Set materials = bomMgr.GetMaterialsForPicking("部件", True)
|
||||||
|
|
||||||
Debug.Print "部件类别物料数量(父类别): " & Materials.Count
|
Debug.Print "部件类别物料数量(父类别): " & materials.Count
|
||||||
|
|
||||||
' 获取"部件"类别的物料(使用子类别)
|
' 获取"部件"类别的物料(使用子类别)
|
||||||
Set Materials = bomMgr.GetMaterialsForPicking("部件", False)
|
Set materials = bomMgr.GetMaterialsForPicking("部件", False)
|
||||||
|
|
||||||
Debug.Print "部件类别物料数量(子类别展开): " & Materials.Count
|
Debug.Print "部件类别物料数量(子类别展开): " & materials.Count
|
||||||
|
|
||||||
' 遍历物料
|
' 遍历物料
|
||||||
Dim mat As clsMaterialItem
|
Dim mat As clsMaterialItem
|
||||||
For Each mat In Materials
|
For Each mat In materials
|
||||||
Debug.Print mat.code & " - " & mat.Name & _
|
Debug.Print mat.code & " - " & mat.Name & _
|
||||||
" | 数量:" & mat.Quantity & _
|
" | 数量:" & mat.Quantity & _
|
||||||
" | 条件:" & mat.Condition
|
" | 条件:" & mat.Condition
|
||||||
@@ -98,36 +98,36 @@ Sub GeneratePickingList()
|
|||||||
' 写入表头
|
' 写入表头
|
||||||
Dim row As Long
|
Dim row As Long
|
||||||
row = 1
|
row = 1
|
||||||
wsPickList.Cells(row, 1).Value = "代号"
|
wsPickList.Cells(row, 1).value = "代号"
|
||||||
wsPickList.Cells(row, 2).Value = "名称"
|
wsPickList.Cells(row, 2).value = "名称"
|
||||||
wsPickList.Cells(row, 3).Value = "类别"
|
wsPickList.Cells(row, 3).value = "类别"
|
||||||
wsPickList.Cells(row, 4).Value = "数量"
|
wsPickList.Cells(row, 4).value = "数量"
|
||||||
wsPickList.Cells(row, 5).Value = "选择条件"
|
wsPickList.Cells(row, 5).value = "选择条件"
|
||||||
wsPickList.Cells(row, 6).Value = "领料方式"
|
wsPickList.Cells(row, 6).value = "领料方式"
|
||||||
row = row + 1
|
row = row + 1
|
||||||
|
|
||||||
' 遍历所有根类别
|
' 遍历所有根类别
|
||||||
Dim rootCats As Collection
|
Dim rootCats As collection
|
||||||
Set rootCats = bomMgr.GetRootCategories
|
Set rootCats = bomMgr.GetRootCategories
|
||||||
|
|
||||||
Dim cat As clsCategory
|
Dim cat As clsCategory
|
||||||
Dim Materials As Collection
|
Dim materials As collection
|
||||||
Dim mat As clsMaterialItem
|
Dim mat As clsMaterialItem
|
||||||
Dim i As Long, j As Long
|
Dim i As Long, j As Long
|
||||||
|
|
||||||
For i = 1 To rootCats.Count
|
For i = 1 To rootCats.Count
|
||||||
Set cat = rootCats(i)
|
Set cat = rootCats(i)
|
||||||
' 默认使用父类别物料
|
' 默认使用父类别物料
|
||||||
Set Materials = bomMgr.GetMaterialsForPicking(cat.categoryName, True)
|
Set materials = bomMgr.GetMaterialsForPicking(cat.categoryName, True)
|
||||||
|
|
||||||
For j = 1 To Materials.Count
|
For j = 1 To materials.Count
|
||||||
Set mat = Materials(j)
|
Set mat = materials(j)
|
||||||
wsPickList.Cells(row, 1).Value = mat.code
|
wsPickList.Cells(row, 1).value = mat.code
|
||||||
wsPickList.Cells(row, 2).Value = mat.Name
|
wsPickList.Cells(row, 2).value = mat.Name
|
||||||
wsPickList.Cells(row, 3).Value = mat.Category
|
wsPickList.Cells(row, 3).value = mat.Category
|
||||||
wsPickList.Cells(row, 4).Value = mat.Quantity
|
wsPickList.Cells(row, 4).value = mat.Quantity
|
||||||
wsPickList.Cells(row, 5).Value = mat.Condition
|
wsPickList.Cells(row, 5).value = mat.Condition
|
||||||
wsPickList.Cells(row, 6).Value = "父类别"
|
wsPickList.Cells(row, 6).value = "父类别"
|
||||||
row = row + 1
|
row = row + 1
|
||||||
Next j
|
Next j
|
||||||
Next i
|
Next i
|
||||||
@@ -139,64 +139,6 @@ Sub GeneratePickingList()
|
|||||||
MsgBox "领料清单生成完成!", vbInformation
|
MsgBox "领料清单生成完成!", vbInformation
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
' 示例: 在立即窗口打印领料清单
|
|
||||||
Sub PrintPickingList()
|
|
||||||
Dim bomMgr As New clsBOMManager
|
|
||||||
Dim wsConfig As Worksheet, wsPlatform As Worksheet
|
|
||||||
|
|
||||||
Set wsConfig = ThisWorkbook.Worksheets("领料配置")
|
|
||||||
Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单")
|
|
||||||
|
|
||||||
bomMgr.LoadData wsConfig, wsPlatform
|
|
||||||
|
|
||||||
' 打印表头
|
|
||||||
Debug.Print String(80, "=")
|
|
||||||
Debug.Print "领料清单"
|
|
||||||
Debug.Print String(80, "=")
|
|
||||||
|
|
||||||
' 遍历所有根类别
|
|
||||||
Dim rootCats As Collection
|
|
||||||
Set rootCats = bomMgr.GetRootCategories
|
|
||||||
|
|
||||||
Dim cat As clsCategory
|
|
||||||
Dim Materials As Collection
|
|
||||||
Dim mat As clsMaterialItem
|
|
||||||
Dim i As Long, j As Long
|
|
||||||
Dim totalCount As Long
|
|
||||||
|
|
||||||
totalCount = 0
|
|
||||||
|
|
||||||
For i = 1 To rootCats.Count
|
|
||||||
Set cat = rootCats(i)
|
|
||||||
|
|
||||||
' 打印类别分隔符
|
|
||||||
Debug.Print ""
|
|
||||||
Debug.Print "【类别: " & cat.categoryName & "】"
|
|
||||||
Debug.Print String(40, "-")
|
|
||||||
|
|
||||||
' 默认使用父类别物料
|
|
||||||
Set Materials = bomMgr.GetMaterialsForPicking(cat.categoryName, True)
|
|
||||||
|
|
||||||
For j = 1 To Materials.Count
|
|
||||||
Set mat = Materials(j)
|
|
||||||
Debug.Print " " & mat.code & _
|
|
||||||
String(20 - Len(mat.code), " ") & _
|
|
||||||
mat.Name & _
|
|
||||||
" | 数量:" & mat.Quantity & _
|
|
||||||
" | 条件:" & IIf(mat.Condition = "", "(无)", mat.Condition)
|
|
||||||
totalCount = totalCount + 1
|
|
||||||
Next j
|
|
||||||
|
|
||||||
Debug.Print " 小计: " & Materials.Count & " 项"
|
|
||||||
Next i
|
|
||||||
|
|
||||||
' 打印汇总
|
|
||||||
Debug.Print ""
|
|
||||||
Debug.Print String(80, "=")
|
|
||||||
Debug.Print "总计: " & totalCount & " 项物料"
|
|
||||||
Debug.Print String(80, "=")
|
|
||||||
End Sub
|
|
||||||
|
|
||||||
' 示例: 查询特定物料信息
|
' 示例: 查询特定物料信息
|
||||||
Sub QueryMaterialInfo()
|
Sub QueryMaterialInfo()
|
||||||
Dim bomMgr As New clsBOMManager
|
Dim bomMgr As New clsBOMManager
|
||||||
@@ -214,15 +156,15 @@ Sub QueryMaterialInfo()
|
|||||||
If Not cat Is Nothing Then
|
If Not cat Is Nothing Then
|
||||||
Debug.Print "类别: " & cat.categoryName
|
Debug.Print "类别: " & cat.categoryName
|
||||||
Debug.Print "父类别: " & cat.ParentCategoryName
|
Debug.Print "父类别: " & cat.ParentCategoryName
|
||||||
Debug.Print "物料数: " & cat.Materials.Count
|
Debug.Print "物料数: " & cat.materials.Count
|
||||||
Debug.Print "子类别数: " & cat.SubCategories.Count
|
Debug.Print "子类别数: " & cat.SubCategories.Count
|
||||||
Debug.Print "是否叶子类别: " & cat.IsLeafCategory
|
Debug.Print "是否叶子类别: " & cat.IsLeafCategory
|
||||||
|
|
||||||
' 列出所有物料
|
' 列出所有物料
|
||||||
Dim mat As clsMaterialItem
|
Dim mat As clsMaterialItem
|
||||||
Dim i As Long
|
Dim i As Long
|
||||||
For i = 1 To cat.Materials.Count
|
For i = 1 To cat.materials.Count
|
||||||
Set mat = cat.Materials(i)
|
Set mat = cat.materials(i)
|
||||||
Debug.Print " - " & mat.code & ": " & mat.Name
|
Debug.Print " - " & mat.code & ": " & mat.Name
|
||||||
Next i
|
Next i
|
||||||
|
|
||||||
@@ -232,7 +174,7 @@ Sub QueryMaterialInfo()
|
|||||||
For j = 1 To cat.SubCategories.Count
|
For j = 1 To cat.SubCategories.Count
|
||||||
Set subCat = cat.SubCategories(j)
|
Set subCat = cat.SubCategories(j)
|
||||||
Debug.Print " 子类别: " & subCat.categoryName & _
|
Debug.Print " 子类别: " & subCat.categoryName & _
|
||||||
" (物料数:" & subCat.Materials.Count & ")"
|
" (物料数:" & subCat.materials.Count & ")"
|
||||||
Next j
|
Next j
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
375
VBA/Modules/modModelParserExamples.bas
Normal file
375
VBA/Modules/modModelParserExamples.bas
Normal file
@@ -0,0 +1,375 @@
|
|||||||
|
' ========================================
|
||||||
|
' 模块: modModelParserExamples
|
||||||
|
' 用途: 型号解析与物料匹配的实际应用示例
|
||||||
|
' ========================================
|
||||||
|
Option Explicit
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 示例1: 根据型号生成完整的领料清单
|
||||||
|
' ========================================
|
||||||
|
Sub Example1_GeneratePickingListByModel()
|
||||||
|
Dim bomMgr As New clsBOMManager
|
||||||
|
Dim wsConfig As Worksheet
|
||||||
|
Dim wsPlatform As Worksheet
|
||||||
|
|
||||||
|
' 加载配置
|
||||||
|
Set wsConfig = ThisWorkbook.Worksheets("领料配置")
|
||||||
|
Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单")
|
||||||
|
bomMgr.LoadData wsConfig, wsPlatform
|
||||||
|
|
||||||
|
' 产品型号
|
||||||
|
Dim modelStr As String
|
||||||
|
modelStr = "YTHN-100.A0.532.M203.M16.Y3|BP-095.2312.M16.PA3"
|
||||||
|
|
||||||
|
' 创建领料清单工作表
|
||||||
|
Dim wsPickList As Worksheet
|
||||||
|
On Error Resume Next
|
||||||
|
Application.DisplayAlerts = False
|
||||||
|
ThisWorkbook.Worksheets("型号领料清单").Delete
|
||||||
|
Application.DisplayAlerts = True
|
||||||
|
On Error GoTo 0
|
||||||
|
|
||||||
|
Set wsPickList = ThisWorkbook.Worksheets.Add
|
||||||
|
wsPickList.Name = "型号领料清单"
|
||||||
|
|
||||||
|
' 写入表头
|
||||||
|
Dim row As Long
|
||||||
|
row = 1
|
||||||
|
wsPickList.Cells(row, 1).value = "产品型号"
|
||||||
|
wsPickList.Cells(row, 2).value = modelStr
|
||||||
|
row = row + 1
|
||||||
|
|
||||||
|
' 提取条件并显示
|
||||||
|
Dim conditions As Object
|
||||||
|
Set conditions = bomMgr.ParseModelAndExtractConditions(modelStr)
|
||||||
|
wsPickList.Cells(row, 1).value = "提取条件"
|
||||||
|
Dim condStr As String
|
||||||
|
Dim key As Variant
|
||||||
|
For Each key In conditions.Keys
|
||||||
|
condStr = condStr & key & "=" & conditions(key) & "; "
|
||||||
|
Next key
|
||||||
|
wsPickList.Cells(row, 2).value = condStr
|
||||||
|
row = row + 2
|
||||||
|
|
||||||
|
' 表头
|
||||||
|
wsPickList.Cells(row, 1).value = "类别"
|
||||||
|
wsPickList.Cells(row, 2).value = "代号"
|
||||||
|
wsPickList.Cells(row, 3).value = "名称"
|
||||||
|
wsPickList.Cells(row, 4).value = "数量"
|
||||||
|
wsPickList.Cells(row, 5).value = "选择条件"
|
||||||
|
wsPickList.Cells(row, 6).value = "匹配状态"
|
||||||
|
wsPickList.Range("A" & row & ":F" & row).Font.Bold = True
|
||||||
|
row = row + 1
|
||||||
|
|
||||||
|
' 遍历所有根类别
|
||||||
|
Dim rootCats As collection
|
||||||
|
Set rootCats = bomMgr.GetRootCategories
|
||||||
|
|
||||||
|
Dim cat As clsCategory
|
||||||
|
Dim materials As collection
|
||||||
|
Dim mat As clsMaterialItem
|
||||||
|
Dim i As Long
|
||||||
|
|
||||||
|
For i = 1 To rootCats.Count
|
||||||
|
Set cat = rootCats(i)
|
||||||
|
|
||||||
|
' 获取该类别符合条件的物料
|
||||||
|
Set materials = bomMgr.GetMaterialsByModel(modelStr, cat.categoryName)
|
||||||
|
|
||||||
|
' 写入物料
|
||||||
|
Dim j As Long
|
||||||
|
For j = 1 To materials.Count
|
||||||
|
Set mat = materials(j)
|
||||||
|
wsPickList.Cells(row, 1).value = cat.categoryName
|
||||||
|
wsPickList.Cells(row, 2).value = mat.code
|
||||||
|
wsPickList.Cells(row, 3).value = mat.Name
|
||||||
|
wsPickList.Cells(row, 4).value = mat.Quantity
|
||||||
|
wsPickList.Cells(row, 5).value = IIf(mat.Condition = "", "(无条件)", mat.Condition)
|
||||||
|
wsPickList.Cells(row, 6).value = "?"
|
||||||
|
row = row + 1
|
||||||
|
Next j
|
||||||
|
Next i
|
||||||
|
|
||||||
|
' 格式化
|
||||||
|
wsPickList.Columns("A:F").AutoFit
|
||||||
|
|
||||||
|
MsgBox "领料清单生成完成!" & vbCrLf & _
|
||||||
|
"请查看工作表: 型号领料清单", vbInformation
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 示例2: 批量处理多个型号
|
||||||
|
' ========================================
|
||||||
|
Sub Example2_BatchProcessModels()
|
||||||
|
Dim bomMgr As New clsBOMManager
|
||||||
|
Dim wsConfig As Worksheet
|
||||||
|
Dim wsPlatform As Worksheet
|
||||||
|
|
||||||
|
' 加载配置
|
||||||
|
Set wsConfig = ThisWorkbook.Worksheets("领料配置")
|
||||||
|
Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单")
|
||||||
|
bomMgr.LoadData wsConfig, wsPlatform
|
||||||
|
|
||||||
|
' 型号列表
|
||||||
|
Dim models() As String
|
||||||
|
models = Split("YTHN-100.A0.532.M203.M16.Y3|BP-095.2312.M16.PA3," & _
|
||||||
|
"YTHN-100.A0.532.M203.M02.Y3|BP-095.2312.M02.PA3," & _
|
||||||
|
"YTHN-100.A0.532.M203.M12.Y3|BP-095.2312.M12.PA3", ",")
|
||||||
|
|
||||||
|
' 创建汇总表
|
||||||
|
Dim wsReport As Worksheet
|
||||||
|
On Error Resume Next
|
||||||
|
Application.DisplayAlerts = False
|
||||||
|
ThisWorkbook.Worksheets("批量型号汇总").Delete
|
||||||
|
Application.DisplayAlerts = True
|
||||||
|
On Error GoTo 0
|
||||||
|
|
||||||
|
Set wsReport = ThisWorkbook.Worksheets.Add
|
||||||
|
wsReport.Name = "批量型号汇总"
|
||||||
|
|
||||||
|
' 表头
|
||||||
|
Dim row As Long
|
||||||
|
row = 1
|
||||||
|
wsReport.Cells(row, 1).value = "型号"
|
||||||
|
wsReport.Cells(row, 2).value = "提取条件"
|
||||||
|
wsReport.Cells(row, 3).value = "匹配物料数"
|
||||||
|
wsReport.Cells(row, 4).value = "部件物料"
|
||||||
|
wsReport.Range("A1:D1").Font.Bold = True
|
||||||
|
row = row + 1
|
||||||
|
|
||||||
|
' 处理每个型号
|
||||||
|
Dim modelStr As String
|
||||||
|
Dim i As Long
|
||||||
|
|
||||||
|
For i = LBound(models) To UBound(models)
|
||||||
|
modelStr = Trim(models(i))
|
||||||
|
If modelStr <> "" Then
|
||||||
|
' 提取条件
|
||||||
|
Dim conditions As Object
|
||||||
|
Set conditions = bomMgr.ParseModelAndExtractConditions(modelStr)
|
||||||
|
|
||||||
|
Dim condStr As String
|
||||||
|
condStr = ""
|
||||||
|
Dim key As Variant
|
||||||
|
For Each key In conditions.Keys
|
||||||
|
condStr = condStr & key & "=" & conditions(key) & "; "
|
||||||
|
Next key
|
||||||
|
|
||||||
|
' 获取物料
|
||||||
|
Dim materials As collection
|
||||||
|
Set materials = bomMgr.GetMaterialsByModel(modelStr, "部件")
|
||||||
|
|
||||||
|
' 写入结果
|
||||||
|
wsReport.Cells(row, 1).value = modelStr
|
||||||
|
wsReport.Cells(row, 2).value = condStr
|
||||||
|
wsReport.Cells(row, 3).value = materials.Count
|
||||||
|
|
||||||
|
' 列出部件物料
|
||||||
|
Dim matList As String
|
||||||
|
matList = ""
|
||||||
|
Dim mat As clsMaterialItem
|
||||||
|
For Each mat In materials
|
||||||
|
matList = matList & mat.code & "(" & mat.Name & "); "
|
||||||
|
Next mat
|
||||||
|
wsReport.Cells(row, 4).value = matList
|
||||||
|
|
||||||
|
row = row + 1
|
||||||
|
End If
|
||||||
|
Next i
|
||||||
|
|
||||||
|
' 格式化
|
||||||
|
wsReport.Columns("A:D").AutoFit
|
||||||
|
|
||||||
|
MsgBox "批量处理完成!", vbInformation
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 示例3: 查询并显示某个型号的详细信息
|
||||||
|
' ========================================
|
||||||
|
Sub Example3_ShowModelDetails()
|
||||||
|
' 弹出输入框
|
||||||
|
Dim modelStr As String
|
||||||
|
modelStr = InputBox("请输入产品型号:", "型号查询", _
|
||||||
|
"YTHN-100.A0.532.M203.M16.Y3")
|
||||||
|
|
||||||
|
If modelStr = "" Then Exit Sub
|
||||||
|
|
||||||
|
' 解析型号
|
||||||
|
Dim parser As New clsModelParser
|
||||||
|
If Not parser.ParseModel(modelStr) Then
|
||||||
|
MsgBox "型号解析失败: " & parser.ErrorMessage, vbCritical
|
||||||
|
Exit Sub
|
||||||
|
End If
|
||||||
|
|
||||||
|
' 提取条件
|
||||||
|
Dim extractor As New clsConditionExtractor
|
||||||
|
Dim conditions As Object
|
||||||
|
Set conditions = extractor.ExtractConditions(parser)
|
||||||
|
|
||||||
|
' 显示详细信息
|
||||||
|
Dim msg As String
|
||||||
|
msg = "【型号解析结果】" & vbCrLf & vbCrLf
|
||||||
|
msg = msg & "原始型号: " & parser.RawModel & vbCrLf
|
||||||
|
msg = msg & "表头型号: " & parser.HeaderModel & vbCrLf
|
||||||
|
msg = msg & "表盘型号: " & parser.DialModel & vbCrLf & vbCrLf
|
||||||
|
|
||||||
|
msg = msg & "【表头各部分】" & vbCrLf
|
||||||
|
msg = msg & "型号: " & parser.ModelType & vbCrLf
|
||||||
|
msg = msg & "公称外径: " & parser.Diameter & vbCrLf
|
||||||
|
msg = msg & "安装形式: " & parser.InstallForm & vbCrLf
|
||||||
|
msg = msg & "壳体形式: " & parser.ShellForm & vbCrLf
|
||||||
|
msg = msg & "过程连接&材质: " & parser.ConnectionCode & vbCrLf
|
||||||
|
msg = msg & "量程范围: " & parser.RangeCode & vbCrLf
|
||||||
|
msg = msg & "仪表特性: " & parser.Characteristics & vbCrLf & vbCrLf
|
||||||
|
|
||||||
|
msg = msg & "【提取的物料选择条件】" & vbCrLf
|
||||||
|
Dim key As Variant
|
||||||
|
For Each key In conditions.Keys
|
||||||
|
msg = msg & key & " = " & conditions(key) & vbCrLf
|
||||||
|
Next key
|
||||||
|
|
||||||
|
MsgBox msg, vbInformation, "型号详细信息"
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 示例4: 对比两个型号的差异
|
||||||
|
' ========================================
|
||||||
|
Sub Example4_CompareModels()
|
||||||
|
Dim model1 As String, model2 As String
|
||||||
|
|
||||||
|
model1 = InputBox("请输入第一个型号:", "型号对比", _
|
||||||
|
"YTHN-100.A0.532.M203.M16.Y3")
|
||||||
|
If model1 = "" Then Exit Sub
|
||||||
|
|
||||||
|
model2 = InputBox("请输入第二个型号:", "型号对比", _
|
||||||
|
"YTHN-100.A0.532.M203.M02.Y3")
|
||||||
|
If model2 = "" Then Exit Sub
|
||||||
|
|
||||||
|
' 解析两个型号
|
||||||
|
Dim parser1 As New clsModelParser
|
||||||
|
Dim parser2 As New clsModelParser
|
||||||
|
Dim extractor As New clsConditionExtractor
|
||||||
|
|
||||||
|
parser1.ParseModel model1
|
||||||
|
parser2.ParseModel model2
|
||||||
|
|
||||||
|
Dim cond1 As Object, cond2 As Object
|
||||||
|
Set cond1 = extractor.ExtractConditions(parser1)
|
||||||
|
|
||||||
|
Set extractor = New clsConditionExtractor
|
||||||
|
Set cond2 = extractor.ExtractConditions(parser2)
|
||||||
|
|
||||||
|
' 对比
|
||||||
|
Dim msg As String
|
||||||
|
msg = "【型号对比】" & vbCrLf & vbCrLf
|
||||||
|
msg = msg & "型号1: " & model1 & vbCrLf
|
||||||
|
msg = msg & "型号2: " & model2 & vbCrLf & vbCrLf
|
||||||
|
|
||||||
|
msg = msg & "【条件差异】" & vbCrLf
|
||||||
|
Dim key As Variant
|
||||||
|
Dim allKeys As Object
|
||||||
|
Set allKeys = CreateObject("Scripting.Dictionary")
|
||||||
|
|
||||||
|
For Each key In cond1.Keys
|
||||||
|
allKeys(key) = True
|
||||||
|
Next key
|
||||||
|
For Each key In cond2.Keys
|
||||||
|
allKeys(key) = True
|
||||||
|
Next key
|
||||||
|
|
||||||
|
For Each key In allKeys.Keys
|
||||||
|
Dim val1 As String, val2 As String
|
||||||
|
val1 = ""
|
||||||
|
val2 = ""
|
||||||
|
|
||||||
|
If cond1.Exists(key) Then val1 = cond1(key)
|
||||||
|
If cond2.Exists(key) Then val2 = cond2(key)
|
||||||
|
|
||||||
|
If val1 <> val2 Then
|
||||||
|
msg = msg & key & ": " & val1 & " → " & val2 & " ?" & vbCrLf
|
||||||
|
Else
|
||||||
|
msg = msg & key & ": " & val1 & " ?" & vbCrLf
|
||||||
|
End If
|
||||||
|
Next key
|
||||||
|
|
||||||
|
MsgBox msg, vbInformation, "型号对比结果"
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 示例5: 验证物料选择条件的有效性
|
||||||
|
' ========================================
|
||||||
|
Sub Example5_ValidateMaterialConditions()
|
||||||
|
Dim bomMgr As New clsBOMManager
|
||||||
|
Dim wsConfig As Worksheet
|
||||||
|
Dim wsPlatform As Worksheet
|
||||||
|
|
||||||
|
' 加载配置
|
||||||
|
Set wsConfig = ThisWorkbook.Worksheets("领料配置")
|
||||||
|
Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单")
|
||||||
|
bomMgr.LoadData wsConfig, wsPlatform
|
||||||
|
|
||||||
|
' 创建验证结果表
|
||||||
|
Dim wsValidation As Worksheet
|
||||||
|
On Error Resume Next
|
||||||
|
Application.DisplayAlerts = False
|
||||||
|
ThisWorkbook.Worksheets("条件验证结果").Delete
|
||||||
|
Application.DisplayAlerts = True
|
||||||
|
On Error GoTo 0
|
||||||
|
|
||||||
|
Set wsValidation = ThisWorkbook.Worksheets.Add
|
||||||
|
wsValidation.Name = "条件验证结果"
|
||||||
|
|
||||||
|
' 表头
|
||||||
|
Dim row As Long
|
||||||
|
row = 1
|
||||||
|
wsValidation.Cells(row, 1).value = "代号"
|
||||||
|
wsValidation.Cells(row, 2).value = "名称"
|
||||||
|
wsValidation.Cells(row, 3).value = "选择条件"
|
||||||
|
wsValidation.Cells(row, 4).value = "验证结果"
|
||||||
|
wsValidation.Range("A1:D1").Font.Bold = True
|
||||||
|
row = row + 1
|
||||||
|
|
||||||
|
' 获取所有根类别
|
||||||
|
Dim rootCats As collection
|
||||||
|
Set rootCats = bomMgr.GetRootCategories
|
||||||
|
|
||||||
|
Dim cat As clsCategory
|
||||||
|
Dim materials As collection
|
||||||
|
Dim mat As clsMaterialItem
|
||||||
|
Dim matcher As New clsConditionMatcher
|
||||||
|
Dim i As Long
|
||||||
|
|
||||||
|
' 遍历所有物料
|
||||||
|
For i = 1 To rootCats.Count
|
||||||
|
Set cat = rootCats(i)
|
||||||
|
Set materials = New collection
|
||||||
|
|
||||||
|
' 收集该类别的所有物料
|
||||||
|
Dim j As Long
|
||||||
|
For j = 1 To cat.materials.Count
|
||||||
|
materials.Add cat.materials(j)
|
||||||
|
Next j
|
||||||
|
|
||||||
|
' 验证每个物料的条件
|
||||||
|
For Each mat In materials
|
||||||
|
wsValidation.Cells(row, 1).value = mat.code
|
||||||
|
wsValidation.Cells(row, 2).value = mat.Name
|
||||||
|
wsValidation.Cells(row, 3).value = IIf(mat.Condition = "", "(无)", mat.Condition)
|
||||||
|
|
||||||
|
If mat.Condition = "" Then
|
||||||
|
wsValidation.Cells(row, 4).value = "? 无条件"
|
||||||
|
Else
|
||||||
|
Dim validResult As String
|
||||||
|
validResult = matcher.TestExpression(mat.Condition)
|
||||||
|
wsValidation.Cells(row, 4).value = validResult
|
||||||
|
End If
|
||||||
|
|
||||||
|
row = row + 1
|
||||||
|
Next mat
|
||||||
|
Next i
|
||||||
|
|
||||||
|
' 格式化
|
||||||
|
wsValidation.Columns("A:D").AutoFit
|
||||||
|
|
||||||
|
MsgBox "条件验证完成!", vbInformation
|
||||||
|
End Sub
|
||||||
309
VBA/Modules/modModelParserTest.bas
Normal file
309
VBA/Modules/modModelParserTest.bas
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
' ========================================
|
||||||
|
' 模块: modModelParserTest
|
||||||
|
' 用途: 测试型号解析和物料匹配功能
|
||||||
|
' ========================================
|
||||||
|
Option Explicit
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 测试1: 型号解析器基础功能
|
||||||
|
' ========================================
|
||||||
|
Sub Test1_ModelParser()
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
Debug.Print "测试1: 型号解析器基础功能"
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
|
||||||
|
Dim parser As New clsModelParser
|
||||||
|
Dim modelStr As String
|
||||||
|
|
||||||
|
' 测试用例1: 完整型号
|
||||||
|
modelStr = "YTHN-100.A0.532.M203.M16.Y3|BP-095.2312.M16.PA3"
|
||||||
|
Debug.Print "【测试用例1】完整型号"
|
||||||
|
Debug.Print "输入: " & modelStr
|
||||||
|
|
||||||
|
If parser.ParseModel(modelStr) Then
|
||||||
|
Debug.Print parser.ToString()
|
||||||
|
Debug.Print "? 解析成功"
|
||||||
|
Else
|
||||||
|
Debug.Print "? 解析失败: " & parser.ErrorMessage
|
||||||
|
End If
|
||||||
|
|
||||||
|
Debug.Print ""
|
||||||
|
|
||||||
|
' 测试用例2: 仅表头
|
||||||
|
modelStr = "YTHN-100.A0.532.M203.M16.Y3"
|
||||||
|
Debug.Print "【测试用例2】仅表头"
|
||||||
|
Debug.Print "输入: " & modelStr
|
||||||
|
|
||||||
|
If parser.ParseModel(modelStr) Then
|
||||||
|
Debug.Print " 螺纹代码: " & parser.GetThreadCode()
|
||||||
|
Debug.Print " 材质代码: " & parser.GetMaterialCode()
|
||||||
|
Debug.Print " 量程代码: " & parser.GetRangeCode()
|
||||||
|
Debug.Print "? 解析成功"
|
||||||
|
Else
|
||||||
|
Debug.Print "? 解析失败: " & parser.ErrorMessage
|
||||||
|
End If
|
||||||
|
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
Debug.Print ""
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 测试2: 条件提取器
|
||||||
|
' ========================================
|
||||||
|
Sub Test2_ConditionExtractor()
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
Debug.Print "测试2: 条件提取器"
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
|
||||||
|
Dim parser As New clsModelParser
|
||||||
|
Dim extractor As New clsConditionExtractor
|
||||||
|
Dim modelStr As String
|
||||||
|
|
||||||
|
modelStr = "YTHN-100.A0.532.M203.M16.Y3"
|
||||||
|
Debug.Print "输入型号: " & modelStr
|
||||||
|
|
||||||
|
If parser.ParseModel(modelStr) Then
|
||||||
|
Dim conditions As Object
|
||||||
|
Set conditions = extractor.ExtractConditions(parser)
|
||||||
|
|
||||||
|
Debug.Print extractor.ToString()
|
||||||
|
|
||||||
|
' 验证提取结果
|
||||||
|
Debug.Print "【验证】"
|
||||||
|
Debug.Print " gclj = " & extractor.GetConditionValue("gclj") & _
|
||||||
|
IIf(extractor.GetConditionValue("gclj") = "M20", " ?", " ?")
|
||||||
|
Debug.Print " jycz = " & extractor.GetConditionValue("jycz") & _
|
||||||
|
IIf(extractor.GetConditionValue("jycz") = "3", " ?", " ?")
|
||||||
|
Debug.Print " lcfw = " & extractor.GetConditionValue("lcfw") & _
|
||||||
|
IIf(extractor.GetConditionValue("lcfw") = "M16", " ?", " ?")
|
||||||
|
Else
|
||||||
|
Debug.Print "? 型号解析失败"
|
||||||
|
End If
|
||||||
|
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
Debug.Print ""
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 测试3: 条件匹配器
|
||||||
|
' ========================================
|
||||||
|
Sub Test3_ConditionMatcher()
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
Debug.Print "测试3: 条件匹配器"
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
|
||||||
|
Dim matcher As New clsConditionMatcher
|
||||||
|
Dim conditions As Object
|
||||||
|
Set conditions = CreateObject("Scripting.Dictionary")
|
||||||
|
conditions("gclj") = "M20"
|
||||||
|
conditions("jycz") = "3"
|
||||||
|
conditions("lcfw") = "M16"
|
||||||
|
|
||||||
|
Debug.Print "【测试条件】"
|
||||||
|
Debug.Print " gclj = M20"
|
||||||
|
Debug.Print " jycz = 3"
|
||||||
|
Debug.Print " lcfw = M16"
|
||||||
|
Debug.Print ""
|
||||||
|
|
||||||
|
' 测试用例
|
||||||
|
Dim testCases As Variant
|
||||||
|
testCases = Array( _
|
||||||
|
Array("", True, "空条件"), _
|
||||||
|
Array("lcfw=M16", True, "简单等于"), _
|
||||||
|
Array("lcfw=M17", False, "简单不匹配"), _
|
||||||
|
Array("lcfw=M16 AND gclj=M20", True, "AND 全真"), _
|
||||||
|
Array("lcfw=M16 AND gclj=M10", False, "AND 一假"), _
|
||||||
|
Array("lcfw=M16 OR lcfw=M17", True, "OR 一真"), _
|
||||||
|
Array("lcfw=M15 OR lcfw=M17", False, "OR 全假"), _
|
||||||
|
Array("gclj!=M10", True, "不等于 真"), _
|
||||||
|
Array("gclj!=M20", False, "不等于 假"), _
|
||||||
|
Array("lcfw=M02 AND gclj!=M20", False, "复合条件1"), _
|
||||||
|
Array("lcfw=M16 AND gclj!=M10", True, "复合条件2"), _
|
||||||
|
Array("gclj=M20 AND (lcfw=M16 OR lcfw=M17)", True, "括号优先级1"), _
|
||||||
|
Array("gclj=M20 AND (lcfw=M15 OR lcfw=M17)", False, "括号优先级2") _
|
||||||
|
)
|
||||||
|
|
||||||
|
Dim i As Long
|
||||||
|
Dim testCase As Variant
|
||||||
|
Dim expr As String
|
||||||
|
Dim expected As Boolean
|
||||||
|
Dim actual As Boolean
|
||||||
|
Dim description As String
|
||||||
|
Dim passCount As Long
|
||||||
|
Dim failCount As Long
|
||||||
|
|
||||||
|
passCount = 0
|
||||||
|
failCount = 0
|
||||||
|
|
||||||
|
Debug.Print "【测试用例】"
|
||||||
|
For i = LBound(testCases) To UBound(testCases)
|
||||||
|
testCase = testCases(i)
|
||||||
|
expr = testCase(0)
|
||||||
|
expected = testCase(1)
|
||||||
|
description = testCase(2)
|
||||||
|
|
||||||
|
actual = matcher.IsMatch(expr, conditions)
|
||||||
|
|
||||||
|
If actual = expected Then
|
||||||
|
Debug.Print " ? " & description & ": " & IIf(expr = "", "(空)", expr)
|
||||||
|
passCount = passCount + 1
|
||||||
|
Else
|
||||||
|
Debug.Print " ? " & description & ": " & expr
|
||||||
|
Debug.Print " 预期: " & expected & ", 实际: " & actual
|
||||||
|
failCount = failCount + 1
|
||||||
|
End If
|
||||||
|
Next i
|
||||||
|
|
||||||
|
Debug.Print ""
|
||||||
|
Debug.Print "【统计】"
|
||||||
|
Debug.Print " 通过: " & passCount
|
||||||
|
Debug.Print " 失败: " & failCount
|
||||||
|
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
Debug.Print ""
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 测试4: 完整流程 - 根据型号获取物料
|
||||||
|
' ========================================
|
||||||
|
Sub Test4_GetMaterialsByModel()
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
Debug.Print "测试4: 根据型号获取物料(完整流程)"
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
|
||||||
|
' 加载BOM数据
|
||||||
|
Dim bomMgr As New clsBOMManager
|
||||||
|
Dim wsConfig As Worksheet
|
||||||
|
Dim wsPlatform As Worksheet
|
||||||
|
|
||||||
|
On Error Resume Next
|
||||||
|
Set wsConfig = ThisWorkbook.Worksheets("领料配置")
|
||||||
|
Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单")
|
||||||
|
On Error GoTo 0
|
||||||
|
|
||||||
|
If wsConfig Is Nothing Or wsPlatform Is Nothing Then
|
||||||
|
Debug.Print "? 错误: 找不到必需的工作表"
|
||||||
|
Exit Sub
|
||||||
|
End If
|
||||||
|
|
||||||
|
bomMgr.LoadData wsConfig, wsPlatform
|
||||||
|
Debug.Print "? BOM数据加载完成"
|
||||||
|
Debug.Print ""
|
||||||
|
|
||||||
|
' 测试型号
|
||||||
|
Dim modelStr As String
|
||||||
|
modelStr = "YTHN-100.A0.532.M203.M16.Y3|BP-095.2312.M16.PA3"
|
||||||
|
|
||||||
|
' 获取"部件"类别的符合条件的物料
|
||||||
|
Dim materials As collection
|
||||||
|
Set materials = bomMgr.GetMaterialsByModel(modelStr, "部件")
|
||||||
|
|
||||||
|
Debug.Print ""
|
||||||
|
Debug.Print "【结果验证】"
|
||||||
|
If materials.Count = 1 Then
|
||||||
|
Dim mat As clsMaterialItem
|
||||||
|
Set mat = materials(1)
|
||||||
|
If mat.code = "01011019018" And mat.Name = "高压接头部件" Then
|
||||||
|
Debug.Print "? 测试通过!成功匹配到正确的物料"
|
||||||
|
Debug.Print " 代号: " & mat.code
|
||||||
|
Debug.Print " 名称: " & mat.Name
|
||||||
|
Debug.Print " 条件: " & mat.Condition
|
||||||
|
Else
|
||||||
|
Debug.Print "? 匹配到的物料不正确"
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
Debug.Print "? 匹配数量不正确,预期1个,实际" & materials.Count & "个"
|
||||||
|
End If
|
||||||
|
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
Debug.Print ""
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 测试5: 获取所有类别的符合条件的物料
|
||||||
|
' ========================================
|
||||||
|
Sub Test5_GetAllMaterialsByModel()
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
Debug.Print "测试5: 获取所有类别的符合条件的物料"
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
|
||||||
|
' 加载BOM数据
|
||||||
|
Dim bomMgr As New clsBOMManager
|
||||||
|
Dim wsConfig As Worksheet
|
||||||
|
Dim wsPlatform As Worksheet
|
||||||
|
|
||||||
|
On Error Resume Next
|
||||||
|
Set wsConfig = ThisWorkbook.Worksheets("领料配置")
|
||||||
|
Set wsPlatform = ThisWorkbook.Worksheets("平台配置清单")
|
||||||
|
On Error GoTo 0
|
||||||
|
|
||||||
|
If wsConfig Is Nothing Or wsPlatform Is Nothing Then
|
||||||
|
Debug.Print "? 错误: 找不到必需的工作表"
|
||||||
|
Exit Sub
|
||||||
|
End If
|
||||||
|
|
||||||
|
bomMgr.LoadData wsConfig, wsPlatform
|
||||||
|
|
||||||
|
' 测试型号
|
||||||
|
Dim modelStr As String
|
||||||
|
modelStr = "YTHN-100.A0.532.M203.M16.Y3"
|
||||||
|
|
||||||
|
' 获取所有类别的符合条件的物料
|
||||||
|
Dim materials As collection
|
||||||
|
Set materials = bomMgr.GetMaterialsByModel(modelStr)
|
||||||
|
|
||||||
|
Debug.Print ""
|
||||||
|
Debug.Print "【匹配结果汇总】"
|
||||||
|
Debug.Print " 共匹配 " & materials.Count & " 个物料"
|
||||||
|
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
Debug.Print ""
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 运行所有测试
|
||||||
|
' ========================================
|
||||||
|
Sub RunAllTests()
|
||||||
|
Debug.Print vbCrLf & vbCrLf
|
||||||
|
Debug.Print "╔" & String(78, "═") & "╗"
|
||||||
|
Debug.Print "║" & Space(20) & "型号解析与物料匹配 - 完整测试套件" & Space(20) & "║"
|
||||||
|
Debug.Print "╚" & String(78, "═") & "╝"
|
||||||
|
Debug.Print ""
|
||||||
|
|
||||||
|
Test1_ModelParser
|
||||||
|
Test2_ConditionExtractor
|
||||||
|
Test3_ConditionMatcher
|
||||||
|
Test4_GetMaterialsByModel
|
||||||
|
Test5_GetAllMaterialsByModel
|
||||||
|
|
||||||
|
Debug.Print "╔" & String(78, "═") & "╗"
|
||||||
|
Debug.Print "║" & Space(30) & "所有测试完成" & Space(30) & "║"
|
||||||
|
Debug.Print "╚" & String(78, "═") & "╝"
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' ========================================
|
||||||
|
' 测试6: 条件提取规则展示
|
||||||
|
' ========================================
|
||||||
|
Sub Test6_ShowExtractionRules()
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
Debug.Print "测试6: 当前配置的条件提取规则"
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
|
||||||
|
Dim extractor As New clsConditionExtractor
|
||||||
|
Dim rules As Object
|
||||||
|
Set rules = extractor.GetExtractionRules()
|
||||||
|
|
||||||
|
Debug.Print "【提取规则配置】"
|
||||||
|
Dim key As Variant
|
||||||
|
For Each key In rules.Keys
|
||||||
|
Dim ruleInfo As Variant
|
||||||
|
ruleInfo = rules(key)
|
||||||
|
Debug.Print " 变量名: " & key
|
||||||
|
Debug.Print " 源字段: " & ruleInfo(0)
|
||||||
|
Debug.Print " 提取方法: " & ruleInfo(1)
|
||||||
|
Debug.Print ""
|
||||||
|
Next key
|
||||||
|
|
||||||
|
Debug.Print String(80, "=")
|
||||||
|
Debug.Print ""
|
||||||
|
End Sub
|
||||||
@@ -31,12 +31,6 @@
|
|||||||
"attributes": {},
|
"attributes": {},
|
||||||
"file": "DocumentModules\\Sheet4.cls"
|
"file": "DocumentModules\\Sheet4.cls"
|
||||||
},
|
},
|
||||||
"Sheet6.cls": {
|
|
||||||
"name": "Sheet6",
|
|
||||||
"type": "DocumentModules",
|
|
||||||
"attributes": {},
|
|
||||||
"file": "DocumentModules\\Sheet6.cls"
|
|
||||||
},
|
|
||||||
"clsCategory.cls": {
|
"clsCategory.cls": {
|
||||||
"name": "clsCategory",
|
"name": "clsCategory",
|
||||||
"type": "ClassModules",
|
"type": "ClassModules",
|
||||||
@@ -60,6 +54,42 @@
|
|||||||
"type": "ClassModules",
|
"type": "ClassModules",
|
||||||
"attributes": {},
|
"attributes": {},
|
||||||
"file": "ClassModules\\clsBOMManager.cls"
|
"file": "ClassModules\\clsBOMManager.cls"
|
||||||
|
},
|
||||||
|
"Sheet6.cls": {
|
||||||
|
"name": "Sheet6",
|
||||||
|
"type": "DocumentModules",
|
||||||
|
"attributes": {},
|
||||||
|
"file": "DocumentModules\\Sheet6.cls"
|
||||||
|
},
|
||||||
|
"clsModelParser.cls": {
|
||||||
|
"name": "clsModelParser",
|
||||||
|
"type": "ClassModules",
|
||||||
|
"attributes": {},
|
||||||
|
"file": "ClassModules\\clsModelParser.cls"
|
||||||
|
},
|
||||||
|
"clsConditionExtractor.cls": {
|
||||||
|
"name": "clsConditionExtractor",
|
||||||
|
"type": "ClassModules",
|
||||||
|
"attributes": {},
|
||||||
|
"file": "ClassModules\\clsConditionExtractor.cls"
|
||||||
|
},
|
||||||
|
"clsConditionMatcher.cls": {
|
||||||
|
"name": "clsConditionMatcher",
|
||||||
|
"type": "ClassModules",
|
||||||
|
"attributes": {},
|
||||||
|
"file": "ClassModules\\clsConditionMatcher.cls"
|
||||||
|
},
|
||||||
|
"modModelParserTest.bas": {
|
||||||
|
"name": "modModelParserTest",
|
||||||
|
"type": "Modules",
|
||||||
|
"attributes": {},
|
||||||
|
"file": "Modules\\modModelParserTest.bas"
|
||||||
|
},
|
||||||
|
"modModelParserExamples.bas": {
|
||||||
|
"name": "modModelParserExamples",
|
||||||
|
"type": "Modules",
|
||||||
|
"attributes": {},
|
||||||
|
"file": "Modules\\modModelParserExamples.bas"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
428
型号解析与物料匹配系统 - 使用说明.md
Normal file
428
型号解析与物料匹配系统 - 使用说明.md
Normal file
@@ -0,0 +1,428 @@
|
|||||||
|
# 型号解析与物料匹配系统 - 使用说明
|
||||||
|
|
||||||
|
## 📋 目录
|
||||||
|
|
||||||
|
1. [系统概述](#系统概述)
|
||||||
|
2. [安装部署](#安装部署)
|
||||||
|
3. [快速开始](#快速开始)
|
||||||
|
4. [详细使用](#详细使用)
|
||||||
|
5. [API参考](#api参考)
|
||||||
|
6. [扩展指南](#扩展指南)
|
||||||
|
7. [常见问题](#常见问题)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 系统概述
|
||||||
|
|
||||||
|
### 功能简介
|
||||||
|
|
||||||
|
本系统实现了从产品型号中自动提取物料选择条件,并根据这些条件从BOM库中筛选出符合要求的物料清单。
|
||||||
|
|
||||||
|
### 核心功能
|
||||||
|
|
||||||
|
- ✅ **型号解析**: 自动解析产品型号的各个组成部分
|
||||||
|
- ✅ **条件提取**: 按规则提取物料选择条件(过程连接、接液材质、量程范围等)
|
||||||
|
- ✅ **条件匹配**: 支持复杂的逻辑表达式(AND/OR/NOT/括号)
|
||||||
|
- ✅ **物料筛选**: 自动筛选符合条件的物料
|
||||||
|
- ✅ **批量处理**: 支持批量处理多个型号
|
||||||
|
- ✅ **可扩展性**: 便于添加新的提取条件和匹配规则
|
||||||
|
|
||||||
|
### 示例
|
||||||
|
|
||||||
|
**输入型号**: `YTHN-100.A0.532.M203.M16.Y3|BP-095.2312.M16.PA3`
|
||||||
|
|
||||||
|
**提取条件**:
|
||||||
|
- `gclj` (过程连接) = `M20`
|
||||||
|
- `jycz` (接液材质) = `3`
|
||||||
|
- `lcfw` (量程范围) = `M16`
|
||||||
|
|
||||||
|
**匹配结果**: `01011019018 - 高压接头部件`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 安装部署
|
||||||
|
|
||||||
|
### 1. 导入类模块
|
||||||
|
|
||||||
|
将以下4个类模块文件导入到VBA项目中:
|
||||||
|
|
||||||
|
1. **clsModelParser.cls** - 型号解析器
|
||||||
|
2. **clsConditionExtractor.cls** - 条件提取器
|
||||||
|
3. **clsConditionMatcher.cls** - 条件匹配器
|
||||||
|
4. **clsBOMManager.cls** - BOM管理器(扩展版本)
|
||||||
|
|
||||||
|
### 2. 导入标准模块
|
||||||
|
|
||||||
|
将以下2个标准模块导入到VBA项目中:
|
||||||
|
|
||||||
|
1. **modModelParserTest.bas** - 测试模块
|
||||||
|
2. **modModelParserExamples.bas** - 应用示例模块
|
||||||
|
|
||||||
|
### 3. 验证安装
|
||||||
|
|
||||||
|
运行测试过程验证安装是否成功:
|
||||||
|
|
||||||
|
```vba
|
||||||
|
' 在立即窗口或通过运行按钮执行
|
||||||
|
RunAllTests
|
||||||
|
```
|
||||||
|
|
||||||
|
如果所有测试通过,说明安装成功!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 最简单的使用方式
|
||||||
|
|
||||||
|
```vba
|
||||||
|
Sub QuickStart()
|
||||||
|
' 1. 创建BOM管理器并加载数据
|
||||||
|
Dim bomMgr As New clsBOMManager
|
||||||
|
bomMgr.LoadData ThisWorkbook.Worksheets("领料配置"), _
|
||||||
|
ThisWorkbook.Worksheets("平台配置清单")
|
||||||
|
|
||||||
|
' 2. 根据型号获取物料
|
||||||
|
Dim modelStr As String
|
||||||
|
modelStr = "YTHN-100.A0.532.M203.M16.Y3"
|
||||||
|
|
||||||
|
Dim materials As Collection
|
||||||
|
Set materials = bomMgr.GetMaterialsByModel(modelStr, "部件")
|
||||||
|
|
||||||
|
' 3. 查看结果
|
||||||
|
Dim mat As clsMaterialItem
|
||||||
|
For Each mat In materials
|
||||||
|
Debug.Print mat.Code & " - " & mat.Name
|
||||||
|
Next mat
|
||||||
|
End Sub
|
||||||
|
```
|
||||||
|
|
||||||
|
### 生成领料清单
|
||||||
|
|
||||||
|
运行以下示例生成完整的领料清单:
|
||||||
|
|
||||||
|
```vba
|
||||||
|
Example1_GeneratePickingListByModel
|
||||||
|
```
|
||||||
|
|
||||||
|
这将创建一个新工作表,包含完整的领料清单。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 详细使用
|
||||||
|
|
||||||
|
### 1. 型号解析
|
||||||
|
|
||||||
|
#### 基础解析
|
||||||
|
|
||||||
|
```vba
|
||||||
|
Dim parser As New clsModelParser
|
||||||
|
Dim modelStr As String
|
||||||
|
modelStr = "YTHN-100.A0.532.M203.M16.Y3|BP-095.2312.M16.PA3"
|
||||||
|
|
||||||
|
If parser.ParseModel(modelStr) Then
|
||||||
|
' 解析成功
|
||||||
|
Debug.Print "型号: " & parser.ModelType ' YTHN
|
||||||
|
Debug.Print "外径: " & parser.Diameter ' 100
|
||||||
|
Debug.Print "过程连接: " & parser.ConnectionCode ' M203
|
||||||
|
Debug.Print "量程: " & parser.RangeCode ' M16
|
||||||
|
Else
|
||||||
|
' 解析失败
|
||||||
|
Debug.Print "错误: " & parser.ErrorMessage
|
||||||
|
End If
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 获取提取的代码
|
||||||
|
|
||||||
|
```vba
|
||||||
|
Debug.Print "螺纹代码: " & parser.GetThreadCode() ' M20
|
||||||
|
Debug.Print "材质代码: " & parser.GetMaterialCode() ' 3
|
||||||
|
Debug.Print "量程代码: " & parser.GetRangeCode() ' M16
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 条件提取
|
||||||
|
|
||||||
|
```vba
|
||||||
|
Dim parser As New clsModelParser
|
||||||
|
parser.ParseModel "YTHN-100.A0.532.M203.M16.Y3"
|
||||||
|
|
||||||
|
Dim extractor As New clsConditionExtractor
|
||||||
|
Dim conditions As Object
|
||||||
|
Set conditions = extractor.ExtractConditions(parser)
|
||||||
|
|
||||||
|
' 获取单个条件
|
||||||
|
Debug.Print "过程连接: " & extractor.GetConditionValue("gclj") ' M20
|
||||||
|
Debug.Print "接液材质: " & extractor.GetConditionValue("jycz") ' 3
|
||||||
|
Debug.Print "量程范围: " & extractor.GetConditionValue("lcfw") ' M16
|
||||||
|
|
||||||
|
' 遍历所有条件
|
||||||
|
Dim key As Variant
|
||||||
|
For Each key In conditions.Keys
|
||||||
|
Debug.Print key & " = " & conditions(key)
|
||||||
|
Next key
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 条件匹配
|
||||||
|
|
||||||
|
#### 简单条件
|
||||||
|
|
||||||
|
```vba
|
||||||
|
Dim matcher As New clsConditionMatcher
|
||||||
|
Dim conditions As Object
|
||||||
|
Set conditions = CreateObject("Scripting.Dictionary")
|
||||||
|
conditions("gclj") = "M20"
|
||||||
|
conditions("lcfw") = "M16"
|
||||||
|
|
||||||
|
' 等于
|
||||||
|
Debug.Print matcher.IsMatch("lcfw=M16", conditions) ' True
|
||||||
|
|
||||||
|
' 不等于
|
||||||
|
Debug.Print matcher.IsMatch("gclj!=M10", conditions) ' True
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 复合条件
|
||||||
|
|
||||||
|
```vba
|
||||||
|
' AND 运算
|
||||||
|
Debug.Print matcher.IsMatch("lcfw=M16 AND gclj=M20", conditions) ' True
|
||||||
|
|
||||||
|
' OR 运算
|
||||||
|
Debug.Print matcher.IsMatch("lcfw=M16 OR lcfw=M17", conditions) ' True
|
||||||
|
|
||||||
|
' 括号优先级
|
||||||
|
Debug.Print matcher.IsMatch("gclj=M20 AND (lcfw=M16 OR lcfw=M17)", conditions) ' True
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 获取物料清单
|
||||||
|
|
||||||
|
#### 指定类别
|
||||||
|
|
||||||
|
```vba
|
||||||
|
Dim bomMgr As New clsBOMManager
|
||||||
|
bomMgr.LoadData wsConfig, wsPlatform
|
||||||
|
|
||||||
|
' 获取"部件"类别的符合条件的物料
|
||||||
|
Dim materials As Collection
|
||||||
|
Set materials = bomMgr.GetMaterialsByModel("YTHN-100.A0.532.M203.M16.Y3", "部件")
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 所有类别
|
||||||
|
|
||||||
|
```vba
|
||||||
|
' 获取所有类别的符合条件的物料
|
||||||
|
Set materials = bomMgr.GetMaterialsByModel("YTHN-100.A0.532.M203.M16.Y3")
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 使用父类别/子类别逻辑
|
||||||
|
|
||||||
|
```vba
|
||||||
|
' 使用父类别物料(默认)
|
||||||
|
Set materials = bomMgr.GetMaterialsByCategoryAndModel( _
|
||||||
|
"YTHN-100.A0.532.M203.M16.Y3", "部件", True)
|
||||||
|
|
||||||
|
' 使用子类别物料(库存不足时)
|
||||||
|
Set materials = bomMgr.GetMaterialsByCategoryAndModel( _
|
||||||
|
"YTHN-100.A0.532.M203.M16.Y3", "部件", False)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API参考
|
||||||
|
|
||||||
|
### clsModelParser
|
||||||
|
|
||||||
|
| 方法/属性 | 说明 | 返回类型 |
|
||||||
|
|---------|------|---------|
|
||||||
|
| `ParseModel(modelStr)` | 解析型号字符串 | Boolean |
|
||||||
|
| `GetThreadCode()` | 获取螺纹代码 | String |
|
||||||
|
| `GetMaterialCode()` | 获取材质代码 | String |
|
||||||
|
| `GetRangeCode()` | 获取量程代码 | String |
|
||||||
|
| `IsValid` | 解析是否成功 | Boolean |
|
||||||
|
| `ErrorMessage` | 错误信息 | String |
|
||||||
|
| `ToString()` | 返回解析结果(调试用) | String |
|
||||||
|
|
||||||
|
### clsConditionExtractor
|
||||||
|
|
||||||
|
| 方法/属性 | 说明 | 返回类型 |
|
||||||
|
|---------|------|---------|
|
||||||
|
| `ExtractConditions(parser)` | 提取所有条件 | Dictionary |
|
||||||
|
| `GetConditionValue(varName)` | 获取单个条件值 | String |
|
||||||
|
| `AddCondition(varName, value)` | 手动添加条件 | - |
|
||||||
|
| `AddExtractionRule(...)` | 添加提取规则 | - |
|
||||||
|
| `ToString()` | 返回条件字符串(调试用) | String |
|
||||||
|
|
||||||
|
### clsConditionMatcher
|
||||||
|
|
||||||
|
| 方法 | 说明 | 返回类型 |
|
||||||
|
|-----|------|---------|
|
||||||
|
| `IsMatch(expr, conditions)` | 判断条件是否匹配 | Boolean |
|
||||||
|
| `TestExpression(expr)` | 测试表达式有效性 | String |
|
||||||
|
|
||||||
|
### clsBOMManager (新增方法)
|
||||||
|
|
||||||
|
| 方法 | 说明 | 返回类型 |
|
||||||
|
|-----|------|---------|
|
||||||
|
| `GetMaterialsByModel(modelStr, [categoryName])` | 根据型号获取物料 | Collection |
|
||||||
|
| `GetMaterialsByCategoryAndModel(...)` | 根据类别和型号获取物料 | Collection |
|
||||||
|
| `ParseModelAndExtractConditions(modelStr)` | 解析型号并返回条件 | Dictionary |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 扩展指南
|
||||||
|
|
||||||
|
### 添加新的提取条件
|
||||||
|
|
||||||
|
假设需要添加"表盘类型"条件:
|
||||||
|
|
||||||
|
```vba
|
||||||
|
' 在 clsConditionExtractor.InitializeRules 方法中添加:
|
||||||
|
m_ExtractionRules("bplx") = Array("DialCode", "Direct")
|
||||||
|
```
|
||||||
|
|
||||||
|
### 添加新的提取方法
|
||||||
|
|
||||||
|
如果需要特殊的提取逻辑:
|
||||||
|
|
||||||
|
```vba
|
||||||
|
' 在 clsConditionExtractor.ExtractValue 方法中添加:
|
||||||
|
Case "GetMiddleChars"
|
||||||
|
' 提取中间几位字符
|
||||||
|
If Len(sourceValue) > 4 Then
|
||||||
|
ExtractValue = Mid(sourceValue, 2, 3)
|
||||||
|
Else
|
||||||
|
ExtractValue = sourceValue
|
||||||
|
End If
|
||||||
|
```
|
||||||
|
|
||||||
|
### 扩展条件匹配运算符
|
||||||
|
|
||||||
|
在 `clsConditionMatcher.EvaluateSimpleCondition` 中添加新运算符:
|
||||||
|
|
||||||
|
```vba
|
||||||
|
' 示例: 添加 > 运算符
|
||||||
|
ElseIf InStr(cond, ">") > 0 Then
|
||||||
|
' ... 实现大于比较
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### Q1: 型号解析失败怎么办?
|
||||||
|
|
||||||
|
**A**: 检查型号格式是否正确:
|
||||||
|
- 表头部分必须包含: `型号-外径.安装.壳体.连接.量程.[特性]`
|
||||||
|
- 各部分用 `.` 分隔
|
||||||
|
- 表头和表盘用 `|` 分隔
|
||||||
|
|
||||||
|
### Q2: 条件匹配不准确?
|
||||||
|
|
||||||
|
**A**:
|
||||||
|
1. 检查物料的选择条件表达式是否正确
|
||||||
|
2. 运行 `Test3_ConditionMatcher` 验证匹配器功能
|
||||||
|
3. 使用 `TestExpression` 方法测试具体表达式
|
||||||
|
|
||||||
|
### Q3: 如何调试条件提取?
|
||||||
|
|
||||||
|
**A**: 使用以下代码查看提取结果:
|
||||||
|
|
||||||
|
```vba
|
||||||
|
Dim conditions As Object
|
||||||
|
Set conditions = bomMgr.ParseModelAndExtractConditions(modelStr)
|
||||||
|
|
||||||
|
Dim key As Variant
|
||||||
|
For Each key In conditions.Keys
|
||||||
|
Debug.Print key & " = " & conditions(key)
|
||||||
|
Next key
|
||||||
|
```
|
||||||
|
|
||||||
|
### Q4: 批量处理速度慢?
|
||||||
|
|
||||||
|
**A**:
|
||||||
|
1. 避免在循环中重复加载BOM数据
|
||||||
|
2. 使用 `GetMaterialsByModel` 一次性获取所有类别
|
||||||
|
3. 考虑添加缓存机制
|
||||||
|
|
||||||
|
### Q5: 如何验证物料条件表达式?
|
||||||
|
|
||||||
|
**A**: 运行示例:
|
||||||
|
|
||||||
|
```vba
|
||||||
|
Example5_ValidateMaterialConditions
|
||||||
|
```
|
||||||
|
|
||||||
|
这将生成一个验证报告,显示所有物料条件的有效性。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 测试用例
|
||||||
|
|
||||||
|
### 运行所有测试
|
||||||
|
|
||||||
|
```vba
|
||||||
|
RunAllTests
|
||||||
|
```
|
||||||
|
|
||||||
|
### 单独测试
|
||||||
|
|
||||||
|
```vba
|
||||||
|
' 测试型号解析
|
||||||
|
Test1_ModelParser
|
||||||
|
|
||||||
|
' 测试条件提取
|
||||||
|
Test2_ConditionExtractor
|
||||||
|
|
||||||
|
' 测试条件匹配
|
||||||
|
Test3_ConditionMatcher
|
||||||
|
|
||||||
|
' 测试完整流程
|
||||||
|
Test4_GetMaterialsByModel
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 应用示例
|
||||||
|
|
||||||
|
### 示例1: 生成领料清单
|
||||||
|
|
||||||
|
```vba
|
||||||
|
Example1_GeneratePickingListByModel
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例2: 批量处理型号
|
||||||
|
|
||||||
|
```vba
|
||||||
|
Example2_BatchProcessModels
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例3: 查询型号详情
|
||||||
|
|
||||||
|
```vba
|
||||||
|
Example3_ShowModelDetails
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例4: 对比两个型号
|
||||||
|
|
||||||
|
```vba
|
||||||
|
Example4_CompareModels
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例5: 验证条件表达式
|
||||||
|
|
||||||
|
```vba
|
||||||
|
Example5_ValidateMaterialConditions
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 技术支持
|
||||||
|
|
||||||
|
如有问题,请:
|
||||||
|
1. 查看测试结果和调试信息
|
||||||
|
2. 运行相关示例程序
|
||||||
|
3. 检查条件表达式语法
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**文档版本**: v1.0
|
||||||
|
**最后更新**: 2026-01-19
|
||||||
635
订单物料提取实现计划.md
635
订单物料提取实现计划.md
@@ -1,635 +0,0 @@
|
|||||||
# 订单物料提取功能实现计划
|
|
||||||
|
|
||||||
## 一、项目概述
|
|
||||||
|
|
||||||
### 1.1 目标
|
|
||||||
实现从产品型号中提取选择条件,并根据条件匹配 BOM 库中对应的物料,生成订单物料清单。
|
|
||||||
|
|
||||||
### 1.2 核心功能
|
|
||||||
1. **型号解析**:从产品型号中提取选择条件变量
|
|
||||||
2. **条件匹配引擎**:解析并匹配物料的选择条件表达式
|
|
||||||
3. **物料清单生成**:整合上述功能,生成符合产品配置的物料清单
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 二、产品型号编码规则
|
|
||||||
|
|
||||||
### 2.1 型号结构
|
|
||||||
```
|
|
||||||
[型号] - [公称外径] . [安装形式] . [壳体形式] . [过程连接&接液材质] . [量程范围] . [仪表特性] | [表盘] | [附件] | [法兰隔膜]
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2.2 示例分析
|
|
||||||
**输入**: `YTHN-100.A0.532.M203.M16.Y3|BP-095.2312.M16.PA3`
|
|
||||||
|
|
||||||
**表头部分**: `YTHN-100.A0.532.M203.M16.Y3`
|
|
||||||
|
|
||||||
| 部位 | 代码 | 含义 |
|
|
||||||
|------|------|------|
|
|
||||||
| 型号 | YTHN | 不锈钢耐震压力表 |
|
|
||||||
| 公称外径 | 100 | 100mm |
|
|
||||||
| 安装形式 | A0 | 径向无边 |
|
|
||||||
| 壳体形式 | 532 | 532系列(304外壳、内卡式) |
|
|
||||||
| 过程连接&接液材质 | M203 | M20螺纹 + 3号材质(304) |
|
|
||||||
| 量程范围 | M16 | 0~60 MPa |
|
|
||||||
| 仪表特性 | Y3 | 硅油C充油 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 三、需求分析
|
|
||||||
|
|
||||||
### 3.1 提取的选择条件
|
|
||||||
|
|
||||||
| 变量名 | 变量标签 | 提取位置 | 提取规则 |
|
|
||||||
|--------|----------|----------|----------|
|
|
||||||
| gclj | 过程连接 | 过程连接&接液材质 | 除最后一位外的字符 |
|
|
||||||
| jycz | 接液材质 | 过程连接&接液材质 | 最后一位数字 |
|
|
||||||
| lcfw | 量程范围 | 量程范围 | 完整代码 |
|
|
||||||
|
|
||||||
### 3.2 提取示例
|
|
||||||
|
|
||||||
**输入**: `M203`
|
|
||||||
- 过程连接(gclj): `M20`
|
|
||||||
- 接液材质(jycz): `3`
|
|
||||||
|
|
||||||
**输入**: `M16`
|
|
||||||
- 量程范围(lcfw): `M16`
|
|
||||||
|
|
||||||
### 3.3 匹配逻辑
|
|
||||||
|
|
||||||
#### 物料选择条件类型
|
|
||||||
1. **无条件**:条件为空,表示该物料适用于所有配置
|
|
||||||
2. **简单条件**:单个条件判断
|
|
||||||
- 例: `lcfw=M01`
|
|
||||||
3. **AND 条件**:多个条件同时满足
|
|
||||||
- 例: `lcfw=M02 AND gclj=M20`
|
|
||||||
4. **OR 条件**:任一条件满足即可
|
|
||||||
- 例: `lcfw=M01 OR lcfw=M02 OR lcfw=M03`
|
|
||||||
5. **NOT 条件**:排除特定条件
|
|
||||||
- 例: `lcfw=M02 AND gclj!=M20`
|
|
||||||
6. **复杂条件**:AND、OR、NOT 混合
|
|
||||||
- 例: `gclj=Z12 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M03)`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 四、技术架构设计
|
|
||||||
|
|
||||||
### 4.1 模块结构
|
|
||||||
|
|
||||||
```
|
|
||||||
VBA/
|
|
||||||
├── ClassModules/
|
|
||||||
│ ├── clsBOMManager.cls # (已有)BOM管理器
|
|
||||||
│ ├── clsCategory.cls # (已有)类别类
|
|
||||||
│ ├── clsMaterialItem.cls # (已有)物料项类
|
|
||||||
│ ├── clsModelParser.cls # (新增)型号解析器
|
|
||||||
│ ├── clsConditionEvaluator.cls # (新增)条件表达式求值器
|
|
||||||
│ └── clsOrderMaterialList.cls # (新增)订单物料清单管理器
|
|
||||||
└── Modules/
|
|
||||||
└── modOrderProcessor.bas # (新增)订单处理模块
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4.2 类设计
|
|
||||||
|
|
||||||
#### 4.2.1 clsModelParser(型号解析器)
|
|
||||||
|
|
||||||
**职责**: 解析产品型号,提取选择条件
|
|
||||||
|
|
||||||
**属性**:
|
|
||||||
```vba
|
|
||||||
Public ModelCode As String ' 完整型号代码
|
|
||||||
Public HeaderPart As String ' 表头部分
|
|
||||||
Public DialPart As String ' 表盘部分
|
|
||||||
Public AccessoryPart As String ' 附件部分
|
|
||||||
Public FlangePart As String ' 法兰隔膜部分
|
|
||||||
```
|
|
||||||
|
|
||||||
**方法**:
|
|
||||||
```vba
|
|
||||||
' 解析型号
|
|
||||||
Public Sub ParseModel(modelCode As String)
|
|
||||||
|
|
||||||
' 提取表头部分
|
|
||||||
Public Function ExtractHeader() As String
|
|
||||||
|
|
||||||
' 提取过程连接代码
|
|
||||||
Public Function GetProcessConnection() As String
|
|
||||||
|
|
||||||
' 提取接液材质代码
|
|
||||||
Public Function GetWettedMaterial() As String
|
|
||||||
|
|
||||||
' 提取量程范围代码
|
|
||||||
Public Function GetRangeCode() As String
|
|
||||||
|
|
||||||
' 获取所有选择条件
|
|
||||||
Public Function GetSelectionConditions() As Object
|
|
||||||
```
|
|
||||||
|
|
||||||
**示例数据结构**:
|
|
||||||
```vba
|
|
||||||
' 返回字典对象
|
|
||||||
' Key: 变量名 (如 "gclj", "jycz", "lcfw")
|
|
||||||
' Value: 变量值 (如 "M20", "3", "M16")
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 4.2.2 clsConditionEvaluator(条件表达式求值器)
|
|
||||||
|
|
||||||
**职责**: 解析和求值物料选择条件表达式
|
|
||||||
|
|
||||||
**方法**:
|
|
||||||
```vba
|
|
||||||
' 求值条件表达式
|
|
||||||
' 参数:
|
|
||||||
' conditionExpr - 条件表达式 (如 "lcfw=M02 AND gclj=M20")
|
|
||||||
' conditionsDict - 从型号提取的条件字典
|
|
||||||
' 返回: Boolean - 是否匹配
|
|
||||||
Public Function Evaluate(conditionExpr As String, _
|
|
||||||
conditionsDict As Object) As Boolean
|
|
||||||
|
|
||||||
' 解析条件表达式为抽象语法树(AST)
|
|
||||||
Private Function ParseExpression(expr As String) As Object
|
|
||||||
|
|
||||||
' 求值单个条件
|
|
||||||
' 例: "lcfw=M02" -> True/False
|
|
||||||
Private Function EvaluateSingleCondition(condition As String, _
|
|
||||||
conditionsDict As Object) As Boolean
|
|
||||||
|
|
||||||
' 求值 AND 表达式
|
|
||||||
Private Function EvaluateAndExpression(conditions As Collection, _
|
|
||||||
conditionsDict As Object) As Boolean
|
|
||||||
|
|
||||||
' 求值 OR 表达式
|
|
||||||
Private Function EvaluateOrExpression(conditions As Collection, _
|
|
||||||
conditionsDict As Object) As Boolean
|
|
||||||
|
|
||||||
' 求值 NOT 表达式
|
|
||||||
Private Function EvaluateNotExpression(condition As String, _
|
|
||||||
conditionsDict As Object) As Boolean
|
|
||||||
```
|
|
||||||
|
|
||||||
**支持的运算符**:
|
|
||||||
- `=` : 等于
|
|
||||||
- `!=` 或 `<>` : 不等于
|
|
||||||
- `AND` : 逻辑与
|
|
||||||
- `OR` : 逻辑或
|
|
||||||
- `()` : 分组优先级
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 4.2.3 clsOrderMaterialList(订单物料清单管理器)
|
|
||||||
|
|
||||||
**职责**: 管理单个订单的物料清单
|
|
||||||
|
|
||||||
**属性**:
|
|
||||||
```vba
|
|
||||||
Public OrderModel As String ' 订单型号
|
|
||||||
Public OrderConditions As Object ' 订单选择条件字典
|
|
||||||
Public SelectedMaterials As Collection ' 匹配的物料集合
|
|
||||||
```
|
|
||||||
|
|
||||||
**方法**:
|
|
||||||
```vba
|
|
||||||
' 根据订单型号生成物料清单
|
|
||||||
Public Sub GenerateMaterialList(modelCode As String, _
|
|
||||||
bomMgr As clsBOMManager)
|
|
||||||
|
|
||||||
' 筛选符合条件的物料
|
|
||||||
' 参数:
|
|
||||||
' categoryName - 类别名称
|
|
||||||
' bomMgr - BOM管理器
|
|
||||||
Private Function FilterMaterialsByCategory(categoryName As String, _
|
|
||||||
bomMgr As clsBOMManager) As Collection
|
|
||||||
|
|
||||||
' 获取物料汇总信息
|
|
||||||
Public Function GetMaterialSummary() As String
|
|
||||||
|
|
||||||
' 导出物料清单到工作表
|
|
||||||
Public Sub ExportToWorksheet(ws As Worksheet)
|
|
||||||
|
|
||||||
' 打印物料清单到立即窗口
|
|
||||||
Public Sub PrintToImmediateWindow()
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 4.2.4 clsBOMManager 扩展
|
|
||||||
|
|
||||||
**新增方法**:
|
|
||||||
```vba
|
|
||||||
' 根据选择条件获取物料清单
|
|
||||||
' 参数:
|
|
||||||
' categoryName - 类别名称
|
|
||||||
' conditionsDict - 选择条件字典
|
|
||||||
' 返回: 匹配的物料集合
|
|
||||||
Public Function GetMaterialsByConditions(categoryName As String, _
|
|
||||||
conditionsDict As Object) As Collection
|
|
||||||
|
|
||||||
' 获取整个订单的物料清单
|
|
||||||
' 参数:
|
|
||||||
' conditionsDict - 从型号提取的选择条件字典
|
|
||||||
' useParent - 是否使用父类别领料方式
|
|
||||||
' 返回: 所有类别的匹配物料汇总
|
|
||||||
Public Function GetOrderMaterials(conditionsDict As Object, _
|
|
||||||
Optional useParent As Boolean = True) As Collection
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 五、实现步骤
|
|
||||||
|
|
||||||
### 阶段一:型号解析器(clsModelParser)
|
|
||||||
**优先级**: 高
|
|
||||||
|
|
||||||
**任务清单**:
|
|
||||||
1. 创建 `clsModelParser.cls` 类模块
|
|
||||||
2. 实现型号分段解析(表头、表盘、附件、法兰隔膜)
|
|
||||||
3. 实现表头部分的详细解析
|
|
||||||
4. 实现选择条件提取方法
|
|
||||||
5. 编写单元测试用例
|
|
||||||
|
|
||||||
**测试用例**:
|
|
||||||
```vba
|
|
||||||
Sub TestModelParser()
|
|
||||||
Dim parser As New clsModelParser
|
|
||||||
Dim conditions As Object
|
|
||||||
|
|
||||||
' 测试1: 标准型号
|
|
||||||
parser.ParseModel "YTHN-100.A0.532.M203.M16.Y3|BP-095.2312.M16.PA3"
|
|
||||||
Set conditions = parser.GetSelectionConditions()
|
|
||||||
|
|
||||||
Debug.Assert conditions("gclj") = "M20"
|
|
||||||
Debug.Assert conditions("jycz") = "3"
|
|
||||||
Debug.Assert conditions("lcfw") = "M16"
|
|
||||||
|
|
||||||
' 测试2: 不同过程连接
|
|
||||||
parser.ParseModel "YTHN-100.A0.532.Z121.M06.Y3"
|
|
||||||
Set conditions = parser.GetSelectionConditions()
|
|
||||||
|
|
||||||
Debug.Assert conditions("gclj") = "Z12"
|
|
||||||
Debug.Assert conditions("jycz") = "1"
|
|
||||||
Debug.Assert conditions("lcfw") = "M06"
|
|
||||||
End Sub
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 阶段二:条件表达式求值器(clsConditionEvaluator)
|
|
||||||
**优先级**: 高
|
|
||||||
|
|
||||||
**任务清单**:
|
|
||||||
1. 创建 `clsConditionEvaluator.cls` 类模块
|
|
||||||
2. 实现条件表达式词法分析(分词)
|
|
||||||
3. 实现条件表达式语法分析(构建 AST)
|
|
||||||
4. 实现各种运算符的求值逻辑
|
|
||||||
5. 处理括号优先级
|
|
||||||
6. 编写单元测试用例
|
|
||||||
|
|
||||||
**测试用例**:
|
|
||||||
```vba
|
|
||||||
Sub TestConditionEvaluator()
|
|
||||||
Dim evaluator As New clsConditionEvaluator
|
|
||||||
Dim conditions As Object
|
|
||||||
Set conditions = CreateObject("Scripting.Dictionary")
|
|
||||||
|
|
||||||
conditions("gclj") = "M20"
|
|
||||||
conditions("jycz") = "3"
|
|
||||||
conditions("lcfw") = "M16"
|
|
||||||
|
|
||||||
' 测试1: 简单条件
|
|
||||||
Debug.Assert evaluator.Evaluate("lcfw=M16", conditions) = True
|
|
||||||
Debug.Assert evaluator.Evaluate("lcfw=M02", conditions) = False
|
|
||||||
|
|
||||||
' 测试2: AND 条件
|
|
||||||
Debug.Assert evaluator.Evaluate("lcfw=M16 AND gclj=M20", conditions) = True
|
|
||||||
Debug.Assert evaluator.Evaluate("lcfw=M02 AND gclj=M20", conditions) = False
|
|
||||||
|
|
||||||
' 测试3: OR 条件
|
|
||||||
Debug.Assert evaluator.Evaluate("lcfw=M16 OR lcfw=M02", conditions) = True
|
|
||||||
Debug.Assert evaluator.Evaluate("lcfw=M01 OR lcfw=M02", conditions) = False
|
|
||||||
|
|
||||||
' 测试4: NOT 条件
|
|
||||||
Debug.Assert evaluator.Evaluate("lcfw=M16 AND gclj!=M20", conditions) = False
|
|
||||||
Debug.Assert evaluator.Evaluate("lcfw=M16 AND gclj!=Z12", conditions) = True
|
|
||||||
|
|
||||||
' 测试5: 复杂条件
|
|
||||||
Debug.Assert evaluator.Evaluate("gclj=Z12 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M16)", conditions) = False
|
|
||||||
|
|
||||||
' 测试6: 空条件
|
|
||||||
Debug.Assert evaluator.Evaluate("", conditions) = True
|
|
||||||
End Sub
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 阶段三:BOM管理器扩展
|
|
||||||
**优先级**: 中
|
|
||||||
|
|
||||||
**任务清单**:
|
|
||||||
1. 在 `clsBOMManager.cls` 中添加 `GetMaterialsByConditions()` 方法
|
|
||||||
2. 在 `clsBOMManager.cls` 中添加 `GetOrderMaterials()` 方法
|
|
||||||
3. 集成条件求值器
|
|
||||||
4. 编写单元测试用例
|
|
||||||
|
|
||||||
**测试用例**:
|
|
||||||
```vba
|
|
||||||
Sub TestBOMManagerConditions()
|
|
||||||
Dim bomMgr As New clsBOMManager
|
|
||||||
Dim conditions As Object
|
|
||||||
Dim materials As Collection
|
|
||||||
|
|
||||||
' 加载数据
|
|
||||||
bomMgr.LoadData _
|
|
||||||
ThisWorkbook.Worksheets("领料配置"), _
|
|
||||||
ThisWorkbook.Worksheets("平台配置清单")
|
|
||||||
|
|
||||||
' 准备条件
|
|
||||||
Set conditions = CreateObject("Scripting.Dictionary")
|
|
||||||
conditions("gclj") = "M20"
|
|
||||||
conditions("lcfw") = "M16"
|
|
||||||
|
|
||||||
' 测试: 获取部件类别的匹配物料
|
|
||||||
Set materials = bomMgr.GetMaterialsByConditions("部件", conditions)
|
|
||||||
|
|
||||||
' 验证结果
|
|
||||||
Debug.Print "匹配物料数量: " & materials.Count
|
|
||||||
' 应该只有 01011019018 (高压接头部件) 匹配
|
|
||||||
|
|
||||||
Dim mat As clsMaterialItem
|
|
||||||
For Each mat In materials
|
|
||||||
Debug.Print mat.code & " - " & mat.Name
|
|
||||||
Next mat
|
|
||||||
End Sub
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 阶段四:订单物料清单管理器(clsOrderMaterialList)
|
|
||||||
**优先级**: 中
|
|
||||||
|
|
||||||
**任务清单**:
|
|
||||||
1. 创建 `clsOrderMaterialList.cls` 类模块
|
|
||||||
2. 实现物料清单生成逻辑
|
|
||||||
3. 实现物料汇总统计
|
|
||||||
4. 实现多种输出格式(工作表、立即窗口)
|
|
||||||
5. 编写单元测试用例
|
|
||||||
|
|
||||||
**测试用例**:
|
|
||||||
```vba
|
|
||||||
Sub TestOrderMaterialList()
|
|
||||||
Dim orderList As New clsOrderMaterialList
|
|
||||||
Dim bomMgr As New clsBOMManager
|
|
||||||
|
|
||||||
' 加载 BOM 数据
|
|
||||||
bomMgr.LoadData _
|
|
||||||
ThisWorkbook.Worksheets("领料配置"), _
|
|
||||||
ThisWorkbook.Worksheets("平台配置清单")
|
|
||||||
|
|
||||||
' 生成物料清单
|
|
||||||
orderList.GenerateMaterialList "YTHN-100.A0.532.M203.M16.Y3", bomMgr
|
|
||||||
|
|
||||||
' 打印到立即窗口
|
|
||||||
orderList.PrintToImmediateWindow
|
|
||||||
|
|
||||||
' 导出到工作表
|
|
||||||
Dim ws As Worksheet
|
|
||||||
Set ws = ThisWorkbook.Worksheets.Add
|
|
||||||
orderList.ExportToWorksheet ws
|
|
||||||
End Sub
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 阶段五:订单处理模块(modOrderProcessor)
|
|
||||||
**优先级**: 低
|
|
||||||
|
|
||||||
**任务清单**:
|
|
||||||
1. 创建 `modOrderProcessor.bas` 模块
|
|
||||||
2. 实现批量订单处理过程
|
|
||||||
3. 实现单订单物料清单生成
|
|
||||||
4. 实现订单物料清单打印和导出
|
|
||||||
5. 编写用户界面宏
|
|
||||||
|
|
||||||
**示例宏**:
|
|
||||||
```vba
|
|
||||||
' 主入口:生成订单物料清单
|
|
||||||
Sub GenerateOrderMaterialList()
|
|
||||||
Dim modelCode As String
|
|
||||||
modelCode = InputBox("请输入产品型号:", "生成订单物料清单")
|
|
||||||
|
|
||||||
If modelCode = "" Then Exit Sub
|
|
||||||
|
|
||||||
Dim orderList As New clsOrderMaterialList
|
|
||||||
Dim bomMgr As New clsBOMManager
|
|
||||||
|
|
||||||
bomMgr.LoadData _
|
|
||||||
ThisWorkbook.Worksheets("领料配置"), _
|
|
||||||
ThisWorkbook.Worksheets("平台配置清单")
|
|
||||||
|
|
||||||
orderList.GenerateMaterialList modelCode, bomMgr
|
|
||||||
|
|
||||||
' 输出到工作表
|
|
||||||
Dim ws As Worksheet
|
|
||||||
Application.DisplayAlerts = False
|
|
||||||
On Error Resume Next
|
|
||||||
ThisWorkbook.Worksheets("订单物料清单").Delete
|
|
||||||
On Error GoTo 0
|
|
||||||
Application.DisplayAlerts = True
|
|
||||||
|
|
||||||
Set ws = ThisWorkbook.Worksheets.Add
|
|
||||||
ws.Name = "订单物料清单"
|
|
||||||
orderList.ExportToWorksheet ws
|
|
||||||
|
|
||||||
MsgBox "订单物料清单生成完成!", vbInformation
|
|
||||||
End Sub
|
|
||||||
|
|
||||||
' 快速打印到立即窗口
|
|
||||||
Sub QuickPrintOrderMaterials()
|
|
||||||
Dim modelCode As String
|
|
||||||
modelCode = InputBox("请输入产品型号:", "快速打印订单物料")
|
|
||||||
|
|
||||||
If modelCode = "" Then Exit Sub
|
|
||||||
|
|
||||||
' ... 实现逻辑
|
|
||||||
End Sub
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 六、数据流程图
|
|
||||||
|
|
||||||
```
|
|
||||||
用户输入产品型号
|
|
||||||
↓
|
|
||||||
[clsModelParser] 解析型号
|
|
||||||
↓
|
|
||||||
提取选择条件字典 {gclj: M20, jycz: 3, lcfw: M16}
|
|
||||||
↓
|
|
||||||
[clsOrderMaterialList] 生成物料清单
|
|
||||||
↓
|
|
||||||
遍历所有根类别
|
|
||||||
↓
|
|
||||||
对每个类别调用 [clsBOMManager.GetMaterialsByConditions()]
|
|
||||||
↓
|
|
||||||
遍历类别下的所有物料
|
|
||||||
↓
|
|
||||||
对每个物料使用 [clsConditionEvaluator.Evaluate()]
|
|
||||||
↓
|
|
||||||
匹配成功 → 添加到结果集合
|
|
||||||
匹配失败 → 跳过
|
|
||||||
↓
|
|
||||||
汇总所有匹配物料
|
|
||||||
↓
|
|
||||||
输出到工作表 / 立即窗口
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 七、关键技术难点
|
|
||||||
|
|
||||||
### 7.1 条件表达式解析
|
|
||||||
|
|
||||||
**难点**:
|
|
||||||
- 支持括号嵌套
|
|
||||||
- 运算符优先级处理
|
|
||||||
- 复杂逻辑组合
|
|
||||||
|
|
||||||
**解决方案**:
|
|
||||||
- 使用递归下降分析法
|
|
||||||
- 构建抽象语法树(AST)
|
|
||||||
- 后序遍历求值
|
|
||||||
|
|
||||||
### 7.2 型号格式多样性
|
|
||||||
|
|
||||||
**难点**:
|
|
||||||
- 部分型号可能缺少某些部分
|
|
||||||
- 附件和法兰隔膜数量不固定
|
|
||||||
- 过程连接代码长度不固定
|
|
||||||
|
|
||||||
**解决方案**:
|
|
||||||
- 使用正则表达式(如果 VBA 支持)
|
|
||||||
- 分段解析,容错处理
|
|
||||||
- 提供默认值
|
|
||||||
|
|
||||||
### 7.3 性能优化
|
|
||||||
|
|
||||||
**难点**:
|
|
||||||
- 大量物料匹配可能导致性能问题
|
|
||||||
- 复杂条件表达式求值耗时
|
|
||||||
|
|
||||||
**解决方案**:
|
|
||||||
- 缓存求值结果
|
|
||||||
- 优先筛选简单条件
|
|
||||||
- 减少不必要的条件求值
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 八、测试计划
|
|
||||||
|
|
||||||
### 8.1 单元测试
|
|
||||||
|
|
||||||
每个类都需要独立的单元测试模块:
|
|
||||||
|
|
||||||
1. **TestModelParser**: 测试型号解析功能
|
|
||||||
2. **TestConditionEvaluator**: 测试条件求值功能
|
|
||||||
3. **TestBOMManagerConditions**: 测试 BOM 管理器扩展功能
|
|
||||||
4. **TestOrderMaterialList**: 测试订单物料清单生成功能
|
|
||||||
|
|
||||||
### 8.2 集成测试
|
|
||||||
|
|
||||||
测试完整的订单物料生成流程:
|
|
||||||
|
|
||||||
1. 测试标准型号
|
|
||||||
2. 测试特殊配置型号
|
|
||||||
3. 测试边界条件
|
|
||||||
4. 测试异常输入
|
|
||||||
|
|
||||||
### 8.3 测试数据集
|
|
||||||
|
|
||||||
基于真实订单数据准备测试用例:
|
|
||||||
|
|
||||||
| 测试用例 | 型号 | 预期匹配物料数 |
|
|
||||||
|----------|------|----------------|
|
|
||||||
| 标准配置 | YTHN-100.A0.532.M203.M16.Y3 | 待定 |
|
|
||||||
| 不同螺纹 | YTHN-100.A0.532.Z121.M06.Y3 | 待定 |
|
|
||||||
| 小量程 | YTHN-100.A0.532.M201.M02.Y3 | 待定 |
|
|
||||||
| 大量程 | YTHN-100.A0.532.M201.M16.Y3 | 待定 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 九、文档需求
|
|
||||||
|
|
||||||
### 9.1 代码注释
|
|
||||||
- 所有类模块需要详细的中文注释
|
|
||||||
- 关键算法需要解释说明
|
|
||||||
- 复杂逻辑需要举例说明
|
|
||||||
|
|
||||||
### 9.2 使用说明
|
|
||||||
创建 `订单物料清单使用说明.md`,包括:
|
|
||||||
- 功能概述
|
|
||||||
- 使用方法
|
|
||||||
- API 文档
|
|
||||||
- 常见问题
|
|
||||||
|
|
||||||
### 9.3 开发文档
|
|
||||||
- 类设计文档
|
|
||||||
- 接口定义文档
|
|
||||||
- 测试报告
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 十、实施时间表
|
|
||||||
|
|
||||||
| 阶段 | 任务 | 预计工作量 |
|
|
||||||
|------|------|------------|
|
|
||||||
| 1 | 型号解析器 | 2-3 天 |
|
|
||||||
| 2 | 条件表达式求值器 | 3-4 天 |
|
|
||||||
| 3 | BOM管理器扩展 | 1-2 天 |
|
|
||||||
| 4 | 订单物料清单管理器 | 2-3 天 |
|
|
||||||
| 5 | 订单处理模块 | 1-2 天 |
|
|
||||||
| 6 | 测试与调试 | 2-3 天 |
|
|
||||||
| 7 | 文档编写 | 1-2 天 |
|
|
||||||
|
|
||||||
**总计**: 约 12-19 天
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 十一、风险评估
|
|
||||||
|
|
||||||
### 11.1 技术风险
|
|
||||||
- **风险**: VBA 不支持复杂的字符串处理
|
|
||||||
- **应对**: 使用 VBScript Regular Expression 对象
|
|
||||||
|
|
||||||
### 11.2 数据风险
|
|
||||||
- **风险**: BOM 数据不完整或格式错误
|
|
||||||
- **应对**: 增加数据验证和容错处理
|
|
||||||
|
|
||||||
### 11.3 性能风险
|
|
||||||
- **风险**: 大量物料匹配导致响应缓慢
|
|
||||||
- **应对**: 优化算法,增加缓存机制
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 十二、后续扩展方向
|
|
||||||
|
|
||||||
1. **批量订单处理**: 支持从 Excel 列表批量生成物料清单
|
|
||||||
2. **条件配置化**: 将提取规则配置化,支持动态调整
|
|
||||||
3. **物料替代方案**: 支持物料替代品推荐
|
|
||||||
4. **库存集成**: 与库存系统集成,实时查询可用库存
|
|
||||||
5. **成本计算**: 根据物料清单计算订单成本
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 附录:参考资料
|
|
||||||
|
|
||||||
- 布莱迪公司压力表产品选型大表.md
|
|
||||||
- clsBOMManager使用说明.md
|
|
||||||
- VBA 编程规范
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**文档版本**: 1.0
|
|
||||||
**创建日期**: 2025-01-20
|
|
||||||
**编制人**: Claude Code
|
|
||||||
**审核状态**: 待审核
|
|
||||||
Reference in New Issue
Block a user