diff --git a/src/X1.Application/Features/TestCaseSets/Commands/CreateTestCaseSet/CreateTestCaseSetCommand.cs b/src/X1.Application/Features/TestCaseSets/Commands/CreateTestCaseSet/CreateTestCaseSetCommand.cs new file mode 100644 index 0000000..c177f08 --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Commands/CreateTestCaseSet/CreateTestCaseSetCommand.cs @@ -0,0 +1,55 @@ +using CellularManagement.Domain.Common; +using MediatR; +using System.ComponentModel.DataAnnotations; + +namespace CellularManagement.Application.Features.TestCaseSets.Commands.CreateTestCaseSet; + +/// +/// 创建用例集命令 +/// +public class CreateTestCaseSetCommand : IRequest> +{ + /// + /// 用例集编码 + /// + [Required(ErrorMessage = "用例集编码不能为空")] + [MaxLength(50, ErrorMessage = "用例集编码长度不能超过50个字符")] + public string Code { get; set; } = null!; + + /// + /// 用例集名称 + /// + [Required(ErrorMessage = "用例集名称不能为空")] + [MaxLength(100, ErrorMessage = "用例集名称长度不能超过100个字符")] + public string Name { get; set; } = null!; + + /// + /// 用例集说明 + /// + [MaxLength(1000, ErrorMessage = "用例集说明长度不能超过1000个字符")] + public string? Description { get; set; } + + /// + /// 用例集版本 + /// + [Required(ErrorMessage = "用例集版本不能为空")] + [MaxLength(20, ErrorMessage = "用例集版本长度不能超过20个字符")] + public string Version { get; set; } = null!; + + /// + /// 版本更新信息 + /// + [MaxLength(500, ErrorMessage = "版本更新信息长度不能超过500个字符")] + public string? VersionUpdateInfo { get; set; } + + /// + /// 是否禁用 + /// + public bool IsDisabled { get; set; } = false; + + /// + /// 备注 + /// + [MaxLength(1000, ErrorMessage = "备注长度不能超过1000个字符")] + public string? Remarks { get; set; } +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Commands/CreateTestCaseSet/CreateTestCaseSetCommandHandler.cs b/src/X1.Application/Features/TestCaseSets/Commands/CreateTestCaseSet/CreateTestCaseSetCommandHandler.cs new file mode 100644 index 0000000..e9f3f02 --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Commands/CreateTestCaseSet/CreateTestCaseSetCommandHandler.cs @@ -0,0 +1,111 @@ +using MediatR; +using Microsoft.Extensions.Logging; +using CellularManagement.Domain.Common; +using CellularManagement.Domain.Entities.Device; +using CellularManagement.Domain.Repositories.Device; +using CellularManagement.Domain.Repositories.Base; +using CellularManagement.Domain.Services; + +namespace CellularManagement.Application.Features.TestCaseSets.Commands.CreateTestCaseSet; + +/// +/// 创建用例集命令处理器 +/// +public class CreateTestCaseSetCommandHandler : IRequestHandler> +{ + private readonly ITestCaseSetRepository _testCaseSetRepository; + private readonly ILogger _logger; + private readonly IUnitOfWork _unitOfWork; + private readonly ICurrentUserService _currentUserService; + + /// + /// 初始化命令处理器 + /// + public CreateTestCaseSetCommandHandler( + ITestCaseSetRepository testCaseSetRepository, + ILogger logger, + IUnitOfWork unitOfWork, + ICurrentUserService currentUserService) + { + _testCaseSetRepository = testCaseSetRepository; + _logger = logger; + _unitOfWork = unitOfWork; + _currentUserService = currentUserService; + } + + /// + /// 处理创建用例集命令 + /// + public async Task> Handle(CreateTestCaseSetCommand request, CancellationToken cancellationToken) + { + try + { + _logger.LogInformation("开始创建用例集,用例集编码: {Code}, 用例集名称: {Name}, 版本: {Version}", + request.Code, request.Name, request.Version); + + // 检查用例集编码是否已存在 + if (await _testCaseSetRepository.CodeExistsAsync(request.Code, cancellationToken)) + { + _logger.LogWarning("用例集编码已存在: {Code}", request.Code); + return OperationResult.CreateFailure($"用例集编码 {request.Code} 已存在"); + } + + // 检查用例集版本是否已存在 + if (await _testCaseSetRepository.VersionExistsAsync(request.Version, cancellationToken)) + { + _logger.LogWarning("用例集版本已存在: {Version}", request.Version); + return OperationResult.CreateFailure($"用例集版本 {request.Version} 已存在"); + } + + // 获取当前用户ID + var currentUserId = _currentUserService.GetCurrentUserId(); + if (string.IsNullOrEmpty(currentUserId)) + { + _logger.LogError("无法获取当前用户ID,用户可能未认证"); + return OperationResult.CreateFailure("用户未认证,无法创建用例集"); + } + + // 创建用例集实体 + var testCaseSet = TestCaseSet.Create( + code: request.Code, + name: request.Name, + version: request.Version, + createdBy: currentUserId, + description: request.Description, + versionUpdateInfo: request.VersionUpdateInfo, + isDisabled: request.IsDisabled, + remarks: request.Remarks); + + // 保存用例集 + await _testCaseSetRepository.AddTestCaseSetAsync(testCaseSet, cancellationToken); + + // 保存更改到数据库 + await _unitOfWork.SaveChangesAsync(cancellationToken); + + // 构建响应 + var response = new CreateTestCaseSetResponse + { + TestCaseSetId = testCaseSet.Id, + Code = testCaseSet.Code, + Name = testCaseSet.Name, + Description = testCaseSet.Description, + Version = testCaseSet.Version, + VersionUpdateInfo = testCaseSet.VersionUpdateInfo, + IsDisabled = testCaseSet.IsDisabled, + Remarks = testCaseSet.Remarks, + CreatedAt = testCaseSet.CreatedAt, + CreatedBy = testCaseSet.CreatedBy + }; + + _logger.LogInformation("用例集创建成功,用例集ID: {TestCaseSetId}, 用例集编码: {Code}, 用例集名称: {Name}, 版本: {Version}", + testCaseSet.Id, testCaseSet.Code, testCaseSet.Name, testCaseSet.Version); + return OperationResult.CreateSuccess(response); + } + catch (Exception ex) + { + _logger.LogError(ex, "创建用例集时发生错误,用例集编码: {Code}, 用例集名称: {Name}, 版本: {Version}", + request.Code, request.Name, request.Version); + return OperationResult.CreateFailure($"创建用例集时发生错误: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Commands/CreateTestCaseSet/CreateTestCaseSetResponse.cs b/src/X1.Application/Features/TestCaseSets/Commands/CreateTestCaseSet/CreateTestCaseSetResponse.cs new file mode 100644 index 0000000..f665b0b --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Commands/CreateTestCaseSet/CreateTestCaseSetResponse.cs @@ -0,0 +1,57 @@ +namespace CellularManagement.Application.Features.TestCaseSets.Commands.CreateTestCaseSet; + +/// +/// 创建用例集响应 +/// +public class CreateTestCaseSetResponse +{ + /// + /// 用例集ID + /// + public string TestCaseSetId { get; set; } = null!; + + /// + /// 用例集编码 + /// + public string Code { get; set; } = null!; + + /// + /// 用例集名称 + /// + public string Name { get; set; } = null!; + + /// + /// 用例集说明 + /// + public string? Description { get; set; } + + /// + /// 用例集版本 + /// + public string Version { get; set; } = null!; + + /// + /// 版本更新信息 + /// + public string? VersionUpdateInfo { get; set; } + + /// + /// 是否禁用 + /// + public bool IsDisabled { get; set; } + + /// + /// 备注 + /// + public string? Remarks { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreatedAt { get; set; } + + /// + /// 创建人 + /// + public string CreatedBy { get; set; } = null!; +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Commands/DeleteTestCaseSet/DeleteTestCaseSetCommand.cs b/src/X1.Application/Features/TestCaseSets/Commands/DeleteTestCaseSet/DeleteTestCaseSetCommand.cs new file mode 100644 index 0000000..0e823fc --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Commands/DeleteTestCaseSet/DeleteTestCaseSetCommand.cs @@ -0,0 +1,18 @@ +using CellularManagement.Domain.Common; +using MediatR; +using System.ComponentModel.DataAnnotations; + +namespace CellularManagement.Application.Features.TestCaseSets.Commands.DeleteTestCaseSet; + +/// +/// 删除用例集命令 +/// +public class DeleteTestCaseSetCommand : IRequest> +{ + /// + /// 用例集ID + /// + [Required(ErrorMessage = "用例集ID不能为空")] + [MaxLength(50, ErrorMessage = "用例集ID长度不能超过50个字符")] + public string TestCaseSetId { get; set; } = null!; +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Commands/DeleteTestCaseSet/DeleteTestCaseSetCommandHandler.cs b/src/X1.Application/Features/TestCaseSets/Commands/DeleteTestCaseSet/DeleteTestCaseSetCommandHandler.cs new file mode 100644 index 0000000..26d5dd6 --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Commands/DeleteTestCaseSet/DeleteTestCaseSetCommandHandler.cs @@ -0,0 +1,96 @@ +using MediatR; +using Microsoft.Extensions.Logging; +using CellularManagement.Domain.Common; +using CellularManagement.Domain.Entities.Device; +using CellularManagement.Domain.Repositories.Device; +using CellularManagement.Domain.Repositories.Base; +using CellularManagement.Domain.Services; + +namespace CellularManagement.Application.Features.TestCaseSets.Commands.DeleteTestCaseSet; + +/// +/// 删除用例集命令处理器 +/// +public class DeleteTestCaseSetCommandHandler : IRequestHandler> +{ + private readonly ITestCaseSetRepository _testCaseSetRepository; + private readonly ILogger _logger; + private readonly IUnitOfWork _unitOfWork; + private readonly ICurrentUserService _currentUserService; + + /// + /// 初始化命令处理器 + /// + public DeleteTestCaseSetCommandHandler( + ITestCaseSetRepository testCaseSetRepository, + ILogger logger, + IUnitOfWork unitOfWork, + ICurrentUserService currentUserService) + { + _testCaseSetRepository = testCaseSetRepository; + _logger = logger; + _unitOfWork = unitOfWork; + _currentUserService = currentUserService; + } + + /// + /// 处理删除用例集命令 + /// + public async Task> Handle(DeleteTestCaseSetCommand request, CancellationToken cancellationToken) + { + try + { + _logger.LogInformation("开始删除用例集,用例集ID: {TestCaseSetId}", request.TestCaseSetId); + + // 检查用例集是否存在 + var existingTestCaseSet = await _testCaseSetRepository.GetTestCaseSetByIdAsync(request.TestCaseSetId, cancellationToken); + if (existingTestCaseSet == null) + { + _logger.LogWarning("用例集不存在: {TestCaseSetId}", request.TestCaseSetId); + return OperationResult.CreateFailure($"用例集ID {request.TestCaseSetId} 不存在"); + } + + // 检查用例集是否已被软删除 + if (existingTestCaseSet.IsDeleted) + { + _logger.LogWarning("用例集已被删除: {TestCaseSetId}", request.TestCaseSetId); + return OperationResult.CreateFailure($"用例集ID {request.TestCaseSetId} 已被删除"); + } + + // 获取当前用户ID + var currentUserId = _currentUserService.GetCurrentUserId(); + if (string.IsNullOrEmpty(currentUserId)) + { + _logger.LogError("无法获取当前用户ID,用户可能未认证"); + return OperationResult.CreateFailure("用户未认证,无法删除用例集"); + } + + // 软删除用例集 + existingTestCaseSet.SoftDelete(); + existingTestCaseSet.Update( + code: existingTestCaseSet.Code, + name: existingTestCaseSet.Name, + version: existingTestCaseSet.Version, + updatedBy: currentUserId, + description: existingTestCaseSet.Description, + versionUpdateInfo: existingTestCaseSet.VersionUpdateInfo, + isDisabled: existingTestCaseSet.IsDisabled, + remarks: existingTestCaseSet.Remarks); + + // 保存更改 + _testCaseSetRepository.UpdateTestCaseSet(existingTestCaseSet); + + // 保存更改到数据库 + await _unitOfWork.SaveChangesAsync(cancellationToken); + + _logger.LogInformation("用例集删除成功,用例集ID: {TestCaseSetId}, 用例集编码: {Code}, 用例集名称: {Name}, 版本: {Version}", + existingTestCaseSet.Id, existingTestCaseSet.Code, existingTestCaseSet.Name, existingTestCaseSet.Version); + return OperationResult.CreateSuccess(true); + } + catch (Exception ex) + { + _logger.LogError(ex, "删除用例集时发生错误,用例集ID: {TestCaseSetId}", request.TestCaseSetId); + return OperationResult.CreateFailure($"删除用例集时发生错误: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Commands/DisableTestCaseSet/DisableTestCaseSetCommand.cs b/src/X1.Application/Features/TestCaseSets/Commands/DisableTestCaseSet/DisableTestCaseSetCommand.cs new file mode 100644 index 0000000..a0323fc --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Commands/DisableTestCaseSet/DisableTestCaseSetCommand.cs @@ -0,0 +1,18 @@ +using CellularManagement.Domain.Common; +using MediatR; +using System.ComponentModel.DataAnnotations; + +namespace CellularManagement.Application.Features.TestCaseSets.Commands.DisableTestCaseSet; + +/// +/// 禁用用例集命令 +/// +public class DisableTestCaseSetCommand : IRequest> +{ + /// + /// 用例集ID + /// + [Required(ErrorMessage = "用例集ID不能为空")] + [MaxLength(50, ErrorMessage = "用例集ID长度不能超过50个字符")] + public string TestCaseSetId { get; set; } = null!; +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Commands/DisableTestCaseSet/DisableTestCaseSetCommandHandler.cs b/src/X1.Application/Features/TestCaseSets/Commands/DisableTestCaseSet/DisableTestCaseSetCommandHandler.cs new file mode 100644 index 0000000..07d1075 --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Commands/DisableTestCaseSet/DisableTestCaseSetCommandHandler.cs @@ -0,0 +1,103 @@ +using MediatR; +using Microsoft.Extensions.Logging; +using CellularManagement.Domain.Common; +using CellularManagement.Domain.Entities.Device; +using CellularManagement.Domain.Repositories.Device; +using CellularManagement.Domain.Repositories.Base; +using CellularManagement.Domain.Services; + +namespace CellularManagement.Application.Features.TestCaseSets.Commands.DisableTestCaseSet; + +/// +/// 禁用用例集命令处理器 +/// +public class DisableTestCaseSetCommandHandler : IRequestHandler> +{ + private readonly ITestCaseSetRepository _testCaseSetRepository; + private readonly ILogger _logger; + private readonly IUnitOfWork _unitOfWork; + private readonly ICurrentUserService _currentUserService; + + /// + /// 初始化命令处理器 + /// + public DisableTestCaseSetCommandHandler( + ITestCaseSetRepository testCaseSetRepository, + ILogger logger, + IUnitOfWork unitOfWork, + ICurrentUserService currentUserService) + { + _testCaseSetRepository = testCaseSetRepository; + _logger = logger; + _unitOfWork = unitOfWork; + _currentUserService = currentUserService; + } + + /// + /// 处理禁用用例集命令 + /// + public async Task> Handle(DisableTestCaseSetCommand request, CancellationToken cancellationToken) + { + try + { + _logger.LogInformation("开始禁用用例集,用例集ID: {TestCaseSetId}", request.TestCaseSetId); + + // 检查用例集是否存在 + var existingTestCaseSet = await _testCaseSetRepository.GetTestCaseSetByIdAsync(request.TestCaseSetId, cancellationToken); + if (existingTestCaseSet == null) + { + _logger.LogWarning("用例集不存在: {TestCaseSetId}", request.TestCaseSetId); + return OperationResult.CreateFailure($"用例集ID {request.TestCaseSetId} 不存在"); + } + + // 检查用例集是否已被软删除 + if (existingTestCaseSet.IsDeleted) + { + _logger.LogWarning("用例集已被删除: {TestCaseSetId}", request.TestCaseSetId); + return OperationResult.CreateFailure($"用例集ID {request.TestCaseSetId} 已被删除"); + } + + // 检查用例集是否已经禁用 + if (existingTestCaseSet.IsDisabled) + { + _logger.LogWarning("用例集已经禁用: {TestCaseSetId}", request.TestCaseSetId); + return OperationResult.CreateFailure($"用例集ID {request.TestCaseSetId} 已经禁用"); + } + + // 获取当前用户ID + var currentUserId = _currentUserService.GetCurrentUserId(); + if (string.IsNullOrEmpty(currentUserId)) + { + _logger.LogError("无法获取当前用户ID,用户可能未认证"); + return OperationResult.CreateFailure("用户未认证,无法禁用用例集"); + } + + // 禁用用例集 + existingTestCaseSet.Disable(); + existingTestCaseSet.Update( + code: existingTestCaseSet.Code, + name: existingTestCaseSet.Name, + version: existingTestCaseSet.Version, + updatedBy: currentUserId, + description: existingTestCaseSet.Description, + versionUpdateInfo: existingTestCaseSet.VersionUpdateInfo, + isDisabled: true, + remarks: existingTestCaseSet.Remarks); + + // 保存更改 + _testCaseSetRepository.UpdateTestCaseSet(existingTestCaseSet); + + // 保存更改到数据库 + await _unitOfWork.SaveChangesAsync(cancellationToken); + + _logger.LogInformation("用例集禁用成功,用例集ID: {TestCaseSetId}, 用例集编码: {Code}, 用例集名称: {Name}, 版本: {Version}", + existingTestCaseSet.Id, existingTestCaseSet.Code, existingTestCaseSet.Name, existingTestCaseSet.Version); + return OperationResult.CreateSuccess(true); + } + catch (Exception ex) + { + _logger.LogError(ex, "禁用用例集时发生错误,用例集ID: {TestCaseSetId}", request.TestCaseSetId); + return OperationResult.CreateFailure($"禁用用例集时发生错误: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Commands/EnableTestCaseSet/EnableTestCaseSetCommand.cs b/src/X1.Application/Features/TestCaseSets/Commands/EnableTestCaseSet/EnableTestCaseSetCommand.cs new file mode 100644 index 0000000..8f08f31 --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Commands/EnableTestCaseSet/EnableTestCaseSetCommand.cs @@ -0,0 +1,18 @@ +using CellularManagement.Domain.Common; +using MediatR; +using System.ComponentModel.DataAnnotations; + +namespace CellularManagement.Application.Features.TestCaseSets.Commands.EnableTestCaseSet; + +/// +/// 启用用例集命令 +/// +public class EnableTestCaseSetCommand : IRequest> +{ + /// + /// 用例集ID + /// + [Required(ErrorMessage = "用例集ID不能为空")] + [MaxLength(50, ErrorMessage = "用例集ID长度不能超过50个字符")] + public string TestCaseSetId { get; set; } = null!; +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Commands/EnableTestCaseSet/EnableTestCaseSetCommandHandler.cs b/src/X1.Application/Features/TestCaseSets/Commands/EnableTestCaseSet/EnableTestCaseSetCommandHandler.cs new file mode 100644 index 0000000..be8bf6c --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Commands/EnableTestCaseSet/EnableTestCaseSetCommandHandler.cs @@ -0,0 +1,103 @@ +using MediatR; +using Microsoft.Extensions.Logging; +using CellularManagement.Domain.Common; +using CellularManagement.Domain.Entities.Device; +using CellularManagement.Domain.Repositories.Device; +using CellularManagement.Domain.Repositories.Base; +using CellularManagement.Domain.Services; + +namespace CellularManagement.Application.Features.TestCaseSets.Commands.EnableTestCaseSet; + +/// +/// 启用用例集命令处理器 +/// +public class EnableTestCaseSetCommandHandler : IRequestHandler> +{ + private readonly ITestCaseSetRepository _testCaseSetRepository; + private readonly ILogger _logger; + private readonly IUnitOfWork _unitOfWork; + private readonly ICurrentUserService _currentUserService; + + /// + /// 初始化命令处理器 + /// + public EnableTestCaseSetCommandHandler( + ITestCaseSetRepository testCaseSetRepository, + ILogger logger, + IUnitOfWork unitOfWork, + ICurrentUserService currentUserService) + { + _testCaseSetRepository = testCaseSetRepository; + _logger = logger; + _unitOfWork = unitOfWork; + _currentUserService = currentUserService; + } + + /// + /// 处理启用用例集命令 + /// + public async Task> Handle(EnableTestCaseSetCommand request, CancellationToken cancellationToken) + { + try + { + _logger.LogInformation("开始启用用例集,用例集ID: {TestCaseSetId}", request.TestCaseSetId); + + // 检查用例集是否存在 + var existingTestCaseSet = await _testCaseSetRepository.GetTestCaseSetByIdAsync(request.TestCaseSetId, cancellationToken); + if (existingTestCaseSet == null) + { + _logger.LogWarning("用例集不存在: {TestCaseSetId}", request.TestCaseSetId); + return OperationResult.CreateFailure($"用例集ID {request.TestCaseSetId} 不存在"); + } + + // 检查用例集是否已被软删除 + if (existingTestCaseSet.IsDeleted) + { + _logger.LogWarning("用例集已被删除: {TestCaseSetId}", request.TestCaseSetId); + return OperationResult.CreateFailure($"用例集ID {request.TestCaseSetId} 已被删除"); + } + + // 检查用例集是否已经启用 + if (!existingTestCaseSet.IsDisabled) + { + _logger.LogWarning("用例集已经启用: {TestCaseSetId}", request.TestCaseSetId); + return OperationResult.CreateFailure($"用例集ID {request.TestCaseSetId} 已经启用"); + } + + // 获取当前用户ID + var currentUserId = _currentUserService.GetCurrentUserId(); + if (string.IsNullOrEmpty(currentUserId)) + { + _logger.LogError("无法获取当前用户ID,用户可能未认证"); + return OperationResult.CreateFailure("用户未认证,无法启用用例集"); + } + + // 启用用例集 + existingTestCaseSet.Enable(); + existingTestCaseSet.Update( + code: existingTestCaseSet.Code, + name: existingTestCaseSet.Name, + version: existingTestCaseSet.Version, + updatedBy: currentUserId, + description: existingTestCaseSet.Description, + versionUpdateInfo: existingTestCaseSet.VersionUpdateInfo, + isDisabled: false, + remarks: existingTestCaseSet.Remarks); + + // 保存更改 + _testCaseSetRepository.UpdateTestCaseSet(existingTestCaseSet); + + // 保存更改到数据库 + await _unitOfWork.SaveChangesAsync(cancellationToken); + + _logger.LogInformation("用例集启用成功,用例集ID: {TestCaseSetId}, 用例集编码: {Code}, 用例集名称: {Name}, 版本: {Version}", + existingTestCaseSet.Id, existingTestCaseSet.Code, existingTestCaseSet.Name, existingTestCaseSet.Version); + return OperationResult.CreateSuccess(true); + } + catch (Exception ex) + { + _logger.LogError(ex, "启用用例集时发生错误,用例集ID: {TestCaseSetId}", request.TestCaseSetId); + return OperationResult.CreateFailure($"启用用例集时发生错误: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Commands/UpdateTestCaseSet/UpdateTestCaseSetCommand.cs b/src/X1.Application/Features/TestCaseSets/Commands/UpdateTestCaseSet/UpdateTestCaseSetCommand.cs new file mode 100644 index 0000000..6fdff34 --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Commands/UpdateTestCaseSet/UpdateTestCaseSetCommand.cs @@ -0,0 +1,62 @@ +using CellularManagement.Domain.Common; +using MediatR; +using System.ComponentModel.DataAnnotations; + +namespace CellularManagement.Application.Features.TestCaseSets.Commands.UpdateTestCaseSet; + +/// +/// 更新用例集命令 +/// +public class UpdateTestCaseSetCommand : IRequest> +{ + /// + /// 用例集ID + /// + [Required(ErrorMessage = "用例集ID不能为空")] + [MaxLength(50, ErrorMessage = "用例集ID长度不能超过50个字符")] + public string TestCaseSetId { get; set; } = null!; + + /// + /// 用例集编码 + /// + [Required(ErrorMessage = "用例集编码不能为空")] + [MaxLength(50, ErrorMessage = "用例集编码长度不能超过50个字符")] + public string Code { get; set; } = null!; + + /// + /// 用例集名称 + /// + [Required(ErrorMessage = "用例集名称不能为空")] + [MaxLength(100, ErrorMessage = "用例集名称长度不能超过100个字符")] + public string Name { get; set; } = null!; + + /// + /// 用例集说明 + /// + [MaxLength(1000, ErrorMessage = "用例集说明长度不能超过1000个字符")] + public string? Description { get; set; } + + /// + /// 用例集版本 + /// + [Required(ErrorMessage = "用例集版本不能为空")] + [MaxLength(20, ErrorMessage = "用例集版本长度不能超过20个字符")] + public string Version { get; set; } = null!; + + /// + /// 版本更新信息 + /// + [MaxLength(500, ErrorMessage = "版本更新信息长度不能超过500个字符")] + public string? VersionUpdateInfo { get; set; } + + /// + /// 是否禁用 + /// + public bool IsDisabled { get; set; } = false; + + /// + /// 备注 + /// + [MaxLength(1000, ErrorMessage = "备注长度不能超过1000个字符")] + public string? Remarks { get; set; } +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Commands/UpdateTestCaseSet/UpdateTestCaseSetCommandHandler.cs b/src/X1.Application/Features/TestCaseSets/Commands/UpdateTestCaseSet/UpdateTestCaseSetCommandHandler.cs new file mode 100644 index 0000000..5475945 --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Commands/UpdateTestCaseSet/UpdateTestCaseSetCommandHandler.cs @@ -0,0 +1,121 @@ +using MediatR; +using Microsoft.Extensions.Logging; +using CellularManagement.Domain.Common; +using CellularManagement.Domain.Entities.Device; +using CellularManagement.Domain.Repositories.Device; +using CellularManagement.Domain.Repositories.Base; +using CellularManagement.Domain.Services; + +namespace CellularManagement.Application.Features.TestCaseSets.Commands.UpdateTestCaseSet; + +/// +/// 更新用例集命令处理器 +/// +public class UpdateTestCaseSetCommandHandler : IRequestHandler> +{ + private readonly ITestCaseSetRepository _testCaseSetRepository; + private readonly ILogger _logger; + private readonly IUnitOfWork _unitOfWork; + private readonly ICurrentUserService _currentUserService; + + /// + /// 初始化命令处理器 + /// + public UpdateTestCaseSetCommandHandler( + ITestCaseSetRepository testCaseSetRepository, + ILogger logger, + IUnitOfWork unitOfWork, + ICurrentUserService currentUserService) + { + _testCaseSetRepository = testCaseSetRepository; + _logger = logger; + _unitOfWork = unitOfWork; + _currentUserService = currentUserService; + } + + /// + /// 处理更新用例集命令 + /// + public async Task> Handle(UpdateTestCaseSetCommand request, CancellationToken cancellationToken) + { + try + { + _logger.LogInformation("开始更新用例集,用例集ID: {TestCaseSetId}, 用例集编码: {Code}, 用例集名称: {Name}, 版本: {Version}", + request.TestCaseSetId, request.Code, request.Name, request.Version); + + // 检查用例集是否存在 + var existingTestCaseSet = await _testCaseSetRepository.GetTestCaseSetByIdAsync(request.TestCaseSetId, cancellationToken); + if (existingTestCaseSet == null) + { + _logger.LogWarning("用例集不存在: {TestCaseSetId}", request.TestCaseSetId); + return OperationResult.CreateFailure($"用例集ID {request.TestCaseSetId} 不存在"); + } + + // 检查用例集编码是否已被其他用例集使用 + var testCaseSetWithSameCode = await _testCaseSetRepository.GetTestCaseSetByCodeAsync(request.Code, cancellationToken); + if (testCaseSetWithSameCode != null && testCaseSetWithSameCode.Id != request.TestCaseSetId) + { + _logger.LogWarning("用例集编码已被其他用例集使用: {Code}", request.Code); + return OperationResult.CreateFailure($"用例集编码 {request.Code} 已被其他用例集使用"); + } + + // 检查用例集版本是否已被其他用例集使用 + var testCaseSetWithSameVersion = await _testCaseSetRepository.GetTestCaseSetByVersionAsync(request.Version, cancellationToken); + if (testCaseSetWithSameVersion != null && testCaseSetWithSameVersion.Id != request.TestCaseSetId) + { + _logger.LogWarning("用例集版本已被其他用例集使用: {Version}", request.Version); + return OperationResult.CreateFailure($"用例集版本 {request.Version} 已被其他用例集使用"); + } + + // 获取当前用户ID + var currentUserId = _currentUserService.GetCurrentUserId(); + if (string.IsNullOrEmpty(currentUserId)) + { + _logger.LogError("无法获取当前用户ID,用户可能未认证"); + return OperationResult.CreateFailure("用户未认证,无法更新用例集"); + } + + // 更新用例集 + existingTestCaseSet.Update( + code: request.Code, + name: request.Name, + version: request.Version, + updatedBy: currentUserId, + description: request.Description, + versionUpdateInfo: request.VersionUpdateInfo, + isDisabled: request.IsDisabled, + remarks: request.Remarks); + + // 保存更改 + _testCaseSetRepository.UpdateTestCaseSet(existingTestCaseSet); + + // 保存更改到数据库 + await _unitOfWork.SaveChangesAsync(cancellationToken); + + // 构建响应 + var response = new UpdateTestCaseSetResponse + { + TestCaseSetId = existingTestCaseSet.Id, + Code = existingTestCaseSet.Code, + Name = existingTestCaseSet.Name, + Description = existingTestCaseSet.Description, + Version = existingTestCaseSet.Version, + VersionUpdateInfo = existingTestCaseSet.VersionUpdateInfo, + IsDisabled = existingTestCaseSet.IsDisabled, + Remarks = existingTestCaseSet.Remarks, + UpdatedAt = existingTestCaseSet.UpdatedAt, + UpdatedBy = existingTestCaseSet.UpdatedBy + }; + + _logger.LogInformation("用例集更新成功,用例集ID: {TestCaseSetId}, 用例集编码: {Code}, 用例集名称: {Name}, 版本: {Version}", + existingTestCaseSet.Id, existingTestCaseSet.Code, existingTestCaseSet.Name, existingTestCaseSet.Version); + return OperationResult.CreateSuccess(response); + } + catch (Exception ex) + { + _logger.LogError(ex, "更新用例集时发生错误,用例集ID: {TestCaseSetId}, 用例集编码: {Code}, 用例集名称: {Name}, 版本: {Version}", + request.TestCaseSetId, request.Code, request.Name, request.Version); + return OperationResult.CreateFailure($"更新用例集时发生错误: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Commands/UpdateTestCaseSet/UpdateTestCaseSetResponse.cs b/src/X1.Application/Features/TestCaseSets/Commands/UpdateTestCaseSet/UpdateTestCaseSetResponse.cs new file mode 100644 index 0000000..a638e66 --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Commands/UpdateTestCaseSet/UpdateTestCaseSetResponse.cs @@ -0,0 +1,57 @@ +namespace CellularManagement.Application.Features.TestCaseSets.Commands.UpdateTestCaseSet; + +/// +/// 更新用例集响应 +/// +public class UpdateTestCaseSetResponse +{ + /// + /// 用例集ID + /// + public string TestCaseSetId { get; set; } = null!; + + /// + /// 用例集编码 + /// + public string Code { get; set; } = null!; + + /// + /// 用例集名称 + /// + public string Name { get; set; } = null!; + + /// + /// 用例集说明 + /// + public string? Description { get; set; } + + /// + /// 用例集版本 + /// + public string Version { get; set; } = null!; + + /// + /// 版本更新信息 + /// + public string? VersionUpdateInfo { get; set; } + + /// + /// 是否禁用 + /// + public bool IsDisabled { get; set; } + + /// + /// 备注 + /// + public string? Remarks { get; set; } + + /// + /// 更新时间 + /// + public DateTime? UpdatedAt { get; set; } + + /// + /// 修改人 + /// + public string? UpdatedBy { get; set; } +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSetById/GetTestCaseSetByIdQuery.cs b/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSetById/GetTestCaseSetByIdQuery.cs new file mode 100644 index 0000000..29512c3 --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSetById/GetTestCaseSetByIdQuery.cs @@ -0,0 +1,18 @@ +using CellularManagement.Domain.Common; +using MediatR; +using System.ComponentModel.DataAnnotations; + +namespace CellularManagement.Application.Features.TestCaseSets.Queries.GetTestCaseSetById; + +/// +/// 根据ID获取用例集查询 +/// +public class GetTestCaseSetByIdQuery : IRequest> +{ + /// + /// 用例集ID + /// + [Required(ErrorMessage = "用例集ID不能为空")] + [MaxLength(50, ErrorMessage = "用例集ID长度不能超过50个字符")] + public string Id { get; set; } = null!; +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSetById/GetTestCaseSetByIdQueryHandler.cs b/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSetById/GetTestCaseSetByIdQueryHandler.cs new file mode 100644 index 0000000..3fc3330 --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSetById/GetTestCaseSetByIdQueryHandler.cs @@ -0,0 +1,84 @@ +using MediatR; +using Microsoft.Extensions.Logging; +using CellularManagement.Domain.Common; +using CellularManagement.Domain.Entities.Device; +using CellularManagement.Domain.Repositories; +using System.ComponentModel.DataAnnotations; +using CellularManagement.Domain.Repositories.Device; + +namespace CellularManagement.Application.Features.TestCaseSets.Queries.GetTestCaseSetById; + +/// +/// 根据ID获取用例集查询处理器 +/// +public class GetTestCaseSetByIdQueryHandler : IRequestHandler> +{ + private readonly ITestCaseSetRepository _testCaseSetRepository; + private readonly ILogger _logger; + + /// + /// 初始化查询处理器 + /// + public GetTestCaseSetByIdQueryHandler( + ITestCaseSetRepository testCaseSetRepository, + ILogger logger) + { + _testCaseSetRepository = testCaseSetRepository; + _logger = logger; + } + + /// + /// 处理根据ID获取用例集查询 + /// + public async Task> Handle(GetTestCaseSetByIdQuery request, CancellationToken cancellationToken) + { + try + { + // 验证请求参数 + var validationContext = new ValidationContext(request); + var validationResults = new List(); + if (!Validator.TryValidateObject(request, validationContext, validationResults, true)) + { + var errorMessages = validationResults.Select(r => r.ErrorMessage).ToList(); + _logger.LogWarning("请求参数无效: {Errors}", string.Join(", ", errorMessages)); + return OperationResult.CreateFailure(errorMessages); + } + + _logger.LogInformation("开始根据ID获取用例集,ID: {Id}", request.Id); + + // 获取用例集数据 + var testCaseSet = await _testCaseSetRepository.GetTestCaseSetByIdAsync(request.Id, cancellationToken); + + if (testCaseSet == null) + { + _logger.LogWarning("未找到指定的用例集,ID: {Id}", request.Id); + return OperationResult.CreateFailure($"未找到ID为 {request.Id} 的用例集"); + } + + // 构建响应 + var response = new GetTestCaseSetByIdResponse + { + TestCaseSetId = testCaseSet.Id, + Code = testCaseSet.Code, + Name = testCaseSet.Name, + Description = testCaseSet.Description, + Version = testCaseSet.Version, + VersionUpdateInfo = testCaseSet.VersionUpdateInfo, + IsDisabled = testCaseSet.IsDisabled, + Remarks = testCaseSet.Remarks, + CreatedAt = testCaseSet.CreatedAt, + UpdatedAt = testCaseSet.UpdatedAt, + CreatedBy = testCaseSet.CreatedBy, + UpdatedBy = testCaseSet.UpdatedBy + }; + + _logger.LogInformation("成功获取用例集信息,ID: {Id}", request.Id); + return OperationResult.CreateSuccess(response); + } + catch (Exception ex) + { + _logger.LogError(ex, "根据ID获取用例集时发生错误,ID: {Id}", request.Id); + return OperationResult.CreateFailure($"根据ID获取用例集时发生错误: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSetById/GetTestCaseSetByIdResponse.cs b/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSetById/GetTestCaseSetByIdResponse.cs new file mode 100644 index 0000000..f2386d8 --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSetById/GetTestCaseSetByIdResponse.cs @@ -0,0 +1,67 @@ +namespace CellularManagement.Application.Features.TestCaseSets.Queries.GetTestCaseSetById; + +/// +/// 根据ID获取用例集响应 +/// +public class GetTestCaseSetByIdResponse +{ + /// + /// 用例集ID + /// + public string TestCaseSetId { get; set; } = null!; + + /// + /// 用例集编码 + /// + public string Code { get; set; } = null!; + + /// + /// 用例集名称 + /// + public string Name { get; set; } = null!; + + /// + /// 用例集说明 + /// + public string? Description { get; set; } + + /// + /// 用例集版本 + /// + public string Version { get; set; } = null!; + + /// + /// 版本更新信息 + /// + public string? VersionUpdateInfo { get; set; } + + /// + /// 是否禁用 + /// + public bool IsDisabled { get; set; } + + /// + /// 备注 + /// + public string? Remarks { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreatedAt { get; set; } + + /// + /// 更新时间 + /// + public DateTime? UpdatedAt { get; set; } + + /// + /// 创建人 + /// + public string CreatedBy { get; set; } = null!; + + /// + /// 修改人 + /// + public string? UpdatedBy { get; set; } +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSets/GetTestCaseSetsQuery.cs b/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSets/GetTestCaseSetsQuery.cs new file mode 100644 index 0000000..8a3d627 --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSets/GetTestCaseSetsQuery.cs @@ -0,0 +1,40 @@ +using CellularManagement.Domain.Common; +using MediatR; +using System.ComponentModel.DataAnnotations; + +namespace CellularManagement.Application.Features.TestCaseSets.Queries.GetTestCaseSets; + +/// +/// 获取用例集列表查询 +/// +public class GetTestCaseSetsQuery : IRequest> +{ + /// + /// 页码 + /// + [Range(1, int.MaxValue, ErrorMessage = "页码必须大于0")] + public int PageNumber { get; set; } = 1; + + /// + /// 每页数量 + /// + [Range(1, 100, ErrorMessage = "每页数量必须在1-100之间")] + public int PageSize { get; set; } = 10; + + /// + /// 搜索关键词 + /// + [MaxLength(100)] + public string? SearchTerm { get; set; } + + /// + /// 是否只获取启用的用例集 + /// + public bool? IsEnabled { get; set; } + + /// + /// 版本过滤 + /// + [MaxLength(20)] + public string? Version { get; set; } +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSets/GetTestCaseSetsQueryHandler.cs b/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSets/GetTestCaseSetsQueryHandler.cs new file mode 100644 index 0000000..405a676 --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSets/GetTestCaseSetsQueryHandler.cs @@ -0,0 +1,111 @@ +using MediatR; +using Microsoft.Extensions.Logging; +using CellularManagement.Domain.Common; +using CellularManagement.Domain.Entities.Device; +using CellularManagement.Domain.Repositories; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using CellularManagement.Application.Features.TestCaseSets.Queries.GetTestCaseSetById; +using CellularManagement.Domain.Repositories.Device; + +namespace CellularManagement.Application.Features.TestCaseSets.Queries.GetTestCaseSets; + +/// +/// 获取用例集列表查询处理器 +/// +public class GetTestCaseSetsQueryHandler : IRequestHandler> +{ + private readonly ITestCaseSetRepository _testCaseSetRepository; + private readonly ILogger _logger; + + /// + /// 初始化查询处理器 + /// + public GetTestCaseSetsQueryHandler( + ITestCaseSetRepository testCaseSetRepository, + ILogger logger) + { + _testCaseSetRepository = testCaseSetRepository; + _logger = logger; + } + + /// + /// 处理获取用例集列表查询 + /// + public async Task> Handle(GetTestCaseSetsQuery request, CancellationToken cancellationToken) + { + try + { + // 验证请求参数 + var validationContext = new ValidationContext(request); + var validationResults = new List(); + if (!Validator.TryValidateObject(request, validationContext, validationResults, true)) + { + var errorMessages = validationResults.Select(r => r.ErrorMessage).ToList(); + _logger.LogWarning("请求参数无效: {Errors}", string.Join(", ", errorMessages)); + return OperationResult.CreateFailure(errorMessages); + } + + _logger.LogInformation("开始获取用例集列表,页码: {PageNumber}, 每页数量: {PageSize}, 搜索关键词: {SearchTerm}, 是否启用: {IsEnabled}, 版本: {Version}", + request.PageNumber, request.PageSize, request.SearchTerm, request.IsEnabled, request.Version); + + // 获取用例集数据 + var testCaseSets = await _testCaseSetRepository.SearchTestCaseSetsAsync( + request.SearchTerm, + cancellationToken); + + // 如果指定了启用状态过滤 + if (request.IsEnabled.HasValue) + { + testCaseSets = testCaseSets.Where(tcs => !tcs.IsDisabled == request.IsEnabled.Value).ToList(); + } + + // 如果指定了版本过滤 + if (!string.IsNullOrEmpty(request.Version)) + { + testCaseSets = testCaseSets.Where(tcs => tcs.Version == request.Version).ToList(); + } + + // 计算分页 + int totalCount = testCaseSets.Count(); + var items = testCaseSets + .Skip((request.PageNumber - 1) * request.PageSize) + .Take(request.PageSize) + .ToList(); + + // 构建响应 + var response = new GetTestCaseSetsResponse + { + TotalCount = totalCount, + PageNumber = request.PageNumber, + PageSize = request.PageSize, + TotalPages = (int)Math.Ceiling(totalCount / (double)request.PageSize), + HasPreviousPage = request.PageNumber > 1, + HasNextPage = request.PageNumber < (int)Math.Ceiling(totalCount / (double)request.PageSize), + Items = items.Select(tcs => new GetTestCaseSetByIdResponse + { + TestCaseSetId = tcs.Id, + Code = tcs.Code, + Name = tcs.Name, + Description = tcs.Description, + Version = tcs.Version, + VersionUpdateInfo = tcs.VersionUpdateInfo, + IsDisabled = tcs.IsDisabled, + Remarks = tcs.Remarks, + CreatedAt = tcs.CreatedAt, + UpdatedAt = tcs.UpdatedAt, + CreatedBy = tcs.CreatedBy, + UpdatedBy = tcs.UpdatedBy + }).ToList() + }; + + _logger.LogInformation("成功获取用例集列表,共 {Count} 条记录", items.Count); + return OperationResult.CreateSuccess(response); + } + catch (Exception ex) + { + _logger.LogError(ex, "获取用例集列表时发生错误"); + return OperationResult.CreateFailure($"获取用例集列表时发生错误: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSets/GetTestCaseSetsResponse.cs b/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSets/GetTestCaseSetsResponse.cs new file mode 100644 index 0000000..5c673ee --- /dev/null +++ b/src/X1.Application/Features/TestCaseSets/Queries/GetTestCaseSets/GetTestCaseSetsResponse.cs @@ -0,0 +1,44 @@ +using CellularManagement.Application.Features.TestCaseSets.Queries.GetTestCaseSetById; + +namespace CellularManagement.Application.Features.TestCaseSets.Queries.GetTestCaseSets; + +/// +/// 获取用例集列表响应 +/// +public class GetTestCaseSetsResponse +{ + /// + /// 总数量 + /// + public int TotalCount { get; set; } + + /// + /// 当前页码 + /// + public int PageNumber { get; set; } + + /// + /// 每页数量 + /// + public int PageSize { get; set; } + + /// + /// 总页数 + /// + public int TotalPages { get; set; } + + /// + /// 是否有上一页 + /// + public bool HasPreviousPage { get; set; } + + /// + /// 是否有下一页 + /// + public bool HasNextPage { get; set; } + + /// + /// 用例集列表 + /// + public List Items { get; set; } = new(); +} \ No newline at end of file diff --git a/src/X1.Domain/Entities/Device/TestCaseSet.cs b/src/X1.Domain/Entities/Device/TestCaseSet.cs new file mode 100644 index 0000000..17f33ac --- /dev/null +++ b/src/X1.Domain/Entities/Device/TestCaseSet.cs @@ -0,0 +1,148 @@ +using System.ComponentModel.DataAnnotations; +using CellularManagement.Domain.Entities.Common; + +namespace CellularManagement.Domain.Entities.Device; + +/// +/// 用例集实体 +/// +public class TestCaseSet : AuditableEntity +{ + private TestCaseSet() { } + + /// + /// 用例集编码 + /// + [Required] + [MaxLength(50)] + public string Code { get; private set; } = null!; + + /// + /// 用例集名称 + /// + [Required] + [MaxLength(100)] + public string Name { get; private set; } = null!; + + /// + /// 用例集说明 + /// + [MaxLength(1000)] + public string? Description { get; private set; } + + /// + /// 用例集版本 + /// + [Required] + [MaxLength(20)] + public string Version { get; private set; } = null!; + + /// + /// 版本更新信息 + /// + [MaxLength(500)] + public string? VersionUpdateInfo { get; private set; } + + /// + /// 是否禁用 + /// + public bool IsDisabled { get; private set; } = false; + + /// + /// 备注 + /// + [MaxLength(1000)] + public string? Remarks { get; private set; } + + /// + /// 创建用例集 + /// + public static TestCaseSet Create( + string code, + string name, + string version, + string createdBy, + string? description = null, + string? versionUpdateInfo = null, + bool isDisabled = false, + string? remarks = null) + { + var testCaseSet = new TestCaseSet + { + Id = Guid.NewGuid().ToString(), + Code = code, + Name = name, + Description = description, + Version = version, + VersionUpdateInfo = versionUpdateInfo, + IsDisabled = isDisabled, + Remarks = remarks, + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow, + CreatedBy = createdBy, + UpdatedBy = createdBy + }; + + return testCaseSet; + } + + /// + /// 更新用例集 + /// + public void Update( + string code, + string name, + string version, + string updatedBy, + string? description = null, + string? versionUpdateInfo = null, + bool isDisabled = false, + string? remarks = null) + { + Code = code; + Name = name; + Description = description; + Version = version; + VersionUpdateInfo = versionUpdateInfo; + IsDisabled = isDisabled; + Remarks = remarks; + UpdatedAt = DateTime.UtcNow; + UpdatedBy = updatedBy; + } + + /// + /// 启用用例集 + /// + public void Enable() + { + IsDisabled = false; + UpdatedAt = DateTime.UtcNow; + } + + /// + /// 禁用用例集 + /// + public void Disable() + { + IsDisabled = true; + UpdatedAt = DateTime.UtcNow; + } + + /// + /// 软删除用例集 + /// + public void SoftDelete() + { + IsDeleted = true; + UpdatedAt = DateTime.UtcNow; + } + + /// + /// 恢复用例集 + /// + public void Restore() + { + IsDeleted = false; + UpdatedAt = DateTime.UtcNow; + } +} \ No newline at end of file diff --git a/src/X1.Domain/Repositories/Device/ITestCaseSetRepository.cs b/src/X1.Domain/Repositories/Device/ITestCaseSetRepository.cs new file mode 100644 index 0000000..de6e811 --- /dev/null +++ b/src/X1.Domain/Repositories/Device/ITestCaseSetRepository.cs @@ -0,0 +1,73 @@ +using CellularManagement.Domain.Entities; +using CellularManagement.Domain.Entities.Device; +using CellularManagement.Domain.Repositories.Base; + +namespace CellularManagement.Domain.Repositories.Device; + +/// +/// 用例集仓储接口 +/// +public interface ITestCaseSetRepository : IBaseRepository +{ + /// + /// 添加用例集 + /// + Task AddTestCaseSetAsync(TestCaseSet testCaseSet, CancellationToken cancellationToken = default); + + /// + /// 更新用例集 + /// + void UpdateTestCaseSet(TestCaseSet testCaseSet); + + /// + /// 删除用例集 + /// + Task DeleteTestCaseSetAsync(string id, CancellationToken cancellationToken = default); + + /// + /// 获取所有用例集 + /// + Task> GetAllTestCaseSetsAsync(CancellationToken cancellationToken = default); + + /// + /// 根据ID获取用例集 + /// + Task GetTestCaseSetByIdAsync(string id, CancellationToken cancellationToken = default); + + /// + /// 根据编码获取用例集 + /// + Task GetTestCaseSetByCodeAsync(string code, CancellationToken cancellationToken = default); + + /// + /// 根据版本获取用例集 + /// + Task GetTestCaseSetByVersionAsync(string version, CancellationToken cancellationToken = default); + + /// + /// 搜索用例集 + /// + Task> SearchTestCaseSetsAsync( + string? keyword, + CancellationToken cancellationToken = default); + + /// + /// 检查用例集是否存在 + /// + Task ExistsAsync(string id, CancellationToken cancellationToken = default); + + /// + /// 检查编码是否存在 + /// + Task CodeExistsAsync(string code, CancellationToken cancellationToken = default); + + /// + /// 检查版本是否存在 + /// + Task VersionExistsAsync(string version, CancellationToken cancellationToken = default); + + /// + /// 获取启用的用例集 + /// + Task> GetEnabledTestCaseSetsAsync(CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/src/X1.Infrastructure/Configurations/Device/TestCaseSetConfiguration.cs b/src/X1.Infrastructure/Configurations/Device/TestCaseSetConfiguration.cs new file mode 100644 index 0000000..ab88e74 --- /dev/null +++ b/src/X1.Infrastructure/Configurations/Device/TestCaseSetConfiguration.cs @@ -0,0 +1,32 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using CellularManagement.Domain.Entities.Device; + +namespace CellularManagement.Infrastructure.Configurations.Device; + +public class TestCaseSetConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("TestCaseSets", t => t.HasComment("用例集表")); + builder.HasKey(tcs => tcs.Id); + + // 配置索引 + builder.HasIndex(tcs => tcs.Code).IsUnique().HasDatabaseName("IX_TestCaseSets_Code"); + builder.HasIndex(tcs => tcs.Version).HasDatabaseName("IX_TestCaseSets_Version"); + + // 配置属性 + builder.Property(tcs => tcs.Id).HasComment("用例集ID"); + builder.Property(tcs => tcs.Code).IsRequired().HasMaxLength(50).HasComment("用例集编码"); + builder.Property(tcs => tcs.Name).IsRequired().HasMaxLength(100).HasComment("用例集名称"); + builder.Property(tcs => tcs.Description).HasMaxLength(1000).HasComment("用例集说明"); + builder.Property(tcs => tcs.Version).IsRequired().HasMaxLength(20).HasComment("用例集版本"); + builder.Property(tcs => tcs.VersionUpdateInfo).HasMaxLength(500).HasComment("版本更新信息"); + builder.Property(tcs => tcs.IsDisabled).IsRequired().HasComment("是否禁用"); + builder.Property(tcs => tcs.Remarks).HasMaxLength(1000).HasComment("备注"); + builder.Property(tcs => tcs.CreatedAt).IsRequired().HasColumnType("timestamp with time zone").HasComment("创建时间"); + builder.Property(tcs => tcs.UpdatedAt).HasColumnType("timestamp with time zone").HasComment("更新时间"); + builder.Property(tcs => tcs.CreatedBy).IsRequired().HasMaxLength(50).HasComment("创建人"); + builder.Property(tcs => tcs.UpdatedBy).HasMaxLength(50).HasComment("修改人"); + } +} \ No newline at end of file diff --git a/src/X1.Infrastructure/Context/AppDbContext.cs b/src/X1.Infrastructure/Context/AppDbContext.cs index 0437a35..5481590 100644 --- a/src/X1.Infrastructure/Context/AppDbContext.cs +++ b/src/X1.Infrastructure/Context/AppDbContext.cs @@ -56,6 +56,11 @@ public class AppDbContext : IdentityDbContext /// public DbSet Scenarios { get; set; } = null!; + /// + /// 用例集集合 + /// + public DbSet TestCaseSets { get; set; } = null!; + /// /// 初始化数据库上下文 /// diff --git a/src/X1.Infrastructure/DependencyInjection.cs b/src/X1.Infrastructure/DependencyInjection.cs index 9cbfe4b..0dccb9e 100644 --- a/src/X1.Infrastructure/DependencyInjection.cs +++ b/src/X1.Infrastructure/DependencyInjection.cs @@ -176,6 +176,7 @@ public static class DependencyInjection services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); return services; } diff --git a/src/X1.Infrastructure/Repositories/Device/TestCaseSetRepository.cs b/src/X1.Infrastructure/Repositories/Device/TestCaseSetRepository.cs new file mode 100644 index 0000000..e7335c3 --- /dev/null +++ b/src/X1.Infrastructure/Repositories/Device/TestCaseSetRepository.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using System.Linq; +using Microsoft.Extensions.Logging; +using CellularManagement.Domain.Entities; +using CellularManagement.Domain.Repositories; +using CellularManagement.Infrastructure.Repositories.Base; +using CellularManagement.Domain.Entities.Device; +using CellularManagement.Domain.Repositories.Base; +using CellularManagement.Domain.Repositories.Device; + +namespace CellularManagement.Infrastructure.Repositories.Device; + +/// +/// 用例集仓储实现类 +/// +public class TestCaseSetRepository : BaseRepository, ITestCaseSetRepository +{ + private readonly ILogger _logger; + + /// + /// 初始化仓储 + /// + public TestCaseSetRepository( + ICommandRepository commandRepository, + IQueryRepository queryRepository, + ILogger logger) + : base(commandRepository, queryRepository, logger) + { + _logger = logger; + } + + /// + /// 添加用例集 + /// + public async Task AddTestCaseSetAsync(TestCaseSet testCaseSet, CancellationToken cancellationToken = default) + { + var result = await CommandRepository.AddAsync(testCaseSet, cancellationToken); + return result; + } + + /// + /// 更新用例集 + /// + public void UpdateTestCaseSet(TestCaseSet testCaseSet) + { + CommandRepository.Update(testCaseSet); + } + + /// + /// 删除用例集 + /// + public async Task DeleteTestCaseSetAsync(string id, CancellationToken cancellationToken = default) + { + await CommandRepository.DeleteByIdAsync(id, cancellationToken); + } + + /// + /// 获取所有用例集 + /// + public async Task> GetAllTestCaseSetsAsync(CancellationToken cancellationToken = default) + { + var testCaseSets = await QueryRepository.GetAllAsync(cancellationToken: cancellationToken); + return testCaseSets.ToList(); + } + + /// + /// 根据ID获取用例集 + /// + public async Task GetTestCaseSetByIdAsync(string id, CancellationToken cancellationToken = default) + { + return await QueryRepository.GetByIdAsync(id, cancellationToken: cancellationToken); + } + + /// + /// 根据编码获取用例集 + /// + public async Task GetTestCaseSetByCodeAsync(string code, CancellationToken cancellationToken = default) + { + return await QueryRepository.FirstOrDefaultAsync(tcs => tcs.Code == code, cancellationToken: cancellationToken); + } + + /// + /// 根据版本获取用例集 + /// + public async Task GetTestCaseSetByVersionAsync(string version, CancellationToken cancellationToken = default) + { + return await QueryRepository.FirstOrDefaultAsync(tcs => tcs.Version == version, cancellationToken: cancellationToken); + } + + /// + /// 搜索用例集 + /// + public async Task> SearchTestCaseSetsAsync( + string? keyword, + CancellationToken cancellationToken = default) + { + var query = await QueryRepository.FindAsync(tcs => true, cancellationToken: cancellationToken); + + if (!string.IsNullOrWhiteSpace(keyword)) + { + query = query.Where(tcs => + tcs.Name.Contains(keyword) || + tcs.Code.Contains(keyword) || + tcs.Version.Contains(keyword) || + (tcs.Description != null && tcs.Description.Contains(keyword)) || + (tcs.VersionUpdateInfo != null && tcs.VersionUpdateInfo.Contains(keyword)) || + (tcs.Remarks != null && tcs.Remarks.Contains(keyword))); + } + + var testCaseSets = query; + return testCaseSets.ToList(); + } + + /// + /// 检查用例集是否存在 + /// + public async Task ExistsAsync(string id, CancellationToken cancellationToken = default) + { + return await QueryRepository.AnyAsync(tcs => tcs.Id == id, cancellationToken: cancellationToken); + } + + /// + /// 检查编码是否存在 + /// + public async Task CodeExistsAsync(string code, CancellationToken cancellationToken = default) + { + return await QueryRepository.AnyAsync(tcs => tcs.Code == code, cancellationToken: cancellationToken); + } + + /// + /// 检查版本是否存在 + /// + public async Task VersionExistsAsync(string version, CancellationToken cancellationToken = default) + { + return await QueryRepository.AnyAsync(tcs => tcs.Version == version, cancellationToken: cancellationToken); + } + + /// + /// 获取启用的用例集 + /// + public async Task> GetEnabledTestCaseSetsAsync(CancellationToken cancellationToken = default) + { + var testCaseSets = await QueryRepository.FindAsync(tcs => !tcs.IsDisabled, cancellationToken: cancellationToken); + return testCaseSets.ToList(); + } +} \ No newline at end of file diff --git a/src/X1.Presentation/Controllers/TestCaseSetsController.cs b/src/X1.Presentation/Controllers/TestCaseSetsController.cs new file mode 100644 index 0000000..a0b873b --- /dev/null +++ b/src/X1.Presentation/Controllers/TestCaseSetsController.cs @@ -0,0 +1,175 @@ +using CellularManagement.Application.Features.TestCaseSets.Commands.CreateTestCaseSet; +using CellularManagement.Application.Features.TestCaseSets.Commands.DeleteTestCaseSet; +using CellularManagement.Application.Features.TestCaseSets.Commands.DisableTestCaseSet; +using CellularManagement.Application.Features.TestCaseSets.Commands.EnableTestCaseSet; +using CellularManagement.Application.Features.TestCaseSets.Commands.UpdateTestCaseSet; +using CellularManagement.Application.Features.TestCaseSets.Queries.GetTestCaseSetById; +using CellularManagement.Application.Features.TestCaseSets.Queries.GetTestCaseSets; +using CellularManagement.Domain.Common; +using CellularManagement.Presentation.Abstractions; +using MediatR; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; + +namespace CellularManagement.Presentation.Controllers; + +/// +/// 用例集管理控制器 +/// +[Route("api/testcasesets")] +[ApiController] +[Authorize] +public class TestCaseSetsController : ApiController +{ + private readonly ILogger _logger; + + /// + /// 初始化用例集控制器 + /// + public TestCaseSetsController(IMediator mediator, ILogger logger) + : base(mediator) + { + _logger = logger; + } + + /// + /// 获取用例集列表 + /// + [HttpGet] + public async Task> GetAll([FromQuery] GetTestCaseSetsQuery query) + { + _logger.LogInformation("开始获取用例集列表,页码: {PageNumber}, 每页数量: {PageSize}, 搜索关键词: {SearchTerm}, 是否启用: {IsEnabled}, 版本: {Version}", + query.PageNumber, query.PageSize, query.SearchTerm, query.IsEnabled, query.Version); + + var result = await mediator.Send(query); + if (!result.IsSuccess) + { + _logger.LogWarning("获取用例集列表失败: {Message}", result.ErrorMessages); + return result; + } + + _logger.LogInformation("成功获取用例集列表,共 {Count} 条记录", result.Data?.TotalCount ?? 0); + return result; + } + + /// + /// 获取用例集详情 + /// + [HttpGet("{id}")] + public async Task> GetById(string id) + { + _logger.LogInformation("开始获取用例集详情,用例集ID: {TestCaseSetId}", id); + + var result = await mediator.Send(new GetTestCaseSetByIdQuery { Id = id }); + if (!result.IsSuccess) + { + _logger.LogWarning("获取用例集详情失败: {Message}", result.ErrorMessages); + return result; + } + + _logger.LogInformation("成功获取用例集详情,用例集ID: {TestCaseSetId}", id); + return result; + } + + /// + /// 创建用例集 + /// + [HttpPost] + public async Task> Create([FromBody] CreateTestCaseSetCommand command) + { + _logger.LogInformation("开始创建用例集,用例集编码: {Code}, 用例集名称: {Name}, 版本: {Version}", command.Code, command.Name, command.Version); + + var result = await mediator.Send(command); + if (!result.IsSuccess) + { + _logger.LogWarning("创建用例集失败: {Message}", result.ErrorMessages); + return result; + } + + _logger.LogInformation("成功创建用例集,用例集ID: {TestCaseSetId}", result.Data?.TestCaseSetId); + return result; + } + + /// + /// 更新用例集 + /// + [HttpPut("{id}")] + public async Task> Update(string id, [FromBody] UpdateTestCaseSetCommand command) + { + _logger.LogInformation("开始更新用例集,用例集ID: {TestCaseSetId}", id); + + if (id != command.TestCaseSetId) + { + _logger.LogWarning("用例集ID不匹配,路径ID: {PathId}, 命令ID: {CommandId}", id, command.TestCaseSetId); + return OperationResult.CreateFailure("用例集ID不匹配"); + } + + var result = await mediator.Send(command); + if (!result.IsSuccess) + { + _logger.LogWarning("更新用例集失败: {Message}", result.ErrorMessages); + return result; + } + + _logger.LogInformation("成功更新用例集,用例集ID: {TestCaseSetId}", id); + return result; + } + + /// + /// 删除用例集 + /// + [HttpDelete("{id}")] + public async Task> Delete(string id) + { + _logger.LogInformation("开始删除用例集,用例集ID: {TestCaseSetId}", id); + + var result = await mediator.Send(new DeleteTestCaseSetCommand { TestCaseSetId = id }); + if (!result.IsSuccess) + { + _logger.LogWarning("删除用例集失败: {Message}", result.ErrorMessages); + return result; + } + + _logger.LogInformation("成功删除用例集,用例集ID: {TestCaseSetId}", id); + return result; + } + + /// + /// 启用用例集 + /// + [HttpPost("{id}/enable")] + public async Task> Enable(string id) + { + _logger.LogInformation("开始启用用例集,用例集ID: {TestCaseSetId}", id); + + var result = await mediator.Send(new EnableTestCaseSetCommand { TestCaseSetId = id }); + if (!result.IsSuccess) + { + _logger.LogWarning("启用用例集失败: {Message}", result.ErrorMessages); + return result; + } + + _logger.LogInformation("成功启用用例集,用例集ID: {TestCaseSetId}", id); + return result; + } + + /// + /// 禁用用例集 + /// + [HttpPost("{id}/disable")] + public async Task> Disable(string id) + { + _logger.LogInformation("开始禁用用例集,用例集ID: {TestCaseSetId}", id); + + var result = await mediator.Send(new DisableTestCaseSetCommand { TestCaseSetId = id }); + if (!result.IsSuccess) + { + _logger.LogWarning("禁用用例集失败: {Message}", result.ErrorMessages); + return result; + } + + _logger.LogInformation("成功禁用用例集,用例集ID: {TestCaseSetId}", id); + return result; + } +} \ No newline at end of file