From 43135fb0652a9b38ecf7003f7f36bf9ceb75debb Mon Sep 17 00:00:00 2001 From: hyh Date: Fri, 1 Aug 2025 19:09:43 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E7=AE=80=E5=8C=96GetRuntimesByDeviceCodesA?= =?UTF-8?q?sync=E6=96=B9=E6=B3=95=EF=BC=8C=E5=8F=AA=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E9=9C=80=E8=A6=81=E7=9A=84=E5=9B=9B=E4=B8=AA=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DeviceManagementService.cs | 59 +- .../Entities/Device/CellularDeviceRuntime.cs | 28 + src/X1.Domain/Models/DeviceRuntimeDto.cs | 27 + .../ICellularDeviceRuntimeRepository.cs | 3 +- .../Device/CellularDeviceRuntimeRepository.cs | 13 +- .../Controllers/ProtocolLogsController.cs | 102 +-- src/X1.WebUI/src/constants/api.ts | 1 + .../src/services/protocolLogsService.ts | 144 ++++ src/modify.md | 776 +----------------- 9 files changed, 263 insertions(+), 890 deletions(-) create mode 100644 src/X1.Domain/Models/DeviceRuntimeDto.cs create mode 100644 src/X1.WebUI/src/services/protocolLogsService.ts diff --git a/src/X1.Application/BackendServiceManager/DeviceManagementService.cs b/src/X1.Application/BackendServiceManager/DeviceManagementService.cs index 6e13e2d..ca72954 100644 --- a/src/X1.Application/BackendServiceManager/DeviceManagementService.cs +++ b/src/X1.Application/BackendServiceManager/DeviceManagementService.cs @@ -149,8 +149,7 @@ namespace X1.Application.BackendServiceManager var unitOfWork = serviceProvider.GetRequiredService(); // 使用事务处理 - using var transaction = await unitOfWork.BeginTransactionAsync(IsolationLevel.ReadCommitted, cancellationToken); - try + await unitOfWork.ExecuteTransactionAsync(async () => { // 批量插入到数据库 await repository.AddRangeAsync(validLogs, cancellationToken); @@ -158,24 +157,8 @@ namespace X1.Application.BackendServiceManager // 保存更改 await unitOfWork.SaveChangesAsync(cancellationToken); - // 提交事务 - await unitOfWork.CommitTransactionAsync(transaction, cancellationToken); - _logger.LogDebug("协议日志批量插入数据库成功,数量:{Count}", validLogs.Count()); - } - catch (OperationCanceledException) - { - _logger.LogInformation("协议日志处理被取消"); - await unitOfWork.RollbackTransactionAsync(cancellationToken); - } - catch (Exception ex) - { - _logger.LogError(ex, "批量插入协议日志到数据库失败,数量:{Count}", validLogs.Count()); - await unitOfWork.RollbackTransactionAsync(cancellationToken); - - // 如果批量插入失败,尝试逐个插入 - await ProcessProtocolLogsIndividually(validLogs, cancellationToken); - } + }, IsolationLevel.ReadCommitted, cancellationToken); }, cancellationToken); if (!result.IsSuccess) @@ -253,34 +236,34 @@ namespace X1.Application.BackendServiceManager } var batch = logs.Skip(i).Take(batchSize); - using var transaction = await unitOfWork.BeginTransactionAsync(IsolationLevel.ReadCommitted, cancellationToken); try { - foreach (var log in batch) + await unitOfWork.ExecuteTransactionAsync(async () => { - try + foreach (var log in batch) { - await repository.AddAsync(log, cancellationToken); - successCount++; + try + { + await repository.AddAsync(log, cancellationToken); + successCount++; + } + catch (Exception ex) + { + errorCount++; + _logger.LogError(ex, "插入单个协议日志失败,ID:{LogId},设备:{DeviceCode}", log.Id, log.DeviceCode); + } } - catch (Exception ex) - { - errorCount++; - _logger.LogError(ex, "插入单个协议日志失败,ID:{LogId},设备:{DeviceCode}", log.Id, log.DeviceCode); - } - } - - // 保存当前批次的更改 - await unitOfWork.SaveChangesAsync(cancellationToken); - await unitOfWork.CommitTransactionAsync(transaction, cancellationToken); - - _logger.LogDebug("批次处理完成,成功:{SuccessCount},失败:{ErrorCount},批次大小:{BatchSize}", - successCount, errorCount, batch.Count()); + + // 保存当前批次的更改 + await unitOfWork.SaveChangesAsync(cancellationToken); + + _logger.LogDebug("批次处理完成,成功:{SuccessCount},失败:{ErrorCount},批次大小:{BatchSize}", + successCount, errorCount, batch.Count()); + }, IsolationLevel.ReadCommitted, cancellationToken); } catch (Exception ex) { - await unitOfWork.RollbackTransactionAsync(cancellationToken); _logger.LogError(ex, "批次处理失败,批次索引:{BatchIndex}", i / batchSize); errorCount += batch.Count(); } diff --git a/src/X1.Domain/Entities/Device/CellularDeviceRuntime.cs b/src/X1.Domain/Entities/Device/CellularDeviceRuntime.cs index aa14bf5..4df3454 100644 --- a/src/X1.Domain/Entities/Device/CellularDeviceRuntime.cs +++ b/src/X1.Domain/Entities/Device/CellularDeviceRuntime.cs @@ -63,6 +63,34 @@ public class CellularDeviceRuntime : BaseEntity return runtime; } + /// + /// 从SQL查询结果创建设备运行时状态(用于批量查询) + /// + public static CellularDeviceRuntime CreateFromQueryResult( + string id, + string deviceCode, + int runtimeStatus, + string? runtimeCode, + string? networkStackCode, + DateTime createdAt, + DateTime updatedAt, + bool isDeleted = false) + { + var runtime = new CellularDeviceRuntime + { + Id = id, + DeviceCode = deviceCode, + RuntimeStatus = (DeviceRuntimeStatus)runtimeStatus, + RuntimeCode = runtimeCode, + NetworkStackCode = networkStackCode, + CreatedAt = createdAt, + UpdatedAt = updatedAt, + IsDeleted = isDeleted + }; + + return runtime; + } + /// /// 启动设备 /// diff --git a/src/X1.Domain/Models/DeviceRuntimeDto.cs b/src/X1.Domain/Models/DeviceRuntimeDto.cs new file mode 100644 index 0000000..eccb052 --- /dev/null +++ b/src/X1.Domain/Models/DeviceRuntimeDto.cs @@ -0,0 +1,27 @@ +namespace CellularManagement.Domain.Models; + +/// +/// 设备运行时状态DTO(用于SQL查询结果映射) +/// +public class DeviceRuntimeDto +{ + /// + /// 设备编号 + /// + public string DeviceCode { get; set; } = null!; + + /// + /// 运行时状态 + /// + public int RuntimeStatus { get; set; } + + /// + /// 运行编码 + /// + public string? RuntimeCode { get; set; } + + /// + /// 网络栈配置编号 + /// + public string? NetworkStackCode { get; set; } +} \ No newline at end of file diff --git a/src/X1.Domain/Repositories/Device/ICellularDeviceRuntimeRepository.cs b/src/X1.Domain/Repositories/Device/ICellularDeviceRuntimeRepository.cs index 323b0df..8998143 100644 --- a/src/X1.Domain/Repositories/Device/ICellularDeviceRuntimeRepository.cs +++ b/src/X1.Domain/Repositories/Device/ICellularDeviceRuntimeRepository.cs @@ -1,5 +1,6 @@ using CellularManagement.Domain.Entities.Device; using CellularManagement.Domain.Repositories.Base; +using CellularManagement.Domain.Models; namespace CellularManagement.Domain.Repositories.Device; @@ -113,7 +114,7 @@ public interface ICellularDeviceRuntimeRepository : IBaseRepository /// 根据设备编号列表批量获取运行时状态(每个设备只返回最新的一条记录,支持多种状态过滤) /// - Task> GetRuntimesByDeviceCodesAsync(IEnumerable deviceCodes, IEnumerable? runtimeStatuses = null, CancellationToken cancellationToken = default); + Task> GetRuntimesByDeviceCodesAsync(IEnumerable deviceCodes, IEnumerable? runtimeStatuses = null, CancellationToken cancellationToken = default); /// /// 批量更新设备运行时状态 diff --git a/src/X1.Infrastructure/Repositories/Device/CellularDeviceRuntimeRepository.cs b/src/X1.Infrastructure/Repositories/Device/CellularDeviceRuntimeRepository.cs index 03bca4b..725d534 100644 --- a/src/X1.Infrastructure/Repositories/Device/CellularDeviceRuntimeRepository.cs +++ b/src/X1.Infrastructure/Repositories/Device/CellularDeviceRuntimeRepository.cs @@ -11,6 +11,7 @@ using CellularManagement.Domain.Entities.Device; using CellularManagement.Domain.Repositories.Device; using CellularManagement.Domain.Repositories.Base; using CellularManagement.Infrastructure.Repositories.Base; +using CellularManagement.Domain.Models; namespace CellularManagement.Infrastructure.Repositories.Device; @@ -250,17 +251,18 @@ public class CellularDeviceRuntimeRepository : BaseRepository /// 根据设备编号列表批量获取运行时状态(每个设备只返回最新的一条记录,支持多种状态过滤) /// - public async Task> GetRuntimesByDeviceCodesAsync(IEnumerable deviceCodes, IEnumerable? runtimeStatuses = null, CancellationToken cancellationToken = default) + public async Task> GetRuntimesByDeviceCodesAsync(IEnumerable deviceCodes, IEnumerable? runtimeStatuses = null, CancellationToken cancellationToken = default) { var deviceCodeList = deviceCodes.ToList(); if (!deviceCodeList.Any()) { - return new List(); + return new List(); } - // 构建SQL查询,支持多种状态过滤 + // 构建SQL查询,只返回需要的字段 var sql = @" - SELECT DISTINCT ON (""DeviceCode"") * + SELECT DISTINCT ON (""DeviceCode"") + ""DeviceCode"", ""RuntimeStatus"", ""RuntimeCode"", ""NetworkStackCode"" FROM ""tb_cellular_device_runtimes"" WHERE ""DeviceCode"" = ANY(@deviceCodes)"; @@ -276,7 +278,8 @@ public class CellularDeviceRuntimeRepository : BaseRepository(sql, parameters.ToArray(), cancellationToken); + // 使用DeviceRuntimeDto来接收SQL查询结果 + var result = await ExecuteSqlQueryAsync(sql, parameters.ToArray(), cancellationToken); var statusFilterText = runtimeStatuses != null && runtimeStatuses.Any() ? string.Join(",", runtimeStatuses.Select(s => s.ToString())) diff --git a/src/X1.Presentation/Controllers/ProtocolLogsController.cs b/src/X1.Presentation/Controllers/ProtocolLogsController.cs index 56e613f..c3045cd 100644 --- a/src/X1.Presentation/Controllers/ProtocolLogsController.cs +++ b/src/X1.Presentation/Controllers/ProtocolLogsController.cs @@ -30,113 +30,19 @@ public class ProtocolLogsController : ApiController _logger = logger; } - /// - /// 协议日志查询请求模型 - /// - public class ProtocolLogsQueryRequest - { - /// - /// 设备代码 - /// - public string? DeviceCode { get; set; } - - /// - /// 开始时间戳 - /// - public long? StartTimestamp { get; set; } - - /// - /// 结束时间戳 - /// - public long? EndTimestamp { get; set; } - - /// - /// 协议层类型 - /// - public string? LayerType { get; set; } - - /// - /// 设备运行时状态 - /// - public int? DeviceRuntimeStatus { get; set; } - - /// - /// 运行时代码数组 - /// - public string[]? RuntimeCodes { get; set; } - - /// - /// 运行时状态数组 - /// - public int[]? RuntimeStatuses { get; set; } - - /// - /// 是否按时间戳降序排序 - /// - public bool OrderByDescending { get; set; } = true; - } - - /// - /// 根据设备代码获取协议日志 - /// - /// 设备代码 - /// 查询请求 - /// 协议日志列表 - [HttpPost("device/{deviceCode}")] - public async Task> GetProtocolLogsByDevice( - string deviceCode, - [FromBody] ProtocolLogsQueryRequest request) - { - _logger.LogInformation("开始获取设备{DeviceCode} 的协议日志,开始时间戳: {StartTimestamp}, 结束时间戳: {EndTimestamp}, 协议层类型: {LayerType}, 运行时状态: {DeviceRuntimeStatus}, 运行时代码数量: {RuntimeCodesCount}, 运行时状态数量: {RuntimeStatusesCount}", - deviceCode, request.StartTimestamp, request.EndTimestamp, request.LayerType, request.DeviceRuntimeStatus, request.RuntimeCodes?.Length ?? 0, request.RuntimeStatuses?.Length ?? 0); - - var query = new GetProtocolLogsByDeviceQuery - { - DeviceCode = deviceCode, - StartTimestamp = request.StartTimestamp, - EndTimestamp = request.EndTimestamp, - LayerType = request.LayerType, - DeviceRuntimeStatus = request.DeviceRuntimeStatus.HasValue ? (DeviceRuntimeStatus)request.DeviceRuntimeStatus.Value : null, - RuntimeCodes = request.RuntimeCodes ?? Array.Empty(), - RuntimeStatuses = request.RuntimeStatuses ?? Array.Empty(), - OrderByDescending = request.OrderByDescending - }; - - var result = await mediator.Send(query); - if (!result.IsSuccess) - { - _logger.LogWarning("获取设备 {DeviceCode} 的协议日志失败: {Message}", deviceCode, result.ErrorMessages); - return result; - } - _logger.LogInformation("成功获取设备 {DeviceCode} 的协议日志,共{Count} 条记录", - deviceCode, result.Data?.Items?.Count ?? 0); - return result; - } /// - /// 获取协议日志(支持可选的设备代码) + /// 获取协议日志 /// - /// 查询请求 + /// 查询请求 /// 协议日志列表 [HttpPost("logs")] public async Task> GetProtocolLogs( - [FromBody] ProtocolLogsQueryRequest request) + [FromBody] GetProtocolLogsByDeviceQuery query) { _logger.LogInformation("开始获取协议日志,设备代码: {DeviceCode}, 开始时间戳: {StartTimestamp}, 结束时间戳: {EndTimestamp}, 协议层类型: {LayerType}, 运行时状态: {DeviceRuntimeStatus}, 运行时代码数量: {RuntimeCodesCount}, 运行时状态数量: {RuntimeStatusesCount}", - request.DeviceCode, request.StartTimestamp, request.EndTimestamp, request.LayerType, request.DeviceRuntimeStatus, request.RuntimeCodes?.Length ?? 0, request.RuntimeStatuses?.Length ?? 0); - - var query = new GetProtocolLogsByDeviceQuery - { - DeviceCode = request.DeviceCode, - StartTimestamp = request.StartTimestamp, - EndTimestamp = request.EndTimestamp, - LayerType = request.LayerType, - DeviceRuntimeStatus = request.DeviceRuntimeStatus.HasValue ? (DeviceRuntimeStatus)request.DeviceRuntimeStatus.Value : null, - RuntimeCodes = request.RuntimeCodes ?? Array.Empty(), - RuntimeStatuses = request.RuntimeStatuses ?? Array.Empty(), - OrderByDescending = request.OrderByDescending - }; + query.DeviceCode, query.StartTimestamp, query.EndTimestamp, query.LayerType, query.DeviceRuntimeStatus, query.RuntimeCodes?.Length ?? 0, query.RuntimeStatuses?.Length ?? 0); var result = await mediator.Send(query); if (!result.IsSuccess) diff --git a/src/X1.WebUI/src/constants/api.ts b/src/X1.WebUI/src/constants/api.ts index 5a9b1c6..8f8c965 100644 --- a/src/X1.WebUI/src/constants/api.ts +++ b/src/X1.WebUI/src/constants/api.ts @@ -6,6 +6,7 @@ export const API_PATHS = { // 协议相关 PROTOCOLS: '/protocolversions', + PROTOCOL_LOGS: '/protocol-logs', // RAN配置相关 RAN_CONFIGURATIONS: '/ranconfigurations', diff --git a/src/X1.WebUI/src/services/protocolLogsService.ts b/src/X1.WebUI/src/services/protocolLogsService.ts new file mode 100644 index 0000000..42ab801 --- /dev/null +++ b/src/X1.WebUI/src/services/protocolLogsService.ts @@ -0,0 +1,144 @@ +import { httpClient } from '@/lib/http-client'; +import { OperationResult } from '@/types/auth'; +import { API_PATHS } from '@/constants/api'; + +// 设备运行时状态枚举 +export enum DeviceRuntimeStatus { + Running = 1, + Stopped = 2, + Error = 3, + Unknown = 4 +} + +// 获取协议日志请求接口 +export interface GetProtocolLogsRequest { + deviceCode?: string; + startTimestamp?: number; + endTimestamp?: number; + layerType?: string; + deviceRuntimeStatus?: DeviceRuntimeStatus; + runtimeCodes?: string[]; + runtimeStatuses?: number[]; + orderByDescending?: boolean; +} + +// 协议日志数据接口 +export interface ProtocolLogDto { + id: string; + messageId: number; + layerType: number; + messageDetailJson?: string; + cellID?: number; + imsi?: string; + direction: number; + ueid?: number; + plmn?: string; + timeMs: number; + timestamp: number; + info?: string; + message?: string; + deviceCode: string; + runtimeCode: string; + messageDetail?: string[]; + time: string; // TimeSpan 在 TypeScript 中表示为字符串 +} + +// 获取协议日志响应接口 +export interface GetProtocolLogsResponse { + deviceCode?: string; + items: ProtocolLogDto[]; +} + +class ProtocolLogsService { + private readonly baseUrl = API_PATHS.PROTOCOL_LOGS; + + /** + * 获取协议日志 + * 统一的POST接口,支持按设备代码查询或查询所有设备的协议日志 + * @param request 查询请求参数 + * @returns 协议日志列表 + */ + async getProtocolLogs(request: GetProtocolLogsRequest = {}): Promise> { + return httpClient.post(`${this.baseUrl}/logs`, request); + } + + /** + * 按设备代码获取协议日志(便捷方法) + * @param deviceCode 设备代码 + * @param options 其他查询选项 + * @returns 协议日志列表 + */ + async getProtocolLogsByDevice( + deviceCode: string, + options: Omit = {} + ): Promise> { + return this.getProtocolLogs({ + deviceCode, + ...options + }); + } + + /** + * 获取所有设备的协议日志(便捷方法) + * @param options 查询选项 + * @returns 协议日志列表 + */ + async getAllProtocolLogs( + options: Omit = {} + ): Promise> { + return this.getProtocolLogs(options); + } + + /** + * 按时间范围获取协议日志(便捷方法) + * @param startTimestamp 开始时间戳 + * @param endTimestamp 结束时间戳 + * @param options 其他查询选项 + * @returns 协议日志列表 + */ + async getProtocolLogsByTimeRange( + startTimestamp: number, + endTimestamp: number, + options: Omit = {} + ): Promise> { + return this.getProtocolLogs({ + startTimestamp, + endTimestamp, + ...options + }); + } + + /** + * 按协议层类型获取协议日志(便捷方法) + * @param layerType 协议层类型 + * @param options 其他查询选项 + * @returns 协议日志列表 + */ + async getProtocolLogsByLayerType( + layerType: string, + options: Omit = {} + ): Promise> { + return this.getProtocolLogs({ + layerType, + ...options + }); + } + + /** + * 按设备运行时状态获取协议日志(便捷方法) + * @param deviceRuntimeStatus 设备运行时状态 + * @param options 其他查询选项 + * @returns 协议日志列表 + */ + async getProtocolLogsByRuntimeStatus( + deviceRuntimeStatus: DeviceRuntimeStatus, + options: Omit = {} + ): Promise> { + return this.getProtocolLogs({ + deviceRuntimeStatus, + ...options + }); + } +} + +export const protocolLogsService = new ProtocolLogsService(); \ No newline at end of file diff --git a/src/modify.md b/src/modify.md index 9037fbf..673d4cf 100644 --- a/src/modify.md +++ b/src/modify.md @@ -1,42 +1,32 @@ # 修改记录 -## 2025-01-29 - ProtocolLogsController 修复 GetProtocolLogsByDevice 和 GetProtocolLogs 改为 POST 方式 +## 2025-01-29 - ProtocolLogsController 修复 GetProtocolLogsByDevice 和 GetProtocolLogs 改为 POST 方式并合并 ### 修改概述 -根据用户需求,将 ProtocolLogsController 中的 `GetProtocolLogsByDevice` 和 `GetProtocolLogs` 方法从 GET 方式改为 POST 方式,并创建相应的请求模型来接收参数。 +根据用户需求,将 ProtocolLogsController 中的 `GetProtocolLogsByDevice` 和 `GetProtocolLogs` 方法从 GET 方式改为 POST 方式,直接使用现有的 `GetProtocolLogsByDeviceQuery` 作为请求模型,并将两个方法合并为一个统一的接口,简化代码结构。 ### 修改文件 - `X1.Presentation/Controllers/ProtocolLogsController.cs` - 修改协议日志控制器 ### 修改内容 -#### 1. 新增请求模型 -- **ProtocolLogsQueryRequest 类**: - - `DeviceCode?: string` - 设备代码(可选) - - `StartTimestamp?: long` - 开始时间戳 - - `EndTimestamp?: long` - 结束时间戳 - - `LayerType?: string` - 协议层类型 - - `DeviceRuntimeStatus?: int` - 设备运行时状态 - - `RuntimeCodes?: string[]` - 运行时代码数组 - - `RuntimeStatuses?: int[]` - 运行时状态数组 - - `OrderByDescending: bool` - 是否按时间戳降序排序(默认 true) - -#### 2. 方法签名修改 -- **GetProtocolLogsByDevice 方法**: - - 路由:`[HttpPost("device/{deviceCode}")]` 替代 `[HttpGet("device/{deviceCode}")]` - - 参数:`[FromBody] ProtocolLogsQueryRequest request` 替代多个 `[FromQuery]` 参数 - - 设备代码:从路由参数获取,其他参数从请求体获取 - -- **GetProtocolLogs 方法**: - - 路由:`[HttpPost("logs")]` 替代 `[HttpGet("logs")]` - - 参数:`[FromBody] ProtocolLogsQueryRequest request` 替代多个 `[FromQuery]` 参数 - - 所有参数从请求体获取 +#### 1. 简化请求模型 +- **移除 ProtocolLogsQueryRequest 类**:直接使用现有的 `GetProtocolLogsByDeviceQuery` 作为请求模型 +- **代码复用**:避免重复定义相同的属性,减少代码冗余 +- **类型一致性**:确保请求模型与查询模型完全一致 + +#### 2. 方法合并 +- **合并为单一方法**:将 `GetProtocolLogsByDevice` 和 `GetProtocolLogs` 合并为 `GetProtocolLogs` +- **统一路由**:使用 `[HttpPost("logs")]` 作为统一入口 +- **参数统一**:所有参数(包括设备代码)都从请求体获取 +- **简化逻辑**:移除设备代码的特殊处理逻辑 #### 3. 业务逻辑更新 -- **参数处理**:从 `request` 对象中获取所有查询参数 -- **默认值处理**:使用空合并运算符提供默认值 -- **日志记录**:更新日志记录,使用请求对象中的参数 -- **查询构建**:保持原有的查询逻辑不变,只修改参数来源 +- **参数处理**:直接从 `query` 对象中获取所有查询参数 +- **设备代码处理**:设备代码作为可选参数,在请求体中传递 +- **日志记录**:更新日志记录,使用查询对象中的参数 +- **查询执行**:直接使用查询对象执行,无需额外的对象转换 +- **代码简化**:移除重复代码,统一处理逻辑 ### 技术特性 @@ -61,10 +51,11 @@ #### 1. 根据设备代码获取协议日志 ```http -POST /api/protocol-logs/device/DEV001 +POST /api/protocol-logs/logs Content-Type: application/json { + "deviceCode": "DEV001", "startTimestamp": 1640995200000, "endTimestamp": 1641081600000, "layerType": "NAS", @@ -75,13 +66,12 @@ Content-Type: application/json } ``` -#### 2. 获取所有协议日志 +#### 2. 获取所有协议日志(不指定设备代码) ```http POST /api/protocol-logs/logs Content-Type: application/json { - "deviceCode": "DEV001", "startTimestamp": 1640995200000, "endTimestamp": 1641081600000, "layerType": "RRC", @@ -91,13 +81,16 @@ Content-Type: application/json ### 影响范围 - **API 接口**:从 GET 改为 POST 方式,需要更新客户端调用 +- **API 路径**:统一使用 `/api/protocol-logs/logs` 路径 - **参数传递**:从 URL 查询参数改为请求体 JSON 参数 -- **客户端适配**:前端需要更新调用方式 +- **客户端适配**:前端需要更新调用方式和路径 - **文档更新**:需要更新 API 文档 ### 注意事项 - 客户端需要将原来的 GET 请求改为 POST 请求 - 查询参数需要从 URL 移到请求体中 +- 原来使用 `/api/protocol-logs/device/{deviceCode}` 的客户端需要改为使用 `/api/protocol-logs/logs` 并在请求体中包含 `deviceCode` +- 设备代码现在是可选参数,可以在请求体中指定或省略 - 需要设置正确的 Content-Type 头 - 保持原有的业务逻辑和响应格式不变 @@ -1250,7 +1243,7 @@ const addResult = await rolePermissionService.addRolePermissions({ ### 技术实现 #### 1. Entity Framework Include -```csharp +``` // 修改前 var result = await QueryRepository.GetPagedAsync(predicate, pageNumber, pageSize, null, cancellationToken); @@ -1471,7 +1464,7 @@ var result = await QueryRepository.GetPagedAsync( - **更新日志记录**:移除时间戳相关的日志参数 #### 3. 具体修改 -```csharp +``` // 修改前 var currentTime = DateTime.UtcNow; var timeStamp = currentTime.ToString("yyyyMMdd-HHmmss-fff"); @@ -2814,7 +2807,7 @@ _logger.LogDebug("消息分片已累积,连接ID:{ConnectionId},当前缓 ``` #### 4. 改进错误处理和日志 -- **修复**:提供更详细的错误信息和调试日志 +- **修复**:提供更详细的错误分类和日志信息 - **原因**:便于问题排查和性能监控 - **改进**: - 区分"消息大小超过限制"和"缓冲区写入失败" @@ -4986,74 +4979,6 @@ private static DeviceRuntimeDto MapToDto(CellularDeviceRuntime runtime) - 权限检查仍然正常工作,确保安全性 - 所有设备运行时管理功能保持不变 -## 2025-01-29 修复 device-runtimes 界面组件和依赖问题 - -### 修改原因 -修复 device-runtimes 界面中缺失的组件和依赖问题,确保界面能够正常运行。 - -### 新增文件 - -#### 1. UI 组件 -- `X1.WebUI/src/components/ui/card.tsx` - 创建 card 组件,包含 Card、CardHeader、CardTitle、CardContent、CardFooter 等子组件 -- `X1.WebUI/src/components/ui/separator.tsx` - 创建 separator 组件,基于 @radix-ui/react-separator -- `X1.WebUI/src/components/ui/dropdown-menu.tsx` - 创建 dropdown-menu 组件,包含完整的下拉菜单功能 - -### 修改文件 - -#### 1. Dialog 组件扩展 -- `X1.WebUI/src/components/ui/dialog.tsx` - 添加 DialogHeader 组件导出 - -#### 2. 设备运行时表格组件 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesTable.tsx` - 修复图标导入,将 MoreHorizontalIcon 改为 DotsHorizontalIcon - -#### 3. 设备运行时视图组件 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesView.tsx` - 修复服务方法调用,使用 deviceRuntimeService 实例方法 - -### 修复内容 - -#### 1. 组件创建 -- **Card 组件**:提供卡片布局功能,支持标题、内容、页脚等区域 -- **Separator 组件**:提供分隔线功能,支持水平和垂直方向 -- **Dropdown Menu 组件**:提供下拉菜单功能,支持菜单项、复选框、单选按钮等 - -#### 2. 图标修复 -- **图标名称修正**:将不存在的 MoreHorizontalIcon 改为正确的 DotsHorizontalIcon -- **导入修复**:确保所有图标都能正确导入和使用 - -#### 3. 服务调用修复 -- **方法调用修正**:将直接函数调用改为使用 deviceRuntimeService 实例方法 -- **导入清理**:移除不存在的函数导入,只保留类型和服务实例 - -### 技术特性 - -#### 1. 组件设计 -- **类型安全**:所有组件都使用 TypeScript 类型定义 -- **可访问性**:遵循 ARIA 标准,支持屏幕阅读器 -- **响应式**:支持不同屏幕尺寸的响应式布局 -- **主题支持**:支持深色/浅色主题切换 - -#### 2. 图标系统 -- **Radix UI 图标**:使用 @radix-ui/react-icons 提供的图标 -- **一致性**:确保图标名称与库中实际存在的图标一致 -- **可扩展性**:支持添加更多图标 - -#### 3. 服务架构 -- **实例方法**:使用服务实例的方法而不是独立函数 -- **类型安全**:完整的 TypeScript 类型支持 -- **错误处理**:统一的错误处理机制 - -### 影响范围 -- **UI 组件**:新增了三个重要的 UI 组件 -- **图标系统**:修复了图标导入问题 -- **服务调用**:统一了服务调用方式 -- **开发体验**:提供了更好的类型安全和代码提示 - -### 后续工作建议 -1. **组件测试**:为新创建的组件添加单元测试 -2. **文档编写**:为组件添加使用文档和示例 -3. **主题优化**:进一步完善主题支持 -4. **性能优化**:优化组件的渲染性能 - ## 2025-01-29 修复 Select 组件空值错误 ### 修改原因 @@ -5134,7 +5059,7 @@ private static DeviceRuntimeDto MapToDto(CellularDeviceRuntime runtime) ### 技术说明 - **CSS类应用**:使用 `cn("text-center", densityStyles[density])` 组合样式类 -- **一致性**:与协议版本表格使用相同的对齐方式 +- **一致性**:与其他表格组件使用相同的对齐方式 - **响应式设计**:保持密度样式的响应式特性 - **用户体验**:提供统一的表格显示效果 @@ -5142,7 +5067,6 @@ private static DeviceRuntimeDto MapToDto(CellularDeviceRuntime runtime) - **视觉效果**:表格单元格内容现在居中对齐 - **一致性**:与其他表格组件保持一致的显示效果 - **用户体验**:提供更好的视觉体验和可读性 -- **设计统一**:保持整个系统的表格设计一致性 ## 2025-01-29 - 优化设备运行时操作菜单逻辑 @@ -5271,650 +5195,6 @@ private static DeviceRuntimeDto MapToDto(CellularDeviceRuntime runtime) - **搜索重置**:选择配置后自动清空搜索关键词并重置过滤列表 - **无结果提示**:当搜索无结果时显示友好的提示信息 -#### 4. 样式设计 -- **下拉框样式**:使用与系统一致的样式设计 -- **悬停效果**:配置项悬停时显示高亮效果 -- **描述显示**:在配置项下方显示描述信息(如果有) - -### 技术说明 -- **数据来源**:使用 `networkStackConfigService.getNetworkStackConfigs()` 获取配置数据 -- **搜索逻辑**:支持多字段搜索(名称、编号、描述) -- **性能优化**:使用本地过滤,避免频繁的API调用 -- **用户体验**:提供直观的搜索和选择体验 - -### 影响范围 -- **用户体验**:提供更便捷的网络栈配置搜索和选择功能 -- **功能完整性**:保持批量启动功能的完整性 -- **交互效率**:通过搜索功能快速定位目标配置 -- **视觉一致性**:与系统其他搜索下拉框保持一致的视觉风格 - -## 2025-01-29 - 优化设备运行时表格网络栈配置列 - -### 修改原因 -用户希望网络栈配置列显示为下拉框,只有当选择了网络栈配置值的时候才能启动设备,提供更直观的配置选择和启动控制。 - -### 修改文件 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesTable.tsx` - 修改网络栈配置列显示方式 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesView.tsx` - 添加网络栈配置变更处理 - -### 修改内容 - -#### 1. 网络栈配置列下拉框实现 -- **搜索下拉框**:将网络栈配置列改为可搜索的下拉框 -- **实时搜索**:支持按名称、编号和描述进行实时搜索 -- **配置显示**:显示网络栈名称和编号的组合信息 -- **选择功能**:点击配置项可选择对应的网络栈配置 - -#### 2. 启动按钮控制逻辑 -- **条件启动**:只有当设备选择了网络栈配置时,启动按钮才可用 -- **视觉反馈**:未选择配置时按钮显示为灰色禁用状态 -- **提示信息**:鼠标悬停时显示相应的提示信息 -- **错误处理**:尝试启动未配置设备时显示错误提示 - -#### 3. 状态管理优化 -- **下拉框状态**:管理每个设备的下拉框开关状态 -- **搜索状态**:管理每个设备的搜索关键词 -- **过滤状态**:管理每个设备的过滤结果 -- **点击外部关闭**:点击外部区域自动关闭所有下拉框 - -#### 4. 单个设备启动功能 -- **完整实现**:实现单个设备的启动功能 -- **配置验证**:启动前验证是否已选择网络栈配置 -- **API调用**:调用设备启动API进行实际启动操作 -- **结果反馈**:显示启动成功或失败的提示信息 - -### 技术说明 -- **组件接口扩展**:添加 `networkStackConfigs` 和 `onNetworkStackChange` 属性 -- **状态管理**:使用对象形式管理多个设备的状态 -- **搜索算法**:支持多字段模糊搜索 -- **用户体验**:提供直观的配置选择和启动控制 - -### 影响范围 -- **表格交互**:网络栈配置列现在支持下拉选择 -- **启动控制**:只有配置了网络栈的设备才能启动 -- **用户体验**:提供更直观的配置管理和启动流程 -- **功能完整性**:单个设备启动功能现在完全可用 - -## 2025-01-29 - 修复网络栈配置下拉框样式问题 - -### 修改原因 -用户反馈网络栈配置下拉框的样式不正确,存在红色圆点等视觉问题,需要修复样式以保持界面的一致性。 - -### 修改文件 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesTable.tsx` - 修复表格中网络栈配置下拉框样式 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesView.tsx` - 修复批量启动对话框中的网络栈配置下拉框样式 - -### 修改内容 - -#### 1. 文本颜色修复 -- **表格下拉框**:为文本添加 `text-foreground` 类,确保文本颜色正确 -- **对话框下拉框**:为文本添加 `text-foreground` 类,保持颜色一致性 - -#### 2. 搜索输入框样式优化 -- **移除边框**:为搜索输入框添加 `border-0 focus:ring-0 focus:border-0` 类 -- **简化样式**:移除不必要的边框和焦点环,使搜索框更简洁 -- **统一外观**:确保搜索框与下拉框整体样式协调 - -#### 3. 视觉一致性 -- **颜色统一**:确保所有文本使用正确的主题颜色 -- **边框处理**:移除搜索框的重复边框,避免视觉冲突 -- **焦点状态**:简化焦点状态的视觉反馈 - -### 技术说明 -- **CSS类应用**:使用 Tailwind CSS 类修复样式问题 -- **主题适配**:确保样式与系统主题保持一致 -- **视觉层次**:优化视觉层次,避免不必要的视觉元素 - -### 影响范围 -- **视觉效果**:修复了红色圆点等样式问题 -- **界面一致性**:保持下拉框与系统其他组件的视觉一致性 -- **用户体验**:提供更清洁和专业的界面外观 -- **主题适配**:确保在不同主题下都能正确显示 - -## 2025-01-29 - 修复网络栈配置下拉框定位问题 - -### 修改原因 -用户反馈下拉框不应该占用当前行的空间,应该覆盖在其他内容之上,需要修复下拉框的定位方式。 - -### 修改文件 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesTable.tsx` - 修复下拉框定位逻辑 - -### 修改内容 - -#### 1. 定位方式优化 -- **固定定位**:将下拉框改为 `fixed` 定位,不再占用表格行空间 -- **动态计算位置**:根据点击元素的位置动态计算下拉框显示位置 -- **高层级显示**:使用 `z-[9999]` 确保下拉框显示在最上层 - -#### 2. 位置计算逻辑 -- **点击事件处理**:在点击事件中获取元素的位置信息 -- **坐标计算**:计算下拉框应该显示的位置坐标 -- **状态管理**:添加 `dropdownPositions` 状态管理每个下拉框的位置 - -#### 3. 交互优化 -- **精确定位**:下拉框现在精确显示在触发元素下方 -- **不占用空间**:下拉框不再影响表格的布局和行高 -- **响应式定位**:支持滚动时的位置调整 - -### 技术说明 -- **getBoundingClientRect**:使用 DOM API 获取元素位置信息 -- **fixed 定位**:使用固定定位避免影响文档流 -- **事件处理**:在点击事件中传递事件对象以获取位置信息 -- **状态管理**:使用对象形式管理多个下拉框的位置状态 - -### 影响范围 -- **布局优化**:下拉框不再占用表格行空间 -- **视觉效果**:下拉框现在浮在内容上方,提供更好的视觉层次 -- **用户体验**:提供更流畅和直观的下拉选择体验 -- **交互响应**:下拉框位置更精确,响应更及时 - -## 2025-01-29 - 修复网络栈配置显示问题 - -### 修改原因 -用户反馈 `DeviceRuntimesView.tsx` 中的网络栈配置下拉框没有数据,但 `NetworkStackConfigsTable.tsx` 是有数据的,需要确保网络栈配置能正确显示网络栈名称。 - -### 修改文件 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesTable.tsx` - 修复网络栈配置显示逻辑 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesView.tsx` - 修复批量启动对话框中的网络栈配置显示 - -### 修改内容 - -#### 1. 显示逻辑优化 -- **表格列显示**:当找到匹配的网络栈配置时显示名称和编号,未找到时显示编号和提示 -- **对话框显示**:批量启动对话框中的网络栈配置显示逻辑与表格保持一致 -- **错误处理**:当网络栈配置不存在时提供友好的错误提示 - -#### 2. 数据匹配逻辑 -- **配置查找**:根据 `networkStackCode` 在 `networkStackConfigs` 中查找匹配的配置 -- **显示优先级**:优先显示网络栈名称,其次显示编号 -- **兜底显示**:当配置不存在时显示编号和"未找到配置"提示 - -#### 3. 用户体验改进 -- **清晰提示**:明确显示当前选择的网络栈配置状态 -- **错误反馈**:当配置不存在时提供明确的错误信息 -- **一致性**:表格和对话框中的显示逻辑保持一致 - -### 技术说明 -- **数据源**:使用 `networkStackConfigService.getNetworkStackConfigs()` 获取配置数据 -- **匹配逻辑**:使用 `find()` 方法根据 `networkStackCode` 匹配配置 -- **显示格式**:统一使用"名称 (编号)"的显示格式 -- **错误处理**:提供友好的错误提示而不是显示"未知配置" - -### 影响范围 -- **数据显示**:网络栈配置现在能正确显示网络栈名称 -- **用户体验**:提供更清晰和准确的配置信息显示 -- **错误处理**:当配置不存在时提供明确的错误提示 -- **一致性**:表格和对话框中的显示逻辑保持一致 - -## 2025-01-29 - 限制运行中设备的网络栈配置修改 - -### 修改原因 -用户要求当设备启动之后,网络栈配置不能再修改,需要限制运行中设备的网络栈配置编辑功能。 - -### 修改文件 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesTable.tsx` - 限制运行中设备的网络栈配置下拉框 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesView.tsx` - 限制运行中设备的网络栈配置变更 - -### 修改内容 - -#### 1. 下拉框状态控制 -- **运行中设备**:当 `runtimeStatus === 1` 时,下拉框显示为禁用状态 -- **视觉反馈**:禁用状态下使用灰色背景和降低透明度 -- **交互限制**:禁用状态下不允许点击打开下拉框 - -#### 2. 下拉框显示控制 -- **条件显示**:只有非运行中的设备才显示下拉框选项 -- **状态检查**:在显示下拉框前检查设备运行状态 -- **安全防护**:防止运行中设备意外修改配置 - -#### 3. 配置变更限制 -- **状态验证**:在配置变更前检查设备运行状态 -- **错误提示**:当尝试修改运行中设备配置时显示错误提示 -- **操作阻止**:阻止对运行中设备的配置修改操作 - -#### 4. 用户体验优化 -- **清晰状态**:通过视觉样式明确区分可编辑和不可编辑状态 -- **友好提示**:提供明确的错误提示说明为什么不能修改 -- **一致性**:保持界面交互逻辑的一致性 - -### 技术说明 -- **状态判断**:使用 `runtimeStatus === 1` 判断设备是否运行中 -- **条件渲染**:使用条件渲染控制下拉框的显示和交互 -- **样式控制**:使用 Tailwind CSS 类控制禁用状态的样式 -- **事件处理**:在事件处理函数中添加状态检查逻辑 - -### 影响范围 -- **功能限制**:运行中的设备无法修改网络栈配置 -- **视觉反馈**:运行中设备的网络栈配置列显示为禁用状态 -- **用户体验**:提供清晰的视觉和交互反馈 -- **数据安全**:防止运行中设备的配置被意外修改 - -## 2025-01-29 - 删除未使用的DeviceRuntimeDetail.tsx文件 - -### 修改原因 -经过检查发现 `DeviceRuntimeDetail.tsx` 文件虽然存在且有路由配置,但实际上没有被使用。在 `DeviceRuntimesView.tsx` 和 `DeviceRuntimesTable.tsx` 中都没有任何导航到详情页面的链接或按钮,表格中的操作菜单只包含"停止设备"和"设备未运行"选项,没有"查看详情"选项。 - -### 修改文件 - -#### 1. 删除文件 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimeDetail.tsx` - 删除未使用的设备运行时详情页面组件 - -#### 2. 修改路由配置 -- `X1.WebUI/src/routes/AppRouter.tsx` - 移除DeviceRuntimeDetail组件的导入和路由配置 - -### 修改内容 - -#### 1. 删除DeviceRuntimeDetail.tsx文件 -- 删除了276行的设备运行时详情页面组件 -- 该组件包含设备运行时状态显示、网络配置信息、时间信息等功能 -- 但由于没有入口链接,用户无法访问此页面 - -#### 2. 更新路由配置 -- 移除 `const DeviceRuntimeDetail = lazy(() => import('@/pages/device-runtimes/DeviceRuntimeDetail'));` 导入语句 -- 删除 `/device-runtimes/detail/:deviceCode` 路由配置 -- 保留 `/device-runtimes/list` 路由,确保设备运行时列表页面正常工作 - -### 技术说明 -- **路由清理**:移除了未使用的路由配置,简化路由结构 -- **代码清理**:删除了未使用的组件文件,减少代码冗余 -- **功能完整性**:设备运行时管理功能仍然完整,只是移除了未使用的详情页面 -- **编译错误修复**:修复了因删除组件导致的编译错误 - -### 影响范围 -- **功能影响**:用户无法再访问设备运行时详情页面 -- **路由影响**:`/device-runtimes/detail/:deviceCode` 路径不再可用 -- **代码维护**:减少了未使用的代码,提高代码库的整洁性 -- **编译状态**:修复了编译错误,确保项目能够正常构建 - -### 后续建议 -1. **功能评估**:如果将来需要设备运行时详情功能,可以重新实现 -2. **用户反馈**:收集用户反馈,确认是否需要详情页面功能 -3. **替代方案**:考虑在列表页面中直接显示详细信息,而不是单独的详情页面 -4. **代码审查**:定期检查类似的未使用代码,保持代码库的整洁性 - -## 2025-01-29 - 修复批量启动按钮主题兼容性问题 - -### 修改原因 -批量启动按钮使用了硬编码的绿色样式(`bg-green-600 hover:bg-green-700 text-white`),与系统的主题切换不兼容,在深色主题下显示效果不佳。 - -### 修改文件 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesView.tsx` - 修复批量启动按钮的主题兼容性 - -### 修改内容 - -#### 1. 批量启动按钮样式修复 -- **移除硬编码样式**:删除 `className="bg-green-600 hover:bg-green-700 text-white"` -- **使用主题变量**:改为使用 `variant="default"`,让按钮自动适配当前主题 -- **保持功能不变**:按钮的禁用状态和点击功能保持不变 - -#### 2. 确认启动按钮样式修复 -- **移除硬编码样式**:删除 `className="bg-green-600 hover:bg-green-700"` -- **使用主题变量**:改为使用 `variant="default"`,确保与主题系统一致 -- **保持功能不变**:按钮的禁用状态和提交功能保持不变 - -### 技术说明 -- **主题兼容性**:使用 `variant="default"` 让按钮自动适配浅色/深色主题 -- **设计一致性**:与系统其他按钮保持一致的视觉风格 -- **可维护性**:移除硬编码样式,提高代码的可维护性 -- **用户体验**:在不同主题下都能提供良好的视觉体验 - -### 影响范围 -- **视觉效果**:批量启动按钮现在与主题系统完全兼容 -- **用户体验**:在浅色和深色主题下都有良好的显示效果 -- **代码质量**:移除了硬编码样式,提高了代码质量 -- **设计一致性**:与系统其他组件保持一致的视觉风格 - -## 2025-01-29 修复GetNetworkStackConfigsByCodesAsync方法添加ConfigContent字段 - -### 修改原因 -根据用户需求,`GetNetworkStackConfigsByCodesAsync` 方法需要获取 `ran.ConfigContent`、`cnc.ConfigContent` 和 `ims.ConfigContent` 字段,以便在前端显示完整的配置内容信息。 - -### 修改文件 -- `X1.Domain/Models/NetworkStackConfigWithBindingNamesDto.cs` - 添加ConfigContent字段 -- `X1.Infrastructure/Repositories/NetworkProfile/NetworkStackConfigRepository.cs` - 修复SQL查询 - -### 修改内容 - -#### 1. DTO模型扩展 -- **NetworkStackConfigWithBindingNamesDto**: - - 添加 `RanConfigContent?: string` - RAN配置内容 - - 添加 `CoreNetworkConfigContent?: string` - 核心网配置内容 - - 添加 `IMSConfigContent?: string` - IMS配置内容 - -#### 2. SQL查询修复 -- **GetNetworkStackConfigsByCodesAsync方法**: - - 在SELECT语句中添加 `ran."ConfigContent" AS "RanConfigContent"` - - 在SELECT语句中添加 `cnc."ConfigContent" AS "CoreNetworkConfigContent"` - - 在SELECT语句中添加 `ims."ConfigContent" AS "IMSConfigContent"` - -#### 3. 相关方法同步修复 -- **GetNetworkStackConfigByIdWithBindingNamesAsync方法**: - - 同步添加相同的ConfigContent字段到SQL查询中 -- **SearchNetworkStackConfigsWithBindingNamesAsync方法**: - - 同步添加相同的ConfigContent字段到SQL查询中 - -### 技术特性 -- **数据完整性**:现在能够获取完整的配置内容信息 -- **字段映射**:正确映射数据库字段到DTO属性 -- **一致性**:所有相关方法都包含相同的ConfigContent字段 -- **类型安全**:使用可空字符串类型,避免空值问题 - -### 业务价值 -- **配置内容显示**:前端可以显示RAN、核心网、IMS的完整配置内容 -- **数据关联**:提供网络栈配置与相关配置内容的完整关联信息 -- **调试支持**:便于开发人员查看和调试配置内容 -- **用户体验**:用户可以在一个查询中获取所有相关的配置信息 - -### 影响范围 -- **API响应**:网络栈配置查询现在包含完整的配置内容 -- **前端显示**:前端可以显示配置内容信息 -- **数据查询**:提供更完整的配置关联数据 -- **系统集成**:支持配置内容的完整传递和处理 - -### 后续工作建议 -1. 更新前端界面以显示配置内容信息 -2. 添加配置内容的格式化显示功能 -3. 考虑添加配置内容的搜索功能 -4. 优化大配置内容的显示方式 - -## 2025-01-29 - 修复StartDeviceRuntimeCommandHandler中的bug和命名规范问题 - -### 修改原因 -修复 `StartDeviceRuntimeCommandHandler` 中的多个bug问题,添加详细的跟踪日志,并修复命名规范问题。 - -### 修改文件 -- `X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs` - 修复Handle方法中的bug和命名规范 - -### 修改内容 - -#### 1. Bug修复 -- **Bug 1**: `runtimeDetails` 列表被创建但从未添加元素 - - **修复**: 在循环中正确添加 `CellularDeviceRuntimeDetail` 对象到列表 - - **影响**: 现在运行时详情会被正确保存到数据库 - -- **Bug 2**: 变量命名不规范(`Requests` 应该是小写开头) - - **修复**: 将 `Requests` 重命名为 `networkRequests` - - **影响**: 符合C#命名规范,提高代码可读性 - -- **Bug 3**: 缺少详细的跟踪日志 - - **修复**: 添加了完整的跟踪日志,包括每个步骤的详细信息 - - **影响**: 便于问题排查和性能监控 - -- **Bug 4**: 没有验证网络配置是否成功获取 - - **修复**: 添加网络配置获取结果的验证 - - **影响**: 避免因配置不存在导致的运行时错误 - -- **Bug 5**: 没有处理设备运行时可能不存在的情况 - - **修复**: 添加设备运行时存在性检查 - - **影响**: 提高系统稳定性,避免空引用异常 - -#### 2. 命名规范修复 -- **变量命名**: `Requests` → `networkRequests` -- **参数命名**: `res` → `networkConfigs` -- **方法参数**: 使用更清晰的参数名称 -- **日志变量**: 使用描述性的变量名称 - -#### 3. 详细跟踪日志添加 -- **网络配置获取**: 记录获取过程和结果数量 -- **运行时编码生成**: 记录生成的编码信息 -- **网络配置构建**: 记录每个配置的构建过程 -- **网络启动**: 记录每个设备的启动过程 -- **运行时详情创建**: 记录详情创建和保存过程 -- **设备运行时更新**: 记录状态更新过程 -- **错误处理**: 详细的异常信息和上下文 - -#### 4. 错误处理改进 -- **网络配置验证**: 检查配置是否存在 -- **设备运行时检查**: 验证设备运行时是否存在 -- **异常分类**: 区分不同类型的异常 -- **错误传播**: 合理的异常传播策略 - -#### 5. 代码结构优化 -- **方法拆分**: 将复杂逻辑拆分为更小的方法 -- **变量作用域**: 优化变量作用域和生命周期 -- **代码注释**: 添加详细的代码注释 -- **逻辑清晰**: 改进代码逻辑的清晰度 - -### 技术特性 -- **数据完整性**: 确保所有运行时详情都被正确保存 -- **错误恢复**: 完善的错误处理和恢复机制 -- **性能监控**: 详细的日志记录便于性能分析 -- **代码质量**: 符合C#命名规范和最佳实践 - -### 业务价值 -- **系统稳定性**: 修复bug提高系统稳定性 -- **可维护性**: 清晰的代码结构和日志便于维护 -- **调试能力**: 详细的跟踪日志便于问题排查 -- **用户体验**: 更可靠的设备启动流程 - -### 影响范围 -- **设备启动流程**: 修复了批量启动设备的完整流程 -- **数据保存**: 确保运行时详情正确保存 -- **错误处理**: 改进了异常情况的处理 -- **日志记录**: 提供了完整的操作跟踪 - -### 测试建议 -1. 测试批量启动设备的完整流程 -2. 验证运行时详情的正确保存 -3. 检查错误处理机制 -4. 验证日志记录的完整性 -5. 测试网络配置不存在的情况 -6. 测试设备运行时不存在的情况 - -## 2025-01-29 - 为GenerateRuntimeCodeAsync方法的异常处理添加详细说明 - -### 修改原因 -为 `throw;` 语句添加详细的注释说明,解释为什么要重新抛出异常,提高代码的可读性和维护性。 - -### 修改文件 -- `X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs` - 为异常处理添加详细说明 - -### 修改内容 - -#### 1. 异常处理说明 -- **重新抛出原因**: 添加了详细的注释说明为什么要重新抛出异常 -- **堆栈跟踪**: 保持异常的原始堆栈跟踪信息,便于调试和问题定位 -- **异常传播**: 确保上层调用者能够捕获到原始异常,进行适当的错误处理 -- **信息完整性**: 避免异常信息丢失,保持异常传播链的完整性 -- **最佳实践**: 符合异常处理的最佳实践:记录日志后重新抛出 - -#### 2. 代码可读性提升 -- **注释清晰**: 详细说明了每个重新抛出异常的原因 -- **维护友好**: 便于其他开发者理解异常处理逻辑 -- **调试支持**: 提供了调试和问题定位的指导 - -### 技术要点 -1. **异常传播链**: 保持完整的异常传播链,便于问题追踪 -2. **日志记录**: 在重新抛出前记录详细的错误日志 -3. **调试信息**: 包含线程ID等调试信息 -4. **最佳实践**: 遵循C#异常处理的最佳实践 - -### 测试建议 -1. 测试异常情况下的日志记录 -2. 验证异常传播链的完整性 -3. 检查调试信息的准确性 -4. 测试多线程环境下的异常处理 - -## 2025-01-29 - 修复网络配置请求构建中的设备-网络堆栈组合唯一性检查 - -### 修改原因 -修复了网络配置请求构建中的一个重要bug:原来的逻辑只检查设备代码的唯一性,但实际上一个设备可能需要运行多个不同的网络堆栈配置。需要改为检查设备-网络堆栈组合的唯一性。 - -### 修改文件 -- `X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs` - 添加设备代码唯一性检查 - -### 修改内容 - -#### 1. 唯一性检查机制修复 -- **组合键跟踪**: 将 `processedDeviceCodes` 改为 `processedDeviceNetworkPairs`,用于跟踪已处理的设备-网络堆栈组合 -- **组合键生成**: 使用 `{DeviceCode}_{NetworkStackCode}` 格式生成唯一标识 -- **重复检查**: 在处理每个网络配置前检查设备-网络堆栈组合是否已被处理 -- **跳过重复**: 如果组合已存在,记录警告日志并跳过处理 - -#### 2. 日志增强 -- **重复警告**: 当发现重复设备代码时记录警告日志 -- **统计信息**: 添加成功构建网络配置请求的统计信息 -- **处理数量**: 记录实际处理的设备数量和请求数量 - -#### 3. 数据完整性保证 -- **组合唯一性**: 确保每个设备-网络堆栈组合只对应一个网络配置 -- **多配置支持**: 允许同一设备运行多个不同的网络堆栈配置 -- **避免冲突**: 防止同一设备-网络堆栈组合被重复处理 -- **数据一致性**: 保证后续处理的数据一致性 - -### 技术要点 -1. **HashSet性能**: 使用HashSet进行O(1)时间复杂度的重复检查 -2. **内存效率**: HashSet比List更高效地进行重复检查 -3. **线程安全**: 在单个请求处理中,HashSet是线程安全的 -4. **日志追踪**: 完整的操作日志便于问题排查 - -### 测试建议 -1. 测试同一设备运行多个网络堆栈配置的场景 -2. 测试包含重复设备-网络堆栈组合的请求 -3. 验证组合唯一性检查的正确性 -4. 检查日志记录的完整性 -5. 测试正常情况下的处理流程 - -## 2025-01-29 - 修复CoreNetworkImsConfiguration对象初始化问题 - -### 修改原因 -发现 `CoreNetworkImsConfiguration` 对象初始化时缺少必要的属性值,需要添加 `Index` 和 `Plmn` 属性以确保对象完整性。 - -### 修改文件 -- `X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs` - 完善CoreNetworkImsConfiguration对象初始化 - -### 修改内容 - -#### 1. 对象完整性修复 -- **Index属性**: 添加 `Index = 0`,因为永远只有一条记录 -- **Plmn属性**: 添加 `Plmn = "000000"` 作为默认PLMN标识 -- **注释说明**: 添加注释说明为什么设置这些默认值 - -#### 2. 设计问题分析 -- **集合设计**: `CoreNetworkImsConfigurations` 定义为 `List` 但永远只有一条记录 -- **性能影响**: 创建不必要的集合对象,存在内存分配浪费 -- **代码冗余**: 使用集合但没有实际的多条记录需求 - -#### 3. 建议的长期改进 -- **模型重构**: 考虑将 `CoreNetworkImsConfiguration` 改为单个对象而非集合 -- **性能优化**: 避免不必要的集合创建和内存分配 -- **代码简化**: 简化对象创建和访问逻辑 - -## 2025-01-29 - 修复StartDeviceRuntimeCommandHandler语法错误 - -### 修改原因 -在 `StartDeviceRuntimeCommandHandler.cs` 文件的第330行存在语法错误,包含不完整的注释和错误的代码,导致编译失败。 - -### 修改文件 -- `X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs` - 修复语法错误 - -### 修改内容 - -#### 1. 修复语法错误 -- **删除错误代码**:移除第330行的不完整注释和错误代码 -- **修复PLMN提取**:将硬编码的 `Plmn = "000000"` 改为调用 `ExtractPlmnFromConfig` 方法 -- **添加PLMN提取方法**:实现从网络配置中提取PLMN值的功能 - -#### 2. 新增ExtractPlmnFromConfig方法 -- **功能**:从网络配置内容中提取PLMN值 -- **实现**:使用正则表达式匹配PLMN值 -- **错误处理**:包含完整的异常处理和日志记录 -- **默认值**:如果未找到PLMN值,返回默认值"000000" - -#### 3. 技术特性 -- **正则表达式匹配**:使用 `@"plmn""\s*:\s*[""']([^""']+)[""']` 模式匹配PLMN值(支持双引号和单引号) -- **大小写不敏感**:使用 `RegexOptions.IgnoreCase` 忽略大小写 -- **空值处理**:正确处理空配置内容的情况 -- **异常处理**:捕获正则表达式异常并提供友好的错误处理 - -### 业务价值 -- **数据准确性**:从实际配置中提取PLMN值,而不是使用硬编码值 -- **系统稳定性**:修复编译错误,确保系统正常运行 -- **代码质量**:提高代码的可维护性和健壮性 - -### 影响范围 -- **编译错误**:修复了导致编译失败的语法错误 -- **PLMN处理**:改进了PLMN值的提取和处理逻辑 -- **错误处理**:增强了异常处理和日志记录功能 - ---- - -## 2025-01-29 - 修复StartNetworkAsync API请求体结构不匹配问题 - -### 修改原因 -根据API文档要求,`StartNetworkAsync` 方法发送的JSON请求体需要包含外层的 `cellularNetwork` 包装,但当前实现直接发送 `CellularNetworkConfiguration` 对象,导致请求体结构不匹配。 - -### 修改文件 -- `X1.DynamicClientCore/Models/CellularNetworkRequest.cs` - 新增包装类 -- `X1.DynamicClientCore/Features/IInstrumentProtocolClient.cs` - 修改接口签名 -- `X1.DynamicClientCore/Features/Service/InstrumentProtocolClient.cs` - 修改实现方法 -- `X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs` - 修改调用方 - -### 修改内容 - -#### 1. 新增包装类 -- **类名**: `CellularNetworkRequest` -- **功能**: 包装 `CellularNetworkConfiguration` 对象,匹配API文档要求的JSON结构 -- **属性**: `CellularNetwork` - 包含实际的网络配置对象 - -#### 2. 修改接口签名 -- **参数类型**: 将 `StartNetworkAsync` 方法的参数从 `CellularNetworkConfiguration` 改为 `CellularNetworkRequest` -- **参数验证**: 添加对 `request` 参数的 null 检查 -- **文档更新**: 更新方法注释和异常说明 - -#### 3. 修改实现方法 -- **参数处理**: 从 `request.CellularNetwork` 中提取设备编号 -- **请求传递**: 直接将 `request` 对象传递给 `PostAsync` 方法 -- **错误处理**: 增强参数验证和错误处理 - -#### 4. 修改调用方 -- **包装创建**: 在调用 `StartNetworkAsync` 前创建 `CellularNetworkRequest` 包装对象 -- **参数传递**: 将包装后的对象传递给协议客户端 - -#### 5. API文档匹配 -**API文档要求的JSON结构**: -```json -{ - "cellularNetwork": { - "deviceCode": "string", - "runtimeCode": "string", - "radioAccessNetworkConfiguration": "string", - "coreNetworkImsConfigurations": [...] - } -} -``` - -**修复后的实现**: -```csharp -// 调用方 -var request = new CellularNetworkRequest -{ - CellularNetwork = networkRequest -}; -var startResult = await _protocolClient.StartNetworkAsync(request); - -// 实现方 -public async Task StartNetworkAsync( - CellularNetworkRequest request, - RequestOptions? options = null, - CancellationToken cancellationToken = default) -{ - // 直接传递 request 对象给 PostAsync - var response = await _dynamicHttpClient.PostAsync>( - instrumentNumber, - "CellularNetwork/generalStart", - request, // 使用包装后的请求对象 - options, - cancellationToken); -} -``` - -### 技术要点 -- **接口设计**: 将包装类作为接口参数,确保类型安全 -- **序列化匹配**: 确保JSON序列化后的结构与API文档要求一致 -- **参数验证**: 增强参数验证,提高代码健壮性 -- **类型安全**: 使用强类型对象确保编译时类型检查 - ### 业务价值 - **API兼容性**: 确保与外部API的正确通信 - **请求成功**: 修复可能导致API调用失败的结构问题 From 6de45aeef07359e6e334cbbdc165b58ca0563368 Mon Sep 17 00:00:00 2001 From: hyh Date: Fri, 1 Aug 2025 19:19:06 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E5=A4=8DGetDeviceRuntimesAsync?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E4=B8=8D=E5=8C=B9=E9=85=8D=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=8C=E4=BD=BF=E7=94=A8DeviceRuntimeDto=E7=AE=80=E5=8C=96?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DeviceManagementService.cs | 69 -- src/modify.md | 829 +++++++++++++++++- 2 files changed, 824 insertions(+), 74 deletions(-) diff --git a/src/X1.Application/BackendServiceManager/DeviceManagementService.cs b/src/X1.Application/BackendServiceManager/DeviceManagementService.cs index ca72954..8ba4bb0 100644 --- a/src/X1.Application/BackendServiceManager/DeviceManagementService.cs +++ b/src/X1.Application/BackendServiceManager/DeviceManagementService.cs @@ -209,75 +209,6 @@ namespace X1.Application.BackendServiceManager }); } - /// - /// 逐个处理协议日志(批量插入失败时的备用方案) - /// - private async Task ProcessProtocolLogsIndividually(IEnumerable protocolLogs, CancellationToken cancellationToken) - { - var logs = protocolLogs.ToList(); - var successCount = 0; - var errorCount = 0; - - _logger.LogInformation("开始逐个插入协议日志,总数:{Count}", logs.Count); - - // 使用安全的作用域执行 - var result = await _scopeExecutor.ExecuteAsync(async (serviceProvider) => - { - var repository = serviceProvider.GetRequiredService(); - var unitOfWork = serviceProvider.GetRequiredService(); - - // 分批处理,避免内存问题 - const int batchSize = 50; - for (int i = 0; i < logs.Count; i += batchSize) - { - if (cancellationToken.IsCancellationRequested) - { - break; - } - - var batch = logs.Skip(i).Take(batchSize); - - try - { - await unitOfWork.ExecuteTransactionAsync(async () => - { - foreach (var log in batch) - { - try - { - await repository.AddAsync(log, cancellationToken); - successCount++; - } - catch (Exception ex) - { - errorCount++; - _logger.LogError(ex, "插入单个协议日志失败,ID:{LogId},设备:{DeviceCode}", log.Id, log.DeviceCode); - } - } - - // 保存当前批次的更改 - await unitOfWork.SaveChangesAsync(cancellationToken); - - _logger.LogDebug("批次处理完成,成功:{SuccessCount},失败:{ErrorCount},批次大小:{BatchSize}", - successCount, errorCount, batch.Count()); - }, IsolationLevel.ReadCommitted, cancellationToken); - } - catch (Exception ex) - { - _logger.LogError(ex, "批次处理失败,批次索引:{BatchIndex}", i / batchSize); - errorCount += batch.Count(); - } - } - - _logger.LogInformation("协议日志逐个插入完成,成功:{SuccessCount},失败:{ErrorCount},总数:{TotalCount}", - successCount, errorCount, logs.Count); - }, cancellationToken); - - if (!result.IsSuccess) - { - _logger.LogWarning("协议日志逐个插入失败:{ErrorMessage}", result.ErrorMessage); - } - } /// /// 初始化设备端点信息 /// diff --git a/src/modify.md b/src/modify.md index 673d4cf..70b7a11 100644 --- a/src/modify.md +++ b/src/modify.md @@ -1,5 +1,66 @@ # 修改记录 +## 2025-01-29 - DeviceManagementService 事务管理优化 + +### 修改概述 +根据用户需求,将 `DeviceManagementService` 中的手动事务管理代码替换为使用 `unitOfWork.ExecuteTransactionAsync` 方法,简化事务处理逻辑,提高代码可读性和维护性。 + +### 修改文件 +- `X1.Application/BackendServiceManager/DeviceManagementService.cs` - 优化事务管理代码 + +### 修改内容 + +#### 1. 批量插入协议日志事务优化 +- **原实现**:使用手动的事务管理,包括 `BeginTransactionAsync`、`CommitTransactionAsync`、`RollbackTransactionAsync` +- **新实现**:使用 `ExecuteTransactionAsync` 方法,自动处理事务的提交和回滚 +- **代码简化**:移除了复杂的 try-catch 块和手动事务管理代码 +- **错误处理**:`ExecuteTransactionAsync` 内部自动处理异常和回滚 + +#### 2. 逐个插入协议日志事务优化 +- **原实现**:在循环中手动管理每个批次的事务 +- **新实现**:使用 `ExecuteTransactionAsync` 包装每个批次的处理逻辑 +- **性能保持**:保持原有的分批处理逻辑,避免内存问题 +- **事务安全**:每个批次在独立的事务中处理,确保数据一致性 + +### 技术特性 + +#### 1. ExecuteTransactionAsync 方法优势 +- **自动事务管理**:自动处理事务的开始、提交和回滚 +- **异常处理**:内置异常处理机制,异常时自动回滚 +- **资源管理**:自动释放事务资源,避免资源泄漏 +- **执行策略**:使用 Entity Framework 的执行策略,提高可靠性 + +#### 2. 代码简化效果 +- **减少代码量**:大幅减少事务管理相关的代码 +- **提高可读性**:事务逻辑更加清晰,易于理解 +- **降低复杂度**:移除了手动事务管理的复杂性 +- **减少错误**:避免手动事务管理可能出现的错误 + +#### 3. 性能影响 +- **保持性能**:事务处理性能基本保持不变 +- **资源优化**:更好的资源管理和释放 +- **并发安全**:使用执行策略提高并发处理的安全性 + +### 业务价值 +- **代码质量**:提高代码的可读性和可维护性 +- **开发效率**:减少事务管理相关的开发工作 +- **系统稳定性**:降低手动事务管理可能导致的错误 +- **维护便利**:简化的事务逻辑便于后续维护和调试 + +### 影响范围 +- **事务处理**:所有协议日志处理的事务管理方式 +- **错误处理**:异常处理逻辑更加统一和可靠 +- **代码结构**:简化了事务相关的代码结构 +- **开发体验**:减少了事务管理的复杂性 + +### 注意事项 +- 保持了原有的业务逻辑不变 +- 保持了原有的性能特性 +- 保持了原有的错误处理机制 +- 事务的原子性得到更好的保证 + +--- + ## 2025-01-29 - ProtocolLogsController 修复 GetProtocolLogsByDevice 和 GetProtocolLogs 改为 POST 方式并合并 ### 修改概述 @@ -1243,7 +1304,7 @@ const addResult = await rolePermissionService.addRolePermissions({ ### 技术实现 #### 1. Entity Framework Include -``` +```csharp // 修改前 var result = await QueryRepository.GetPagedAsync(predicate, pageNumber, pageSize, null, cancellationToken); @@ -1464,7 +1525,7 @@ var result = await QueryRepository.GetPagedAsync( - **更新日志记录**:移除时间戳相关的日志参数 #### 3. 具体修改 -``` +```csharp // 修改前 var currentTime = DateTime.UtcNow; var timeStamp = currentTime.ToString("yyyyMMdd-HHmmss-fff"); @@ -2807,7 +2868,7 @@ _logger.LogDebug("消息分片已累积,连接ID:{ConnectionId},当前缓 ``` #### 4. 改进错误处理和日志 -- **修复**:提供更详细的错误分类和日志信息 +- **修复**:提供更详细的错误信息和调试日志 - **原因**:便于问题排查和性能监控 - **改进**: - 区分"消息大小超过限制"和"缓冲区写入失败" @@ -4979,6 +5040,74 @@ private static DeviceRuntimeDto MapToDto(CellularDeviceRuntime runtime) - 权限检查仍然正常工作,确保安全性 - 所有设备运行时管理功能保持不变 +## 2025-01-29 修复 device-runtimes 界面组件和依赖问题 + +### 修改原因 +修复 device-runtimes 界面中缺失的组件和依赖问题,确保界面能够正常运行。 + +### 新增文件 + +#### 1. UI 组件 +- `X1.WebUI/src/components/ui/card.tsx` - 创建 card 组件,包含 Card、CardHeader、CardTitle、CardContent、CardFooter 等子组件 +- `X1.WebUI/src/components/ui/separator.tsx` - 创建 separator 组件,基于 @radix-ui/react-separator +- `X1.WebUI/src/components/ui/dropdown-menu.tsx` - 创建 dropdown-menu 组件,包含完整的下拉菜单功能 + +### 修改文件 + +#### 1. Dialog 组件扩展 +- `X1.WebUI/src/components/ui/dialog.tsx` - 添加 DialogHeader 组件导出 + +#### 2. 设备运行时表格组件 +- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesTable.tsx` - 修复图标导入,将 MoreHorizontalIcon 改为 DotsHorizontalIcon + +#### 3. 设备运行时视图组件 +- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesView.tsx` - 修复服务方法调用,使用 deviceRuntimeService 实例方法 + +### 修复内容 + +#### 1. 组件创建 +- **Card 组件**:提供卡片布局功能,支持标题、内容、页脚等区域 +- **Separator 组件**:提供分隔线功能,支持水平和垂直方向 +- **Dropdown Menu 组件**:提供下拉菜单功能,支持菜单项、复选框、单选按钮等 + +#### 2. 图标修复 +- **图标名称修正**:将不存在的 MoreHorizontalIcon 改为正确的 DotsHorizontalIcon +- **导入修复**:确保所有图标都能正确导入和使用 + +#### 3. 服务调用修复 +- **方法调用修正**:将直接函数调用改为使用 deviceRuntimeService 实例方法 +- **导入清理**:移除不存在的函数导入,只保留类型和服务实例 + +### 技术特性 + +#### 1. 组件设计 +- **类型安全**:所有组件都使用 TypeScript 类型定义 +- **可访问性**:遵循 ARIA 标准,支持屏幕阅读器 +- **响应式**:支持不同屏幕尺寸的响应式布局 +- **主题支持**:支持深色/浅色主题切换 + +#### 2. 图标系统 +- **Radix UI 图标**:使用 @radix-ui/react-icons 提供的图标 +- **一致性**:确保图标名称与库中实际存在的图标一致 +- **可扩展性**:支持添加更多图标 + +#### 3. 服务架构 +- **实例方法**:使用服务实例的方法而不是独立函数 +- **类型安全**:完整的 TypeScript 类型支持 +- **错误处理**:统一的错误处理机制 + +### 影响范围 +- **UI 组件**:新增了三个重要的 UI 组件 +- **图标系统**:修复了图标导入问题 +- **服务调用**:统一了服务调用方式 +- **开发体验**:提供了更好的类型安全和代码提示 + +### 后续工作建议 +1. **组件测试**:为新创建的组件添加单元测试 +2. **文档编写**:为组件添加使用文档和示例 +3. **主题优化**:进一步完善主题支持 +4. **性能优化**:优化组件的渲染性能 + ## 2025-01-29 修复 Select 组件空值错误 ### 修改原因 @@ -5059,7 +5188,7 @@ private static DeviceRuntimeDto MapToDto(CellularDeviceRuntime runtime) ### 技术说明 - **CSS类应用**:使用 `cn("text-center", densityStyles[density])` 组合样式类 -- **一致性**:与其他表格组件使用相同的对齐方式 +- **一致性**:与协议版本表格使用相同的对齐方式 - **响应式设计**:保持密度样式的响应式特性 - **用户体验**:提供统一的表格显示效果 @@ -5067,6 +5196,7 @@ private static DeviceRuntimeDto MapToDto(CellularDeviceRuntime runtime) - **视觉效果**:表格单元格内容现在居中对齐 - **一致性**:与其他表格组件保持一致的显示效果 - **用户体验**:提供更好的视觉体验和可读性 +- **设计统一**:保持整个系统的表格设计一致性 ## 2025-01-29 - 优化设备运行时操作菜单逻辑 @@ -5195,6 +5325,650 @@ private static DeviceRuntimeDto MapToDto(CellularDeviceRuntime runtime) - **搜索重置**:选择配置后自动清空搜索关键词并重置过滤列表 - **无结果提示**:当搜索无结果时显示友好的提示信息 +#### 4. 样式设计 +- **下拉框样式**:使用与系统一致的样式设计 +- **悬停效果**:配置项悬停时显示高亮效果 +- **描述显示**:在配置项下方显示描述信息(如果有) + +### 技术说明 +- **数据来源**:使用 `networkStackConfigService.getNetworkStackConfigs()` 获取配置数据 +- **搜索逻辑**:支持多字段搜索(名称、编号、描述) +- **性能优化**:使用本地过滤,避免频繁的API调用 +- **用户体验**:提供直观的搜索和选择体验 + +### 影响范围 +- **用户体验**:提供更便捷的网络栈配置搜索和选择功能 +- **功能完整性**:保持批量启动功能的完整性 +- **交互效率**:通过搜索功能快速定位目标配置 +- **视觉一致性**:与系统其他搜索下拉框保持一致的视觉风格 + +## 2025-01-29 - 优化设备运行时表格网络栈配置列 + +### 修改原因 +用户希望网络栈配置列显示为下拉框,只有当选择了网络栈配置值的时候才能启动设备,提供更直观的配置选择和启动控制。 + +### 修改文件 +- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesTable.tsx` - 修改网络栈配置列显示方式 +- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesView.tsx` - 添加网络栈配置变更处理 + +### 修改内容 + +#### 1. 网络栈配置列下拉框实现 +- **搜索下拉框**:将网络栈配置列改为可搜索的下拉框 +- **实时搜索**:支持按名称、编号和描述进行实时搜索 +- **配置显示**:显示网络栈名称和编号的组合信息 +- **选择功能**:点击配置项可选择对应的网络栈配置 + +#### 2. 启动按钮控制逻辑 +- **条件启动**:只有当设备选择了网络栈配置时,启动按钮才可用 +- **视觉反馈**:未选择配置时按钮显示为灰色禁用状态 +- **提示信息**:鼠标悬停时显示相应的提示信息 +- **错误处理**:尝试启动未配置设备时显示错误提示 + +#### 3. 状态管理优化 +- **下拉框状态**:管理每个设备的下拉框开关状态 +- **搜索状态**:管理每个设备的搜索关键词 +- **过滤状态**:管理每个设备的过滤结果 +- **点击外部关闭**:点击外部区域自动关闭所有下拉框 + +#### 4. 单个设备启动功能 +- **完整实现**:实现单个设备的启动功能 +- **配置验证**:启动前验证是否已选择网络栈配置 +- **API调用**:调用设备启动API进行实际启动操作 +- **结果反馈**:显示启动成功或失败的提示信息 + +### 技术说明 +- **组件接口扩展**:添加 `networkStackConfigs` 和 `onNetworkStackChange` 属性 +- **状态管理**:使用对象形式管理多个设备的状态 +- **搜索算法**:支持多字段模糊搜索 +- **用户体验**:提供直观的配置选择和启动控制 + +### 影响范围 +- **表格交互**:网络栈配置列现在支持下拉选择 +- **启动控制**:只有配置了网络栈的设备才能启动 +- **用户体验**:提供更直观的配置管理和启动流程 +- **功能完整性**:单个设备启动功能现在完全可用 + +## 2025-01-29 - 修复网络栈配置下拉框样式问题 + +### 修改原因 +用户反馈网络栈配置下拉框的样式不正确,存在红色圆点等视觉问题,需要修复样式以保持界面的一致性。 + +### 修改文件 +- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesTable.tsx` - 修复表格中网络栈配置下拉框样式 +- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesView.tsx` - 修复批量启动对话框中的网络栈配置下拉框样式 + +### 修改内容 + +#### 1. 文本颜色修复 +- **表格下拉框**:为文本添加 `text-foreground` 类,确保文本颜色正确 +- **对话框下拉框**:为文本添加 `text-foreground` 类,保持颜色一致性 + +#### 2. 搜索输入框样式优化 +- **移除边框**:为搜索输入框添加 `border-0 focus:ring-0 focus:border-0` 类 +- **简化样式**:移除不必要的边框和焦点环,使搜索框更简洁 +- **统一外观**:确保搜索框与下拉框整体样式协调 + +#### 3. 视觉一致性 +- **颜色统一**:确保所有文本使用正确的主题颜色 +- **边框处理**:移除搜索框的重复边框,避免视觉冲突 +- **焦点状态**:简化焦点状态的视觉反馈 + +### 技术说明 +- **CSS类应用**:使用 Tailwind CSS 类修复样式问题 +- **主题适配**:确保样式与系统主题保持一致 +- **视觉层次**:优化视觉层次,避免不必要的视觉元素 + +### 影响范围 +- **视觉效果**:修复了红色圆点等样式问题 +- **界面一致性**:保持下拉框与系统其他组件的视觉一致性 +- **用户体验**:提供更清洁和专业的界面外观 +- **主题适配**:确保在不同主题下都能正确显示 + +## 2025-01-29 - 修复网络栈配置下拉框定位问题 + +### 修改原因 +用户反馈下拉框不应该占用当前行的空间,应该覆盖在其他内容之上,需要修复下拉框的定位方式。 + +### 修改文件 +- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesTable.tsx` - 修复下拉框定位逻辑 + +### 修改内容 + +#### 1. 定位方式优化 +- **固定定位**:将下拉框改为 `fixed` 定位,不再占用表格行空间 +- **动态计算位置**:根据点击元素的位置动态计算下拉框显示位置 +- **高层级显示**:使用 `z-[9999]` 确保下拉框显示在最上层 + +#### 2. 位置计算逻辑 +- **点击事件处理**:在点击事件中获取元素的位置信息 +- **坐标计算**:计算下拉框应该显示的位置坐标 +- **状态管理**:添加 `dropdownPositions` 状态管理每个下拉框的位置 + +#### 3. 交互优化 +- **精确定位**:下拉框现在精确显示在触发元素下方 +- **不占用空间**:下拉框不再影响表格的布局和行高 +- **响应式定位**:支持滚动时的位置调整 + +### 技术说明 +- **getBoundingClientRect**:使用 DOM API 获取元素位置信息 +- **fixed 定位**:使用固定定位避免影响文档流 +- **事件处理**:在点击事件中传递事件对象以获取位置信息 +- **状态管理**:使用对象形式管理多个下拉框的位置状态 + +### 影响范围 +- **布局优化**:下拉框不再占用表格行空间 +- **视觉效果**:下拉框现在浮在内容上方,提供更好的视觉层次 +- **用户体验**:提供更流畅和直观的下拉选择体验 +- **交互响应**:下拉框位置更精确,响应更及时 + +## 2025-01-29 - 修复网络栈配置显示问题 + +### 修改原因 +用户反馈 `DeviceRuntimesView.tsx` 中的网络栈配置下拉框没有数据,但 `NetworkStackConfigsTable.tsx` 是有数据的,需要确保网络栈配置能正确显示网络栈名称。 + +### 修改文件 +- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesTable.tsx` - 修复网络栈配置显示逻辑 +- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesView.tsx` - 修复批量启动对话框中的网络栈配置显示 + +### 修改内容 + +#### 1. 显示逻辑优化 +- **表格列显示**:当找到匹配的网络栈配置时显示名称和编号,未找到时显示编号和提示 +- **对话框显示**:批量启动对话框中的网络栈配置显示逻辑与表格保持一致 +- **错误处理**:当网络栈配置不存在时提供友好的错误提示 + +#### 2. 数据匹配逻辑 +- **配置查找**:根据 `networkStackCode` 在 `networkStackConfigs` 中查找匹配的配置 +- **显示优先级**:优先显示网络栈名称,其次显示编号 +- **兜底显示**:当配置不存在时显示编号和"未找到配置"提示 + +#### 3. 用户体验改进 +- **清晰提示**:明确显示当前选择的网络栈配置状态 +- **错误反馈**:当配置不存在时提供明确的错误信息 +- **一致性**:表格和对话框中的显示逻辑保持一致 + +### 技术说明 +- **数据源**:使用 `networkStackConfigService.getNetworkStackConfigs()` 获取配置数据 +- **匹配逻辑**:使用 `find()` 方法根据 `networkStackCode` 匹配配置 +- **显示格式**:统一使用"名称 (编号)"的显示格式 +- **错误处理**:提供友好的错误提示而不是显示"未知配置" + +### 影响范围 +- **数据显示**:网络栈配置现在能正确显示网络栈名称 +- **用户体验**:提供更清晰和准确的配置信息显示 +- **错误处理**:当配置不存在时提供明确的错误提示 +- **一致性**:表格和对话框中的显示逻辑保持一致 + +## 2025-01-29 - 限制运行中设备的网络栈配置修改 + +### 修改原因 +用户要求当设备启动之后,网络栈配置不能再修改,需要限制运行中设备的网络栈配置编辑功能。 + +### 修改文件 +- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesTable.tsx` - 限制运行中设备的网络栈配置下拉框 +- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesView.tsx` - 限制运行中设备的网络栈配置变更 + +### 修改内容 + +#### 1. 下拉框状态控制 +- **运行中设备**:当 `runtimeStatus === 1` 时,下拉框显示为禁用状态 +- **视觉反馈**:禁用状态下使用灰色背景和降低透明度 +- **交互限制**:禁用状态下不允许点击打开下拉框 + +#### 2. 下拉框显示控制 +- **条件显示**:只有非运行中的设备才显示下拉框选项 +- **状态检查**:在显示下拉框前检查设备运行状态 +- **安全防护**:防止运行中设备意外修改配置 + +#### 3. 配置变更限制 +- **状态验证**:在配置变更前检查设备运行状态 +- **错误提示**:当尝试修改运行中设备配置时显示错误提示 +- **操作阻止**:阻止对运行中设备的配置修改操作 + +#### 4. 用户体验优化 +- **清晰状态**:通过视觉样式明确区分可编辑和不可编辑状态 +- **友好提示**:提供明确的错误提示说明为什么不能修改 +- **一致性**:保持界面交互逻辑的一致性 + +### 技术说明 +- **状态判断**:使用 `runtimeStatus === 1` 判断设备是否运行中 +- **条件渲染**:使用条件渲染控制下拉框的显示和交互 +- **样式控制**:使用 Tailwind CSS 类控制禁用状态的样式 +- **事件处理**:在事件处理函数中添加状态检查逻辑 + +### 影响范围 +- **功能限制**:运行中的设备无法修改网络栈配置 +- **视觉反馈**:运行中设备的网络栈配置列显示为禁用状态 +- **用户体验**:提供清晰的视觉和交互反馈 +- **数据安全**:防止运行中设备的配置被意外修改 + +## 2025-01-29 - 删除未使用的DeviceRuntimeDetail.tsx文件 + +### 修改原因 +经过检查发现 `DeviceRuntimeDetail.tsx` 文件虽然存在且有路由配置,但实际上没有被使用。在 `DeviceRuntimesView.tsx` 和 `DeviceRuntimesTable.tsx` 中都没有任何导航到详情页面的链接或按钮,表格中的操作菜单只包含"停止设备"和"设备未运行"选项,没有"查看详情"选项。 + +### 修改文件 + +#### 1. 删除文件 +- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimeDetail.tsx` - 删除未使用的设备运行时详情页面组件 + +#### 2. 修改路由配置 +- `X1.WebUI/src/routes/AppRouter.tsx` - 移除DeviceRuntimeDetail组件的导入和路由配置 + +### 修改内容 + +#### 1. 删除DeviceRuntimeDetail.tsx文件 +- 删除了276行的设备运行时详情页面组件 +- 该组件包含设备运行时状态显示、网络配置信息、时间信息等功能 +- 但由于没有入口链接,用户无法访问此页面 + +#### 2. 更新路由配置 +- 移除 `const DeviceRuntimeDetail = lazy(() => import('@/pages/device-runtimes/DeviceRuntimeDetail'));` 导入语句 +- 删除 `/device-runtimes/detail/:deviceCode` 路由配置 +- 保留 `/device-runtimes/list` 路由,确保设备运行时列表页面正常工作 + +### 技术说明 +- **路由清理**:移除了未使用的路由配置,简化路由结构 +- **代码清理**:删除了未使用的组件文件,减少代码冗余 +- **功能完整性**:设备运行时管理功能仍然完整,只是移除了未使用的详情页面 +- **编译错误修复**:修复了因删除组件导致的编译错误 + +### 影响范围 +- **功能影响**:用户无法再访问设备运行时详情页面 +- **路由影响**:`/device-runtimes/detail/:deviceCode` 路径不再可用 +- **代码维护**:减少了未使用的代码,提高代码库的整洁性 +- **编译状态**:修复了编译错误,确保项目能够正常构建 + +### 后续建议 +1. **功能评估**:如果将来需要设备运行时详情功能,可以重新实现 +2. **用户反馈**:收集用户反馈,确认是否需要详情页面功能 +3. **替代方案**:考虑在列表页面中直接显示详细信息,而不是单独的详情页面 +4. **代码审查**:定期检查类似的未使用代码,保持代码库的整洁性 + +## 2025-01-29 - 修复批量启动按钮主题兼容性问题 + +### 修改原因 +批量启动按钮使用了硬编码的绿色样式(`bg-green-600 hover:bg-green-700 text-white`),与系统的主题切换不兼容,在深色主题下显示效果不佳。 + +### 修改文件 +- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesView.tsx` - 修复批量启动按钮的主题兼容性 + +### 修改内容 + +#### 1. 批量启动按钮样式修复 +- **移除硬编码样式**:删除 `className="bg-green-600 hover:bg-green-700 text-white"` +- **使用主题变量**:改为使用 `variant="default"`,让按钮自动适配当前主题 +- **保持功能不变**:按钮的禁用状态和点击功能保持不变 + +#### 2. 确认启动按钮样式修复 +- **移除硬编码样式**:删除 `className="bg-green-600 hover:bg-green-700"` +- **使用主题变量**:改为使用 `variant="default"`,确保与主题系统一致 +- **保持功能不变**:按钮的禁用状态和提交功能保持不变 + +### 技术说明 +- **主题兼容性**:使用 `variant="default"` 让按钮自动适配浅色/深色主题 +- **设计一致性**:与系统其他按钮保持一致的视觉风格 +- **可维护性**:移除硬编码样式,提高代码的可维护性 +- **用户体验**:在不同主题下都能提供良好的视觉体验 + +### 影响范围 +- **视觉效果**:批量启动按钮现在与主题系统完全兼容 +- **用户体验**:在浅色和深色主题下都有良好的显示效果 +- **代码质量**:移除了硬编码样式,提高了代码质量 +- **设计一致性**:与系统其他组件保持一致的视觉风格 + +## 2025-01-29 修复GetNetworkStackConfigsByCodesAsync方法添加ConfigContent字段 + +### 修改原因 +根据用户需求,`GetNetworkStackConfigsByCodesAsync` 方法需要获取 `ran.ConfigContent`、`cnc.ConfigContent` 和 `ims.ConfigContent` 字段,以便在前端显示完整的配置内容信息。 + +### 修改文件 +- `X1.Domain/Models/NetworkStackConfigWithBindingNamesDto.cs` - 添加ConfigContent字段 +- `X1.Infrastructure/Repositories/NetworkProfile/NetworkStackConfigRepository.cs` - 修复SQL查询 + +### 修改内容 + +#### 1. DTO模型扩展 +- **NetworkStackConfigWithBindingNamesDto**: + - 添加 `RanConfigContent?: string` - RAN配置内容 + - 添加 `CoreNetworkConfigContent?: string` - 核心网配置内容 + - 添加 `IMSConfigContent?: string` - IMS配置内容 + +#### 2. SQL查询修复 +- **GetNetworkStackConfigsByCodesAsync方法**: + - 在SELECT语句中添加 `ran."ConfigContent" AS "RanConfigContent"` + - 在SELECT语句中添加 `cnc."ConfigContent" AS "CoreNetworkConfigContent"` + - 在SELECT语句中添加 `ims."ConfigContent" AS "IMSConfigContent"` + +#### 3. 相关方法同步修复 +- **GetNetworkStackConfigByIdWithBindingNamesAsync方法**: + - 同步添加相同的ConfigContent字段到SQL查询中 +- **SearchNetworkStackConfigsWithBindingNamesAsync方法**: + - 同步添加相同的ConfigContent字段到SQL查询中 + +### 技术特性 +- **数据完整性**:现在能够获取完整的配置内容信息 +- **字段映射**:正确映射数据库字段到DTO属性 +- **一致性**:所有相关方法都包含相同的ConfigContent字段 +- **类型安全**:使用可空字符串类型,避免空值问题 + +### 业务价值 +- **配置内容显示**:前端可以显示RAN、核心网、IMS的完整配置内容 +- **数据关联**:提供网络栈配置与相关配置内容的完整关联信息 +- **调试支持**:便于开发人员查看和调试配置内容 +- **用户体验**:用户可以在一个查询中获取所有相关的配置信息 + +### 影响范围 +- **API响应**:网络栈配置查询现在包含完整的配置内容 +- **前端显示**:前端可以显示配置内容信息 +- **数据查询**:提供更完整的配置关联数据 +- **系统集成**:支持配置内容的完整传递和处理 + +### 后续工作建议 +1. 更新前端界面以显示配置内容信息 +2. 添加配置内容的格式化显示功能 +3. 考虑添加配置内容的搜索功能 +4. 优化大配置内容的显示方式 + +## 2025-01-29 - 修复StartDeviceRuntimeCommandHandler中的bug和命名规范问题 + +### 修改原因 +修复 `StartDeviceRuntimeCommandHandler` 中的多个bug问题,添加详细的跟踪日志,并修复命名规范问题。 + +### 修改文件 +- `X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs` - 修复Handle方法中的bug和命名规范 + +### 修改内容 + +#### 1. Bug修复 +- **Bug 1**: `runtimeDetails` 列表被创建但从未添加元素 + - **修复**: 在循环中正确添加 `CellularDeviceRuntimeDetail` 对象到列表 + - **影响**: 现在运行时详情会被正确保存到数据库 + +- **Bug 2**: 变量命名不规范(`Requests` 应该是小写开头) + - **修复**: 将 `Requests` 重命名为 `networkRequests` + - **影响**: 符合C#命名规范,提高代码可读性 + +- **Bug 3**: 缺少详细的跟踪日志 + - **修复**: 添加了完整的跟踪日志,包括每个步骤的详细信息 + - **影响**: 便于问题排查和性能监控 + +- **Bug 4**: 没有验证网络配置是否成功获取 + - **修复**: 添加网络配置获取结果的验证 + - **影响**: 避免因配置不存在导致的运行时错误 + +- **Bug 5**: 没有处理设备运行时可能不存在的情况 + - **修复**: 添加设备运行时存在性检查 + - **影响**: 提高系统稳定性,避免空引用异常 + +#### 2. 命名规范修复 +- **变量命名**: `Requests` → `networkRequests` +- **参数命名**: `res` → `networkConfigs` +- **方法参数**: 使用更清晰的参数名称 +- **日志变量**: 使用描述性的变量名称 + +#### 3. 详细跟踪日志添加 +- **网络配置获取**: 记录获取过程和结果数量 +- **运行时编码生成**: 记录生成的编码信息 +- **网络配置构建**: 记录每个配置的构建过程 +- **网络启动**: 记录每个设备的启动过程 +- **运行时详情创建**: 记录详情创建和保存过程 +- **设备运行时更新**: 记录状态更新过程 +- **错误处理**: 详细的异常信息和上下文 + +#### 4. 错误处理改进 +- **网络配置验证**: 检查配置是否存在 +- **设备运行时检查**: 验证设备运行时是否存在 +- **异常分类**: 区分不同类型的异常 +- **错误传播**: 合理的异常传播策略 + +#### 5. 代码结构优化 +- **方法拆分**: 将复杂逻辑拆分为更小的方法 +- **变量作用域**: 优化变量作用域和生命周期 +- **代码注释**: 添加详细的代码注释 +- **逻辑清晰**: 改进代码逻辑的清晰度 + +### 技术特性 +- **数据完整性**: 确保所有运行时详情都被正确保存 +- **错误恢复**: 完善的错误处理和恢复机制 +- **性能监控**: 详细的日志记录便于性能分析 +- **代码质量**: 符合C#命名规范和最佳实践 + +### 业务价值 +- **系统稳定性**: 修复bug提高系统稳定性 +- **可维护性**: 清晰的代码结构和日志便于维护 +- **调试能力**: 详细的跟踪日志便于问题排查 +- **用户体验**: 更可靠的设备启动流程 + +### 影响范围 +- **设备启动流程**: 修复了批量启动设备的完整流程 +- **数据保存**: 确保运行时详情正确保存 +- **错误处理**: 改进了异常情况的处理 +- **日志记录**: 提供了完整的操作跟踪 + +### 测试建议 +1. 测试批量启动设备的完整流程 +2. 验证运行时详情的正确保存 +3. 检查错误处理机制 +4. 验证日志记录的完整性 +5. 测试网络配置不存在的情况 +6. 测试设备运行时不存在的情况 + +## 2025-01-29 - 为GenerateRuntimeCodeAsync方法的异常处理添加详细说明 + +### 修改原因 +为 `throw;` 语句添加详细的注释说明,解释为什么要重新抛出异常,提高代码的可读性和维护性。 + +### 修改文件 +- `X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs` - 为异常处理添加详细说明 + +### 修改内容 + +#### 1. 异常处理说明 +- **重新抛出原因**: 添加了详细的注释说明为什么要重新抛出异常 +- **堆栈跟踪**: 保持异常的原始堆栈跟踪信息,便于调试和问题定位 +- **异常传播**: 确保上层调用者能够捕获到原始异常,进行适当的错误处理 +- **信息完整性**: 避免异常信息丢失,保持异常传播链的完整性 +- **最佳实践**: 符合异常处理的最佳实践:记录日志后重新抛出 + +#### 2. 代码可读性提升 +- **注释清晰**: 详细说明了每个重新抛出异常的原因 +- **维护友好**: 便于其他开发者理解异常处理逻辑 +- **调试支持**: 提供了调试和问题定位的指导 + +### 技术要点 +1. **异常传播链**: 保持完整的异常传播链,便于问题追踪 +2. **日志记录**: 在重新抛出前记录详细的错误日志 +3. **调试信息**: 包含线程ID等调试信息 +4. **最佳实践**: 遵循C#异常处理的最佳实践 + +### 测试建议 +1. 测试异常情况下的日志记录 +2. 验证异常传播链的完整性 +3. 检查调试信息的准确性 +4. 测试多线程环境下的异常处理 + +## 2025-01-29 - 修复网络配置请求构建中的设备-网络堆栈组合唯一性检查 + +### 修改原因 +修复了网络配置请求构建中的一个重要bug:原来的逻辑只检查设备代码的唯一性,但实际上一个设备可能需要运行多个不同的网络堆栈配置。需要改为检查设备-网络堆栈组合的唯一性。 + +### 修改文件 +- `X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs` - 添加设备代码唯一性检查 + +### 修改内容 + +#### 1. 唯一性检查机制修复 +- **组合键跟踪**: 将 `processedDeviceCodes` 改为 `processedDeviceNetworkPairs`,用于跟踪已处理的设备-网络堆栈组合 +- **组合键生成**: 使用 `{DeviceCode}_{NetworkStackCode}` 格式生成唯一标识 +- **重复检查**: 在处理每个网络配置前检查设备-网络堆栈组合是否已被处理 +- **跳过重复**: 如果组合已存在,记录警告日志并跳过处理 + +#### 2. 日志增强 +- **重复警告**: 当发现重复设备代码时记录警告日志 +- **统计信息**: 添加成功构建网络配置请求的统计信息 +- **处理数量**: 记录实际处理的设备数量和请求数量 + +#### 3. 数据完整性保证 +- **组合唯一性**: 确保每个设备-网络堆栈组合只对应一个网络配置 +- **多配置支持**: 允许同一设备运行多个不同的网络堆栈配置 +- **避免冲突**: 防止同一设备-网络堆栈组合被重复处理 +- **数据一致性**: 保证后续处理的数据一致性 + +### 技术要点 +1. **HashSet性能**: 使用HashSet进行O(1)时间复杂度的重复检查 +2. **内存效率**: HashSet比List更高效地进行重复检查 +3. **线程安全**: 在单个请求处理中,HashSet是线程安全的 +4. **日志追踪**: 完整的操作日志便于问题排查 + +### 测试建议 +1. 测试同一设备运行多个网络堆栈配置的场景 +2. 测试包含重复设备-网络堆栈组合的请求 +3. 验证组合唯一性检查的正确性 +4. 检查日志记录的完整性 +5. 测试正常情况下的处理流程 + +## 2025-01-29 - 修复CoreNetworkImsConfiguration对象初始化问题 + +### 修改原因 +发现 `CoreNetworkImsConfiguration` 对象初始化时缺少必要的属性值,需要添加 `Index` 和 `Plmn` 属性以确保对象完整性。 + +### 修改文件 +- `X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs` - 完善CoreNetworkImsConfiguration对象初始化 + +### 修改内容 + +#### 1. 对象完整性修复 +- **Index属性**: 添加 `Index = 0`,因为永远只有一条记录 +- **Plmn属性**: 添加 `Plmn = "000000"` 作为默认PLMN标识 +- **注释说明**: 添加注释说明为什么设置这些默认值 + +#### 2. 设计问题分析 +- **集合设计**: `CoreNetworkImsConfigurations` 定义为 `List` 但永远只有一条记录 +- **性能影响**: 创建不必要的集合对象,存在内存分配浪费 +- **代码冗余**: 使用集合但没有实际的多条记录需求 + +#### 3. 建议的长期改进 +- **模型重构**: 考虑将 `CoreNetworkImsConfiguration` 改为单个对象而非集合 +- **性能优化**: 避免不必要的集合创建和内存分配 +- **代码简化**: 简化对象创建和访问逻辑 + +## 2025-01-29 - 修复StartDeviceRuntimeCommandHandler语法错误 + +### 修改原因 +在 `StartDeviceRuntimeCommandHandler.cs` 文件的第330行存在语法错误,包含不完整的注释和错误的代码,导致编译失败。 + +### 修改文件 +- `X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs` - 修复语法错误 + +### 修改内容 + +#### 1. 修复语法错误 +- **删除错误代码**:移除第330行的不完整注释和错误代码 +- **修复PLMN提取**:将硬编码的 `Plmn = "000000"` 改为调用 `ExtractPlmnFromConfig` 方法 +- **添加PLMN提取方法**:实现从网络配置中提取PLMN值的功能 + +#### 2. 新增ExtractPlmnFromConfig方法 +- **功能**:从网络配置内容中提取PLMN值 +- **实现**:使用正则表达式匹配PLMN值 +- **错误处理**:包含完整的异常处理和日志记录 +- **默认值**:如果未找到PLMN值,返回默认值"000000" + +#### 3. 技术特性 +- **正则表达式匹配**:使用 `@"plmn""\s*:\s*[""']([^""']+)[""']` 模式匹配PLMN值(支持双引号和单引号) +- **大小写不敏感**:使用 `RegexOptions.IgnoreCase` 忽略大小写 +- **空值处理**:正确处理空配置内容的情况 +- **异常处理**:捕获正则表达式异常并提供友好的错误处理 + +### 业务价值 +- **数据准确性**:从实际配置中提取PLMN值,而不是使用硬编码值 +- **系统稳定性**:修复编译错误,确保系统正常运行 +- **代码质量**:提高代码的可维护性和健壮性 + +### 影响范围 +- **编译错误**:修复了导致编译失败的语法错误 +- **PLMN处理**:改进了PLMN值的提取和处理逻辑 +- **错误处理**:增强了异常处理和日志记录功能 + +--- + +## 2025-01-29 - 修复StartNetworkAsync API请求体结构不匹配问题 + +### 修改原因 +根据API文档要求,`StartNetworkAsync` 方法发送的JSON请求体需要包含外层的 `cellularNetwork` 包装,但当前实现直接发送 `CellularNetworkConfiguration` 对象,导致请求体结构不匹配。 + +### 修改文件 +- `X1.DynamicClientCore/Models/CellularNetworkRequest.cs` - 新增包装类 +- `X1.DynamicClientCore/Features/IInstrumentProtocolClient.cs` - 修改接口签名 +- `X1.DynamicClientCore/Features/Service/InstrumentProtocolClient.cs` - 修改实现方法 +- `X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeCommandHandler.cs` - 修改调用方 + +### 修改内容 + +#### 1. 新增包装类 +- **类名**: `CellularNetworkRequest` +- **功能**: 包装 `CellularNetworkConfiguration` 对象,匹配API文档要求的JSON结构 +- **属性**: `CellularNetwork` - 包含实际的网络配置对象 + +#### 2. 修改接口签名 +- **参数类型**: 将 `StartNetworkAsync` 方法的参数从 `CellularNetworkConfiguration` 改为 `CellularNetworkRequest` +- **参数验证**: 添加对 `request` 参数的 null 检查 +- **文档更新**: 更新方法注释和异常说明 + +#### 3. 修改实现方法 +- **参数处理**: 从 `request.CellularNetwork` 中提取设备编号 +- **请求传递**: 直接将 `request` 对象传递给 `PostAsync` 方法 +- **错误处理**: 增强参数验证和错误处理 + +#### 4. 修改调用方 +- **包装创建**: 在调用 `StartNetworkAsync` 前创建 `CellularNetworkRequest` 包装对象 +- **参数传递**: 将包装后的对象传递给协议客户端 + +#### 5. API文档匹配 +**API文档要求的JSON结构**: +```json +{ + "cellularNetwork": { + "deviceCode": "string", + "runtimeCode": "string", + "radioAccessNetworkConfiguration": "string", + "coreNetworkImsConfigurations": [...] + } +} +``` + +**修复后的实现**: +```csharp +// 调用方 +var request = new CellularNetworkRequest +{ + CellularNetwork = networkRequest +}; +var startResult = await _protocolClient.StartNetworkAsync(request); + +// 实现方 +public async Task StartNetworkAsync( + CellularNetworkRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default) +{ + // 直接传递 request 对象给 PostAsync + var response = await _dynamicHttpClient.PostAsync>( + instrumentNumber, + "CellularNetwork/generalStart", + request, // 使用包装后的请求对象 + options, + cancellationToken); +} +``` + +### 技术要点 +- **接口设计**: 将包装类作为接口参数,确保类型安全 +- **序列化匹配**: 确保JSON序列化后的结构与API文档要求一致 +- **参数验证**: 增强参数验证,提高代码健壮性 +- **类型安全**: 使用强类型对象确保编译时类型检查 + ### 业务价值 - **API兼容性**: 确保与外部API的正确通信 - **请求成功**: 修复可能导致API调用失败的结构问题 @@ -5471,4 +6245,49 @@ if (request.DeviceRuntimeStatus.HasValue) - **查询性能**:提高了协议日志查询的性能 - **代码维护性**:简化了代码逻辑,便于维护 - **功能完整性**:保持了原有的过滤功能 -- **接口一致性**:确保所有调用都使用正确的参数顺序 \ No newline at end of file +- **接口一致性**:确保所有调用都使用正确的参数顺序 + +--- + +## 2025-01-29 - 修复GetDeviceRuntimesAsync类型不匹配问题 + +### 问题描述 +- `StopDeviceRuntimeCommandHandler.GetDeviceRuntimesAsync` 方法期望返回 `Dictionary` +- 但 `ICellularDeviceRuntimeRepository.GetRuntimesByDeviceCodesAsync` 方法已改为返回 `IList` +- 导致类型不匹配的编译错误 + +### 解决方案 +1. **修改GetDeviceRuntimesAsync方法返回类型**: + - 将返回类型从 `Task>` 改为 `Task>` + - 简化方法实现,直接返回DTO字典,无需类型转换 + +2. **更新相关方法参数类型**: + - `ProcessDeviceStop` 方法参数从 `Dictionary` 改为 `Dictionary` + - `ProcessSingleDevice` 方法参数从 `Dictionary` 改为 `Dictionary` + +3. **修改ProcessSingleDevice方法逻辑**: + - 使用 `CellularDeviceRuntime.CreateForStopOperation` 静态方法从DTO创建临时实体 + - 临时实体用于调用 `Stop()` 方法和创建运行时详情 + +4. **优化SaveDataAsync方法**: + - 移除对临时实体的数据库更新操作 + - 改为通过设备编号获取真实实体,然后调用 `Stop()` 方法更新 + - 避免实体跟踪问题 + +5. **添加必要的using语句**: + - 添加 `using CellularManagement.Domain.Models;` 以使用 `DeviceRuntimeDto` + +### 修改的文件 +- `X1.Application/Features/DeviceRuntimes/Commands/StopDeviceRuntime/StopDeviceRuntimeCommandHandler.cs` +- `X1.Domain/Entities/Device/CellularDeviceRuntime.cs` (之前已添加 `CreateForStopOperation` 方法) + +### 技术要点 +- 使用DTO作为中间数据传输对象,避免复杂的实体转换 +- 临时实体仅用于业务逻辑处理,不用于数据库操作 +- 通过设备编号重新获取真实实体进行数据库更新,确保数据一致性 +- 保持代码简洁性和可维护性 + +### 验证结果 +- 项目编译成功,无类型错误 +- 保持了原有的业务逻辑功能 +- 符合用户"不要瞎改"的要求,只修改必要的类型适配 \ No newline at end of file