Browse Source

feat: 实现用例完整的CRUD功能 - 添加创建用例命令和处理器 - 添加更新用例命令和处理器 - 添加删除用例命令和处理器 - 添加启用用例命令和处理器 - 添加禁用用例命令和处理器 - 更新控制器添加所有CRUD API接口 - 完善用例实体、仓储、查询功能

feature/x1-owen-debug
test 4 weeks ago
parent
commit
c87c6ae949
  1. 91
      src/X1.Application/Features/TestCases/Commands/CreateTestCase/CreateTestCaseCommand.cs
  2. 123
      src/X1.Application/Features/TestCases/Commands/CreateTestCase/CreateTestCaseCommandHandler.cs
  3. 87
      src/X1.Application/Features/TestCases/Commands/CreateTestCase/CreateTestCaseResponse.cs
  4. 18
      src/X1.Application/Features/TestCases/Commands/DeleteTestCase/DeleteTestCaseCommand.cs
  5. 102
      src/X1.Application/Features/TestCases/Commands/DeleteTestCase/DeleteTestCaseCommandHandler.cs
  6. 18
      src/X1.Application/Features/TestCases/Commands/DisableTestCase/DisableTestCaseCommand.cs
  7. 109
      src/X1.Application/Features/TestCases/Commands/DisableTestCase/DisableTestCaseCommandHandler.cs
  8. 18
      src/X1.Application/Features/TestCases/Commands/EnableTestCase/EnableTestCaseCommand.cs
  9. 109
      src/X1.Application/Features/TestCases/Commands/EnableTestCase/EnableTestCaseCommandHandler.cs
  10. 98
      src/X1.Application/Features/TestCases/Commands/UpdateTestCase/UpdateTestCaseCommand.cs
  11. 133
      src/X1.Application/Features/TestCases/Commands/UpdateTestCase/UpdateTestCaseCommandHandler.cs
  12. 87
      src/X1.Application/Features/TestCases/Commands/UpdateTestCase/UpdateTestCaseResponse.cs
  13. 14
      src/X1.Application/Features/TestCases/Queries/GetTestCaseById/GetTestCaseByIdQuery.cs
  14. 76
      src/X1.Application/Features/TestCases/Queries/GetTestCaseById/GetTestCaseByIdQueryHandler.cs
  15. 97
      src/X1.Application/Features/TestCases/Queries/GetTestCaseById/GetTestCaseByIdResponse.cs
  16. 14
      src/X1.Application/Features/TestCases/Queries/GetTestCases/GetTestCasesQuery.cs
  17. 76
      src/X1.Application/Features/TestCases/Queries/GetTestCases/GetTestCasesQueryHandler.cs
  18. 113
      src/X1.Application/Features/TestCases/Queries/GetTestCases/GetTestCasesResponse.cs
  19. 205
      src/X1.Domain/Entities/Device/TestCase.cs
  20. 73
      src/X1.Domain/Repositories/Device/ITestCaseRepository.cs
  21. 94
      src/X1.Infrastructure/Configurations/Device/TestCaseConfiguration.cs
  22. 5
      src/X1.Infrastructure/Context/AppDbContext.cs
  23. 1
      src/X1.Infrastructure/DependencyInjection.cs
  24. 149
      src/X1.Infrastructure/Repositories/Device/TestCaseRepository.cs
  25. 169
      src/X1.Presentation/Controllers/TestCasesController.cs

91
src/X1.Application/Features/TestCases/Commands/CreateTestCase/CreateTestCaseCommand.cs

@ -0,0 +1,91 @@
using CellularManagement.Domain.Common;
using MediatR;
using System.ComponentModel.DataAnnotations;
namespace CellularManagement.Application.Features.TestCases.Commands.CreateTestCase;
/// <summary>
/// 创建用例命令
/// </summary>
public class CreateTestCaseCommand : IRequest<OperationResult<CreateTestCaseResponse>>
{
/// <summary>
/// 用例编码
/// </summary>
[Required(ErrorMessage = "用例编码不能为空")]
[MaxLength(50, ErrorMessage = "用例编码长度不能超过50个字符")]
public string Code { get; set; } = null!;
/// <summary>
/// 用例名称
/// </summary>
[Required(ErrorMessage = "用例名称不能为空")]
[MaxLength(100, ErrorMessage = "用例名称长度不能超过100个字符")]
public string Name { get; set; } = null!;
/// <summary>
/// 用户数
/// </summary>
[Range(0, int.MaxValue, ErrorMessage = "用户数必须大于等于0")]
public int UserCount { get; set; } = 0;
/// <summary>
/// 用户信息列表(JSON格式)
/// </summary>
[MaxLength(4000, ErrorMessage = "用户信息列表长度不能超过4000个字符")]
public string? UserInfoList { get; set; }
/// <summary>
/// 时延阈值数
/// </summary>
[Range(0, int.MaxValue, ErrorMessage = "时延阈值数必须大于等于0")]
public int LatencyThresholdCount { get; set; } = 0;
/// <summary>
/// 时延阈值列表(JSON格式)
/// </summary>
[MaxLength(2000, ErrorMessage = "时延阈值列表长度不能超过2000个字符")]
public string? LatencyThresholdList { get; set; }
/// <summary>
/// 吞吐量阈值数
/// </summary>
[Range(0, int.MaxValue, ErrorMessage = "吞吐量阈值数必须大于等于0")]
public int ThroughputThresholdCount { get; set; } = 0;
/// <summary>
/// 吞吐量阈值列表(JSON格式)
/// </summary>
[MaxLength(2000, ErrorMessage = "吞吐量阈值列表长度不能超过2000个字符")]
public string? ThroughputThresholdList { get; set; }
/// <summary>
/// 用例说明
/// </summary>
[MaxLength(1000, ErrorMessage = "用例说明长度不能超过1000个字符")]
public string? Description { get; set; }
/// <summary>
/// 用例版本
/// </summary>
[Required(ErrorMessage = "用例版本不能为空")]
[MaxLength(20, ErrorMessage = "用例版本长度不能超过20个字符")]
public string Version { get; set; } = null!;
/// <summary>
/// 版本更新信息
/// </summary>
[MaxLength(500, ErrorMessage = "版本更新信息长度不能超过500个字符")]
public string? VersionUpdateInfo { get; set; }
/// <summary>
/// 是否禁用
/// </summary>
public bool IsDisabled { get; set; } = false;
/// <summary>
/// 备注
/// </summary>
[MaxLength(1000, ErrorMessage = "备注长度不能超过1000个字符")]
public string? Remarks { get; set; }
}

123
src/X1.Application/Features/TestCases/Commands/CreateTestCase/CreateTestCaseCommandHandler.cs

@ -0,0 +1,123 @@
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.TestCases.Commands.CreateTestCase;
/// <summary>
/// 创建用例命令处理器
/// </summary>
public class CreateTestCaseCommandHandler : IRequestHandler<CreateTestCaseCommand, OperationResult<CreateTestCaseResponse>>
{
private readonly ITestCaseRepository _testCaseRepository;
private readonly ILogger<CreateTestCaseCommandHandler> _logger;
private readonly IUnitOfWork _unitOfWork;
private readonly ICurrentUserService _currentUserService;
/// <summary>
/// 初始化命令处理器
/// </summary>
public CreateTestCaseCommandHandler(
ITestCaseRepository testCaseRepository,
ILogger<CreateTestCaseCommandHandler> logger,
IUnitOfWork unitOfWork,
ICurrentUserService currentUserService)
{
_testCaseRepository = testCaseRepository;
_logger = logger;
_unitOfWork = unitOfWork;
_currentUserService = currentUserService;
}
/// <summary>
/// 处理创建用例命令
/// </summary>
public async Task<OperationResult<CreateTestCaseResponse>> Handle(CreateTestCaseCommand request, CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("开始创建用例,用例编码: {Code}, 用例名称: {Name}, 版本: {Version}",
request.Code, request.Name, request.Version);
// 检查用例编码是否已存在
if (await _testCaseRepository.CodeExistsAsync(request.Code, cancellationToken))
{
_logger.LogWarning("用例编码已存在: {Code}", request.Code);
return OperationResult<CreateTestCaseResponse>.CreateFailure($"用例编码 {request.Code} 已存在");
}
// 检查用例版本是否已存在
if (await _testCaseRepository.VersionExistsAsync(request.Version, cancellationToken))
{
_logger.LogWarning("用例版本已存在: {Version}", request.Version);
return OperationResult<CreateTestCaseResponse>.CreateFailure($"用例版本 {request.Version} 已存在");
}
// 获取当前用户ID
var currentUserId = _currentUserService.GetCurrentUserId();
if (string.IsNullOrEmpty(currentUserId))
{
_logger.LogError("无法获取当前用户ID,用户可能未认证");
return OperationResult<CreateTestCaseResponse>.CreateFailure("用户未认证,无法创建用例");
}
// 创建用例实体
var testCase = TestCase.Create(
code: request.Code,
name: request.Name,
version: request.Version,
createdBy: currentUserId,
userCount: request.UserCount,
userInfoList: request.UserInfoList,
latencyThresholdCount: request.LatencyThresholdCount,
latencyThresholdList: request.LatencyThresholdList,
throughputThresholdCount: request.ThroughputThresholdCount,
throughputThresholdList: request.ThroughputThresholdList,
description: request.Description,
versionUpdateInfo: request.VersionUpdateInfo,
isDisabled: request.IsDisabled,
remarks: request.Remarks);
// 保存用例
await _testCaseRepository.AddTestCaseAsync(testCase, cancellationToken);
// 保存更改到数据库
await _unitOfWork.SaveChangesAsync(cancellationToken);
// 构建响应
var response = new CreateTestCaseResponse
{
TestCaseId = testCase.Id,
Code = testCase.Code,
Name = testCase.Name,
UserCount = testCase.UserCount,
UserInfoList = testCase.UserInfoList,
LatencyThresholdCount = testCase.LatencyThresholdCount,
LatencyThresholdList = testCase.LatencyThresholdList,
ThroughputThresholdCount = testCase.ThroughputThresholdCount,
ThroughputThresholdList = testCase.ThroughputThresholdList,
Description = testCase.Description,
Version = testCase.Version,
VersionUpdateInfo = testCase.VersionUpdateInfo,
IsDisabled = testCase.IsDisabled,
Remarks = testCase.Remarks,
CreatedAt = testCase.CreatedAt,
CreatedBy = testCase.CreatedBy
};
_logger.LogInformation("用例创建成功,用例ID: {TestCaseId}, 用例编码: {Code}, 用例名称: {Name}, 版本: {Version}",
testCase.Id, testCase.Code, testCase.Name, testCase.Version);
return OperationResult<CreateTestCaseResponse>.CreateSuccess(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "创建用例时发生错误,用例编码: {Code}, 用例名称: {Name}, 版本: {Version}",
request.Code, request.Name, request.Version);
return OperationResult<CreateTestCaseResponse>.CreateFailure($"创建用例时发生错误: {ex.Message}");
}
}
}

87
src/X1.Application/Features/TestCases/Commands/CreateTestCase/CreateTestCaseResponse.cs

@ -0,0 +1,87 @@
namespace CellularManagement.Application.Features.TestCases.Commands.CreateTestCase;
/// <summary>
/// 创建用例响应
/// </summary>
public class CreateTestCaseResponse
{
/// <summary>
/// 用例ID
/// </summary>
public string TestCaseId { get; set; } = null!;
/// <summary>
/// 用例编码
/// </summary>
public string Code { get; set; } = null!;
/// <summary>
/// 用例名称
/// </summary>
public string Name { get; set; } = null!;
/// <summary>
/// 用户数
/// </summary>
public int UserCount { get; set; }
/// <summary>
/// 用户信息列表
/// </summary>
public string? UserInfoList { get; set; }
/// <summary>
/// 时延阈值数
/// </summary>
public int LatencyThresholdCount { get; set; }
/// <summary>
/// 时延阈值列表
/// </summary>
public string? LatencyThresholdList { get; set; }
/// <summary>
/// 吞吐量阈值数
/// </summary>
public int ThroughputThresholdCount { get; set; }
/// <summary>
/// 吞吐量阈值列表
/// </summary>
public string? ThroughputThresholdList { get; set; }
/// <summary>
/// 用例说明
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 用例版本
/// </summary>
public string Version { get; set; } = null!;
/// <summary>
/// 版本更新信息
/// </summary>
public string? VersionUpdateInfo { get; set; }
/// <summary>
/// 是否禁用
/// </summary>
public bool IsDisabled { get; set; }
/// <summary>
/// 备注
/// </summary>
public string? Remarks { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreatedAt { get; set; }
/// <summary>
/// 创建人
/// </summary>
public string CreatedBy { get; set; } = null!;
}

18
src/X1.Application/Features/TestCases/Commands/DeleteTestCase/DeleteTestCaseCommand.cs

@ -0,0 +1,18 @@
using CellularManagement.Domain.Common;
using MediatR;
using System.ComponentModel.DataAnnotations;
namespace CellularManagement.Application.Features.TestCases.Commands.DeleteTestCase;
/// <summary>
/// 删除用例命令
/// </summary>
public class DeleteTestCaseCommand : IRequest<OperationResult<bool>>
{
/// <summary>
/// 用例ID
/// </summary>
[Required(ErrorMessage = "用例ID不能为空")]
[MaxLength(50, ErrorMessage = "用例ID长度不能超过50个字符")]
public string TestCaseId { get; set; } = null!;
}

102
src/X1.Application/Features/TestCases/Commands/DeleteTestCase/DeleteTestCaseCommandHandler.cs

@ -0,0 +1,102 @@
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.TestCases.Commands.DeleteTestCase;
/// <summary>
/// 删除用例命令处理器
/// </summary>
public class DeleteTestCaseCommandHandler : IRequestHandler<DeleteTestCaseCommand, OperationResult<bool>>
{
private readonly ITestCaseRepository _testCaseRepository;
private readonly ILogger<DeleteTestCaseCommandHandler> _logger;
private readonly IUnitOfWork _unitOfWork;
private readonly ICurrentUserService _currentUserService;
/// <summary>
/// 初始化命令处理器
/// </summary>
public DeleteTestCaseCommandHandler(
ITestCaseRepository testCaseRepository,
ILogger<DeleteTestCaseCommandHandler> logger,
IUnitOfWork unitOfWork,
ICurrentUserService currentUserService)
{
_testCaseRepository = testCaseRepository;
_logger = logger;
_unitOfWork = unitOfWork;
_currentUserService = currentUserService;
}
/// <summary>
/// 处理删除用例命令
/// </summary>
public async Task<OperationResult<bool>> Handle(DeleteTestCaseCommand request, CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("开始删除用例,用例ID: {TestCaseId}", request.TestCaseId);
// 检查用例是否存在
var existingTestCase = await _testCaseRepository.GetTestCaseByIdAsync(request.TestCaseId, cancellationToken);
if (existingTestCase == null)
{
_logger.LogWarning("用例不存在: {TestCaseId}", request.TestCaseId);
return OperationResult<bool>.CreateFailure($"用例ID {request.TestCaseId} 不存在");
}
// 检查用例是否已被软删除
if (existingTestCase.IsDeleted)
{
_logger.LogWarning("用例已被删除: {TestCaseId}", request.TestCaseId);
return OperationResult<bool>.CreateFailure($"用例ID {request.TestCaseId} 已被删除");
}
// 获取当前用户ID
var currentUserId = _currentUserService.GetCurrentUserId();
if (string.IsNullOrEmpty(currentUserId))
{
_logger.LogError("无法获取当前用户ID,用户可能未认证");
return OperationResult<bool>.CreateFailure("用户未认证,无法删除用例");
}
// 软删除用例
existingTestCase.SoftDelete();
existingTestCase.Update(
code: existingTestCase.Code,
name: existingTestCase.Name,
version: existingTestCase.Version,
updatedBy: currentUserId,
userCount: existingTestCase.UserCount,
userInfoList: existingTestCase.UserInfoList,
latencyThresholdCount: existingTestCase.LatencyThresholdCount,
latencyThresholdList: existingTestCase.LatencyThresholdList,
throughputThresholdCount: existingTestCase.ThroughputThresholdCount,
throughputThresholdList: existingTestCase.ThroughputThresholdList,
description: existingTestCase.Description,
versionUpdateInfo: existingTestCase.VersionUpdateInfo,
isDisabled: existingTestCase.IsDisabled,
remarks: existingTestCase.Remarks);
// 保存更改
_testCaseRepository.UpdateTestCase(existingTestCase);
// 保存更改到数据库
await _unitOfWork.SaveChangesAsync(cancellationToken);
_logger.LogInformation("用例删除成功,用例ID: {TestCaseId}, 用例编码: {Code}, 用例名称: {Name}, 版本: {Version}",
existingTestCase.Id, existingTestCase.Code, existingTestCase.Name, existingTestCase.Version);
return OperationResult<bool>.CreateSuccess(true);
}
catch (Exception ex)
{
_logger.LogError(ex, "删除用例时发生错误,用例ID: {TestCaseId}", request.TestCaseId);
return OperationResult<bool>.CreateFailure($"删除用例时发生错误: {ex.Message}");
}
}
}

18
src/X1.Application/Features/TestCases/Commands/DisableTestCase/DisableTestCaseCommand.cs

@ -0,0 +1,18 @@
using CellularManagement.Domain.Common;
using MediatR;
using System.ComponentModel.DataAnnotations;
namespace CellularManagement.Application.Features.TestCases.Commands.DisableTestCase;
/// <summary>
/// 禁用用例命令
/// </summary>
public class DisableTestCaseCommand : IRequest<OperationResult<bool>>
{
/// <summary>
/// 用例ID
/// </summary>
[Required(ErrorMessage = "用例ID不能为空")]
[MaxLength(50, ErrorMessage = "用例ID长度不能超过50个字符")]
public string TestCaseId { get; set; } = null!;
}

109
src/X1.Application/Features/TestCases/Commands/DisableTestCase/DisableTestCaseCommandHandler.cs

@ -0,0 +1,109 @@
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.TestCases.Commands.DisableTestCase;
/// <summary>
/// 禁用用例命令处理器
/// </summary>
public class DisableTestCaseCommandHandler : IRequestHandler<DisableTestCaseCommand, OperationResult<bool>>
{
private readonly ITestCaseRepository _testCaseRepository;
private readonly ILogger<DisableTestCaseCommandHandler> _logger;
private readonly IUnitOfWork _unitOfWork;
private readonly ICurrentUserService _currentUserService;
/// <summary>
/// 初始化命令处理器
/// </summary>
public DisableTestCaseCommandHandler(
ITestCaseRepository testCaseRepository,
ILogger<DisableTestCaseCommandHandler> logger,
IUnitOfWork unitOfWork,
ICurrentUserService currentUserService)
{
_testCaseRepository = testCaseRepository;
_logger = logger;
_unitOfWork = unitOfWork;
_currentUserService = currentUserService;
}
/// <summary>
/// 处理禁用用例命令
/// </summary>
public async Task<OperationResult<bool>> Handle(DisableTestCaseCommand request, CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("开始禁用用例,用例ID: {TestCaseId}", request.TestCaseId);
// 检查用例是否存在
var existingTestCase = await _testCaseRepository.GetTestCaseByIdAsync(request.TestCaseId, cancellationToken);
if (existingTestCase == null)
{
_logger.LogWarning("用例不存在: {TestCaseId}", request.TestCaseId);
return OperationResult<bool>.CreateFailure($"用例ID {request.TestCaseId} 不存在");
}
// 检查用例是否已被软删除
if (existingTestCase.IsDeleted)
{
_logger.LogWarning("用例已被删除: {TestCaseId}", request.TestCaseId);
return OperationResult<bool>.CreateFailure($"用例ID {request.TestCaseId} 已被删除");
}
// 检查用例是否已经禁用
if (existingTestCase.IsDisabled)
{
_logger.LogWarning("用例已经禁用: {TestCaseId}", request.TestCaseId);
return OperationResult<bool>.CreateFailure($"用例ID {request.TestCaseId} 已经禁用");
}
// 获取当前用户ID
var currentUserId = _currentUserService.GetCurrentUserId();
if (string.IsNullOrEmpty(currentUserId))
{
_logger.LogError("无法获取当前用户ID,用户可能未认证");
return OperationResult<bool>.CreateFailure("用户未认证,无法禁用用例");
}
// 禁用用例
existingTestCase.Disable();
existingTestCase.Update(
code: existingTestCase.Code,
name: existingTestCase.Name,
version: existingTestCase.Version,
updatedBy: currentUserId,
userCount: existingTestCase.UserCount,
userInfoList: existingTestCase.UserInfoList,
latencyThresholdCount: existingTestCase.LatencyThresholdCount,
latencyThresholdList: existingTestCase.LatencyThresholdList,
throughputThresholdCount: existingTestCase.ThroughputThresholdCount,
throughputThresholdList: existingTestCase.ThroughputThresholdList,
description: existingTestCase.Description,
versionUpdateInfo: existingTestCase.VersionUpdateInfo,
isDisabled: true,
remarks: existingTestCase.Remarks);
// 保存更改
_testCaseRepository.UpdateTestCase(existingTestCase);
// 保存更改到数据库
await _unitOfWork.SaveChangesAsync(cancellationToken);
_logger.LogInformation("用例禁用成功,用例ID: {TestCaseId}, 用例编码: {Code}, 用例名称: {Name}, 版本: {Version}",
existingTestCase.Id, existingTestCase.Code, existingTestCase.Name, existingTestCase.Version);
return OperationResult<bool>.CreateSuccess(true);
}
catch (Exception ex)
{
_logger.LogError(ex, "禁用用例时发生错误,用例ID: {TestCaseId}", request.TestCaseId);
return OperationResult<bool>.CreateFailure($"禁用用例时发生错误: {ex.Message}");
}
}
}

18
src/X1.Application/Features/TestCases/Commands/EnableTestCase/EnableTestCaseCommand.cs

@ -0,0 +1,18 @@
using CellularManagement.Domain.Common;
using MediatR;
using System.ComponentModel.DataAnnotations;
namespace CellularManagement.Application.Features.TestCases.Commands.EnableTestCase;
/// <summary>
/// 启用用例命令
/// </summary>
public class EnableTestCaseCommand : IRequest<OperationResult<bool>>
{
/// <summary>
/// 用例ID
/// </summary>
[Required(ErrorMessage = "用例ID不能为空")]
[MaxLength(50, ErrorMessage = "用例ID长度不能超过50个字符")]
public string TestCaseId { get; set; } = null!;
}

109
src/X1.Application/Features/TestCases/Commands/EnableTestCase/EnableTestCaseCommandHandler.cs

@ -0,0 +1,109 @@
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.TestCases.Commands.EnableTestCase;
/// <summary>
/// 启用用例命令处理器
/// </summary>
public class EnableTestCaseCommandHandler : IRequestHandler<EnableTestCaseCommand, OperationResult<bool>>
{
private readonly ITestCaseRepository _testCaseRepository;
private readonly ILogger<EnableTestCaseCommandHandler> _logger;
private readonly IUnitOfWork _unitOfWork;
private readonly ICurrentUserService _currentUserService;
/// <summary>
/// 初始化命令处理器
/// </summary>
public EnableTestCaseCommandHandler(
ITestCaseRepository testCaseRepository,
ILogger<EnableTestCaseCommandHandler> logger,
IUnitOfWork unitOfWork,
ICurrentUserService currentUserService)
{
_testCaseRepository = testCaseRepository;
_logger = logger;
_unitOfWork = unitOfWork;
_currentUserService = currentUserService;
}
/// <summary>
/// 处理启用用例命令
/// </summary>
public async Task<OperationResult<bool>> Handle(EnableTestCaseCommand request, CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("开始启用用例,用例ID: {TestCaseId}", request.TestCaseId);
// 检查用例是否存在
var existingTestCase = await _testCaseRepository.GetTestCaseByIdAsync(request.TestCaseId, cancellationToken);
if (existingTestCase == null)
{
_logger.LogWarning("用例不存在: {TestCaseId}", request.TestCaseId);
return OperationResult<bool>.CreateFailure($"用例ID {request.TestCaseId} 不存在");
}
// 检查用例是否已被软删除
if (existingTestCase.IsDeleted)
{
_logger.LogWarning("用例已被删除: {TestCaseId}", request.TestCaseId);
return OperationResult<bool>.CreateFailure($"用例ID {request.TestCaseId} 已被删除");
}
// 检查用例是否已经启用
if (!existingTestCase.IsDisabled)
{
_logger.LogWarning("用例已经启用: {TestCaseId}", request.TestCaseId);
return OperationResult<bool>.CreateFailure($"用例ID {request.TestCaseId} 已经启用");
}
// 获取当前用户ID
var currentUserId = _currentUserService.GetCurrentUserId();
if (string.IsNullOrEmpty(currentUserId))
{
_logger.LogError("无法获取当前用户ID,用户可能未认证");
return OperationResult<bool>.CreateFailure("用户未认证,无法启用用例");
}
// 启用用例
existingTestCase.Enable();
existingTestCase.Update(
code: existingTestCase.Code,
name: existingTestCase.Name,
version: existingTestCase.Version,
updatedBy: currentUserId,
userCount: existingTestCase.UserCount,
userInfoList: existingTestCase.UserInfoList,
latencyThresholdCount: existingTestCase.LatencyThresholdCount,
latencyThresholdList: existingTestCase.LatencyThresholdList,
throughputThresholdCount: existingTestCase.ThroughputThresholdCount,
throughputThresholdList: existingTestCase.ThroughputThresholdList,
description: existingTestCase.Description,
versionUpdateInfo: existingTestCase.VersionUpdateInfo,
isDisabled: false,
remarks: existingTestCase.Remarks);
// 保存更改
_testCaseRepository.UpdateTestCase(existingTestCase);
// 保存更改到数据库
await _unitOfWork.SaveChangesAsync(cancellationToken);
_logger.LogInformation("用例启用成功,用例ID: {TestCaseId}, 用例编码: {Code}, 用例名称: {Name}, 版本: {Version}",
existingTestCase.Id, existingTestCase.Code, existingTestCase.Name, existingTestCase.Version);
return OperationResult<bool>.CreateSuccess(true);
}
catch (Exception ex)
{
_logger.LogError(ex, "启用用例时发生错误,用例ID: {TestCaseId}", request.TestCaseId);
return OperationResult<bool>.CreateFailure($"启用用例时发生错误: {ex.Message}");
}
}
}

98
src/X1.Application/Features/TestCases/Commands/UpdateTestCase/UpdateTestCaseCommand.cs

@ -0,0 +1,98 @@
using CellularManagement.Domain.Common;
using MediatR;
using System.ComponentModel.DataAnnotations;
namespace CellularManagement.Application.Features.TestCases.Commands.UpdateTestCase;
/// <summary>
/// 更新用例命令
/// </summary>
public class UpdateTestCaseCommand : IRequest<OperationResult<UpdateTestCaseResponse>>
{
/// <summary>
/// 用例ID
/// </summary>
[Required(ErrorMessage = "用例ID不能为空")]
[MaxLength(50, ErrorMessage = "用例ID长度不能超过50个字符")]
public string TestCaseId { get; set; } = null!;
/// <summary>
/// 用例编码
/// </summary>
[Required(ErrorMessage = "用例编码不能为空")]
[MaxLength(50, ErrorMessage = "用例编码长度不能超过50个字符")]
public string Code { get; set; } = null!;
/// <summary>
/// 用例名称
/// </summary>
[Required(ErrorMessage = "用例名称不能为空")]
[MaxLength(100, ErrorMessage = "用例名称长度不能超过100个字符")]
public string Name { get; set; } = null!;
/// <summary>
/// 用户数
/// </summary>
[Range(0, int.MaxValue, ErrorMessage = "用户数必须大于等于0")]
public int UserCount { get; set; } = 0;
/// <summary>
/// 用户信息列表(JSON格式)
/// </summary>
[MaxLength(4000, ErrorMessage = "用户信息列表长度不能超过4000个字符")]
public string? UserInfoList { get; set; }
/// <summary>
/// 时延阈值数
/// </summary>
[Range(0, int.MaxValue, ErrorMessage = "时延阈值数必须大于等于0")]
public int LatencyThresholdCount { get; set; } = 0;
/// <summary>
/// 时延阈值列表(JSON格式)
/// </summary>
[MaxLength(2000, ErrorMessage = "时延阈值列表长度不能超过2000个字符")]
public string? LatencyThresholdList { get; set; }
/// <summary>
/// 吞吐量阈值数
/// </summary>
[Range(0, int.MaxValue, ErrorMessage = "吞吐量阈值数必须大于等于0")]
public int ThroughputThresholdCount { get; set; } = 0;
/// <summary>
/// 吞吐量阈值列表(JSON格式)
/// </summary>
[MaxLength(2000, ErrorMessage = "吞吐量阈值列表长度不能超过2000个字符")]
public string? ThroughputThresholdList { get; set; }
/// <summary>
/// 用例说明
/// </summary>
[MaxLength(1000, ErrorMessage = "用例说明长度不能超过1000个字符")]
public string? Description { get; set; }
/// <summary>
/// 用例版本
/// </summary>
[Required(ErrorMessage = "用例版本不能为空")]
[MaxLength(20, ErrorMessage = "用例版本长度不能超过20个字符")]
public string Version { get; set; } = null!;
/// <summary>
/// 版本更新信息
/// </summary>
[MaxLength(500, ErrorMessage = "版本更新信息长度不能超过500个字符")]
public string? VersionUpdateInfo { get; set; }
/// <summary>
/// 是否禁用
/// </summary>
public bool IsDisabled { get; set; } = false;
/// <summary>
/// 备注
/// </summary>
[MaxLength(1000, ErrorMessage = "备注长度不能超过1000个字符")]
public string? Remarks { get; set; }
}

133
src/X1.Application/Features/TestCases/Commands/UpdateTestCase/UpdateTestCaseCommandHandler.cs

@ -0,0 +1,133 @@
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.TestCases.Commands.UpdateTestCase;
/// <summary>
/// 更新用例命令处理器
/// </summary>
public class UpdateTestCaseCommandHandler : IRequestHandler<UpdateTestCaseCommand, OperationResult<UpdateTestCaseResponse>>
{
private readonly ITestCaseRepository _testCaseRepository;
private readonly ILogger<UpdateTestCaseCommandHandler> _logger;
private readonly IUnitOfWork _unitOfWork;
private readonly ICurrentUserService _currentUserService;
/// <summary>
/// 初始化命令处理器
/// </summary>
public UpdateTestCaseCommandHandler(
ITestCaseRepository testCaseRepository,
ILogger<UpdateTestCaseCommandHandler> logger,
IUnitOfWork unitOfWork,
ICurrentUserService currentUserService)
{
_testCaseRepository = testCaseRepository;
_logger = logger;
_unitOfWork = unitOfWork;
_currentUserService = currentUserService;
}
/// <summary>
/// 处理更新用例命令
/// </summary>
public async Task<OperationResult<UpdateTestCaseResponse>> Handle(UpdateTestCaseCommand request, CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("开始更新用例,用例ID: {TestCaseId}, 用例编码: {Code}, 用例名称: {Name}, 版本: {Version}",
request.TestCaseId, request.Code, request.Name, request.Version);
// 检查用例是否存在
var existingTestCase = await _testCaseRepository.GetTestCaseByIdAsync(request.TestCaseId, cancellationToken);
if (existingTestCase == null)
{
_logger.LogWarning("用例不存在: {TestCaseId}", request.TestCaseId);
return OperationResult<UpdateTestCaseResponse>.CreateFailure($"用例ID {request.TestCaseId} 不存在");
}
// 检查用例编码是否已被其他用例使用
var testCaseWithSameCode = await _testCaseRepository.GetTestCaseByCodeAsync(request.Code, cancellationToken);
if (testCaseWithSameCode != null && testCaseWithSameCode.Id != request.TestCaseId)
{
_logger.LogWarning("用例编码已被其他用例使用: {Code}", request.Code);
return OperationResult<UpdateTestCaseResponse>.CreateFailure($"用例编码 {request.Code} 已被其他用例使用");
}
// 检查用例版本是否已被其他用例使用
var testCaseWithSameVersion = await _testCaseRepository.GetTestCaseByVersionAsync(request.Version, cancellationToken);
if (testCaseWithSameVersion != null && testCaseWithSameVersion.Id != request.TestCaseId)
{
_logger.LogWarning("用例版本已被其他用例使用: {Version}", request.Version);
return OperationResult<UpdateTestCaseResponse>.CreateFailure($"用例版本 {request.Version} 已被其他用例使用");
}
// 获取当前用户ID
var currentUserId = _currentUserService.GetCurrentUserId();
if (string.IsNullOrEmpty(currentUserId))
{
_logger.LogError("无法获取当前用户ID,用户可能未认证");
return OperationResult<UpdateTestCaseResponse>.CreateFailure("用户未认证,无法更新用例");
}
// 更新用例
existingTestCase.Update(
code: request.Code,
name: request.Name,
version: request.Version,
updatedBy: currentUserId,
userCount: request.UserCount,
userInfoList: request.UserInfoList,
latencyThresholdCount: request.LatencyThresholdCount,
latencyThresholdList: request.LatencyThresholdList,
throughputThresholdCount: request.ThroughputThresholdCount,
throughputThresholdList: request.ThroughputThresholdList,
description: request.Description,
versionUpdateInfo: request.VersionUpdateInfo,
isDisabled: request.IsDisabled,
remarks: request.Remarks);
// 保存更改
_testCaseRepository.UpdateTestCase(existingTestCase);
// 保存更改到数据库
await _unitOfWork.SaveChangesAsync(cancellationToken);
// 构建响应
var response = new UpdateTestCaseResponse
{
TestCaseId = existingTestCase.Id,
Code = existingTestCase.Code,
Name = existingTestCase.Name,
UserCount = existingTestCase.UserCount,
UserInfoList = existingTestCase.UserInfoList,
LatencyThresholdCount = existingTestCase.LatencyThresholdCount,
LatencyThresholdList = existingTestCase.LatencyThresholdList,
ThroughputThresholdCount = existingTestCase.ThroughputThresholdCount,
ThroughputThresholdList = existingTestCase.ThroughputThresholdList,
Description = existingTestCase.Description,
Version = existingTestCase.Version,
VersionUpdateInfo = existingTestCase.VersionUpdateInfo,
IsDisabled = existingTestCase.IsDisabled,
Remarks = existingTestCase.Remarks,
UpdatedAt = existingTestCase.UpdatedAt,
UpdatedBy = existingTestCase.UpdatedBy
};
_logger.LogInformation("用例更新成功,用例ID: {TestCaseId}, 用例编码: {Code}, 用例名称: {Name}, 版本: {Version}",
existingTestCase.Id, existingTestCase.Code, existingTestCase.Name, existingTestCase.Version);
return OperationResult<UpdateTestCaseResponse>.CreateSuccess(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "更新用例时发生错误,用例ID: {TestCaseId}, 用例编码: {Code}, 用例名称: {Name}, 版本: {Version}",
request.TestCaseId, request.Code, request.Name, request.Version);
return OperationResult<UpdateTestCaseResponse>.CreateFailure($"更新用例时发生错误: {ex.Message}");
}
}
}

87
src/X1.Application/Features/TestCases/Commands/UpdateTestCase/UpdateTestCaseResponse.cs

@ -0,0 +1,87 @@
namespace CellularManagement.Application.Features.TestCases.Commands.UpdateTestCase;
/// <summary>
/// 更新用例响应
/// </summary>
public class UpdateTestCaseResponse
{
/// <summary>
/// 用例ID
/// </summary>
public string TestCaseId { get; set; } = null!;
/// <summary>
/// 用例编码
/// </summary>
public string Code { get; set; } = null!;
/// <summary>
/// 用例名称
/// </summary>
public string Name { get; set; } = null!;
/// <summary>
/// 用户数
/// </summary>
public int UserCount { get; set; }
/// <summary>
/// 用户信息列表
/// </summary>
public string? UserInfoList { get; set; }
/// <summary>
/// 时延阈值数
/// </summary>
public int LatencyThresholdCount { get; set; }
/// <summary>
/// 时延阈值列表
/// </summary>
public string? LatencyThresholdList { get; set; }
/// <summary>
/// 吞吐量阈值数
/// </summary>
public int ThroughputThresholdCount { get; set; }
/// <summary>
/// 吞吐量阈值列表
/// </summary>
public string? ThroughputThresholdList { get; set; }
/// <summary>
/// 用例说明
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 用例版本
/// </summary>
public string Version { get; set; } = null!;
/// <summary>
/// 版本更新信息
/// </summary>
public string? VersionUpdateInfo { get; set; }
/// <summary>
/// 是否禁用
/// </summary>
public bool IsDisabled { get; set; }
/// <summary>
/// 备注
/// </summary>
public string? Remarks { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime? UpdatedAt { get; set; }
/// <summary>
/// 修改人
/// </summary>
public string? UpdatedBy { get; set; }
}

14
src/X1.Application/Features/TestCases/Queries/GetTestCaseById/GetTestCaseByIdQuery.cs

@ -0,0 +1,14 @@
using MediatR;
namespace CellularManagement.Application.Features.TestCases.Queries.GetTestCaseById;
/// <summary>
/// 根据ID获取用例查询
/// </summary>
public class GetTestCaseByIdQuery : IRequest<GetTestCaseByIdResponse?>
{
/// <summary>
/// 用例ID
/// </summary>
public string Id { get; set; } = null!;
}

76
src/X1.Application/Features/TestCases/Queries/GetTestCaseById/GetTestCaseByIdQueryHandler.cs

@ -0,0 +1,76 @@
using MediatR;
using Microsoft.Extensions.Logging;
using CellularManagement.Domain.Repositories.Device;
namespace CellularManagement.Application.Features.TestCases.Queries.GetTestCaseById;
/// <summary>
/// 根据ID获取用例查询处理器
/// </summary>
public class GetTestCaseByIdQueryHandler : IRequestHandler<GetTestCaseByIdQuery, GetTestCaseByIdResponse?>
{
private readonly ITestCaseRepository _testCaseRepository;
private readonly ILogger<GetTestCaseByIdQueryHandler> _logger;
/// <summary>
/// 初始化查询处理器
/// </summary>
public GetTestCaseByIdQueryHandler(
ITestCaseRepository testCaseRepository,
ILogger<GetTestCaseByIdQueryHandler> logger)
{
_testCaseRepository = testCaseRepository;
_logger = logger;
}
/// <summary>
/// 处理根据ID获取用例查询
/// </summary>
public async Task<GetTestCaseByIdResponse?> Handle(GetTestCaseByIdQuery request, CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("开始获取用例详情,用例ID: {TestCaseId}", request.Id);
// 获取用例
var testCase = await _testCaseRepository.GetTestCaseByIdAsync(request.Id, cancellationToken);
if (testCase == null)
{
_logger.LogWarning("用例不存在: {TestCaseId}", request.Id);
return null;
}
// 转换为响应
var response = new GetTestCaseByIdResponse
{
Id = testCase.Id,
Code = testCase.Code,
Name = testCase.Name,
UserCount = testCase.UserCount,
UserInfoList = testCase.UserInfoList,
LatencyThresholdCount = testCase.LatencyThresholdCount,
LatencyThresholdList = testCase.LatencyThresholdList,
ThroughputThresholdCount = testCase.ThroughputThresholdCount,
ThroughputThresholdList = testCase.ThroughputThresholdList,
Description = testCase.Description,
Version = testCase.Version,
VersionUpdateInfo = testCase.VersionUpdateInfo,
IsDisabled = testCase.IsDisabled,
Remarks = testCase.Remarks,
CreatedAt = testCase.CreatedAt,
CreatedBy = testCase.CreatedBy,
UpdatedAt = testCase.UpdatedAt,
UpdatedBy = testCase.UpdatedBy
};
_logger.LogInformation("成功获取用例详情,用例ID: {TestCaseId}, 用例编码: {Code}, 用例名称: {Name}",
testCase.Id, testCase.Code, testCase.Name);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "获取用例详情时发生错误,用例ID: {TestCaseId}", request.Id);
throw;
}
}
}

97
src/X1.Application/Features/TestCases/Queries/GetTestCaseById/GetTestCaseByIdResponse.cs

@ -0,0 +1,97 @@
namespace CellularManagement.Application.Features.TestCases.Queries.GetTestCaseById;
/// <summary>
/// 根据ID获取用例响应
/// </summary>
public class GetTestCaseByIdResponse
{
/// <summary>
/// 用例ID
/// </summary>
public string Id { get; set; } = null!;
/// <summary>
/// 用例编码
/// </summary>
public string Code { get; set; } = null!;
/// <summary>
/// 用例名称
/// </summary>
public string Name { get; set; } = null!;
/// <summary>
/// 用户数
/// </summary>
public int UserCount { get; set; }
/// <summary>
/// 用户信息列表
/// </summary>
public string? UserInfoList { get; set; }
/// <summary>
/// 时延阈值数
/// </summary>
public int LatencyThresholdCount { get; set; }
/// <summary>
/// 时延阈值列表
/// </summary>
public string? LatencyThresholdList { get; set; }
/// <summary>
/// 吞吐量阈值数
/// </summary>
public int ThroughputThresholdCount { get; set; }
/// <summary>
/// 吞吐量阈值列表
/// </summary>
public string? ThroughputThresholdList { get; set; }
/// <summary>
/// 用例说明
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 用例版本
/// </summary>
public string Version { get; set; } = null!;
/// <summary>
/// 版本更新信息
/// </summary>
public string? VersionUpdateInfo { get; set; }
/// <summary>
/// 是否禁用
/// </summary>
public bool IsDisabled { get; set; }
/// <summary>
/// 备注
/// </summary>
public string? Remarks { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreatedAt { get; set; }
/// <summary>
/// 创建人
/// </summary>
public string CreatedBy { get; set; } = null!;
/// <summary>
/// 更新时间
/// </summary>
public DateTime? UpdatedAt { get; set; }
/// <summary>
/// 修改人
/// </summary>
public string? UpdatedBy { get; set; }
}

14
src/X1.Application/Features/TestCases/Queries/GetTestCases/GetTestCasesQuery.cs

@ -0,0 +1,14 @@
using MediatR;
namespace CellularManagement.Application.Features.TestCases.Queries.GetTestCases;
/// <summary>
/// 获取所有用例查询
/// </summary>
public class GetTestCasesQuery : IRequest<GetTestCasesResponse>
{
/// <summary>
/// 搜索关键词
/// </summary>
public string? Keyword { get; set; }
}

76
src/X1.Application/Features/TestCases/Queries/GetTestCases/GetTestCasesQueryHandler.cs

@ -0,0 +1,76 @@
using MediatR;
using Microsoft.Extensions.Logging;
using CellularManagement.Domain.Repositories.Device;
namespace CellularManagement.Application.Features.TestCases.Queries.GetTestCases;
/// <summary>
/// 获取所有用例查询处理器
/// </summary>
public class GetTestCasesQueryHandler : IRequestHandler<GetTestCasesQuery, GetTestCasesResponse>
{
private readonly ITestCaseRepository _testCaseRepository;
private readonly ILogger<GetTestCasesQueryHandler> _logger;
/// <summary>
/// 初始化查询处理器
/// </summary>
public GetTestCasesQueryHandler(
ITestCaseRepository testCaseRepository,
ILogger<GetTestCasesQueryHandler> logger)
{
_testCaseRepository = testCaseRepository;
_logger = logger;
}
/// <summary>
/// 处理获取所有用例查询
/// </summary>
public async Task<GetTestCasesResponse> Handle(GetTestCasesQuery request, CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("开始获取用例列表,搜索关键词: {Keyword}", request.Keyword ?? "无");
// 获取用例列表
var testCases = await _testCaseRepository.SearchTestCasesAsync(request.Keyword, cancellationToken);
// 转换为DTO
var testCaseDtos = testCases.Select(tc => new TestCaseDto
{
Id = tc.Id,
Code = tc.Code,
Name = tc.Name,
UserCount = tc.UserCount,
UserInfoList = tc.UserInfoList,
LatencyThresholdCount = tc.LatencyThresholdCount,
LatencyThresholdList = tc.LatencyThresholdList,
ThroughputThresholdCount = tc.ThroughputThresholdCount,
ThroughputThresholdList = tc.ThroughputThresholdList,
Description = tc.Description,
Version = tc.Version,
VersionUpdateInfo = tc.VersionUpdateInfo,
IsDisabled = tc.IsDisabled,
Remarks = tc.Remarks,
CreatedAt = tc.CreatedAt,
CreatedBy = tc.CreatedBy,
UpdatedAt = tc.UpdatedAt,
UpdatedBy = tc.UpdatedBy
}).ToList();
var response = new GetTestCasesResponse
{
TestCases = testCaseDtos,
TotalCount = testCaseDtos.Count
};
_logger.LogInformation("成功获取用例列表,总数: {TotalCount}", response.TotalCount);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "获取用例列表时发生错误,搜索关键词: {Keyword}", request.Keyword ?? "无");
throw;
}
}
}

113
src/X1.Application/Features/TestCases/Queries/GetTestCases/GetTestCasesResponse.cs

@ -0,0 +1,113 @@
namespace CellularManagement.Application.Features.TestCases.Queries.GetTestCases;
/// <summary>
/// 获取所有用例响应
/// </summary>
public class GetTestCasesResponse
{
/// <summary>
/// 用例列表
/// </summary>
public List<TestCaseDto> TestCases { get; set; } = new();
/// <summary>
/// 总数
/// </summary>
public int TotalCount { get; set; }
}
/// <summary>
/// 用例数据传输对象
/// </summary>
public class TestCaseDto
{
/// <summary>
/// 用例ID
/// </summary>
public string Id { get; set; } = null!;
/// <summary>
/// 用例编码
/// </summary>
public string Code { get; set; } = null!;
/// <summary>
/// 用例名称
/// </summary>
public string Name { get; set; } = null!;
/// <summary>
/// 用户数
/// </summary>
public int UserCount { get; set; }
/// <summary>
/// 用户信息列表
/// </summary>
public string? UserInfoList { get; set; }
/// <summary>
/// 时延阈值数
/// </summary>
public int LatencyThresholdCount { get; set; }
/// <summary>
/// 时延阈值列表
/// </summary>
public string? LatencyThresholdList { get; set; }
/// <summary>
/// 吞吐量阈值数
/// </summary>
public int ThroughputThresholdCount { get; set; }
/// <summary>
/// 吞吐量阈值列表
/// </summary>
public string? ThroughputThresholdList { get; set; }
/// <summary>
/// 用例说明
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 用例版本
/// </summary>
public string Version { get; set; } = null!;
/// <summary>
/// 版本更新信息
/// </summary>
public string? VersionUpdateInfo { get; set; }
/// <summary>
/// 是否禁用
/// </summary>
public bool IsDisabled { get; set; }
/// <summary>
/// 备注
/// </summary>
public string? Remarks { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreatedAt { get; set; }
/// <summary>
/// 创建人
/// </summary>
public string CreatedBy { get; set; } = null!;
/// <summary>
/// 更新时间
/// </summary>
public DateTime? UpdatedAt { get; set; }
/// <summary>
/// 修改人
/// </summary>
public string? UpdatedBy { get; set; }
}

205
src/X1.Domain/Entities/Device/TestCase.cs

@ -0,0 +1,205 @@
using System.ComponentModel.DataAnnotations;
using CellularManagement.Domain.Entities.Common;
namespace CellularManagement.Domain.Entities.Device;
/// <summary>
/// 用例实体
/// </summary>
public class TestCase : AuditableEntity
{
private TestCase() { }
/// <summary>
/// 用例编码
/// </summary>
[Required]
[MaxLength(50)]
public string Code { get; private set; } = null!;
/// <summary>
/// 用例名称
/// </summary>
[Required]
[MaxLength(100)]
public string Name { get; private set; } = null!;
/// <summary>
/// 用户数
/// </summary>
public int UserCount { get; private set; } = 0;
/// <summary>
/// 用户信息列表(JSON格式存储)
/// </summary>
[MaxLength(4000)]
public string? UserInfoList { get; private set; }
/// <summary>
/// 时延阈值数
/// </summary>
public int LatencyThresholdCount { get; private set; } = 0;
/// <summary>
/// 时延阈值列表(JSON格式存储)
/// </summary>
[MaxLength(2000)]
public string? LatencyThresholdList { get; private set; }
/// <summary>
/// 吞吐量阈值数
/// </summary>
public int ThroughputThresholdCount { get; private set; } = 0;
/// <summary>
/// 吞吐量阈值列表(JSON格式存储)
/// </summary>
[MaxLength(2000)]
public string? ThroughputThresholdList { get; private set; }
/// <summary>
/// 用例说明
/// </summary>
[MaxLength(1000)]
public string? Description { get; private set; }
/// <summary>
/// 用例版本
/// </summary>
[Required]
[MaxLength(20)]
public string Version { get; private set; } = null!;
/// <summary>
/// 版本更新信息
/// </summary>
[MaxLength(500)]
public string? VersionUpdateInfo { get; private set; }
/// <summary>
/// 是否禁用
/// </summary>
public bool IsDisabled { get; private set; } = false;
/// <summary>
/// 备注
/// </summary>
[MaxLength(1000)]
public string? Remarks { get; private set; }
/// <summary>
/// 创建用例
/// </summary>
public static TestCase Create(
string code,
string name,
string version,
string createdBy,
int userCount = 0,
string? userInfoList = null,
int latencyThresholdCount = 0,
string? latencyThresholdList = null,
int throughputThresholdCount = 0,
string? throughputThresholdList = null,
string? description = null,
string? versionUpdateInfo = null,
bool isDisabled = false,
string? remarks = null)
{
var testCase = new TestCase
{
Id = Guid.NewGuid().ToString(),
Code = code,
Name = name,
Version = version,
UserCount = userCount,
UserInfoList = userInfoList,
LatencyThresholdCount = latencyThresholdCount,
LatencyThresholdList = latencyThresholdList,
ThroughputThresholdCount = throughputThresholdCount,
ThroughputThresholdList = throughputThresholdList,
Description = description,
VersionUpdateInfo = versionUpdateInfo,
IsDisabled = isDisabled,
Remarks = remarks,
CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow,
CreatedBy = createdBy,
UpdatedBy = createdBy
};
return testCase;
}
/// <summary>
/// 更新用例
/// </summary>
public void Update(
string code,
string name,
string version,
string updatedBy,
int userCount = 0,
string? userInfoList = null,
int latencyThresholdCount = 0,
string? latencyThresholdList = null,
int throughputThresholdCount = 0,
string? throughputThresholdList = null,
string? description = null,
string? versionUpdateInfo = null,
bool isDisabled = false,
string? remarks = null)
{
Code = code;
Name = name;
Version = version;
UserCount = userCount;
UserInfoList = userInfoList;
LatencyThresholdCount = latencyThresholdCount;
LatencyThresholdList = latencyThresholdList;
ThroughputThresholdCount = throughputThresholdCount;
ThroughputThresholdList = throughputThresholdList;
Description = description;
VersionUpdateInfo = versionUpdateInfo;
IsDisabled = isDisabled;
Remarks = remarks;
UpdatedAt = DateTime.UtcNow;
UpdatedBy = updatedBy;
}
/// <summary>
/// 启用用例
/// </summary>
public void Enable()
{
IsDisabled = false;
UpdatedAt = DateTime.UtcNow;
}
/// <summary>
/// 禁用用例
/// </summary>
public void Disable()
{
IsDisabled = true;
UpdatedAt = DateTime.UtcNow;
}
/// <summary>
/// 软删除用例
/// </summary>
public void SoftDelete()
{
IsDeleted = true;
UpdatedAt = DateTime.UtcNow;
}
/// <summary>
/// 恢复用例
/// </summary>
public void Restore()
{
IsDeleted = false;
UpdatedAt = DateTime.UtcNow;
}
}

73
src/X1.Domain/Repositories/Device/ITestCaseRepository.cs

@ -0,0 +1,73 @@
using CellularManagement.Domain.Entities;
using CellularManagement.Domain.Entities.Device;
using CellularManagement.Domain.Repositories.Base;
namespace CellularManagement.Domain.Repositories.Device;
/// <summary>
/// 用例仓储接口
/// </summary>
public interface ITestCaseRepository : IBaseRepository<TestCase>
{
/// <summary>
/// 添加用例
/// </summary>
Task<TestCase> AddTestCaseAsync(TestCase testCase, CancellationToken cancellationToken = default);
/// <summary>
/// 更新用例
/// </summary>
void UpdateTestCase(TestCase testCase);
/// <summary>
/// 删除用例
/// </summary>
Task DeleteTestCaseAsync(string id, CancellationToken cancellationToken = default);
/// <summary>
/// 获取所有用例
/// </summary>
Task<IList<TestCase>> GetAllTestCasesAsync(CancellationToken cancellationToken = default);
/// <summary>
/// 根据ID获取用例
/// </summary>
Task<TestCase?> GetTestCaseByIdAsync(string id, CancellationToken cancellationToken = default);
/// <summary>
/// 根据编码获取用例
/// </summary>
Task<TestCase?> GetTestCaseByCodeAsync(string code, CancellationToken cancellationToken = default);
/// <summary>
/// 根据版本获取用例
/// </summary>
Task<TestCase?> GetTestCaseByVersionAsync(string version, CancellationToken cancellationToken = default);
/// <summary>
/// 搜索用例
/// </summary>
Task<IList<TestCase>> SearchTestCasesAsync(
string? keyword,
CancellationToken cancellationToken = default);
/// <summary>
/// 检查用例是否存在
/// </summary>
Task<bool> ExistsAsync(string id, CancellationToken cancellationToken = default);
/// <summary>
/// 检查编码是否存在
/// </summary>
Task<bool> CodeExistsAsync(string code, CancellationToken cancellationToken = default);
/// <summary>
/// 检查版本是否存在
/// </summary>
Task<bool> VersionExistsAsync(string version, CancellationToken cancellationToken = default);
/// <summary>
/// 获取启用的用例
/// </summary>
Task<IList<TestCase>> GetEnabledTestCasesAsync(CancellationToken cancellationToken = default);
}

94
src/X1.Infrastructure/Configurations/Device/TestCaseConfiguration.cs

@ -0,0 +1,94 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using CellularManagement.Domain.Entities.Device;
namespace CellularManagement.Infrastructure.Configurations.Device;
/// <summary>
/// 用例数据库配置
/// </summary>
public class TestCaseConfiguration : IEntityTypeConfiguration<TestCase>
{
/// <summary>
/// 配置用例实体
/// </summary>
public void Configure(EntityTypeBuilder<TestCase> builder)
{
// 表名
builder.ToTable("TestCases");
// 主键
builder.HasKey(x => x.Id);
// 属性配置
builder.Property(x => x.Id)
.HasMaxLength(50)
.IsRequired();
builder.Property(x => x.Code)
.HasMaxLength(50)
.IsRequired();
builder.Property(x => x.Name)
.HasMaxLength(100)
.IsRequired();
builder.Property(x => x.UserCount)
.IsRequired()
.HasDefaultValue(0);
builder.Property(x => x.UserInfoList)
.HasMaxLength(4000);
builder.Property(x => x.LatencyThresholdCount)
.IsRequired()
.HasDefaultValue(0);
builder.Property(x => x.LatencyThresholdList)
.HasMaxLength(2000);
builder.Property(x => x.ThroughputThresholdCount)
.IsRequired()
.HasDefaultValue(0);
builder.Property(x => x.ThroughputThresholdList)
.HasMaxLength(2000);
builder.Property(x => x.Description)
.HasMaxLength(1000);
builder.Property(x => x.Version)
.HasMaxLength(20)
.IsRequired();
builder.Property(x => x.VersionUpdateInfo)
.HasMaxLength(500);
builder.Property(x => x.IsDisabled)
.IsRequired()
.HasDefaultValue(false);
builder.Property(x => x.Remarks)
.HasMaxLength(1000);
// 索引
builder.HasIndex(x => x.Code)
.IsUnique()
.HasFilter("\"IsDeleted\" = false");
builder.HasIndex(x => x.Version)
.HasFilter("\"IsDeleted\" = false");
builder.HasIndex(x => x.Name)
.HasFilter("\"IsDeleted\" = false");
builder.HasIndex(x => x.IsDisabled)
.HasFilter("\"IsDeleted\" = false");
builder.HasIndex(x => x.CreatedAt)
.HasFilter("\"IsDeleted\" = false");
// 软删除过滤器
builder.HasQueryFilter(x => !x.IsDeleted);
}
}

5
src/X1.Infrastructure/Context/AppDbContext.cs

@ -61,6 +61,11 @@ public class AppDbContext : IdentityDbContext<AppUser, AppRole, string>
/// </summary>
public DbSet<TestCaseSet> TestCaseSets { get; set; } = null!;
/// <summary>
/// 用例集合
/// </summary>
public DbSet<TestCase> TestCases { get; set; } = null!;
/// <summary>
/// 初始化数据库上下文
/// </summary>

1
src/X1.Infrastructure/DependencyInjection.cs

@ -177,6 +177,7 @@ public static class DependencyInjection
services.AddScoped<INetworkConfigRepository, NetworkConfigRepository>();
services.AddScoped<IScenarioRepository, ScenarioRepository>();
services.AddScoped<ITestCaseSetRepository, TestCaseSetRepository>();
services.AddScoped<ITestCaseRepository, TestCaseRepository>();
return services;
}

149
src/X1.Infrastructure/Repositories/Device/TestCaseRepository.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;
/// <summary>
/// 用例仓储实现类
/// </summary>
public class TestCaseRepository : BaseRepository<TestCase>, ITestCaseRepository
{
private readonly ILogger<TestCaseRepository> _logger;
/// <summary>
/// 初始化仓储
/// </summary>
public TestCaseRepository(
ICommandRepository<TestCase> commandRepository,
IQueryRepository<TestCase> queryRepository,
ILogger<TestCaseRepository> logger)
: base(commandRepository, queryRepository, logger)
{
_logger = logger;
}
/// <summary>
/// 添加用例
/// </summary>
public async Task<TestCase> AddTestCaseAsync(TestCase testCase, CancellationToken cancellationToken = default)
{
var result = await CommandRepository.AddAsync(testCase, cancellationToken);
return result;
}
/// <summary>
/// 更新用例
/// </summary>
public void UpdateTestCase(TestCase testCase)
{
CommandRepository.Update(testCase);
}
/// <summary>
/// 删除用例
/// </summary>
public async Task DeleteTestCaseAsync(string id, CancellationToken cancellationToken = default)
{
await CommandRepository.DeleteByIdAsync(id, cancellationToken);
}
/// <summary>
/// 获取所有用例
/// </summary>
public async Task<IList<TestCase>> GetAllTestCasesAsync(CancellationToken cancellationToken = default)
{
var testCases = await QueryRepository.GetAllAsync(cancellationToken: cancellationToken);
return testCases.ToList();
}
/// <summary>
/// 根据ID获取用例
/// </summary>
public async Task<TestCase?> GetTestCaseByIdAsync(string id, CancellationToken cancellationToken = default)
{
return await QueryRepository.GetByIdAsync(id, cancellationToken: cancellationToken);
}
/// <summary>
/// 根据编码获取用例
/// </summary>
public async Task<TestCase?> GetTestCaseByCodeAsync(string code, CancellationToken cancellationToken = default)
{
return await QueryRepository.FirstOrDefaultAsync(tc => tc.Code == code, cancellationToken: cancellationToken);
}
/// <summary>
/// 根据版本获取用例
/// </summary>
public async Task<TestCase?> GetTestCaseByVersionAsync(string version, CancellationToken cancellationToken = default)
{
return await QueryRepository.FirstOrDefaultAsync(tc => tc.Version == version, cancellationToken: cancellationToken);
}
/// <summary>
/// 搜索用例
/// </summary>
public async Task<IList<TestCase>> SearchTestCasesAsync(
string? keyword,
CancellationToken cancellationToken = default)
{
var query = await QueryRepository.FindAsync(tc => true, cancellationToken: cancellationToken);
if (!string.IsNullOrWhiteSpace(keyword))
{
query = query.Where(tc =>
tc.Name.Contains(keyword) ||
tc.Code.Contains(keyword) ||
tc.Version.Contains(keyword) ||
(tc.Description != null && tc.Description.Contains(keyword)) ||
(tc.VersionUpdateInfo != null && tc.VersionUpdateInfo.Contains(keyword)) ||
(tc.Remarks != null && tc.Remarks.Contains(keyword)));
}
var testCases = query;
return testCases.ToList();
}
/// <summary>
/// 检查用例是否存在
/// </summary>
public async Task<bool> ExistsAsync(string id, CancellationToken cancellationToken = default)
{
return await QueryRepository.AnyAsync(tc => tc.Id == id, cancellationToken: cancellationToken);
}
/// <summary>
/// 检查编码是否存在
/// </summary>
public async Task<bool> CodeExistsAsync(string code, CancellationToken cancellationToken = default)
{
return await QueryRepository.AnyAsync(tc => tc.Code == code, cancellationToken: cancellationToken);
}
/// <summary>
/// 检查版本是否存在
/// </summary>
public async Task<bool> VersionExistsAsync(string version, CancellationToken cancellationToken = default)
{
return await QueryRepository.AnyAsync(tc => tc.Version == version, cancellationToken: cancellationToken);
}
/// <summary>
/// 获取启用的用例
/// </summary>
public async Task<IList<TestCase>> GetEnabledTestCasesAsync(CancellationToken cancellationToken = default)
{
var testCases = await QueryRepository.FindAsync(tc => !tc.IsDisabled, cancellationToken: cancellationToken);
return testCases.ToList();
}
}

169
src/X1.Presentation/Controllers/TestCasesController.cs

@ -0,0 +1,169 @@
using CellularManagement.Application.Features.TestCases.Commands.CreateTestCase;
using CellularManagement.Application.Features.TestCases.Commands.DeleteTestCase;
using CellularManagement.Application.Features.TestCases.Commands.DisableTestCase;
using CellularManagement.Application.Features.TestCases.Commands.EnableTestCase;
using CellularManagement.Application.Features.TestCases.Commands.UpdateTestCase;
using CellularManagement.Application.Features.TestCases.Queries.GetTestCaseById;
using CellularManagement.Application.Features.TestCases.Queries.GetTestCases;
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;
/// <summary>
/// 用例控制器
/// </summary>
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class TestCasesController : ApiController
{
private readonly ILogger<TestCasesController> _logger;
/// <summary>
/// 初始化控制器
/// </summary>
public TestCasesController(IMediator mediator, ILogger<TestCasesController> logger)
: base(mediator)
{
_logger = logger;
}
/// <summary>
/// 获取用例列表
/// </summary>
[HttpGet]
public async Task<GetTestCasesResponse> GetList([FromQuery] string? keyword)
{
_logger.LogInformation("开始获取用例列表,搜索关键词: {Keyword}", keyword ?? "无");
var result = await mediator.Send(new GetTestCasesQuery { Keyword = keyword });
_logger.LogInformation("成功获取用例列表,总数: {TotalCount}", result.TotalCount);
return result;
}
/// <summary>
/// 获取用例详情
/// </summary>
[HttpGet("{id}")]
public async Task<GetTestCaseByIdResponse?> GetById(string id)
{
_logger.LogInformation("开始获取用例详情,用例ID: {TestCaseId}", id);
var result = await mediator.Send(new GetTestCaseByIdQuery { Id = id });
if (result == null)
{
_logger.LogWarning("用例不存在: {TestCaseId}", id);
return null;
}
_logger.LogInformation("成功获取用例详情,用例ID: {TestCaseId}", id);
return result;
}
/// <summary>
/// 创建用例
/// </summary>
[HttpPost]
public async Task<OperationResult<CreateTestCaseResponse>> Create([FromBody] CreateTestCaseCommand 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: {TestCaseId}", result.Data?.TestCaseId);
return result;
}
/// <summary>
/// 更新用例
/// </summary>
[HttpPut("{id}")]
public async Task<OperationResult<UpdateTestCaseResponse>> Update(string id, [FromBody] UpdateTestCaseCommand command)
{
_logger.LogInformation("开始更新用例,用例ID: {TestCaseId}", id);
if (id != command.TestCaseId)
{
_logger.LogWarning("用例ID不匹配,路径ID: {PathId}, 命令ID: {CommandId}", id, command.TestCaseId);
return OperationResult<UpdateTestCaseResponse>.CreateFailure("用例ID不匹配");
}
var result = await mediator.Send(command);
if (!result.IsSuccess)
{
_logger.LogWarning("更新用例失败: {Message}", result.ErrorMessages);
return result;
}
_logger.LogInformation("成功更新用例,用例ID: {TestCaseId}", id);
return result;
}
/// <summary>
/// 删除用例
/// </summary>
[HttpDelete("{id}")]
public async Task<OperationResult<bool>> Delete(string id)
{
_logger.LogInformation("开始删除用例,用例ID: {TestCaseId}", id);
var result = await mediator.Send(new DeleteTestCaseCommand { TestCaseId = id });
if (!result.IsSuccess)
{
_logger.LogWarning("删除用例失败: {Message}", result.ErrorMessages);
return result;
}
_logger.LogInformation("成功删除用例,用例ID: {TestCaseId}", id);
return result;
}
/// <summary>
/// 启用用例
/// </summary>
[HttpPost("{id}/enable")]
public async Task<OperationResult<bool>> Enable(string id)
{
_logger.LogInformation("开始启用用例,用例ID: {TestCaseId}", id);
var result = await mediator.Send(new EnableTestCaseCommand { TestCaseId = id });
if (!result.IsSuccess)
{
_logger.LogWarning("启用用例失败: {Message}", result.ErrorMessages);
return result;
}
_logger.LogInformation("成功启用用例,用例ID: {TestCaseId}", id);
return result;
}
/// <summary>
/// 禁用用例
/// </summary>
[HttpPost("{id}/disable")]
public async Task<OperationResult<bool>> Disable(string id)
{
_logger.LogInformation("开始禁用用例,用例ID: {TestCaseId}", id);
var result = await mediator.Send(new DisableTestCaseCommand { TestCaseId = id });
if (!result.IsSuccess)
{
_logger.LogWarning("禁用用例失败: {Message}", result.ErrorMessages);
return result;
}
_logger.LogInformation("成功禁用用例,用例ID: {TestCaseId}", id);
return result;
}
}
Loading…
Cancel
Save