All checks were successful
NTFY Notification / notify (push) Successful in 12s
Replace "原表行号" (original row number) field with "生产订单号" (production order number) in BOM Extraction System error reporting to improve traceability. Changes: - clsErrorLogger: Update Record/RecordWarning signatures to accept OrderNo (String) instead of RowIndex (Long) - M09_BOMExtractor: Propagate productionOrderNo through validation chain for context-aware error reporting - M06/M07/M08: Use empty string for system-level errors without production order context - Error report header: Change column B from "原表行号" to "生产订单号" Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
335 lines
11 KiB
QBasic
335 lines
11 KiB
QBasic
' ==============================================================================
|
||
' 模块: M06_ModelParser
|
||
' 职责: 产品型号解析,从完整产品型号中提取关键参数
|
||
'
|
||
' 产品型号结构: [表头]|[表盘]|[附件]|[法兰隔膜]
|
||
' 表头结构: [型号]-[公称外径].[安装形式].[壳体形式].[过程连接&接液材质].[量程范围].[仪表特性]
|
||
'
|
||
' 示例: YTHN-100.A0.531.G123.M04.Y3|BP-088.2312.B09.0A3
|
||
' 表头: YTHN-100.A0.531.G123.M04.Y3
|
||
' azxs: A0, bkxs: 531, gclj: G12, jycz: 3, lcfw: M04, fjgn: Y3
|
||
'
|
||
' 注意: 仅处理表头部分,其他部分(表盘、附件、法兰隔膜)暂时丢弃
|
||
' ==============================================================================
|
||
Option Explicit
|
||
|
||
' 模块级变量 - 错误记录器
|
||
Private g_Logger As clsErrorLogger
|
||
|
||
' ------------------------------------------------------------------------------
|
||
' 初始化型号解析器
|
||
' ------------------------------------------------------------------------------
|
||
Public Sub InitModelParser(logger As clsErrorLogger)
|
||
Set g_Logger = logger
|
||
End Sub
|
||
|
||
' ------------------------------------------------------------------------------
|
||
' 主入口: 解析产品型号
|
||
'
|
||
' 输入:
|
||
' modelString - 完整的产品型号字符串
|
||
'
|
||
' 输出:
|
||
' Object (Scripting.Dictionary) - 包含提取的参数
|
||
' 键值对: "xh"->型号, "gcwj"->公称外径, "azxs"->安装形式,
|
||
' "bkxs"->表壳形式, "gclj"->过程连接, "jycz"->接液材质,
|
||
' "lcfw"->量程范围, "fjgn"->附加功能
|
||
'
|
||
' 示例:
|
||
' Set params = ParseProductModel("YTHN-100.A0.531.G123.M04.Y3|BP-088.2312.B09.0A3")
|
||
' ' params("azxs") = "A0"
|
||
' ' params("gclj") = "G12"
|
||
' ' params("jycz") = "3"
|
||
' ------------------------------------------------------------------------------
|
||
Public Function ParseProductModel(ByVal modelString As String) As Object
|
||
On Error GoTo ErrorHandler
|
||
|
||
Dim params As Object
|
||
Set params = CreateObject("Scripting.Dictionary")
|
||
|
||
' 预处理:去除前后空格
|
||
modelString = Trim(modelString)
|
||
|
||
' 如果型号为空,返回空字典
|
||
If Len(modelString) = 0 Then
|
||
Set ParseProductModel = params
|
||
Exit Function
|
||
End If
|
||
|
||
' 步骤1: 提取表头部分(第一个管道符之前的部分)
|
||
Dim headerPart As String
|
||
headerPart = ExtractHeaderPart(modelString)
|
||
|
||
If Len(headerPart) = 0 Then
|
||
If Not g_Logger Is Nothing Then
|
||
g_Logger.Record "", "M06.ParseProductModel", "ModelParseError", _
|
||
"无法提取表头部分,型号可能为空或格式错误", modelString
|
||
End If
|
||
Set ParseProductModel = params
|
||
Exit Function
|
||
End If
|
||
|
||
' 步骤2: 分割表头为段
|
||
Dim segments As Variant
|
||
segments = SplitHeaderPart(headerPart)
|
||
|
||
If Not IsArray(segments) Then
|
||
If Not g_Logger Is Nothing Then
|
||
g_Logger.Record "", "M06.ParseProductModel", "ModelParseError", _
|
||
"表头分割失败", headerPart
|
||
End If
|
||
Set ParseProductModel = params
|
||
Exit Function
|
||
End If
|
||
|
||
' 步骤3: 验证段数是否足够
|
||
If UBound(segments) - LBound(segments) + 1 < MODEL_HEADER_MIN_SEGMENTS Then
|
||
If Not g_Logger Is Nothing Then
|
||
g_Logger.Record "", "M06.ParseProductModel", "ModelParseError", _
|
||
"表头段数不足,需要至少" & MODEL_HEADER_MIN_SEGMENTS & "段,实际" & _
|
||
(UBound(segments) - LBound(segments) + 1) & "段", headerPart
|
||
End If
|
||
End If
|
||
|
||
' 步骤4: 提取型号和公称外径(预留,暂不参与BOM匹配)
|
||
Call ExtractModelAndSize(headerPart, params)
|
||
|
||
' 步骤5: 提取各参数
|
||
' 注意:segments(0)是"型号-公称外径",需要从segments(1)开始提取参数
|
||
|
||
' 提取原始值
|
||
Dim azxsRaw As String, bkxsRaw As String
|
||
Dim gcljRaw As String, jyczRaw As String
|
||
Dim lcfwRaw As String, fjgnRaw As String
|
||
|
||
If UBound(segments) - LBound(segments) + 1 >= 2 Then
|
||
azxsRaw = ExtractAzxs(segments(1))
|
||
End If
|
||
|
||
If UBound(segments) - LBound(segments) + 1 >= 3 Then
|
||
bkxsRaw = ExtractBkxs(segments(2))
|
||
End If
|
||
|
||
If UBound(segments) - LBound(segments) + 1 >= 4 Then
|
||
Call ExtractGcljAndJycz(segments(3), gcljRaw, jyczRaw)
|
||
End If
|
||
|
||
If UBound(segments) - LBound(segments) + 1 >= 5 Then
|
||
lcfwRaw = ExtractLcfw(segments(4))
|
||
End If
|
||
|
||
If UBound(segments) - LBound(segments) + 1 >= 6 Then
|
||
fjgnRaw = ExtractFjgn(segments, 5)
|
||
End If
|
||
|
||
' 步骤6: 应用映射(如果映射器已初始化)
|
||
If M06A_Mapper.IsInitialized() Then
|
||
' 应用azxs和lcfw映射,返回双值格式(raw,mapped)
|
||
If Len(azxsRaw) > 0 Then
|
||
params("azxs") = M06A_Mapper.MapAzxs(azxsRaw)
|
||
End If
|
||
If Len(lcfwRaw) > 0 Then
|
||
params("lcfw") = M06A_Mapper.MapLcfw(lcfwRaw)
|
||
End If
|
||
Else
|
||
' 映射器未初始化,使用原始值
|
||
If Len(azxsRaw) > 0 Then
|
||
params("azxs") = azxsRaw
|
||
End If
|
||
If Len(lcfwRaw) > 0 Then
|
||
params("lcfw") = lcfwRaw
|
||
End If
|
||
End If
|
||
|
||
' 添加其他参数(不需要映射)
|
||
If Len(bkxsRaw) > 0 Then
|
||
params("bkxs") = bkxsRaw
|
||
End If
|
||
If Len(gcljRaw) > 0 Then
|
||
params("gclj") = gcljRaw
|
||
End If
|
||
If Len(jyczRaw) > 0 Then
|
||
params("jycz") = jyczRaw
|
||
End If
|
||
If Len(fjgnRaw) > 0 Then
|
||
params("fjgn") = fjgnRaw
|
||
End If
|
||
|
||
Set ParseProductModel = params
|
||
Exit Function
|
||
|
||
ErrorHandler:
|
||
If Not g_Logger Is Nothing Then
|
||
g_Logger.Record "", "M06.ParseProductModel", "SystemError", _
|
||
"解析过程发生错误: " & Err.Description, modelString
|
||
End If
|
||
Set ParseProductModel = CreateObject("Scripting.Dictionary")
|
||
End Function
|
||
|
||
' ------------------------------------------------------------------------------
|
||
' 提取表头部分(管道符之前)
|
||
'
|
||
' 输入: YTHN-100.A0.531.G123.M04.Y3|BP-088.2312.B09.0A3
|
||
' 输出: YTHN-100.A0.531.G123.M04.Y3
|
||
' ------------------------------------------------------------------------------
|
||
Private Function ExtractHeaderPart(ByVal fullModel As String) As String
|
||
Dim pipePos As Long
|
||
pipePos = InStr(fullModel, MODEL_SEPARATOR_PIPELINE)
|
||
|
||
If pipePos > 0 Then
|
||
ExtractHeaderPart = Left(fullModel, pipePos - 1)
|
||
Else
|
||
ExtractHeaderPart = fullModel
|
||
End If
|
||
End Function
|
||
|
||
' ------------------------------------------------------------------------------
|
||
' 分割表头部分为段数组
|
||
'
|
||
' 输入: YTHN-100.A0.531.G123.M04.Y3
|
||
' 输出: Array("YTHN-100", "A0", "531", "G123", "M04", "Y3")
|
||
' ------------------------------------------------------------------------------
|
||
Private Function SplitHeaderPart(ByVal headerPart As String) As Variant
|
||
' 按点号分割
|
||
Dim rawSegments As Variant
|
||
rawSegments = Split(headerPart, MODEL_SEPARATOR_DOT)
|
||
|
||
' 如果分割失败或结果为空
|
||
If Not IsArray(rawSegments) Then
|
||
SplitHeaderPart = Null
|
||
Exit Function
|
||
End If
|
||
|
||
' 去除每个段的空格
|
||
Dim i As Long
|
||
For i = LBound(rawSegments) To UBound(rawSegments)
|
||
rawSegments(i) = Trim(CStr(rawSegments(i)))
|
||
Next i
|
||
|
||
SplitHeaderPart = rawSegments
|
||
End Function
|
||
|
||
' ------------------------------------------------------------------------------
|
||
' 提取型号和公称外径(预留字段)
|
||
'
|
||
' 输入: YTHN-100
|
||
' 输出: params("xh")="YTHN", params("gcwj")="100"
|
||
' ------------------------------------------------------------------------------
|
||
Private Sub ExtractModelAndSize(ByVal firstSegment As String, ByRef params As Object)
|
||
Dim dashPos As Long
|
||
dashPos = InStr(firstSegment, "-")
|
||
|
||
If dashPos > 1 Then
|
||
params("xh") = Left(firstSegment, dashPos - 1)
|
||
Dim afterDash As String
|
||
afterDash = Mid(firstSegment, dashPos + 1)
|
||
|
||
' 提取-号后的数字部分(公称外径)
|
||
' 因为firstSegment是"YTHN-100.A0...",需要去掉后面的点号内容
|
||
Dim dotPos As Long
|
||
dotPos = InStr(afterDash, ".")
|
||
If dotPos > 0 Then
|
||
params("gcwj") = Left(afterDash, dotPos - 1)
|
||
Else
|
||
params("gcwj") = afterDash
|
||
End If
|
||
End If
|
||
End Sub
|
||
|
||
' ------------------------------------------------------------------------------
|
||
' 提取安装形式
|
||
'
|
||
' 输入: A0
|
||
' 输出: A0
|
||
'
|
||
' 规则: 直接返回第一段的值
|
||
' ------------------------------------------------------------------------------
|
||
Private Function ExtractAzxs(ByVal segment As String) As String
|
||
ExtractAzxs = Trim(segment)
|
||
End Function
|
||
|
||
' ------------------------------------------------------------------------------
|
||
' 提取表壳形式
|
||
'
|
||
' 输入: 531
|
||
' 输出: 531
|
||
'
|
||
' 规则: 直接返回第二段的值
|
||
' ------------------------------------------------------------------------------
|
||
Private Function ExtractBkxs(ByVal segment As String) As String
|
||
ExtractBkxs = Trim(segment)
|
||
End Function
|
||
|
||
' ------------------------------------------------------------------------------
|
||
' 提取过程连接和接液材质
|
||
'
|
||
' 输入: G123
|
||
' 输出: gclj="G12", jycz="3"
|
||
'
|
||
' 规则:
|
||
' - 过程连接: 去除最后一位
|
||
' - 接液材质: 最后一位
|
||
' ------------------------------------------------------------------------------
|
||
Private Sub ExtractGcljAndJycz(ByVal segment As String, ByRef gclj As String, ByRef jycz As String)
|
||
segment = Trim(segment)
|
||
|
||
If Len(segment) >= 1 Then
|
||
jycz = Right(segment, 1)
|
||
If Len(segment) > 1 Then
|
||
gclj = Left(segment, Len(segment) - 1)
|
||
Else
|
||
gclj = ""
|
||
End If
|
||
Else
|
||
gclj = ""
|
||
jycz = ""
|
||
End If
|
||
End Sub
|
||
|
||
' ------------------------------------------------------------------------------
|
||
' 提取量程范围
|
||
'
|
||
' 输入: M04
|
||
' 输出: M04
|
||
'
|
||
' 规则: 直接返回第四段的值
|
||
' ------------------------------------------------------------------------------
|
||
Private Function ExtractLcfw(ByVal segment As String) As String
|
||
ExtractLcfw = Trim(segment)
|
||
End Function
|
||
|
||
' ------------------------------------------------------------------------------
|
||
' 提取附加功能
|
||
'
|
||
' 输入: segments数组,起始索引为4
|
||
' 输出: Y3 或 N1,N2 或 N1.N2
|
||
'
|
||
' 规则:
|
||
' - 从第五段开始,所有段合并为附加功能
|
||
' - 用逗号或点号分隔的多个功能,保留原分隔符
|
||
' - 示例: Y3 -> Y3
|
||
' - 示例: N1,N2.Y3 -> N1,N2,Y3
|
||
' ------------------------------------------------------------------------------
|
||
Private Function ExtractFjgn(ByRef segments As Variant, ByVal startIndex As Long) As String
|
||
Dim result As String
|
||
result = ""
|
||
|
||
Dim i As Long
|
||
For i = startIndex To UBound(segments)
|
||
Dim segment As String
|
||
segment = Trim(CStr(segments(i)))
|
||
|
||
If Len(segment) > 0 Then
|
||
' 替换点号为逗号(统一分隔符)
|
||
segment = Replace(segment, MODEL_SEPARATOR_DOT, ",")
|
||
|
||
If Len(result) > 0 Then
|
||
result = result & "," & segment
|
||
Else
|
||
result = segment
|
||
End If
|
||
End If
|
||
Next i
|
||
|
||
ExtractFjgn = result
|
||
End Function |