FatigueTestController.cs 11 KB
using Microsoft.AspNetCore.Mvc;
using Rcs.Application.Common;
using Rcs.Application.Services;
using StatusCodes = Microsoft.AspNetCore.Http.StatusCodes;

namespace Rcs.Api.Controllers;

/// <summary>
/// 疲劳测试控制器 - 用于配置和管理疲劳测试任务生成
/// @author zzy
/// </summary>
[ApiController]
[Route("api/[controller]")]
public class FatigueTestController : ControllerBase
{
    private readonly ILogger<FatigueTestController> _logger;
    private readonly IFatigueTestConfigService _configService;

    public FatigueTestController(
        ILogger<FatigueTestController> logger,
        IFatigueTestConfigService configService)
    {
        _logger = logger;
        _configService = configService;
    }

    /// <summary>
    /// 获取疲劳测试配置
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>配置信息</returns>
    [HttpGet("config")]
    public async Task<IActionResult> GetConfig(CancellationToken cancellationToken = default)
    {
        try
        {
            var config = await _configService.GetConfigAsync(cancellationToken);
            if (config == null)
            {
                return Ok(ApiResponse.Successful(new FatigueTestConfigDto()));
            }

            var dto = new FatigueTestConfigDto
            {
                MapId = config.MapId,
                RobotIds = config.RobotIds,
                LocationIds = config.LocationIds,
                IsRunning = config.IsRunning,
                TaskIntervalMs = config.TaskIntervalMs,
                CreatedAt = config.CreatedAt,
                UpdatedAt = config.UpdatedAt
            };

            return Ok(ApiResponse.Successful(dto));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "[FatigueTest] 获取配置失败");
            return Ok(ApiResponse.Failed($"获取配置失败: {ex.Message}"));
        }
    }

    /// <summary>
    /// 保存疲劳测试配置
    /// </summary>
    /// <param name="dto">配置DTO</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>操作结果</returns>
    [HttpPost("config")]
    public async Task<IActionResult> SaveConfig([FromBody] SaveFatigueTestConfigDto dto, CancellationToken cancellationToken = default)
    {
        try
        {

            if (dto.RobotIds == null || !dto.RobotIds.Any())
            {
                return Ok(ApiResponse.Failed("机器人ID集合不能为空", StatusCodes.Status400BadRequest));
            }

            if (dto.LocationIds == null || dto.LocationIds.Count < 2)
            {
                return Ok(ApiResponse.Failed("库位ID集合至少需要包含2个库位", StatusCodes.Status400BadRequest));
            }

            // 过滤无效的ID
            var validRobotIds = dto.RobotIds
                .Where(id => !string.IsNullOrWhiteSpace(id) && Guid.TryParse(id, out _))
                .Distinct()
                .ToList();

            var validLocationIds = dto.LocationIds
                .Where(id => !string.IsNullOrWhiteSpace(id) && Guid.TryParse(id, out _))
                .Distinct()
                .ToList();

            if (validRobotIds.Count == 0)
            {
                return Ok(ApiResponse.Failed("没有有效的机器人ID", StatusCodes.Status400BadRequest));
            }

            if (validLocationIds.Count < 2)
            {
                return Ok(ApiResponse.Failed("有效的库位ID数量不足,至少需要2个", StatusCodes.Status400BadRequest));
            }

            // 获取现有配置或创建新配置
            var existingConfig = await _configService.GetConfigAsync(cancellationToken);
            var config = existingConfig ?? new FatigueTestConfig();

            // 更新配置
            config.RobotIds = validRobotIds;
            config.LocationIds = validLocationIds;
            config.TaskIntervalMs = Math.Max(100, Math.Min(60000, dto.TaskIntervalMs)); // 限制在100ms到60s之间

            var result = await _configService.SaveConfigAsync(config, cancellationToken);
            if (!result)
            {
                return Ok(ApiResponse.Failed("保存配置失败", StatusCodes.Status500InternalServerError));
            }

            _logger.LogInformation("[FatigueTest] 配置已更新: MapId={MapId}, Robots={RobotCount}, Locations={LocationCount}",
                config.MapId, validRobotIds.Count, validLocationIds.Count);

            return Ok(ApiResponse.Successful("配置保存成功"));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "[FatigueTest] 保存配置失败");
            return Ok(ApiResponse.Failed($"保存配置失败: {ex.Message}"));
        }
    }

    /// <summary>
    /// 启动疲劳测试
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>操作结果</returns>
    [HttpPost("start")]
    public async Task<IActionResult> Start(CancellationToken cancellationToken = default)
    {
        try
        {
            var config = await _configService.GetConfigAsync(cancellationToken);
            if (config == null)
            {
                return Ok(ApiResponse.Failed("配置不存在,请先配置参数", StatusCodes.Status400BadRequest));
            }

            var result = await _configService.StartAsync(cancellationToken);
            if (!result)
            {
                return Ok(ApiResponse.Failed("启动失败", StatusCodes.Status500InternalServerError));
            }

            _logger.LogInformation("[FatigueTest] 疲劳测试已启动");
            return Ok(ApiResponse.Successful("疲劳测试已启动"));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "[FatigueTest] 启动失败");
            return Ok(ApiResponse.Failed($"启动失败: {ex.Message}"));
        }
    }

    /// <summary>
    /// 停止疲劳测试
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>操作结果</returns>
    [HttpPost("stop")]
    public async Task<IActionResult> Stop(CancellationToken cancellationToken = default)
    {
        try
        {
            var result = await _configService.StopAsync(cancellationToken);
            if (!result)
            {
                return Ok(ApiResponse.Failed("停止失败", StatusCodes.Status500InternalServerError));
            }

            _logger.LogInformation("[FatigueTest] 疲劳测试已停止");
            return Ok(ApiResponse.Successful("疲劳测试已停止"));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "[FatigueTest] 停止失败");
            return Ok(ApiResponse.Failed($"停止失败: {ex.Message}"));
        }
    }

    /// <summary>
    /// 获取疲劳测试运行状态
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>运行状态</returns>
    [HttpGet("status")]
    public async Task<IActionResult> GetStatus(CancellationToken cancellationToken = default)
    {
        try
        {
            var isRunning = await _configService.GetRunningStatusAsync(cancellationToken);
            var config = await _configService.GetConfigAsync(cancellationToken);

            var status = new FatigueTestStatusDto
            {
                IsRunning = isRunning,
                MapId = config?.MapId,
                RobotCount = config?.RobotIds?.Count ?? 0,
                LocationCount = config?.LocationIds?.Count ?? 0,
                TaskIntervalMs = config?.TaskIntervalMs ?? 1000
            };

            return Ok(ApiResponse.Successful(status));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "[FatigueTest] 获取状态失败");
            return Ok(ApiResponse.Failed($"获取状态失败: {ex.Message}"));
        }
    }

    /// <summary>
    /// 清空配置
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>操作结果</returns>
    [HttpDelete("config")]
    public async Task<IActionResult> ClearConfig(CancellationToken cancellationToken = default)
    {
        try
        {
            // 先停止测试
            await _configService.StopAsync(cancellationToken);

            // 清空配置(保存一个空配置)
            var emptyConfig = new FatigueTestConfig
            {
                MapId = string.Empty,
                RobotIds = new List<string>(),
                LocationIds = new List<string>(),
                IsRunning = false,
                TaskIntervalMs = 1000
            };

            await _configService.SaveConfigAsync(emptyConfig, cancellationToken);

            _logger.LogInformation("[FatigueTest] 配置已清空");
            return Ok(ApiResponse.Successful("配置已清空"));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "[FatigueTest] 清空配置失败");
            return Ok(ApiResponse.Failed($"清空配置失败: {ex.Message}"));
        }
    }
}

/// <summary>
/// 疲劳测试配置DTO
/// </summary>
public class FatigueTestConfigDto
{
    /// <summary>
    /// 地图ID
    /// </summary>
    public string MapId { get; set; } = string.Empty;

    /// <summary>
    /// 机器人ID集合
    /// </summary>
    public List<string> RobotIds { get; set; } = new();

    /// <summary>
    /// 库位ID集合
    /// </summary>
    public List<string> LocationIds { get; set; } = new();

    /// <summary>
    /// 是否正在运行
    /// </summary>
    public bool IsRunning { get; set; } = false;

    /// <summary>
    /// 任务生成间隔(毫秒)
    /// </summary>
    public int TaskIntervalMs { get; set; } = 1000;

    /// <summary>
    /// 创建时间
    /// </summary>
    public DateTime CreatedAt { get; set; }

    /// <summary>
    /// 最后更新时间
    /// </summary>
    public DateTime UpdatedAt { get; set; }
}

/// <summary>
/// 保存疲劳测试配置DTO
/// </summary>
public class SaveFatigueTestConfigDto
{
    /// <summary>
    /// 地图ID
    /// </summary>
    public string? MapId { get; set; }

    /// <summary>
    /// 机器人ID集合
    /// </summary>
    public List<string> RobotIds { get; set; } = new();

    /// <summary>
    /// 库位ID集合
    /// </summary>
    public List<string> LocationIds { get; set; } = new();

    /// <summary>
    /// 任务生成间隔(毫秒,默认1000ms,范围100-60000)
    /// </summary>
    public int TaskIntervalMs { get; set; } = 1000;
}

/// <summary>
/// 疲劳测试状态DTO
/// </summary>
public class FatigueTestStatusDto
{
    /// <summary>
    /// 是否正在运行
    /// </summary>
    public bool IsRunning { get; set; }

    /// <summary>
    /// 地图ID
    /// </summary>
    public string? MapId { get; set; }

    /// <summary>
    /// 机器人数量
    /// </summary>
    public int RobotCount { get; set; }

    /// <summary>
    /// 库位数量
    /// </summary>
    public int LocationCount { get; set; }

    /// <summary>
    /// 任务生成间隔(毫秒)
    /// </summary>
    public int TaskIntervalMs { get; set; }
}