using Microsoft.Extensions.Logging; using RIZO.Model.Mes.Scanner; using RIZO.Service.Mes.IMesService.Scanner; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace RIZO.Service.Mes.Scanner { public class ScannerService : IScannerService, IDisposable { private readonly ILogger _logger; private SerialPort? _serialPort; private ScannerConfig _config = new(); private bool _isInitialized = false; public bool IsConnected => _serialPort?.IsOpen == true; // 事件定义 public event EventHandler? OnScanDataReceived; public event EventHandler? OnScannerError; public ScannerService(ILogger logger) { _logger = logger; } public async Task InitializeAsync(ScannerConfig config) { try { _config = config; await Task.Run(() => { _serialPort = new SerialPort( _config.PortName, _config.BaudRate, ParseParity(_config.Parity), _config.DataBits, ParseStopBits(_config.StopBits)) { Encoding = System.Text.Encoding.UTF8, ReadTimeout = 1000, WriteTimeout = 1000 }; _serialPort.DataReceived += SerialPort_DataReceived; }); _isInitialized = true; _logger.LogInformation($"扫码服务初始化成功 - 端口:{_config.PortName} 波特率:{_config.BaudRate}"); return true; } catch (Exception ex) { _logger.LogError(ex, "扫码服务初始化失败"); OnScannerError?.Invoke(this, $"初始化失败: {ex.Message}"); return false; } } public async Task StartAsync() { if (!_isInitialized || _serialPort == null) { OnScannerError?.Invoke(this, "扫码服务未初始化"); return false; } try { if (!_serialPort.IsOpen) { await Task.Run(() => _serialPort.Open()); _logger.LogInformation("串口扫码枪启动成功"); } return true; } catch (Exception ex) { _logger.LogError(ex, "启动串口扫码枪失败"); OnScannerError?.Invoke(this, $"启动失败: {ex.Message}"); return false; } } public async Task StopAsync() { if (_serialPort?.IsOpen == true) { await Task.Run(() => _serialPort.Close()); _logger.LogInformation("串口扫码枪已停止"); } return true; } /// /// 串口数据接收事件处理 /// private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { try { if (sender is SerialPort sp) { string scannedData = sp.ReadExisting().Trim(); if (!string.IsNullOrEmpty(scannedData)) { _logger.LogInformation($"接收到扫码数据: {scannedData}"); // 异步处理扫码数据 _ = Task.Run(async () => { var result = await ProcessScanCodeAsync(scannedData); if (result.Success && result.Data != null) { OnScanDataReceived?.Invoke(this, result.Data); } }); } } } catch (Exception ex) { _logger.LogError(ex, "处理扫码数据时发生错误"); OnScannerError?.Invoke(this, $"数据处理错误: {ex.Message}"); } } /// /// 处理扫码数据业务逻辑 /// public async Task ProcessScanCodeAsync(string scanCode) { try { _logger.LogInformation($"开始处理扫码数据: {scanCode}"); var scanData = new ScanData { Code = scanCode.ToUpper(), ScanTime = DateTime.Now }; // ============ 业务逻辑判断 ============ // 判断是否为产品条码(根据你的业务规则修改) if (IsProductCode(scanCode)) { scanData.CodeType = "Product"; await ProcessProductCodeAsync(scanData); } // 判断是否为物料条码 else if (IsMaterialCode(scanCode)) { scanData.CodeType = "Material"; await ProcessMaterialCodeAsync(scanData); } // 判断是否为追溯码 else if (IsTraceCode(scanCode)) { scanData.CodeType = "Trace"; await ProcessTraceCodeAsync(scanData); } else { scanData.CodeType = "Unknown"; scanData.IsValid = false; scanData.ErrorMessage = "未知条码类型"; await ProcessUnknownCodeAsync(scanData); } return new ScanResult { Success = scanData.IsValid, Message = scanData.IsValid ? "处理成功" : scanData.ErrorMessage, Data = scanData }; } catch (Exception ex) { _logger.LogError(ex, $"处理扫码数据时发生错误: {scanCode}"); return new ScanResult { Success = false, Message = $"处理失败: {ex.Message}" }; } } #region 业务逻辑方法 - 根据你的需求修改这些方法 private bool IsProductCode(string code) { // 根据你的业务规则判断是否为产品条码 return code.Length == 20 || code.StartsWith("P") || code.StartsWith("PROD"); } private bool IsMaterialCode(string code) { // 根据你的业务规则判断是否为物料条码 return code.Length == 15 || code.StartsWith("M") || code.StartsWith("MAT"); } private bool IsTraceCode(string code) { // 根据你的业务规则判断是否为追溯码 return code.Contains("TRACE") || code.Contains(GetCurrentLineName()); } private async Task ProcessProductCodeAsync(ScanData scanData) { _logger.LogInformation($"处理产品条码: {scanData.Code}"); // 这里实现产品条码处理逻辑 // 例如:更新数据库、与PLC通信、更新界面等 // 模拟异步处理 await Task.Delay(10); // 示例:更新全局状态 // global.ScanCode = scanData.Code; } private async Task ProcessMaterialCodeAsync(ScanData scanData) { _logger.LogInformation($"处理物料条码: {scanData.Code}"); // 这里实现物料条码处理逻辑 await Task.Delay(10); } private async Task ProcessTraceCodeAsync(ScanData scanData) { _logger.LogInformation($"处理追溯码: {scanData.Code}"); // 这里实现追溯码处理逻辑 await Task.Delay(10); } private async Task ProcessUnknownCodeAsync(ScanData scanData) { _logger.LogWarning($"未知条码类型: {scanData.Code}"); // 处理未知条码 await Task.Delay(10); } private string GetCurrentLineName() { // 返回当前生产线名称,根据你的业务逻辑实现 return "LINE001"; } #endregion #region 辅助方法 private Parity ParseParity(string parity) { return parity.ToUpper() switch { "N" or "NONE" => Parity.None, "E" or "EVEN" => Parity.Even, "O" or "ODD" => Parity.Odd, "M" or "MARK" => Parity.Mark, "S" or "SPACE" => Parity.Space, _ => Parity.None }; } private StopBits ParseStopBits(string stopBits) { return stopBits.ToUpper() switch { "1" or "ONE" => StopBits.One, "1.5" or "ONEPOINTFIVE" => StopBits.OnePointFive, "2" or "TWO" => StopBits.Two, _ => StopBits.One }; } public void Dispose() { _serialPort?.Close(); _serialPort?.Dispose(); _logger.LogInformation("扫码服务资源已释放"); } #endregion } }