From 058c8149e866d332d5b1c5b9aaca5b7b725645a4 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 15 Aug 2025 17:34:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=BB=88=E7=AB=AF=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StartDeviceRuntimeCommandHandler.cs | 4 +- .../StopDeviceRuntimeCommandHandler.cs | 4 +- .../CreateDeviceCommandHandler.cs | 4 +- .../CreateTerminalDeviceCommand.cs | 2 + .../CreateTerminalDeviceCommandHandler.cs | 159 +++-- .../CreateTerminalDeviceResponse.cs | 5 + .../UpdateTerminalDeviceCommand.cs | 20 - .../UpdateTerminalDeviceCommandHandler.cs | 41 +- .../UpdateTerminalDeviceResponse.cs | 5 + .../GetTerminalDeviceByIdQueryHandler.cs | 2 +- .../GetTerminalDeviceByIdResponse.cs | 10 +- .../GetTerminalDevicesQueryHandler.cs | 2 +- .../GetTerminalDevicesResponse.cs | 10 +- .../DeviceManagementService.cs | 4 +- src/X1.Domain/DependencyInjection.cs | 19 - .../Entities/Terminal/TerminalDevice.cs | 28 + .../Entities/Terminal/TerminalDeviceType.cs | 17 + .../IBaseInstrumentClient.cs | 4 +- .../IInstrumentHttpClient.cs | 2 +- .../IInstrumentProtocolClient.cs | 4 +- .../IServiceEndpointManager.cs | 4 +- .../ITerminal/IADBOperationTerminalClient.cs | 15 + .../ITerminal/IATOperationTerminalClient.cs | 13 + .../ITerminal/IBaseTerminalClient.cs | 26 + .../ITerminal/ITerminalHttpClient.cs | 13 + .../Models/ApiActionResult.cs | 2 +- .../Models/CellularNetworkConfiguration.cs | 2 +- .../Models/CellularNetworkRequest.cs | 2 +- .../Models/CircuitBreakerOptions.cs | 2 +- .../Models/DeviceInfoResponse.cs | 2 +- .../Models/DynamicHttpClientException.cs | 2 +- .../Models/HttpRequestOptions.cs | 2 +- .../Models/ServiceEndpoint.cs | 2 +- .../Models/TestTerminalResponse.cs | 55 ++ .../Core/DynamicHttpClient.Core.cs | 2 +- .../Core/DynamicHttpClient.Sync.cs | 2 +- .../Core/DynamicHttpClient.SyncCore.cs | 2 +- .../Core/DynamicHttpClient.cs | 4 +- .../Extensions/ServiceCollectionExtensions.cs | 10 +- .../DynamicHttpClient.FileDownload.cs | 2 +- .../DynamicHttpClient.FileInfo.cs | 2 +- .../DynamicHttpClient.FileUpload.cs | 2 +- .../Infrastructure/CircuitBreakerManager.cs | 2 +- .../Infrastructure/ServiceEndpointManager.cs | 4 +- .../Interfaces/IAsyncHttpClient.cs | 2 +- .../Interfaces/ICircuitBreakerManager.cs | 2 +- .../Interfaces/IFileHttpClient.cs | 2 +- .../Interfaces/ISyncHttpClient.cs | 2 +- .../Service/InstrumentProtocolClient.cs | 32 +- .../Service/TestTerminalRequestClient.cs | 108 +++ .../Terminal/TerminalDeviceConfiguration.cs | 91 +++ src/X1.Infrastructure/Context/AppDbContext.cs | 6 + .../Extensions/ServiceCollectionExtensions.cs | 2 +- .../Handlers/ProtocolMessageHandler.cs | 14 +- .../Handlers/TerminalMessageHandler.cs | 38 ++ src/modify.md | 627 +++++++++++++++++- 56 files changed, 1248 insertions(+), 198 deletions(-) delete mode 100644 src/X1.Domain/DependencyInjection.cs create mode 100644 src/X1.Domain/Entities/Terminal/TerminalDeviceType.cs rename src/X1.Domain/{ExternalCommunication => ThirdPartyDeviceHttpClient}/IBaseInstrumentClient.cs (93%) rename src/X1.Domain/{ExternalCommunication => ThirdPartyDeviceHttpClient}/IInstrumentHttpClient.cs (95%) rename src/X1.Domain/{ExternalCommunication => ThirdPartyDeviceHttpClient}/IInstrumentProtocolClient.cs (95%) rename src/X1.Domain/{ExternalCommunication => ThirdPartyDeviceHttpClient}/IServiceEndpointManager.cs (93%) create mode 100644 src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/IADBOperationTerminalClient.cs create mode 100644 src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/IATOperationTerminalClient.cs create mode 100644 src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/IBaseTerminalClient.cs create mode 100644 src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/ITerminalHttpClient.cs rename src/X1.Domain/{ExternalCommunication => ThirdPartyDeviceHttpClient}/Models/ApiActionResult.cs (98%) rename src/X1.Domain/{ExternalCommunication => ThirdPartyDeviceHttpClient}/Models/CellularNetworkConfiguration.cs (97%) rename src/X1.Domain/{ExternalCommunication => ThirdPartyDeviceHttpClient}/Models/CellularNetworkRequest.cs (91%) rename src/X1.Domain/{ExternalCommunication => ThirdPartyDeviceHttpClient}/Models/CircuitBreakerOptions.cs (97%) rename src/X1.Domain/{ExternalCommunication => ThirdPartyDeviceHttpClient}/Models/DeviceInfoResponse.cs (91%) rename src/X1.Domain/{ExternalCommunication => ThirdPartyDeviceHttpClient}/Models/DynamicHttpClientException.cs (98%) rename src/X1.Domain/{ExternalCommunication => ThirdPartyDeviceHttpClient}/Models/HttpRequestOptions.cs (95%) rename src/X1.Domain/{ExternalCommunication => ThirdPartyDeviceHttpClient}/Models/ServiceEndpoint.cs (97%) create mode 100644 src/X1.Domain/ThirdPartyDeviceHttpClient/Models/TestTerminalResponse.cs create mode 100644 src/X1.DynamicClientCore/Service/TestTerminalRequestClient.cs create mode 100644 src/X1.Infrastructure/Configurations/Terminal/TerminalDeviceConfiguration.cs create mode 100644 src/X1.WebSocket/Handlers/TerminalMessageHandler.cs diff --git a/src/X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs b/src/X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs index 8856ce0..18ce272 100644 --- a/src/X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs +++ b/src/X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs @@ -8,8 +8,8 @@ using CellularManagement.Domain.Services; using CellularManagement.Domain.Repositories.NetworkProfile; using X1.Domain.Models; using System.Collections.Concurrent; -using X1.Domain.ExternalCommunication.Models; -using X1.Domain.ExternalCommunication; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; +using X1.Domain.ThirdPartyDeviceHttpClient; namespace CellularManagement.Application.Features.DeviceRuntimes.Commands.StartDeviceRuntime; diff --git a/src/X1.Application/Features/DeviceRuntimes/Commands/StopDeviceRuntime/StopDeviceRuntimeCommandHandler.cs b/src/X1.Application/Features/DeviceRuntimes/Commands/StopDeviceRuntime/StopDeviceRuntimeCommandHandler.cs index 0cd5902..0504234 100644 --- a/src/X1.Application/Features/DeviceRuntimes/Commands/StopDeviceRuntime/StopDeviceRuntimeCommandHandler.cs +++ b/src/X1.Application/Features/DeviceRuntimes/Commands/StopDeviceRuntime/StopDeviceRuntimeCommandHandler.cs @@ -5,8 +5,8 @@ using CellularManagement.Domain.Entities.Device; using CellularManagement.Domain.Repositories.Device; using CellularManagement.Domain.Repositories.Base; using CellularManagement.Domain.Services; -using X1.Domain.ExternalCommunication.Models; -using X1.Domain.ExternalCommunication; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; +using X1.Domain.ThirdPartyDeviceHttpClient; namespace CellularManagement.Application.Features.DeviceRuntimes.Commands.StopDeviceRuntime; diff --git a/src/X1.Application/Features/Devices/Commands/CreateDevice/CreateDeviceCommandHandler.cs b/src/X1.Application/Features/Devices/Commands/CreateDevice/CreateDeviceCommandHandler.cs index 1c100e6..545f707 100644 --- a/src/X1.Application/Features/Devices/Commands/CreateDevice/CreateDeviceCommandHandler.cs +++ b/src/X1.Application/Features/Devices/Commands/CreateDevice/CreateDeviceCommandHandler.cs @@ -6,8 +6,8 @@ using CellularManagement.Domain.Repositories; using CellularManagement.Domain.Repositories.Device; using CellularManagement.Domain.Repositories.Base; using CellularManagement.Domain.Services; -using X1.Domain.ExternalCommunication.Models; -using X1.Domain.ExternalCommunication; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; +using X1.Domain.ThirdPartyDeviceHttpClient; namespace CellularManagement.Application.Features.Devices.Commands.CreateDevice; diff --git a/src/X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommand.cs b/src/X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommand.cs index d69db25..3928a27 100644 --- a/src/X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommand.cs +++ b/src/X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommand.cs @@ -40,4 +40,6 @@ public class CreateTerminalDeviceCommand : IRequest public bool IsEnabled { get; set; } = true; + + } diff --git a/src/X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommandHandler.cs b/src/X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommandHandler.cs index 64a5419..4b516e6 100644 --- a/src/X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommandHandler.cs +++ b/src/X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommandHandler.cs @@ -8,11 +8,28 @@ using CellularManagement.Domain.Repositories.Base; using CellularManagement.Domain.Services; using CellularManagement.Domain.Repositories.Terminal; using CellularManagement.Domain.Entities.Terminal; -using X1.Domain.ExternalCommunication.Models; -using X1.Domain.ExternalCommunication; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.ITerminal; +using X1.Domain.ThirdPartyDeviceHttpClient; namespace CellularManagement.Application.Features.TerminalDevices.Commands.CreateTerminalDevice; +/// +/// 设备信息数据传输对象 +/// +public class DeviceInfo +{ + /// + /// 设备序列号 + /// + public string SerialNumber { get; set; } = string.Empty; + + /// + /// 设备类型 + /// + public TerminalDeviceType DeviceType { get; set; } +} + /// /// 创建终端设备命令处理器 /// @@ -22,7 +39,7 @@ public class CreateTerminalDeviceCommandHandler : IRequestHandler _logger; private readonly IUnitOfWork _unitOfWork; private readonly ICurrentUserService _currentUserService; - private readonly IBaseInstrumentClient _instrumentClient; + private readonly IBaseTerminalClient _terminalClient; private readonly IServiceEndpointManager _endpointManager; /// @@ -33,14 +50,14 @@ public class CreateTerminalDeviceCommandHandler : IRequestHandler logger, IUnitOfWork unitOfWork, ICurrentUserService currentUserService, - IBaseInstrumentClient instrumentClient, + IBaseTerminalClient terminalClient, IServiceEndpointManager endpointManager) { _deviceRepository = deviceRepository; _logger = logger; _unitOfWork = unitOfWork; _currentUserService = currentUserService; - _instrumentClient = instrumentClient; + _terminalClient = terminalClient; _endpointManager = endpointManager; } @@ -71,14 +88,15 @@ public class CreateTerminalDeviceCommandHandler : IRequestHandler.CreateFailure(serialNumberResult.ErrorMessages); + return OperationResult.CreateFailure(deviceInfoResult.ErrorMessages ?? new List { "获取设备信息失败" }); } - var serialNumber = serialNumberResult.Data; + var serialNumber = deviceInfoResult.Data!.SerialNumber; + var deviceType = deviceInfoResult.Data!.DeviceType; // 验证序列号 if (string.IsNullOrWhiteSpace(serialNumber)) @@ -95,14 +113,7 @@ public class CreateTerminalDeviceCommandHandler : IRequestHandler.CreateFailure($"终端设备编码 {deviceCode} 已存在"); - } + var deviceCode = await GenerateUniqueDeviceCodeAsync(cancellationToken); // 创建终端设备实体 var terminalDevice = TerminalDevice.Create( @@ -113,12 +124,18 @@ public class CreateTerminalDeviceCommandHandler : IRequestHandler - /// 生成设备编码 + /// 生成唯一的设备编码 /// - private async Task GenerateDeviceCodeAsync(string serialNumber, CancellationToken cancellationToken) + private async Task GenerateUniqueDeviceCodeAsync(CancellationToken cancellationToken) { - // 获取当前设备总数 - var deviceCount = await _deviceRepository.GetDeviceCountAsync(cancellationToken); - var nextNumber = deviceCount + 1; - - // 计算需要的位数,确保至少3位数 - var digitCount = CalculateRequiredDigits(nextNumber); - - // 格式化序号,动态补0,确保从000开始 - var formattedNumber = nextNumber.ToString($"D{digitCount}"); + // 使用短UUID生成唯一编码 + var shortId = Guid.NewGuid().ToString("N").Substring(0, 8); + var deviceCode = $"TERM-{shortId}"; - // 生成设备编号格式:TERM-000-SN, TERM-001-SN, TERM-002-SN 等 - var deviceCode = $"TERM-{formattedNumber}-{serialNumber}"; - - _logger.LogDebug("生成终端设备编号: {DeviceCode}, 设备总数: {DeviceCount}, 位数: {DigitCount}", deviceCode, deviceCount, digitCount); + // 检查设备编码是否已存在(理论上概率极低) + if (await _deviceRepository.DeviceCodeExistsAsync(deviceCode, cancellationToken)) + { + // 如果冲突,使用时间戳后缀 + var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() % 1000000; // 取后6位 + deviceCode = $"TERM-{shortId}-{timestamp}"; + _logger.LogDebug("设备编码冲突,使用时间戳后缀: {DeviceCode}", deviceCode); + } + _logger.LogDebug("生成终端设备编号: {DeviceCode}", deviceCode); return deviceCode; } - /// - /// 计算需要的位数 - /// - private int CalculateRequiredDigits(int number) - { - if (number <= 0) return 3; // 从000开始,至少3位数 - - // 计算位数:确保至少3位数,从000开始 - // 1-999用3位,1000-9999用4位,10000-99999用5位,以此类推 - var calculatedDigits = (int)Math.Floor(Math.Log10(number)) + 1; - return Math.Max(calculatedDigits, 3); // 确保至少3位数 - } - /// /// 创建服务端点配置 /// @@ -235,9 +239,9 @@ public class CreateTerminalDeviceCommandHandler : IRequestHandler - /// 获取设备序列号 + /// 获取设备序列号和系统类型信息 /// - private async Task> GetDeviceSerialNumberAsync(CreateTerminalDeviceCommand request, ServiceEndpoint serviceEndpoint, CancellationToken cancellationToken) + private async Task> GetDeviceInfoAsync(CreateTerminalDeviceCommand request, ServiceEndpoint serviceEndpoint, CancellationToken cancellationToken) { try { @@ -245,33 +249,74 @@ public class CreateTerminalDeviceCommandHandler : IRequestHandler.CreateFailure($"无法通过IP地址 {request.IpAddress} 获取终端设备序列号,请检查设备连接状态"); + return OperationResult.CreateFailure($"无法通过IP地址 {request.IpAddress} 获取终端设备序列号或系统类型,请检查设备连接状态"); } - _logger.LogInformation("成功获取终端设备序列号: {SerialNumber}, IP地址: {IpAddress}", serialNumber, request.IpAddress); + var serialNumber = machineCodeData.MachineCode; + var systemType = machineCodeData.SystemType.ToLowerInvariant(); + var detectedType = DetectDeviceTypeFromSystemType(systemType); + + _logger.LogInformation("成功获取终端设备序列号: {SerialNumber}, IP地址: {IpAddress}, 系统类型: {SystemType}", + serialNumber, request.IpAddress, systemType); // 获取序列号成功后,移除临时服务端点 _endpointManager.RemoveEndpoint(serviceEndpoint.Name); _logger.LogDebug("已移除临时服务端点: {EndpointName}", serviceEndpoint.Name); - return OperationResult.CreateSuccess(serialNumber); + return OperationResult.CreateSuccess(new DeviceInfo { SerialNumber = serialNumber, DeviceType = detectedType }); } catch (Exception ex) { - _logger.LogError(ex, "获取终端设备序列号时发生异常,IP地址: {IpAddress}", request.IpAddress); + _logger.LogError(ex, "获取终端设备序列号或系统类型时发生异常,IP地址: {IpAddress}", request.IpAddress); // 发生异常时清理服务端点 _endpointManager.RemoveEndpoint(serviceEndpoint.Name); _logger.LogDebug("已清理服务端点: {EndpointName}", serviceEndpoint.Name); - return OperationResult.CreateFailure($"获取终端设备序列号时发生错误: {ex.Message}"); + return OperationResult.CreateFailure($"获取终端设备序列号或系统类型时发生错误: {ex.Message}"); + } + } + + /// + /// 根据系统类型字符串检测设备类型 + /// + /// 系统类型字符串 + /// 检测到的设备类型 + private TerminalDeviceType DetectDeviceTypeFromSystemType(string systemType) + { + // 转换为小写进行比较 + var lowerSystemType = systemType.ToLowerInvariant(); + + // 检测Linux系统 + if (lowerSystemType.Contains("linux") || + lowerSystemType.Contains("ubuntu") || + lowerSystemType.Contains("centos") || + lowerSystemType.Contains("debian") || + lowerSystemType.Contains("fedora") || + lowerSystemType.Contains("redhat") || + lowerSystemType.Contains("suse") || + lowerSystemType.Contains("unix")) + { + return TerminalDeviceType.Linux; } + + // 检测Windows系统 + if (lowerSystemType.Contains("windows") || + lowerSystemType.Contains("win") || + lowerSystemType.Contains("nt")) + { + return TerminalDeviceType.Windows; + } + + // 默认返回Windows类型 + _logger.LogDebug("未知系统类型: {SystemType},使用默认类型Windows", systemType); + return TerminalDeviceType.Windows; } } diff --git a/src/X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceResponse.cs b/src/X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceResponse.cs index 893a236..b73243f 100644 --- a/src/X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceResponse.cs +++ b/src/X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceResponse.cs @@ -35,6 +35,11 @@ public class CreateTerminalDeviceResponse /// public bool IsEnabled { get; set; } + /// + /// 设备类型 + /// + public string DeviceType { get; set; } = string.Empty; + /// /// 创建时间 /// diff --git a/src/X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceCommand.cs b/src/X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceCommand.cs index b5fbd6c..a5710b9 100644 --- a/src/X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceCommand.cs +++ b/src/X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceCommand.cs @@ -15,32 +15,12 @@ public class UpdateTerminalDeviceCommand : IRequest - /// 设备名称 - /// - [Required(ErrorMessage = "设备名称不能为空")] - [MaxLength(100, ErrorMessage = "设备名称不能超过100个字符")] - public string DeviceName { get; set; } = null!; - /// /// 设备描述 /// [MaxLength(500, ErrorMessage = "设备描述不能超过500个字符")] public string Description { get; set; } = string.Empty; - /// - /// IP地址 - /// - [Required(ErrorMessage = "设备IP不能为空")] - [MaxLength(45, ErrorMessage = "IP地址不能超过45个字符")] - public string IpAddress { get; set; } = null!; - - /// - /// Agent端口 - /// - [Required(ErrorMessage = "Agent端口不能为空")] - public int AgentPort { get; set; } - /// /// 是否启用 /// diff --git a/src/X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceCommandHandler.cs b/src/X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceCommandHandler.cs index 3286f19..e3ea7bd 100644 --- a/src/X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceCommandHandler.cs +++ b/src/X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceCommandHandler.cs @@ -2,6 +2,7 @@ using MediatR; using Microsoft.Extensions.Logging; using CellularManagement.Domain.Common; using CellularManagement.Domain.Entities.Device; +using CellularManagement.Domain.Entities.Terminal; using CellularManagement.Domain.Repositories.Device; using CellularManagement.Domain.Repositories.Base; using CellularManagement.Domain.Services; @@ -46,8 +47,7 @@ public class UpdateTerminalDeviceCommandHandler : IRequestHandler.CreateFailure(validationResult.ErrorMessages); } - _logger.LogInformation("开始更新终端设备,设备ID: {DeviceId}, 设备名称: {DeviceName}", - request.DeviceId, request.DeviceName); + _logger.LogInformation("开始更新终端设备,设备ID: {DeviceId}", request.DeviceId); // 验证用户认证 var currentUserId = ValidateUserAuthentication(); @@ -66,16 +66,17 @@ public class UpdateTerminalDeviceCommandHandler : IRequestHandler.CreateFailure("终端设备不存在"); } - // 更新设备信息 - device.Update( - request.DeviceName, - device.SerialNumber, // 序列号不允许修改 - device.DeviceCode, // 设备编码不允许修改 - request.Description, - request.AgentPort, - request.IpAddress, - currentUserId.Data!, - request.IsEnabled); + // 只更新允许修改的字段 + device.UpdateDescription(request.Description); + if (request.IsEnabled) + { + device.Enable(); + } + else + { + device.Disable(); + } + device.UpdateAuditInfo(currentUserId.Data!); // 保存到数据库 _deviceRepository.UpdateDevice(device); @@ -92,6 +93,7 @@ public class UpdateTerminalDeviceCommandHandler : IRequestHandler.CreateFailure("设备ID不能为空"); } - if (string.IsNullOrWhiteSpace(request.DeviceName)) - { - return OperationResult.CreateFailure("设备名称不能为空"); - } - - if (string.IsNullOrWhiteSpace(request.IpAddress)) - { - return OperationResult.CreateFailure("IP地址不能为空"); - } - - if (request.AgentPort <= 0 || request.AgentPort > 65535) - { - return OperationResult.CreateFailure("Agent端口必须在1-65535之间"); - } - return OperationResult.CreateSuccess(true); } diff --git a/src/X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceResponse.cs b/src/X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceResponse.cs index eb9a0c5..dd7861b 100644 --- a/src/X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceResponse.cs +++ b/src/X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceResponse.cs @@ -35,6 +35,11 @@ public class UpdateTerminalDeviceResponse /// public bool IsEnabled { get; set; } + /// + /// 设备类型 + /// + public string DeviceType { get; set; } = string.Empty; + /// /// 更新时间 /// diff --git a/src/X1.Application/Features/TerminalDevices/Queries/GetTerminalDeviceById/GetTerminalDeviceByIdQueryHandler.cs b/src/X1.Application/Features/TerminalDevices/Queries/GetTerminalDeviceById/GetTerminalDeviceByIdQueryHandler.cs index 98d096c..6c98121 100644 --- a/src/X1.Application/Features/TerminalDevices/Queries/GetTerminalDeviceById/GetTerminalDeviceByIdQueryHandler.cs +++ b/src/X1.Application/Features/TerminalDevices/Queries/GetTerminalDeviceById/GetTerminalDeviceByIdQueryHandler.cs @@ -47,12 +47,12 @@ public class GetTerminalDeviceByIdQueryHandler : IRequestHandler public string Name { get; set; } = string.Empty; - /// - /// 设备序列号 - /// - public string SerialNumber { get; set; } = string.Empty; + /// /// 设备编码 @@ -45,6 +42,11 @@ public class GetTerminalDeviceByIdResponse /// public bool IsEnabled { get; set; } + /// + /// 设备类型 + /// + public string DeviceType { get; set; } = string.Empty; + /// /// 创建时间 /// diff --git a/src/X1.Application/Features/TerminalDevices/Queries/GetTerminalDevices/GetTerminalDevicesQueryHandler.cs b/src/X1.Application/Features/TerminalDevices/Queries/GetTerminalDevices/GetTerminalDevicesQueryHandler.cs index 00c5188..b5033db 100644 --- a/src/X1.Application/Features/TerminalDevices/Queries/GetTerminalDevices/GetTerminalDevicesQueryHandler.cs +++ b/src/X1.Application/Features/TerminalDevices/Queries/GetTerminalDevices/GetTerminalDevicesQueryHandler.cs @@ -49,12 +49,12 @@ public class GetTerminalDevicesQueryHandler : IRequestHandler public string Name { get; set; } = string.Empty; - /// - /// 设备序列号 - /// - public string SerialNumber { get; set; } = string.Empty; + /// /// 设备编码 @@ -76,6 +73,11 @@ public class TerminalDeviceDto /// public bool IsEnabled { get; set; } + /// + /// 设备类型 + /// + public string DeviceType { get; set; } = string.Empty; + /// /// 创建时间 /// diff --git a/src/X1.BackendServices/BackendServiceManager/DeviceManagementService.cs b/src/X1.BackendServices/BackendServiceManager/DeviceManagementService.cs index f912293..8ae4cdc 100644 --- a/src/X1.BackendServices/BackendServiceManager/DeviceManagementService.cs +++ b/src/X1.BackendServices/BackendServiceManager/DeviceManagementService.cs @@ -13,8 +13,8 @@ using X1.Domain.Transmission; using CellularManagement.Domain.Repositories.Base; using System.Data; using Microsoft.Extensions.DependencyInjection; -using X1.Domain.ExternalCommunication.Models; -using X1.Domain.ExternalCommunication; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; +using X1.Domain.ThirdPartyDeviceHttpClient; namespace X1.BackendServices.BackendServiceManager { diff --git a/src/X1.Domain/DependencyInjection.cs b/src/X1.Domain/DependencyInjection.cs deleted file mode 100644 index bdba907..0000000 --- a/src/X1.Domain/DependencyInjection.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace CellularManagement.Domain; - -/// -/// 领域层依赖注入扩展 -/// -public static class DependencyInjection -{ - /// - /// 添加领域层服务 - /// - /// 服务集合 - /// 服务集合 - public static IServiceCollection AddDomainServices(this IServiceCollection services) - { - return services; - } -} \ No newline at end of file diff --git a/src/X1.Domain/Entities/Terminal/TerminalDevice.cs b/src/X1.Domain/Entities/Terminal/TerminalDevice.cs index 80d5143..edef0a7 100644 --- a/src/X1.Domain/Entities/Terminal/TerminalDevice.cs +++ b/src/X1.Domain/Entities/Terminal/TerminalDevice.cs @@ -56,6 +56,12 @@ public class TerminalDevice : AuditableEntity /// public bool IsEnabled { get; private set; } = true; + /// + /// 设备类型 + /// + [Required] + public TerminalDeviceType DeviceType { get; private set; } = TerminalDeviceType.Windows; + /// /// 创建设备 /// @@ -67,6 +73,7 @@ public class TerminalDevice : AuditableEntity int agentPort, string ipAddress, string createdBy, + TerminalDeviceType deviceType = TerminalDeviceType.Windows, bool isEnabled = true) { var device = new TerminalDevice @@ -78,6 +85,7 @@ public class TerminalDevice : AuditableEntity Description = description, AgentPort = agentPort, IpAddress = ipAddress, + DeviceType = deviceType, IsEnabled = isEnabled, CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow, @@ -99,6 +107,7 @@ public class TerminalDevice : AuditableEntity int agentPort, string ipAddress, string updatedBy, + TerminalDeviceType deviceType = TerminalDeviceType.Windows, bool isEnabled = true) { Name = name; @@ -107,6 +116,7 @@ public class TerminalDevice : AuditableEntity Description = description; AgentPort = agentPort; IpAddress = ipAddress; + DeviceType = deviceType; IsEnabled = isEnabled; UpdatedAt = DateTime.UtcNow; UpdatedBy = updatedBy; @@ -129,4 +139,22 @@ public class TerminalDevice : AuditableEntity IsEnabled = false; UpdatedAt = DateTime.UtcNow; } + + /// + /// 更新描述 + /// + public void UpdateDescription(string description) + { + Description = description; + UpdatedAt = DateTime.UtcNow; + } + + /// + /// 更新审计信息 + /// + public void UpdateAuditInfo(string updatedBy) + { + UpdatedAt = DateTime.UtcNow; + UpdatedBy = updatedBy; + } } diff --git a/src/X1.Domain/Entities/Terminal/TerminalDeviceType.cs b/src/X1.Domain/Entities/Terminal/TerminalDeviceType.cs new file mode 100644 index 0000000..90dc811 --- /dev/null +++ b/src/X1.Domain/Entities/Terminal/TerminalDeviceType.cs @@ -0,0 +1,17 @@ +namespace CellularManagement.Domain.Entities.Terminal; + +/// +/// 终端设备类型枚举 +/// +public enum TerminalDeviceType +{ + /// + /// Windows系统 + /// + Windows = 1, + + /// + /// Linux系统 + /// + Linux = 2 +} diff --git a/src/X1.Domain/ExternalCommunication/IBaseInstrumentClient.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/IBaseInstrumentClient.cs similarity index 93% rename from src/X1.Domain/ExternalCommunication/IBaseInstrumentClient.cs rename to src/X1.Domain/ThirdPartyDeviceHttpClient/IBaseInstrumentClient.cs index df861ce..436c18e 100644 --- a/src/X1.Domain/ExternalCommunication/IBaseInstrumentClient.cs +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/IBaseInstrumentClient.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; -namespace X1.Domain.ExternalCommunication +namespace X1.Domain.ThirdPartyDeviceHttpClient { /// /// 基础仪器客户端接口 diff --git a/src/X1.Domain/ExternalCommunication/IInstrumentHttpClient.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/IInstrumentHttpClient.cs similarity index 95% rename from src/X1.Domain/ExternalCommunication/IInstrumentHttpClient.cs rename to src/X1.Domain/ThirdPartyDeviceHttpClient/IInstrumentHttpClient.cs index a4ebd76..ef41a04 100644 --- a/src/X1.Domain/ExternalCommunication/IInstrumentHttpClient.cs +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/IInstrumentHttpClient.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace X1.Domain.ExternalCommunication +namespace X1.Domain.ThirdPartyDeviceHttpClient { /// /// 仪器HTTP客户端接口 diff --git a/src/X1.Domain/ExternalCommunication/IInstrumentProtocolClient.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/IInstrumentProtocolClient.cs similarity index 95% rename from src/X1.Domain/ExternalCommunication/IInstrumentProtocolClient.cs rename to src/X1.Domain/ThirdPartyDeviceHttpClient/IInstrumentProtocolClient.cs index 32784a5..ab5492d 100644 --- a/src/X1.Domain/ExternalCommunication/IInstrumentProtocolClient.cs +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/IInstrumentProtocolClient.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; -namespace X1.Domain.ExternalCommunication +namespace X1.Domain.ThirdPartyDeviceHttpClient { /// /// 仪器协议客户端接口 diff --git a/src/X1.Domain/ExternalCommunication/IServiceEndpointManager.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/IServiceEndpointManager.cs similarity index 93% rename from src/X1.Domain/ExternalCommunication/IServiceEndpointManager.cs rename to src/X1.Domain/ThirdPartyDeviceHttpClient/IServiceEndpointManager.cs index 89394b6..71c2500 100644 --- a/src/X1.Domain/ExternalCommunication/IServiceEndpointManager.cs +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/IServiceEndpointManager.cs @@ -1,6 +1,6 @@ -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; -namespace X1.Domain.ExternalCommunication +namespace X1.Domain.ThirdPartyDeviceHttpClient { /// /// 服务端点管理器接口 diff --git a/src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/IADBOperationTerminalClient.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/IADBOperationTerminalClient.cs new file mode 100644 index 0000000..38799f0 --- /dev/null +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/IADBOperationTerminalClient.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace X1.Domain.ThirdPartyDeviceHttpClient.ITerminal +{ + public interface IADBOperationTerminalClient + { + + } + + +} diff --git a/src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/IATOperationTerminalClient.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/IATOperationTerminalClient.cs new file mode 100644 index 0000000..a989fb3 --- /dev/null +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/IATOperationTerminalClient.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace X1.Domain.ThirdPartyDeviceHttpClient.ITerminal +{ + public interface IATOperationTerminalClient + { + + } +} diff --git a/src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/IBaseTerminalClient.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/IBaseTerminalClient.cs new file mode 100644 index 0000000..6135414 --- /dev/null +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/IBaseTerminalClient.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; + +namespace X1.Domain.ThirdPartyDeviceHttpClient.ITerminal +{ + public interface IBaseTerminalClient + { + /// + /// 获取测试终端机器码数据 + /// + /// 测试终端ID + /// 请求选项,包含超时、请求头等配置 + /// 取消令牌,用于取消异步操作 + /// 测试终端机器码数据,如果获取失败则返回null + /// 当terminalId为null时抛出 + /// 当terminalId配置无效时抛出 + Task GetDeviceSerialNumberAsync( + string terminalId, + RequestOptions? options = null, + CancellationToken cancellationToken = default); + } +} diff --git a/src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/ITerminalHttpClient.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/ITerminalHttpClient.cs new file mode 100644 index 0000000..a42a0b3 --- /dev/null +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/ITerminalHttpClient.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace X1.Domain.ThirdPartyDeviceHttpClient.ITerminal +{ + public interface ITerminalHttpClient: IADBOperationTerminalClient, IATOperationTerminalClient, IBaseTerminalClient + { + + } +} diff --git a/src/X1.Domain/ExternalCommunication/Models/ApiActionResult.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/ApiActionResult.cs similarity index 98% rename from src/X1.Domain/ExternalCommunication/Models/ApiActionResult.cs rename to src/X1.Domain/ThirdPartyDeviceHttpClient/Models/ApiActionResult.cs index c145e2e..2ffc73a 100644 --- a/src/X1.Domain/ExternalCommunication/Models/ApiActionResult.cs +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/ApiActionResult.cs @@ -5,7 +5,7 @@ using System.Text; using System.Threading.Tasks; using System.Net; -namespace X1.Domain.ExternalCommunication.Models +namespace X1.Domain.ThirdPartyDeviceHttpClient.Models { /// /// API操作结果 diff --git a/src/X1.Domain/ExternalCommunication/Models/CellularNetworkConfiguration.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/CellularNetworkConfiguration.cs similarity index 97% rename from src/X1.Domain/ExternalCommunication/Models/CellularNetworkConfiguration.cs rename to src/X1.Domain/ThirdPartyDeviceHttpClient/Models/CellularNetworkConfiguration.cs index 1c3de1f..91cd92e 100644 --- a/src/X1.Domain/ExternalCommunication/Models/CellularNetworkConfiguration.cs +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/CellularNetworkConfiguration.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace X1.Domain.ExternalCommunication.Models +namespace X1.Domain.ThirdPartyDeviceHttpClient.Models { /// /// 蜂窝网络配置实体 diff --git a/src/X1.Domain/ExternalCommunication/Models/CellularNetworkRequest.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/CellularNetworkRequest.cs similarity index 91% rename from src/X1.Domain/ExternalCommunication/Models/CellularNetworkRequest.cs rename to src/X1.Domain/ThirdPartyDeviceHttpClient/Models/CellularNetworkRequest.cs index dc6334e..5b8ca71 100644 --- a/src/X1.Domain/ExternalCommunication/Models/CellularNetworkRequest.cs +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/CellularNetworkRequest.cs @@ -1,4 +1,4 @@ -namespace X1.Domain.ExternalCommunication.Models +namespace X1.Domain.ThirdPartyDeviceHttpClient.Models { /// /// 蜂窝网络启动请求包装类 diff --git a/src/X1.Domain/ExternalCommunication/Models/CircuitBreakerOptions.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/CircuitBreakerOptions.cs similarity index 97% rename from src/X1.Domain/ExternalCommunication/Models/CircuitBreakerOptions.cs rename to src/X1.Domain/ThirdPartyDeviceHttpClient/Models/CircuitBreakerOptions.cs index c1cd51f..7d49397 100644 --- a/src/X1.Domain/ExternalCommunication/Models/CircuitBreakerOptions.cs +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/CircuitBreakerOptions.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace X1.Domain.ExternalCommunication.Models +namespace X1.Domain.ThirdPartyDeviceHttpClient.Models { /// /// 熔断器配置选项 diff --git a/src/X1.Domain/ExternalCommunication/Models/DeviceInfoResponse.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/DeviceInfoResponse.cs similarity index 91% rename from src/X1.Domain/ExternalCommunication/Models/DeviceInfoResponse.cs rename to src/X1.Domain/ThirdPartyDeviceHttpClient/Models/DeviceInfoResponse.cs index e4d7db1..9b93f7e 100644 --- a/src/X1.Domain/ExternalCommunication/Models/DeviceInfoResponse.cs +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/DeviceInfoResponse.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace X1.Domain.ExternalCommunication.Models +namespace X1.Domain.ThirdPartyDeviceHttpClient.Models { /// /// 设备信息响应模型(用于API响应) diff --git a/src/X1.Domain/ExternalCommunication/Models/DynamicHttpClientException.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/DynamicHttpClientException.cs similarity index 98% rename from src/X1.Domain/ExternalCommunication/Models/DynamicHttpClientException.cs rename to src/X1.Domain/ThirdPartyDeviceHttpClient/Models/DynamicHttpClientException.cs index 796a10a..4ef8e7c 100644 --- a/src/X1.Domain/ExternalCommunication/Models/DynamicHttpClientException.cs +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/DynamicHttpClientException.cs @@ -1,6 +1,6 @@ using System.Runtime.Serialization; -namespace X1.Domain.ExternalCommunication.Models +namespace X1.Domain.ThirdPartyDeviceHttpClient.Models { /// /// 动态HTTP客户端异常 diff --git a/src/X1.Domain/ExternalCommunication/Models/HttpRequestOptions.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/HttpRequestOptions.cs similarity index 95% rename from src/X1.Domain/ExternalCommunication/Models/HttpRequestOptions.cs rename to src/X1.Domain/ThirdPartyDeviceHttpClient/Models/HttpRequestOptions.cs index 8aeee99..82f59bc 100644 --- a/src/X1.Domain/ExternalCommunication/Models/HttpRequestOptions.cs +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/HttpRequestOptions.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace X1.Domain.ExternalCommunication.Models +namespace X1.Domain.ThirdPartyDeviceHttpClient.Models { /// /// HTTP请求选项 - 定义HTTP请求的配置参数 diff --git a/src/X1.Domain/ExternalCommunication/Models/ServiceEndpoint.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/ServiceEndpoint.cs similarity index 97% rename from src/X1.Domain/ExternalCommunication/Models/ServiceEndpoint.cs rename to src/X1.Domain/ThirdPartyDeviceHttpClient/Models/ServiceEndpoint.cs index d576678..88f1052 100644 --- a/src/X1.Domain/ExternalCommunication/Models/ServiceEndpoint.cs +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/ServiceEndpoint.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace X1.Domain.ExternalCommunication.Models +namespace X1.Domain.ThirdPartyDeviceHttpClient.Models { /// /// 服务端点配置模型 - 定义单个服务的连接配置信息 diff --git a/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/TestTerminalResponse.cs b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/TestTerminalResponse.cs new file mode 100644 index 0000000..caed96e --- /dev/null +++ b/src/X1.Domain/ThirdPartyDeviceHttpClient/Models/TestTerminalResponse.cs @@ -0,0 +1,55 @@ +using System.Text.Json.Serialization; + +namespace X1.Domain.ThirdPartyDeviceHttpClient.Models +{ + /// + /// 测试终端响应模型(泛型版本) + /// + /// 响应数据类型 + public class TestTerminalResponse + { + /// + /// 是否成功 + /// + [JsonPropertyName("success")] + public bool Success { get; set; } + + /// + /// 响应消息 + /// + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; + + /// + /// 响应数据 + /// + [JsonPropertyName("data")] + public T? Data { get; set; } + } + + /// + /// 机器码数据 + /// + public class MachineCodeData + { + /// + /// 机器码 + /// + [JsonPropertyName("machine_code")] + public string MachineCode { get; set; } = string.Empty; + + /// + /// 系统类型 + /// + [JsonPropertyName("system_type")] + public string SystemType { get; set; } = string.Empty; + } + + /// + /// 测试终端响应模型(非泛型版本,使用MachineCodeData作为默认类型) + /// + public class TestTerminalResponse : TestTerminalResponse + { + // 继承自泛型版本,使用MachineCodeData作为默认类型 + } +} diff --git a/src/X1.DynamicClientCore/Core/DynamicHttpClient.Core.cs b/src/X1.DynamicClientCore/Core/DynamicHttpClient.Core.cs index 66e4293..7ce31b4 100644 --- a/src/X1.DynamicClientCore/Core/DynamicHttpClient.Core.cs +++ b/src/X1.DynamicClientCore/Core/DynamicHttpClient.Core.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; namespace X1.DynamicClientCore.Core { diff --git a/src/X1.DynamicClientCore/Core/DynamicHttpClient.Sync.cs b/src/X1.DynamicClientCore/Core/DynamicHttpClient.Sync.cs index 76f883a..963b475 100644 --- a/src/X1.DynamicClientCore/Core/DynamicHttpClient.Sync.cs +++ b/src/X1.DynamicClientCore/Core/DynamicHttpClient.Sync.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; namespace X1.DynamicClientCore.Core { diff --git a/src/X1.DynamicClientCore/Core/DynamicHttpClient.SyncCore.cs b/src/X1.DynamicClientCore/Core/DynamicHttpClient.SyncCore.cs index e28e079..e8e559c 100644 --- a/src/X1.DynamicClientCore/Core/DynamicHttpClient.SyncCore.cs +++ b/src/X1.DynamicClientCore/Core/DynamicHttpClient.SyncCore.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Polly; using Polly.CircuitBreaker; -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; namespace X1.DynamicClientCore.Core { diff --git a/src/X1.DynamicClientCore/Core/DynamicHttpClient.cs b/src/X1.DynamicClientCore/Core/DynamicHttpClient.cs index 824a78c..04ecc62 100644 --- a/src/X1.DynamicClientCore/Core/DynamicHttpClient.cs +++ b/src/X1.DynamicClientCore/Core/DynamicHttpClient.cs @@ -1,7 +1,7 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using X1.Domain.ExternalCommunication; -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; using X1.DynamicClientCore.Interfaces; namespace X1.DynamicClientCore.Core diff --git a/src/X1.DynamicClientCore/Extensions/ServiceCollectionExtensions.cs b/src/X1.DynamicClientCore/Extensions/ServiceCollectionExtensions.cs index 1fd9954..aa44b0b 100644 --- a/src/X1.DynamicClientCore/Extensions/ServiceCollectionExtensions.cs +++ b/src/X1.DynamicClientCore/Extensions/ServiceCollectionExtensions.cs @@ -3,9 +3,10 @@ using Microsoft.Extensions.Logging; using X1.DynamicClientCore.Interfaces; using X1.DynamicClientCore.Core; using X1.DynamicClientCore.Infrastructure; -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; using X1.DynamicClientCore.Service; -using X1.Domain.ExternalCommunication; +using X1.Domain.ThirdPartyDeviceHttpClient; +using X1.Domain.ThirdPartyDeviceHttpClient.ITerminal; namespace X1.DynamicClientCore.Extensions { @@ -52,6 +53,11 @@ namespace X1.DynamicClientCore.Extensions services.AddSingleton(); services.AddSingleton(); + // 注册仪器协议客户端(单例) + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); return services; } diff --git a/src/X1.DynamicClientCore/FileOperations/DynamicHttpClient.FileDownload.cs b/src/X1.DynamicClientCore/FileOperations/DynamicHttpClient.FileDownload.cs index 9d6c7b4..d1a803b 100644 --- a/src/X1.DynamicClientCore/FileOperations/DynamicHttpClient.FileDownload.cs +++ b/src/X1.DynamicClientCore/FileOperations/DynamicHttpClient.FileDownload.cs @@ -1,5 +1,5 @@ using Microsoft.Extensions.Logging; -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; namespace X1.DynamicClientCore.Core { diff --git a/src/X1.DynamicClientCore/FileOperations/DynamicHttpClient.FileInfo.cs b/src/X1.DynamicClientCore/FileOperations/DynamicHttpClient.FileInfo.cs index 141e71f..6a1f9a2 100644 --- a/src/X1.DynamicClientCore/FileOperations/DynamicHttpClient.FileInfo.cs +++ b/src/X1.DynamicClientCore/FileOperations/DynamicHttpClient.FileInfo.cs @@ -1,4 +1,4 @@ -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; namespace X1.DynamicClientCore.Core { diff --git a/src/X1.DynamicClientCore/FileOperations/DynamicHttpClient.FileUpload.cs b/src/X1.DynamicClientCore/FileOperations/DynamicHttpClient.FileUpload.cs index 892af2a..d07bf7c 100644 --- a/src/X1.DynamicClientCore/FileOperations/DynamicHttpClient.FileUpload.cs +++ b/src/X1.DynamicClientCore/FileOperations/DynamicHttpClient.FileUpload.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; namespace X1.DynamicClientCore.Core { diff --git a/src/X1.DynamicClientCore/Infrastructure/CircuitBreakerManager.cs b/src/X1.DynamicClientCore/Infrastructure/CircuitBreakerManager.cs index 7c6458e..4602c52 100644 --- a/src/X1.DynamicClientCore/Infrastructure/CircuitBreakerManager.cs +++ b/src/X1.DynamicClientCore/Infrastructure/CircuitBreakerManager.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.Logging; using Polly; using Polly.CircuitBreaker; using Polly.Extensions.Http; -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; using X1.DynamicClientCore.Interfaces; namespace X1.DynamicClientCore.Infrastructure diff --git a/src/X1.DynamicClientCore/Infrastructure/ServiceEndpointManager.cs b/src/X1.DynamicClientCore/Infrastructure/ServiceEndpointManager.cs index fff0a38..e838f5b 100644 --- a/src/X1.DynamicClientCore/Infrastructure/ServiceEndpointManager.cs +++ b/src/X1.DynamicClientCore/Infrastructure/ServiceEndpointManager.cs @@ -1,5 +1,5 @@ -using X1.Domain.ExternalCommunication; -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; using X1.DynamicClientCore.Interfaces; namespace X1.DynamicClientCore.Infrastructure diff --git a/src/X1.DynamicClientCore/Interfaces/IAsyncHttpClient.cs b/src/X1.DynamicClientCore/Interfaces/IAsyncHttpClient.cs index d80e216..a7b1d43 100644 --- a/src/X1.DynamicClientCore/Interfaces/IAsyncHttpClient.cs +++ b/src/X1.DynamicClientCore/Interfaces/IAsyncHttpClient.cs @@ -1,4 +1,4 @@ -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; namespace X1.DynamicClientCore.Interfaces { diff --git a/src/X1.DynamicClientCore/Interfaces/ICircuitBreakerManager.cs b/src/X1.DynamicClientCore/Interfaces/ICircuitBreakerManager.cs index c0d43a2..7079d35 100644 --- a/src/X1.DynamicClientCore/Interfaces/ICircuitBreakerManager.cs +++ b/src/X1.DynamicClientCore/Interfaces/ICircuitBreakerManager.cs @@ -1,6 +1,6 @@ using Polly; using Polly.CircuitBreaker; -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; namespace X1.DynamicClientCore.Interfaces { diff --git a/src/X1.DynamicClientCore/Interfaces/IFileHttpClient.cs b/src/X1.DynamicClientCore/Interfaces/IFileHttpClient.cs index 4433e2e..7cf0b0d 100644 --- a/src/X1.DynamicClientCore/Interfaces/IFileHttpClient.cs +++ b/src/X1.DynamicClientCore/Interfaces/IFileHttpClient.cs @@ -1,4 +1,4 @@ -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; namespace X1.DynamicClientCore.Interfaces diff --git a/src/X1.DynamicClientCore/Interfaces/ISyncHttpClient.cs b/src/X1.DynamicClientCore/Interfaces/ISyncHttpClient.cs index 97f078e..60bcd7a 100644 --- a/src/X1.DynamicClientCore/Interfaces/ISyncHttpClient.cs +++ b/src/X1.DynamicClientCore/Interfaces/ISyncHttpClient.cs @@ -1,4 +1,4 @@ -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; namespace X1.DynamicClientCore.Interfaces { diff --git a/src/X1.DynamicClientCore/Service/InstrumentProtocolClient.cs b/src/X1.DynamicClientCore/Service/InstrumentProtocolClient.cs index 412dd83..56b08ab 100644 --- a/src/X1.DynamicClientCore/Service/InstrumentProtocolClient.cs +++ b/src/X1.DynamicClientCore/Service/InstrumentProtocolClient.cs @@ -4,8 +4,8 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using X1.Domain.ExternalCommunication; -using X1.Domain.ExternalCommunication.Models; +using X1.Domain.ThirdPartyDeviceHttpClient; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; using X1.DynamicClientCore.Interfaces; @@ -33,8 +33,8 @@ namespace X1.DynamicClientCore.Service /// 日志记录器 /// 当任何必需参数为null时抛出 public InstrumentProtocolClient( - IDynamicHttpClient dynamicHttpClient, - IServiceEndpointManager serviceEndpointManager, + IDynamicHttpClient dynamicHttpClient, + IServiceEndpointManager serviceEndpointManager, ILogger logger) { _dynamicHttpClient = dynamicHttpClient ?? throw new ArgumentNullException(nameof(dynamicHttpClient)); @@ -51,8 +51,8 @@ namespace X1.DynamicClientCore.Service /// 设备序列号,如果获取失败则返回空字符串 /// 当endpoint为null时抛出 public async Task GetDeviceSerialNumberAsync( - string instrumentNumber, - RequestOptions? options = null, + string? instrumentNumber, + RequestOptions? options = null, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(instrumentNumber)) @@ -61,13 +61,13 @@ namespace X1.DynamicClientCore.Service try { _logger.LogDebug("开始获取设备序列号,端点:{EndpointName}", instrumentNumber); - - + + // 发送HTTP请求获取设备信息 var response = await _dynamicHttpClient.GetAsync>( - instrumentNumber, - "System/serial-number", - options, + instrumentNumber, + "System/serial-number", + options, cancellationToken); if (response == null) @@ -78,15 +78,15 @@ namespace X1.DynamicClientCore.Service if (!response.IsSuccess) { - _logger.LogWarning("获取设备序列号失败:请求未成功,端点:{EndpointName},错误:{ErrorMessage}", + _logger.LogWarning("获取设备序列号失败:请求未成功,端点:{EndpointName},错误:{ErrorMessage}", instrumentNumber, response.Message ?? "未知错误"); return string.Empty; } var serialNumber = response.Data?.SerialNumber ?? string.Empty; - _logger.LogInformation("成功获取设备序列号:{SerialNumber},端点:{EndpointName}", + _logger.LogInformation("成功获取设备序列号:{SerialNumber},端点:{EndpointName}", serialNumber, instrumentNumber); - + return serialNumber; } catch (Exception ex) @@ -107,7 +107,7 @@ namespace X1.DynamicClientCore.Service /// 当request中的设备编号为空时抛出 public async Task StartNetworkAsync( StartCellularNetworkRequest request, - RequestOptions? options = null, + RequestOptions? options = null, CancellationToken cancellationToken = default) { if (request == null) @@ -170,7 +170,7 @@ namespace X1.DynamicClientCore.Service public async Task StopNetworkAsync( string instrumentNumber, StopCellularNetworkRequest request, - RequestOptions? options = null, + RequestOptions? options = null, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(instrumentNumber)) diff --git a/src/X1.DynamicClientCore/Service/TestTerminalRequestClient.cs b/src/X1.DynamicClientCore/Service/TestTerminalRequestClient.cs new file mode 100644 index 0000000..462cf10 --- /dev/null +++ b/src/X1.DynamicClientCore/Service/TestTerminalRequestClient.cs @@ -0,0 +1,108 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using X1.Domain.ThirdPartyDeviceHttpClient; +using X1.Domain.ThirdPartyDeviceHttpClient.ITerminal; +using X1.Domain.ThirdPartyDeviceHttpClient.Models; +using X1.DynamicClientCore.Interfaces; + +namespace X1.DynamicClientCore.Service +{ + /// + /// 测试终端HTTP客户端 + /// 提供与测试终端设备进行HTTP通信的功能 + /// + /// + /// 实现ITerminalHttpClient接口,专门用于测试终端设备的通信。 + /// 支持获取测试终端的机器码和系统信息等基础功能。 + /// + public class TestTerminalRequestClient : ITerminalHttpClient + { + private readonly ILogger _logger; + private readonly IDynamicHttpClient _dynamicHttpClient; + private readonly IServiceEndpointManager _serviceEndpointManager; + + /// + /// 初始化测试终端 + /// + /// 动态HTTP客户端 + /// 服务端点管理器 + /// 日志记录器 + /// 当任何必需参数为null时抛出 + public TestTerminalRequestClient( + IDynamicHttpClient dynamicHttpClient, + IServiceEndpointManager serviceEndpointManager, + ILogger logger) + { + _dynamicHttpClient = dynamicHttpClient ?? throw new ArgumentNullException(nameof(dynamicHttpClient)); + _serviceEndpointManager = serviceEndpointManager ?? throw new ArgumentNullException(nameof(serviceEndpointManager)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + /// + /// 获取测试终端机器码数据 + /// + /// 测试终端ID,用作服务名称 + /// 请求选项,包含超时、请求头等配置 + /// 取消令牌,用于取消异步操作 + /// 测试终端机器码数据,包含机器码和系统类型信息,如果获取失败则返回null + /// 当terminalId为null或空时抛出 + /// 当terminalId配置无效时抛出 + /// + /// 该方法通过HTTP请求调用测试终端的机器码API,获取设备的机器码和系统类型信息。 + /// 使用terminalId作为服务名称进行API调用,端点固定为"/api/v1/system/machine-code"。 + /// 返回的MachineCodeData包含机器码和系统类型两个字段。 + /// + public async Task GetDeviceSerialNumberAsync(string terminalId, RequestOptions? options = null, CancellationToken cancellationToken = default) + { + try + { + _logger.LogInformation("开始获取测试终端机器码数据,终端ID: {TerminalId}", terminalId); + + var endpoint = "/api/v1/system/machine-code"; + + // 调用机器码API + var response = await _dynamicHttpClient.GetAsync>( + terminalId, + endpoint, + options, + cancellationToken); + + if (response == null) + { + _logger.LogWarning("获取测试终端机器码响应为空,终端ID: {TerminalId}", terminalId); + return null; + } + + if (!response.Success) + { + _logger.LogError("获取测试终端机器码失败,终端ID: {TerminalId}, 错误信息: {Message}", + terminalId, response.Message); + return null; + } + + if (response.Data?.MachineCode == null) + { + _logger.LogWarning("测试终端机器码数据为空,终端ID: {TerminalId}", terminalId); + return null; + } + + var machineCode = response.Data.MachineCode; + var systemType = response.Data.SystemType; + + _logger.LogInformation("成功获取测试终端机器码数据,终端ID: {TerminalId}, 机器码: {MachineCode}, 系统类型: {SystemType}", + terminalId, machineCode, systemType); + + return response.Data; + } + catch (Exception ex) + { + _logger.LogError(ex, "获取测试终端机器码数据时发生异常,终端ID: {TerminalId}", terminalId); + return null; + } + } + } +} diff --git a/src/X1.Infrastructure/Configurations/Terminal/TerminalDeviceConfiguration.cs b/src/X1.Infrastructure/Configurations/Terminal/TerminalDeviceConfiguration.cs new file mode 100644 index 0000000..fbad63e --- /dev/null +++ b/src/X1.Infrastructure/Configurations/Terminal/TerminalDeviceConfiguration.cs @@ -0,0 +1,91 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using CellularManagement.Domain.Entities.Terminal; + +namespace CellularManagement.Infrastructure.Configurations.Terminal; + +/// +/// 终端设备实体配置 +/// +public class TerminalDeviceConfiguration : IEntityTypeConfiguration +{ + /// + /// 配置终端设备实体 + /// + /// 实体类型构建器 + public void Configure(EntityTypeBuilder builder) + { + // 表名 + builder.ToTable("tb_terminal_devices"); + + // 主键 + builder.HasKey(x => x.Id); + + // 属性配置 + builder.Property(x => x.Id) + .IsRequired() + .HasMaxLength(450); + + builder.Property(x => x.Name) + .IsRequired() + .HasMaxLength(100); + + builder.Property(x => x.SerialNumber) + .IsRequired() + .HasMaxLength(50); + + builder.Property(x => x.DeviceCode) + .IsRequired() + .HasMaxLength(50); + + builder.Property(x => x.Description) + .HasMaxLength(500); + + builder.Property(x => x.AgentPort) + .IsRequired(); + + builder.Property(x => x.IpAddress) + .IsRequired() + .HasMaxLength(45); + + builder.Property(x => x.IsEnabled) + .IsRequired() + .HasDefaultValue(true); + + builder.Property(x => x.DeviceType) + .IsRequired() + .HasConversion() + .HasDefaultValue(TerminalDeviceType.Windows); + + // 审计字段 + builder.Property(x => x.CreatedAt) + .IsRequired(); + + builder.Property(x => x.UpdatedAt); + + builder.Property(x => x.CreatedBy) + .IsRequired() + .HasMaxLength(450); + + builder.Property(x => x.UpdatedBy) + .HasMaxLength(450); + + // 索引 + builder.HasIndex(x => x.SerialNumber) + .IsUnique(); + + builder.HasIndex(x => x.DeviceCode) + .IsUnique(); + + builder.HasIndex(x => x.IpAddress); + + builder.HasIndex(x => x.IsEnabled); + + builder.HasIndex(x => x.DeviceType); + + builder.HasIndex(x => x.CreatedAt); + + // 软删除过滤器 + builder.HasQueryFilter(x => !x.IsDeleted); + } +} diff --git a/src/X1.Infrastructure/Context/AppDbContext.cs b/src/X1.Infrastructure/Context/AppDbContext.cs index 01dfcaa..bb0be3a 100644 --- a/src/X1.Infrastructure/Context/AppDbContext.cs +++ b/src/X1.Infrastructure/Context/AppDbContext.cs @@ -6,6 +6,7 @@ using CellularManagement.Domain.Entities; using CellularManagement.Domain.Entities.Logging; using CellularManagement.Domain.Entities.Device; using CellularManagement.Domain.Entities.NetworkProfile; +using CellularManagement.Domain.Entities.Terminal; namespace CellularManagement.Infrastructure.Context; @@ -82,6 +83,11 @@ public class AppDbContext : IdentityDbContext /// public DbSet Stack_CoreIMS_Bindings { get; set; } = null!; + /// + /// 终端设备集合 + /// + public DbSet TerminalDevices { get; set; } = null!; + /// /// 初始化数据库上下文 /// diff --git a/src/X1.WebSocket/Extensions/ServiceCollectionExtensions.cs b/src/X1.WebSocket/Extensions/ServiceCollectionExtensions.cs index e7d5514..5184ca8 100644 --- a/src/X1.WebSocket/Extensions/ServiceCollectionExtensions.cs +++ b/src/X1.WebSocket/Extensions/ServiceCollectionExtensions.cs @@ -37,7 +37,7 @@ public static class ServiceCollectionExtensions services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - + services.AddSingleton(); // 注册后台服务 services.AddHostedService(); services.AddHostedService(); diff --git a/src/X1.WebSocket/Handlers/ProtocolMessageHandler.cs b/src/X1.WebSocket/Handlers/ProtocolMessageHandler.cs index e6560cb..a3c1839 100644 --- a/src/X1.WebSocket/Handlers/ProtocolMessageHandler.cs +++ b/src/X1.WebSocket/Handlers/ProtocolMessageHandler.cs @@ -33,11 +33,11 @@ namespace CellularManagement.WebSocket.Handlers public async Task HandleAsync(WebSocketMessage message) { var messageData = Encoding.UTF8.GetString(message.Data); - _logger.LogDebug("收到协议消息,连接ID:{ConnectionId},数据长度:{DataLength}字节", + _logger.LogDebug("收到协议消息,连接ID:{ConnectionId},数据长度:{DataLength}字节", message.ConnectionId, message.Data.Length); - - ProcessProtocolMessage(messageData); - + + ProcessProtocolMessage(messageData); + var response = new WebSocketMessage { ConnectionId = message.ConnectionId, @@ -64,7 +64,7 @@ namespace CellularManagement.WebSocket.Handlers try { var protocolMessage = JsonSerializer.Deserialize(messageData, _jsonOptions); - + if (protocolMessage?.Payload?.Message == null) { _logger.LogWarning("协议消息载荷为空或格式无效"); @@ -81,7 +81,7 @@ namespace CellularManagement.WebSocket.Handlers } ProcessProtocolLogs(protocolMessage.Payload.Message); - + _logger.LogInformation("协议消息处理完成,成功处理 {MessageCount} 条消息", messageCount); } catch (JsonException jsonEx) @@ -158,7 +158,7 @@ namespace CellularManagement.WebSocket.Handlers Message = !string.IsNullOrEmpty(log.Message) ? log.Message : "N/A" }; - _logger.LogDebug("处理协议日志 - 【ID】{Id} 【时间】{Time} 【层】{Layer} 【UEID】{UEID} 【IMSI】{IMSI} 【PLMN】{PLMN} 【小区】{CellID} 【方向】{Direction} 【信息】{Info} 【消息】{Message}", + _logger.LogDebug("处理协议日志 - 【ID】{Id} 【时间】{Time} 【层】{Layer} 【UEID】{UEID} 【IMSI】{IMSI} 【PLMN】{PLMN} 【小区】{CellID} 【方向】{Direction} 【信息】{Info} 【消息】{Message}", logInfo.Id, logInfo.Time, logInfo.Layer, logInfo.UEID, logInfo.IMSI, logInfo.PLMN, logInfo.CellID, logInfo.Direction, logInfo.Info, logInfo.Message); // 这里可以添加具体的业务逻辑处理 diff --git a/src/X1.WebSocket/Handlers/TerminalMessageHandler.cs b/src/X1.WebSocket/Handlers/TerminalMessageHandler.cs new file mode 100644 index 0000000..a26d7a6 --- /dev/null +++ b/src/X1.WebSocket/Handlers/TerminalMessageHandler.cs @@ -0,0 +1,38 @@ +using CellularManagement.WebSocket.Models; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CellularManagement.WebSocket.Handlers +{ + public class TerminalMessageHandler : IWebSocketMessageHandler + { + private readonly ILogger _logger; + + public TerminalMessageHandler(ILogger logger) + { + _logger = logger; + } + + public string MessageType => "terminal"; + + public async Task HandleAsync(WebSocketMessage message) + { + var messageData = Encoding.UTF8.GetString(message.Data); + _logger.LogDebug("收到终端数据,连接ID:{ConnectionId} Data:{messageData}", message.ConnectionId, messageData); + + await Task.CompletedTask.ConfigureAwait(false); + + var response = new WebSocketMessage + { + ConnectionId = message.ConnectionId, + MessageType = System.Net.WebSockets.WebSocketMessageType.Text, + NeedQueue = false + }; + return response; + } + } +} diff --git a/src/modify.md b/src/modify.md index 49589a0..e168e44 100644 --- a/src/modify.md +++ b/src/modify.md @@ -2,6 +2,75 @@ ## 2024年修改记录 +### 修复CreateTerminalDeviceCommandHandler中的空引用警告和并发问题 + +#### 修改文件: +`X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommandHandler.cs` + +#### 修改内容: + +1. **问题描述**: + - 在第95行出现可能的空引用警告 + - `deviceInfoResult.ErrorMessages` 可能为 null,但 `CreateFailure(List errorMessages)` 方法期望非空参数 + - 设备编码生成逻辑存在并发问题:多个请求可能生成相同的设备编码 + +2. **解决方案**: + - 使用空合并操作符 `??` 提供默认值 + - 使用空断言操作符 `!` 处理已知非空的Data属性 + - 重构设备编码生成逻辑,添加重试机制和并发处理 + - 将原来的 `GenerateDeviceCodeAsync` 和编码检查逻辑合并为 `GenerateUniqueDeviceCodeAsync` + +3. **修改代码**: + ```csharp + // 修改前 - 空引用问题 + return OperationResult.CreateFailure(deviceInfoResult.ErrorMessages); + + // 修改后 - 空引用问题 + return OperationResult.CreateFailure(deviceInfoResult.ErrorMessages ?? new List { "获取设备信息失败" }); + + // 修改前 - Data空引用问题 + var serialNumber = deviceInfoResult.Data.SerialNumber; + var deviceType = deviceInfoResult.Data.DeviceType; + + // 修改后 - Data空引用问题 + var serialNumber = deviceInfoResult.Data!.SerialNumber; + var deviceType = deviceInfoResult.Data!.DeviceType; + + // 修改前 - 并发问题 + var deviceCode = await GenerateDeviceCodeAsync(serialNumber, cancellationToken); + if (await _deviceRepository.DeviceCodeExistsAsync(deviceCode, cancellationToken)) + { + return OperationResult.CreateFailure($"终端设备编码 {deviceCode} 已存在"); + } + + // 修改后 - 并发问题 + var deviceCode = await GenerateUniqueDeviceCodeAsync(cancellationToken); + ``` + +4. **新的GenerateUniqueDeviceCodeAsync方法特性**: + - 使用短UUID(8位)生成简洁的设备编码 + - 格式:`TERM-{8位短UUID}`,如 `TERM-a1b2c3d4` + - 极低的冲突概率,理论上几乎不可能重复 + - 如果发生冲突,自动添加时间戳后缀(6位数字) + - 简洁高效的实现,无需复杂的重试逻辑 + - 无需序列号参数,使用纯UUID生成方式 + - 完整的日志记录,便于调试和监控 + +5. **技术细节**: + - 使用 `??` 空合并操作符处理可能的 null 值 + - 提供有意义的默认错误消息 + - 使用 `Guid.NewGuid().ToString("N").Substring(0, 8)` 生成8位短UUID + - 使用 `DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() % 1000000` 生成6位时间戳后缀 + - 保持代码的简洁性和高效性 + +#### 修改时间: +2024年 + +#### 修改原因: +解决编译警告,确保代码的健壮性,避免运行时出现空引用异常。同时解决高并发场景下设备编码重复的问题,提高系统的可靠性和稳定性。 + +--- + ### ADB操作和AT操作控制器实现 #### 修改文件: @@ -1154,4 +1223,560 @@ - ✅ 控制器已完善,参考ProtocolVersionsController模式 - ✅ 统一的错误处理和日志记录 - ✅ 符合DDD和CQRS架构模式 -- ✅ 支持完整的CRUD操作 \ No newline at end of file +- ✅ 支持完整的CRUD操作 + +--- + +## 2025-01-13 TerminalDevice 添加设备类型枚举 + +### 修改文件 +1. `X1.Domain/Entities/Terminal/TerminalDeviceType.cs` - 新增设备类型枚举 +2. `X1.Domain/Entities/Terminal/TerminalDevice.cs` - 添加设备类型属性 +3. `X1.Application/Features/TerminalDevices/Queries/GetTerminalDevices/GetTerminalDevicesResponse.cs` - 更新DTO +4. `X1.Application/Features/TerminalDevices/Queries/GetTerminalDevices/GetTerminalDevicesQueryHandler.cs` - 更新映射 +5. `X1.Application/Features/TerminalDevices/Queries/GetTerminalDeviceById/GetTerminalDeviceByIdResponse.cs` - 更新响应 +6. `X1.Application/Features/TerminalDevices/Queries/GetTerminalDeviceById/GetTerminalDeviceByIdQueryHandler.cs` - 更新映射 +7. `X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommand.cs` - 添加设备类型参数 +8. `X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceResponse.cs` - 更新响应 +9. `X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommandHandler.cs` - 更新处理逻辑 +10. `X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceCommand.cs` - 添加设备类型参数 +11. `X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceResponse.cs` - 更新响应 +12. `X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceCommandHandler.cs` - 更新处理逻辑 +13. `X1.Infrastructure/Context/AppDbContext.cs` - 添加TerminalDevice DbSet +14. `X1.Infrastructure/Configurations/Terminal/TerminalDeviceConfiguration.cs` - 新增数据库配置 + +### 修改内容 + +1. **设备类型枚举创建**: + - 创建了 `TerminalDeviceType` 枚举 + - 包含 `Windows = 1` 和 `Linux = 2` 两个选项 + - 用于区分终端设备的操作系统类型 + +2. **TerminalDevice实体更新**: + - 添加了 `DeviceType` 属性,类型为 `TerminalDeviceType` + - 默认值为 `TerminalDeviceType.Windows` + - 更新了 `Create` 和 `Update` 方法,添加设备类型参数 + - 在数据库中以整数形式存储枚举值 + +3. **Application层更新**: + - **DTO和响应类**:所有相关的DTO和响应类都添加了 `DeviceType` 字段 + - **查询处理器**:更新了映射逻辑,将枚举值转换为字符串 + - **命令类**:添加了设备类型参数,默认值为 "Windows" + - **命令处理器**:添加了枚举解析逻辑和验证 + +4. **数据库配置**: + - 在 `AppDbContext` 中添加了 `TerminalDevices` DbSet + - 创建了 `TerminalDeviceConfiguration` 配置类 + - 配置了设备类型字段的数据库映射(使用整数存储) + - 添加了相关的索引和约束 + +5. **技术特性**: + - 使用枚举确保类型安全 + - 在数据库中存储为整数,提高性能 + - 在API中返回字符串,便于前端使用 + - 完整的验证和错误处理 + - 向后兼容,现有数据默认为Windows类型 + +6. **设计原则**: + - 遵循DDD原则,使用枚举表示领域概念 + - 保持与现有架构的一致性 + - 提供完整的CRUD操作支持 + - 确保数据完整性和类型安全 + +### 完成状态 +- ✅ 设备类型枚举创建完成 +- ✅ TerminalDevice实体更新完成 +- ✅ Application层所有相关文件更新完成 +- ✅ 数据库配置完成 +- ✅ 类型安全和验证逻辑完整 +- ✅ 向后兼容性确保完成 + +--- + +## 2025-01-13 TerminalDevice 数据库表命名规范修正 + +### 修改文件 +`X1.Infrastructure/Configurations/Terminal/TerminalDeviceConfiguration.cs` + +### 修改内容 + +1. **问题描述**: + - 原表名 `"TerminalDevices"` 不符合项目的命名规范 + - 项目要求使用 `tb_` 前缀并且都是小写 + +2. **修正方案**: + - 将表名从 `"TerminalDevices"` 修改为 `"tb_terminal_devices"` + - 符合项目的命名规范:`tb_` 前缀 + 全小写 + 下划线分隔 + +3. **具体修改**: + ```csharp + // 修改前 + builder.ToTable("TerminalDevices"); + + // 修改后 + builder.ToTable("tb_terminal_devices"); + ``` + +4. **命名规范说明**: + - `tb_`:表名前缀,表示这是一个数据库表 + - `terminal_devices`:实体名称的小写形式,使用下划线分隔单词 + - 符合项目的统一命名约定 + +### 完成状态 +- ✅ 表名修正完成 +- ✅ 符合项目命名规范 +- ✅ 与现有数据库表命名保持一致 + +--- + +## 2025-01-13 TerminalDevice 命令字段限制修改 + +### 修改文件 +1. `X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommand.cs` +2. `X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommandHandler.cs` +3. `X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceCommand.cs` +4. `X1.Application/Features/TerminalDevices/Commands/UpdateTerminalDevice/UpdateTerminalDeviceCommandHandler.cs` +5. `X1.Domain/Entities/Terminal/TerminalDevice.cs` + +### 修改内容 + +1. **CreateTerminalDeviceCommand 修改**: + - **移除字段**:删除了 `DeviceType` 字段,不再由用户填写 + - **自动检测**:设备类型由系统根据设备连接信息自动检测 + - **业务逻辑**:系统会尝试获取设备系统信息来判断是Windows还是Linux + +2. **CreateTerminalDeviceCommandHandler 修改**: + - **自动检测逻辑**:添加了 `DetectDeviceTypeAsync` 方法 + - **系统信息检测**:通过 `GetDeviceSystemInfoAsync` 获取设备系统信息 + - **智能判断**:根据系统信息中的关键词判断设备类型 + - **默认处理**:如果无法检测,默认使用Windows类型 + - **错误处理**:完整的异常处理和日志记录 + +3. **UpdateTerminalDeviceCommand 修改**: + - **字段限制**:只保留 `DeviceId`、`Description` 和 `IsEnabled` 字段 + - **移除字段**:删除了 `DeviceName`、`IpAddress`、`AgentPort`、`DeviceType` 字段 + - **业务逻辑**:只允许修改设备描述和启用状态,保护核心配置信息 + +4. **UpdateTerminalDeviceCommandHandler 修改**: + - **更新逻辑**:只更新允许修改的字段(描述和启用状态) + - **验证简化**:移除了对已删除字段的验证 + - **方法调用**:使用专门的 `UpdateDescription` 和 `Enable/Disable` 方法 + - **审计信息**:正确更新审计信息 + +5. **TerminalDevice 实体修改**: + - **新增方法**:添加了 `UpdateDescription` 方法用于更新描述 + - **新增方法**:添加了 `UpdateAuditInfo` 方法用于更新审计信息 + - **封装性**:保持实体的封装性,通过方法修改状态 + +6. **技术特性**: + - **自动检测**:设备类型自动检测,无需用户干预 + - **字段保护**:核心配置字段不允许修改,确保数据安全 + - **业务逻辑**:符合实际业务需求,只允许修改非关键信息 + - **错误处理**:完整的异常处理和日志记录 + +### 完成状态 +- ✅ CreateTerminalDeviceCommand 设备类型字段移除完成 +- ✅ 自动设备类型检测逻辑实现完成 +- ✅ UpdateTerminalDeviceCommand 字段限制完成 +- ✅ 命令处理器逻辑更新完成 +- ✅ TerminalDevice 实体方法扩展完成 +- ✅ 业务逻辑安全性确保完成 + +--- + +## 2025-01-13 TerminalDevice DTO 序列号字段移除 + +### 修改文件 +1. `X1.Application/Features/TerminalDevices/Queries/GetTerminalDevices/GetTerminalDevicesResponse.cs` +2. `X1.Application/Features/TerminalDevices/Queries/GetTerminalDevices/GetTerminalDevicesQueryHandler.cs` +3. `X1.Application/Features/TerminalDevices/Queries/GetTerminalDeviceById/GetTerminalDeviceByIdResponse.cs` +4. `X1.Application/Features/TerminalDevices/Queries/GetTerminalDeviceById/GetTerminalDeviceByIdQueryHandler.cs` + +### 修改内容 + +1. **GetTerminalDevicesResponse.cs 修改**: + - **移除字段**:从 `TerminalDeviceDto` 中删除了 `SerialNumber` 字段 + - **安全考虑**:序列号是敏感信息,不应该在列表中显示 + - **数据保护**:保护设备序列号信息不被泄露 + +2. **GetTerminalDevicesQueryHandler.cs 修改**: + - **映射移除**:移除了对 `SerialNumber` 字段的映射 + - **数据过滤**:确保列表查询不返回序列号信息 + - **性能优化**:减少不必要的数据传输 + +3. **GetTerminalDeviceByIdResponse.cs 修改**: + - **移除字段**:从详情响应中删除了 `SerialNumber` 字段 + - **一致性**:与列表查询保持一致,都不显示序列号 + - **安全策略**:统一的安全策略,保护敏感信息 + +4. **GetTerminalDeviceByIdQueryHandler.cs 修改**: + - **映射移除**:移除了对 `SerialNumber` 字段的映射 + - **详情保护**:即使是在详情查询中也不显示序列号 + - **数据安全**:确保序列号信息不被任何API端点泄露 + +5. **安全特性**: + - **信息保护**:序列号作为设备唯一标识,属于敏感信息 + - **访问控制**:通过API层面控制敏感信息的访问 + - **数据最小化**:只返回必要的设备信息 + - **隐私保护**:符合数据隐私保护原则 + +### 完成状态 +- ✅ GetTerminalDevicesResponse 序列号字段移除完成 +- ✅ GetTerminalDevicesQueryHandler 映射移除完成 +- ✅ GetTerminalDeviceByIdResponse 序列号字段移除完成 +- ✅ GetTerminalDeviceByIdQueryHandler 映射移除完成 +- ✅ 数据安全保护策略实施完成 + +### TestTerminalRequestClient GetDeviceSerialNumberAsync 方法完善 + +#### 修改文件: +1. `X1.Domain/ThirdPartyDeviceHttpClient/Models/MachineCodeResponse.cs` - 新增机器码响应模型 +2. `X1.DynamicClientCore/Service/TestTerminalRequestClient.cs` - 完善GetDeviceSerialNumberAsync方法 + +#### 修改内容: + +1. **功能描述**: + - 完善了 `TestTerminalRequestClient` 的 `GetDeviceSerialNumberAsync` 方法 + - 实现了调用机器码API获取设备序列号的功能 + - 创建了对应的响应模型来匹配API返回的数据结构 + +2. **新增响应模型**: + - **MachineCodeResponse**:机器码响应模型 + - `Success`:是否成功 + - `Message`:响应消息 + - `Data`:响应数据 + - **MachineCodeData**:机器码数据 + - `MachineCode`:机器码(设备序列号) + - `SystemType`:系统类型 + +3. **API调用实现**: + - **端点**:`/api/v1/system/machine-code` + - **服务名称**:`test-terminal` + - **HTTP方法**:GET + - **响应处理**:完整的成功/失败状态检查 + +4. **技术特性**: + - **异步操作**:使用 `async/await` 模式 + - **错误处理**:完整的异常捕获和日志记录 + - **参数验证**:检查响应数据的有效性 + - **日志记录**:详细的操作日志,包括开始、成功、失败信息 + - **资源清理**:确保异常情况下的资源正确释放 + +5. **业务逻辑**: + - 调用机器码API获取设备序列号 + - 验证API响应的成功状态 + - 提取机器码作为设备序列号返回 + - 记录系统类型信息用于调试 + - 失败时返回空字符串 + +6. **响应格式匹配**: + ```json + { + "success": true, + "message": "机器码获取成功", + "data": { + "machine_code": "03000200-0400-0500-0006-000700080009", + "system_type": "windows" + } + } + ``` + +7. **设计原则**: + - 遵循现有架构模式 + - 完整的错误处理和日志记录 + - 使用依赖注入管理依赖关系 + - 支持取消令牌和异步操作 + - 统一的响应格式处理 + +#### 修改时间: +2025年1月13日 + +#### 修改原因: +需要完善 `TestTerminalRequestClient` 的 `GetDeviceSerialNumberAsync` 方法,实现从指定API端点获取设备机器码的功能,为终端设备管理提供真实的设备序列号获取能力。 + +### MachineCodeResponse 重构为 TestTerminalResponse + +#### 修改文件: +1. `X1.Domain/ThirdPartyDeviceHttpClient/Models/MachineCodeResponse.cs` - 重构响应模型 +2. `X1.DynamicClientCore/Service/TestTerminalRequestClient.cs` - 更新使用新的响应模型 + +#### 修改内容: + +1. **功能描述**: + - 将 `MachineCodeResponse` 重构为更通用的 `TestTerminalResponse` + - 使测试终端相关的所有API都可以使用这个响应实体 + - 直接删除向后兼容的 `MachineCodeResponse` 类,简化代码结构 + +2. **响应模型重构**: + - **TestTerminalResponse**:泛型版本,支持任意数据类型 + - `Success`:是否成功 + - `Message`:响应消息 + - `Data`:泛型响应数据 + - **TestTerminalResponse**:非泛型版本,默认使用 `MachineCodeData` + - **MachineCodeResponse**:已删除,不再提供向后兼容 + +3. **数据模型**: + - **MachineCodeData**:机器码数据模型 + - `MachineCode`:机器码(设备序列号) + - `SystemType`:系统类型 + +4. **技术特性**: + - **泛型设计**:支持任意数据类型的响应 + - **简化结构**:删除不必要的向后兼容类 + - **类型安全**:使用泛型确保编译时类型检查 + - **可扩展性**:未来可以轻松添加新的数据类型 + +5. **使用示例**: + ```csharp + // 使用泛型版本(推荐) + var response = await _dynamicHttpClient.GetAsync>( + serviceName, endpoint, options, cancellationToken); + + // 使用非泛型版本(简化) + var response = await _dynamicHttpClient.GetAsync( + serviceName, endpoint, options, cancellationToken); + ``` + +6. **设计原则**: + - **单一职责**:专注于测试终端响应格式 + - **开闭原则**:对扩展开放,对修改封闭 + - **简洁性**:删除不必要的向后兼容代码 + - **类型安全**:编译时类型检查 + +7. **未来扩展**: + - 可以轻松添加新的数据类型,如设备状态、网络配置等 + - 所有测试终端API都可以使用统一的响应格式 + - 支持不同的业务场景和数据需求 + +#### 修改时间: +2025年1月13日 + +#### 修改原因: +需要将机器码响应模型重构为更通用的测试终端响应模型,使所有测试终端相关的API都可以使用统一的响应格式,提高代码的可复用性和类型安全性。删除不必要的向后兼容代码,简化代码结构。 + +### TestTerminalRequestClient 添加 GetMachineCodeDataAsync 方法 + +#### 修改文件: +`X1.DynamicClientCore/Service/TestTerminalRequestClient.cs` - 添加获取完整机器码数据的方法 + +#### 修改内容: + +1. **功能描述**: + - 添加了 `GetMachineCodeDataAsync` 方法,返回完整的 `MachineCodeData` 对象 + - 重构了 `GetDeviceSerialNumberAsync` 方法,使其调用新的方法 + - 保持接口兼容性的同时,提供更丰富的数据返回 + +2. **新增方法**: + - **GetMachineCodeDataAsync**:获取完整的机器码数据 + - 返回类型:`Task` + - 包含机器码和系统类型信息 + - 完整的错误处理和日志记录 + +3. **方法重构**: + - **GetDeviceSerialNumberAsync**:重构为调用 `GetMachineCodeDataAsync` + - 保持原有接口兼容性 + - 只返回机器码字符串 + - 简化了实现逻辑 + +4. **技术特性**: + - **代码复用**:避免重复的API调用逻辑 + - **类型安全**:返回强类型的 `MachineCodeData` 对象 + - **错误处理**:统一的异常处理和日志记录 + - **向后兼容**:保持原有接口不变 + +5. **使用示例**: + ```csharp + // 获取完整机器码数据(推荐) + var machineCodeData = await client.GetMachineCodeDataAsync(instrumentNumber); + if (machineCodeData != null) + { + var machineCode = machineCodeData.MachineCode; + var systemType = machineCodeData.SystemType; + } + + // 获取机器码字符串(兼容原有接口) + var serialNumber = await client.GetDeviceSerialNumberAsync(instrumentNumber); + ``` + +6. **设计原则**: + - **单一职责**:每个方法专注于特定功能 + - **代码复用**:避免重复的API调用逻辑 + - **向后兼容**:保持原有接口不变 + - **类型安全**:提供强类型的数据返回 + +7. **业务价值**: + - 提供更丰富的设备信息(机器码 + 系统类型) + - 支持更复杂的业务逻辑处理 + - 保持与现有代码的兼容性 + - 提高代码的可维护性 + +#### 修改时间: +2025年1月13日 + +#### 修改原因: +需要提供获取完整机器码数据的功能,包括机器码和系统类型信息,同时保持与现有接口的兼容性,为测试终端管理提供更丰富的数据支持。 + +### TestTerminalRequestClient 最终优化 + +#### 修改文件: +1. `X1.Domain/ThirdPartyDeviceHttpClient/ITerminal/IBaseTerminalClient.cs` - 更新接口定义 +2. `X1.DynamicClientCore/Service/TestTerminalRequestClient.cs` - 优化实现和注释 + +#### 修改内容: + +1. **接口定义优化**: + - 将 `GetDeviceSerialNumberAsync` 方法返回类型从 `Task` 改为 `Task` + - 参数名从 `instrumentNumber` 改为 `terminalId` + - 更新方法注释,明确返回测试终端机器码数据 + +2. **实现优化**: + - 移除重复的 `GetMachineCodeDataAsync` 方法 + - 直接使用 `GetDeviceSerialNumberAsync` 返回 `MachineCodeData` 对象 + - 使用 `terminalId` 作为服务名称,而不是硬编码的 "test-terminal" + - 添加完整的XML注释,包含参数说明、返回值说明、异常说明和备注 + +3. **技术特性**: + - **简化设计**:移除重复方法,统一使用一个方法 + - **正确命名**:使用 `terminalId` 作为服务名称 + - **完整注释**:提供详细的XML文档注释 + - **类型安全**:返回强类型的 `MachineCodeData` 对象 + +4. **XML注释内容**: + - 参数说明:明确 `terminalId` 用作服务名称 + - 返回值说明:详细描述返回的数据结构 + - 异常说明:列出可能抛出的异常类型 + - 备注说明:解释方法的工作原理和API调用细节 + +5. **使用示例**: + ```csharp + // 获取测试终端机器码数据 + var machineCodeData = await client.GetDeviceSerialNumberAsync("terminal-001"); + if (machineCodeData != null) + { + var machineCode = machineCodeData.MachineCode; + var systemType = machineCodeData.SystemType; + } + ``` + +6. **设计原则**: + - **单一职责**:一个方法专注于获取机器码数据 + - **正确命名**:参数名和方法名符合业务语义 + - **完整文档**:提供详细的XML注释 + - **类型安全**:使用强类型返回数据 + +#### 修改时间: +2025年1月13日 + +#### 修改原因: +优化TestTerminalRequestClient的设计,简化方法结构,修正命名规范,使用正确的服务名称,并提供完整的XML文档注释,提高代码的可读性和可维护性。 + +### CreateTerminalDeviceCommandHandler 设备类型检测优化 + +#### 修改文件: +`X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommandHandler.cs` - 优化设备类型检测逻辑 + +#### 修改内容: + +1. **依赖注入修复**: + - 将 `IBaseInstrumentClient` 替换为 `IBaseTerminalClient` + - 更新字段名从 `_instrumentClient` 到 `_terminalClient` + - 添加正确的using语句引用 + +2. **设备类型检测优化**: + - 实现真实的设备类型检测逻辑 + - 通过调用 `GetDeviceSerialNumberAsync` 获取系统类型信息 + - 根据系统类型字符串智能判断设备类型 + - 支持Linux和Windows系统的识别 + +3. **系统类型识别逻辑**: + - **Linux系统识别**:linux、ubuntu、centos、debian、fedora、redhat、suse、unix + - **Windows系统识别**:windows、win、nt + - **默认处理**:未知系统类型默认使用Windows + +4. **技术特性**: + - **真实检测**:基于API返回的系统类型信息进行检测 + - **智能识别**:支持多种Linux发行版和Windows版本 + - **错误处理**:检测失败时使用默认类型 + - **资源管理**:自动清理临时服务端点 + +5. **方法调用修复**: + - 更新 `GetDeviceSerialNumberAsync` 方法调用 + - 处理返回的 `MachineCodeData` 对象 + - 提取 `MachineCode` 和 `SystemType` 信息 + - 完整的null检查和异常处理 + +6. **日志记录优化**: + - 记录设备类型检测过程 + - 记录系统类型和检测结果 + - 记录检测失败的原因 + - 详细的调试信息 + +7. **使用示例**: + ```csharp + // 设备类型检测流程 + var deviceType = await DetectDeviceTypeByPortsAsync(request, serviceEndpoint, cancellationToken); + // 根据API返回的系统类型自动判断是Windows还是Linux + ``` + +#### 修改时间: +2025年1月13日 + +#### 修改原因: +需要实现真实的设备类型检测功能,通过API获取的系统类型信息智能判断设备是Windows还是Linux系统,提高设备管理的准确性和自动化程度。 + +### CreateTerminalDeviceCommandHandler API调用优化 + +#### 修改文件: +`X1.Application/Features/TerminalDevices/Commands/CreateTerminalDevice/CreateTerminalDeviceCommandHandler.cs` - 优化API调用逻辑 + +#### 修改内容: + +1. **API调用优化**: + - 合并序列号获取和设备类型检测为一次API调用 + - 移除重复的 `DetectDeviceTypeByPortsAsync` 方法 + - 创建 `DeviceInfo` 数据传输对象,包含序列号和设备类型 + +2. **新增DeviceInfo类**: + - `SerialNumber`:设备序列号 + - `DeviceType`:设备类型(Windows/Linux) + - 用于封装API返回的完整设备信息 + +3. **方法重构**: + - `GetDeviceSerialNumberAsync` → `GetDeviceInfoAsync` + - 在一次API调用中同时获取序列号和系统类型 + - 根据系统类型自动判断设备类型 + - 返回包含完整信息的 `DeviceInfo` 对象 + +4. **技术特性**: + - **性能优化**:减少API调用次数,从2次减少到1次 + - **数据完整性**:确保序列号和系统类型信息的一致性 + - **错误处理**:统一的错误处理和资源清理 + - **类型安全**:使用强类型的 `DeviceInfo` 对象 + +5. **工作流程优化**: + ``` + 原流程:获取序列号 → 检测设备类型(重复API调用) + 新流程:获取设备信息(一次API调用,包含序列号和系统类型) + ``` + +6. **代码简化**: + - 移除重复的API调用逻辑 + - 简化主处理流程 + - 统一的资源管理和错误处理 + +7. **使用示例**: + ```csharp + // 一次API调用获取完整设备信息 + var deviceInfoResult = await GetDeviceInfoAsync(request, serviceEndpoint, cancellationToken); + if (deviceInfoResult.IsSuccess) + { + var serialNumber = deviceInfoResult.Data.SerialNumber; + var deviceType = deviceInfoResult.Data.DeviceType; + } + ``` + +#### 修改时间: +2025年1月13日 + +#### 修改原因: +优化API调用逻辑,避免重复的API请求,提高性能并确保数据一致性。将序列号获取和设备类型检测合并为一次API调用,简化代码结构并提升用户体验。 \ No newline at end of file