From 1c7b1922703c80b6a83eecf148ec775c04ea92d6 Mon Sep 17 00:00:00 2001 From: git_rabbit Date: Tue, 16 Dec 2025 10:42:04 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=AD=90=E9=9B=B6=E4=BB=B6?= =?UTF-8?q?=E7=A0=81=E9=AA=8C=E8=AF=81=E9=80=BB=E8=BE=91=EF=BC=8C=E6=8F=90?= =?UTF-8?q?=E5=8D=87=E5=85=BC=E5=AE=B9=E6=80=A7=E4=B8=8E=E5=81=A5=E5=A3=AE?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将子零件码(摄像头码)验证规则全部下沉至 ScanService 服务层,支持多种日期格式(ddMMyy、ddMMyyyy、yyMMdd)智能提取与判定,统一以日期大于等于 2025-11-01 为合格标准。视图层仅负责调用服务、异常处理和流程控制,提升了代码可维护性和扫码兼容性。完善了异常处理和日志记录,优化用户体验。 --- .../Services/ScanService.cs | 84 ++++++++++++++++++- .../ViewModels/MainWindowViewModel.cs | 60 ++++++++++--- 2 files changed, 133 insertions(+), 11 deletions(-) diff --git a/src/LineTraceabilitySystem/Services/ScanService.cs b/src/LineTraceabilitySystem/Services/ScanService.cs index 1d9556b..9a068c5 100644 --- a/src/LineTraceabilitySystem/Services/ScanService.cs +++ b/src/LineTraceabilitySystem/Services/ScanService.cs @@ -30,7 +30,89 @@ namespace LineTraceabilitySystem.Services public bool ValidateSubPartCode(string code) { - return true; + // 将子零件码的判定规则集中在此处,视图层不再包含具体规则。 + // 新规则: + // 1. 不限制长度 + // 2. 在二维码中提取日期信息,日期小于 2025-11-01 判定为不合格,>= 判定为合格 + // 3. 日期可能以 6 位 (ddMMyy) 或 8 位 (ddMMyyyy) 等形式存在,解析应具备较高兼容性,避免简单的固定位置截取 + if (string.IsNullOrWhiteSpace(code)) + { + return false; + } + + code = code.Trim(); + + // 优先尝试在整个字符串中查找 6 或 8 位连续数字序列作为候选日期字段 + // 使用正则以提高兼容性(避免基于固定下标截取) + try + { + var matches = System.Text.RegularExpressions.Regex.Matches(code, "\\d{6,8}"); + var threshold = new DateTime(2025, 11, 1); + + foreach (System.Text.RegularExpressions.Match m in matches) + { + var seq = m.Value; + + // 优先尝试 ddMMyyyy (8 位) + if (seq.Length == 8) + { + if (int.TryParse(seq.Substring(0, 2), out var dd) + && int.TryParse(seq.Substring(2, 2), out var MM) + && int.TryParse(seq.Substring(4, 4), out var yyyy)) + { + if (IsValidDate(yyyy, MM, dd, threshold)) + return true; + } + } + + // 兼容 6 位形式,通常为 ddMMyy(例:261125 表示 26-11-25 -> 2025-11-26) + if (seq.Length == 6) + { + if (int.TryParse(seq.Substring(0, 2), out var dd) + && int.TryParse(seq.Substring(2, 2), out var MM) + && int.TryParse(seq.Substring(4, 2), out var yy)) + { + var yyyy = 2000 + yy; // 以 2000 年为基准 + if (IsValidDate(yyyy, MM, dd, threshold)) + return true; + } + // 兼容性扩展:如果 6 位不能按 ddMMyy 解析,通过 yyMMdd 尝试解析 + if (int.TryParse(seq.Substring(0, 2), out var alt1) + && int.TryParse(seq.Substring(2, 2), out var alt2) + && int.TryParse(seq.Substring(4, 2), out var alt3)) + { + // 尝试 yyMMdd -> year = 2000 + alt1, month=alt2, day=alt3 + var yyyy = 2000 + alt1; + if (IsValidDate(yyyy, alt2, alt3, threshold)) + return true; + } + } + } + } + catch + { + // 解析异常视为不合格 + return false; + } + + // 未找到满足条件的日期序列,判定为不合格 + return false; + } + + /// + /// 判断指定年月日是否合法并且大于等于阈值日期 + /// + private static bool IsValidDate(int year, int month, int day, DateTime threshold) + { + try + { + var dt = new DateTime(year, month, day); + return dt >= threshold; + } + catch + { + return false; + } } public bool ValidateTraceabilityCode(string code) diff --git a/src/LineTraceabilitySystem/ViewModels/MainWindowViewModel.cs b/src/LineTraceabilitySystem/ViewModels/MainWindowViewModel.cs index 7a2ef7b..06c6907 100644 --- a/src/LineTraceabilitySystem/ViewModels/MainWindowViewModel.cs +++ b/src/LineTraceabilitySystem/ViewModels/MainWindowViewModel.cs @@ -602,46 +602,86 @@ namespace LineTraceabilitySystem.ViewModels } /// - /// 处理摄像头码扫描事件 + /// 处理摄像头码扫描事件(异步)。 + /// 验证规则已全部封装到 `IScanService.ValidateSubPartCode` 中,视图层只负责调用、展示状态与流程控制。 /// /// 扫描到的摄像头码 private async Task OnSubPartCodeScannedAsync(string code) { + // 当前子件名称(供后续上传使用) string partCodeScanName = _scanList[CurrentStep]; + + // 记录扫码结果到视图模型以便绑定更新 SubPartScanCode = code; - // 验证摄像头码逻辑 - 注意:ITraceMainService中可能没有VerifySubPartScanCode方法 - // 以下代码需要根据实际ITraceMainService接口定义进行调整 - bool isSubPartScanCodeValid = code.Contains("2F1980546#")&& code.Length==31 && _scanService.ValidateSubPartCode(code); + + bool isSubPartScanCodeValid; + try + { + // 将所有判定逻辑放到扫描服务中,此处仅调用并捕获可能的异常 + isSubPartScanCodeValid = _scanService.ValidateSubPartCode(code); + } + catch (Exception ex) + { + // 服务验证出现异常,记录并提示,视为验证失败 + AddToOperationHistory($"验证子零件码异常: {ex.Message}"); + _alertService.ShowError("验证子零件码时发生错误,请检查日志"); + isSubPartScanCodeValid = false; + } + + // 更新状态显示 SubPartScanCodeStatus = isSubPartScanCodeValid ? "OK" : "NG"; SubPartScanCodeStatusColor = isSubPartScanCodeValid ? Brushes.Green : Brushes.Red; + if (!isSubPartScanCodeValid) { + // 验证不通过,更新UI状态并记录日志,结束本次扫描流程 ScanResult = "NG"; IsScanOk = false; + AddToOperationHistory($"扫描摄像头码: {code}, 状态: {SubPartScanCodeStatus}"); _alertService.ShowWarning("不是有效的码"); return; } + + // 验证通过 + ScanResult = "OK"; + IsScanOk = true; AddToOperationHistory($"扫描摄像头码: {code}, 状态: {SubPartScanCodeStatus}"); + + // 进入下一步 CurrentStep += 1; - if (CurrentStep == _scanList.Count) + // 判断是否已完成所有待扫项。如果完成,触发PLC相关写入并进入上传步骤。 + if (CurrentStep >= _scanList.Count) { - Debug.WriteLine($"追溯数据上传服务器"); - AddToOperationHistory($"追溯数据上传服务器"); - TagServer tagServer = HostManager.GetTagServerByIp(PLCIP); - if (CheckTagNameValid(tagServer, ScrewGunEnable)) + AddToOperationHistory("追溯数据准备上传(所有子件已扫)"); + try { - tagServer.WriteIntSingle(tagCommon.TagAddress, 1); + TagServer tagServer = HostManager.GetTagServerByIp(PLCIP); + if (CheckTagNameValid(tagServer, ScrewGunEnable)) + { + // 通知PLC启用拧紧枪或触发拍照 + tagServer.WriteIntSingle(tagCommon.TagAddress, 1); + } } + catch (Exception ex) + { + AddToOperationHistory($"向PLC写入触发位失败: {ex.Message}"); + } + + // 使用特殊值表示上传阶段 CurrentStep = 1000; } + + // 上传阶段 if (CurrentStep == 1000) { await OnUploadScanned(SubPartScanCode, partCodeScanName); + // 重置流程,准备下一个追溯件 Initialize(); } else { + // 更新提示文本,等待下一个扫码 CurrentStepText = $"请扫{_scanList[CurrentStep]}码"; } }