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} + /> +
+ +
+ +