From d9ef1cb65458c732b8c078c7d402113a0bed07c9 Mon Sep 17 00:00:00 2001 From: hyh Date: Fri, 1 Aug 2025 18:48:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DSwagger=20schemaId=E5=86=B2?= =?UTF-8?q?=E7=AA=81=EF=BC=9A=E6=8F=90=E5=8F=96=E5=85=B1=E4=BA=AB=E7=9A=84?= =?UTF-8?q?BatchOperationSummary=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StartDeviceRuntimeResponse.cs | 32 +- .../StopDeviceRuntimeResponse.cs | 28 +- src/X1.Domain/Common/BatchOperationSummary.cs | 27 + .../Controllers/ProtocolLogsController.cs | 132 ++-- src/modify.md | 579 ++++-------------- 5 files changed, 210 insertions(+), 588 deletions(-) create mode 100644 src/X1.Domain/Common/BatchOperationSummary.cs diff --git a/src/X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeResponse.cs b/src/X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeResponse.cs index e8f1e36..0b7dc13 100644 --- a/src/X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeResponse.cs +++ b/src/X1.Application/Features/DeviceRuntimes/Commands/StartDeviceRuntime/StartDeviceRuntimeResponse.cs @@ -1,3 +1,5 @@ +using CellularManagement.Domain.Common; + namespace CellularManagement.Application.Features.DeviceRuntimes.Commands.StartDeviceRuntime; /// @@ -25,8 +27,6 @@ public class StartDeviceRuntimeResponse /// public string? NetworkStackCode { get; set; } - - /// /// 更新时间 /// @@ -68,8 +68,6 @@ public class DeviceStartResult /// public string? NetworkStackCode { get; set; } - - /// /// 更新时间 /// @@ -84,30 +82,4 @@ public class DeviceStartResult /// 错误信息 /// public string? ErrorMessage { get; set; } -} - -/// -/// 批量操作统计 -/// -public class BatchOperationSummary -{ - /// - /// 总设备数 - /// - public int TotalCount { get; set; } - - /// - /// 成功数量 - /// - public int SuccessCount { get; set; } - - /// - /// 失败数量 - /// - public int FailureCount { get; set; } - - /// - /// 成功率 - /// - public double SuccessRate => TotalCount > 0 ? (double)SuccessCount / TotalCount * 100 : 0; } \ No newline at end of file diff --git a/src/X1.Application/Features/DeviceRuntimes/Commands/StopDeviceRuntime/StopDeviceRuntimeResponse.cs b/src/X1.Application/Features/DeviceRuntimes/Commands/StopDeviceRuntime/StopDeviceRuntimeResponse.cs index 608f945..d0f6419 100644 --- a/src/X1.Application/Features/DeviceRuntimes/Commands/StopDeviceRuntime/StopDeviceRuntimeResponse.cs +++ b/src/X1.Application/Features/DeviceRuntimes/Commands/StopDeviceRuntime/StopDeviceRuntimeResponse.cs @@ -1,3 +1,5 @@ +using CellularManagement.Domain.Common; + namespace CellularManagement.Application.Features.DeviceRuntimes.Commands.StopDeviceRuntime; /// @@ -90,30 +92,4 @@ public class DeviceStopResult /// 错误信息 /// public string? ErrorMessage { get; set; } -} - -/// -/// 批量操作统计 -/// -public class BatchOperationSummary -{ - /// - /// 总设备数 - /// - public int TotalCount { get; set; } - - /// - /// 成功数量 - /// - public int SuccessCount { get; set; } - - /// - /// 失败数量 - /// - public int FailureCount { get; set; } - - /// - /// 成功率 - /// - public double SuccessRate => TotalCount > 0 ? (double)SuccessCount / TotalCount * 100 : 0; } \ No newline at end of file diff --git a/src/X1.Domain/Common/BatchOperationSummary.cs b/src/X1.Domain/Common/BatchOperationSummary.cs new file mode 100644 index 0000000..6e34459 --- /dev/null +++ b/src/X1.Domain/Common/BatchOperationSummary.cs @@ -0,0 +1,27 @@ +namespace CellularManagement.Domain.Common; + +/// +/// 批量操作统计 +/// +public class BatchOperationSummary +{ + /// + /// 总设备数 + /// + public int TotalCount { get; set; } + + /// + /// 成功数量 + /// + public int SuccessCount { get; set; } + + /// + /// 失败数量 + /// + public int FailureCount { get; set; } + + /// + /// 成功率 + /// + public double SuccessRate => TotalCount > 0 ? (double)SuccessCount / TotalCount * 100 : 0; +} \ No newline at end of file diff --git a/src/X1.Presentation/Controllers/ProtocolLogsController.cs b/src/X1.Presentation/Controllers/ProtocolLogsController.cs index 4c4d3f7..56e613f 100644 --- a/src/X1.Presentation/Controllers/ProtocolLogsController.cs +++ b/src/X1.Presentation/Controllers/ProtocolLogsController.cs @@ -24,50 +24,82 @@ public class ProtocolLogsController : ApiController /// /// 中介者 /// 日志记录器 - public ProtocolLogsController(IMediator mediator, ILogger logger) + public ProtocolLogsController(IMediator mediator, ILogger logger) : base(mediator) { _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; + } /// /// 根据设备代码获取协议日志 /// /// 设备代码 - /// 开始时间戳 - /// 结束时间戳 - /// 协议层类型 - /// 设备运行时状态 - /// 运行时代码数组 - /// 运行时状态数组 - /// 是否按时间戳降序排序 + /// 查询请求 /// 协议日志列表 - [HttpGet("device/{deviceCode}")] + [HttpPost("device/{deviceCode}")] public async Task> GetProtocolLogsByDevice( string deviceCode, - [FromQuery] long? startTimestamp = null, - [FromQuery] long? endTimestamp = null, - [FromQuery] string? layerType = null, - [FromQuery] int? deviceRuntimeStatus = null, - [FromQuery] string[]? runtimeCodes = null, - [FromQuery] int[]? runtimeStatuses = null, - [FromQuery] bool orderByDescending = true) + [FromBody] ProtocolLogsQueryRequest request) { - _logger.LogInformation("开始获取设备 {DeviceCode} 的协议日志,开始时间戳: {StartTimestamp}, 结束时间戳: {EndTimestamp}, 协议层类型: {LayerType}, 运行时状态: {DeviceRuntimeStatus}, 运行时代码数量: {RuntimeCodesCount}, 运行时状态数量: {RuntimeStatusesCount}", - deviceCode, startTimestamp, endTimestamp, layerType, deviceRuntimeStatus, runtimeCodes?.Length ?? 0, runtimeStatuses?.Length ?? 0); + _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 - { + var query = new GetProtocolLogsByDeviceQuery + { DeviceCode = deviceCode, - StartTimestamp = startTimestamp, - EndTimestamp = endTimestamp, - LayerType = layerType, - DeviceRuntimeStatus = deviceRuntimeStatus.HasValue ? (DeviceRuntimeStatus)deviceRuntimeStatus.Value : null, - RuntimeCodes = runtimeCodes ?? Array.Empty(), - RuntimeStatuses = runtimeStatuses ?? Array.Empty(), - OrderByDescending = orderByDescending + 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); @@ -77,7 +109,7 @@ public class ProtocolLogsController : ApiController return result; } - _logger.LogInformation("成功获取设备 {DeviceCode} 的协议日志,共 {Count} 条记录", + _logger.LogInformation("成功获取设备 {DeviceCode} 的协议日志,共{Count} 条记录", deviceCode, result.Data?.Items?.Count ?? 0); return result; } @@ -85,39 +117,25 @@ public class ProtocolLogsController : ApiController /// /// 获取协议日志(支持可选的设备代码) /// - /// 设备代码(可选) - /// 开始时间戳 - /// 结束时间戳 - /// 协议层类型 - /// 设备运行时状态 - /// 运行时代码数组 - /// 运行时状态数组 - /// 是否按时间戳降序排序 + /// 查询请求 /// 协议日志列表 - [HttpGet("logs")] + [HttpPost("logs")] public async Task> GetProtocolLogs( - [FromQuery] string? deviceCode = null, - [FromQuery] long? startTimestamp = null, - [FromQuery] long? endTimestamp = null, - [FromQuery] string? layerType = null, - [FromQuery] int? deviceRuntimeStatus = null, - [FromQuery] string[]? runtimeCodes = null, - [FromQuery] int[]? runtimeStatuses = null, - [FromQuery] bool orderByDescending = true) + [FromBody] ProtocolLogsQueryRequest request) { _logger.LogInformation("开始获取协议日志,设备代码: {DeviceCode}, 开始时间戳: {StartTimestamp}, 结束时间戳: {EndTimestamp}, 协议层类型: {LayerType}, 运行时状态: {DeviceRuntimeStatus}, 运行时代码数量: {RuntimeCodesCount}, 运行时状态数量: {RuntimeStatusesCount}", - deviceCode, startTimestamp, endTimestamp, layerType, deviceRuntimeStatus, runtimeCodes?.Length ?? 0, runtimeStatuses?.Length ?? 0); + request.DeviceCode, request.StartTimestamp, request.EndTimestamp, request.LayerType, request.DeviceRuntimeStatus, request.RuntimeCodes?.Length ?? 0, request.RuntimeStatuses?.Length ?? 0); - var query = new GetProtocolLogsByDeviceQuery - { - DeviceCode = deviceCode, - StartTimestamp = startTimestamp, - EndTimestamp = endTimestamp, - LayerType = layerType, - DeviceRuntimeStatus = deviceRuntimeStatus.HasValue ? (DeviceRuntimeStatus)deviceRuntimeStatus.Value : null, - RuntimeCodes = runtimeCodes ?? Array.Empty(), - RuntimeStatuses = runtimeStatuses ?? Array.Empty(), - OrderByDescending = orderByDescending + 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 }; var result = await mediator.Send(query); @@ -127,7 +145,7 @@ public class ProtocolLogsController : ApiController return result; } - _logger.LogInformation("成功获取协议日志,共 {Count} 条记录", + _logger.LogInformation("成功获取协议日志,共 {Count} 条记录", result.Data?.Items?.Count ?? 0); return result; } diff --git a/src/modify.md b/src/modify.md index 3f38f5f..9037fbf 100644 --- a/src/modify.md +++ b/src/modify.md @@ -1,5 +1,108 @@ # 修改记录 +## 2025-01-29 - ProtocolLogsController 修复 GetProtocolLogsByDevice 和 GetProtocolLogs 改为 POST 方式 + +### 修改概述 +根据用户需求,将 ProtocolLogsController 中的 `GetProtocolLogsByDevice` 和 `GetProtocolLogs` 方法从 GET 方式改为 POST 方式,并创建相应的请求模型来接收参数。 + +### 修改文件 +- `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]` 参数 + - 所有参数从请求体获取 + +#### 3. 业务逻辑更新 +- **参数处理**:从 `request` 对象中获取所有查询参数 +- **默认值处理**:使用空合并运算符提供默认值 +- **日志记录**:更新日志记录,使用请求对象中的参数 +- **查询构建**:保持原有的查询逻辑不变,只修改参数来源 + +### 技术特性 + +#### 1. POST 方式优势 +- **参数复杂性**:支持复杂的查询参数,包括数组类型 +- **安全性**:敏感参数不会出现在 URL 中 +- **数据大小**:支持更大的查询参数 +- **一致性**:与其他复杂查询接口保持一致 + +#### 2. 请求模型设计 +- **类型安全**:使用强类型的请求模型 +- **可选参数**:大部分参数都是可选的,提供灵活性 +- **默认值**:为常用参数提供合理的默认值 +- **文档完整**:为所有属性添加 XML 文档注释 + +#### 3. 向后兼容性 +- **API 路径**:保持原有的 API 路径不变 +- **响应格式**:保持原有的响应格式不变 +- **业务逻辑**:保持原有的查询逻辑不变 + +### API 使用示例 + +#### 1. 根据设备代码获取协议日志 +```http +POST /api/protocol-logs/device/DEV001 +Content-Type: application/json + +{ + "startTimestamp": 1640995200000, + "endTimestamp": 1641081600000, + "layerType": "NAS", + "deviceRuntimeStatus": 1, + "runtimeCodes": ["RT-001-DEV001", "RT-002-DEV001"], + "runtimeStatuses": [1, 2], + "orderByDescending": true +} +``` + +#### 2. 获取所有协议日志 +```http +POST /api/protocol-logs/logs +Content-Type: application/json + +{ + "deviceCode": "DEV001", + "startTimestamp": 1640995200000, + "endTimestamp": 1641081600000, + "layerType": "RRC", + "runtimeStatuses": [1] +} +``` + +### 影响范围 +- **API 接口**:从 GET 改为 POST 方式,需要更新客户端调用 +- **参数传递**:从 URL 查询参数改为请求体 JSON 参数 +- **客户端适配**:前端需要更新调用方式 +- **文档更新**:需要更新 API 文档 + +### 注意事项 +- 客户端需要将原来的 GET 请求改为 POST 请求 +- 查询参数需要从 URL 移到请求体中 +- 需要设置正确的 Content-Type 头 +- 保持原有的业务逻辑和响应格式不变 + +--- + ## 2025-01-29 - StopDeviceRuntimeCommandHandler重构优化 ### 修改概述 @@ -1022,480 +1125,6 @@ const addResult = await rolePermissionService.addRolePermissions({ 4. **错误处理**:完善错误处理和用户提示 5. **测试验证**:为所有服务方法添加单元测试 ---- - -## 2025-01-29 修复设备运行时服务接口与后端控制器完全对应 - -### 修改原因 -确保前端设备运行时服务的接口定义与后端控制器完全对应,避免数据类型不匹配和字段缺失问题。 - -### 修改文件 -- `X1.WebUI/src/services/deviceRuntimeService.ts` - 更新接口定义以匹配后端响应实体 - -### 修改内容 - -#### 1. 设备运行时信息接口 (DeviceRuntime) -**对应后端 DeviceRuntimeDto**: -- `deviceCode: string` - 设备编号 -- `runtimeStatus: number` - 运行时状态(对应后端的 int 类型) -- `networkStackCode?: string` - 网络栈配置编号 -- `name?: string` - 设备名称(对应后端的 Name 字段) -- `createdAt: string` - 创建时间(对应后端的 DateTime) - -#### 2. 获取设备运行时状态响应接口 (GetDeviceRuntimeStatusResponse) -**对应后端 GetDeviceRuntimeStatusResponse**: -- `deviceCode: string` - 设备编号 -- `runtimeStatus: string` - 运行时状态(对应后端的 string 类型) -- `runtimeCode?: string` - 运行编码 -- `networkStackCode?: string` - 网络栈配置编号 - -#### 3. 启动设备请求接口 (StartDeviceRequest) -**对应后端 DeviceStartRequest**: -- `deviceCode: string` - 设备编号 -- `networkStackCode: string` - 网络栈配置编号(必填字段) - -#### 4. 启动设备响应接口 (StartDeviceRuntimeResponse) -**对应后端 StartDeviceRuntimeResponse**: -- `id?: string` - 运行时状态ID -- `deviceCode?: string` - 设备编号 -- `runtimeStatus?: string` - 运行时状态 -- `networkStackCode?: string` - 网络栈配置编号 -- `updatedAt: string` - 更新时间 -- `deviceResults?: DeviceStartResult[]` - 设备启动结果列表 -- `summary?: BatchOperationSummary` - 批量操作统计 - -#### 5. 设备启动结果接口 (DeviceStartResult) -**对应后端 DeviceStartResult**: -- `deviceCode: string` - 设备编号 -- `id: string` - 运行时状态ID -- `runtimeStatus: string` - 运行时状态 -- `networkStackCode?: string` - 网络栈配置编号 -- `updatedAt: string` - 更新时间 -- `isSuccess: boolean` - 是否成功 -- `errorMessage?: string` - 错误信息 - -#### 6. 批量操作统计接口 (BatchOperationSummary) -**对应后端 BatchOperationSummary**: -- `totalCount: number` - 总设备数 -- `successCount: number` - 成功数量 -- `failureCount: number` - 失败数量 -- `successRate: number` - 成功率(对应后端的计算属性) - -#### 7. 停止设备响应接口 (StopDeviceRuntimeResponse) -**对应后端 StopDeviceRuntimeResponse**: -- `id: string` - 运行时状态ID -- `deviceCode: string` - 设备编号 -- `runtimeStatus: string` - 运行时状态 -- `runtimeCode?: string` - 运行编码 -- `networkStackCode?: string` - 网络栈配置编号 -- `updatedAt: string` - 更新时间 - -### 技术改进 - -#### 1. 状态类型处理 -- **数字状态转换**:添加 `getRuntimeStatusString()` 方法,将数字状态转换为字符串状态 -- **状态描述方法**:更新 `getRuntimeStatusDescription()` 和 `getRuntimeStatusColor()` 方法,支持数字和字符串状态 -- **状态映射**: - - 0: Initializing(初始化) - - 1: Running(运行中) - - 2: Stopped(已停止) - - 3: Error(错误) - -#### 2. 查询参数处理 -- **运行时状态过滤**:修复 `runtimeStatus` 参数处理,支持数字类型 -- **参数验证**:使用 `!== undefined` 检查,避免 0 值被忽略 - -#### 3. 接口注释 -- **对应关系说明**:为每个接口添加注释,说明对应的后端实体 -- **字段类型说明**:标注字段类型与后端的对应关系 - -### 影响范围 -- **类型安全**:确保前端接口定义与后端API完全匹配 -- **数据一致性**:避免因字段不匹配导致的数据丢失 -- **开发体验**:提供准确的类型提示和代码补全 -- **错误减少**:减少运行时类型错误 - -### 使用示例更新 -``` -// 获取设备运行时状态列表(使用数字状态过滤) -const result = await deviceRuntimeService.getDeviceRuntimes({ - pageNumber: 1, - pageSize: 10, - searchTerm: 'DEV001', - runtimeStatus: 1 // 对应 Running 状态 -}); - -// 启动设备(需要提供网络栈配置编号) -const startResult = await deviceRuntimeService.startDevices([ - { deviceCode: 'DEV001', networkStackCode: 'STACK001' }, - { deviceCode: 'DEV002', networkStackCode: 'STACK002' } -]); - -// 处理启动结果 -if (startResult.isSuccess && startResult.data?.summary) { - console.log(`启动完成:总数 ${startResult.data.summary.totalCount},成功 ${startResult.data.summary.successCount},失败 ${startResult.data.summary.failureCount}`); -} -``` - ---- - -## 2025-01-29 实现设备运行时管理前端界面 - -### 修改原因 -为设备运行时管理功能实现完整的前端界面,包括列表页面、详情页面、搜索功能、批量操作等,提供用户友好的操作体验。 - -### 新增文件 - -#### 1. 设备运行时管理页面 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesView.tsx` - 设备运行时管理主页面 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimesTable.tsx` - 设备运行时表格组件 -- `X1.WebUI/src/pages/device-runtimes/DeviceRuntimeDetail.tsx` - 设备运行时详情页面 - -### 修改文件 - -#### 1. 路由配置 -- `X1.WebUI/src/routes/AppRouter.tsx` - 添加设备运行时管理路由 - -#### 2. 菜单配置 -- `X1.WebUI/src/constants/menuConfig.ts` - 添加设备运行时管理菜单项和权限 - -#### 3. 服务接口 -- `X1.WebUI/src/services/deviceRuntimeService.ts` - 修复GetDeviceRuntimeStatusResponse接口,添加updatedAt字段 - -### 功能特性 - -#### 1. 设备运行时管理主页面 (DeviceRuntimesView.tsx) -- **统计卡片**:显示总设备数、运行中、已停止、错误状态的数量 -- **搜索功能**:支持按设备编号/名称搜索、按运行时状态过滤 -- **批量操作**:支持批量启动设备,需要指定网络栈配置编号 -- **表格显示**:显示设备运行时状态列表,支持分页、排序、列显示控制 -- **实时操作**:支持单个设备停止操作 - -#### 2. 设备运行时表格组件 (DeviceRuntimesTable.tsx) -- **选择功能**:支持单选、全选设备 -- **状态显示**:使用不同颜色的Badge显示运行时状态 -- **操作菜单**:根据设备状态显示不同的操作选项 -- **响应式设计**:支持紧凑、默认、舒适三种密度模式 -- **加载状态**:显示加载中和空数据状态 - -#### 3. 设备运行时详情页面 (DeviceRuntimeDetail.tsx) -- **状态概览**:显示设备运行时状态和基本信息 -- **详细信息**:分卡片显示网络配置和时间信息 -- **实时刷新**:支持手动刷新设备状态 -- **状态持续时间**:计算并显示当前状态的持续时间 -- **导航功能**:提供返回列表的导航 - -### 技术特性 - -#### 1. 组件设计 -- **模块化**:将功能拆分为独立的组件,便于维护和复用 -- **类型安全**:完整的TypeScript类型定义 -- **响应式**:支持不同屏幕尺寸的响应式布局 -- **可访问性**:遵循ARIA标准,支持键盘导航 - -#### 2. 状态管理 -- **本地状态**:使用React hooks管理组件状态 -- **加载状态**:统一的加载和错误状态处理 -- **表单状态**:搜索条件和批量操作的表单状态管理 - -#### 3. 用户体验 -- **即时反馈**:操作后立即显示结果和状态变化 -- **错误处理**:友好的错误提示和恢复机制 -- **操作确认**:重要操作提供确认对话框 -- **进度指示**:长时间操作显示进度状态 - -### 界面功能 - -#### 1. 搜索和过滤 -```typescript -// 搜索条件 -const searchConditions = { - searchTerm: string, // 设备编号或名称 - runtimeStatus: number, // 运行时状态过滤 - pageSize: number // 每页显示数量 -}; -``` - -#### 2. 批量操作 -```typescript -// 批量启动设备 -const batchStartDevices = async (deviceCodes: string[], networkStackCode: string) => { - const deviceRequests = deviceCodes.map(code => ({ - deviceCode: code, - networkStackCode: networkStackCode - })); - return await startDevices(deviceRequests); -}; -``` - -#### 3. 状态显示 -```typescript -// 状态映射 -const statusMapping = { - 0: { text: '初始化', color: 'default' }, - 1: { text: '运行中', color: 'success' }, - 2: { text: '已停止', color: 'warning' }, - 3: { text: '错误', color: 'error' } -}; -``` - -### 路由配置 - -#### 1. 新增路由 -```typescript -// 设备运行时管理路由 - - } /> - } /> - } /> - -``` - -#### 2. 权限控制 -```typescript -// 权限配置 -const permissions = { - 'deviceruntimes.view': '查看设备运行时', - 'deviceruntimes.manage': '管理设备运行时' -}; -``` - -### 菜单配置 - -#### 1. 新增菜单项 -```typescript -{ - title: '设备运行时', - icon: Gauge, - href: '/dashboard/device-runtimes', - permission: 'deviceruntimes.view', - children: [ - { - title: '运行时状态', - href: '/dashboard/device-runtimes/list', - permission: 'deviceruntimes.view', - } - ], -} -``` - -### 使用流程 - -#### 1. 查看设备运行时状态 -1. 导航到"设备运行时" → "运行时状态" -2. 查看设备运行时状态列表 -3. 使用搜索和过滤功能查找特定设备 -4. 点击设备编号查看详细信息 - -#### 2. 批量启动设备 -1. 在设备列表中勾选要启动的设备 -2. 点击"批量启动"按钮 -3. 在弹出的对话框中输入网络栈配置编号 -4. 确认启动操作 - -#### 3. 停止单个设备 -1. 在设备列表中找到运行中的设备 -2. 点击操作菜单中的"停止设备" -3. 确认停止操作 - -#### 4. 查看设备详情 -1. 点击设备编号进入详情页面 -2. 查看设备的运行时状态、网络配置等信息 -3. 使用刷新按钮更新状态 -4. 返回列表页面 - -### 影响范围 -- **前端界面**:提供了完整的设备运行时管理界面 -- **用户体验**:改善了设备运行时管理的操作体验 -- **功能完整性**:实现了设备运行时管理的所有核心功能 -- **系统集成**:与现有的权限系统和导航系统完全集成 - -### 后续优化建议 -1. **实时更新**:添加WebSocket支持,实现设备状态的实时更新 -2. **历史记录**:添加设备运行时历史记录查看功能 -3. **批量导入**:支持批量导入设备配置 -4. **监控告警**:添加设备状态异常告警功能 -5. **操作日志**:记录和查看设备操作历史 - -### 修改原因 -根据后端 `DeviceRuntimesController` 的实现,为前端 `X1.WebUI/src/services` 目录创建对应的服务,实现设备运行时状态管理的完整功能。 - -### 新增文件 - -#### 1. 设备运行时服务 -- `X1.WebUI/src/services/deviceRuntimeService.ts` - 设备运行时状态管理服务 - -#### 2. 设备管理服务 -- `X1.WebUI/src/services/deviceService.ts` - 设备管理服务 - -#### 3. 权限管理服务 -- `X1.WebUI/src/services/permissionService.ts` - 权限管理服务 - -#### 4. 角色权限管理服务 -- `X1.WebUI/src/services/rolePermissionService.ts` - 角色权限管理服务 - -### 修改文件 - -#### 1. API常量配置 -- `X1.WebUI/src/constants/api.ts` - 添加设备运行时、设备、权限、角色权限相关的API路径 - -### 功能特性 - -#### 1. 设备运行时服务 (deviceRuntimeService.ts) -- **设备运行时状态枚举**:`DeviceRuntimeStatus`(Running、Stopped、Error、Unknown) -- **核心功能**: - - `getDeviceRuntimes()` - 获取设备运行时状态列表(支持分页、搜索、状态过滤) - - `getDeviceRuntimeStatus()` - 根据设备编号获取设备运行时状态 - - `startDevices()` - 批量启动设备 - - `stopDevice()` - 停止单个设备 -- **辅助功能**: - - `getRuntimeStatusDescription()` - 获取状态的可读描述 - - `getRuntimeStatusColor()` - 获取状态对应的颜色 - -#### 2. 设备管理服务 (deviceService.ts) -- **核心功能**: - - `getDevices()` - 获取设备列表(支持分页、搜索、类型过滤、状态过滤) - - `getDeviceById()` - 根据ID获取设备详情 - - `createDevice()` - 创建设备 - - `updateDevice()` - 更新设备 - - `deleteDevice()` - 删除设备 -- **辅助功能**: - - `getDeviceStatusDescription()` - 获取设备状态描述 - - `getDeviceStatusColor()` - 获取设备状态颜色 - -#### 3. 权限管理服务 (permissionService.ts) -- **核心功能**: - - `createPermission()` - 创建权限 - - `getPermissions()` - 获取权限列表 - - `getPermissionById()` - 根据ID获取权限详情 - - `deletePermission()` - 删除权限 - -#### 4. 角色权限管理服务 (rolePermissionService.ts) -- **核心功能**: - - `getRolePermissions()` - 获取角色权限 - - `addRolePermissions()` - 添加角色权限 - - `deleteRolePermissions()` - 删除角色权限 - - `batchAddPermissions()` - 批量添加权限到角色 - - `batchRemovePermissions()` - 批量从角色删除权限 -- **辅助功能**: - - `getRolePermissionStats()` - 获取角色权限统计信息 - -### 技术特性 - -#### 1. 类型安全 -- 完整的 TypeScript 接口定义 -- 与后端 API 响应格式完全匹配 -- 提供良好的开发体验和代码提示 - -#### 2. 错误处理 -- 统一的错误处理机制 -- 使用 `OperationResult` 包装响应 -- 详细的错误信息记录 - -#### 3. HTTP 客户端集成 -- 使用 `httpClient` 进行 API 调用 -- 支持 GET、POST、PUT、DELETE 方法 -- 自动处理查询参数构建 - -#### 4. 查询参数支持 -- 分页参数:`pageNumber`、`pageSize` -- 搜索参数:`searchTerm` -- 过滤参数:状态、类型等 -- 排序参数:按时间、名称等排序 - -### API 路径配置 - -#### 1. 新增的 API 路径 -```typescript -export const API_PATHS = { - // 设备相关 - DEVICES: '/devices', - DEVICE_RUNTIMES: '/api/device-runtimes', - - // 权限相关 - PERMISSIONS: '/api/permissions', - ROLE_PERMISSIONS: '/api/role-permissions', - - // ... 其他现有路径 -} -``` - -### 使用示例 - -#### 1. 设备运行时管理 -```typescript -// 获取设备运行时状态列表 -const result = await deviceRuntimeService.getDeviceRuntimes({ - pageNumber: 1, - pageSize: 10, - searchTerm: 'DEV001', - runtimeStatus: DeviceRuntimeStatus.Running -}); - -// 启动设备 -const startResult = await deviceRuntimeService.startDevices([ - { deviceCode: 'DEV001', deviceName: '设备1' }, - { deviceCode: 'DEV002', deviceName: '设备2' } -]); - -// 停止设备 -const stopResult = await deviceRuntimeService.stopDevice('DEV001'); -``` - -#### 2. 设备管理 -```typescript -// 获取设备列表 -const result = await deviceService.getDevices({ - pageNumber: 1, - pageSize: 10, - searchTerm: 'LTE', - deviceType: 'Cellular', - isActive: true -}); - -// 创建设备 -const createResult = await deviceService.createDevice({ - deviceName: '新设备', - deviceCode: 'DEV003', - deviceType: 'Cellular', - description: '测试设备' -}); -``` - -#### 3. 权限管理 -```typescript -// 创建权限 -const result = await permissionService.createPermission({ - name: 'CreateUser', - description: '创建用户的权限' -}); -``` - -#### 4. 角色权限管理 -```typescript -// 获取角色权限 -const result = await rolePermissionService.getRolePermissions('roleId', true); - -// 添加角色权限 -const addResult = await rolePermissionService.addRolePermissions({ - roleId: 'roleId', - permissionIds: ['perm1', 'perm2'] -}); -``` - -### 影响范围 -- **前端服务**:提供了完整的设备运行时、设备、权限、角色权限管理前端服务 -- **API 集成**:与后端控制器完全对应 -- **类型安全**:提供了完整的 TypeScript 类型定义 -- **开发体验**:统一的服务接口,便于前端开发使用 - -### 后续工作建议 -1. **前端页面开发**:基于这些服务开发对应的前端页面 -2. **组件开发**:开发设备运行时状态显示组件 -3. **状态管理**:集成到前端状态管理系统中 -4. **错误处理**:完善错误处理和用户提示 -5. **测试验证**:为所有服务方法添加单元测试 - ## 2025-01-29 更新instrumentService.ts和DevicesView.tsx以匹配后端API ### 修改原因 @@ -2415,7 +2044,7 @@ return runtimes.OrderByDescending(r => r.CreatedAt).FirstOrDefault(); ### 技术细节 - 将 `key={column.key}` 修改为 `key={`${configuration.raN_ConfigurationId}-${column.key}`}`、`key={`${configuration.ims_ConfigurationId}-${column.key}`}` 和 `key={`${config.CoreNetworkConfigId}-${column.key}`}` -- 重构操作列按钮渲染:使用数组map方法替代静态JSX,确保每个按钮都有唯一key +- 重构操作列按钮渲染:使用数组map渲染,确保每个按钮都有唯一key - 使用动态key:将TableHeader和TableBody的key改为 `key={`header-${Date.now()}`}` 和 `key={`body-${Date.now()}`}` - 确保每个表格单元格和子元素都有唯一的key属性 - 避免React渲染时的key冲突问题