From 096077376696b5ba8725edaa313a1d885c2cf649 Mon Sep 17 00:00:00 2001 From: root <295172551@qq.com> Date: Sun, 6 Jul 2025 04:48:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AE=BE=E5=A4=87=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=B8=AD=E7=9A=84ProtocolVersion=E5=AF=BC=E8=88=AA?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E9=97=AE=E9=A2=98=20-=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E4=BB=93=E5=82=A8=E8=AE=BE=E8=AE=A1=EF=BC=8C=E9=81=BF=E5=85=8D?= =?UTF-8?q?N+1=E6=9F=A5=E8=AF=A2=20-=20=E5=9C=A8=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E5=92=8C=E6=9F=A5=E8=AF=A2=E5=A4=84=E7=90=86=E5=99=A8=E4=B8=AD?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE=E6=B3=A8=E5=85=A5IProtocolVersionRepository?= =?UTF-8?q?=20-=20=E4=BC=98=E5=8C=96=E6=89=B9=E9=87=8F=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=80=A7=E8=83=BD=EF=BC=8C=E9=81=BF=E5=85=8D=E4=B8=BA=E6=AF=8F?= =?UTF-8?q?=E4=B8=AA=E8=AE=BE=E5=A4=87=E5=8D=95=E7=8B=AC=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E7=89=88=E6=9C=AC=20-=20=E7=AC=A6=E5=90=88?= =?UTF-8?q?=E5=8D=95=E4=B8=80=E8=81=8C=E8=B4=A3=E5=8E=9F=E5=88=99=EF=BC=8C?= =?UTF-8?q?CellularDeviceRepository=E5=8F=AA=E8=B4=9F=E8=B4=A3=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CreateDevice/CreateDeviceCommand.cs | 5 +- .../CreateDeviceCommandHandler.cs | 9 +- .../UpdateDevice/UpdateDeviceCommand.cs | 2 +- .../UpdateDeviceCommandHandler.cs | 9 +- .../GetDeviceByIdQueryHandler.cs | 8 +- .../GetDevices/GetDevicesQueryHandler.cs | 28 +- .../Device/ICellularDeviceRepository.cs | 8 + .../Device/CellularDeviceRepository.cs | 8 + src/X1.WebUI/src/constants/api.ts | 64 ++++ .../src/pages/instruments/DeviceForm.tsx | 160 +++++++++ .../src/pages/instruments/DevicesTable.tsx | 228 ++++++------ .../src/pages/instruments/DevicesView.tsx | 326 ++++++++++++++---- src/X1.WebUI/src/services/configService.ts | 3 +- src/X1.WebUI/src/services/deviceService.ts | 113 ------ .../src/services/instrumentService.ts | 232 ++++++++++++- src/X1.WebUI/src/services/protocolService.ts | 7 +- 16 files changed, 892 insertions(+), 318 deletions(-) create mode 100644 src/X1.WebUI/src/constants/api.ts create mode 100644 src/X1.WebUI/src/pages/instruments/DeviceForm.tsx delete mode 100644 src/X1.WebUI/src/services/deviceService.ts diff --git a/src/X1.Application/Features/Devices/Commands/CreateDevice/CreateDeviceCommand.cs b/src/X1.Application/Features/Devices/Commands/CreateDevice/CreateDeviceCommand.cs index 13a049b..a26c849 100644 --- a/src/X1.Application/Features/Devices/Commands/CreateDevice/CreateDeviceCommand.cs +++ b/src/X1.Application/Features/Devices/Commands/CreateDevice/CreateDeviceCommand.cs @@ -38,8 +38,9 @@ public class CreateDeviceCommand : IRequest /// IP地址 /// - [MaxLength(45, ErrorMessage = "Agent端口不能为空")] - public string IpAddress { get; private set; } = null!; + [Required(ErrorMessage = "设备IP不能为空")] + [MaxLength(45, ErrorMessage = "IP地址不能超过45个字符")] + public string IpAddress { get; set; } = null!; /// /// Agent端口 diff --git a/src/X1.Application/Features/Devices/Commands/CreateDevice/CreateDeviceCommandHandler.cs b/src/X1.Application/Features/Devices/Commands/CreateDevice/CreateDeviceCommandHandler.cs index 74f4200..2e89723 100644 --- a/src/X1.Application/Features/Devices/Commands/CreateDevice/CreateDeviceCommandHandler.cs +++ b/src/X1.Application/Features/Devices/Commands/CreateDevice/CreateDeviceCommandHandler.cs @@ -15,6 +15,7 @@ namespace CellularManagement.Application.Features.Devices.Commands.CreateDevice; public class CreateDeviceCommandHandler : IRequestHandler> { private readonly ICellularDeviceRepository _deviceRepository; + private readonly IProtocolVersionRepository _protocolVersionRepository; private readonly ILogger _logger; private readonly IUnitOfWork _unitOfWork; private readonly ICurrentUserService _currentUserService; @@ -24,11 +25,13 @@ public class CreateDeviceCommandHandler : IRequestHandler public CreateDeviceCommandHandler( ICellularDeviceRepository deviceRepository, + IProtocolVersionRepository protocolVersionRepository, ILogger logger, IUnitOfWork unitOfWork, ICurrentUserService currentUserService) { _deviceRepository = deviceRepository; + _protocolVersionRepository = protocolVersionRepository; _logger = logger; _unitOfWork = unitOfWork; _currentUserService = currentUserService; @@ -77,8 +80,8 @@ public class CreateDeviceCommandHandler : IRequestHandler [Required] [MaxLength(45)] - public string IpAddress { get; private set; } = null!; + public string IpAddress { get; set; } = null!; /// /// Agent端口 /// diff --git a/src/X1.Application/Features/Devices/Commands/UpdateDevice/UpdateDeviceCommandHandler.cs b/src/X1.Application/Features/Devices/Commands/UpdateDevice/UpdateDeviceCommandHandler.cs index 8ad839a..71c6465 100644 --- a/src/X1.Application/Features/Devices/Commands/UpdateDevice/UpdateDeviceCommandHandler.cs +++ b/src/X1.Application/Features/Devices/Commands/UpdateDevice/UpdateDeviceCommandHandler.cs @@ -17,6 +17,7 @@ namespace CellularManagement.Application.Features.Devices.Commands.UpdateDevice; public class UpdateDeviceCommandHandler : IRequestHandler> { private readonly ICellularDeviceRepository _deviceRepository; + private readonly IProtocolVersionRepository _protocolVersionRepository; private readonly ILogger _logger; private readonly IUnitOfWork _unitOfWork; private readonly ICurrentUserService _currentUserService; @@ -26,11 +27,13 @@ public class UpdateDeviceCommandHandler : IRequestHandler public UpdateDeviceCommandHandler( ICellularDeviceRepository deviceRepository, + IProtocolVersionRepository protocolVersionRepository, ILogger logger, IUnitOfWork unitOfWork, ICurrentUserService currentUserService) { _deviceRepository = deviceRepository; + _protocolVersionRepository = protocolVersionRepository; _logger = logger; _unitOfWork = unitOfWork; _currentUserService = currentUserService; @@ -89,8 +92,8 @@ public class UpdateDeviceCommandHandler : IRequestHandler> { private readonly ICellularDeviceRepository _deviceRepository; + private readonly IProtocolVersionRepository _protocolVersionRepository; private readonly ILogger _logger; /// @@ -20,9 +21,11 @@ public class GetDeviceByIdQueryHandler : IRequestHandler public GetDeviceByIdQueryHandler( ICellularDeviceRepository deviceRepository, + IProtocolVersionRepository protocolVersionRepository, ILogger logger) { _deviceRepository = deviceRepository; + _protocolVersionRepository = protocolVersionRepository; _logger = logger; } @@ -43,13 +46,16 @@ public class GetDeviceByIdQueryHandler : IRequestHandler.CreateFailure($"未找到ID为 {request.DeviceId} 的设备"); } + // 获取协议版本信息 + var protocolVersion = await _protocolVersionRepository.GetProtocolVersionByIdAsync(device.ProtocolVersionId, cancellationToken); + var response = new GetDeviceByIdResponse { DeviceId = device.Id, DeviceName = device.Name, SerialNumber = device.SerialNumber, Description = device.Description, - ProtocolVersion = device.ProtocolVersion?.Version ?? "未知", + ProtocolVersion = protocolVersion?.Version ?? "未知", AgentPort = device.AgentPort, IsEnabled = device.IsEnabled, IsRunning = device.IsRunning, diff --git a/src/X1.Application/Features/Devices/Queries/GetDevices/GetDevicesQueryHandler.cs b/src/X1.Application/Features/Devices/Queries/GetDevices/GetDevicesQueryHandler.cs index afdbb73..82be90d 100644 --- a/src/X1.Application/Features/Devices/Queries/GetDevices/GetDevicesQueryHandler.cs +++ b/src/X1.Application/Features/Devices/Queries/GetDevices/GetDevicesQueryHandler.cs @@ -16,6 +16,7 @@ namespace CellularManagement.Application.Features.Devices.Queries.GetDevices; public class GetDevicesQueryHandler : IRequestHandler> { private readonly ICellularDeviceRepository _deviceRepository; + private readonly IProtocolVersionRepository _protocolVersionRepository; private readonly ILogger _logger; /// @@ -23,9 +24,11 @@ public class GetDevicesQueryHandler : IRequestHandler public GetDevicesQueryHandler( ICellularDeviceRepository deviceRepository, + IProtocolVersionRepository protocolVersionRepository, ILogger logger) { _deviceRepository = deviceRepository; + _protocolVersionRepository = protocolVersionRepository; _logger = logger; } @@ -61,6 +64,11 @@ public class GetDevicesQueryHandler : IRequestHandler d.ProtocolVersionId).Distinct().ToList(); + var allProtocolVersions = await _protocolVersionRepository.GetAllProtocolVersionsAsync(cancellationToken); + var protocolVersionDict = allProtocolVersions.ToDictionary(pv => pv.Id, pv => pv.Version); + // 构建响应 var response = new GetDevicesResponse { @@ -70,17 +78,17 @@ public class GetDevicesQueryHandler : IRequestHandler 1, HasNextPage = request.PageNumber < (int)Math.Ceiling(totalCount / (double)request.PageSize), - Items = items.Select(d => new GetDeviceByIdResponse + Items = items.Select(device => new GetDeviceByIdResponse { - DeviceId = d.Id, - DeviceName = d.Name, - SerialNumber = d.SerialNumber, - Description = d.Description, - ProtocolVersion = d.ProtocolVersion?.Version ?? "未知", - AgentPort = d.AgentPort, - IsEnabled = d.IsEnabled, - IsRunning = d.IsRunning, - CreatedAt = d.CreatedAt + DeviceId = device.Id, + DeviceName = device.Name, + SerialNumber = device.SerialNumber, + Description = device.Description, + ProtocolVersion = protocolVersionDict.TryGetValue(device.ProtocolVersionId, out var version) ? version : "未知", + AgentPort = device.AgentPort, + IsEnabled = device.IsEnabled, + IsRunning = device.IsRunning, + CreatedAt = device.CreatedAt }).ToList() }; diff --git a/src/X1.Domain/Repositories/Device/ICellularDeviceRepository.cs b/src/X1.Domain/Repositories/Device/ICellularDeviceRepository.cs index 97d133f..87e121b 100644 --- a/src/X1.Domain/Repositories/Device/ICellularDeviceRepository.cs +++ b/src/X1.Domain/Repositories/Device/ICellularDeviceRepository.cs @@ -35,6 +35,10 @@ public interface ICellularDeviceRepository : IBaseRepository /// Task GetDeviceByIdAsync(string id, CancellationToken cancellationToken = default); + + + + /// /// 根据序列号获取蜂窝设备 /// @@ -47,6 +51,10 @@ public interface ICellularDeviceRepository : IBaseRepository string? keyword, CancellationToken cancellationToken = default); + + + + /// /// 检查蜂窝设备是否存在 /// diff --git a/src/X1.Infrastructure/Repositories/Device/CellularDeviceRepository.cs b/src/X1.Infrastructure/Repositories/Device/CellularDeviceRepository.cs index 9aafabf..c033a1d 100644 --- a/src/X1.Infrastructure/Repositories/Device/CellularDeviceRepository.cs +++ b/src/X1.Infrastructure/Repositories/Device/CellularDeviceRepository.cs @@ -76,6 +76,10 @@ public class CellularDeviceRepository : BaseRepository, ICellula return await QueryRepository.GetByIdAsync(id, cancellationToken); } + + + + /// /// 根据序列号获取蜂窝设备 /// @@ -105,6 +109,10 @@ public class CellularDeviceRepository : BaseRepository, ICellula return devices.ToList(); } + + + + /// /// 检查蜂窝设备是否存在 /// diff --git a/src/X1.WebUI/src/constants/api.ts b/src/X1.WebUI/src/constants/api.ts new file mode 100644 index 0000000..8a93493 --- /dev/null +++ b/src/X1.WebUI/src/constants/api.ts @@ -0,0 +1,64 @@ +// API 路径常量 +export const API_PATHS = { + // 设备相关 + DEVICES: '/devices', + + // 协议相关 + PROTOCOLS: '/protocolversions', + + // 配置相关 + CONFIGS: '/instruments/configs', + + // 用户相关 + USERS: '/users', + ROLES: '/roles', + + // 认证相关 + AUTH: { + LOGIN: '/auth/login', + REGISTER: '/auth/register', + REFRESH: '/auth/refresh', + LOGOUT: '/auth/logout', + }, + + // 任务相关 + TASKS: '/tasks', + TASK_EXECUTIONS: '/task-executions', + TASK_REVIEWS: '/task-reviews', + + // 场景相关 + SCENARIOS: '/scenarios', + + // 测试用例相关 + TEST_CASES: '/test-cases', + TEST_STEPS: '/test-steps', + + // 分析相关 + ANALYSIS: { + FUNCTIONAL: '/analysis/functional', + PERFORMANCE: '/analysis/performance', + ISSUE: '/analysis/issue', + UE: '/analysis/ue', + } +} as const; + +// API 响应状态码 +export const API_STATUS = { + SUCCESS: 200, + CREATED: 201, + NO_CONTENT: 204, + BAD_REQUEST: 400, + UNAUTHORIZED: 401, + FORBIDDEN: 403, + NOT_FOUND: 404, + INTERNAL_SERVER_ERROR: 500, +} as const; + +// HTTP 方法 +export const HTTP_METHODS = { + GET: 'GET', + POST: 'POST', + PUT: 'PUT', + DELETE: 'DELETE', + PATCH: 'PATCH', +} as const; \ No newline at end of file diff --git a/src/X1.WebUI/src/pages/instruments/DeviceForm.tsx b/src/X1.WebUI/src/pages/instruments/DeviceForm.tsx new file mode 100644 index 0000000..e7e91a3 --- /dev/null +++ b/src/X1.WebUI/src/pages/instruments/DeviceForm.tsx @@ -0,0 +1,160 @@ +import React, { useEffect, useState } from 'react'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Textarea } from '@/components/ui/textarea'; +import { Checkbox } from '@/components/ui/checkbox'; +import { CreateDeviceRequest, UpdateDeviceRequest } from '@/services/instrumentService'; +import { protocolService, ProtocolVersion } from '@/services/protocolService'; + +interface DeviceFormProps { + onSubmit: (data: CreateDeviceRequest | UpdateDeviceRequest) => void; + initialData?: Partial; + isEdit?: boolean; + isSubmitting?: boolean; +} + +export default function DeviceForm({ onSubmit, initialData, isEdit = false, isSubmitting = false }: DeviceFormProps) { + const [formData, setFormData] = React.useState({ + deviceName: initialData?.deviceName || '', + serialNumber: initialData?.serialNumber || '', + description: initialData?.description || '', + protocolVersionId: initialData?.protocolVersionId || '', + ipAddress: initialData?.ipAddress || '', + agentPort: initialData?.agentPort || 8080, + isEnabled: initialData?.isEnabled ?? false, + isRunning: initialData?.isRunning ?? false + }); + + const [protocolVersions, setProtocolVersions] = useState([]); + const [loadingProtocols, setLoadingProtocols] = useState(false); + + // 加载协议版本列表 + useEffect(() => { + const loadProtocolVersions = async () => { + setLoadingProtocols(true); + try { + const result = await protocolService.getProtocolVersions({ + pageSize: 100, + isEnabled: true + }); + if (result.isSuccess && result.data) { + setProtocolVersions(result.data.items || []); + + // 如果是编辑模式且有初始数据,尝试根据协议版本名称找到对应的ID + if (isEdit && initialData && !initialData.protocolVersionId) { + // 这里需要根据实际情况来匹配协议版本 + // 由于后端返回的是协议版本名称,我们需要找到对应的ID + // 暂时设置为空,需要后端提供更详细的设备信息 + } + } + } catch (error) { + console.error('加载协议版本失败:', error); + } finally { + setLoadingProtocols(false); + } + }; + + loadProtocolVersions(); + }, [isEdit, initialData]); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + if (isSubmitting) return; // 防止重复提交 + onSubmit(formData); + }; + + return ( +
+
+ + setFormData({ ...formData, deviceName: e.target.value })} + placeholder="请输入设备名称" + required + disabled={isSubmitting} + /> +
+ +
+ + setFormData({ ...formData, serialNumber: e.target.value })} + placeholder="请输入设备序列号" + required + disabled={isSubmitting} + /> +
+ +
+ +