Compare commits

..

26 Commits

Author SHA1 Message Date
Misaka_Company
c597a6cf75 feat(error-analysis): add configurable header row for report layout
Add OUTPUT_HEADER_ROW constant (row 10) to allow space above error report:
- Preserves rows 1-9 for title, instructions, or summary information
- Error report header now starts at row 10
- Only clears data from header row downwards (preserves upper content)
- Removed AutoFit to maintain custom column widths

This provides flexibility for report formatting and allows
additional context to be added above the error analysis data.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 16:48:39 +08:00
Misaka_Company
1e995b5485 feat(error-analysis): split unmatched parameters into name and value columns
Enhance error analysis report to display unmatched parameters in separate columns:
- "未匹配参数" (parameter name) - shows which parameter caused the mismatch
- "未匹配参数值" (parameter value) - shows the actual value that didn't match

This separation provides clearer visibility into specific parameter conflicts
and makes troubleshooting BOM matching issues easier.

Changes:
- Modified CreateErrorRowArray to accept separate param and value arguments
- Updated FindUnmatchedParameter to return key:value pairs
- Enhanced output formatting to highlight both columns in red/bold
- Updated header to include new "未匹配参数值" column

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 15:05:00 +08:00
Misaka_Company
d4f8e77c66 🎨 style: standardize parameter naming to camelCase
Refactor parameter and property names from PascalCase to camelCase
for consistent naming conventions across VBA modules.

Changes:
- Conditions → conditions (property and parameters)
- Update all references across 7 modules
- Maintain functional behavior while improving code readability

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 14:47:17 +08:00
Misaka_Company
7d59e489b1 feat(BIP): add weighted parameter error analysis algorithm
Implement intelligent BOM error analysis module that:
- Extracts and analyzes failed order matching attempts
- Uses feature-weight algorithm (azxs=10000, bkxs=1000, etc.) for accurate parameter conflict detection
- Automatically traces unmatched parameters to root cause
- Splits multi-error results into separate rows for detailed analysis
- Exposes BomExtractor data pool via GetAllItems() for external analysis

This solves fuzzy tie problems that caused parameter false positives in previous matching logic.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 14:41:58 +08:00
Misaka_Company
658f8a7160 refactor(BIP): skip invalid orders and remove remarks column
- Add logic to skip orders where [是否领料] = "否"
- Remove remarks column from BIP output (10 columns → 9 columns)
- Simplify error handling by removing detailed error notes
- Update data reading range to include column G (是否领料)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 12:15:02 +08:00
Misaka_Company
04099d25bc docs: add extraction remarks data source documentation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 09:58:29 +08:00
Misaka_Company
9b543ab466 refactor: split order validation and processing into separate functions
- Add OrderValidationModule for checking order material validity
- Modify Sheet9 to separate validation (CommandButton1) from processing (CommandButton5)
- Support filtered data validation with performance optimization

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 09:57:48 +08:00
Misaka_Company
36c00befa5 refactor: support filtered data processing and optimize performance
- Add clear data button functionality to Sheet9
- Refactor AccessDataModule to safely handle filtered data with memory array optimization
- Refactor BIPUploadModule to process only visible rows with screen updating optimization
- Refactor ComponentInventoryCheckModule to support filtered data and improve performance
- Refactor MainModule to handle filtered data and remove '代号' field
- Add RestoreAppStatus helper for better application state management
- Improve overall performance by using memory arrays instead of cell-by-cell operations

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 13:12:31 +08:00
Misaka_Company
596a2d0ad2 chore: clean up whitespace and update gitignore
- Remove trailing whitespace in BIPUploadModule.bas
- Add missing newline at end of BomItem.cls
- Update .gitignore: rename Claude to AI Agent, add .sisyphus/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 17:23:59 +08:00
Misaka_Company
7e2710da3f feat(BIP): dynamic row number from platform config column L 2026-03-12 14:48:54 +08:00
Misaka_Company
c119d2370b feat(BomItem): add BipRowNumberBase property from column L 2026-03-12 14:40:40 +08:00
Misaka_Company
1747af046b feat: add Access data integration and total queue number column
- Add new AccessDataModule for fetching data from Access database based on total queue number
- Add CommandButton3_Click handler in Sheet9 for Access data fetch
- Add support for new "总排号" (Total Queue Number) column at column A
- Adjust all column indices to accommodate the new column (shifted by +1)
- Standardize code style: Collection, Count, Quantity, ProductModel, Description
- Fix inventory check result to write to correct column (F instead of E)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 13:53:28 +08:00
Misaka_Company
787b3f56ab docs: add AGENTS.md documentation files
Add comprehensive AGENTS.md documentation files across the project structure to document the agent architecture and capabilities.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 14:05:56 +08:00
Misaka_Company
318d1c31f7 chore: update .gitignore to include .xlsx files 2026-03-11 09:57:50 +08:00
Misaka_Company
b412c55654 refactor: update output fields in MainModule
- Add 生产订单号 field from column A of [产品订单] sheet
- Remove 表头型号 field from output
- Reorder columns to place 生产订单号 as first column
- Update ProcessSingleModel and CreateOutputRowArray signatures

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-03 09:45:28 +08:00
Misaka_Company
8545177bd5 docs: add ComponentInventoryCheckModule flowchart documentation
Add comprehensive flowchart documentation for the component inventory check module:
- Business flowchart (for non-technical users)
- Technical flowchart (for developers)
- Detailed inventory allocation process
- BOM parsing process
- Data processing sequence diagram
- Data structure documentation and execution examples

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-03 09:32:07 +08:00
Misaka_Company
dd6ae4c005 feat: add component inventory check module
Implement automatic component inventory verification that marks
orders with insufficient stock as "Component Priority = No".

Key features:
- Reads orders from [产品订单] worksheet
- Parses BOM to identify component category materials
- Validates inventory against [现存量] worksheet
- Allocates stock in order sequence
- Handles missing components with warnings instead of errors
- Provides detailed statistics on completion

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-02 17:55:08 +08:00
Misaka_Company
57adf860ac feat: add additional features (fjgn) support
- Add fjgn (附加功能) field extraction from instrument characteristics
- Extract additional features from model number's instrument feature field
- Merge all fields from index 5 onwards to handle dot separators in features
- Remove oil-fill type (Y+digit) suffix from additional features
- Normalize separators (comma and dot) to comma for consistent parsing
- Implement multi-value matching for fjgn conditions (contains logic)
  - fjgn=N1: true if fjgn contains N1
  - fjgn!=N1: true if fjgn does not contain N1
- Add fjgn to condition config in MainModule and BIPUploadModule

Fixes issue where additional features with dot separators (e.g., N3.N2.Y3)
were incorrectly parsed by merging all fields from index 5 onwards.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-02 11:04:19 +08:00
Misaka_Company
a22ee42119 chore: remove auto-generated metadata from file headers
- Remove "作者: Auto-generated" and date fields from module headers
- Clean up unnecessary metadata comments

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-02 10:09:40 +08:00
Misaka_Company
6e45d6bdd2 refactor: standardize variable naming and file formatting
- Rename Quantity to quantity in BomItem for consistent naming convention
- Update references in MainModule to use lowercase quantity
- Add newlines at end of files for consistency
- Update vba_metadata.json with new source path and document module

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-02 10:01:57 +08:00
Misaka
f3047bccb8 docs: add BIPUploadModule flowchart documentation
Add comprehensive flowchart documentation for BIPUploadModule:
- Simplified main flow diagram for management review
- Detailed ProcessOrdersToBIP flowchart
- ProcessSingleOrder sub-process flowchart
- WriteBatchData batch write flowchart
- Data structure specifications
- Key features and performance optimizations
- Execution examples (normal and error cases)
- Related modules and dependencies

Documentation uses Mermaid diagrams for visualization
with proper bracket escaping for compatibility.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-01 23:25:04 +08:00
Misaka
d68dc945bc perf: optimize output logic using batch array writes
Optimize BIPUploadModule and MainModule for better performance:
- Replace cell-by-cell writes with batch array operations
- Collect all output data in memory using Collection objects
- Use WriteBatchData to write all data in single operation
- Add CreateBIPRowArray and CreateOutputRowArray helper functions
- Remove deprecated WriteBIPRow and WriteOutputRow functions

Performance improvement:
- Before: N cell write operations per row (thousands of Excel calls)
- After: 1 batch write operation for all data
- Expected speedup: 10-100x depending on data volume

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-01 23:06:26 +08:00
Misaka
73491c104b fix: clear error messages between BOM extractions
Fix bug where error messages from previous orders were accumulating:
- Add ClearErrorMessages() public method to BomExtractor class
- Initialize pErrorMessages as new collection in ExtractBom()
- Replace commented-out pErrorMessages.Clear with proper initialization
- Ensures each order's error information is independent

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-01 22:42:00 +08:00
Misaka
c7c12838b2 feat: add component priority support to MainModule
Update MainModule to support component priority field:
- Read component priority from column E of [产品订单] worksheet
- Pass component priority to ProcessSingleModel function
- Apply category exclusion logic based on priority flag:
  - When "否"/"0"/"FALSE", exclude "部件" category
  - Only extract sub-category materials when disabled
- Consistent with BIPUploadModule implementation

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-01 22:35:25 +08:00
Misaka
c5f2d804fb feat: add component priority exclusion feature
Add support for excluding "部件" category based on component priority flag:
- BomExtractor: Add exclude categories functionality
  - Add pExcludeCategories collection member
  - Add SetExcludeCategories() and ClearExcludeCategories() methods
  - Modify DetermineRequiredCategories() to skip excluded categories

- BIPUploadModule: Read and use component priority field
  - Read component priority from column E of [产品订单] worksheet
  - Pass component priority to ProcessSingleOrder()
  - When priority is "否"/"0"/"FALSE", exclude "部件" category
  - Only extract sub-category materials when component priority is disabled

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-01 22:25:10 +08:00
Misaka
8fae8f0389 feat: add BIP upload module for order processing
Add BIPUploadModule to process product orders and generate BIP upload format:
- Read order data from [产品订单] worksheet
- Extract BOM using existing BomExtractor and ProductModelParser
- Output to [BIP上传模板] with formatted fields:
  - Source document number, product code, quantity
  - Line number (base 7000 + index)
  - Material code (66 code from BOM)
  - Supply method, required date, issue organization
  - Planned outbound quantity, remarks for errors

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-01 22:07:36 +08:00
24 changed files with 4766 additions and 210 deletions

9
.gitignore vendored
View File

@@ -6,11 +6,16 @@ log
*.spec
temp
# Claude 临时文件
# AI Agent 临时文件
.claude/
.sisyphus/
tmpclaude-*
*.log
*workspace*
*.png
data/
*.xlsm
*.xlsm
*.xlsx

131
AGENTS.md Normal file
View File

@@ -0,0 +1,131 @@
# AutoBOM Knowledge Base
**Generated:** 2026-03-11
**Stack:** VBA (Excel) + Python automation
## OVERVIEW
VBA-based BOM extraction system that parses product model strings and matches components from a platform configuration list. Core workflow: parse model → extract conditions → match BOM items → export results.
## STRUCTURE
```
AutoBOM/
├── VBA/ # Core VBA modules
│ ├── ClassModules/ # Data models + logic classes
│ ├── Modules/ # Entry points + workflows
│ └── DocumentModules/ # Sheet-specific code
├── docs/ # Flowcharts + execution plans
├── reference_docs/ # External product references
└── *.xlsm/*.xlsx # Excel workbooks with embedded macros
```
## WHERE TO LOOK
| Task | Location | Notes |
|------|----------|-------|
| Parse product model | `VBA/ClassModules/ProductModelParser.cls` | Extracts conditions from model string |
| Match BOM items | `VBA/ClassModules/BomExtractor.cls` | Core matching logic with assembly hierarchy |
| BOM data model | `VBA/ClassModules/BomItem.cls` | Row structure for platform configuration |
| Condition evaluation | `VBA/ClassModules/ConditionEvaluator.cls` | Evaluates selection conditions |
| Main workflow | `VBA/Modules/MainModule.bas` | `ProcessProductModels()` entry point |
| BIP upload | `VBA/Modules/BIPUploadModule.bas` | Upload results to BIP system |
| Component check | `VBA/Modules/ComponentInventoryCheckModule.bas` | Inventory verification |
| Excel→Markdown | `.claude/skills/excel-to-markdown/scripts/excel_to_markdown.py` | Python utility |
## CODE MAP
### Core Classes
| Symbol | Type | Location | Role |
|--------|------|----------|------|
| `BomExtractor` | Class | `ClassModules/BomExtractor.cls` | Extracts matching BOM items based on conditions |
| `BomItem` | Class | `ClassModules/BomItem.cls` | Data model for BOM row (11 fields) |
| `ProductModelParser` | Class | `ClassModules/ProductModelParser.cls` | Parses model string like `Y-100-M203.316SS` |
| `ConditionEvaluator` | Class | `ClassModules/ConditionEvaluator.cls` | Evaluates condition expressions |
| `MainModule` | Module | `Modules/MainModule.bas` | Orchestrates end-to-end workflow |
### Key Functions
| Function | Location | Description |
|----------|----------|-------------|
| `ProcessProductModels()` | `MainModule.bas` | Main entry point |
| `ExtractBom(conditions)` | `BomExtractor.cls` | Returns matched `Collection` of `BomItem` |
| `Parse(modelString)` | `ProductModelParser.cls` | Extracts `azxs`, `bkxs`, `gclj`, `jycz`, `lcfw`, `fjgn` |
| `Evaluate(condition, conditions)` | `ConditionEvaluator.cls` | Returns `Boolean` match result |
## CONVENTIONS
### VBA Structure
- **ClassModules**: Domain logic classes (`*.cls`)
- **Modules**: Procedural workflows (`*.bas`)
- **DocumentModules**: Sheet-specific event handlers (`Sheet9.cls`)
### Model String Format
```
[Header]-[Spec1].[Spec2].[Spec3].[Spec4].[Spec5]|[Detail1]|[Detail2]
Example: Y-100-M203.316SS.L100.N2
```
### Condition Config
```vba
Private Const CONDITION_CONFIG = "azxs安装形式|bkxs表壳形式|gclj过程连接|jycz接液材质|lcfw量程范围|fjgn附加功能"
```
## ANTI-PATTERNS (THIS PROJECT)
- **DO NOT** modify row indexing in `BomExtractor.LoadBomData()` — starts at row 4 (header is row 3)
- **DO NOT** change `BomItem` field order — hardcoded column mapping in `LoadFromRow()`
- **DO NOT** remove `On Error Resume Next` in `BomItem.LoadFromRow()` — handles type conversion failures
- **NEVER** skip assembly logic in `ApplyAssemblyLogic()` — handles parent/child component hierarchy
- **NEVER** hardcode workbook names — use `ThisWorkbook` reference
## UNIQUE STYLES
### Assembly Logic (Parent/Child Override)
If parent category matches (e.g., "部件") AND all children match (e.g., "接头", "弹性元件"), parent overrides children in output. Controlled by `ApplyAssemblyLogic()`.
### Batch Output Pattern
Results collected in `Collection` → converted to 2D array → single `Range.Value` write for performance.
### Condition Expression Syntax
```vba
' Format: "field=value" or "field1=value1|field2=value2"
' Example: "azxs=M|azxs=L" (vertical OR horizontal)
```
## COMMANDS
### Python Virtual Environment
```bash
# Activate (Windows)
.venv\Scripts\activate
# Run Excel→Markdown converter
python .claude/skills/excel-to-markdown/scripts/excel_to_markdown.py input.xlsx -o output.md
```
### Excel Macros
```
1. Open *.xlsm workbook
2. Press Alt+F11 to open VBA editor
3. Run: MainModule.ProcessProductModels
```
## NOTES
### Workbook Requirements
- Input sheet: `产品订单` (product orders)
- BOM sheet: `平台配置清单` (platform configuration)
- Output sheet: `BOM 提取结果` (auto-created)
### Git Configuration
`.gitignore` excludes `*.xlsm`, `*.xlsx`, `*.png`, `.venv/`, `build/`, `dist/`. Binary Excel files not tracked.
### ConditionEvaluator Dependencies
VBA `Scripting.Dictionary` required (Windows only). Not compatible with Mac Excel.
### Error Handling
- Parse failures → `extractNote = "解析失败:..."`
- No matches → `extractNote = "未匹配到任何物料"`
- Multi-match → logged but outputs all (data quality flag)

95
VBA/AGENTS.md Normal file
View File

@@ -0,0 +1,95 @@
# VBA Module Knowledge Base
**Scope:** `VBA/` directory - Core automation logic
## OVERVIEW
VBA modules for BOM extraction: ClassModules (domain logic), Modules (workflows), DocumentModules (sheet events).
## STRUCTURE
```
VBA/
├── ClassModules/ # 4 classes: BomExtractor, BomItem, ProductModelParser, ConditionEvaluator
├── Modules/ # 4 modules: MainModule, BIPUploadModule, ComponentInventoryCheckModule, TestModule
├── DocumentModules/ # Sheet9.cls (event handlers)
└── vba_metadata.json # Module metadata
```
## WHERE TO LOOK
| Task | Location | Notes |
|------|----------|-------|
| Main entry point | `Modules/MainModule.bas` | `ProcessProductModels()` |
| BOM extraction | `ClassModules/BomExtractor.cls` | `ExtractBom()` with assembly logic |
| Model parsing | `ClassModules/ProductModelParser.cls` | `Parse()` extracts 6 conditions |
| Condition logic | `ClassModules/ConditionEvaluator.cls` | Expression evaluation |
| BIP upload | `Modules/BIPUploadModule.bas` | Upload to BIP system |
| Inventory check | `Modules/ComponentInventoryCheckModule.bas` | Component verification |
## CODE MAP
| Symbol | Type | Location | Role |
|--------|------|----------|------|
| `ProcessProductModels()` | Sub | `MainModule.bas` | Main entry point |
| `ExtractBom()` | Function | `BomExtractor.cls` | Core matching logic |
| `Parse()` | Function | `ProductModelParser.cls` | Model string parser |
| `Evaluate()` | Function | `ConditionEvaluator.cls` | Condition evaluator |
| `LoadFromRow()` | Sub | `BomItem.cls` | Row data loader |
## CONVENTIONS
### Module Organization
- **ClassModules**: `*.cls` files with `Option Explicit`, public methods, private state
- **Modules**: `*.bas` files with public subs, helper functions
- **DocumentModules**: Sheet-specific event handlers (e.g., `Sheet9.cls`)
### Error Handling Pattern
```vba
On Error GoTo ErrorHandler
' ... logic ...
Exit Sub
ErrorHandler:
' Handle error
```
### Data Loading
- `BomExtractor.LoadBomData()` starts at row 4 (row 3 is header)
- `BomItem.LoadFromRow()` uses `On Error Resume Next` for type conversions
## ANTI-PATTERNS (THIS PROJECT)
- **NEVER** change row indexing in `LoadBomData()` — hardcoded to start at row 4
- **NEVER** reorder `BomItem` fields — column mapping is hardcoded (11 fields)
- **NEVER** remove `On Error Resume Next` in `LoadFromRow()` — handles type conversion
- **NEVER** bypass `ApplyAssemblyLogic()` — parent/child override is critical
- **NEVER** hardcode workbook names — always use `ThisWorkbook`
## UNIQUE STYLES
### Assembly Logic (总成逻辑)
Parent category overrides children if:
1. Parent matches exactly 1 item
2. All children match at least 1 item
3. Result: parent output, children hidden
### Batch Output Pattern
```vba
' Collect in Collection
' Convert to 2D array
' Single Range.Value write
```
### Condition Syntax
- Format: `"field=value|field2=value2"` (pipe = OR)
- Example: `"azxs=M|azxs=L"` (vertical OR horizontal installation)
## NOTES
### Scripting.Dictionary Dependency
All classes use `CreateObject("Scripting.Dictionary")` - Windows only, not Mac-compatible.
### Workbook Sheets Required
- `产品订单` - Input orders
- `平台配置清单` - BOM configuration (starts at row 4)
- `BOM 提取结果` - Auto-created output

148
VBA/ClassModules/AGENTS.md Normal file
View File

@@ -0,0 +1,148 @@
# ClassModules Knowledge Base
**Scope:** `VBA/ClassModules/` - Domain logic classes
## OVERVIEW
4 classes: `ProductModelParser` (parse model strings), `BomItem` (data model), `ConditionEvaluator` (evaluate conditions), `BomExtractor` (core matching logic).
## STRUCTURE
```
ClassModules/
├── ProductModelParser.cls # Parse model strings → extract 6 conditions
├── BomItem.cls # BOM data model (11 fields)
├── ConditionEvaluator.cls # Evaluate condition expressions
└── BomExtractor.cls # Core matching + assembly logic
```
## WHERE TO LOOK
| Task | Location | Notes |
|------|----------|-------|
| Parse model string | `ProductModelParser.cls` | `Parse()` method |
| Extract conditions | `ProductModelParser.cls` | Returns `azxs`, `bkxs`, `gclj`, `jycz`, `lcfw`, `fjgn` |
| Load BOM row | `BomItem.cls` | `LoadFromRow()` with type conversion |
| Evaluate condition | `ConditionEvaluator.cls` | `Evaluate(condition, conditions)` |
| Match BOM items | `BomExtractor.cls` | `ExtractBom()` with 4-step process |
| Assembly logic | `BomExtractor.cls` | `ApplyAssemblyLogic()` parent/child override |
## CODE MAP
### ProductModelParser
| Method | Role |
|--------|------|
| `Parse(modelString)` | Entry point, validates format |
| `ParseHeader()` | Splits model string by `-` and `.` |
| `ExtractConnectionAndMaterial()` | Separates `gclj` and `jycz` from code |
| `ExtractAdditionalFeatures()` | Removes oil-fill type (Y+digit) from `fjgn` |
### BomItem
| Property | Type | Column |
|----------|------|--------|
| `RowNumber` | Long | A |
| `Module` | String | B |
| `code` | String | C |
| `Name` | String | D |
| `quantity` | Double | E |
| `SelectCondition` | String | F |
| `Remark` | String | G |
| `category` | String | H |
| `ParentCategory` | String | I |
| `CategoryCondition` | String | J |
| `Code66` | String | K |
### BomExtractor
| Method | Role |
|--------|------|
| `LoadBomData()` | Loads from row 4 (header row 3) |
| `ExtractBom(conditions)` | 4-step: determine categories → match → apply assembly → validate |
| `ApplyAssemblyLogic()` | Parent overrides children if all match |
| `ValidateResult()` |双向覆盖检查 (parent/child coverage) |
## CONVENTIONS
### Class Structure
```vba
Option Explicit
' Private state
Private pPropertyName As Type
' Initialize
Private Sub Class_Initialize()
Set pProperty = New Collection
End Sub
' Public methods
Public Function MethodName() As ReturnType
On Error GoTo ErrorHandler
' Logic
Exit Function
ErrorHandler:
' Handle
End Function
```
### Condition Dictionary
All condition methods accept `Scripting.Dictionary` with keys: `azxs`, `bkxs`, `gclj`, `jycz`, `lcfw`, `fjgn`.
### Error Collection Pattern
```vba
Private pErrorMessages As Collection
Public Function GetErrorSummary() As String
' Join all errors with "; "
End Function
```
## ANTI-PATTERNS (THIS PROJECT)
- **NEVER** change `BomItem.LoadFromRow()` column indices — hardcoded to match platform configuration sheet
- **NEVER** remove `On Error Resume Next` in `LoadFromRow()` — type conversions fail gracefully
- **NEVER** skip validation in `ValidateResult()` —双向覆盖检查 prevents false negatives
- **DO NOT** modify `BomExtractor.LoadBomData()` row start — must be row 4 (row 3 is header)
## UNIQUE STYLES
### Assembly Logic Algorithm
```vba
' 1. Build parent→child map from CategoryHierarchy
' 2. Count matches per category
' 3. If parent=1 AND all children≥1 → parent covers children
' 4. Output parent only, hide children
```
### Model String Format
```
[Header]-[Spec1].[Spec2].[Spec3].[Spec4].[Spec5]|[Detail1]|[Detail2]
Example: Y-100-M203.316SS.L100.N2
Parsed conditions:
- azxs (安装形式): M (vertical)
- bkxs (表壳形式): 3
- gclj (过程连接): M20
- jycz (接液材质): 3 (316SS)
- lcfw (量程范围): 0.L100
- fjgn (附加功能): N2 (from .316SS.L100.N2)
```
### Condition Expression Syntax
```vba
' Single: "field=value"
' OR: "field1=value1|field2=value2"
' Example: "azxs=M|azxs=L" → vertical OR horizontal
```
## NOTES
### Category Hierarchy
Built from `ParentCategory` field (column I). Example:
- "接头" → "部件"
- "弹性元件" → "部件"
- Result: if "部件" matches AND both children match → output "部件" only
### Type Conversion
`BomItem.LoadFromRow()` uses `CLng()`, `CStr()`, `CDbl()` with `On Error Resume Next` — invalid conversions become 0 or empty string.
### Scripting.Dictionary
Windows-only. All dictionary usage via `CreateObject("Scripting.Dictionary")`.

View File

@@ -1,19 +1,18 @@
'=====================================================================
' 类名: BomExtractor
' 功能: BOM提取器,从平台配置清单中提取匹配的物料
' 作者: Auto-generated
' 日期: 2025-01-29
'=====================================================================
Option Explicit
Private pWorksheet As Worksheet
Private pConditionEvaluator As ConditionEvaluator
Private pAllItems As collection ' 所有BOM项
Private pMatchedItems As collection ' 匹配的BOM项
Private pRequiredCategories As collection ' 需要的类别
Private pAllItems As Collection ' 所有BOM项
Private pMatchedItems As Collection ' 匹配的BOM项
Private pRequiredCategories As Collection ' 需要的类别
Private pCategoryHierarchy As Object ' 类别层次结构 Dictionary(子类别->父类别)
Private pErrorMessages As collection
Private pErrorMessages As Collection
Private pExcludeCategories As Collection ' 需要排除的类别
'=====================================================================
' 方法: Class_Initialize
@@ -21,11 +20,12 @@ Private pErrorMessages As collection
'=====================================================================
Private Sub Class_Initialize()
Set pConditionEvaluator = New ConditionEvaluator
Set pAllItems = New collection
Set pMatchedItems = New collection
Set pRequiredCategories = New collection
Set pAllItems = New Collection
Set pMatchedItems = New Collection
Set pRequiredCategories = New Collection
Set pCategoryHierarchy = CreateObject("Scripting.Dictionary")
Set pErrorMessages = New collection
Set pErrorMessages = New Collection
Set pExcludeCategories = New Collection
End Sub
'=====================================================================
@@ -52,12 +52,12 @@ Public Function LoadBomData() As Boolean
End If
'
Set pAllItems = New collection
Set pAllItems = New Collection
Set pCategoryHierarchy = CreateObject("Scripting.Dictionary")
' 从第4行开始读取(第3行是表头)
Dim lastRow As Long
lastRow = pWorksheet.Cells(pWorksheet.Rows.Count, 1).End(xlUp).row
lastRow = pWorksheet.Cells(pWorksheet.Rows.count, 1).End(xlUp).row
Dim i As Long
Dim item As BomItem
@@ -89,24 +89,48 @@ Public Function LoadBomData() As Boolean
Exit Function
ErrorHandler:
pErrorMessages.Add "加载BOM数据异常: " & Err.description
pErrorMessages.Add "加载BOM数据异常: " & Err.Description
LoadBomData = False
End Function
'=====================================================================
' 方法: SetExcludeCategories
' 功能: 设置需要排除的类别
' 参数: categories - 类别集合
'=====================================================================
Public Sub SetExcludeCategories(categories As Collection)
Set pExcludeCategories = categories
End Sub
'=====================================================================
' 方法: ClearExcludeCategories
' 功能: 清空排除类别列表
'=====================================================================
Public Sub ClearExcludeCategories()
Set pExcludeCategories = New Collection
End Sub
'=====================================================================
' 方法: ClearErrorMessages
' 功能: 清空错误信息列表
'=====================================================================
Public Sub ClearErrorMessages()
Set pErrorMessages = New Collection
End Sub
'=====================================================================
' 方法: ExtractBom
' 功能: 根据产品条件提取BOM
' 参数: productConditions - 产品条件字典
' 返回: Collection - 匹配的BOM项集合
'=====================================================================
Public Function ExtractBom(productConditions As Object) As collection
Public Function ExtractBom(productConditions As Object) As Collection
On Error GoTo ErrorHandler
' 清空结果
Set pMatchedItems = New collection
Set pRequiredCategories = New collection
'pErrorMessages.Clear
Set pMatchedItems = New Collection
Set pRequiredCategories = New Collection
Set pErrorMessages = New Collection
' 第一步:确定需要的类别
DetermineRequiredCategories productConditions
@@ -124,7 +148,7 @@ Public Function ExtractBom(productConditions As Object) As collection
Exit Function
ErrorHandler:
pErrorMessages.Add "提取BOM异常: " & Err.description
pErrorMessages.Add "提取BOM异常: " & Err.Description
Set ExtractBom = pMatchedItems
End Function
@@ -141,20 +165,34 @@ Private Sub DetermineRequiredCategories(productConditions As Object)
' 遍历所有有效物料,获取唯一类别
For Each item In pAllItems
If item.IsValidItem Then
'
Dim categoryRequired As Boolean
If Trim(item.CategoryCondition) = "" Then
' 无条件,必需类别
categoryRequired = True
Else
' 有条件,评估条件
categoryRequired = pConditionEvaluator.Evaluate(item.CategoryCondition, productConditions)
End If
' 检查是否在排除列表中
Dim isExcluded As Boolean
isExcluded = False
Dim excludeCat As Variant
For Each excludeCat In pExcludeCategories
If item.category = CStr(excludeCat) Then
isExcluded = True
Exit For
End If
Next excludeCat
If categoryRequired Then
If Not uniqueCategories.Exists(item.category) Then
uniqueCategories.Add item.category, True
pRequiredCategories.Add item.category
' 如果不在排除列表中,继续处理
If Not isExcluded Then
'
Dim categoryRequired As Boolean
If Trim(item.CategoryCondition) = "" Then
' 无条件,必需类别
categoryRequired = True
Else
' 有条件,评估条件
categoryRequired = pConditionEvaluator.Evaluate(item.CategoryCondition, productConditions)
End If
If categoryRequired Then
If Not uniqueCategories.Exists(item.category) Then
uniqueCategories.Add item.category, True
pRequiredCategories.Add item.category
End If
End If
End If
End If
@@ -173,8 +211,8 @@ Private Sub MatchItems(productConditions As Object)
' 遍历每个需要的类别
For Each category In pRequiredCategories
Dim categoryMatches As collection
Set categoryMatches = New collection
Dim categoryMatches As Collection
Set categoryMatches = New Collection
' 查找该类别下所有匹配的物料
For Each item In pAllItems
@@ -197,19 +235,19 @@ Private Sub MatchItems(productConditions As Object)
Next item
' 检查匹配结果
If categoryMatches.Count = 0 Then
If categoryMatches.count = 0 Then
' ---------------------------------------------------------
' CHANGE: 这里不再立即报错
' 理由: 未匹配到可能是正常的(例如:父类别缺失但子类别齐全,或者子类别被父类别覆盖)
' 具体的缺失检查移交到 ValidateResult 方法中统一处理
' ---------------------------------------------------------
ElseIf categoryMatches.Count = 1 Then
ElseIf categoryMatches.count = 1 Then
' 正常:匹配到1条
pMatchedItems.Add categoryMatches(1)
Else
' : ()
Dim multiMsg As String
multiMsg = "类别[" & category & "]匹配到多条物料(" & categoryMatches.Count & "条)"
multiMsg = "类别[" & category & "]匹配到多条物料(" & categoryMatches.count & "条)"
pErrorMessages.Add multiMsg
' 临时处理:输出所有匹配的
@@ -265,8 +303,8 @@ Private Sub ApplyAssemblyLogic()
Dim coveredCategories As Object
Set coveredCategories = CreateObject("Scripting.Dictionary")
Dim satisfiedParentItems As collection
Set satisfiedParentItems = New collection
Dim satisfiedParentItems As Collection
Set satisfiedParentItems = New Collection
For Each parentCat In parentToChildren.Keys
' 只有当该父类别确实有匹配物料时才进行检查
@@ -307,8 +345,8 @@ Private Sub ApplyAssemblyLogic()
Next parentCat
' 4. 构建新的结果集
Dim newMatchedItems As collection
Set newMatchedItems = New collection
Dim newMatchedItems As Collection
Set newMatchedItems = New Collection
' 4.1 先添加满足条件的父类别项 (总成)
For Each item In satisfiedParentItems
@@ -421,7 +459,7 @@ End Sub
' 功能: 获取错误信息集合
' 返回: Collection
'=====================================================================
Public Function GetErrorMessages() As collection
Public Function GetErrorMessages() As Collection
Set GetErrorMessages = pErrorMessages
End Function
@@ -431,7 +469,7 @@ End Function
' 返回: String
'=====================================================================
Public Function GetErrorSummary() As String
If pErrorMessages.Count = 0 Then
If pErrorMessages.count = 0 Then
GetErrorSummary = ""
Else
Dim result As String
@@ -442,3 +480,11 @@ Public Function GetErrorSummary() As String
GetErrorSummary = result
End If
End Function
'=====================================================================
' 方法: GetAllItems
' 功能: 获取所有加载的BOM物料 (暴露数据池供异常分析溯源算法使用)
' 返回: Collection
'=====================================================================
Public Function GetAllItems() As Collection
Set GetAllItems = pAllItems
End Function

View File

@@ -1,8 +1,6 @@
'=====================================================================
' 类名: BomItem
' 功能: BOM物料项数据模型
' 作者: Auto-generated
' 日期: 2025-01-29
' 类名BomItem
' 功能BOM 物料项数据模型
'=====================================================================
Option Explicit
@@ -18,71 +16,74 @@ Public Remark As String ' 备注
Public category As String ' 类别
Public ParentCategory As String ' 上层类别
Public CategoryCondition As String ' 类别选用条件
Public Code66 As String ' 66代码
Public Code66 As String ' 66 代码
Public BipRowNumberBase As Long ' BIP 行号基数
' 匹配状态
Public IsMatched As Boolean ' 是否匹配
Public MatchError As String ' 匹配错误信息
'=====================================================================
' 方法: Class_Initialize
' 功能: 初始化类
' 方法Class_Initialize
' 功能初始化类
'=====================================================================
Private Sub Class_Initialize()
IsMatched = False
MatchError = ""
BipRowNumberBase = 7000
End Sub
'=====================================================================
' 方法: LoadFromRow
' 功能: 从工作表行加载数据
' 参数: ws - 工作表对象
' 方法LoadFromRow
' 功能从工作表行加载数据
' 参数ws - 工作表对象
' row - 行号
'=====================================================================
Public Sub LoadFromRow(ws As Worksheet, row As Long)
On Error Resume Next
Me.RowNumber = CLng(ws.Cells(row, 1).value) ' A列: 行号
Me.Module = CStr(ws.Cells(row, 2).value) ' B列: 模块
Me.code = CStr(ws.Cells(row, 3).value) ' C列: 代号
Me.Name = CStr(ws.Cells(row, 4).value) ' D列: 名称
Me.Quantity = CDbl(ws.Cells(row, 5).value) ' E列: 数量
Me.SelectCondition = CStr(ws.Cells(row, 6).value) ' F列: 选择条件
Me.Remark = CStr(ws.Cells(row, 7).value) ' G列: 备注
Me.category = CStr(ws.Cells(row, 8).value) ' H列: 类别
Me.ParentCategory = CStr(ws.Cells(row, 9).value) ' I列: 上层类别
Me.CategoryCondition = CStr(ws.Cells(row, 10).value) ' J列: 类别选用条件
Me.Code66 = CStr(ws.Cells(row, 11).value) ' K列: 66代码
Me.RowNumber = CLng(ws.Cells(row, 1).value) ' A 列:行号
Me.Module = CStr(ws.Cells(row, 2).value) ' B 列:模块
Me.code = CStr(ws.Cells(row, 3).value) ' C 列:代号
Me.Name = CStr(ws.Cells(row, 4).value) ' D 列:名称
Me.Quantity = CDbl(ws.Cells(row, 5).value) ' E 列:数量
Me.SelectCondition = CStr(ws.Cells(row, 6).value) ' F 列:选择条件
Me.Remark = CStr(ws.Cells(row, 7).value) ' G 列:备注
Me.category = CStr(ws.Cells(row, 8).value) ' H 列:类别
Me.ParentCategory = CStr(ws.Cells(row, 9).value) ' I 列:上层类别
Me.CategoryCondition = CStr(ws.Cells(row, 10).value) ' J 列:类别选用条件
Me.Code66 = CStr(ws.Cells(row, 11).value) ' K 列:66 代码
Me.BipRowNumberBase = CLng(ws.Cells(row, 12).value) ' L 列BIP 行号基数
On Error GoTo 0
End Sub
'=====================================================================
' 方法: IsValidItem
' 功能: 判断是否为有效物料(类别字段不为空)
' 返回: Boolean
' 方法IsValidItem
' 功能判断是否为有效物料 (类别字段不为空)
' 返回Boolean
'=====================================================================
Public Function IsValidItem() As Boolean
IsValidItem = (Trim(Me.category) <> "")
End Function
'=====================================================================
' 方法: HasParentCategory
' 功能: 判断是否有父类别
' 返回: Boolean
' 方法HasParentCategory
' 功能判断是否有父类别
' 返回Boolean
'=====================================================================
Public Function HasParentCategory() As Boolean
HasParentCategory = (Trim(Me.ParentCategory) <> "")
End Function
'=====================================================================
' 方法: ToString
' 功能: 转换为字符串描述
' 返回: String
' 方法ToString
' 功能转换为字符串描述
' 返回String
'=====================================================================
Public Function ToString() As String
ToString = "行号:" & Me.RowNumber & _
" | 类别:" & Me.category & _
" | 代号:" & Me.code & _
" | 名称:" & Me.Name
End Function
End Function

View File

@@ -1,8 +1,6 @@
'=====================================================================
' 类名: ConditionEvaluator
' 功能: 解析和评估条件表达式
' 作者: Auto-generated
' 日期: 2025-01-29
'=====================================================================
Option Explicit
@@ -41,7 +39,7 @@ End Function
' conditions - 条件字典
' 返回: Boolean
'=====================================================================
Private Function EvaluateExpression(expr As String, Conditions As Object) As Boolean
Private Function EvaluateExpression(expr As String, conditions As Object) As Boolean
expr = Trim(expr)
'
@@ -54,7 +52,7 @@ Private Function EvaluateExpression(expr As String, Conditions As Object) As Boo
' OR()
Dim orResult As Variant
orResult = SplitByOperator(expr, " OR ", Conditions)
orResult = SplitByOperator(expr, " OR ", conditions)
If Not IsEmpty(orResult) Then
EvaluateExpression = orResult
Exit Function
@@ -62,14 +60,14 @@ Private Function EvaluateExpression(expr As String, Conditions As Object) As Boo
' AND
Dim andResult As Variant
andResult = SplitByOperator(expr, " AND ", Conditions)
andResult = SplitByOperator(expr, " AND ", conditions)
If Not IsEmpty(andResult) Then
EvaluateExpression = andResult
Exit Function
End If
' 处理单个条件
EvaluateExpression = EvaluateSingleCondition(expr, Conditions)
EvaluateExpression = EvaluateSingleCondition(expr, conditions)
End Function
'=====================================================================
@@ -80,7 +78,7 @@ End Function
' conditions - 条件字典
' 返回: Variant - 评估结果或Empty
'=====================================================================
Private Function SplitByOperator(expr As String, operator As String, Conditions As Object) As Variant
Private Function SplitByOperator(expr As String, operator As String, conditions As Object) As Variant
Dim pos As Long
Dim leftPart As String
Dim rightPart As String
@@ -105,11 +103,11 @@ Private Function SplitByOperator(expr As String, operator As String, Conditions
'
If operator = " OR " Then
SplitByOperator = EvaluateExpression(leftPart, Conditions) Or _
EvaluateExpression(rightPart, Conditions)
SplitByOperator = EvaluateExpression(leftPart, conditions) Or _
EvaluateExpression(rightPart, conditions)
ElseIf operator = " AND " Then
SplitByOperator = EvaluateExpression(leftPart, Conditions) And _
EvaluateExpression(rightPart, Conditions)
SplitByOperator = EvaluateExpression(leftPart, conditions) And _
EvaluateExpression(rightPart, conditions)
End If
Exit Function
End If
@@ -127,7 +125,7 @@ End Function
' conditions - 条件字典
' 返回: Boolean
'=====================================================================
Private Function EvaluateSingleCondition(condition As String, Conditions As Object) As Boolean
Private Function EvaluateSingleCondition(condition As String, conditions As Object) As Boolean
Dim varName As String
Dim operator As String
Dim value As String
@@ -144,11 +142,19 @@ Private Function EvaluateSingleCondition(condition As String, Conditions As Obje
value = Trim(parts(1))
' 特殊规则:如果产品条件中不存在该变量,视为满足!=条件
If Not Conditions.Exists(varName) Then
If Not conditions.Exists(varName) Then
EvaluateSingleCondition = True
Else
actualValue = Conditions(varName)
EvaluateSingleCondition = (actualValue <> value)
actualValue = conditions(varName)
' fjgn
If varName = "fjgn" Then
' fjgn!=N1检查actualValue中是否不包含value
EvaluateSingleCondition = (InStr(actualValue, value) = 0)
Else
' 其他字段使用精确匹配
EvaluateSingleCondition = (actualValue <> value)
End If
End If
Exit Function
End If
@@ -162,11 +168,19 @@ Private Function EvaluateSingleCondition(condition As String, Conditions As Obje
varName = Trim(eqParts(0))
value = Trim(eqParts(1))
If Not Conditions.Exists(varName) Then
If Not conditions.Exists(varName) Then
EvaluateSingleCondition = False
Else
actualValue = Conditions(varName)
EvaluateSingleCondition = (actualValue = value)
actualValue = conditions(varName)
' fjgn
If varName = "fjgn" Then
' fjgn=N1检查actualValue中是否包含value
EvaluateSingleCondition = (InStr(actualValue, value) > 0)
Else
' 其他字段使用精确匹配
EvaluateSingleCondition = (actualValue = value)
End If
End If
Exit Function
End If
@@ -207,4 +221,4 @@ Private Function IsMatchedParentheses(str As String) As Boolean
Next i
IsMatchedParentheses = (depth = 0)
End Function
End Function

View File

@@ -1,8 +1,6 @@
'=====================================================================
' 类名: ProductModelParser
' 功能: 解析产品型号并提取物料选择条件
' 作者: Auto-generated
' 日期: 2025-01-29
'=====================================================================
Option Explicit
@@ -33,8 +31,8 @@ End Property
'=====================================================================
' 属性: Conditions - 提取的条件字典
'=====================================================================
Public Property Get Conditions() As Object
Set Conditions = pConditions
Public Property Get conditions() As Object
Set conditions = pConditions
End Property
'=====================================================================
@@ -88,7 +86,7 @@ Public Function Parse(modelString As String) As Boolean
Exit Function
ErrorHandler:
pErrorMessage = "解析异常: " & Err.description
pErrorMessage = "解析异常: " & Err.Description
Parse = False
End Function
@@ -152,11 +150,36 @@ Private Function ParseHeader() As Boolean
lcfw = Trim(dotParts(4))
pConditions.Add "lcfw", lcfw
' 仪表特性 - 第6个位置(索引5)及之后的所有部分
' .(N3.N2.Y3)5
Dim fjgn As String
If UBound(dotParts) >= 5 Then
Dim instrumentFeature As String
Dim i As Long
instrumentFeature = ""
' 5.
For i = 5 To UBound(dotParts)
If instrumentFeature = "" Then
instrumentFeature = dotParts(i)
Else
instrumentFeature = instrumentFeature & "." & dotParts(i)
End If
Next i
instrumentFeature = Trim(instrumentFeature)
fjgn = ExtractAdditionalFeatures(instrumentFeature)
Else
' fjgn
fjgn = ""
End If
pConditions.Add "fjgn", fjgn
ParseHeader = True
Exit Function
ErrorHandler:
pErrorMessage = "解析表头异常: " & Err.description
pErrorMessage = "解析表头异常: " & Err.Description
ParseHeader = False
End Function
@@ -198,7 +221,7 @@ Private Function ExtractConnectionAndMaterial(code As String, _
Exit Function
ErrorHandler:
pErrorMessage = "提取过程连接和材质异常: " & Err.description
pErrorMessage = "提取过程连接和材质异常: " & Err.Description
ExtractConnectionAndMaterial = False
End Function
@@ -232,3 +255,49 @@ Public Function GetAllConditions() As String
GetAllConditions = result
End Function
'=====================================================================
' 方法: ExtractAdditionalFeatures
' 功能: 从仪表特性中提取附加功能
' : instrumentFeature - ("N2,N3.Y3""Y3")
' 返回: String - 附加功能字符串,多个功能用逗号分隔
' 说明:
' 1. 识别并去除充油类型(位于最后格式为Y+一位数字)
' 2. 统一分隔符处理(将.替换为,)
' 3. 去除可能的后缀分隔符
'=====================================================================
Private Function ExtractAdditionalFeatures(instrumentFeature As String) As String
On Error GoTo ErrorHandler
Dim result As String
result = Trim(instrumentFeature)
' 1. 检查是否以Y+数字结尾(充油类型)
If Len(result) >= 2 Then
Dim lastTwoChars As String
lastTwoChars = Right(result, 2)
' Y+
If UCase(Left(lastTwoChars, 1)) = "Y" And IsNumeric(Right(lastTwoChars, 1)) Then
' 去掉充油类型
result = Left(result, Len(result) - 2)
result = Trim(result)
End If
End If
' 2. 处理可能的分隔符(,或.
' .,
result = Replace(result, ".", ",")
' 3.
If Len(result) > 0 And Right(result, 1) = "," Then
result = Left(result, Len(result) - 1)
End If
ExtractAdditionalFeatures = Trim(result)
Exit Function
ErrorHandler:
'
ExtractAdditionalFeatures = ""
End Function

View File

@@ -0,0 +1,32 @@
'=====================================================================
' 主按钮点击事件
' 功能: 执行BOM提取和BIP上传
'=====================================================================
Private Sub CommandButton1_Click()
Call ProcessProductModels
Call ValidateOrderMaterials
End Sub
'=====================================================================
' 部件库存核对按钮点击事件
' 功能: 执行部件库存核对,标记库存不足的订单
'=====================================================================
Private Sub CommandButton2_Click()
Call CheckComponentInventory
End Sub
'=====================================================================
' 数据提取按钮点击事件
' 功能:基于总排号查询相关字段数据
'=====================================================================
Private Sub CommandButton3_Click()
Call FetchDataFromAccess
End Sub
Private Sub CommandButton4_Click()
ThisWorkbook.Worksheets("产品订单").Range("A2:G10000").ClearContents
End Sub
Private Sub CommandButton5_Click()
Call ProcessOrdersToBIP
End Sub

142
VBA/Modules/AGENTS.md Normal file
View File

@@ -0,0 +1,142 @@
# Modules Knowledge Base
**Scope:** `VBA/Modules/` - Procedural workflows and entry points
## OVERVIEW
4 modules: `MainModule` (main workflow), `BIPUploadModule` (upload results), `ComponentInventoryCheckModule` (inventory check), `TestModule` (testing utilities).
## STRUCTURE
```
Modules/
├── MainModule.bas # Main entry point + orchestration
├── BIPUploadModule.bas # Upload to BIP system
├── ComponentInventoryCheckModule.bas # Component inventory verification
└── TestModule.bas # Testing utilities
```
## WHERE TO LOOK
| Task | Location | Notes |
|------|----------|-------|
| Run BOM extraction | `MainModule.bas` | `ProcessProductModels()` |
| Upload results | `BIPUploadModule.bas` | BIP system integration |
| Check inventory | `ComponentInventoryCheckModule.bas` | Component count verification |
| Test parsing | `TestModule.bas` | Unit test utilities |
## CODE MAP
### MainModule
| Function | Role |
|----------|------|
| `ProcessProductModels()` | Main entry point, orchestrates workflow |
| `ProcessSingleModel()` | Process one model, collect output |
| `CreateOutputRowArray()` | Build row data array |
| `WriteBatchData()` | Bulk write to worksheet |
| `GetInputSheet()` | Get `产品订单` sheet |
| `GetBomSheet()` | Get `平台配置清单` sheet |
| `CreateOutputSheet()` | Create/reset `BOM 提取结果` |
### BIPUploadModule
| Function | Role |
|----------|------|
| `UploadToBIP()` | Upload BOM results to BIP system |
### ComponentInventoryCheckModule
| Function | Role |
|----------|------|
| `CheckComponentInventory()` | Verify component counts match |
## CONVENTIONS
### Module Structure
```vba
Option Explicit
' Constants
Private Const CONDITION_CONFIG = "azxs安装形式|bkxs表壳形式|..."
' Public entry points
Public Sub MainEntryPoint()
On Error GoTo ErrorHandler
' Orchestration
Exit Sub
ErrorHandler:
MsgBox "Error: " & Err.Description
End Sub
' Private helpers
Private Sub HelperFunction()
' Implementation
End Sub
```
### Workflow Pattern
1. Get input sheet (`产品订单`)
2. Get BOM sheet (`平台配置清单`)
3. Create output sheet (`BOM 提取结果`)
4. Initialize `BomExtractor`, load data
5. Loop through models, call `ProcessSingleModel()`
6. Batch write results
7. Format output, show message
### Batch Output Pattern
```vba
' Collect in Collection
Dim outputData As Collection
Set outputData = New Collection
' Add arrays
outputData.Add CreateOutputRowArray(...)
' Convert to 2D array
ReDim resultData(1 To rowCount, 1 To colCount)
' Fill array...
' Single write
ws.Range("A2").Resize(rowCount, colCount).Value = resultData
```
## ANTI-PATTERNS (THIS PROJECT)
- **NEVER** hardcode sheet names — use `GetInputSheet()`, `GetBomSheet()` helpers
- **NEVER** write row-by-row — always batch write via 2D array
- **NEVER** skip error handling — all public subs use `On Error GoTo ErrorHandler`
- **DO NOT** change output column order — must match header definition in `WriteOutputHeader()`
## UNIQUE STYLES
### Condition Config Constant
```vba
Private Const CONDITION_CONFIG = "azxs安装形式|bkxs表壳形式|gclj过程连接|jycz接液材质|lcfw量程范围|fjgn附加功能"
```
Format: `code,label|code,label|...` — parsed dynamically for header generation.
### Component Priority Flag
From column E of input sheet:
- "是" (or "1", "TRUE") → include all categories
- "否" (or "0", "FALSE") → exclude "部件" (components) category
### Output Row Structure
```
Column 1: 生产订单号 (order number)
Column 2: 产品型号 (full model)
Columns 3-8: 6 conditions (azxs, bkxs, gclj, jycz, lcfw, fjgn)
Columns 9-16: BOM fields (行号模块代号名称数量类别66 代码,备注)
```
## NOTES
### Output Sheet Formatting
- Row 1: Bold, gray background (RGB 217,217,217), centered
- Data starts at row 2
- AutoFit columns (commented out in current code)
### Error Messages
- Parse failure: `"解析失败:" + error`
- No match: `"未匹配到任何物料"`
- Multi-match: `"类别[X] 匹配到多条物料(N 条)"` — outputs all but flags
### Performance
Batch write via `Range.Value = resultData` is 10-100x faster than cell-by-cell writes for large datasets.

View File

@@ -0,0 +1,172 @@
'=====================================================================
' 模块名: AccessDataModule
' 功能: 连接Access数据库根据[总排号]提取数据并填充到[产品订单]工作表
' 特性: [安全极速版] 完美解决筛选状态下全量数组写回导致的错位 Bug
'=====================================================================
Option Explicit
'=====================================================================
' 配置区域 (请根据你的实际情况修改以下常量)
'=====================================================================
' Access数据库文件的完整路径
Private Const DB_PATH = "\\192.168.110.114\生产进度表\2025年数据\生产合同数据.accdb"
' Access中目标数据表的名称
Private Const TARGET_TABLE = "26年压力表合同数据"
'=====================================================================
' 过程: FetchDataFromAccess
' 功能: 主控程序,执行数据提取和回填逻辑
'=====================================================================
Public Sub FetchDataFromAccess()
On Error GoTo ErrorHandler
Dim startTime As Double
startTime = Timer
Dim ws As Worksheet
Set ws = GetOrderSheet()
If ws Is Nothing Then
MsgBox "未找到[产品订单]工作表,请检查工作表名称。", vbCritical
Exit Sub
End If
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.count, 1).End(xlUp).row
If lastRow < 2 Then
MsgBox "[产品订单]工作表中没有需要处理的数据。", vbInformation
Exit Sub
End If
' 1. 获取A列中所有筛选后的可见单元格
Dim visibleRange As Range
On Error Resume Next
Set visibleRange = ws.Range("A2:A" & lastRow).SpecialCells(xlCellTypeVisible)
On Error GoTo ErrorHandler
If visibleRange Is Nothing Then
MsgBox "当前筛选状态下没有可见的数据。", vbInformation
Exit Sub
End If
' 2. 仅收集可见行中的总排号
Dim cell As Range
Dim queueNums As String
Dim currentNum As String
For Each cell In visibleRange
currentNum = Trim(cell.value)
If currentNum <> "" Then
queueNums = queueNums & "'" & currentNum & "',"
End If
Next cell
If queueNums = "" Then
MsgBox "可见数据中没有找到有效的总排号。", vbInformation
Exit Sub
End If
queueNums = Left(queueNums, Len(queueNums) - 1)
' 3. 连接Access查询并装入字典 (内存极速匹配)
Dim cn As Object, rs As Object
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
Dim connStr As String
connStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & DB_PATH & ";"
cn.Open connStr
Dim sql As String
sql = "SELECT 总排号, 生产订单号, 产品型号, 数量, 成品物料码 " & _
"FROM [" & TARGET_TABLE & "] " & _
"WHERE 总排号 IN (" & queueNums & ")"
rs.Open sql, cn, 1, 1
Dim dbDict As Object
Set dbDict = CreateObject("Scripting.Dictionary")
If Not rs.EOF Then
rs.MoveFirst
Do Until rs.EOF
Dim key As String
key = Trim(rs.Fields("总排号").value)
If Not dbDict.Exists(key) Then
dbDict.Add key, Array( _
rs.Fields("生产订单号").value, _
rs.Fields("产品型号").value, _
rs.Fields("数量").value, _
rs.Fields("成品物料码").value _
)
End If
rs.MoveNext
Loop
End If
rs.Close
cn.Close
Set rs = Nothing
Set cn = Nothing
' 4. 【核心修复】安全且极速地回写可见数据
Dim matchCount As Long
matchCount = 0
' 关闭屏幕刷新、自动计算和事件触发,拉满单行写入性能
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
For Each cell In visibleRange
currentNum = Trim(cell.value)
If dbDict.Exists(currentNum) Then
Dim dbRecord As Variant
dbRecord = dbDict(currentNum)
' 【神级优化点】将4个字段装入一个微型一维数组利用 Resize 一次性写入 B 到 E 列
' 这样每一行只需要 1 次单元格操作,而不是 4 次!性能无限逼近全量数组写回。
cell.Offset(0, 1).Resize(1, 4).value = Array(dbRecord(0), dbRecord(1), dbRecord(2), dbRecord(3))
matchCount = matchCount + 1
End If
Next cell
' 恢复应用状态
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Set dbDict = Nothing
Dim elapsedTime As Double
elapsedTime = Timer - startTime
MsgBox "数据提取完成!" & vbCrLf & _
"成功匹配并更新了 " & matchCount & " 条筛选记录。" & vbCrLf & _
"用时: " & Format(elapsedTime, "0.00") & " 秒", vbInformation
Exit Sub
ErrorHandler:
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
On Error Resume Next
If Not rs Is Nothing Then If rs.State = 1 Then rs.Close
If Not cn Is Nothing Then If cn.State = 1 Then cn.Close
On Error GoTo 0
MsgBox "提取Access数据时发生异常: " & Err.Description, vbCritical
End Sub
'=====================================================================
' 函数: GetOrderSheet
' 功能: 获取[产品订单]工作表
' 返回: Worksheet - 工作表对象
'=====================================================================
Private Function GetOrderSheet() As Worksheet
On Error Resume Next
Set GetOrderSheet = ThisWorkbook.Worksheets("产品订单")
On Error GoTo 0
End Function

View File

@@ -0,0 +1,452 @@
'=====================================================================
' 模块名: BIPUploadModule
' 功能: 处理产品订单数据提取BOM后生成[BIP上传模板]格式数据
'=====================================================================
Option Explicit
'=====================================================================
' 常量定义
'=====================================================================
' 提取条件配置
Private Const CONDITION_CONFIG = "azxs安装形式 |bkxs表壳形式 |gclj过程连接 |jycz接液材质 |lcfw量程范围 |fjgn附加功能"
'=====================================================================
' 过程: ProcessOrdersToBIP
' 功能: 处理产品订单数据生成BIP上传格式
' 说明: 主入口程序,从[产品订单]读取数据,输出到[BIP上传模板]
'=====================================================================
Public Sub ProcessOrdersToBIP()
On Error GoTo ErrorHandler
Dim startTime As Double
startTime = Timer
Application.ScreenUpdating = False
' 准备工作表对象
Dim orderSheet As Worksheet
Dim bipSheet As Worksheet
Dim bomSheet As Worksheet
' 获取[产品订单]工作表
Set orderSheet = GetOrderSheet()
If orderSheet Is Nothing Then
Application.ScreenUpdating = True
MsgBox "未找到[产品订单]工作表!", vbCritical
Exit Sub
End If
' 获取[BIP上传模板]工作表
Set bipSheet = GetBIPUploadSheet()
' 获取BOM库工作表
Set bomSheet = GetBomSheet()
If bomSheet Is Nothing Then
Application.ScreenUpdating = True
MsgBox "未找到[平台配置清单]工作表!", vbCritical
Exit Sub
End If
' 初始化BOM提取器
Dim BomExtractor As BomExtractor
Set BomExtractor = New BomExtractor
BomExtractor.SetWorksheet bomSheet
If Not BomExtractor.LoadBomData Then
Application.ScreenUpdating = True
MsgBox "加载BOM数据失败:" & BomExtractor.GetErrorSummary, vbCritical
Exit Sub
End If
' 清空BIP上传模板数据保留表头
ClearBIPSheetData bipSheet
' 写入BIP上传模板表头
WriteBIPHeader bipSheet
' 获取订单数据行数
Dim lastRow As Long
lastRow = orderSheet.Cells(orderSheet.Rows.count, 1).End(xlUp).row
' 如果只有表头或没有数据
If lastRow < 2 Then
Application.ScreenUpdating = True
MsgBox "[产品订单]工作表中没有数据!", vbExclamation
Exit Sub
End If
' 【性能核心】全量读入源数据
Dim sourceDataArr As Variant
sourceDataArr = orderSheet.Range("A2:G" & lastRow).value
' 【筛选核心】获取可见区域
Dim visibleRange As Range
On Error Resume Next
Set visibleRange = orderSheet.Range("A2:A" & lastRow).SpecialCells(xlCellTypeVisible)
On Error GoTo ErrorHandler
If visibleRange Is Nothing Then
Application.ScreenUpdating = True
MsgBox "当前筛选状态下没有可见的数据。", vbInformation
Exit Sub
End If
' 收集所有输出数据
Dim outputData As Collection
Set outputData = New Collection
Dim cell As Range
Dim arrIndex As Long
Dim processedCount As Long
Dim orderCount As Long
Dim skippedCount As Long
processedCount = 0
orderCount = 0
skippedCount = 0
' 遍历筛选出来的可见单元格
For Each cell In visibleRange
' 计算内存数组索引
arrIndex = cell.row - 1
' 读取订单数据
Dim totalQueueNum As String
Dim orderNumber As String
Dim ProductModel As String
Dim Quantity As String
Dim productCode As String
Dim componentPriority As String
Dim isIssueMaterial As String
totalQueueNum = Trim(sourceDataArr(arrIndex, 1)) ' A列总排号
orderNumber = Trim(sourceDataArr(arrIndex, 2)) ' B列生产订单号
ProductModel = Trim(sourceDataArr(arrIndex, 3)) ' C列产品型号
Quantity = Trim(sourceDataArr(arrIndex, 4)) ' D列数量
productCode = Trim(sourceDataArr(arrIndex, 5)) ' E列产品编码
componentPriority = Trim(sourceDataArr(arrIndex, 6)) ' F列部件优先
isIssueMaterial = Trim(sourceDataArr(arrIndex, 7)) ' G列是否领料
' 【拦截逻辑】忽略[是否领料]为"否"的订单
If isIssueMaterial = "否" Then
skippedCount = skippedCount + 1
GoTo ContinueLoop
End If
' 跳过空行
If orderNumber = "" And ProductModel = "" Then
GoTo ContinueLoop
End If
' 验证必填字段
If orderNumber = "" Then
MsgBox "工作表第" & cell.row & "行:生产订单号为空,跳过该行!", vbExclamation
GoTo ContinueLoop
End If
If ProductModel = "" Then
MsgBox "工作表第" & cell.row & "行:产品型号为空,跳过该行!", vbExclamation
GoTo ContinueLoop
End If
If Quantity = "" Then
MsgBox "工作表第" & cell.row & "行:数量为空,跳过该行!", vbExclamation
GoTo ContinueLoop
End If
orderCount = orderCount + 1
' 处理单个订单,收集输出数据
ProcessSingleOrder orderNumber, ProductModel, Quantity, productCode, _
componentPriority, BomExtractor, outputData
processedCount = processedCount + 1
ContinueLoop:
Next cell
' 批量写入数据到工作表
If outputData.count > 0 Then
WriteBatchData bipSheet, outputData
End If
' 格式化BIP上传模板
FormatBIPSheet bipSheet
Dim elapsedTime As Double
elapsedTime = Timer - startTime
Application.ScreenUpdating = True
MsgBox "处理完成!" & vbCrLf & _
"处理有效订单数: " & orderCount & vbCrLf & _
"忽略无效订单数: " & skippedCount & vbCrLf & _
"生成BIP行数: " & outputData.count & vbCrLf & _
"用时: " & Format(elapsedTime, "0.00") & "秒", vbInformation
' 激活BIP上传模板
bipSheet.Activate
Exit Sub
ErrorHandler:
Application.ScreenUpdating = True
MsgBox "处理异常: " & Err.Description, vbCritical
End Sub
'=====================================================================
' 过程: ProcessSingleOrder
' 功能: 处理单个订单提取BOM并将数据添加到输出集合
' 参数: orderNumber - 生产订单号
' ProductModel - 产品型号
' Quantity - 生产数量
' productCode - 产品编码
' componentPriority - 部件优先标志("是"或"否"
' BomExtractor - BOM提取器对象
' outputData - 输出数据集合
'=====================================================================
Private Sub ProcessSingleOrder(orderNumber As String, _
ProductModel As String, _
Quantity As String, _
productCode As String, _
componentPriority As String, _
BomExtractor As BomExtractor, _
outputData As Collection)
On Error Resume Next
' 根据部件优先设置排除类别
BomExtractor.ClearExcludeCategories
If UCase(componentPriority) = "否" Or componentPriority = "0" Or componentPriority = "FALSE" Then
Dim excludeCats As New Collection
excludeCats.Add "部件"
BomExtractor.SetExcludeCategories excludeCats
End If
' 解析产品型号
Dim parser As ProductModelParser
Set parser = New ProductModelParser
If Not parser.Parse(ProductModel) Then
' 解析失败,添加一行空物料记录
outputData.Add CreateBIPRowArray(orderNumber, productCode, Quantity, 1, "")
Exit Sub
End If
' 提取BOM
Dim matchedItems As Collection
Set matchedItems = BomExtractor.ExtractBom(parser.conditions)
' 输出结果
If matchedItems.count = 0 Then
' 没有匹配项,添加一行空物料记录
outputData.Add CreateBIPRowArray(orderNumber, productCode, Quantity, 1, "")
Else
' 输出每个匹配的物料
Dim item As BomItem
Dim lineIndex As Long
lineIndex = 1
' 创建字典跟踪每个 BIP 行号基数的当前序号
Dim bipRowBaseDict As Object
Set bipRowBaseDict = CreateObject("Scripting.Dictionary")
For Each item In matchedItems
' 计算实际行号:行号 = BIP 行号基数 + 组内序号 (从 1 开始)
Dim baseValue As Long
baseValue = item.BipRowNumberBase
Dim currentIndex As Long
If bipRowBaseDict.Exists(baseValue) Then
currentIndex = bipRowBaseDict(baseValue) + 1
Else
currentIndex = 1
End If
bipRowBaseDict(baseValue) = currentIndex
Dim actualRowNumber As Long
actualRowNumber = baseValue + currentIndex
' 创建 BIP 行数据并添加到集合 (已移除备注参数)
outputData.Add CreateBIPRowArray(orderNumber, productCode, Quantity, _
actualRowNumber, item.Code66)
lineIndex = lineIndex + 1
Next item
End If
End Sub
'=====================================================================
' 函数CreateBIPRowArray
' 功能:创建 BIP 上传模板一行数据的数组
' 参数orderNumber - 生产订单号
' productCode - 产品编码
' Quantity - 生产数量
' actualRowNumber - 实际行号BIP 行号基数 + 组内序号)
' materialCode - 材料编码66 编码)
' 返回Variant() - 包含 9 个元素的数组
'=====================================================================
Private Function CreateBIPRowArray(orderNumber As String, _
productCode As String, _
Quantity As String, _
actualRowNumber As Long, _
materialCode As String) As Variant()
Dim rowData(1 To 9) As Variant
rowData(1) = orderNumber ' 来源单据号(生产订单号)
rowData(2) = productCode ' 产品编码
rowData(3) = Quantity ' 生产数量
rowData(4) = actualRowNumber ' 行号
rowData(5) = materialCode ' 材料编码66 编码)
rowData(6) = "一般发料" ' 供应方式(固定值)
rowData(7) = Date ' 需用日期(当天日期)
rowData(8) = "重庆布莱迪仪器仪表有限公司" ' 发料组织(固定值)
rowData(9) = Quantity ' 计划出库数量(与生产数量一致)
CreateBIPRowArray = rowData
End Function
'=====================================================================
' 过程: WriteBatchData
' 功能: 批量写入数据到工作表
' 参数: ws - 工作表对象
' outputData - 输出数据集合,每个元素是一个一维数组
'=====================================================================
Private Sub WriteBatchData(ws As Worksheet, outputData As Collection)
' 如果没有数据,直接返回
If outputData.count = 0 Then
Exit Sub
End If
' 创建二维数组
Dim rowCount As Long
rowCount = outputData.count
Dim resultData() As Variant
ReDim resultData(1 To rowCount, 1 To 9)
' 填充数据到二维数组
Dim i As Long
Dim rowArray As Variant
For i = 1 To rowCount
rowArray = outputData(i)
resultData(i, 1) = rowArray(1)
resultData(i, 2) = rowArray(2)
resultData(i, 3) = rowArray(3)
resultData(i, 4) = rowArray(4)
resultData(i, 5) = rowArray(5)
resultData(i, 6) = rowArray(6)
resultData(i, 7) = rowArray(7)
resultData(i, 8) = rowArray(8)
resultData(i, 9) = rowArray(9)
Next i
' 一次性写入工作表从第2行开始
ws.Range("A2").Resize(rowCount, 9).value = resultData
End Sub
'=====================================================================
' 过程: WriteBIPHeader
' 功能: 写入BIP上传模板表头
' 参数: ws - 工作表对象
'=====================================================================
Private Sub WriteBIPHeader(ws As Worksheet)
' 第1行主表头
ws.Cells(1, 1).value = "来源单据号(生产订单号)"
ws.Cells(1, 2).value = "产品编码"
ws.Cells(1, 3).value = "生产数量"
ws.Cells(1, 4).value = "行号"
ws.Cells(1, 5).value = "材料编码"
ws.Cells(1, 6).value = "供应方式"
ws.Cells(1, 7).value = "需用日期"
ws.Cells(1, 8).value = "发料组织"
ws.Cells(1, 9).value = "计划出库数量"
End Sub
'=====================================================================
' 函数: GetOrderSheet
' 功能: 获取[产品订单]工作表
' 返回: Worksheet - 工作表对象
'=====================================================================
Private Function GetOrderSheet() As Worksheet
On Error Resume Next
Set GetOrderSheet = ThisWorkbook.Worksheets("产品订单")
On Error GoTo 0
End Function
'=====================================================================
' 函数: GetBIPUploadSheet
' 功能: 获取或创建[BIP上传模板]工作表
' 返回: Worksheet - 工作表对象
'=====================================================================
Private Function GetBIPUploadSheet() As Worksheet
Dim wsName As String
wsName = "BIP上传模板"
On Error Resume Next
Set GetBIPUploadSheet = ThisWorkbook.Worksheets(wsName)
On Error GoTo 0
If GetBIPUploadSheet Is Nothing Then
' 创建新工作表
Set GetBIPUploadSheet = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.count))
GetBIPUploadSheet.Name = wsName
End If
End Function
'=====================================================================
' 函数: GetBomSheet
' 功能: 获取BOM工作表
' 返回: Worksheet - BOM工作表对象
'=====================================================================
Private Function GetBomSheet() As Worksheet
On Error Resume Next
Set GetBomSheet = ThisWorkbook.Worksheets("平台配置清单")
On Error GoTo 0
End Function
'=====================================================================
' 过程: ClearBIPSheetData
' 功能: 清空BIP上传模板的数据保留表头
' 参数: ws - 工作表对象
'=====================================================================
Private Sub ClearBIPSheetData(ws As Worksheet)
' 清空从第2行开始的所有数据
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.count, 1).End(xlUp).row
If lastRow > 1 Then
ws.Rows("2:" & lastRow).ClearContents
End If
End Sub
'=====================================================================
' 过程: FormatBIPSheet
' 功能: 格式化BIP上传模板工作表
' 参数: ws - 工作表对象
'=====================================================================
Private Sub FormatBIPSheet(ws As Worksheet)
On Error Resume Next
' 设置表头格式
With ws.Rows(1)
.Font.Bold = True
.Interior.Color = RGB(217, 217, 217)
.HorizontalAlignment = xlCenter
End With
' 设置所有单元格居中对齐
With ws.UsedRange
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
End With
' 自动调整列宽
ws.Columns.AutoFit
' 设置日期列格式
ws.Columns(7).NumberFormat = "yyyy/mm/dd"
On Error GoTo 0
End Sub

View File

@@ -0,0 +1,513 @@
'=====================================================================
' 模块名: ComponentInventoryCheckModule
' 功能: 部件库存核推模块 - 自动核对产品订单中"部件"类物料的库存情况
' 特性: [已重构] 支持仅对筛选后的数据进行处理,采用内存极速读取
'=====================================================================
Option Explicit
'=====================================================================
' 数据结构定义 - 使用字典以支持引用更新
'=====================================================================
' 订单字典键
Private Const ORDER_ROW As String = "RowNumber"
Private Const ORDER_MODEL As String = "ProductModel"
Private Const ORDER_QUANTITY As String = "Quantity"
Private Const ORDER_COMP_CODE As String = "ComponentCode"
Private Const ORDER_COMP_QTY As String = "ComponentQty"
Private Const ORDER_HAS_COMP As String = "HasComponent"
Private Const ORDER_PARSE_ERR As String = "ParseError"
' 部件库存字典键
Private Const INV_CODE As String = "ComponentCode"
Private Const INV_DEMAND As String = "TotalDemand"
Private Const INV_STOCK As String = "AvailableStock"
Private Const INV_SHORTAGE As String = "IsShortage"
' 统计信息结构
Private Type Statistics
TotalOrders As Long ' 总订单数
OrdersWithComponent As Long ' 包含部件的订单数
OrdersSufficient As Long ' 库存充足订单数
OrdersInsufficient As Long ' 库存不足订单数
OrdersSkipped As Long ' 跳过订单数
End Type
'=====================================================================
' 主入口程序
'=====================================================================
Public Sub CheckComponentInventory()
On Error GoTo ErrorHandler
Dim startTime As Double
startTime = Timer
' 提升性能:关闭屏幕更新和自动计算
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
' 获取工作表对象
Dim orderSheet As Worksheet
Dim inventorySheet As Worksheet
Dim bomSheet As Worksheet
Set orderSheet = GetOrderSheet()
If orderSheet Is Nothing Then
RestoreAppStatus
MsgBox "未找到[产品订单]工作表!", vbExclamation
Exit Sub
End If
Set inventorySheet = GetInventorySheet()
If inventorySheet Is Nothing Then
RestoreAppStatus
MsgBox "未找到[现存量]工作表!", vbExclamation
Exit Sub
End If
Set bomSheet = GetBomSheet()
If bomSheet Is Nothing Then
RestoreAppStatus
MsgBox "未找到[平台配置清单]工作表!", vbExclamation
Exit Sub
End If
' 检查订单数据 (调整为按C列:产品型号获取最后一行)
Dim lastRow As Long
lastRow = orderSheet.Cells(orderSheet.Rows.count, 3).End(xlUp).row
If lastRow < 2 Then
RestoreAppStatus
MsgBox "[产品订单]工作表没有数据!", vbExclamation
Exit Sub
End If
' 【核心重构】获取筛选后的可见单元格区域 (A列)
Dim visibleRange As Range
On Error Resume Next
Set visibleRange = orderSheet.Range("A2:A" & lastRow).SpecialCells(xlCellTypeVisible)
On Error GoTo ErrorHandler
If visibleRange Is Nothing Then
RestoreAppStatus
MsgBox "当前筛选状态下没有可见的数据。", vbInformation
Exit Sub
End If
' 初始化BOM提取器
Dim BomExtractor As BomExtractor
Set BomExtractor = New BomExtractor
BomExtractor.SetWorksheet bomSheet
If Not BomExtractor.LoadBomData Then
RestoreAppStatus
MsgBox "加载BOM数据失败:" & BomExtractor.GetErrorSummary, vbCritical
Exit Sub
End If
' 读取库存数据到字典
Dim inventoryData As Object
Set inventoryData = LoadInventoryData(inventorySheet)
If inventoryData.count = 0 Then
RestoreAppStatus
MsgBox "[现存量]工作表没有有效数据!", vbExclamation
Exit Sub
End If
' 【核心重构】传递可见区域和总行数,仅读取可见订单数据
Dim orders As Collection
Set orders = LoadOrderData(orderSheet, visibleRange, lastRow)
If orders.count = 0 Then
RestoreAppStatus
MsgBox "可见区域中没有有效的订单数据!", vbExclamation
Exit Sub
End If
' 解析所有订单的BOM
ParseAllOrdersBOM orders, BomExtractor
' 统计部件总需求
Dim componentDemands As Object
Set componentDemands = CalculateComponentDemand(orders)
If componentDemands.count = 0 Then
RestoreAppStatus
MsgBox "筛选的订单中没有包含'部件'类别物料,无需处理库存!", vbInformation
Exit Sub
End If
' 验证库存
Dim validationWarnings As Collection
Set validationWarnings = ValidateInventory(componentDemands, inventoryData)
' 按订单顺序分配库存并标记
Dim stats As Statistics
AllocateInventory orders, componentDemands, orderSheet, stats
' 恢复应用状态
RestoreAppStatus
' 输出结果统计
Dim elapsedTime As Double
elapsedTime = Timer - startTime
Dim resultMsg As String
resultMsg = "部件库存核对完成!" & vbCrLf & vbCrLf
resultMsg = resultMsg & "处理筛选订单数: " & stats.TotalOrders & vbCrLf
resultMsg = resultMsg & "包含部件订单: " & stats.OrdersWithComponent & vbCrLf
resultMsg = resultMsg & "库存充足订单: " & stats.OrdersSufficient & vbCrLf
resultMsg = resultMsg & "库存不足订单: " & stats.OrdersInsufficient & vbCrLf
If stats.OrdersSkipped > 0 Then
resultMsg = resultMsg & "跳过订单数: " & stats.OrdersSkipped & vbCrLf
End If
resultMsg = resultMsg & vbCrLf & "耗时: " & Format(elapsedTime, "0.00") & "秒"
' 显示警告信息(如果有)
If validationWarnings.count > 0 Then
resultMsg = resultMsg & vbCrLf & vbCrLf & "警告信息:" & vbCrLf
resultMsg = resultMsg & JoinCollection(validationWarnings, vbCrLf)
End If
MsgBox resultMsg, vbInformation
Exit Sub
ErrorHandler:
RestoreAppStatus
MsgBox "部件库存核对异常: " & Err.Description, vbCritical
End Sub
'=====================================================================
' 辅助过程: RestoreAppStatus
' 功能: 恢复Excel应用程序的状态
'=====================================================================
Private Sub RestoreAppStatus()
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
'=====================================================================
' 函数: LoadOrderData
' 功能: 读取订单数据
' 参数: ws - [产品订单]工作表
' 返回: Collection - 每个元素是字典对象,包含订单信息
'=====================================================================
Private Function LoadOrderData(ws As Worksheet, visibleRange As Range, lastRow As Long) As Collection
Set LoadOrderData = New Collection
' 全量读入内存数组提升速度
Dim sourceDataArr As Variant
sourceDataArr = ws.Range("A2:F" & lastRow).value
Dim cell As Range
Dim arrIndex As Long
' 仅遍历可见的单元格
For Each cell In visibleRange
Dim model As String
Dim qty As Variant
' 数组索引 = Excel行号 - 1
arrIndex = cell.row - 1
' 从内存数组中提取数据
model = Trim(sourceDataArr(arrIndex, 3)) ' C列: 产品型号
qty = sourceDataArr(arrIndex, 4) ' D列: 产品数量
' 跳过空行
If model <> "" Then
Dim order As Object
Set order = CreateObject("Scripting.Dictionary")
' 记录真实的Excel行号用于后续库存不足时精准写入F列
order.Add ORDER_ROW, CLng(cell.row)
order.Add ORDER_MODEL, CStr(model)
order.Add ORDER_QUANTITY, CDbl(IIf(IsNull(qty) Or IsEmpty(qty), 0, qty))
order.Add ORDER_COMP_CODE, ""
order.Add ORDER_COMP_QTY, 0
order.Add ORDER_HAS_COMP, False
order.Add ORDER_PARSE_ERR, ""
LoadOrderData.Add order
End If
Next cell
End Function
'=====================================================================
' 函数: LoadInventoryData
' 功能: 读取库存数据
' 参数: ws - [现存量]工作表
' 返回: Dictionary(物料编码 -> 库存数量)
'=====================================================================
Private Function LoadInventoryData(ws As Worksheet) As Object
Set LoadInventoryData = CreateObject("Scripting.Dictionary")
' 从第4行开始读取(第3行是表头)
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.count, 2).End(xlUp).row
Dim i As Long
For i = 4 To lastRow
Dim code As String
Dim qty As Variant
code = Trim(ws.Cells(i, 2).value) ' B列: 物料编码
qty = ws.Cells(i, 10).value ' J列: 结存主数量
If code <> "" And Not IsEmpty(qty) Then
If Not LoadInventoryData.Exists(code) Then
LoadInventoryData.Add code, CDbl(qty)
End If
End If
Next i
End Function
'=====================================================================
' 过程: ParseAllOrdersBOM
' 功能: 解析所有订单的BOM
' 参数: orders - 订单集合(每个元素是字典)
' bomExtractor - BOM提取器
'=====================================================================
Private Sub ParseAllOrdersBOM(orders As Collection, BomExtractor As BomExtractor)
Dim i As Long
For i = 1 To orders.count
Dim order As Object
Set order = orders(i)
ParseOrderBOM order, BomExtractor
Next i
End Sub
'=====================================================================
' 过程: ParseOrderBOM
' 功能: 解析单个订单的BOM,识别部件类别物料
' 参数: orderInfo - 订单信息字典(ByRef)
' bomExtractor - BOM提取器
'=====================================================================
Private Sub ParseOrderBOM(ByRef orderInfo As Object, BomExtractor As BomExtractor)
On Error Resume Next
' 解析型号
Dim parser As ProductModelParser
Set parser = New ProductModelParser
If Not parser.Parse(orderInfo(ORDER_MODEL)) Then
orderInfo(ORDER_PARSE_ERR) = "解析失败: " & parser.ErrorMessage
Exit Sub
End If
' 提取BOM
Dim matchedItems As Collection
Set matchedItems = BomExtractor.ExtractBom(parser.conditions)
' 查找"部件"类别物料
Dim item As BomItem
For Each item In matchedItems
If item.category = "部件" Then
orderInfo(ORDER_COMP_CODE) = item.Code66
orderInfo(ORDER_COMP_QTY) = item.Quantity
orderInfo(ORDER_HAS_COMP) = True
Exit For
End If
Next item
End Sub
'=====================================================================
' 函数: CalculateComponentDemand
' 功能: 统计部件总需求
' 参数: orders - 订单集合
' 返回: Dictionary(部件编码 -> 库存信息字典)
'=====================================================================
Private Function CalculateComponentDemand(orders As Collection) As Object
Dim demands As Object
Set demands = CreateObject("Scripting.Dictionary")
Dim i As Long
For i = 1 To orders.count
Dim order As Object
Set order = orders(i)
If order(ORDER_HAS_COMP) Then
Dim demand As Double
demand = order(ORDER_COMP_QTY) * order(ORDER_QUANTITY)
Dim compCode As String
compCode = order(ORDER_COMP_CODE)
If demands.Exists(compCode) Then
Dim compInv As Object
Set compInv = demands(compCode)
compInv(INV_DEMAND) = compInv(INV_DEMAND) + demand
Else
Dim newComp As Object
Set newComp = CreateObject("Scripting.Dictionary")
newComp.Add INV_CODE, compCode
newComp.Add INV_DEMAND, demand
newComp.Add INV_STOCK, 0
newComp.Add INV_SHORTAGE, False
demands.Add compCode, newComp
End If
End If
Next i
Set CalculateComponentDemand = demands
End Function
'=====================================================================
' 函数: ValidateInventory
' 功能: 验证库存数据
' 参数: componentDemands - 部件需求字典
' inventoryData - 库存数据字典
' 返回: Collection - 警告信息集合(找不到的部件)
'=====================================================================
Private Function ValidateInventory(componentDemands As Object, _
inventoryData As Object) As Collection
Set ValidateInventory = New Collection
Dim code As Variant
For Each code In componentDemands.Keys
Dim compInv As Object
Set compInv = componentDemands(code)
' 检查库存中是否存在该部件
If Not inventoryData.Exists(compInv(INV_CODE)) Then
compInv(INV_STOCK) = 0
compInv(INV_SHORTAGE) = True
ValidateInventory.Add "部件 '" & compInv(INV_CODE) & "' 在[现存量]中未找到"
Else
compInv(INV_STOCK) = inventoryData(compInv(INV_CODE))
If compInv(INV_DEMAND) > compInv(INV_STOCK) Then
compInv(INV_SHORTAGE) = True
End If
End If
Next code
End Function
'=====================================================================
' 过程: AllocateInventory
' 功能: 按订单顺序分配库存并标记
' 参数: orders - 订单集合
' componentDemands - 部件需求字典
' orderSheet - 订单工作表
' stats - 统计信息(ByRef)
'=====================================================================
Private Sub AllocateInventory(orders As Collection, _
componentDemands As Object, _
orderSheet As Worksheet, _
ByRef stats As Statistics)
' 初始化统计
stats.TotalOrders = orders.count
stats.OrdersWithComponent = 0
stats.OrdersSufficient = 0
stats.OrdersInsufficient = 0
stats.OrdersSkipped = 0
Dim i As Long
For i = 1 To orders.count
Dim order As Object
Set order = orders(i)
' 跳过解析失败的订单
If order(ORDER_PARSE_ERR) <> "" Then
stats.OrdersSkipped = stats.OrdersSkipped + 1
GoTo NextOrder
End If
' 跳过没有部件的订单
If Not order(ORDER_HAS_COMP) Then
stats.OrdersSkipped = stats.OrdersSkipped + 1
GoTo NextOrder
End If
' 跳过数量为0的订单
If order(ORDER_QUANTITY) = 0 Then
stats.OrdersSkipped = stats.OrdersSkipped + 1
GoTo NextOrder
End If
stats.OrdersWithComponent = stats.OrdersWithComponent + 1
' 获取部件库存信息
Dim compInv As Object
Set compInv = componentDemands(order(ORDER_COMP_CODE))
' 计算需求量
Dim requiredQty As Double
requiredQty = order(ORDER_COMP_QTY) * order(ORDER_QUANTITY)
' 检查库存是否充足
If compInv(INV_STOCK) >= requiredQty Then
' 库存充足,扣减库存,保持原值
compInv(INV_STOCK) = compInv(INV_STOCK) - requiredQty
stats.OrdersSufficient = stats.OrdersSufficient + 1
Else
' --- 因为已经保存了真正的行号 ORDER_ROW, 在关闭屏幕刷新的情况下,这里直接写入是非常快的 ---
orderSheet.Cells(order(ORDER_ROW), 6).value = "否"
compInv(INV_STOCK) = compInv(INV_STOCK) - requiredQty
stats.OrdersInsufficient = stats.OrdersInsufficient + 1
End If
NextOrder:
Next i
End Sub
'=====================================================================
' 函数: GetOrderSheet
' 功能: 获取[产品订单]工作表
' 返回: Worksheet
'=====================================================================
Private Function GetOrderSheet() As Worksheet
On Error Resume Next
Set GetOrderSheet = ThisWorkbook.Worksheets("产品订单")
On Error GoTo 0
End Function
'=====================================================================
' 函数: GetInventorySheet
' 功能: 获取[现存量]工作表
' 返回: Worksheet
'=====================================================================
Private Function GetInventorySheet() As Worksheet
On Error Resume Next
Set GetInventorySheet = ThisWorkbook.Worksheets("现存量")
On Error GoTo 0
End Function
'=====================================================================
' 函数: GetBomSheet
' 功能: 获取[平台配置清单]工作表
' 返回: Worksheet
'=====================================================================
Private Function GetBomSheet() As Worksheet
On Error Resume Next
Set GetBomSheet = ThisWorkbook.Worksheets("平台配置清单")
On Error GoTo 0
End Function
'=====================================================================
' 函数: JoinCollection
' 功能: 将集合内容连接为字符串
' 参数: coll - 集合
' separator - 分隔符
' 返回: String
'=====================================================================
Private Function JoinCollection(coll As Collection, separator As String) As String
Dim result As String
result = ""
Dim item As Variant
Dim isFirst As Boolean
isFirst = True
For Each item In coll
If Not isFirst Then
result = result & separator
End If
result = result & CStr(item)
isFirst = False
Next item
JoinCollection = result
End Function

View File

@@ -0,0 +1,586 @@
'=====================================================================
' 模块名: ErrorAnalysisModule
' 功能: BOM匹配异常分析模块仅提取报错订单拆分多行并自动回溯"未匹配参数"
' 特性: 采用"特征权重算法"解决模糊平局(Tie)导致的参数误报问题
'=====================================================================
Option Explicit
' 提取条件配置
Private Const CONDITION_CONFIG = "azxs,安装形式|bkxs,表壳形式|gclj,过程连接|jycz,接液材质|lcfw,量程范围|fjgn,附加功能"
' 指定输出[BOM匹配异常报表]的表头所在行号
Private Const OUTPUT_HEADER_ROW As Long = 10
'=====================================================================
' 过程: GenerateErrorAnalysisReport
' 功能: 批量处理产品型号输出BOM匹配异常报表
'=====================================================================
Public Sub GenerateErrorAnalysisReport()
On Error GoTo ErrorHandler
Dim startTime As Double
startTime = Timer
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
' 获取工作表
Dim orderSheet As Worksheet
Dim bomSheet As Worksheet
Dim outputSheet As Worksheet
Set orderSheet = GetOrderSheet()
If orderSheet Is Nothing Then
RestoreAppStatus
MsgBox "未找到[产品订单]工作表!", vbCritical
Exit Sub
End If
Set bomSheet = GetBomSheet()
If bomSheet Is Nothing Then
RestoreAppStatus
MsgBox "未找到[平台配置清单]工作表!", vbCritical
Exit Sub
End If
' 初始化BOM提取器
Dim BomExtractor As BomExtractor
Set BomExtractor = New BomExtractor
BomExtractor.SetWorksheet bomSheet
If Not BomExtractor.LoadBomData Then
RestoreAppStatus
MsgBox "加载BOM数据失败:" & BomExtractor.GetErrorSummary, vbCritical
Exit Sub
End If
' 获取或创建输出表
Set outputSheet = CreateErrorOutputSheet()
WriteOutputHeader outputSheet
' 获取筛选后的订单数据
Dim lastRow As Long
lastRow = orderSheet.Cells(orderSheet.Rows.count, 3).End(xlUp).row
If lastRow < 2 Then
RestoreAppStatus
MsgBox "[产品订单]工作表中没有数据!", vbExclamation
Exit Sub
End If
Dim sourceDataArr As Variant
sourceDataArr = orderSheet.Range("A2:F" & lastRow).value
Dim visibleRange As Range
On Error Resume Next
Set visibleRange = orderSheet.Range("A2:A" & lastRow).SpecialCells(xlCellTypeVisible)
On Error GoTo ErrorHandler
If visibleRange Is Nothing Then
RestoreAppStatus
MsgBox "当前筛选状态下没有可见的数据。", vbInformation
Exit Sub
End If
' 初始化正则表达式引擎 (只初始化一次,提速)
Dim regEx As Object
Set regEx = CreateObject("VBScript.RegExp")
regEx.Global = True
regEx.IgnoreCase = True
' 匹配如 azxs=A0, fjgn!=N1 这样的条件结构
regEx.Pattern = "(azxs|bkxs|gclj|jycz|lcfw|fjgn)\s*(!=|=)\s*([A-Za-z0-9_]+)"
Dim outputData As Collection
Set outputData = New Collection
Dim cell As Range
Dim arrIndex As Long
Dim totalProcessed As Long
Dim errorOrdersCount As Long
Dim errorRowsCount As Long
totalProcessed = 0
errorOrdersCount = 0
errorRowsCount = 0
' 遍历可见订单
For Each cell In visibleRange
arrIndex = cell.row - 1
Dim totalQueueNum As String
Dim orderNumber As String
Dim modelString As String
Dim componentPriority As String
totalQueueNum = Trim(sourceDataArr(arrIndex, 1))
orderNumber = Trim(sourceDataArr(arrIndex, 2))
modelString = Trim(sourceDataArr(arrIndex, 3))
componentPriority = Trim(sourceDataArr(arrIndex, 6))
If modelString <> "" Then
totalProcessed = totalProcessed + 1
' 解析并匹配BOM
Dim parser As ProductModelParser
Set parser = New ProductModelParser
Dim hasError As Boolean
hasError = False
Dim errors As String
errors = ""
If Not parser.Parse(modelString) Then
hasError = True
errors = "型号解析失败: " & parser.ErrorMessage
Else
' 提取逻辑
BomExtractor.ClearExcludeCategories
If UCase(componentPriority) = "否" Or componentPriority = "0" Or componentPriority = "FALSE" Then
Dim excludeCats As New Collection
excludeCats.Add "部件"
BomExtractor.SetExcludeCategories excludeCats
End If
Dim matchedItems As Collection
Set matchedItems = BomExtractor.ExtractBom(parser.conditions)
errors = BomExtractor.GetErrorSummary()
If errors <> "" Or matchedItems.count = 0 Then
hasError = True
If errors = "" And matchedItems.count = 0 Then
errors = "完全未匹配到物料"
End If
End If
' 深度检查BOM行自身的报错如"匹配到多条"
Dim item As BomItem
For Each item In matchedItems
If item.MatchError <> "" Then
hasError = True
errors = errors & item.category & ":" & item.MatchError & ";"
End If
Next item
End If
' 如果存在错误,拆分为多行并寻找未匹配参数
If hasError Then
errorOrdersCount = errorOrdersCount + 1
Dim errArray() As String
errArray = Split(errors, ";")
Dim i As Long
For i = LBound(errArray) To UBound(errArray)
Dim singleError As String
singleError = Trim(errArray(i))
If singleError <> "" Then
Dim unmatchedValues As String
unmatchedValues = "无法精准定位:无法精准定位"
' 如果是型号解析失败,跳过溯源
If InStr(singleError, "型号解析失败") = 0 And InStr(singleError, "完全未匹配到物料") = 0 Then
Dim targetCategory As String
targetCategory = ExtractCategoryName(singleError)
If targetCategory <> "" Then
' 核心:调用带权重的重合度算法定位冲突参数(通过 | 分隔,内部用 : 分隔键值)
unmatchedValues = FindUnmatchedParameter(targetCategory, parser.conditions, BomExtractor.GetAllItems(), regEx)
End If
End If
' ---> 拆分未匹配参数,避免糅合在一起
Dim unmatchArr() As String
unmatchArr = Split(unmatchedValues, "|")
Dim j As Long
For j = LBound(unmatchArr) To UBound(unmatchArr)
Dim singleUnmatch As String
singleUnmatch = Trim(unmatchArr(j))
If singleUnmatch <> "" Then
Dim uParam As String
Dim uValue As String
Dim colonPos As Long
colonPos = InStr(singleUnmatch, ":")
' 拆分键和值
If colonPos > 0 Then
uParam = Left(singleUnmatch, colonPos - 1)
uValue = Mid(singleUnmatch, colonPos + 1)
Else
uParam = singleUnmatch
uValue = singleUnmatch
End If
outputData.Add CreateErrorRowArray(totalQueueNum, orderNumber, modelString, parser.conditions, uParam, uValue, singleError)
errorRowsCount = errorRowsCount + 1
End If
Next j
End If
Next i
End If
End If
Next cell
' 批量写入数据
If outputData.count > 0 Then
WriteBatchData outputSheet, outputData
Else
MsgBox "太棒了所选订单均完美匹配BOM未发现任何异常。", vbInformation
End If
' 格式化表格
FormatOutputSheet outputSheet
RestoreAppStatus
Dim elapsedTime As Double
elapsedTime = Timer - startTime
MsgBox "异常分析完成!" & vbCrLf & _
"共检查订单: " & totalProcessed & vbCrLf & _
"发现异常订单: " & errorOrdersCount & vbCrLf & _
"生成异常明细: " & errorRowsCount & " 行" & vbCrLf & _
"用时: " & Format(elapsedTime, "0.00") & "秒", vbInformation
outputSheet.Activate
Exit Sub
ErrorHandler:
RestoreAppStatus
MsgBox "异常分析发生错误: " & Err.Description, vbCritical
End Sub
'=====================================================================
' 核心算法: FindUnmatchedParameter (带权重的最大特征重合度算法)
' 功能: 分析BOM库找出与当前订单特征最相似的物料并提取冲突(未匹配)的参数值
'=====================================================================
Private Function FindUnmatchedParameter(category As String, productConds As Object, allBomItems As Collection, regEx As Object) As String
' 使用 Long 类型,因为加入权重后得分会超过 Integer 上限
Dim maxScore As Long
maxScore = -1
Dim bestConflictKeys As String
bestConflictKeys = ""
Dim item As BomItem
' 遍历BOM库中同类别的所有物料
For Each item In allBomItems
If item.category = category And Trim(item.SelectCondition) <> "" Then
Dim allowed As Object
Set allowed = CreateObject("Scripting.Dictionary")
Dim forbidden As Object
Set forbidden = CreateObject("Scripting.Dictionary")
' 使用正则提取该物料的所有约束条件 (如 azxs=A0)
Dim matches As Object
Set matches = regEx.Execute(item.SelectCondition)
Dim match As Object
For Each match In matches
Dim k As String, op As String, v As String
k = match.SubMatches(0)
op = Trim(match.SubMatches(1))
v = Trim(match.SubMatches(2))
If op = "=" Then
If Not allowed.Exists(k) Then allowed(k) = "|"
allowed(k) = allowed(k) & v & "|"
ElseIf op = "!=" Or op = "<>" Then
If Not forbidden.Exists(k) Then forbidden(k) = "|"
forbidden(k) = forbidden(k) & v & "|"
End If
Next match
' 合并出现过的所有参数键
Dim allRuleKeys As Object
Set allRuleKeys = CreateObject("Scripting.Dictionary")
Dim vKey As Variant
For Each vKey In allowed.Keys: allRuleKeys(vKey) = True: Next vKey
For Each vKey In forbidden.Keys: allRuleKeys(vKey) = True: Next vKey
Dim currentScore As Long
currentScore = 0
Dim currentConflicts As String
currentConflicts = ""
' 计算该物料与实际订单参数的重合度得分
Dim keyVar As Variant
For Each keyVar In allRuleKeys.Keys
Dim keyStr As String
keyStr = CStr(keyVar)
Dim prodVal As String
If productConds.Exists(keyStr) Then prodVal = productConds(keyStr) Else prodVal = ""
Dim isMatch As Boolean
isMatch = False
If allowed.Exists(keyStr) Then
' 如果实际值包含在允许值中,则得分
If InStr(allowed(keyStr), "|" & prodVal & "|") > 0 Then
isMatch = True
End If
ElseIf forbidden.Exists(keyStr) Then
' 如果没有允许值限制,只有禁止值限制,且实际值不在禁止值中,则得分
If InStr(forbidden(keyStr), "|" & prodVal & "|") = 0 Then
isMatch = True
End If
End If
If isMatch Then
' 【核心修改】引入特征权重,让系统具备业务直觉
currentScore = currentScore + GetFeatureWeight(keyStr)
Else
currentConflicts = currentConflicts & keyStr & ","
End If
Next keyVar
' 更新最高得分记录
If currentScore > maxScore Then
maxScore = currentScore
bestConflictKeys = currentConflicts
ElseIf currentScore = maxScore And currentScore > 0 Then
' 如果权重得分依然相同,合并所有可能的冲突原因
Dim keysArray() As String
keysArray = Split(currentConflicts, ",")
Dim cKey As Variant
For Each cKey In keysArray
If Trim(cKey) <> "" And InStr(bestConflictKeys, cKey & ",") = 0 Then
bestConflictKeys = bestConflictKeys & cKey & ","
End If
Next cKey
End If
End If
Next item
' 将最高分的冲突Key翻译为实际的参数值
If bestConflictKeys <> "" Then
Dim resultStr As String
resultStr = ""
Dim finalKeys() As String
finalKeys = Split(bestConflictKeys, ",")
Dim fKey As Variant
For Each fKey In finalKeys
If Trim(fKey) <> "" Then
Dim actVal As String
If productConds.Exists(fKey) Then actVal = productConds(fKey) Else actVal = "无值"
' 使用 | 作为条目分隔符,使用 : 分隔键和值
Dim pairStr As String
pairStr = fKey & ":" & actVal
If resultStr = "" Then
resultStr = pairStr
Else
If InStr("|" & resultStr & "|", "|" & pairStr & "|") = 0 Then
resultStr = resultStr & "|" & pairStr
End If
End If
End If
Next fKey
If resultStr <> "" Then
FindUnmatchedParameter = resultStr
Else
FindUnmatchedParameter = "无法精准定位:无法精准定位"
End If
Else
FindUnmatchedParameter = "无法精准定位:无法精准定位"
End If
End Function
'=====================================================================
' 辅助函数: GetFeatureWeight
' 功能: 获取字段的匹配权重,严格保证高优先级特征的决定性
'=====================================================================
Private Function GetFeatureWeight(keyStr As String) As Long
Select Case LCase(Trim(keyStr))
Case "azxs"
GetFeatureWeight = 10000 ' 安装形式 - 决定物理结构,最重要
Case "bkxs"
GetFeatureWeight = 1000 ' 表壳形式
Case "gclj"
GetFeatureWeight = 100 ' 过程连接
Case "jycz"
GetFeatureWeight = 50 ' 接液材质
Case "lcfw"
GetFeatureWeight = 10 ' 量程范围
Case "fjgn"
GetFeatureWeight = 1 ' 附加功能
Case Else
GetFeatureWeight = 0
End Select
End Function
'=====================================================================
' 辅助函数: ExtractCategoryName
' 功能: 从报错文本如 "必需类别[部件]未匹配" 中提取出 "部件"
'=====================================================================
Private Function ExtractCategoryName(errorMsg As String) As String
Dim startPos As Long
Dim endPos As Long
startPos = InStr(errorMsg, "[")
endPos = InStr(errorMsg, "]")
If startPos > 0 And endPos > startPos Then
ExtractCategoryName = Mid(errorMsg, startPos + 1, endPos - startPos - 1)
Else
ExtractCategoryName = ""
End If
End Function
'=====================================================================
' 过程: WriteOutputHeader
'=====================================================================
Private Sub WriteOutputHeader(ws As Worksheet)
Dim col As Long
col = 1
ws.Cells(OUTPUT_HEADER_ROW, col).value = "总排号": col = col + 1
ws.Cells(OUTPUT_HEADER_ROW, col).value = "生产订单号": col = col + 1
ws.Cells(OUTPUT_HEADER_ROW, col).value = "产品型号": col = col + 1
Dim configs() As String
configs = Split(CONDITION_CONFIG, "|")
Dim i As Long
For i = LBound(configs) To UBound(configs)
ws.Cells(OUTPUT_HEADER_ROW, col).value = Trim(Split(configs(i), ",")(1))
col = col + 1
Next i
ws.Cells(OUTPUT_HEADER_ROW, col).value = "未匹配参数": col = col + 1
ws.Cells(OUTPUT_HEADER_ROW, col).value = "未匹配参数值": col = col + 1
ws.Cells(OUTPUT_HEADER_ROW, col).value = "提取备注": col = col + 1
End Sub
'=====================================================================
' 函数: CreateErrorRowArray
' 功能: 构建输出的一行数据
'=====================================================================
Private Function CreateErrorRowArray(totalQueueNum As String, orderNumber As String, _
modelStr As String, conditions As Object, _
unmatchedParam As String, unmatchedValue As String, errorNote As String) As Variant()
Dim configs() As String
configs = Split(CONDITION_CONFIG, "|")
Dim totalCols As Long
totalCols = 3 + UBound(configs) - LBound(configs) + 1 + 3
ReDim rowData(1 To totalCols) As Variant
Dim col As Long
col = 1
rowData(col) = totalQueueNum: col = col + 1
rowData(col) = orderNumber: col = col + 1
rowData(col) = modelStr: col = col + 1
Dim i As Long
For i = LBound(configs) To UBound(configs)
Dim key As String
key = Trim(Split(configs(i), ",")(0))
If conditions.Exists(key) Then
rowData(col) = conditions(key)
Else
rowData(col) = ""
End If
col = col + 1
Next i
rowData(col) = unmatchedParam: col = col + 1
rowData(col) = unmatchedValue: col = col + 1
rowData(col) = errorNote: col = col + 1
CreateErrorRowArray = rowData
End Function
'=====================================================================
' 过程: WriteBatchData
'=====================================================================
Private Sub WriteBatchData(ws As Worksheet, outputData As Collection)
Dim firstRow As Variant
firstRow = outputData(1)
Dim rowCount As Long
Dim colCount As Long
rowCount = outputData.count
colCount = UBound(firstRow) - LBound(firstRow) + 1
Dim resultData() As Variant
ReDim resultData(1 To rowCount, 1 To colCount)
Dim i As Long, j As Long
Dim rowArray As Variant
For i = 1 To rowCount
rowArray = outputData(i)
For j = 1 To colCount
resultData(i, j) = rowArray(j)
Next j
Next i
' 数据从表头的下一行开始写入
ws.Cells(OUTPUT_HEADER_ROW + 1, 1).Resize(rowCount, colCount).value = resultData
End Sub
'=====================================================================
' 辅助过程
'=====================================================================
Private Function GetOrderSheet() As Worksheet
On Error Resume Next
Set GetOrderSheet = ThisWorkbook.Worksheets("产品订单")
If GetOrderSheet Is Nothing Then Set GetOrderSheet = ActiveSheet
On Error GoTo 0
End Function
Private Function GetBomSheet() As Worksheet
On Error Resume Next
Set GetBomSheet = ThisWorkbook.Worksheets("平台配置清单")
On Error GoTo 0
End Function
Private Function CreateErrorOutputSheet() As Worksheet
Dim wsName As String
wsName = "BOM匹配异常报表"
On Error Resume Next
Set CreateErrorOutputSheet = ThisWorkbook.Worksheets(wsName)
On Error GoTo 0
If CreateErrorOutputSheet Is Nothing Then
Set CreateErrorOutputSheet = ThisWorkbook.Worksheets.Add
CreateErrorOutputSheet.Name = wsName
Else
' 只清空表头及其以下的数据,保留表头以上的可能存在的内容
CreateErrorOutputSheet.Rows(OUTPUT_HEADER_ROW & ":" & CreateErrorOutputSheet.Rows.count).Clear
End If
End Function
Private Sub FormatOutputSheet(ws As Worksheet)
On Error Resume Next
With ws.Rows(OUTPUT_HEADER_ROW)
.Font.Bold = True
.Interior.Color = RGB(244, 176, 132) ' 橙色背景,突出异常属性
.HorizontalAlignment = xlCenter
End With
' 将"未匹配参数"列和"未匹配参数值"列加粗显示,颜色标红
Dim unmatchValCol As Long
unmatchValCol = ws.Cells(OUTPUT_HEADER_ROW, ws.Columns.count).End(xlToLeft).Column - 1
Dim unmatchParamCol As Long
unmatchParamCol = unmatchValCol - 1
If unmatchParamCol > 0 Then
ws.Columns(unmatchParamCol).Font.Color = RGB(255, 0, 0)
ws.Columns(unmatchParamCol).Font.Bold = True
ws.Columns(unmatchValCol).Font.Color = RGB(255, 0, 0)
ws.Columns(unmatchValCol).Font.Bold = True
End If
On Error GoTo 0
End Sub
Private Sub RestoreAppStatus()
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub

View File

@@ -1,8 +1,7 @@
'=====================================================================
' 模块名: MainModule
' 功能: 主控模块,处理产品型号提取和BOM匹配的上层逻辑
' 作者: Auto-generated
' 日期: 2025-01-29
' 特性: [已重构] 支持仅对筛选后的数据进行处理,采用内存极速读取
'=====================================================================
Option Explicit
@@ -11,7 +10,7 @@ Option Explicit
' 常量定义
'=====================================================================
' 提取条件配置(可灵活扩展)
Private Const CONDITION_CONFIG = "azxs,安装形式|bkxs,表壳形式|gclj,过程连接|jycz,接液材质|lcfw,量程范围"
Private Const CONDITION_CONFIG = "azxs,安装形式|bkxs,表壳形式|gclj,过程连接|jycz,接液材质|lcfw,量程范围|fjgn,附加功能"
'=====================================================================
' 过程: ProcessProductModels
@@ -24,6 +23,9 @@ Public Sub ProcessProductModels()
Dim startTime As Double
startTime = Timer
' 关闭屏幕刷新提升速度
Application.ScreenUpdating = False
' 准备输入输出
Dim inputSheet As Worksheet
Dim outputSheet As Worksheet
@@ -32,6 +34,7 @@ Public Sub ProcessProductModels()
' 获取工作表
Set inputSheet = GetInputSheet()
If inputSheet Is Nothing Then
Application.ScreenUpdating = True
MsgBox "未找到输入工作表,请确保工作簿中有包含订单数据的工作表", vbCritical
Exit Sub
End If
@@ -39,6 +42,7 @@ Public Sub ProcessProductModels()
' 获取BOM库工作表
Set bomSheet = GetBomSheet()
If bomSheet Is Nothing Then
Application.ScreenUpdating = True
MsgBox "未找到'平台配置清单'工作表,请确保BOM数据存在", vbCritical
Exit Sub
End If
@@ -52,36 +56,76 @@ Public Sub ProcessProductModels()
BomExtractor.SetWorksheet bomSheet
If Not BomExtractor.LoadBomData Then
Application.ScreenUpdating = True
MsgBox "加载BOM数据失败:" & BomExtractor.GetErrorSummary, vbCritical
Exit Sub
End If
' 处理每个产品型号
Dim lastRow As Long
lastRow = inputSheet.Cells(inputSheet.Rows.Count, 1).End(xlUp).row
lastRow = inputSheet.Cells(inputSheet.Rows.count, 1).End(xlUp).row
Dim outputRow As Long
outputRow = 2 ' 从第2行开始输出(第1行是表头)
If lastRow < 2 Then
Application.ScreenUpdating = True
MsgBox "[产品订单]工作表中没有数据!", vbExclamation
Exit Sub
End If
' 【性能核心】将输入数据全量读入内存数组
Dim sourceDataArr As Variant
sourceDataArr = inputSheet.Range("A2:F" & lastRow).value
' 【筛选核心】获取可见的单元格区域
Dim visibleRange As Range
On Error Resume Next
Set visibleRange = inputSheet.Range("A2:A" & lastRow).SpecialCells(xlCellTypeVisible)
On Error GoTo ErrorHandler
If visibleRange Is Nothing Then
Application.ScreenUpdating = True
MsgBox "当前筛选状态下没有可见的数据。", vbInformation
Exit Sub
End If
' 写入输出表头
WriteOutputHeader outputSheet
Dim i As Long
' 收集所有输出数据
Dim outputData As Collection
Set outputData = New Collection
Dim cell As Range
Dim arrIndex As Long
Dim modelString As String
Dim processedCount As Long
processedCount = 0
' 假设产品型号在第1列,从第2行开始
For i = 2 To lastRow
modelString = Trim(inputSheet.Cells(i, 2).value)
' 仅遍历筛选出来的可见行
For Each cell In visibleRange
Dim totalQueueNum As String
Dim orderNumber As String
Dim componentPriority As String
' 将工作表行号映射到数组索引
arrIndex = cell.row - 1
' 从内存数组中极速读取对应字段
totalQueueNum = Trim(sourceDataArr(arrIndex, 1)) ' A列总排号
orderNumber = Trim(sourceDataArr(arrIndex, 2)) ' B列生产订单号
modelString = Trim(sourceDataArr(arrIndex, 3)) ' C列产品型号
componentPriority = Trim(sourceDataArr(arrIndex, 6)) ' F列部件优先
If modelString <> "" Then
' 处理单个型号
outputRow = ProcessSingleModel(modelString, BomExtractor, outputSheet, outputRow)
' 处理单个型号,收集数据
ProcessSingleModel totalQueueNum, orderNumber, modelString, componentPriority, BomExtractor, outputData
processedCount = processedCount + 1
End If
Next i
Next cell
' 批量写入数据到工作表
If outputData.count > 0 Then
WriteBatchData outputSheet, outputData
End If
' 格式化输出表
FormatOutputSheet outputSheet
@@ -89,8 +133,10 @@ Public Sub ProcessProductModels()
Dim elapsedTime As Double
elapsedTime = Timer - startTime
Application.ScreenUpdating = True
MsgBox "处理完成!" & vbCrLf & _
"处理型号数: " & processedCount & vbCrLf & _
"处理筛选型号数: " & processedCount & vbCrLf & _
"用时: " & Format(elapsedTime, "0.00") & "秒", vbInformation
' 激活输出表
@@ -99,26 +145,34 @@ Public Sub ProcessProductModels()
Exit Sub
ErrorHandler:
MsgBox "处理异常: " & Err.description, vbCritical
Application.ScreenUpdating = True
MsgBox "处理异常: " & Err.Description, vbCritical
End Sub
'=====================================================================
' 函数: ProcessSingleModel
' 功能: 处理单个产品型号
' 参数: modelString - 产品型号字符串
' 过程: ProcessSingleModel
' 功能: 处理单个产品型号,将数据添加到输出集合
' 参数: orderNumber - 生产订单号
' modelString - 产品型号字符串
' componentPriority - 部件优先标志("是"或"否"
' bomExtractor - BOM提取器对象
' outputSheet - 输出工作表
' startRow - 起始行号
' 返回: Long - 下一个可用行号
' outputData - 输出数据集合
'=====================================================================
Private Function ProcessSingleModel(modelString As String, _
BomExtractor As BomExtractor, _
outputSheet As Worksheet, _
startRow As Long) As Long
Private Sub ProcessSingleModel(totalQueueNum As String, _
orderNumber As String, _
modelString As String, _
componentPriority As String, _
BomExtractor As BomExtractor, _
outputData As Collection)
On Error Resume Next
Dim currentRow As Long
currentRow = startRow
' 根据部件优先设置排除类别
BomExtractor.ClearExcludeCategories
If UCase(componentPriority) = "否" Or componentPriority = "0" Or componentPriority = "FALSE" Then
Dim excludeCats As New Collection
excludeCats.Add "部件"
BomExtractor.SetExcludeCategories excludeCats
End If
' 解析产品型号
Dim parser As ProductModelParser
@@ -130,14 +184,13 @@ Private Function ProcessSingleModel(modelString As String, _
If Not parser.Parse(modelString) Then
' 解析失败
extractNote = "解析失败: " & parser.ErrorMessage
WriteOutputRow outputSheet, currentRow, modelString, "", parser.Conditions, extractNote, Nothing
ProcessSingleModel = currentRow + 1
Exit Function
outputData.Add CreateOutputRowArray(totalQueueNum, orderNumber, modelString, parser.conditions, extractNote, Nothing)
Exit Sub
End If
' 提取BOM
Dim matchedItems As collection
Set matchedItems = BomExtractor.ExtractBom(parser.Conditions)
Dim matchedItems As Collection
Set matchedItems = BomExtractor.ExtractBom(parser.conditions)
' 获取错误信息
Dim bomErrors As String
@@ -147,13 +200,12 @@ Private Function ProcessSingleModel(modelString As String, _
End If
' 输出结果
If matchedItems.Count = 0 Then
If matchedItems.count = 0 Then
' 没有匹配项
If extractNote = "" Then
extractNote = "未匹配到任何物料"
End If
WriteOutputRow outputSheet, currentRow, modelString, parser.HeaderModel, parser.Conditions, extractNote, Nothing
currentRow = currentRow + 1
outputData.Add CreateOutputRowArray(totalQueueNum, orderNumber, modelString, parser.conditions, extractNote, Nothing)
Else
' 输出每个匹配的物料
Dim item As BomItem
@@ -171,18 +223,16 @@ Private Function ProcessSingleModel(modelString As String, _
End If
If isFirst Then
WriteOutputRow outputSheet, currentRow, modelString, parser.HeaderModel, parser.Conditions, itemNote, item
' 首行保留总排号和订单号
outputData.Add CreateOutputRowArray(totalQueueNum, orderNumber, modelString, parser.conditions, itemNote, item)
isFirst = False
Else
WriteOutputRow outputSheet, currentRow, "", "", parser.Conditions, itemNote, item
' 同一个型号的后续BOM项总排号和订单号留空以保持报表整洁
outputData.Add CreateOutputRowArray("", "", modelString, parser.conditions, itemNote, item)
End If
currentRow = currentRow + 1
Next item
End If
ProcessSingleModel = currentRow
End Function
End Sub
'=====================================================================
' 过程: WriteOutputHeader
@@ -193,16 +243,18 @@ Private Sub WriteOutputHeader(ws As Worksheet)
Dim col As Long
col = 1
' 新增总排号表头
ws.Cells(1, col).value = "总排号": col = col + 1
ws.Cells(1, col).value = "生产订单号": col = col + 1
ws.Cells(1, col).value = "产品型号": col = col + 1
ws.Cells(1, col).value = "表头型号": col = col + 1
' 写入条件字段表头
Dim Conditions() As String
Dim conditions() As String
Dim labels() As String
GetConditionConfig Conditions, labels
GetConditionConfig conditions, labels
Dim i As Long
For i = LBound(Conditions) To UBound(Conditions)
For i = LBound(conditions) To UBound(conditions)
ws.Cells(1, col).value = labels(i)
col = col + 1
Next i
@@ -210,7 +262,7 @@ Private Sub WriteOutputHeader(ws As Worksheet)
' BOM字段表头
ws.Cells(1, col).value = "行号": col = col + 1
ws.Cells(1, col).value = "模块": col = col + 1
ws.Cells(1, col).value = "代号": col = col + 1
' ws.Cells(1, col).Value = "代号": col = col + 1 <-- 已移除
ws.Cells(1, col).value = "名称": col = col + 1
ws.Cells(1, col).value = "数量": col = col + 1
ws.Cells(1, col).value = "类别": col = col + 1
@@ -219,58 +271,111 @@ Private Sub WriteOutputHeader(ws As Worksheet)
End Sub
'=====================================================================
' 过程: WriteOutputRow
' 功能: 写入输出行
' 参数: ws - 工作表对象
' row - 行
' fullModel - 完整型号
' headerModel - 表头型号
' conditions - 条件字典
' 函数: CreateOutputRowArray
' 功能: 创建输出行数据的数组
' 参数: orderNumber - 生产订单号
' FullModel - 完整型
' Conditions - 条件字典
' note - 备注
' item - BOM项(可为Nothing)
' 返回: Variant() - 行数据数组
'=====================================================================
Private Sub WriteOutputRow(ws As Worksheet, _
row As Long, _
FullModel As String, _
HeaderModel As String, _
Conditions As Object, _
note As String, _
item As BomItem)
Dim col As Long
col = 1
ws.Cells(row, col).value = FullModel: col = col + 1
ws.Cells(row, col).value = HeaderModel: col = col + 1
' 写入条件值
Private Function CreateOutputRowArray(totalQueueNum As String, _
orderNumber As String, _
FullModel As String, _
conditions As Object, _
note As String, _
item As BomItem) As Variant()
' 获取条件配置
Dim condNames() As String
Dim labels() As String
GetConditionConfig condNames, labels
' 计算总列数3 (排号+订单+型号) + 条件数 + 7 (BOM字段减去代号后剩6个 + 1个备注)
Dim totalCols As Long
totalCols = 3 + (UBound(condNames) - LBound(condNames) + 1) + 7
' 创建数组
ReDim rowData(1 To totalCols) As Variant
Dim col As Long
col = 1
' 基础信息
rowData(col) = totalQueueNum: col = col + 1
rowData(col) = orderNumber: col = col + 1
rowData(col) = FullModel: col = col + 1
' 写入条件值
Dim i As Long
For i = LBound(condNames) To UBound(condNames)
If Conditions.Exists(condNames(i)) Then
ws.Cells(row, col).value = Conditions(condNames(i))
If conditions.Exists(condNames(i)) Then
rowData(col) = conditions(condNames(i))
Else
ws.Cells(row, col).value = ""
rowData(col) = ""
End If
col = col + 1
Next i
' 写入BOM数据
If Not item Is Nothing Then
ws.Cells(row, col).value = item.RowNumber: col = col + 1
ws.Cells(row, col).value = item.Module: col = col + 1
ws.Cells(row, col).value = item.code: col = col + 1
ws.Cells(row, col).value = item.Name: col = col + 1
ws.Cells(row, col).value = item.Quantity: col = col + 1
ws.Cells(row, col).value = item.category: col = col + 1
ws.Cells(row, col).value = item.Code66: col = col + 1
rowData(col) = item.RowNumber: col = col + 1
rowData(col) = item.Module: col = col + 1
' rowData(col) = item.code: col = col + 1 <-- 已移除
rowData(col) = item.Name: col = col + 1
rowData(col) = item.Quantity: col = col + 1
rowData(col) = item.category: col = col + 1
rowData(col) = item.Code66: col = col + 1
Else
col = col + 7 ' 跳过BOM字段
' 跳过BOM字段 (原本是7个字段去掉代号后变成6个字段)
col = col + 6
End If
ws.Cells(row, col).value = note
' 备注
rowData(col) = note
CreateOutputRowArray = rowData
End Function
'=====================================================================
' 过程: WriteBatchData
' 功能: 批量写入数据到工作表
' 参数: ws - 工作表对象
' outputData - 输出数据集合
'=====================================================================
Private Sub WriteBatchData(ws As Worksheet, outputData As Collection)
' 如果没有数据,直接返回
If outputData.count = 0 Then
Exit Sub
End If
' 获取第一行数据来确定列数
Dim firstRow As Variant
firstRow = outputData(1)
Dim rowCount As Long
Dim colCount As Long
rowCount = outputData.count
colCount = UBound(firstRow) - LBound(firstRow) + 1
' 创建二维数组
Dim resultData() As Variant
ReDim resultData(1 To rowCount, 1 To colCount)
' 填充数据到二维数组
Dim i As Long
Dim j As Long
Dim rowArray As Variant
For i = 1 To rowCount
rowArray = outputData(i)
For j = 1 To colCount
resultData(i, j) = rowArray(j)
Next j
Next i
' 一次性写入工作表从第2行开始
ws.Range("A2").Resize(rowCount, colCount).value = resultData
End Sub
'=====================================================================

View File

@@ -0,0 +1,217 @@
'=====================================================================
' 模块名: OrderValidationModule
' 功能: 订单物料有效性检查模块
' 说明: 检查[产品订单]中可见行的产品型号是否能成功提取BOM。
' 如果发生任何提取错误或无法匹配物料则在G列[是否领料]写入"否"。
' 特性: 采用内存极速读取,仅对筛选后的数据进行处理。
'=====================================================================
Option Explicit
'=====================================================================
' 过程: ValidateOrderMaterials
' 功能: 批量检查可见订单的BOM提取有效性
'=====================================================================
Public Sub ValidateOrderMaterials()
On Error GoTo ErrorHandler
Dim startTime As Double
startTime = Timer
' 提升性能:关闭屏幕更新和自动计算
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
' 获取工作表
Dim orderSheet As Worksheet
Dim bomSheet As Worksheet
Set orderSheet = GetOrderSheet()
If orderSheet Is Nothing Then
RestoreAppStatus
MsgBox "未找到[产品订单]工作表!", vbCritical
Exit Sub
End If
Set bomSheet = GetBomSheet()
If bomSheet Is Nothing Then
RestoreAppStatus
MsgBox "未找到[平台配置清单]工作表!", vbCritical
Exit Sub
End If
' 初始化BOM提取器
Dim BomExtractor As BomExtractor
Set BomExtractor = New BomExtractor
BomExtractor.SetWorksheet bomSheet
If Not BomExtractor.LoadBomData Then
RestoreAppStatus
MsgBox "加载BOM数据失败:" & BomExtractor.GetErrorSummary, vbCritical
Exit Sub
End If
' 写入G列表头
orderSheet.Cells(1, 7).value = "是否领料"
Dim lastRow As Long
lastRow = orderSheet.Cells(orderSheet.Rows.count, 3).End(xlUp).row
If lastRow < 2 Then
RestoreAppStatus
MsgBox "[产品订单]工作表中没有需要处理的数据!", vbExclamation
Exit Sub
End If
' 【性能核心】将输入数据全量读入内存数组 (读取A到F列即可)
Dim sourceDataArr As Variant
sourceDataArr = orderSheet.Range("A2:F" & lastRow).value
' 【筛选核心】获取可见的单元格区域 (A列)
Dim visibleRange As Range
On Error Resume Next
Set visibleRange = orderSheet.Range("A2:A" & lastRow).SpecialCells(xlCellTypeVisible)
On Error GoTo ErrorHandler
If visibleRange Is Nothing Then
RestoreAppStatus
MsgBox "当前筛选状态下没有可见的数据。", vbInformation
Exit Sub
End If
Dim cell As Range
Dim arrIndex As Long
Dim modelString As String
Dim componentPriority As String
Dim processedCount As Long
Dim invalidCount As Long
processedCount = 0
invalidCount = 0
' 仅遍历筛选出来的可见行
For Each cell In visibleRange
' 将工作表行号映射到数组索引 (数据从第2行开始所以数组索引 = 行号 - 1)
arrIndex = cell.row - 1
' 从内存数组中极速读取所需的关键字段
modelString = Trim(sourceDataArr(arrIndex, 3)) ' C列产品型号
componentPriority = Trim(sourceDataArr(arrIndex, 6)) ' F列部件优先
If modelString <> "" Then
processedCount = processedCount + 1
' 调用校验逻辑判断是否存在BOM提取错误
If IsInvalidOrderBOM(modelString, componentPriority, BomExtractor) Then
' 如果无效/有报错直接在对应行的第7列(G列)写入"否"
' 正常订单不做任何处理,保留原样
orderSheet.Cells(cell.row, 7).value = "否"
invalidCount = invalidCount + 1
End If
End If
Next cell
' 恢复应用状态
RestoreAppStatus
Dim elapsedTime As Double
elapsedTime = Timer - startTime
MsgBox "有效性检查完成!" & vbCrLf & _
"共检查了 " & processedCount & " 个筛选订单。" & vbCrLf & _
"发现并标记了 " & invalidCount & " 个无效/报错订单。" & vbCrLf & _
"用时: " & Format(elapsedTime, "0.00") & " 秒", vbInformation
Exit Sub
ErrorHandler:
RestoreAppStatus
MsgBox "检查订单物料有效性时发生异常: " & Err.Description, vbCritical
End Sub
'=====================================================================
' 函数: IsInvalidOrderBOM
' 功能: 模拟BOM提取过程判定该订单是否存在错误
' 参数: modelString - 产品型号
' componentPriority - 部件优先标识
' BomExtractor - 已初始化的BOM提取器对象
' 返回: Boolean - 只要发生任何错误或未匹配到物料,则返回 True
'=====================================================================
Private Function IsInvalidOrderBOM(modelString As String, _
componentPriority As String, _
BomExtractor As BomExtractor) As Boolean
On Error Resume Next
' 默认认为它是有效的,直到发现错误
IsInvalidOrderBOM = False
' 1. 根据部件优先设置排除类别
BomExtractor.ClearExcludeCategories
If UCase(componentPriority) = "否" Or componentPriority = "0" Or componentPriority = "FALSE" Then
Dim excludeCats As New Collection
excludeCats.Add "部件"
BomExtractor.SetExcludeCategories excludeCats
End If
' 2. 解析产品型号
Dim parser As ProductModelParser
Set parser = New ProductModelParser
If Not parser.Parse(modelString) Then
' 解析失败,属于无效订单
IsInvalidOrderBOM = True
Exit Function
End If
' 3. 提取BOM
Dim matchedItems As Collection
Set matchedItems = BomExtractor.ExtractBom(parser.conditions)
' 4. 检查 BOM 提取器全局错误日志
If BomExtractor.GetErrorSummary <> "" Then
IsInvalidOrderBOM = True
Exit Function
End If
' 5. 检查是否完全没有匹配到物料
If matchedItems.count = 0 Then
IsInvalidOrderBOM = True
Exit Function
End If
' 6. 深度检查:遍历提取出的每一项,看是否存在子项报错
Dim item As BomItem
For Each item In matchedItems
If item.MatchError <> "" Then
IsInvalidOrderBOM = True
Exit Function
End If
Next item
On Error GoTo 0
End Function
'=====================================================================
' 辅助过程: RestoreAppStatus
' 功能: 恢复Excel应用程序的状态
'=====================================================================
Private Sub RestoreAppStatus()
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
'=====================================================================
' 辅助函数: 获取所需工作表
'=====================================================================
Private Function GetOrderSheet() As Worksheet
On Error Resume Next
Set GetOrderSheet = ThisWorkbook.Worksheets("产品订单")
On Error GoTo 0
End Function
Private Function GetBomSheet() As Worksheet
On Error Resume Next
Set GetBomSheet = ThisWorkbook.Worksheets("平台配置清单")
On Error GoTo 0
End Function

View File

@@ -1,8 +1,6 @@
'=====================================================================
' 模块名: TestModule
' 功能: 单元测试模块
' 作者: Auto-generated
' 日期: 2025-01-29
'=====================================================================
Option Explicit
@@ -118,21 +116,21 @@ Public Sub TestConditionEvaluator()
Set evaluator = New ConditionEvaluator
' 创建测试条件字典
Dim Conditions As Object
Set Conditions = CreateObject("Scripting.Dictionary")
Conditions.Add "azxs", "A0"
Conditions.Add "bkxs", "531"
Conditions.Add "gclj", "M20"
Conditions.Add "jycz", "3"
Conditions.Add "lcfw", "M06"
Dim conditions As Object
Set conditions = CreateObject("Scripting.Dictionary")
conditions.Add "azxs", "A0"
conditions.Add "bkxs", "531"
conditions.Add "gclj", "M20"
conditions.Add "jycz", "3"
conditions.Add "lcfw", "M06"
' 测试用例1: 简单等式
Debug.Print "测试用例1: 简单等式"
Dim expr1 As String
expr1 = "azxs=A0"
Debug.Print " 表达式: " & expr1
Debug.Print " 结果: " & evaluator.Evaluate(expr1, Conditions)
AssertTrue "简单等式", evaluator.Evaluate(expr1, Conditions)
Debug.Print " 结果: " & evaluator.Evaluate(expr1, conditions)
AssertTrue "简单等式", evaluator.Evaluate(expr1, conditions)
Debug.Print ""
' 测试用例2: AND运算
@@ -140,8 +138,8 @@ Public Sub TestConditionEvaluator()
Dim expr2 As String
expr2 = "azxs=A0 AND bkxs=531"
Debug.Print " 表达式: " & expr2
Debug.Print " 结果: " & evaluator.Evaluate(expr2, Conditions)
AssertTrue "AND运算", evaluator.Evaluate(expr2, Conditions)
Debug.Print " 结果: " & evaluator.Evaluate(expr2, conditions)
AssertTrue "AND运算", evaluator.Evaluate(expr2, conditions)
Debug.Print ""
' 测试用例3: OR运算
@@ -149,8 +147,8 @@ Public Sub TestConditionEvaluator()
Dim expr3 As String
expr3 = "azxs=AT OR azxs=A0"
Debug.Print " 表达式: " & expr3
Debug.Print " 结果: " & evaluator.Evaluate(expr3, Conditions)
AssertTrue "OR运算", evaluator.Evaluate(expr3, Conditions)
Debug.Print " 结果: " & evaluator.Evaluate(expr3, conditions)
AssertTrue "OR运算", evaluator.Evaluate(expr3, conditions)
Debug.Print ""
' 测试用例4: !=运算
@@ -158,8 +156,8 @@ Public Sub TestConditionEvaluator()
Dim expr4 As String
expr4 = "azxs!=AH"
Debug.Print " 表达式: " & expr4
Debug.Print " 结果: " & evaluator.Evaluate(expr4, Conditions)
AssertTrue "!=运算", evaluator.Evaluate(expr4, Conditions)
Debug.Print " 结果: " & evaluator.Evaluate(expr4, conditions)
AssertTrue "!=运算", evaluator.Evaluate(expr4, conditions)
Debug.Print ""
' 测试用例5: 复杂嵌套
@@ -167,8 +165,8 @@ Public Sub TestConditionEvaluator()
Dim expr5 As String
expr5 = "(azxs=A0 OR azxs=AT) AND (bkxs=531 OR bkxs=541)"
Debug.Print " 表达式: " & expr5
Debug.Print " 结果: " & evaluator.Evaluate(expr5, Conditions)
AssertTrue "复杂嵌套", evaluator.Evaluate(expr5, Conditions)
Debug.Print " 结果: " & evaluator.Evaluate(expr5, conditions)
AssertTrue "复杂嵌套", evaluator.Evaluate(expr5, conditions)
Debug.Print ""
' 测试用例6: 不存在的变量(!=情况)
@@ -176,8 +174,8 @@ Public Sub TestConditionEvaluator()
Dim expr6 As String
expr6 = "tsyq!=SCRJ"
Debug.Print " 表达式: " & expr6
Debug.Print " 结果: " & evaluator.Evaluate(expr6, Conditions)
AssertTrue "不存在的变量!=", evaluator.Evaluate(expr6, Conditions)
Debug.Print " 结果: " & evaluator.Evaluate(expr6, conditions)
AssertTrue "不存在的变量!=", evaluator.Evaluate(expr6, conditions)
Debug.Print ""
' 测试用例7: 实际BOM条件
@@ -185,9 +183,9 @@ Public Sub TestConditionEvaluator()
Dim expr7 As String
expr7 = "gclj=M20 AND jycz=1 AND lcfw=M01 AND (azxs=A0 OR azxs=AT OR azxs=AH)"
Debug.Print " 表达式: " & expr7
Debug.Print " 结果: " & evaluator.Evaluate(expr7, Conditions)
Debug.Print " 结果: " & evaluator.Evaluate(expr7, conditions)
' 这个应该是False,因为jycz=3,不是1
AssertFalse "实际BOM条件(应该False)", evaluator.Evaluate(expr7, Conditions)
AssertFalse "实际BOM条件(应该False)", evaluator.Evaluate(expr7, conditions)
Debug.Print ""
Debug.Print "<<< ConditionEvaluator 测试完成"
@@ -236,12 +234,12 @@ Public Sub TestBomExtractor()
testConditions.Add "jycz", "1"
testConditions.Add "lcfw", "M01"
Dim matchedItems As collection
Dim matchedItems As Collection
Set matchedItems = extractor.ExtractBom(testConditions)
Debug.Print " 匹配到 " & matchedItems.Count & " 个物料"
Debug.Print " 匹配到 " & matchedItems.count & " 个物料"
If matchedItems.Count > 0 Then
If matchedItems.count > 0 Then
Debug.Print " 匹配的物料:"
Dim item As BomItem
Dim i As Long

View File

@@ -1,6 +1,12 @@
{
"source_file": "C:\\Users\\pengq\\Downloads\\AutoBOM\\AutoBOM\\YTHN-100_-_Claude3.xlsm",
"source_file": "C:\\Users\\Administrator\\Desktop\\新BOM\\AutoBOM\\YTHN-100.xlsm",
"modules": {
"Sheet9.cls": {
"name": "Sheet9",
"type": "DocumentModules",
"attributes": {},
"file": "DocumentModules\\Sheet9.cls"
},
"MainModule.bas": {
"name": "MainModule",
"type": "Modules",
@@ -36,6 +42,12 @@
"type": "ClassModules",
"attributes": {},
"file": "ClassModules\\ProductModelParser.cls"
},
"BIPUploadModule.bas": {
"name": "BIPUploadModule",
"type": "Modules",
"attributes": {},
"file": "Modules\\BIPUploadModule.bas"
}
}
}

View File

@@ -0,0 +1,226 @@
# BIPUploadModule 流程图文档
## 模块概述
**模块名**: BIPUploadModule
**功能**: 处理产品订单数据提取BOM后生成[BIP上传模板]格式数据
**主入口**: ProcessOrdersToBIP
## ProcessOrdersToBIP 流程图(简化版)
```mermaid
flowchart TD
Start([开始处理]) --> Init["初始化<br/>1. 获取工作表<br/>2. 加载BOM库"]
Init --> Loop["循环处理每个订单"]
Loop --> Read["读取订单信息<br/>- 生产订单号<br/>- 产品型号<br/>- 数量<br/>- 产品编码<br/>- 部件优先标志"]
Read --> Parse["解析产品型号<br/>提取规格参数"]
Parse --> Extract["提取BOM物料<br/>根据规格参数匹配物料库"]
Extract --> CheckPriority{"部件优先=否?"}
CheckPriority -->|是| SkipComponent["排除'部件'类别<br/>只提取子类别物料"]
CheckPriority -->|否| KeepAll["保留所有物料"]
SkipComponent --> Generate
KeepAll --> Generate["生成BIP上传数据<br/>- 订单信息<br/>- 物料清单<br/>- 行号编码"]
Generate --> Collect["收集到内存集合"]
Collect --> NextOrder{"还有订单?"}
NextOrder -->|是| Loop
NextOrder -->|否| BatchWrite["批量写入[BIP上传模板]"]
BatchWrite --> Format["格式化表格"]
Format --> End([完成])
style Init fill:#e1f5e1
style Parse fill:#fff3cd
style Extract fill:#d1ecf1
style Generate fill:#d1ecf1
style BatchWrite fill:#f8d7da
style End fill:#e1f5e1
```
---
## ProcessSingleOrder 子流程(详细版)
> 注:以下为技术人员提供详细流程图
```mermaid
flowchart TD
Start([开始 ProcessSingleOrder]) --> ClearExclude["清空排除类别<br/>ClearExcludeCategories"]
ClearExclude --> CheckPriority{"部件优先?"}
CheckPriority -->|否/0/FALSE| AddExclude["创建排除类别集合<br/>添加: 部件"]
AddExclude --> SetExclude["设置排除类别"]
SetExclude --> ParseModel
CheckPriority -->|是| ParseModel["解析产品型号<br/>ProductModelParser.Parse"]
ParseModel --> CheckParse{"解析成功?"}
CheckParse -->|否| CreateError1["创建错误行数据<br/>备注: 解析失败信息"]
CreateError1 --> AddError1["添加到outputData"] --> End1([返回])
CheckParse -->|是| ExtractBOM["提取BOM<br/>BomExtractor.ExtractBom"]
ExtractBOM --> GetErrors["获取错误信息摘要"]
GetErrors --> CheckMatch{"匹配到物料?"}
CheckMatch -->|否| SetError1["设置备注: 未匹配到任何物料"]
SetError1 --> CreateError2["创建空记录行数据"]
CreateError2 --> AddError2["添加到outputData"] --> End2([返回])
CheckMatch -->|是| InitLine["初始化行号索引 lineIndex = 1"]
InitLine --> StartLoop["开始循环物料"]
StartLoop --> GetItem["获取物料项"]
GetItem --> InitNote["初始化备注 = 提取错误"]
InitNote --> CheckItemError{"物料有错误?"}
CheckItemError -->|是| AppendError["追加物料错误信息"]
CheckItemError -->|否| CreateRow
AppendError --> CreateRow["创建BIP行数据<br/>CreateBIPRowArray"]
CreateRow --> AddRow["添加到outputData"]
AddRow --> IncLine["lineIndex++"]
IncLine --> NextLoop{"还有物料?"}
NextLoop -->|是| StartLoop
NextLoop -->|否| End3([返回])
```
## WriteBatchData 批量写入流程
```mermaid
flowchart TD
Start([开始 WriteBatchData]) --> CheckData{"outputData为空?"}
CheckData -->|是| End1([直接返回])
CheckData -->|否| GetRowCount["获取行数 rowCount"]
GetRowCount --> CreateArray["创建二维数组<br/>resultData1 to rowCount, 1 to 10"]
CreateArray --> StartLoop["开始循环: i = 1 to rowCount"]
StartLoop --> GetRowArray["获取行数组 rowArray = outputDatai"]
GetRowArray --> FillArray["填充二维数组<br/>resultDatai, 1 to 10 = rowArray1 to 10"]
FillArray --> NextLoop{"i++ 还有数据?"}
NextLoop -->|是| StartLoop
NextLoop -->|否| WriteSheet["一次性写入工作表<br/>A2单元格.Resize rowCount, 10"]
WriteSheet --> End([完成])
```
## 数据结构说明
### BIP上传模板字段 (10列)
| 列号 | 字段名 | 说明 | 数据来源 |
|------|--------|------|----------|
| 1 | 来源单据号(生产订单号) | 订单唯一标识 | [产品订单] A列 |
| 2 | 产品编码 | 产品代码 | [产品订单] D列 |
| 3 | 生产数量 | 生产数量 | [产品订单] C列 |
| 4 | 行号 | BOM行号 = 7000 + 索引 | 自动生成7001, 7002... |
| 5 | 材料编码 | 物料66编码 | BOM提取结果 |
| 6 | 供应方式 | 固定值 | "一般发料" |
| 7 | 需用日期 | 日期 | 当天日期 Date |
| 8 | 发料组织 | 固定值 | "重庆布莱迪仪器仪表有限公司" |
| 9 | 计划出库数量 | 数量 | 与生产数量一致 |
| 10 | 备注 | 异常信息 | BOM提取错误/异常 |
### [产品订单] 工作表结构 (5列)
| 列号 | 字段名 | 说明 | 必填 |
|------|--------|------|------|
| A | 生产订单号 | 订单唯一标识 | 是 |
| B | 产品型号 | 产品完整型号 | 是 |
| C | 数量 | 生产数量 | 是 |
| D | 产品编码 | 产品代码 | 否 |
| E | 部件优先 | 是否优先提取部件类别 | 否 |
## 关键特性
### 1. 性能优化
- **批量写入**: 使用数组一次性写入所有数据,而非逐个单元格写入
- **内存缓存**: 所有数据先收集到Collection对象最后统一输出
- **预期性能提升**: 10-100倍取决于数据量
### 2. 部件优先功能
-`部件优先` = "否"/"0"/"FALSE"时:
- 排除"部件"类别的物料
- 只提取"部件"的子类别物料(如"接头"、"弹性元件"等)
-`部件优先` = "是"或其他值时:
- 正常提取所有物料,包括"部件"类别及其子类别
### 3. 错误处理
- **必填字段验证**: 生产订单号、产品型号、数量
- **解析失败处理**: 记录错误信息到备注列
- **BOM提取异常**: 记录匹配失败和异常信息
- **空行处理**: 自动跳过完全空白的行
### 4. 数据完整性
- 每次运行前清空旧数据(保留表头)
- 自动创建[BIP上传模板]工作表(如不存在)
- 行号自动生成7001, 7002, 7003...
- 日期自动填充为当天日期
## 执行示例
### 正常流程示例
```
输入: [产品订单] 3行数据
- 订单001, 型号MD-100, 数量10, 编码P001, 部件优先=是
- 订单002, 型号MD-200, 数量20, 编码P002, 部件优先=否
- 订单003, 型号MD-300, 数量30, 编码P003, 部件优先=是
处理流程:
1. 读取3行订单数据
2. 逐个解析产品型号
3. 根据部件优先设置提取BOM
4. 订单001: 提取5种物料包括部件
5. 订单002: 提取4种物料排除部件只提取子类别
6. 订单003: 提取6种物料包括部件
7. 批量写入15行数据到[BIP上传模板]
8. 显示完成信息: 处理3个订单生成15行BOM数据
输出: [BIP上传模板] 15行数据
```
### 异常处理示例
```
输入: [产品订单] 包含异常数据
- 订单A01, 型号INVALID, 数量5 ← 型号解析失败
- 订单A02, 型号MD-100, 数量0 ← 未匹配到任何物料
- 订单A03, 型号MD-200, 数量10 ← 正常提取3种物料
输出:
第1行: 订单A01, ..., 备注: "解析失败: 无效的型号格式"
第2行: 订单A02, ..., 备注: "未匹配到任何物料"
第3-5行: 订单A03, 3种物料数据
```
## 相关模块
### 依赖的类模块
- **BomExtractor**: BOM提取器负责从平台配置清单中提取匹配的物料
- **ProductModelParser**: 产品型号解析器,解析型号字符串为结构化条件
- **BomItem**: BOM物料项数据模型
- **ConditionEvaluator**: 条件评估器,评估选择条件和类别条件
### 相关模块
- **MainModule**: 主控模块处理产品型号提取和BOM匹配
- 类似的处理逻辑
- 输出到[BOM提取结果]工作表
- 支持部件优先功能
- 使用相同的批量写入优化
## 版本历史
| 版本 | 日期 | 说明 |
|------|------|------|
| 1.0 | 2026-02-01 | 初始版本实现基本的订单处理和BOM提取功能 |
| 1.1 | 2026-02-01 | 添加部件优先功能,支持排除特定类别 |
| 1.2 | 2026-02-01 | 性能优化,使用数组批量写入替代逐个单元格写入 |
| 1.3 | 2026-02-01 | 修复Mermaid流程图方括号转义问题 |

View File

@@ -0,0 +1,443 @@
# ComponentInventoryCheckModule 流程图文档
## 模块概述
**模块名**: ComponentInventoryCheckModule
**功能**: 部件库存核对模块 - 自动核对产品订单中"部件"类物料的库存情况
**主入口**: CheckComponentInventory
**说明**: 当库存不足时,按订单顺序将超出部分的订单的"部件优先"字段标记为"否"
---
## 业务流程图(面向非技术人员)
```mermaid
flowchart TD
Start([开始核对部件库存]) --> Step1["1. 读取数据<br/>读取产品订单表<br/>读取库存表<br/>读取物料配置表"]
Step1 --> Step2["2. 分析订单<br/>查看每个订单需要哪些部件<br/>计算每个订单需要多少个部件"]
Step2 --> Step3["3. 汇总需求<br/>统计所有订单总共需要多少个部件<br/>按部件种类分别统计"]
Step3 --> Step4["4. 检查库存<br/>对比库存数量和需求数量<br/>找出库存不够的部件"]
Step4 --> Step5["5. 分配库存<br/>按订单从上到下依次分配<br/>库存够的订单→保持不变<br/>库存不够的订单→标记为'否'"]
Step5 --> Step6["6. 完成处理<br/>显示处理结果<br/>多少订单能发货<br/>多少订单缺部件"]
Step6 --> End([完成])
style Step1 fill:#e1f5e1
style Step2 fill:#d1ecf1
style Step3 fill:#fff3cd
style Step4 fill:#ffe5b4
style Step5 fill:#f8d7da
style Step6 fill:#e1f5e1
```
### 业务流程说明
| 步骤 | 做什么 | 为什么 |
|------|--------|--------|
| **1. 读取数据** | 从Excel表格中读取订单、库存、配置信息 | 获取处理所需的所有数据 |
| **2. 分析订单** | 查看每个订单需要什么部件、多少个 | 了解每个订单的部件需求 |
| **3. 汇总需求** | 把所有订单的相同部件需求加在一起 | 算出总共需要多少部件 |
| **4. 检查库存** | 对比总需求和实际库存 | 判断库存是否够用 |
| **5. 分配库存** | 先来先得,库存不够的标记为"否" | 确定哪些订单能按时发货 |
| **6. 完成处理** | 显示统计结果 | 让用户了解处理情况 |
### 举例说明
假设有3个订单都需要同一个部件A
| 订单 | 需要部件A数量 | 库存分配过程 | 最终状态 |
|------|--------------|--------------|---------|
| 订单1 | 2个 | 库存剩5个够用 | ✓ 保持原值 |
| 订单2 | 2个 | 库存剩3个够用 | ✓ 保持原值 |
| 订单3 | 2个 | 库存剩1个不够 | ✗ 标记为"否" |
> **技术说明**:标记为"否"的订单在生成BIP上传数据时会跳过部件类物料优先保证子部件供应。
---
## CheckComponentInventory 主流程图(技术版)
> 以下流程图面向技术人员,展示完整的错误处理和验证步骤。
---
## CheckComponentInventory 主流程图(详细版)
```mermaid
flowchart TD
Start(["开始 CheckComponentInventory"]) --> GetSheet1["获取[产品订单]工作表"]
GetSheet1 --> CheckSheet1{工作表存在?}
CheckSheet1 -->|否| ShowMsg1["显示错误消息"] --> End1(["结束"])
CheckSheet1 -->|是| GetSheet2["获取[现存量]工作表"]
GetSheet2 --> CheckSheet2{工作表存在?}
CheckSheet2 -->|否| ShowMsg2["显示错误消息"] --> End2(["结束"])
CheckSheet2 -->|是| GetSheet3["获取[平台配置清单]工作表"]
GetSheet3 --> CheckSheet3{工作表存在?}
CheckSheet3 -->|否| ShowMsg3["显示错误消息"] --> End3(["结束"])
CheckSheet3 -->|是| CheckData{订单数据存在?}
CheckData -->|否| ShowMsg4["显示无数据消息"] --> End4(["结束"])
CheckData -->|是| InitBOM["初始化BOM提取器<br/>LoadBomData"]
InitBOM --> CheckBOM{BOM加载成功?}
CheckBOM -->|否| ShowMsg5["显示BOM错误"] --> End5(["结束"])
CheckBOM -->|是| LoadInv["LoadInventoryData<br/>读取库存数据到字典"]
LoadInv --> CheckInv{库存数据有效?}
CheckInv -->|否| ShowMsg6["显示无库存消息"] --> End6(["结束"])
CheckInv -->|是| LoadOrders["LoadOrderData<br/>读取订单数据"]
LoadOrders --> CheckOrders{订单数据有效?}
CheckOrders -->|否| ShowMsg7["显示无订单消息"] --> End7(["结束"])
CheckOrders -->|是| ParseAll["ParseAllOrdersBOM<br/>解析所有订单的BOM"]
ParseAll --> CalcDemand["CalculateComponentDemand<br/>统计部件总需求"]
CalcDemand --> CheckDemand{有部件需求?}
CheckDemand -->|否| ShowMsg8["显示无部件消息"] --> End8(["结束"])
CheckDemand -->|是| Validate["ValidateInventory<br/>验证库存数据"]
Validate --> Allocate["AllocateInventory<br/>按订单顺序分配库存"]
Allocate --> ShowResult["显示结果统计<br/>总订单数、包含部件订单数<br/>库存充足/不足订单数"]
ShowResult --> End9(["完成"])
style InitBOM fill:#e1f5e1
style LoadInv fill:#d1ecf1
style LoadOrders fill:#d1ecf1
style ParseAll fill:#fff3cd
style CalcDemand fill:#fff3cd
style Validate fill:#ffe5b4
style Allocate fill:#f8d7da
style End9 fill:#e1f5e1
```
---
## AllocateInventory 库存分配详细流程
```mermaid
flowchart TD
AllocStart([开始 AllocateInventory]) --> InitStats[初始化统计信息<br/>TotalOrders, OrdersWithComponent<br/>OrdersSufficient, OrdersInsufficient, OrdersSkipped]
InitStats --> LoopStart{遍历订单<br/>i = 1 to orders.Count}
LoopStart -->|有订单| GetOrder[获取订单 order = orders i]
GetOrder --> CheckParse{解析失败?}
CheckParse -->|ORDER_PARSE_ERR <> ""| Skip1[跳过订单<br/>OrdersSkipped++]
CheckParse -->|无错误| CheckHasComp{包含部件?}
CheckHasComp -->|ORDER_HAS_COMP = False| Skip2[跳过订单<br/>OrdersSkipped++]
CheckHasComp -->|HasComponent = True| CheckQty{数量为0?}
CheckQty -->|ORDER_QUANTITY = 0| Skip3[跳过订单<br/>OrdersSkipped++]
CheckQty -->|数量 > 0| UpdateComp[OrdersWithComponent++]
UpdateComp --> GetComp[获取部件库存信息<br/>compInv = componentDemands compCode]
GetComp --> CalcReq[计算需求量<br/>requiredQty = CompQty × OrderQty]
CalcReq --> CheckStock{库存充足?<br/>compInv.STOCK >= requiredQty}
CheckStock -->|是| DeductSufficient[扣减库存<br/>compInv.STOCK -= requiredQty<br/>OrdersSufficient++]
CheckStock -->|否| MarkNo[标记E列为"否"<br/>orderSheet.Cells Row, 5 = "否"<br/>compInv.STOCK -= requiredQty<br/>OrdersInsufficient++]
DeductSufficient --> NextOrder[继续下一个订单]
MarkNo --> NextOrder
Skip1 --> NextOrder
Skip2 --> NextOrder
Skip3 --> NextOrder
NextOrder --> LoopStart
style UpdateComp fill:#e1f5e1
style DeductSufficient fill:#e1f5e1
style MarkNo fill:#f8d7da
```
---
## ParseOrderBOM 解析详细流程
```mermaid
flowchart TD
ParseStart([开始 ParseOrderBOM]) --> CreateParser[创建ProductModelParser]
CreateParser --> ParseModel[解析型号<br/>parser.Parse model]
ParseModel --> CheckParse{解析成功?}
CheckParse -->|否| SetError[设置解析错误<br/>ORDER_PARSE_ERR = "解析失败: ..."]
SetError --> ParseEnd([结束返回])
CheckParse -->|是| ExtractBOM[提取BOM<br/>bomExtractor.ExtractBom conditions]
ExtractBOM --> LoopComp{遍历BOM项目<br/>For Each item In matchedItems}
LoopComp -->|有项目| CheckCat{item.category = "部件"?}
CheckCat -->|否| NextItem[继续下一个项目]
CheckCat -->|是| SetCompInfo[设置部件信息<br/>ORDER_COMP_CODE = item.Code66<br/>ORDER_COMP_QTY = item.quantity<br/>ORDER_HAS_COMP = True]
SetCompInfo --> ParseEnd
NextItem --> LoopComp
style SetCompInfo fill:#d1ecf1
style SetError fill:#f8d7da
```
---
## 数据处理序列图
```mermaid
sequenceDiagram
participant Main as CheckComponentInventory
participant Loader as 数据加载器
participant Parser as BOM解析器
participant Calc as 需求计算器
participant Validator as 库存验证器
participant Allocator as 库存分配器
Main->>Loader: LoadInventoryData(ws)
Loader-->>Main: 库存字典 Dictionary(编码 -> 数量)
Main->>Loader: LoadOrderData(ws)
Loader-->>Main: 订单集合 Collection(Of Dictionary)
loop 每个订单
Main->>Parser: ParseOrderBOM(order, bomExtractor)
Parser->>Parser: ProductModelParser.Parse(model)
Parser->>Parser: BomExtractor.ExtractBom(conditions)
Parser->>Parser: 查找 category="部件" 的物料
Parser-->>Main: 设置订单部件信息
end
Main->>Calc: CalculateComponentDemand(orders)
Calc->>Calc: 累加每个订单的部件需求
Note over Calc: 需求 = CompQty × OrderQty
Calc-->>Main: 部件需求字典 Dictionary(编码 -> 库存信息)
Main->>Validator: ValidateInventory(demands, inventoryData)
Validator->>Validator: 检查每个部件是否存在
Validator->>Validator: 计算是否短缺
Validator-->>Main: 警告集合 Collection
Main->>Allocator: AllocateInventory(orders, demands, sheet)
loop 按订单顺序遍历
Allocator->>Allocator: 获取订单部件需求
Allocator->>Allocator: 检查库存是否充足
alt 库存充足
Allocator->>Allocator: 扣减库存,保持原值
Note over Allocator: OrdersSufficient++
else 库存不足
Allocator->>Allocator: 标记 E5 = "否"
Note over Allocator: OrdersInsufficient++
end
end
Allocator-->>Main: 统计信息 Statistics
Main-->>Main: 显示结果消息框
```
---
## 数据结构说明
### 订单字典结构 (Dictionary Object)
| 键名 | 常量 | 类型 | 说明 |
|------|------|------|------|
| RowNumber | ORDER_ROW | Long | 订单所在行号 |
| ProductModel | ORDER_MODEL | String | 产品型号 |
| Quantity | ORDER_QUANTITY | Double | 产品数量 |
| ComponentCode | ORDER_COMP_CODE | String | 部件66编码 |
| ComponentQty | ORDER_COMP_QTY | Double | 部件BOM数量 |
| HasComponent | ORDER_HAS_COMP | Boolean | 是否包含部件 |
| ParseError | ORDER_PARSE_ERR | String | 解析错误信息 |
### 部件库存字典结构 (Dictionary Object)
| 键名 | 常量 | 类型 | 说明 |
|------|------|------|------|
| ComponentCode | INV_CODE | String | 部件66编码 |
| TotalDemand | INV_DEMAND | Double | 总需求量 |
| AvailableStock | INV_STOCK | Double | 可用库存(动态扣减) |
| IsShortage | INV_SHORTAGE | Boolean | 是否短缺 |
### 统计信息结构 (Statistics Type)
| 字段 | 类型 | 说明 |
|------|------|------|
| TotalOrders | Long | 总订单数 |
| OrdersWithComponent | Long | 包含部件的订单数 |
| OrdersSufficient | Long | 库存充足订单数 |
| OrdersInsufficient | Long | 库存不足订单数 |
| OrdersSkipped | Long | 跳过订单数 |
---
## 关键特性
### 1. 库存分配策略
- **按订单顺序分配**: 从上到下遍历订单,先到先得
- **动态库存扣减**: 库存充足时扣减,不足时标记为负数
- **只标记不跳过**: 即使库存不足也继续处理后续订单
### 2. 部件识别机制
- 通过 `BomExtractor` 提取完整BOM
- 遍历BOM项目查找 `category = "部件"` 的物料
- 只记录第一个匹配到的部件(假设每个产品只有一个主部件)
### 3. 错误处理
- **工作表缺失**: 提前验证,友好提示
- **BOM加载失败**: 显示错误摘要,终止处理
- **型号解析失败**: 记录错误,跳过该订单
- **部件找不到库存**: 添加警告继续处理库存设为0
### 4. 数据完整性
- 使用 `Dictionary` 实现库存的引用更新
- 使用 `Collection` 保持订单顺序
- 统计跳过的订单解析失败、无部件、数量为0
---
## 执行示例
### 正常流程示例
```
输入数据:
[产品订单]
第2行: MD-100, 数量2, 部件A(编码661001, 用量1)
第3行: MD-200, 数量2, 部件A(编码661001, 用量1)
第4行: MD-300, 数量2, 部件A(编码661001, 用量1)
[现存量]
661001: 5
处理流程:
1. 读取3个订单
2. 解析BOM识别部件661001
3. 统计需求: 1×2 + 1×2 + 1×2 = 6
4. 验证库存: 6 > 5短缺
5. 分配库存:
- 订单2: 需求2库存5→3充足
- 订单3: 需求2库存3→1充足
- 订单4: 需求2库存1→-1不足标记E4="否"
输出结果:
[产品订单]
第2行: E列保持原值
第3行: E列保持原值
第4行: E列 = "否"
统计信息:
处理订单数: 3
包含部件订单: 3
库存充足订单: 2
库存不足订单: 1
```
### 异常处理示例
```
输入数据:
[产品订单]
第2行: INVALID-MODEL, 数量5 ← 型号解析失败
第3行: MD-100, 数量0 ← 数量为0
第4行: MD-200, 数量2, 部件669999 (库存中不存在)
[现存量]
661001: 10
输出结果:
第2行: 跳过(解析失败)
第3行: 跳过数量为0
第4行: 标记E4="否",但添加警告 "部件 '669999' 在[现存量]中未找到"
统计信息:
处理订单数: 3
包含部件订单: 1
库存充足订单: 0
库存不足订单: 1
跳过订单数: 2
警告信息:
部件 '669999' 在[现存量]中未找到
```
---
## 工作表结构要求
### [产品订单] 工作表
| 列号 | 字段名 | 说明 | 必填 |
|------|--------|------|------|
| A | 生产订单号 | 订单唯一标识 | 否 |
| B | 产品型号 | 产品完整型号 | 是 |
| C | 数量 | 生产数量 | 是 |
| D | 产品编码 | 产品代码 | 否 |
| E | 部件优先 | 是否优先提取部件类别(输出字段) | - |
- **表头**: 第1行
- **数据起始**: 第2行
- **输出位置**: E列第5列
### [现存量] 工作表
| 列号 | 字段名 | 说明 |
|------|--------|------|
| B | 物料编码 | 对应BOM中的66代码 |
| J | 结存主数量 | 库存数量 |
- **表头**: 第3行
- **数据起始**: 第4行
### [平台配置清单] 工作表
标准的BOM配置清单用于提取物料信息。
---
## 相关模块
### 依赖的类模块
- **BomExtractor**: BOM提取器负责从平台配置清单中提取匹配的物料
- **ProductModelParser**: 产品型号解析器,解析型号字符串为结构化条件
- **BomItem**: BOM物料项数据模型
### 相关模块
- **BIPUploadModule**: 生成BIP上传模板
- 读取"部件优先"字段
- 当值为"否"时排除"部件"类别物料
- 与本模块功能互补
---
## 算法复杂度
| 操作 | 时间复杂度 | 说明 |
|------|-----------|------|
| LoadInventoryData | O(n) | n = 库存行数 |
| LoadOrderData | O(m) | m = 订单行数 |
| ParseAllOrdersBOM | O(m × p) | p = 平均BOM物料数 |
| CalculateComponentDemand | O(m) | 遍历订单统计需求 |
| ValidateInventory | O(k) | k = 不同部件数 |
| AllocateInventory | O(m) | 遍历订单分配库存 |
**总体复杂度**: O(m × p)主要由BOM解析决定
---
## 版本历史
| 版本 | 日期 | 说明 |
|------|------|------|
| 1.0 | 2026-02-03 | 初始版本,实现部件库存核对功能 |

View File

@@ -0,0 +1,391 @@
# 执行计划:部件数量核对功能
## 一、需求概述
### 1.1 功能描述
自动核对产品订单中"部件"类物料的库存情况,当库存不足时,按订单顺序将超出部分的订单的"部件优先"字段标记为"否"。
### 1.2 数据源
#### [产品订单]工作表
- **表头位置**第1行
- **数据起始行**第2行
- **关键列**
- B列产品型号
- C列产品数量
- E列部件优先输出字段
#### [现存量]工作表
- **表头位置**第3行
- **数据起始行**第4行
- **关键列**
- B列物料编码对应BOM中的66代码
- J列结存主数量库存数量
---
## 二、业务逻辑
### 2.1 核心流程
```
1. 读取所有订单 → 2. 解析型号提取BOM → 3. 识别部件物料
4. 统计部件总需求 → 5. 查询库存 → 6. 库存充足性检查
7. 按订单顺序分配库存 → 8. 修改部件优先字段
```
### 2.2 计算规则
#### 部件总需求量
```
部件总需求 = Σ(订单i的BOM中部件数量 × 订单i的产品数量)
```
#### 示例
```
订单1产品数量=2部件A的BOM数量=1 → 需求 = 1 × 2 = 2
订单2产品数量=2部件A的BOM数量=1 → 需求 = 1 × 2 = 2
订单3产品数量=2部件A的BOM数量=1 → 需求 = 1 × 2 = 2
--------------------------------------------------------
部件A总需求 = 2 + 2 + 2 = 6
部件A库存 = 5
库存不足 = 6 - 5 = 1
```
### 2.3 分配策略
**原则**:按订单自上而下的顺序分配库存
| 订单 | 需求量 | 分配前库存 | 分配后库存 | 部件优先 |
|------|--------|-----------|-----------|---------|
| 订单1 | 2 | 5 | 3 | 保持不变 |
| 订单2 | 2 | 3 | 1 | 保持不变 |
| 订单3 | 2 | 1 | -1不足 | **改为"否"** |
---
## 三、处理规则
### 3.1 正常情况
- 订单包含"部件"物料,库存充足 → 保持原值
- 订单包含"部件"物料,库存不足 → 改为"否"
- 订单不包含"部件"物料 → **保持原值不变**
### 3.2 异常情况
- **部件在[现存量]中找不到** → 报错提示,终止处理
- **型号解析失败** → 跳过该订单,记录错误
- **未匹配到任何物料** → 跳过该订单(无部件)
### 3.3 字段修改规则
- **基于现有值进行修改**(不清空原有值)
- **只修改E列"部件优先"字段**
- 修改格式:`是``否``1``0``TRUE``FALSE` 均可识别
---
## 四、数据结构设计
### 4.1 订单数据结构
```vba
Type OrderInfo
RowNumber As Long ' 行号
ProductModel As String ' 产品型号
Quantity As Long ' 产品数量
ComponentCode As String ' 部件66编码
ComponentQty As Double ' 部件BOM数量
HasComponent As Boolean ' 是否包含部件
ParseError As String ' 解析错误信息
End Type
```
### 4.2 部件库存结构
```vba
Type ComponentInventory
ComponentCode As String ' 部件66编码
TotalDemand As Double ' 总需求量
AvailableStock As Double ' 可用库存
IsShortage As Boolean ' 是否短缺
End Type
```
---
## 五、实现方案
### 5.1 新建模块
**文件名**`ComponentInventoryCheckModule.bas`
**主要过程**
```vba
Public Sub CheckComponentInventory()
' 主入口程序
End Sub
```
### 5.2 核心函数
#### 5.2.1 读取订单数据
```vba
Private Function LoadOrderData(ws As Worksheet) As Collection
' 返回 Collection(Of OrderInfo)
' 读取[产品订单]的B、C列数据
End Function
```
#### 5.2.2 读取库存数据
```vba
Private Function LoadInventoryData(ws As Worksheet) As Object
' 返回 Dictionary(物料编码 -> 库存数量)
' 读取[现存量]的B、J列数据
End Function
```
#### 5.2.3 解析订单BOM
```vba
Private Sub ParseOrderBOM(orderInfo As OrderInfo, _
bomExtractor As BomExtractor, _
parser As ProductModelParser)
' 解析型号提取BOM
' 识别"部件"类别物料
' 填充 orderInfo.ComponentCode 和 orderInfo.ComponentQty
End Sub
```
#### 5.2.4 统计部件需求
```vba
Private Function CalculateComponentDemand( _
orders As Collection) As Object
' 返回 Dictionary(部件编码 -> ComponentInventory)
' 累加所有订单的部件需求量
End Function
```
#### 5.2.5 检查库存充足性
```vba
Private Sub ValidateInventory( _
componentDemands As Object, _
inventoryData As Object)
' 检查每个部件的库存是否充足
' 如果找不到或不足,报错提示
End Sub
```
#### 5.2.6 分配库存并标记
```vba
Private Sub AllocateInventory( _
orders As Collection, _
componentDemands As Object, _
orderSheet As Worksheet)
' 按订单顺序分配库存
' 库存不足时修改E列"部件优先"为"否"
End Sub
```
---
## 六、详细实现步骤
### 6.1 主流程CheckComponentInventory
```
1. 获取工作表对象
├─ [产品订单]工作表
├─ [现存量]工作表
└─ [平台配置清单]工作表
2. 初始化BOM提取器
└─ 加载BOM数据
3. 读取库存数据到字典
└─ Dictionary(66编码 -> 库存数量)
4. 读取订单数据
└─ Collection(Of OrderInfo)
5. 解析所有订单的BOM
└─ 识别部件填充ComponentCode和ComponentQty
6. 统计部件总需求
└─ Dictionary(部件编码 -> ComponentInventory)
7. 验证库存
└─ 检查部件是否存在于[现存量]中
8. 按订单顺序分配库存
└─ 修改E列"部件优先"字段
9. 输出结果统计
└─ MsgBox显示处理结果
```
### 6.2 分配算法(伪代码)
```vba
For Each order In orders
If order.HasComponent Then
Dim demand As ComponentInventory
demand = componentDemands(order.ComponentCode)
Dim requiredQty As Double
requiredQty = order.ComponentQty * order.Quantity
If demand.AvailableStock >= requiredQty Then
' 库存充足,保持原值
demand.AvailableStock = demand.AvailableStock - requiredQty
Else
' 库存不足,标记为"否"
orderSheet.Cells(order.RowNumber, 5).Value = "否"
demand.AvailableStock = demand.AvailableStock - requiredQty
End If
End If
Next order
```
---
## 七、边界情况处理
### 7.1 无部件的订单
```
条件订单的BOM中没有"类别=部件"的物料
处理跳过该订单E列保持原值
```
### 7.2 多个订单使用不同部件
```
订单1部件A
订单2部件B
处理分别统计A和B的需求独立核算库存
```
### 7.3 库存为0的情况
```
条件:[现存量]中某部件的结存主数量 = 0
处理:所有需要该部件的订单都标记为"否"
```
### 7.4 产品数量为0的情况
```
条件订单的C列产品数量 = 0
处理:该订单的部件需求 = 0不影响库存
```
### 7.5 部件优先字段原有值
```
可能的值:"是"、"否"、1、0、TRUE、FALSE、空
处理:基于现有值修改,不清空
```
---
## 八、测试用例
### 8.1 基本功能测试
| 测试场景 | 订单数 | 部件 | 总需求 | 库存 | 预期结果 |
|---------|--------|------|--------|------|---------|
| 库存充足 | 3 | A(1) | 6 | 10 | 全部保持原值 |
| 库存不足 | 3 | A(1) | 6 | 5 | 第3个订单改为"否" |
| 库存刚好 | 3 | A(1) | 6 | 6 | 全部保持原值 |
| 无部件订单 | 2 | - | - | - | 保持原值 |
| 库存为0 | 2 | A(1) | 4 | 0 | 全部改为"否" |
### 8.2 异常情况测试
| 测试场景 | 预期行为 |
|---------|---------|
| 部件在[现存量]中不存在 | 报错提示,终止处理 |
| 型号解析失败 | 跳过该订单,记录错误 |
| [产品订单]为空 | 提示无数据,退出 |
| [现存量]为空 | 报错提示,退出 |
### 8.3 边界值测试
| 测试场景 | 输入值 | 预期结果 |
|---------|--------|---------|
| 产品数量为1 | 所有订单数量=1 | 正常计算 |
| 产品数量为大数 | 订单数量=1000 | 正常计算 |
| 部件BOM数量为小数 | 0.5 | 正确计算总需求 |
| 库存数量为小数 | 2.5 | 正确判断库存 |
---
## 九、用户界面设计
### 9.1 执行入口
建议在主界面添加按钮:
```
[部件库存核对]
```
### 9.2 结果提示
执行完成后显示:
```
✓ 部件库存核对完成!
处理订单数10
包含部件订单8
库存充足订单6
库存不足订单2
耗时0.50秒
```
### 9.3 错误提示
格式:
```
✗ 部件库存核对失败!
错误信息:
- 订单第5行部件 '661234' 在[现存量]中未找到
请检查数据后重试。
```
---
## 十、实施步骤
1. **创建新模块**
- 文件名:`ComponentInventoryCheckModule.bas`
- 位置:`VBA/Modules/`
2. **实现核心函数**
- LoadOrderData
- LoadInventoryData
- ParseOrderBOM
- CalculateComponentDemand
- ValidateInventory
- AllocateInventory
3. **实现主流程**
- CheckComponentInventory
4. **测试验证**
- 基本功能测试
- 异常情况测试
- 边界值测试
5. **集成到主界面**
- 添加按钮或菜单项
---
## 十一、风险评估
| 风险 | 影响 | 缓解措施 |
|------|------|---------|
| 库存数据不准确 | 导致错误的分配结果 | 执行前提示用户确认库存数据 |
| 订单量大导致性能问题 | 处理时间长 | 优化算法,使用批量操作 |
| BOM解析失败 | 无法识别部件 | 记录错误日志,跳过该订单 |
| 部件编码不一致 | 无法匹配库存 | 严格验证,报错提示 |
---
**是否批准此执行计划?确认后我将开始代码实现。**

View File

@@ -0,0 +1,199 @@
# 执行计划添加附加功能fjgn支持
## 一、需求概述
### 1.1 新增条件字段
- **条件代码**`fjgn`
- **条件名称**`附加功能`
- **提取位置**:从型号表头的[仪表特性]字段中提取第6个位置索引5
### 1.2 型号结构
```
[型号]-[公称外径].[安装形式].[壳体形式].[过程连接&接液材质].[量程范围].[仪表特性]
```
### 1.3 仪表特性解析规则
- **充油类型**:位于最后,格式为 `Y`+一位数字(如 Y3
- **附加功能**:在充油类型前面的内容
- 分隔符可能是 `,``.`(如 `N2,N3``N2.N3`
- 可能为空(如仪表特性只有 `Y3`
### 1.4 示例
| 型号 | 仪表特性 | 充油类型 | 附加功能 |
|------|----------|----------|----------|
| PYTHN-100.A0.541.M201.M06.N2,N3.Y3 | N2,N3.Y3 | Y3 | N2,N3 |
| YTHN-100.A0.531.M201.M08.Y3 | Y3 | Y3 | (空) |
---
## 二、条件评估规则
### 2.1 fjgn 条件的特殊处理
| 条件表达式 | 型号中的 fjgn | 评估结果 | 说明 |
|-----------|--------------|---------|------|
| fjgn=N1 | N1,N2 | ✅ True | 包含 N1 |
| fjgn=N1 | N2,N3 | ❌ False | 不包含 N1 |
| fjgn=N1 | (空) | ❌ False | 空值不包含任何值 |
| fjgn!=N1 | N1,N2 | ❌ False | 包含 N1不满足!= |
| fjgn!=N1 | N2,N3 | ✅ True | 不包含 N1 |
| fjgn!=N1 | (空) | ✅ True | 空值不包含 N1 |
### 2.2 匹配逻辑
- **等值匹配fjgn=XX**fjgn 字符串中包含指定值即为真
- **不等匹配fjgn!=XX**fjgn 字符串中不包含指定值即为真
- **空值处理**:空字符串不包含任何值
---
## 三、代码修改方案
### 3.1 ProductModelParser.cls
**修改位置**`ParseHeader()` 方法
**新增内容**
```vba
' 仪表特性 - 第6个位置(索引5),可能不存在
If UBound(dotParts) >= 5 Then
Dim instrumentFeature As String
instrumentFeature = Trim(dotParts(5))
' 提取附加功能
Dim fjgn As String
fjgn = ExtractAdditionalFeatures(instrumentFeature)
pConditions.Add "fjgn", fjgn
Else
' 如果没有仪表特性字段fjgn为空
pConditions.Add "fjgn", ""
End If
```
**新增方法**`ExtractAdditionalFeatures()`
```vba
Private Function ExtractAdditionalFeatures(instrumentFeature As String) As String
' 1. 检查是否以Y+数字结尾(充油类型)
Dim lastTwoChars As String
If Len(instrumentFeature) >= 2 Then
lastTwoChars = Right(instrumentFeature, 2)
If UCase(Left(lastTwoChars, 1)) = "Y" And IsNumeric(Right(lastTwoChars, 1)) Then
' 去掉充油类型
instrumentFeature = Left(instrumentFeature, Len(instrumentFeature) - 2)
instrumentFeature = Trim(instrumentFeature)
End If
End If
' 2. 处理可能的分隔符(,或.
' 将可能的.替换为,,统一处理
instrumentFeature = Replace(instrumentFeature, ".", ",")
' 3. 去除可能的后缀分隔符
If Right(instrumentFeature, 1) = "," Then
instrumentFeature = Left(instrumentFeature, Len(instrumentFeature) - 1)
End If
ExtractAdditionalFeatures = Trim(instrumentFeature)
End Function
```
---
### 3.2 BIPUploadModule.bas
**修改位置**第12行常量定义
**修改内容**
```vba
' 修改前
Private Const CONDITION_CONFIG = "azxs,安装形式|bkxs,表壳形式|gclj,过程连接|jycz,接液材质|lcfw,量程范围"
' 修改后
Private Const CONDITION_CONFIG = "azxs,安装形式|bkxs,表壳形式|gclj,过程连接|jycz,接液材质|lcfw,量程范围|fjgn,附加功能"
```
---
### 3.3 ConditionEvaluator.cls
**修改位置**`EvaluateSingleCondition()` 方法
**修改内容**:在现有的 `=``!=` 运算符处理后,添加 fjgn 特殊处理
```vba
' 在现有的 actualValue = Conditions(varName) 之后添加
actualValue = Conditions(varName)
' fjgn 字段特殊处理(多值匹配)
If varName = "fjgn" Then
If operator = "=" Then
' fjgn=N1检查actualValue中是否包含value
EvaluateSingleCondition = InStr(actualValue, value) > 0
ElseIf operator = "!=" Then
' fjgn!=N1检查actualValue中是否不包含value
EvaluateSingleCondition = InStr(actualValue, value) = 0
End If
Exit Function
End If
' 其他字段使用原有逻辑
EvaluateSingleCondition = (actualValue = value)
```
---
## 四、测试用例
### 4.1 解析测试
| 测试型号 | 预期 fjgn | 预期其他条件 |
|---------|----------|-------------|
| PYTHN-100.A0.541.M201.M06.N2,N3.Y3 | N2,N3 | azxs=A0, bkxs=541, gclj=M20, jycz=1, lcfw=M06 |
| YTHN-100.A0.531.M201.M08.Y3 | (空) | azxs=A0, bkxs=531, gclj=M20, jycz=1, lcfw=M08 |
| BP-088.2312.M08.0A3.N1.N2.Y2 | N1,N2 | azxs=23, bkxs=12, gclj=M08, jycz=0, lcfw=A3 |
| BP-088.2312.M08.0A3.Y2 | (空) | azxs=23, bkxs=12, gclj=M08, jycz=0, lcfw=A3 |
### 4.2 条件评估测试
| fjgn值 | 选用条件 | 预期结果 |
|-------|---------|---------|
| N1,N2 | fjgn=N1 | True |
| N1,N2 | fjgn=N3 | False |
| (空) | fjgn=N1 | False |
| N1,N2 | fjgn!=N1 | False |
| N1,N2 | fjgn!=N3 | True |
| (空) | fjgn!=N1 | True |
---
## 五、实施步骤
1. **修改 ProductModelParser.cls**
-`ParseHeader()` 方法中添加仪表特性提取逻辑
- 新增 `ExtractAdditionalFeatures()` 方法
2. **修改 BIPUploadModule.bas**
- 更新 `CONDITION_CONFIG` 常量
3. **修改 ConditionEvaluator.cls**
-`EvaluateSingleCondition()` 方法中添加 fjgn 特殊处理逻辑
4. **测试验证**
- 测试型号解析是否正确
- 测试条件评估是否符合预期
- 测试边界情况(空值、多个附加功能等)
---
## 六、风险评估
| 风险 | 影响 | 缓解措施 |
|------|------|---------|
| 旧型号缺少仪表特性字段 | 解析失败 | 判断字段是否存在,不存在时 fjgn 为空 |
| 充油类型识别错误 | 提取错误 | 严格匹配 Y+一位数字的格式 |
| 分隔符不一致 | 解析错误 | 统一将 `.` 替换为 `,` 处理 |
| 条件评估逻辑错误 | 匹配错误 | 充分测试各种边界情况 |
---
**是否批准此执行计划?确认后我将开始代码实现。**

View File

@@ -0,0 +1,444 @@
# 提取备注字段数据来源分析
**文档生成时间**: 2026-03-13
**入口函数**: `MainModule.ProcessProductModels()`
**输出位置**: `BOM 提取结果` 工作表的"提取备注"列(最后一列)
---
## 核心数据流图
```mermaid
flowchart TD
A[ProcessProductModels<br/>主入口] --> B[ProcessSingleModel<br/>处理单个型号]
B --> C{解析产品型号<br/>parser.Parse}
C -->|解析失败 | D["extractNote = <br/>解析失败: + ErrorMessage"]
C -->|解析成功 | E[BomExtractor.ExtractBom<br/>提取 BOM]
E --> F[DetermineRequiredCategories<br/>确定必需类别]
F --> G[MatchItems<br/>匹配物料]
G --> H{匹配数量?}
H -->|0 条 | I[不立即报错<br/>移交 ValidateResult]
H -->|1 条 | J[正常添加到结果集]
H -->|多条 | K["记录错误到 pErrorMessages<br/>类别 X 匹配到多条物料 N 条"]
K --> L[设置 item.MatchError<br/>并添加所有匹配项]
I --> M[ValidateResult<br/>双向覆盖检查]
L --> M
J --> M
M --> N{必需类别存在?}
N -->|被子类覆盖 | O[视为正常<br/>不报错]
N -->|被父类覆盖 | O
N -->|确实缺失 | P["记录错误<br/>必需类别 X 未匹配"]
O --> Q[GetErrorSummary<br/>汇总错误]
P --> Q
Q --> R{bomErrors 为空?}
R -->|非空 | S[extractNote = bomErrors]
R -->|空 | T[extractNote 保持空]
S --> U{matchedItems 为空?}
T --> U
U -->|是 | V{extractNote 为空?}
U -->|否 | W[遍历每个 item]
V -->|是 | X["extractNote = <br/>未匹配到任何物料"]
V -->|否 | Y[保持现有 extractNote]
X --> Z1[CreateOutputRowArray<br/>创建输出行]
Y --> Z1
W --> AA[For Each item<br/>itemNote = extractNote]
AA --> AB{item.MatchError<br/>非空?}
AB -->|是 | AC["拼接itemNote += <br/>; + MatchError"]
AB -->|否 | AD[保持 itemNote]
AC --> AE[CreateOutputRowArray<br/>创建输出行]
AD --> AE
Z1 --> AF[输出到 BOM 提取结果<br/>提取备注列]
AE --> AF
style D fill:#ff6b6b
style K fill:#ffa94d
style P fill:#ff6b6b
style X fill:#51cf66
style AF fill:#339af0,color:#fff
```
---
## 详细数据来源
### 来源 1: 产品型号解析失败
**位置**: `MainModule.bas` 第 184-188 行
**触发条件**: `ProductModelParser.Parse()` 返回 `False`
**错误来源**: `ProductModelParser.ErrorMessage`
```vba
' MainModule.bas:184-188
If Not parser.Parse(modelString) Then
' 解析失败
extractNote = "解析失败:" & parser.ErrorMessage
outputData.Add CreateOutputRowArray(..., extractNote, Nothing)
Exit Sub
End If
```
**可能的错误消息**(来自 `ProductModelParser.cls`:
| 错误场景 | 错误消息示例 | 源码位置 |
|---------|-------------|---------|
| 缺少表头部分 | `型号格式错误:缺少表头部分` | Parse() L73 |
| 缺少'-'分隔符 | `表头格式错误:缺少'-'分隔符` | ParseHeader() L108 |
| 表头结构不完整 | `表头结构不完整:缺少必要字段` | ParseHeader() L114 |
| 过程连接代码格式错误 | `过程连接代码格式错误:长度不足` | ExtractConnectionAndMaterial() L205 |
| 最后一位不是数字 | `过程连接代码格式错误:最后一位不是数字` | ExtractConnectionAndMaterial() L213 |
| 解析异常 | `解析表头异常:[VBA 错误描述]` | ParseHeader() ErrorHandler L131 |
---
### 来源 2: BOM 提取器错误汇总
**位置**: `MainModule.bas` 第 197-200 行
**触发条件**: `BomExtractor.GetErrorSummary()` 返回非空字符串
**错误来源**: `BomExtractor.pErrorMessages` 集合
```vba
' MainModule.bas:197-200
Dim bomErrors As String
bomErrors = BomExtractor.GetErrorSummary
If bomErrors <> "" Then
extractNote = bomErrors
End If
```
**错误汇总逻辑**`BomExtractor.cls` L471-481:
```vba
Public Function GetErrorSummary() As String
If pErrorMessages.Count = 0 Then
GetErrorSummary = ""
Else
Dim result As String
Dim msg As Variant
For Each msg In pErrorMessages
result = result & CStr(msg) & "; " ' 使用"; " 连接
Next msg
GetErrorSummary = result
End If
End Function
```
---
### 来源 3: 多匹配错误
**位置**: `BomExtractor.cls` 第 247-258 行
**触发条件**: 同一类别匹配到多条物料
**错误消息**: `类别 [X] 匹配到多条物料 (N 条)`
```vba
' BomExtractor.cls:247-258
ElseIf categoryMatches.Count = 1 Then
' 正常:匹配到 1 条
pMatchedItems.Add categoryMatches(1)
Else
' 异常:匹配到多条
Dim multiMsg As String
multiMsg = "类别 [" & category & "] 匹配到多条物料 (" & categoryMatches.Count & "条)"
pErrorMessages.Add multiMsg
' 临时处理:输出所有匹配的
Dim tempItem As BomItem
For Each tempItem In categoryMatches
tempItem.MatchError = multiMsg ' ← 设置到 item
pMatchedItems.Add tempItem
Next tempItem
End If
```
**特性**:
- 错误同时添加到 `pErrorMessages`(进入 GetErrorSummary
- 同时设置到 `item.MatchError`(逐行附加)
- 输出所有匹配项,但每条都带警告
---
### 来源 4: 必需类别缺失
**位置**: `BomExtractor.cls` 第 449-451 行
**触发条件**: ValidateResult 检测到必需类别未匹配且无覆盖
**错误消息**: `必需类别 [X] 未匹配`
```vba
' BomExtractor.cls:449-451
If Not isResolved Then
pErrorMessages.Add "必需类别 [" & category & "] 未匹配"
End If
```
**双向覆盖检查逻辑**:
```mermaid
flowchart LR
A[必需类别 X 缺失] --> B{检查 1: 有父类?}
B -->|是 | C{父类别已匹配?}
C -->|是 | D[被父类覆盖<br/>不报错]
C -->|否 | E[检查 2]
B -->|否 | E
E --> F{检查 2: 有子类?}
F -->|是 | G{所有子类都匹配?}
G -->|是 | H[被子类覆盖<br/>不报错]
G -->|否 | I[确实缺失<br/>报错]
F -->|否 | I
D --> J[Continue]
H --> J
I --> K[添加到 pErrorMessages]
style D fill:#51cf66
style H fill:#51cf66
style K fill:#ff6b6b
```
**覆盖场景示例**:
| 场景 | 父类别 | 子类别 1 | 子类别 2 | 结果 |
|------|--------|---------|---------|------|
| 总成优先 | ✅ 部件 (1 条) | ✅ 接头 (2 条) | ✅ 弹性元件 (1 条) | 输出"部件",子类不报错 |
| 散件满足 | ❌ 部件 (缺失) | ✅ 接头 (2 条) | ✅ 弹性元件 (1 条) | 输出子类,父类不报错 |
| 确实缺失 | ❌ 部件 (缺失) | ❌ 接头 (缺失) | ✅ 弹性元件 (1 条) | 报错:"必需类别 [接头] 未匹配" |
---
### 来源 5: 无匹配物料
**位置**: `MainModule.bas` 第 203-208 行
**触发条件**: `matchedItems.Count = 0``extractNote` 为空
**错误消息**: `未匹配到任何物料`
```vba
' MainModule.bas:203-208
If matchedItems.Count = 0 Then
' 没有匹配项
If extractNote = "" Then
extractNote = "未匹配到任何物料"
End If
outputData.Add CreateOutputRowArray(..., extractNote, Nothing)
```
**注意**: 如果已有其他错误(如解析错误),则不会覆盖。
---
### 来源 6: 物料级 MatchError
**位置**: `MainModule.bas` 第 215-223 行
**触发条件**: `BomItem.MatchError` 非空
**错误来源**: 由 `BomExtractor.MatchItems()` 设置(见来源 3
```vba
' MainModule.bas:215-223
For Each item In matchedItems
Dim itemNote As String
itemNote = extractNote
' 添加物料特定的错误
If item.MatchError <> "" Then
If itemNote <> "" Then itemNote = itemNote & "; "
itemNote = itemNote & item.MatchError
End If
' ... 添加到输出
Next item
```
**特性**:
- 每条 BOM 物料单独输出时附加
- 使用 `"; "` 分隔符拼接
- 首行继承全局 `extractNote`,后续行只继承不含物料级错误
---
## 错误消息拼接规则
```mermaid
sequenceDiagram
participant M as MainModule
participant P as ProductModelParser
participant E as BomExtractor
participant I as BomItem
M->>P: Parse modelString
alt 解析失败
P-->>M: 返回 ErrorMessage
Note over M: extractNote = 解析失败 + ErrorMessage
M->>M: 输出单行后结束
else 解析成功
M->>E: ExtractBom conditions
Note over E: 收集错误到 pErrorMessages
Note over E: 设置 item.MatchError
E-->>M: GetErrorSummary
alt bomErrors 非空
Note over M: extractNote = bomErrors
else bomErrors 为空
Note over M: extractNote 保持空
end
alt matchedItems = 0
Note over M: 设为 未匹配到任何物料
M->>M: 输出单行后结束
else matchedItems > 0
loop For Each item
M->>M: itemNote = extractNote
alt item.MatchError 非空
Note over M: itemNote += MatchError
end
M->>M: CreateOutputRowArray
end
end
end
Note over M: 输出到提取备注列
```
**拼接规则总结**:
| 场景 | 拼接方式 | 示例 |
|------|---------|------|
| 全局错误汇总 | 分号连接 | 错误 1; 错误 2 |
| 物料级附加 | 检查非空后加分号 | extractNote + MatchError |
| 多类别缺失 | 逐个添加到集合后汇总 | 必需类别 A 未匹配; 必需类别 B 未匹配 |
| 解析失败 + 其他 | 解析失败时立即退出不叠加 | 解析失败:... |
---
## 输出列定义
**位置**: `MainModule.bas` 第 270 行
```vba
' MainModule.bas:242-270
Private Sub WriteOutputHeader(ws As Worksheet)
' ... 前面的列 ...
ws.Cells(1, col).Value = "66 代码": col = col + 1
ws.Cells(1, col).Value = "提取备注": col = col + 1 ' ← 最后一列
End Sub
```
**数据写入**: `CreateOutputRowArray()` 函数的最后一个元素
```vba
' MainModule.bas:283-339
Private Function CreateOutputRowArray(..., note As String, ...) As Variant()
' ... 填充前面的列 ...
' 备注(最后一列)
rowData(col) = note
CreateOutputRowArray = rowData
End Function
```
---
## 完整错误消息类型汇总表
| 错误类型 | 错误消息模板 | 触发条件 | 源码位置 | 是否可叠加 |
|---------|-------------|---------|---------|----------|
| **解析错误** | `解析失败:[具体原因]` | Parse() 失败 | MainModule.bas:186 | ❌ 单独输出 |
| **多匹配** | `类别 [X] 匹配到多条物料 (N 条)` | 同类别匹配>1 | BomExtractor.cls:250 | ✅ 可叠加 |
| **必需类别缺失** | `必需类别 [X] 未匹配` | ValidateResult 检测缺失 | BomExtractor.cls:450 | ✅ 可叠加 |
| **无匹配** | `未匹配到任何物料` | matchedItems.Count = 0 | MainModule.bas:207 | ❌ 仅当无其他错误 |
| **物料级多匹配** | `类别 [X] 匹配到多条物料 (N 条)` | item.MatchError | MainModule.bas:221 | ✅ 逐行附加 |
---
## 典型输出示例
### 示例 1: 解析失败
```
产品型号Y-100-M203.316SS
提取备注:解析失败:表头结构不完整:缺少必要字段
```
### 示例 2: 正常匹配(无错误)
```
产品型号Y-100-M203.316SS.L100.N2
提取备注:(空)
```
### 示例 3: 多匹配错误
```
产品型号Y-100-M203.316SS.L100.N2
提取备注:类别 [接液材质] 匹配到多条物料 (3 条); 类别 [量程范围] 匹配到多条物料 (2 条);
```
### 示例 4: 必需类别缺失
```
产品型号Y-100-M203.316SS.L100.N2
提取备注:必需类别 [安装形式] 未匹配; 必需类别 [表壳形式] 未匹配;
```
### 示例 5: 无匹配
```
产品型号INVALID-MODEL
提取备注:未匹配到任何物料
```
### 示例 6: 物料级错误附加
```
产品型号Y-100-M203.316SS.L100.N2
行号 | 类别 | 提取备注
-----|------|----------
1 | 接头 | 类别 [接液材质] 匹配到多条物料 (3 条); 类别 [接液材质] 匹配到多条物料 (3 条);
2 | 弹性元件 | 类别 [接液材质] 匹配到多条物料 (3 条);
```
---
## 关键代码路径索引
| 功能 | 文件 | 行号范围 |
|------|------|---------|
| 主入口 | MainModule.bas | 20-150 |
| 单型号处理 | MainModule.bas | 161-235 |
| 输出表头定义 | MainModule.bas | 242-271 |
| 行数据创建 | MainModule.bas | 283-339 |
| 型号解析 | ProductModelParser.cls | 60-91 |
| BOM 提取 | BomExtractor.cls | 130-152 |
| 匹配物料 | BomExtractor.cls | 208-261 |
| 总成逻辑 | BomExtractor.cls | 270-367 |
| 结果验证 | BomExtractor.cls | 376-455 |
| 错误汇总 | BomExtractor.cls | 471-482 |
| 物料数据模型 | BomItem.cls | 1-89 |
---
## 设计特点
**优点**:
1. 错误信息分层清晰(解析层、匹配层、验证层)
2. 支持多错误叠加,不丢失任何警告
3. 双向覆盖检查避免误报(总成/散件场景)
4. 物料级错误逐行附加,便于定位问题
⚠️ **注意事项**:
1. 解析失败时立即退出,不执行后续 BOM 提取
2. 多匹配错误会输出所有匹配项(数据不确定时保留全部)
3. 错误消息使用 `"; "` 分隔,末尾可能有多余分隔符
4. "未匹配到任何物料"仅在无其他错误时显示
---
**文档结束**

View File

@@ -0,0 +1,115 @@
| 代号 | Y-100 | 描述 | | 英文名称 | | | | | | | | |
|------|---------|--------------|------------|------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----|------|------|--------|-------------|---------|-----------------|
| 名称 | 压力表 | 负责人 | | 备注 | | | | | | | | |
| 行号 | 模块 | 代号 | 名称 | 数量 | 选择条件 | 备注 | 类别 | 上层类别 | 类别选用条件 | 66代码 | BIP行号基数 | 修改备注 |
| 10 | 表壳 | 01091004644 | 轴向表壳(黑色) | 1 | (azxs=B0 OR azxs=BT) AND (bkxs=200 OR bkxs=210) | | 表壳 | | | 66071004644 | 7100 | |
| 20 | 表壳 | 01091004647 | 轴向表壳(抛光) | 1 | azxs=B0 AND bkxs=500 | | 表壳 | | | 66071004647 | 7100 | |
| 30 | 表壳 | 01091004643 | 径向表壳(黑色) | 1 | (azxs=A0 OR azxs=AT) AND (bkxs=200 OR bkxs=210) | | 表壳 | | | 66071004643 | 7100 | |
| 40 | 表壳 | 01091004648 | 径向表壳(抛光) | 1 | azxs=A0 AND bkxs=500 | | 表壳 | | | 66071004648 | 7100 | |
| 50 | 表壳 | 01081013918 | 带后边表壳(黑色) | 1 | azxs=AH AND (bkxs=200 OR bkxs=210) | | 表壳 | | | 66051013918 | 7100 | |
| 60 | 罩壳 | 01091004768 | 罩壳(抛光) | 1 | azxs=A0 AND bkxs=500 | | 罩壳 | | | 66071004768 | 7100 | |
| 70 | 罩壳 | 01091005032 | 罩壳(抛光) | 1 | azxs=B0 AND bkxs=500 | | 罩壳 | | | 66071005032 | 7100 | 改为 66071005032 |
| 80 | 罩壳 | 01091004624 | 罩壳(黑色) | 1 | azxs=AT AND bkxs=200 | | 罩壳 | | | 66071004624 | 7100 | |
| 90 | 罩壳 | 01091004623 | 罩壳(亮) | 1 | azxs=A0 AND bkxs=210 | | 罩壳 | | | 66071004623 | 7100 | |
| 100 | 罩壳 | 01091004621 | 罩壳(亮) | 1 | azxs=BT AND bkxs=210 | | 罩壳 | | | 66071004621 | 7100 | |
| 110 | 罩壳 | 01091004620 | 罩壳(黑色) | 1 | azxs=BT AND bkxs=200 | | 罩壳 | | | 66071004620 | 7100 | |
| 120 | 罩壳 | 01091004619 | 罩壳(黑色) | 1 | azxs=B0 AND bkxs=200 | | 罩壳 | | | 66071004619 | 7100 | |
| 130 | 罩壳 | 01091004618 | 罩壳(黑色) | 1 | azxs=A0 AND bkxs=200 | | 罩壳 | | | 66071004618 | 7100 | |
| 140 | 罩壳 | 01091004617 | 罩壳(亮) | 1 | azxs=B0 AND bkxs=210 | | 罩壳 | | | 66071004617 | 7100 | |
| 150 | 玻璃 | 01111001334 | 表玻璃 | 1 | fjgn!=N1 | | 玻璃 | | | 66201001334 | 7100 | |
| 160 | 定位型玻璃部件 | 01111001335 | 表玻璃 | 1 | fjgn=N1 | | 玻璃 | | | 66201001202 | 7100 | 改为 66201001202 |
| 170 | 定位型玻璃部件 | 01091004453 | 100 红色定位指针 | 1 | fjgn= N1 | | | | | 66071004453 | 7100 | |
| 180 | 定位型玻璃部件 | 01091004451 | 100 绿色定位指针 | 1 | fjgn=N1 | | | | | 66071004451 | 7100 | |
| 190 | 定位型玻璃部件 | 01081014387 | 定位钉 | 1 | fjgn=N1 | | | | | 66051014387 | 7100 | |
| 200 | 定位型玻璃部件 | 01201002619 | 固定套 | 1 | fjgn=N1 | | | | | 66991922619 | 7100 | |
| 210 | 定位型玻璃部件 | 01121002259 | 橡胶垫<2> | 1 | fjgn=N1 | | | | | 66181002259 | 7100 | |
| 220 | 定位型玻璃部件 | 01121002258 | 橡胶垫<1> | 1 | fjgn=N1 | | | | | 66181002258 | 7100 | |
| 230 | 定位型玻璃部件 | 01140003351 | O型圈 | 1 | fjgn=N1 | | | | | 66220003351 | 7100 | |
| 240 | 定位型玻璃部件 | 01140003353 | O型圈 | 1 | fjgn=N1 | | | | | 66220003353 | 7100 | |
| 250 | 衬圈 | 01121002271 | 衬圈 | 1 | | | 衬圈 | | | 66181002271 | 7100 | |
| 260 | 表壳螺钉 | 01140002660 | 表壳螺钉 | 3 | | | | | | 260 | | |
| 270 | 罩壳螺钉 | 01140002701 | 罩壳螺钉 | 2 | | | | | | 270 | | |
| 280 | 铅封螺钉 | 01081008107 | 铅封螺钉 | 1 | | | | | | 66051008107 | | |
| 290 | 表盘螺钉 | 01140002695 | 表盘螺钉 | 2 | | | | | | 290 | | |
| 300 | 盘止钉 | 01081005277 | 盘止钉 | 1 | lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11 OR lcfw=M12 OR lcfw=M13 OR lcfw=M14 OR lcfw=M15 OR lcfw=M16 OR lcfw=M30 | | | | | 300 | | |
| 310 | 接头部件 | 01011019173 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND (lcfw=M01 OR lcfw=K78) AND gclj=M20 | | 部件 | | | 66021019173 | 7200 | |
| 320 | 接头部件 | 01011019174 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M02 AND gclj=M20 | | 部件 | | | 66021019174 | 7200 | |
| 330 | 接头部件 | 01011019175 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M03 AND gclj=M20 | | 部件 | | | 66021019175 | 7200 | |
| 340 | 接头部件 | 01011019176 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M04 AND gclj=M20 | | 部件 | | | 66021019176 | 7200 | |
| 350 | 接头部件 | 01011019177 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M05 AND gclj=M20 | | 部件 | | | 66021019177 | 7200 | |
| 360 | 接头部件 | 01011019178 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M06 AND gclj=M20 | | 部件 | | | 66021019178 | 7200 | |
| 370 | 接头部件 | 01011019179 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M07 AND gclj=M20 | | 部件 | | | 66021019179 | 7200 | |
| 380 | 接头部件 | 01011019180 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M08 AND gclj=M20 | | 部件 | | | 66021019180 | 7200 | |
| 390 | 接头部件 | 01011019181 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M09 AND gclj=M20 | | 部件 | | | 66021019181 | 7200 | |
| 400 | 接头部件 | 01011019182 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M10 AND gclj=M20 | | 部件 | | | 66021019182 | 7200 | |
| 410 | 接头部件 | 01011019183 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M11 AND gclj=M20 | | 部件 | | | 66021019183 | 7200 | |
| 420 | 接头部件 | 01011019184 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M12 AND gclj=M20 | | 部件 | | | 66021019184 | 7200 | |
| 430 | 接头部件 | 01011019185 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M13 AND gclj=M20 | | 部件 | | | 66021019185 | 7200 | |
| 440 | 接头部件 | 01011019186 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M14 AND gclj=M20 | | 部件 | | | 66021019186 | 7200 | |
| 450 | 接头部件 | 01011019187 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M15 AND gclj=M20 | | 部件 | | | 66021019187 | 7200 | |
| 460 | 接头部件 | 01011019188 | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M16 AND gclj=M20 | | 部件 | | | 66021019188 | 7200 | |
| 470 | 接头部件 | 01011019189 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND (lcfw=M02 OR lcfw=K107) AND gclj=M20 | | 部件 | | | 66021019189 | 7200 | |
| 480 | 接头部件 | 01011019190 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M03 AND gclj=M20 | | 部件 | | | 66021019190 | 7200 | |
| 490 | 接头部件 | 01011019191 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M04 AND gclj=M20 | | 部件 | | | 66021019191 | 7200 | |
| 500 | 接头部件 | 01011019192 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M05 AND gclj=M20 | | 部件 | | | 66021019192 | 7200 | |
| 510 | 接头部件 | 01011019193 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M06 AND gclj=M20 | | 部件 | | | 66021019193 | 7200 | |
| 520 | 接头部件 | 01011019194 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M07 AND gclj=M20 | | 部件 | | | 66021019194 | 7200 | |
| 530 | 接头部件 | 01011019195 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M08 AND gclj=M20 | | 部件 | | | 66021019195 | 7200 | |
| 540 | 接头部件 | 01011019196 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M09 AND gclj=M20 | | 部件 | | | 66021019196 | 7200 | |
| 550 | 接头部件 | 01011019197 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M10 AND gclj=M20 | | 部件 | | | 66021019197 | 7200 | |
| 560 | 接头部件 | 01011019198 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M11 AND gclj=M20 | | 部件 | | | 66021019198 | 7200 | |
| 570 | 接头部件 | 01011019199 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M12 AND gclj=M20 | | 部件 | | | 66021019199 | 7200 | |
| 580 | 接头部件 | 01011019200 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M13 AND gclj=M20 | | 部件 | | | 66021019200 | 7200 | |
| 590 | 接头部件 | 01011019201 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M14 AND gclj=M20 | | 部件 | | | 66021019201 | 7200 | |
| 600 | 接头部件 | 01011019172 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M15 AND gclj=M20 | | | | | 66021019172 | 7200 | 删除 |
| 610 | 接头部件 | 01011019202 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M01 AND gclj=M20 | | 部件 | | | 66021019202 | 7200 | |
| 620 | 接头部件 | 01011019203 | 轴向部件 | 1 | (azxs=B0 OR azxs=BT) AND lcfw=M16 AND gclj=M20 | | 部件 | | | 66021019203 | 7200 | |
| 630 | 接头 | 01081013687 | 径向低压接头 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND gclj=M14 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11 ) | | 接头 | 部件 | | 66051013687 | 7200 | |
| 640 | 接头 | 01081013686 | 径向低压接头 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND gclj=Z14 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11) | | 接头 | 部件 | | 66051013686 | 7200 | |
| 650 | 接头 | 01081013685 | 径向低压接头 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND gclj=G14 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11) | | 接头 | 部件 | | 66051013685 | 7200 | |
| 660 | 接头 | 01081013684 | 径向低压接头 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND gclj=G12 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11) | | 接头 | 部件 | | 66051013684 | 7200 | |
| 670 | 接头 | 01081013683 | 径向低压接头 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND gclj=G38 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11) | | 接头 | 部件 | | 66051013683 | 7200 | |
| 680 | 接头 | 01081013682 | 径向低压接头 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND gclj=R12 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11) | | 接头 | 部件 | | 66051013682 | 7200 | |
| 690 | 接头 | 01081013681 | 径向低压接头 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND gclj=Z12 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11) | | 接头 | 部件 | | 66051013681 | 7200 | |
| 700 | 接头 | 01081014361 | 径向高压接头 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND gclj=Z14 AND (lcfw=M12 OR lcfw=M13 OR lcfw=M14 OR lcfw=M15 OR lcfw=M16) | | 接头 | 部件 | | 66码缺失 | 7200 | |
| 710 | 接头 | 01081013694 | 径向高压接头 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND gclj=G12 AND (lcfw=M12 OR lcfw=M13 OR lcfw=M14 OR lcfw=M15 OR lcfw=M16) | | 接头 | 部件 | | 66051013694 | 7200 | |
| 720 | 接头 | 01081013692 | 径向高压接头 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND gclj=M14 AND (lcfw=M12 OR lcfw=M13 OR lcfw=M14 OR lcfw=M15 OR lcfw=M16) | | 接头 | 部件 | | 66051013692 | 7200 | |
| 730 | 接头 | 01081013691 | 径向高压接头 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND gclj=R12 AND (lcfw=M12 OR lcfw=M13 OR lcfw=M14 OR lcfw=M15 OR lcfw=M16) | | 接头 | 部件 | | 66051013691 | 7200 | |
| 740 | 接头 | 01081013690 | 径向高压接头 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND gclj=Z12 AND (lcfw=M12 OR lcfw=M13 OR lcfw=M14 OR lcfw=M15 OR lcfw=M16) | | 接头 | 部件 | | 66051013690 | 7200 | |
| 750 | 接头 | 01081013702 | 下轴向低压接头 | 1 | (azxs=B0 OR azxs=BT) AND gclj=R12 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11 OR lcfw=K107 ) | | 接头 | 部件 | | 66051013702 | 7200 | |
| 760 | 接头 | 01081013701 | 下轴向低压接头 | 1 | (azxs=B0 OR azxs=BT) AND gclj=M14 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11 OR lcfw=K107) | | 接头 | 部件 | | 66051013701 | 7200 | |
| 770 | 接头 | 01081013700 | 下轴向低压接头 | 1 | (azxs=B0 OR azxs=BT) AND gclj=Z12 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11 OR lcfw=K107) | | 接头 | 部件 | | 66051013700 | 7200 | |
| 780 | 接头 | 01081013698 | 下轴向低压接头 | 1 | (azxs=B0 OR azxs=BT) AND gclj=G14 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11 OR lcfw=K107) | | 接头 | 部件 | | 66051013698 | 7200 | |
| 790 | 接头 | 01081013697 | 下轴向低压接头 | 1 | (azxs=B0 OR azxs=BT) AND gclj=Z14 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11 OR lcfw=K107) | | 接头 | 部件 | | 66051013697 | 7200 | |
| 800 | 接头 | 01081013696 | 下轴向低压接头 | 1 | (azxs=B0 OR azxs=BT) AND gclj=G12 AND (lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11 OR lcfw=K107) | | 接头 | 部件 | | 66051013696 | 7200 | |
| 810 | 接头 | 01081013709 | 下轴向高压接头 | 1 | (azxs=B0 OR azxs=BT) AND gclj=M14 AND (lcfw=M12 OR lcfw=M13 OR lcfw=M14 OR lcfw=M15 OR lcfw=M16) | | 接头 | 部件 | | 66051013709 | 7200 | |
| 820 | 接头 | 01081013707 | 下轴向高压接头 | 1 | (azxs=B0 OR azxs=BT) AND gclj=G14 AND (lcfw=M12 OR lcfw=M13 OR lcfw=M14 OR lcfw=M15 OR lcfw=M16) | | 接头 | 部件 | | 66051013707 | 7200 | |
| 830 | 接头 | 01081013706 | 下轴向高压接头 | 1 | (azxs=B0 OR azxs=BT) AND gclj=Z14 AND (lcfw=M12 OR lcfw=M13 OR lcfw=M14 OR lcfw=M15 OR lcfw=M16) | | 接头 | 部件 | | 66051013706 | 7200 | |
| 840 | 接头 | 01081013705 | 下轴向高压接头 | 1 | (azxs=B0 OR azxs=BT) AND gclj=G12 AND (lcfw=M12 OR lcfw=M13 OR lcfw=M14 OR lcfw=M15 OR lcfw=M16) | | 接头 | 部件 | | 66051013705 | 7200 | |
| 850 | 接头 | 01081013704 | 下轴向高压接头 | 1 | (azxs=B0 OR azxs=BT) AND gclj=R12 AND (lcfw=M12 OR lcfw=M13 OR lcfw=M14 OR lcfw=M15 OR lcfw=M16) | | 接头 | 部件 | | 66051013704 | 7200 | |
| 860 | 弹性元件 | 01041005171 | 弹簧管 | 1 | lcfw=M01 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005171 | 7200 | |
| 870 | 弹性元件 | 01041005169 | 弹簧管 | 1 | lcfw=M02 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005169 | 7200 | |
| 880 | 弹性元件 | 01041005170 | 弹簧管 | 1 | lcfw=M03 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005170 | 7200 | |
| 890 | 弹性元件 | 01041005453 | 弹簧管 | 1 | lcfw=M04 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005453 | 7200 | |
| 900 | 弹性元件 | 01041005235 | 弹簧管 | 1 | lcfw=M05 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005235 | 7200 | |
| 910 | 弹性元件 | 01041005114 | 弹簧管 | 1 | lcfw=M06 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005114 | 7200 | |
| 920 | 弹性元件 | 01041005230 | 弹簧管 | 1 | lcfw=M07 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005230 | 7200 | |
| 930 | 弹性元件 | 01041005233 | 弹簧管 | 1 | lcfw=M08 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005233 | 7200 | |
| 940 | 弹性元件 | 01041005229 | 弹簧管 | 1 | lcfw=M09 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005229 | 7200 | |
| 950 | 弹性元件 | 01041005172 | 弹簧管 | 1 | lcfw=M10 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005172 | 7200 | |
| 960 | 弹性元件 | 01041005452 | 弹簧管 | 1 | lcfw=M11 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005452 | 7200 | |
| 970 | 弹性元件 | 01041005005 | 螺旋管 | 1 | lcfw=M12 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005005 | 7200 | |
| 980 | 弹性元件 | 01041005006 | 螺旋管 | 1 | lcfw=M13 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005006 | 7200 | |
| 990 | 弹性元件 | 01041005007 | 螺旋管 | 1 | lcfw=M14 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005007 | 7200 | |
| 1000 | 弹性元件 | 01041005008 | 螺旋管 | 1 | lcfw=M15 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005008 | 7200 | |
| 1010 | 弹性元件 | 01041005009 | 螺旋管 | 1 | lcfw=M16 AND gclj!=M20 | | 弹性元件 | 部件 | | 66131005009 | 7200 | |
| 1020 | 封口片 | 01091003680 | 高压封口片 | 1 | (lcfw=M12 OR lcfw=M13 OR lcfw=M14 OR lcfw=M15 OR lcfw=M16)AND gclj!=M20 | | | | | 66071003680 | | |
| 1030 | 封口片 | 01091003663 | 低压封口片 | 1 | (lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11)AND gclj!=M20 | | | | | 66071003663 | | |
| 1040 | 连接螺钉 | 01081008105 | 连接螺钉 | 1 | | | | | | 66051008105 | | |
| 1050 | 垫片 | 01091004354 | 垫片 | 1 | lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11 OR lcfw=K107 | | | | | 66071004354 | | |
| 1060 | 机芯螺钉 | 01140003413 | 机芯螺钉 | 2 | | | | | | 66220003413 | | |
| 1070 | 机芯部件 | 01101000574 | 机芯 | 1 | lcfw=M01 OR lcfw=M02 OR lcfw=M03 OR lcfw=M04 OR lcfw=K107 | | 机芯 | | | 66151000574 | 7100 | 删除 OR lcfw=M12 |
| 1080 | 机芯部件 | 01101000575 | 机芯 | 1 | lcfw=M05 OR lcfw=M06 OR lcfw=M07 OR lcfw=M08 OR lcfw=M09 OR lcfw=M10 OR lcfw=M11 OR lcfw=M13 OR lcfw=M14 OR lcfw=M15 OR lcfw=M16 OR lcfw=M12 | | 机芯 | | | 66151000575 | 7100 | 增加 OR lcfw=M12 |
| 1090 | 接头部件 | | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M05 AND gclj=G12 | | 部件 | | | 66021019206 | 7200 | 新增物料 |
| 1100 | 接头部件 | | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M09 AND gclj=Z12 | | 部件 | | | 66021019212 | 7200 | 新增物料 |
| 1120 | 接头部件 | | 径向部件 | 1 | (azxs=A0 OR azxs=AT OR azxs=AH) AND lcfw=M08 AND gclj=G12 | | 部件 | | | 66021019208 | 7200 | 新增物料 |