2897 lines
104 KiB
C#
2897 lines
104 KiB
C#
using Microsoft.Extensions.Logging;
|
||
using Microsoft.Extensions.Options;
|
||
using OrpaonVision.Core.Common;
|
||
using OrpaonVision.Core.Results;
|
||
using OrpaonVision.Core.ManualOverride;
|
||
using OrpaonVision.SiteApp.Runtime.Contracts;
|
||
using OrpaonVision.SiteApp.Runtime.Options;
|
||
using System.Collections.Concurrent;
|
||
|
||
namespace OrpaonVision.SiteApp.Runtime.Services;
|
||
|
||
/// <summary>
|
||
/// 高级运行时状态机服务。
|
||
/// </summary>
|
||
public sealed class AdvancedRuntimeStateMachineService : IRuntimeStateMachineService, IDisposable
|
||
{
|
||
private readonly ILogger<AdvancedRuntimeStateMachineService> _logger;
|
||
private readonly RuntimeOptions _options;
|
||
private readonly IManualOverrideService _manualOverrideService;
|
||
private readonly ConcurrentQueue<StateTransitionEvent> _eventHistory;
|
||
private readonly object _stateLock = new();
|
||
private RuntimeState _currentState;
|
||
private int _currentLayer;
|
||
private DateTime _lastTransitionTime;
|
||
private bool _isPaused;
|
||
private bool _isStopped;
|
||
|
||
public AdvancedRuntimeStateMachineService(
|
||
ILogger<AdvancedRuntimeStateMachineService> logger,
|
||
IOptions<RuntimeOptions> options,
|
||
IManualOverrideService manualOverrideService)
|
||
{
|
||
_logger = logger;
|
||
_options = options.Value;
|
||
_manualOverrideService = manualOverrideService;
|
||
_eventHistory = new ConcurrentQueue<StateTransitionEvent>();
|
||
|
||
Reset();
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public RuntimeStateSnapshotDto GetSnapshot()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
return new RuntimeStateSnapshotDto
|
||
{
|
||
CurrentLayer = _currentLayer,
|
||
TotalLayers = _options.TotalLayers,
|
||
StateText = GetStateDescription(_currentState)
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result MoveToNextLayer()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogDebug("尝试移动到下一层:当前层={CurrentLayer},总层数={TotalLayers}",
|
||
_currentLayer, _options.TotalLayers);
|
||
|
||
// 检查是否可以移动
|
||
if (!CanMoveToNextLayer())
|
||
{
|
||
var reason = GetCannotMoveForwardReason();
|
||
_logger.LogWarning("无法移动到下一层:{Reason}", reason);
|
||
return Result.Fail("CANNOT_MOVE_FORWARD", reason);
|
||
}
|
||
|
||
// 记录状态转换事件
|
||
var previousState = _currentState;
|
||
var previousLayer = _currentLayer;
|
||
|
||
// 执行状态转换
|
||
_currentLayer++;
|
||
_currentState = RuntimeState.Running;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
|
||
// 记录事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.LayerForward,
|
||
PreviousState = previousState,
|
||
NewState = _currentState,
|
||
PreviousLayer = previousLayer,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = _lastTransitionTime,
|
||
Reason = "用户请求移动到下一层"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
_logger.LogInformation("已移动到第 {CurrentLayer} 层,状态:{State}", _currentLayer, _currentState);
|
||
|
||
// 检查是否完成所有层
|
||
if (_currentLayer >= _options.TotalLayers)
|
||
{
|
||
return CompleteProcess();
|
||
}
|
||
|
||
return Result.Success("LAYER_MOVED_FORWARD", $"已移动到第 {_currentLayer} 层");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "移动到下一层失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "MOVE_TO_NEXT_LAYER_FAILED", "移动到下一层失败", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result MoveToPreviousLayer()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogDebug("尝试移动到上一层:当前层={CurrentLayer}", _currentLayer);
|
||
|
||
// 检查是否可以移动
|
||
if (!CanMoveToPreviousLayer())
|
||
{
|
||
var reason = GetCannotMoveBackwardReason();
|
||
_logger.LogWarning("无法移动到上一层:{Reason}", reason);
|
||
return Result.Fail("CANNOT_MOVE_BACKWARD", reason);
|
||
}
|
||
|
||
// 记录状态转换事件
|
||
var previousState = _currentState;
|
||
var previousLayer = _currentLayer;
|
||
|
||
// 执行状态转换
|
||
_currentLayer--;
|
||
_currentState = RuntimeState.Running;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
|
||
// 记录事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.LayerBackward,
|
||
PreviousState = previousState,
|
||
NewState = _currentState,
|
||
PreviousLayer = previousLayer,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = _lastTransitionTime,
|
||
Reason = "用户请求移动到上一层"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
_logger.LogInformation("已移动到第 {CurrentLayer} 层,状态:{State}", _currentLayer, _currentState);
|
||
|
||
return Result.Success("LAYER_MOVED_BACKWARD", $"已移动到第 {_currentLayer} 层");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "移动到上一层失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "MOVE_TO_PREVIOUS_LAYER_FAILED", "移动到上一层失败", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result Pause()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogDebug("尝试暂停状态机");
|
||
|
||
// 检查是否可以暂停
|
||
if (!CanPause())
|
||
{
|
||
var reason = GetCannotPauseReason();
|
||
_logger.LogWarning("无法暂停:{Reason}", reason);
|
||
return Result.Fail("CANNOT_PAUSE", reason);
|
||
}
|
||
|
||
// 记录状态转换事件
|
||
var previousState = _currentState;
|
||
|
||
// 执行状态转换
|
||
_currentState = RuntimeState.Paused;
|
||
_isPaused = true;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
|
||
// 记录事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.Pause,
|
||
PreviousState = previousState,
|
||
NewState = _currentState,
|
||
PreviousLayer = _currentLayer,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = _lastTransitionTime,
|
||
Reason = "用户请求暂停"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
_logger.LogInformation("状态机已暂停,当前层:{CurrentLayer}", _currentLayer);
|
||
|
||
return Result.Success("STATE_MACHINE_PAUSED", "状态机已暂停");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "暂停状态机失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "PAUSE_STATE_MACHINE_FAILED", "暂停状态机失败", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result Resume()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogDebug("尝试恢复状态机");
|
||
|
||
// 检查是否可以恢复
|
||
if (!CanResume())
|
||
{
|
||
var reason = GetCannotResumeReason();
|
||
_logger.LogWarning("无法恢复:{Reason}", reason);
|
||
return Result.Fail("CANNOT_RESUME", reason);
|
||
}
|
||
|
||
// 记录状态转换事件
|
||
var previousState = _currentState;
|
||
|
||
// 执行状态转换
|
||
_currentState = RuntimeState.Running;
|
||
_isPaused = false;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
|
||
// 记录事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.Resume,
|
||
PreviousState = previousState,
|
||
NewState = _currentState,
|
||
PreviousLayer = _currentLayer,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = _lastTransitionTime,
|
||
Reason = "用户请求恢复"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
_logger.LogInformation("状态机已恢复,当前层:{CurrentLayer}", _currentLayer);
|
||
|
||
return Result.Success("STATE_MACHINE_RESUMED", "状态机已恢复");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "恢复状态机失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "RESUME_STATE_MACHINE_FAILED", "恢复状态机失败", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result Stop()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogDebug("尝试停止状态机");
|
||
|
||
// 检查是否可以停止
|
||
if (!CanStop())
|
||
{
|
||
var reason = GetCannotStopReason();
|
||
_logger.LogWarning("无法停止:{Reason}", reason);
|
||
return Result.Fail("CANNOT_STOP", reason);
|
||
}
|
||
|
||
// 记录状态转换事件
|
||
var previousState = _currentState;
|
||
|
||
// 执行状态转换
|
||
_currentState = RuntimeState.Stopped;
|
||
_isStopped = true;
|
||
_isPaused = false;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
|
||
// 记录事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.Stop,
|
||
PreviousState = previousState,
|
||
NewState = _currentState,
|
||
PreviousLayer = _currentLayer,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = _lastTransitionTime,
|
||
Reason = "用户请求停止"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
_logger.LogInformation("状态机已停止,当前层:{CurrentLayer}", _currentLayer);
|
||
|
||
return Result.Success("STATE_MACHINE_STOPPED", "状态机已停止");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "停止状态机失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "STOP_STATE_MACHINE_FAILED", "停止状态机失败", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public void Reset()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("重置状态机");
|
||
|
||
// 记录重置事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.Reset,
|
||
PreviousState = _currentState,
|
||
NewState = RuntimeState.Idle,
|
||
PreviousLayer = _currentLayer,
|
||
NewLayer = 1,
|
||
Timestamp = DateTime.UtcNow,
|
||
Reason = "用户请求重置"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
// 重置状态
|
||
_currentState = RuntimeState.Idle;
|
||
_currentLayer = 1;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
_isPaused = false;
|
||
_isStopped = false;
|
||
|
||
_logger.LogInformation("状态机已重置");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "重置状态机失败");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result<IReadOnlyList<StateTransitionEvent>> GetEventHistory(int maxCount = 100)
|
||
{
|
||
try
|
||
{
|
||
var events = _eventHistory.ToArray();
|
||
var recentEvents = events.Length > maxCount
|
||
? events[^maxCount..]
|
||
: events;
|
||
|
||
return Result<IReadOnlyList<StateTransitionEvent>>.Success(recentEvents.ToList(),
|
||
message: $"获取到 {recentEvents.Length} 个历史事件");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "获取事件历史失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "GET_EVENT_HISTORY_FAILED", "获取事件历史失败", traceId);
|
||
return Result<IReadOnlyList<StateTransitionEvent>>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发产品进入事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerProductEntered()
|
||
{
|
||
return TriggerTransition(StateTrigger.ProductEntered, "产品进入检测区域");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发开始层识别事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerStartLayerIdentification()
|
||
{
|
||
return TriggerTransition(StateTrigger.StartLayerIdentification, "开始层识别");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发层识别完成事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerLayerIdentificationCompleted()
|
||
{
|
||
return TriggerTransition(StateTrigger.LayerIdentificationCompleted, "层识别完成");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发NG检测事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerNgDetected(string reason)
|
||
{
|
||
return TriggerTransition(StateTrigger.NgDetected, reason ?? "检测到NG");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发人工干预事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerManualIntervention(string reason)
|
||
{
|
||
return TriggerTransition(StateTrigger.ManualIntervention, reason ?? "需要人工干预");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发故障事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerFault(string reason)
|
||
{
|
||
return TriggerTransition(StateTrigger.Fault, reason ?? "系统故障");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发故障恢复事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerFaultRecovered(string reason)
|
||
{
|
||
return TriggerTransition(StateTrigger.FaultRecovered, reason ?? "故障已恢复");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发初始化事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerInitialize()
|
||
{
|
||
return TriggerTransition(StateTrigger.Initialize, "系统初始化");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发初始化完成事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerInitialized()
|
||
{
|
||
return TriggerTransition(StateTrigger.Initialized, "系统初始化完成");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发启动事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerStart()
|
||
{
|
||
return TriggerTransition(StateTrigger.Start, "系统启动");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发完成事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerComplete()
|
||
{
|
||
return TriggerTransition(StateTrigger.Complete, "处理完成");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前状态。
|
||
/// </summary>
|
||
public RuntimeState GetCurrentState()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
return _currentState;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前层级。
|
||
/// </summary>
|
||
public int GetCurrentLayer()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
return _currentLayer;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查是否可以执行特定操作。
|
||
/// </summary>
|
||
public bool CanExecuteOperation(StateTrigger trigger)
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
var guardResult = EvaluateTransitionGuard(trigger, _currentState, null);
|
||
return guardResult.IsAllowed;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 完成处理流程。
|
||
/// </summary>
|
||
private Result CompleteProcess()
|
||
{
|
||
_currentState = RuntimeState.Completed;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
|
||
// 记录完成事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.Complete,
|
||
PreviousState = RuntimeState.Running,
|
||
NewState = _currentState,
|
||
PreviousLayer = _currentLayer - 1,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = _lastTransitionTime,
|
||
Reason = "所有层处理完成"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
_logger.LogInformation("处理流程已完成,共处理 {TotalLayers} 层", _options.TotalLayers);
|
||
|
||
return Result.Success("PROCESS_COMPLETED", $"所有 {_options.TotalLayers} 层处理完成");
|
||
}
|
||
|
||
#region 新增守卫条件方法
|
||
|
||
private GuardResult CanInitialize()
|
||
{
|
||
return _currentState == RuntimeState.Uninitialized
|
||
? new GuardResult { IsAllowed = true, Reason = "可以从未初始化状态开始初始化" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许初始化" };
|
||
}
|
||
|
||
private GuardResult CanStart()
|
||
{
|
||
return _currentState == RuntimeState.Idle
|
||
? new GuardResult { IsAllowed = true, Reason = "可以从空闲状态开始运行" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许开始运行" };
|
||
}
|
||
|
||
private GuardResult CanAcceptProduct()
|
||
{
|
||
return _currentState == RuntimeState.Ready
|
||
? new GuardResult { IsAllowed = true, Reason = "就绪状态可以接受产品" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许接受产品" };
|
||
}
|
||
|
||
private GuardResult CanStartLayerIdentification()
|
||
{
|
||
return _currentState == RuntimeState.WaitingProduct || _currentState == RuntimeState.Ready
|
||
? new GuardResult { IsAllowed = true, Reason = "可以开始层识别" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许开始层识别" };
|
||
}
|
||
|
||
private GuardResult CanCompleteLayerIdentification()
|
||
{
|
||
return _currentState == RuntimeState.LayerIdentifying
|
||
? new GuardResult { IsAllowed = true, Reason = "可以完成层识别" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许完成层识别" };
|
||
}
|
||
|
||
private GuardResult CanMoveToNextLayerGuard()
|
||
{
|
||
if (_currentState != RuntimeState.Running)
|
||
return new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许移动到下一层" };
|
||
|
||
if (_currentLayer >= _options.TotalLayers)
|
||
return new GuardResult { IsAllowed = false, Reason = "已到达最后一层" };
|
||
|
||
return new GuardResult { IsAllowed = true, Reason = "可以移动到下一层" };
|
||
}
|
||
|
||
private GuardResult CanMoveToPreviousLayerGuard()
|
||
{
|
||
if (_currentState != RuntimeState.Running)
|
||
return new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许移动到上一层" };
|
||
|
||
if (_currentLayer <= 1)
|
||
return new GuardResult { IsAllowed = false, Reason = "已在第一层" };
|
||
|
||
return new GuardResult { IsAllowed = true, Reason = "可以移动到上一层" };
|
||
}
|
||
|
||
private GuardResult CanPauseGuard()
|
||
{
|
||
return _currentState == RuntimeState.Running && !_isPaused && !_isStopped
|
||
? new GuardResult { IsAllowed = true, Reason = "运行状态可以暂停" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许暂停" };
|
||
}
|
||
|
||
private GuardResult CanResumeGuard()
|
||
{
|
||
return _currentState == RuntimeState.Paused && _isPaused && !_isStopped
|
||
? new GuardResult { IsAllowed = true, Reason = "暂停状态可以恢复" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许恢复" };
|
||
}
|
||
|
||
private GuardResult CanStopGuard()
|
||
{
|
||
return _currentState != RuntimeState.Stopped && _currentState != RuntimeState.Completed && _currentState != RuntimeState.ShuttingDown
|
||
? new GuardResult { IsAllowed = true, Reason = "可以停止" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许停止" };
|
||
}
|
||
|
||
private GuardResult CanHandleNg()
|
||
{
|
||
return (_currentState == RuntimeState.Running || _currentState == RuntimeState.LayerIdentifying) && !_isStopped
|
||
? new GuardResult { IsAllowed = true, Reason = "可以处理NG检测" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许处理NG" };
|
||
}
|
||
|
||
private GuardResult CanAcceptManualIntervention()
|
||
{
|
||
return (_currentState == RuntimeState.NgLocked || _currentState == RuntimeState.Faulted || _currentState == RuntimeState.Error) && !_isStopped
|
||
? new GuardResult { IsAllowed = true, Reason = "可以接受人工干预" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许人工干预" };
|
||
}
|
||
|
||
private GuardResult CanCompleteManualIntervention()
|
||
{
|
||
return _currentState == RuntimeState.ManualIntervening
|
||
? new GuardResult { IsAllowed = true, Reason = "可以完成人工干预" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许完成人工干预" };
|
||
}
|
||
|
||
private GuardResult CanHandleFault()
|
||
{
|
||
return _currentState != RuntimeState.ShuttingDown && _currentState != RuntimeState.Uninitialized
|
||
? new GuardResult { IsAllowed = true, Reason = "可以处理故障" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许处理故障" };
|
||
}
|
||
|
||
private GuardResult CanRecoverFromFault()
|
||
{
|
||
return _currentState == RuntimeState.Faulted
|
||
? new GuardResult { IsAllowed = true, Reason = "可以从故障状态恢复" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许从故障恢复" };
|
||
}
|
||
|
||
private GuardResult CanResetGuard()
|
||
{
|
||
return _currentState != RuntimeState.ShuttingDown && _currentState != RuntimeState.Uninitialized
|
||
? new GuardResult { IsAllowed = true, Reason = "可以重置" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许重置" };
|
||
}
|
||
|
||
private GuardResult CanShutdown()
|
||
{
|
||
return _currentState != RuntimeState.ShuttingDown && _currentState != RuntimeState.Uninitialized
|
||
? new GuardResult { IsAllowed = true, Reason = "可以关闭" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许关闭" };
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 人工干预闭环方法
|
||
|
||
/// <summary>
|
||
/// 执行人工放行操作。
|
||
/// </summary>
|
||
public async Task<Result<StateTransitionEvent>> ExecuteManualReleaseAsync(Guid sessionId, string operatorId, string? reason = null, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("开始执行人工放行操作:会话ID={SessionId},操作员={OperatorId}", sessionId, operatorId);
|
||
|
||
// 1. 权限校验
|
||
var permissionResult = await _manualOverrideService.GetOverridePermissionAsync(sessionId, operatorId, cancellationToken);
|
||
if (!permissionResult.IsSuccess || !permissionResult.Data?.HasPermission == true)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("PERMISSION_DENIED", "人工放行权限校验失败");
|
||
}
|
||
|
||
// 2. 构建人工干预请求
|
||
var overrideRequest = new ManualOverrideRequest
|
||
{
|
||
RequestId = Guid.NewGuid(),
|
||
SessionId = sessionId,
|
||
OperatorId = operatorId,
|
||
OperatorName = operatorId,
|
||
OverrideType = OverrideType.ForcePass,
|
||
TargetStatus = SessionStatus.Completed,
|
||
RequestTimeUtc = DateTime.UtcNow
|
||
};
|
||
|
||
// 3. 条件验证
|
||
var validationResult = await _manualOverrideService.ValidateOverrideConditionsAsync(sessionId, overrideRequest, cancellationToken);
|
||
if (!validationResult.IsSuccess || !validationResult.Data?.IsValid == true)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("VALIDATION_FAILED", "人工放行条件验证失败");
|
||
}
|
||
|
||
// 4. 执行状态迁移
|
||
var transitionResult = TriggerTransition(StateTrigger.ManualInterventionCompleted, reason ?? "人工放行", new { OperatorId = operatorId });
|
||
if (!transitionResult.IsSuccess)
|
||
{
|
||
return transitionResult;
|
||
}
|
||
|
||
// 5. 执行人工干预
|
||
var overrideResult = await _manualOverrideService.ExecuteManualOverrideAsync(overrideRequest, cancellationToken);
|
||
if (!overrideResult.IsSuccess)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("OVERRIDE_FAILED", "人工放行执行失败");
|
||
}
|
||
|
||
// 6. 记录审计日志
|
||
await LogManualOverrideAuditAsync(sessionId, overrideRequest, overrideResult.Data, reason, cancellationToken);
|
||
|
||
_logger.LogInformation("人工放行操作成功完成:会话ID={SessionId},操作员={OperatorId}", sessionId, operatorId);
|
||
return transitionResult;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "执行人工放行操作失败。TraceId: {TraceId}", traceId);
|
||
return Result<StateTransitionEvent>.FailWithTrace("MANUAL_RELEASE_FAILED", "执行人工放行操作失败", traceId);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行人工复位操作。
|
||
/// </summary>
|
||
public async Task<Result<StateTransitionEvent>> ExecuteManualResetAsync(Guid sessionId, string operatorId, string? reason = null, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("开始执行人工复位操作:会话ID={SessionId},操作员={OperatorId}", sessionId, operatorId);
|
||
|
||
// 1. 权限校验
|
||
var permissionResult = await _manualOverrideService.GetOverridePermissionAsync(sessionId, operatorId, cancellationToken);
|
||
if (!permissionResult.IsSuccess || !permissionResult.Data?.HasPermission == true)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("PERMISSION_DENIED", "人工复位权限校验失败");
|
||
}
|
||
|
||
// 2. 构建人工干预请求
|
||
var overrideRequest = new ManualOverrideRequest
|
||
{
|
||
RequestId = Guid.NewGuid(),
|
||
SessionId = sessionId,
|
||
OperatorId = operatorId,
|
||
OperatorName = operatorId,
|
||
OverrideType = OverrideType.ResetAndRelease,
|
||
TargetStatus = SessionStatus.Active,
|
||
RequestTimeUtc = DateTime.UtcNow
|
||
};
|
||
|
||
// 3. 条件验证
|
||
var validationResult = await _manualOverrideService.ValidateOverrideConditionsAsync(sessionId, overrideRequest, cancellationToken);
|
||
if (!validationResult.IsSuccess || !validationResult.Data?.IsValid == true)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("VALIDATION_FAILED", "人工复位条件验证失败");
|
||
}
|
||
|
||
// 4. 执行状态迁移
|
||
var transitionResult = TriggerTransition(StateTrigger.Reset, reason ?? "人工复位", new { OperatorId = operatorId });
|
||
if (!transitionResult.IsSuccess)
|
||
{
|
||
return transitionResult;
|
||
}
|
||
|
||
// 5. 执行人工干预
|
||
var overrideResult = await _manualOverrideService.ExecuteManualOverrideAsync(overrideRequest, cancellationToken);
|
||
if (!overrideResult.IsSuccess)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("OVERRIDE_FAILED", "人工复位执行失败");
|
||
}
|
||
|
||
// 6. 记录审计日志
|
||
await LogManualOverrideAuditAsync(sessionId, overrideRequest, overrideResult.Data, reason, cancellationToken);
|
||
|
||
_logger.LogInformation("人工复位操作成功完成:会话ID={SessionId},操作员={OperatorId}", sessionId, operatorId);
|
||
return transitionResult;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "执行人工复位操作失败。TraceId: {TraceId}", traceId);
|
||
return Result<StateTransitionEvent>.FailWithTrace("MANUAL_RESET_FAILED", "执行人工复位操作失败", traceId);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行人工跳层操作。
|
||
/// </summary>
|
||
public async Task<Result<StateTransitionEvent>> ExecuteManualSkipLayerAsync(Guid sessionId, string operatorId, int targetLayer, string? reason = null, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("开始执行人工跳层操作:会话ID={SessionId},操作员={OperatorId},目标层={TargetLayer}", sessionId, operatorId, targetLayer);
|
||
|
||
// 1. 权限校验
|
||
var permissionResult = await _manualOverrideService.GetOverridePermissionAsync(sessionId, operatorId, cancellationToken);
|
||
if (!permissionResult.IsSuccess || !permissionResult.Data?.HasPermission == true)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("PERMISSION_DENIED", "人工跳层权限校验失败");
|
||
}
|
||
|
||
// 2. 构建人工干预请求
|
||
var overrideRequest = new ManualOverrideRequest
|
||
{
|
||
RequestId = Guid.NewGuid(),
|
||
SessionId = sessionId,
|
||
OperatorId = operatorId,
|
||
OperatorName = operatorId,
|
||
OverrideType = OverrideType.SkipInspection,
|
||
TargetStatus = SessionStatus.Active,
|
||
RequestTimeUtc = DateTime.UtcNow
|
||
};
|
||
|
||
// 3. 条件验证
|
||
var validationResult = await _manualOverrideService.ValidateOverrideConditionsAsync(sessionId, overrideRequest, cancellationToken);
|
||
if (!validationResult.IsSuccess || !validationResult.Data?.IsValid == true)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("VALIDATION_FAILED", "人工跳层条件验证失败");
|
||
}
|
||
|
||
// 4. 执行状态迁移(直接设置目标层)
|
||
StateTransitionEvent transitionEvent;
|
||
lock (_stateLock)
|
||
{
|
||
if (targetLayer < 1 || targetLayer > _options.TotalLayers)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("INVALID_TARGET_LAYER", $"目标层 {targetLayer} 无效");
|
||
}
|
||
|
||
var previousLayer = _currentLayer;
|
||
_currentLayer = targetLayer;
|
||
|
||
transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.LayerForward,
|
||
PreviousState = _currentState,
|
||
NewState = _currentState,
|
||
PreviousLayer = previousLayer,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = DateTime.UtcNow,
|
||
Reason = reason ?? $"人工跳层到第{targetLayer}层",
|
||
Trigger = StateTrigger.ManualIntervention,
|
||
GuardResult = "人工干预跳层"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
_logger.LogInformation("人工跳层成功:{PreviousLayer} -> {NewLayer}", previousLayer, _currentLayer);
|
||
}
|
||
|
||
// 5. 执行人工干预
|
||
var overrideResult = await _manualOverrideService.ExecuteManualOverrideAsync(overrideRequest, cancellationToken);
|
||
|
||
// 6. 记录审计日志
|
||
await LogManualOverrideAuditAsync(sessionId, overrideRequest, overrideResult.Data, reason, cancellationToken);
|
||
|
||
return Result<StateTransitionEvent>.Success(transitionEvent, "人工跳层成功");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "执行人工跳层操作失败。TraceId: {TraceId}", traceId);
|
||
return Result<StateTransitionEvent>.FailWithTrace("MANUAL_SKIP_LAYER_FAILED", "执行人工跳层操作失败", traceId);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 记录人工干预审计日志。
|
||
/// </summary>
|
||
private async Task LogManualOverrideAuditAsync(Guid sessionId, ManualOverrideRequest request, ManualOverrideResult? result, string? reason, CancellationToken cancellationToken)
|
||
{
|
||
try
|
||
{
|
||
// 这里可以通过审计服务记录日志
|
||
// 目前使用日志记录
|
||
_logger.LogInformation(
|
||
"人工干预审计记录:会话ID={SessionId},请求ID={RequestId},操作员={OperatorId},类型={OverrideType},原因={Reason},结果={OverrideResult}",
|
||
sessionId, request.RequestId, request.OperatorId, request.OverrideType, reason, result?.OverrideResult);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "记录人工干预审计日志失败");
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 状态检查方法
|
||
|
||
private bool CanMoveToNextLayer()
|
||
{
|
||
return !_isStopped && !_isPaused && _currentLayer < _options.TotalLayers;
|
||
}
|
||
|
||
private bool CanMoveToPreviousLayer()
|
||
{
|
||
return !_isStopped && !_isPaused && _currentLayer > 1;
|
||
}
|
||
|
||
private bool CanPause()
|
||
{
|
||
return _currentState == RuntimeState.Running && !_isPaused && !_isStopped;
|
||
}
|
||
|
||
private bool CanResume()
|
||
{
|
||
return _currentState == RuntimeState.Paused && _isPaused && !_isStopped;
|
||
}
|
||
|
||
private bool CanReset()
|
||
{
|
||
return true; // 总是可以重置
|
||
}
|
||
|
||
private bool CanStop()
|
||
{
|
||
return _currentState != RuntimeState.Stopped && _currentState != RuntimeState.Completed;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 错误原因获取方法
|
||
|
||
private string GetCannotMoveForwardReason()
|
||
{
|
||
if (_isStopped) return "状态机已停止";
|
||
if (_isPaused) return "状态机已暂停";
|
||
if (_currentLayer >= _options.TotalLayers) return "已到达最后一层";
|
||
return "未知原因";
|
||
}
|
||
|
||
private string GetCannotMoveBackwardReason()
|
||
{
|
||
if (_isStopped) return "状态机已停止";
|
||
if (_isPaused) return "状态机已暂停";
|
||
if (_currentLayer <= 1) return "已在第一层";
|
||
return "未知原因";
|
||
}
|
||
|
||
private string GetCannotPauseReason()
|
||
{
|
||
if (_isPaused) return "状态机已暂停";
|
||
if (_isStopped) return "状态机已停止";
|
||
if (_currentState == RuntimeState.Completed) return "处理已完成";
|
||
if (_currentState != RuntimeState.Running) return "状态机不在运行状态";
|
||
return "未知原因";
|
||
}
|
||
|
||
private string GetCannotResumeReason()
|
||
{
|
||
if (!_isPaused) return "状态机未暂停";
|
||
if (_isStopped) return "状态机已停止";
|
||
return "未知原因";
|
||
}
|
||
|
||
private string GetCannotStopReason()
|
||
{
|
||
if (_isStopped) return "状态机已停止";
|
||
if (_currentState == RuntimeState.Completed) return "处理已完成";
|
||
return "未知原因";
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 状态描述方法
|
||
|
||
private string GetStateDescription(RuntimeState state)
|
||
{
|
||
return state switch
|
||
{
|
||
RuntimeState.Uninitialized => "未初始化",
|
||
RuntimeState.Initializing => "初始化中",
|
||
RuntimeState.Idle => "空闲",
|
||
RuntimeState.Ready => "就绪",
|
||
RuntimeState.WaitingProduct => "等待产品",
|
||
RuntimeState.LayerIdentifying => "层识别中",
|
||
RuntimeState.Running => "运行中",
|
||
RuntimeState.Paused => "已暂停",
|
||
RuntimeState.Stopped => "已停止",
|
||
RuntimeState.Completed => "已完成",
|
||
RuntimeState.NgLocked => "NG锁定",
|
||
RuntimeState.ManualIntervening => "人工干预",
|
||
RuntimeState.Faulted => "故障",
|
||
RuntimeState.Error => "错误",
|
||
RuntimeState.ShuttingDown => "关闭中",
|
||
_ => "未知状态"
|
||
};
|
||
}
|
||
|
||
private string GetDetailedStateDescription(RuntimeState state)
|
||
{
|
||
return state switch
|
||
{
|
||
RuntimeState.Uninitialized => "状态机未初始化,需要执行初始化流程",
|
||
RuntimeState.Initializing => "状态机正在初始化,加载配置和资源",
|
||
RuntimeState.Idle => "状态机处于空闲状态,等待开始处理",
|
||
RuntimeState.Ready => "状态机已就绪,等待产品进入工位",
|
||
RuntimeState.WaitingProduct => "状态机正在等待产品进入检测区域",
|
||
RuntimeState.LayerIdentifying => $"状态机正在识别第 {_currentLayer} 层的部件",
|
||
RuntimeState.Running => $"状态机正在运行,当前处理第 {_currentLayer} 层",
|
||
RuntimeState.Paused => $"状态机已暂停,当前在第 {_currentLayer} 层",
|
||
RuntimeState.Stopped => "状态机已停止,需要重置才能重新开始",
|
||
RuntimeState.Completed => $"所有 {_options.TotalLayers} 层处理已完成",
|
||
RuntimeState.NgLocked => "检测到NG,状态机已锁定,需要人工干预",
|
||
RuntimeState.ManualIntervening => "人工正在进行干预操作",
|
||
RuntimeState.Faulted => "设备发生故障,需要检查并修复",
|
||
RuntimeState.Error => "状态机发生错误,需要检查并重置",
|
||
RuntimeState.ShuttingDown => "状态机正在关闭,清理资源中",
|
||
_ => "状态机处于未知状态"
|
||
};
|
||
}
|
||
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 基于触发器执行状态转换。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerTransition(StateTrigger trigger, string? reason = null, object? parameters = null)
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogDebug("尝试触发状态转换:触发器={Trigger},当前状态={CurrentState}", trigger, _currentState);
|
||
|
||
// 检查转换是否被允许
|
||
var guardResult = EvaluateTransitionGuard(trigger, _currentState, parameters);
|
||
if (!guardResult.IsAllowed)
|
||
{
|
||
_logger.LogWarning("状态转换被守卫条件拒绝:触发器={Trigger},原因={Reason}", trigger, guardResult.Reason);
|
||
return Result<StateTransitionEvent>.Fail("TRANSITION_GUARD_REJECTED", guardResult.Reason);
|
||
}
|
||
|
||
// 获取目标状态
|
||
var targetState = GetTargetState(trigger, _currentState);
|
||
if (targetState == _currentState)
|
||
{
|
||
_logger.LogWarning("状态转换无效果:触发器={Trigger},当前状态={CurrentState}", trigger, _currentState);
|
||
return Result<StateTransitionEvent>.Fail("TRANSITION_NO_EFFECT", "状态转换无效果");
|
||
}
|
||
|
||
// 执行状态转换
|
||
return ExecuteStateTransition(trigger, targetState, reason ?? $"触发器 {trigger} 执行");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "触发状态转换失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "TRIGGER_TRANSITION_FAILED", "触发状态转换失败", traceId);
|
||
return Result<StateTransitionEvent>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 评估状态转换守卫条件。
|
||
/// </summary>
|
||
private GuardResult EvaluateTransitionGuard(StateTrigger trigger, RuntimeState currentState, object? parameters)
|
||
{
|
||
return trigger switch
|
||
{
|
||
StateTrigger.Initialize => CanInitialize(),
|
||
StateTrigger.Start => CanStart(),
|
||
StateTrigger.ProductEntered => CanAcceptProduct(),
|
||
StateTrigger.StartLayerIdentification => CanStartLayerIdentification(),
|
||
StateTrigger.LayerIdentificationCompleted => CanCompleteLayerIdentification(),
|
||
StateTrigger.MoveToNextLayer => CanMoveToNextLayerGuard(),
|
||
StateTrigger.MoveToPreviousLayer => CanMoveToPreviousLayerGuard(),
|
||
StateTrigger.Pause => CanPauseGuard(),
|
||
StateTrigger.Resume => CanResumeGuard(),
|
||
StateTrigger.Stop => CanStopGuard(),
|
||
StateTrigger.NgDetected => CanHandleNg(),
|
||
StateTrigger.ManualIntervention => CanAcceptManualIntervention(),
|
||
StateTrigger.ManualInterventionCompleted => CanCompleteManualIntervention(),
|
||
StateTrigger.Fault => CanHandleFault(),
|
||
StateTrigger.FaultRecovered => CanRecoverFromFault(),
|
||
StateTrigger.Reset => CanResetGuard(),
|
||
StateTrigger.Shutdown => CanShutdown(),
|
||
_ => new GuardResult { IsAllowed = false, Reason = $"未知的触发器: {trigger}" }
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取触发器的目标状态。
|
||
/// </summary>
|
||
private RuntimeState GetTargetState(StateTrigger trigger, RuntimeState currentState)
|
||
{
|
||
return trigger switch
|
||
{
|
||
StateTrigger.Initialize => RuntimeState.Initializing,
|
||
StateTrigger.Initialized => RuntimeState.Idle,
|
||
StateTrigger.Start => RuntimeState.Ready,
|
||
StateTrigger.ProductEntered => RuntimeState.LayerIdentifying,
|
||
StateTrigger.StartLayerIdentification => RuntimeState.LayerIdentifying,
|
||
StateTrigger.LayerIdentificationCompleted => RuntimeState.Running,
|
||
StateTrigger.MoveToNextLayer => RuntimeState.Running,
|
||
StateTrigger.MoveToPreviousLayer => RuntimeState.Running,
|
||
StateTrigger.Pause => RuntimeState.Paused,
|
||
StateTrigger.Resume => RuntimeState.Running,
|
||
StateTrigger.Stop => RuntimeState.Stopped,
|
||
StateTrigger.Complete => RuntimeState.Completed,
|
||
StateTrigger.NgDetected => RuntimeState.NgLocked,
|
||
StateTrigger.ManualIntervention => RuntimeState.ManualIntervening,
|
||
StateTrigger.ManualInterventionCompleted => RuntimeState.Running,
|
||
StateTrigger.Fault => RuntimeState.Faulted,
|
||
StateTrigger.FaultRecovered => RuntimeState.Running,
|
||
StateTrigger.Error => RuntimeState.Error,
|
||
StateTrigger.Reset => RuntimeState.Idle,
|
||
StateTrigger.Shutdown => RuntimeState.ShuttingDown,
|
||
_ => currentState
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行状态转换。
|
||
/// </summary>
|
||
private Result<StateTransitionEvent> ExecuteStateTransition(StateTrigger trigger, RuntimeState targetState, string reason)
|
||
{
|
||
var previousState = _currentState;
|
||
var previousLayer = _currentLayer;
|
||
|
||
// 更新状态
|
||
_currentState = targetState;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
|
||
// 特殊处理某些转换
|
||
if (trigger == StateTrigger.MoveToNextLayer)
|
||
{
|
||
_currentLayer++;
|
||
}
|
||
else if (trigger == StateTrigger.MoveToPreviousLayer)
|
||
{
|
||
_currentLayer--;
|
||
}
|
||
else if (trigger == StateTrigger.Reset)
|
||
{
|
||
_currentLayer = 1;
|
||
_isPaused = false;
|
||
_isStopped = false;
|
||
}
|
||
|
||
// 创建转换事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = GetEventTypeFromTrigger(trigger),
|
||
PreviousState = previousState,
|
||
NewState = targetState,
|
||
PreviousLayer = previousLayer,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = _lastTransitionTime,
|
||
Reason = reason,
|
||
Trigger = trigger,
|
||
GuardResult = "守卫条件通过"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
_logger.LogInformation("状态转换成功:{PreviousState} -> {NewState},触发器={Trigger},原因={Reason}",
|
||
previousState, targetState, trigger, reason);
|
||
|
||
return Result<StateTransitionEvent>.Success(transitionEvent, "状态转换成功");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从触发器获取事件类型。
|
||
/// </summary>
|
||
private StateTransitionEventType GetEventTypeFromTrigger(StateTrigger trigger)
|
||
{
|
||
return trigger switch
|
||
{
|
||
StateTrigger.MoveToNextLayer => StateTransitionEventType.LayerForward,
|
||
StateTrigger.MoveToPreviousLayer => StateTransitionEventType.LayerBackward,
|
||
StateTrigger.Pause => StateTransitionEventType.Pause,
|
||
StateTrigger.Resume => StateTransitionEventType.Resume,
|
||
StateTrigger.Stop => StateTransitionEventType.Stop,
|
||
StateTrigger.Reset => StateTransitionEventType.Reset,
|
||
StateTrigger.Complete => StateTransitionEventType.Complete,
|
||
StateTrigger.NgDetected => StateTransitionEventType.NgLocked,
|
||
StateTrigger.ManualIntervention => StateTransitionEventType.ManualIntervention,
|
||
StateTrigger.Fault => StateTransitionEventType.Fault,
|
||
StateTrigger.Shutdown => StateTransitionEventType.Shutdown,
|
||
_ => StateTransitionEventType.Error
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 释放资源。
|
||
/// </summary>
|
||
public void Dispose()
|
||
{
|
||
try
|
||
{
|
||
_eventHistory.Clear();
|
||
_logger.LogInformation("运行状态机服务已释放");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "释放运行状态机服务资源时发生错误");
|
||
}
|
||
}
|
||
}
|
||
|
||
#region 状态机内部类型
|
||
|
||
/// <summary>
|
||
/// 守卫条件结果。
|
||
/// </summary>
|
||
internal sealed class GuardResult
|
||
{
|
||
public bool IsAllowed { get; init; }
|
||
public string Reason { get; init; } = string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态转换触发器。
|
||
/// </summary>
|
||
public enum StateTrigger
|
||
{
|
||
/// <summary>
|
||
/// 初始化触发器。
|
||
/// </summary>
|
||
Initialize,
|
||
|
||
/// <summary>
|
||
/// 初始化完成触发器。
|
||
/// </summary>
|
||
Initialized,
|
||
|
||
/// <summary>
|
||
/// 启动触发器。
|
||
/// </summary>
|
||
Start,
|
||
|
||
/// <summary>
|
||
/// 产品进入触发器。
|
||
/// </summary>
|
||
ProductEntered,
|
||
|
||
/// <summary>
|
||
/// 开始层识别触发器。
|
||
/// </summary>
|
||
StartLayerIdentification,
|
||
|
||
/// <summary>
|
||
/// 层识别完成触发器。
|
||
/// </summary>
|
||
LayerIdentificationCompleted,
|
||
|
||
/// <summary>
|
||
/// 移动到下一层触发器。
|
||
/// </summary>
|
||
MoveToNextLayer,
|
||
|
||
/// <summary>
|
||
/// 移动到上一层触发器。
|
||
/// </summary>
|
||
MoveToPreviousLayer,
|
||
|
||
/// <summary>
|
||
/// 暂停触发器。
|
||
/// </summary>
|
||
Pause,
|
||
|
||
/// <summary>
|
||
/// 恢复触发器。
|
||
/// </summary>
|
||
Resume,
|
||
|
||
/// <summary>
|
||
/// 停止触发器。
|
||
/// </summary>
|
||
Stop,
|
||
|
||
/// <summary>
|
||
/// 完成触发器。
|
||
/// </summary>
|
||
Complete,
|
||
|
||
/// <summary>
|
||
/// NG检测触发器。
|
||
/// </summary>
|
||
NgDetected,
|
||
|
||
/// <summary>
|
||
/// 人工干预触发器。
|
||
/// </summary>
|
||
ManualIntervention,
|
||
|
||
/// <summary>
|
||
/// 人工干预完成触发器。
|
||
/// </summary>
|
||
ManualInterventionCompleted,
|
||
|
||
/// <summary>
|
||
/// 故障触发器。
|
||
/// </summary>
|
||
Fault,
|
||
|
||
/// <summary>
|
||
/// 故障恢复触发器。
|
||
/// </summary>
|
||
FaultRecovered,
|
||
|
||
/// <summary>
|
||
/// 错误触发器。
|
||
/// </summary>
|
||
Error,
|
||
|
||
/// <summary>
|
||
/// 重置触发器。
|
||
/// </summary>
|
||
Reset,
|
||
|
||
/// <summary>
|
||
/// 关闭触发器。
|
||
/// </summary>
|
||
Shutdown
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态转换事件。
|
||
/// </summary>
|
||
public sealed class StateTransitionEvent
|
||
{
|
||
public StateTransitionEventType EventType { get; init; }
|
||
public RuntimeState PreviousState { get; init; }
|
||
public RuntimeState NewState { get; init; }
|
||
public int PreviousLayer { get; init; }
|
||
public int NewLayer { get; init; }
|
||
public DateTime Timestamp { get; init; }
|
||
public string Reason { get; init; } = string.Empty;
|
||
public StateTrigger Trigger { get; init; }
|
||
public string? GuardResult { get; init; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态转换事件类型。
|
||
/// </summary>
|
||
public enum StateTransitionEventType
|
||
{
|
||
LayerForward,
|
||
LayerBackward,
|
||
Pause,
|
||
Resume,
|
||
Stop,
|
||
Reset,
|
||
Complete,
|
||
Error,
|
||
NgLocked,
|
||
ManualIntervention,
|
||
Fault,
|
||
Shutdown
|
||
}
|
||
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 运行状态枚举。
|
||
/// </summary>
|
||
public enum RuntimeState
|
||
{
|
||
/// <summary>
|
||
/// 未初始化状态。
|
||
/// </summary>
|
||
Uninitialized,
|
||
|
||
/// <summary>
|
||
/// 初始化中状态。
|
||
/// </summary>
|
||
Initializing,
|
||
|
||
/// <summary>
|
||
/// 空闲状态。
|
||
/// </summary>
|
||
Idle,
|
||
|
||
/// <summary>
|
||
/// 就绪状态,等待产品。
|
||
/// </summary>
|
||
Ready,
|
||
|
||
/// <summary>
|
||
/// 等待产品状态。
|
||
/// </summary>
|
||
WaitingProduct,
|
||
|
||
/// <summary>
|
||
/// 层识别中状态。
|
||
/// </summary>
|
||
LayerIdentifying,
|
||
|
||
/// <summary>
|
||
/// 运行中状态。
|
||
/// </summary>
|
||
Running,
|
||
|
||
/// <summary>
|
||
/// 已暂停状态。
|
||
/// </summary>
|
||
Paused,
|
||
|
||
/// <summary>
|
||
/// 已停止状态。
|
||
/// </summary>
|
||
Stopped,
|
||
|
||
/// <summary>
|
||
/// 已完成状态。
|
||
/// </summary>
|
||
Completed,
|
||
|
||
/// <summary>
|
||
/// NG锁定状态。
|
||
/// </summary>
|
||
NgLocked,
|
||
|
||
/// <summary>
|
||
/// 人工干预状态。
|
||
/// </summary>
|
||
ManualIntervening,
|
||
|
||
/// <summary>
|
||
/// 故障状态。
|
||
/// </summary>
|
||
Faulted,
|
||
|
||
/// <summary>
|
||
/// 错误状态。
|
||
/// </summary>
|
||
Error,
|
||
|
||
/// <summary>
|
||
/// 关闭中状态。
|
||
/// </summary>
|
||
ShuttingDown
|
||
}
|
||
#if false
|
||
using Microsoft.Extensions.Logging;
|
||
using Microsoft.Extensions.Options;
|
||
using OrpaonVision.Core.Results;
|
||
using OrpaonVision.Core.ManualOverride;
|
||
using OrpaonVision.SiteApp.Runtime.Contracts;
|
||
using OrpaonVision.SiteApp.Runtime.Options;
|
||
using System.Collections.Concurrent;
|
||
|
||
namespace OrpaonVision.SiteApp.Runtime.Services;
|
||
|
||
/// <summary>
|
||
/// 高级运行时状态机服务。
|
||
/// </summary>
|
||
public sealed class AdvancedRuntimeStateMachineService : IRuntimeStateMachineService, IDisposable
|
||
{
|
||
private readonly ILogger<AdvancedRuntimeStateMachineService> _logger;
|
||
private readonly RuntimeOptions _options;
|
||
private readonly IManualOverrideService _manualOverrideService;
|
||
private readonly ConcurrentQueue<StateTransitionEvent> _eventHistory;
|
||
private readonly object _stateLock = new();
|
||
private RuntimeState _currentState;
|
||
private int _currentLayer;
|
||
private DateTime _lastTransitionTime;
|
||
private bool _isPaused;
|
||
private bool _isStopped;
|
||
|
||
public AdvancedRuntimeStateMachineService(
|
||
ILogger<AdvancedRuntimeStateMachineService> logger,
|
||
IOptions<RuntimeOptions> options,
|
||
IManualOverrideService manualOverrideService)
|
||
{
|
||
_logger = logger;
|
||
_options = options.Value;
|
||
_manualOverrideService = manualOverrideService;
|
||
_eventHistory = new ConcurrentQueue<StateTransitionEvent>();
|
||
|
||
Reset();
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public RuntimeStateSnapshotDto GetSnapshot()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
return new RuntimeStateSnapshotDto
|
||
{
|
||
CurrentLayer = _currentLayer,
|
||
TotalLayers = _options.TotalLayers,
|
||
StateText = GetStateDescription(_currentState)
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result MoveToNextLayer()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogDebug("尝试移动到下一层:当前层={CurrentLayer},总层数={TotalLayers}",
|
||
_currentLayer, _options.TotalLayers);
|
||
|
||
// 检查是否可以移动
|
||
if (!CanMoveToNextLayer())
|
||
{
|
||
var reason = GetCannotMoveForwardReason();
|
||
_logger.LogWarning("无法移动到下一层:{Reason}", reason);
|
||
return Result.Fail("CANNOT_MOVE_FORWARD", reason);
|
||
}
|
||
|
||
// 记录状态转换事件
|
||
var previousState = _currentState;
|
||
var previousLayer = _currentLayer;
|
||
|
||
// 执行状态转换
|
||
_currentLayer++;
|
||
_currentState = RuntimeState.Running;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
|
||
// 记录事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.LayerForward,
|
||
PreviousState = previousState,
|
||
NewState = _currentState,
|
||
PreviousLayer = previousLayer,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = _lastTransitionTime,
|
||
Reason = "用户请求移动到下一层"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
_logger.LogInformation("已移动到第 {CurrentLayer} 层,状态:{State}", _currentLayer, _currentState);
|
||
|
||
// 检查是否完成所有层
|
||
if (_currentLayer >= _options.TotalLayers)
|
||
{
|
||
return CompleteProcess();
|
||
}
|
||
|
||
return Result.Success("LAYER_MOVED_FORWARD", $"已移动到第 {_currentLayer} 层");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "移动到下一层失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "MOVE_TO_NEXT_LAYER_FAILED", "移动到下一层失败", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result MoveToPreviousLayer()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogDebug("尝试移动到上一层:当前层={CurrentLayer}", _currentLayer);
|
||
|
||
// 检查是否可以移动
|
||
if (!CanMoveToPreviousLayer())
|
||
{
|
||
var reason = GetCannotMoveBackwardReason();
|
||
_logger.LogWarning("无法移动到上一层:{Reason}", reason);
|
||
return Result.Fail("CANNOT_MOVE_BACKWARD", reason);
|
||
}
|
||
|
||
// 记录状态转换事件
|
||
var previousState = _currentState;
|
||
var previousLayer = _currentLayer;
|
||
|
||
// 执行状态转换
|
||
_currentLayer--;
|
||
_currentState = RuntimeState.Running;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
|
||
// 记录事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.LayerBackward,
|
||
PreviousState = previousState,
|
||
NewState = _currentState,
|
||
PreviousLayer = previousLayer,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = _lastTransitionTime,
|
||
Reason = "用户请求移动到上一层"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
_logger.LogInformation("已移动到第 {CurrentLayer} 层,状态:{State}", _currentLayer, _currentState);
|
||
|
||
return Result.Success("LAYER_MOVED_BACKWARD", $"已移动到第 {_currentLayer} 层");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "移动到上一层失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "MOVE_TO_PREVIOUS_LAYER_FAILED", "移动到上一层失败", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result Pause()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogDebug("尝试暂停状态机");
|
||
|
||
// 检查是否可以暂停
|
||
if (!CanPause())
|
||
{
|
||
var reason = GetCannotPauseReason();
|
||
_logger.LogWarning("无法暂停:{Reason}", reason);
|
||
return Result.Fail("CANNOT_PAUSE", reason);
|
||
}
|
||
|
||
// 记录状态转换事件
|
||
var previousState = _currentState;
|
||
|
||
// 执行状态转换
|
||
_currentState = RuntimeState.Paused;
|
||
_isPaused = true;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
|
||
// 记录事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.Pause,
|
||
PreviousState = previousState,
|
||
NewState = _currentState,
|
||
PreviousLayer = _currentLayer,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = _lastTransitionTime,
|
||
Reason = "用户请求暂停"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
_logger.LogInformation("状态机已暂停,当前层:{CurrentLayer}", _currentLayer);
|
||
|
||
return Result.Success("STATE_MACHINE_PAUSED", "状态机已暂停");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "暂停状态机失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "PAUSE_STATE_MACHINE_FAILED", "暂停状态机失败", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result Resume()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogDebug("尝试恢复状态机");
|
||
|
||
// 检查是否可以恢复
|
||
if (!CanResume())
|
||
{
|
||
var reason = GetCannotResumeReason();
|
||
_logger.LogWarning("无法恢复:{Reason}", reason);
|
||
return Result.Fail("CANNOT_RESUME", reason);
|
||
}
|
||
|
||
// 记录状态转换事件
|
||
var previousState = _currentState;
|
||
|
||
// 执行状态转换
|
||
_currentState = RuntimeState.Running;
|
||
_isPaused = false;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
|
||
// 记录事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.Resume,
|
||
PreviousState = previousState,
|
||
NewState = _currentState,
|
||
PreviousLayer = _currentLayer,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = _lastTransitionTime,
|
||
Reason = "用户请求恢复"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
_logger.LogInformation("状态机已恢复,当前层:{CurrentLayer}", _currentLayer);
|
||
|
||
return Result.Success("STATE_MACHINE_RESUMED", "状态机已恢复");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "恢复状态机失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "RESUME_STATE_MACHINE_FAILED", "恢复状态机失败", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result Stop()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogDebug("尝试停止状态机");
|
||
|
||
// 检查是否可以停止
|
||
if (!CanStop())
|
||
{
|
||
var reason = GetCannotStopReason();
|
||
_logger.LogWarning("无法停止:{Reason}", reason);
|
||
return Result.Fail("CANNOT_STOP", reason);
|
||
}
|
||
|
||
// 记录状态转换事件
|
||
var previousState = _currentState;
|
||
|
||
// 执行状态转换
|
||
_currentState = RuntimeState.Stopped;
|
||
_isStopped = true;
|
||
_isPaused = false;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
|
||
// 记录事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.Stop,
|
||
PreviousState = previousState,
|
||
NewState = _currentState,
|
||
PreviousLayer = _currentLayer,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = _lastTransitionTime,
|
||
Reason = "用户请求停止"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
_logger.LogInformation("状态机已停止,当前层:{CurrentLayer}", _currentLayer);
|
||
|
||
return Result.Success("STATE_MACHINE_STOPPED", "状态机已停止");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "停止状态机失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "STOP_STATE_MACHINE_FAILED", "停止状态机失败", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public void Reset()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("重置状态机");
|
||
|
||
// 记录重置事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.Reset,
|
||
PreviousState = _currentState,
|
||
NewState = RuntimeState.Idle,
|
||
PreviousLayer = _currentLayer,
|
||
NewLayer = 1,
|
||
Timestamp = DateTime.UtcNow,
|
||
Reason = "用户请求重置"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
// 重置状态
|
||
_currentState = RuntimeState.Idle;
|
||
_currentLayer = 1;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
_isPaused = false;
|
||
_isStopped = false;
|
||
|
||
_logger.LogInformation("状态机已重置");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "重置状态机失败");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result<IReadOnlyList<StateTransitionEvent>> GetEventHistory(int maxCount = 100)
|
||
{
|
||
try
|
||
{
|
||
var events = _eventHistory.ToArray();
|
||
var recentEvents = events.Length > maxCount
|
||
? events[^maxCount..]
|
||
: events;
|
||
|
||
return Result<IReadOnlyList<StateTransitionEvent>>.Success(recentEvents.ToList(),
|
||
message: $"获取到 {recentEvents.Length} 个历史事件");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "获取事件历史失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "GET_EVENT_HISTORY_FAILED", "获取事件历史失败", traceId);
|
||
return Result<IReadOnlyList<StateTransitionEvent>>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发产品进入事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerProductEntered()
|
||
{
|
||
return TriggerTransition(StateTrigger.ProductEntered, "产品进入检测区域");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发开始层识别事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerStartLayerIdentification()
|
||
{
|
||
return TriggerTransition(StateTrigger.StartLayerIdentification, "开始层识别");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发层识别完成事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerLayerIdentificationCompleted()
|
||
{
|
||
return TriggerTransition(StateTrigger.LayerIdentificationCompleted, "层识别完成");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发NG检测事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerNgDetected(string reason)
|
||
{
|
||
return TriggerTransition(StateTrigger.NgDetected, reason ?? "检测到NG");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发人工干预事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerManualIntervention(string reason)
|
||
{
|
||
return TriggerTransition(StateTrigger.ManualIntervention, reason ?? "需要人工干预");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发故障事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerFault(string reason)
|
||
{
|
||
return TriggerTransition(StateTrigger.Fault, reason ?? "系统故障");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发故障恢复事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerFaultRecovered(string reason)
|
||
{
|
||
return TriggerTransition(StateTrigger.FaultRecovered, reason ?? "故障已恢复");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发初始化事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerInitialize()
|
||
{
|
||
return TriggerTransition(StateTrigger.Initialize, "系统初始化");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发初始化完成事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerInitialized()
|
||
{
|
||
return TriggerTransition(StateTrigger.Initialized, "系统初始化完成");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发启动事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerStart()
|
||
{
|
||
return TriggerTransition(StateTrigger.Start, "系统启动");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发完成事件。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerComplete()
|
||
{
|
||
return TriggerTransition(StateTrigger.Complete, "处理完成");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前状态。
|
||
/// </summary>
|
||
public RuntimeState GetCurrentState()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
return _currentState;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前层级。
|
||
/// </summary>
|
||
public int GetCurrentLayer()
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
return _currentLayer;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查是否可以执行特定操作。
|
||
/// </summary>
|
||
public bool CanExecuteOperation(StateTrigger trigger)
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
var guardResult = EvaluateTransitionGuard(trigger, _currentState, null);
|
||
return guardResult.IsAllowed;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 完成处理流程。
|
||
/// </summary>
|
||
private Result CompleteProcess()
|
||
{
|
||
_currentState = RuntimeState.Completed;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
|
||
// 记录完成事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.Complete,
|
||
PreviousState = RuntimeState.Running,
|
||
NewState = _currentState,
|
||
PreviousLayer = _currentLayer - 1,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = _lastTransitionTime,
|
||
Reason = "所有层处理完成"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
_logger.LogInformation("处理流程已完成,共处理 {TotalLayers} 层", _options.TotalLayers);
|
||
|
||
return Result.Success("PROCESS_COMPLETED", $"所有 {_options.TotalLayers} 层处理完成");
|
||
}
|
||
|
||
#region 新增守卫条件方法
|
||
|
||
private GuardResult CanInitialize()
|
||
{
|
||
return _currentState == RuntimeState.Uninitialized
|
||
? new GuardResult { IsAllowed = true, Reason = "可以从未初始化状态开始初始化" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许初始化" };
|
||
}
|
||
|
||
private GuardResult CanStart()
|
||
{
|
||
return _currentState == RuntimeState.Idle
|
||
? new GuardResult { IsAllowed = true, Reason = "可以从空闲状态开始运行" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许开始运行" };
|
||
}
|
||
|
||
private GuardResult CanAcceptProduct()
|
||
{
|
||
return _currentState == RuntimeState.Ready
|
||
? new GuardResult { IsAllowed = true, Reason = "就绪状态可以接受产品" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许接受产品" };
|
||
}
|
||
|
||
private GuardResult CanStartLayerIdentification()
|
||
{
|
||
return _currentState == RuntimeState.WaitingProduct || _currentState == RuntimeState.Ready
|
||
? new GuardResult { IsAllowed = true, Reason = "可以开始层识别" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许开始层识别" };
|
||
}
|
||
|
||
private GuardResult CanCompleteLayerIdentification()
|
||
{
|
||
return _currentState == RuntimeState.LayerIdentifying
|
||
? new GuardResult { IsAllowed = true, Reason = "可以完成层识别" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许完成层识别" };
|
||
}
|
||
|
||
private GuardResult CanMoveToNextLayerGuard()
|
||
{
|
||
if (_currentState != RuntimeState.Running)
|
||
return new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许移动到下一层" };
|
||
|
||
if (_currentLayer >= _options.TotalLayers)
|
||
return new GuardResult { IsAllowed = false, Reason = "已到达最后一层" };
|
||
|
||
return new GuardResult { IsAllowed = true, Reason = "可以移动到下一层" };
|
||
}
|
||
|
||
private GuardResult CanMoveToPreviousLayerGuard()
|
||
{
|
||
if (_currentState != RuntimeState.Running)
|
||
return new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许移动到上一层" };
|
||
|
||
if (_currentLayer <= 1)
|
||
return new GuardResult { IsAllowed = false, Reason = "已在第一层" };
|
||
|
||
return new GuardResult { IsAllowed = true, Reason = "可以移动到上一层" };
|
||
}
|
||
|
||
private GuardResult CanPauseGuard()
|
||
{
|
||
return _currentState == RuntimeState.Running && !_isPaused && !_isStopped
|
||
? new GuardResult { IsAllowed = true, Reason = "运行状态可以暂停" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许暂停" };
|
||
}
|
||
|
||
private GuardResult CanResumeGuard()
|
||
{
|
||
return _currentState == RuntimeState.Paused && _isPaused && !_isStopped
|
||
? new GuardResult { IsAllowed = true, Reason = "暂停状态可以恢复" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许恢复" };
|
||
}
|
||
|
||
private GuardResult CanStopGuard()
|
||
{
|
||
return _currentState != RuntimeState.Stopped && _currentState != RuntimeState.Completed && _currentState != RuntimeState.ShuttingDown
|
||
? new GuardResult { IsAllowed = true, Reason = "可以停止" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许停止" };
|
||
}
|
||
|
||
private GuardResult CanHandleNg()
|
||
{
|
||
return (_currentState == RuntimeState.Running || _currentState == RuntimeState.LayerIdentifying) && !_isStopped
|
||
? new GuardResult { IsAllowed = true, Reason = "可以处理NG检测" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许处理NG" };
|
||
}
|
||
|
||
private GuardResult CanAcceptManualIntervention()
|
||
{
|
||
return (_currentState == RuntimeState.NgLocked || _currentState == RuntimeState.Faulted || _currentState == RuntimeState.Error) && !_isStopped
|
||
? new GuardResult { IsAllowed = true, Reason = "可以接受人工干预" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许人工干预" };
|
||
}
|
||
|
||
private GuardResult CanCompleteManualIntervention()
|
||
{
|
||
return _currentState == RuntimeState.ManualIntervening
|
||
? new GuardResult { IsAllowed = true, Reason = "可以完成人工干预" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许完成人工干预" };
|
||
}
|
||
|
||
private GuardResult CanHandleFault()
|
||
{
|
||
return _currentState != RuntimeState.ShuttingDown && _currentState != RuntimeState.Uninitialized
|
||
? new GuardResult { IsAllowed = true, Reason = "可以处理故障" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许处理故障" };
|
||
}
|
||
|
||
private GuardResult CanRecoverFromFault()
|
||
{
|
||
return _currentState == RuntimeState.Faulted
|
||
? new GuardResult { IsAllowed = true, Reason = "可以从故障状态恢复" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许从故障恢复" };
|
||
}
|
||
|
||
private GuardResult CanResetGuard()
|
||
{
|
||
return _currentState != RuntimeState.ShuttingDown && _currentState != RuntimeState.Uninitialized
|
||
? new GuardResult { IsAllowed = true, Reason = "可以重置" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许重置" };
|
||
}
|
||
|
||
private GuardResult CanShutdown()
|
||
{
|
||
return _currentState != RuntimeState.ShuttingDown && _currentState != RuntimeState.Uninitialized
|
||
? new GuardResult { IsAllowed = true, Reason = "可以关闭" }
|
||
: new GuardResult { IsAllowed = false, Reason = $"当前状态 {_currentState} 不允许关闭" };
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 人工干预闭环方法
|
||
|
||
/// <summary>
|
||
/// 执行人工放行操作。
|
||
/// </summary>
|
||
public async Task<Result<StateTransitionEvent>> ExecuteManualReleaseAsync(Guid sessionId, string operatorId, string? reason = null, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("开始执行人工放行操作:会话ID={SessionId},操作员={OperatorId}", sessionId, operatorId);
|
||
|
||
// 1. 权限校验
|
||
var permissionResult = await _manualOverrideService.GetOverridePermissionAsync(sessionId, operatorId, cancellationToken);
|
||
if (!permissionResult.IsSuccess || !permissionResult.Data?.HasPermission == true)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("PERMISSION_DENIED", "人工放行权限校验失败");
|
||
}
|
||
|
||
// 2. 构建人工干预请求
|
||
var overrideRequest = new ManualOverrideRequest
|
||
{
|
||
RequestId = Guid.NewGuid(),
|
||
SessionId = sessionId,
|
||
OperatorId = operatorId,
|
||
OperatorName = operatorId,
|
||
OverrideType = OverrideType.Release,
|
||
TargetStatus = SessionStatus.Running,
|
||
RequestTimeUtc = DateTime.UtcNow
|
||
};
|
||
|
||
// 3. 条件验证
|
||
var validationResult = await _manualOverrideService.ValidateOverrideConditionsAsync(sessionId, overrideRequest, cancellationToken);
|
||
if (!validationResult.IsSuccess || !validationResult.Data?.IsValid == true)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("VALIDATION_FAILED", "人工放行条件验证失败");
|
||
}
|
||
|
||
// 4. 执行状态迁移
|
||
var transitionResult = TriggerTransition(StateTrigger.ManualInterventionCompleted, reason ?? "人工放行", new { OperatorId = operatorId });
|
||
if (!transitionResult.IsSuccess)
|
||
{
|
||
return transitionResult;
|
||
}
|
||
|
||
// 5. 执行人工干预
|
||
var overrideResult = await _manualOverrideService.ExecuteManualOverrideAsync(overrideRequest, cancellationToken);
|
||
if (!overrideResult.IsSuccess)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("OVERRIDE_FAILED", "人工放行执行失败");
|
||
}
|
||
|
||
// 6. 记录审计日志
|
||
await LogManualOverrideAuditAsync(sessionId, overrideRequest, overrideResult.Data, reason, cancellationToken);
|
||
|
||
_logger.LogInformation("人工放行操作成功完成:会话ID={SessionId},操作员={OperatorId}", sessionId, operatorId);
|
||
return transitionResult;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "执行人工放行操作失败。TraceId: {TraceId}", traceId);
|
||
return Result<StateTransitionEvent>.FailWithTrace("MANUAL_RELEASE_FAILED", "执行人工放行操作失败", traceId);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行人工复位操作。
|
||
/// </summary>
|
||
public async Task<Result<StateTransitionEvent>> ExecuteManualResetAsync(Guid sessionId, string operatorId, string? reason = null, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("开始执行人工复位操作:会话ID={SessionId},操作员={OperatorId}", sessionId, operatorId);
|
||
|
||
// 1. 权限校验
|
||
var permissionResult = await _manualOverrideService.GetOverridePermissionAsync(sessionId, operatorId, cancellationToken);
|
||
if (!permissionResult.IsSuccess || !permissionResult.Data?.HasPermission == true)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("PERMISSION_DENIED", "人工复位权限校验失败");
|
||
}
|
||
|
||
// 2. 构建人工干预请求
|
||
var overrideRequest = new ManualOverrideRequest
|
||
{
|
||
RequestId = Guid.NewGuid(),
|
||
SessionId = sessionId,
|
||
OperatorId = operatorId,
|
||
OperatorName = operatorId,
|
||
OverrideType = OverrideType.Reset,
|
||
TargetStatus = SessionStatus.Ready,
|
||
RequestTimeUtc = DateTime.UtcNow
|
||
};
|
||
|
||
// 3. 条件验证
|
||
var validationResult = await _manualOverrideService.ValidateOverrideConditionsAsync(sessionId, overrideRequest, cancellationToken);
|
||
if (!validationResult.IsSuccess || !validationResult.Data?.IsValid == true)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("VALIDATION_FAILED", "人工复位条件验证失败");
|
||
}
|
||
|
||
// 4. 执行状态迁移
|
||
var transitionResult = TriggerTransition(StateTrigger.Reset, reason ?? "人工复位", new { OperatorId = operatorId });
|
||
if (!transitionResult.IsSuccess)
|
||
{
|
||
return transitionResult;
|
||
}
|
||
|
||
// 5. 执行人工干预
|
||
var overrideResult = await _manualOverrideService.ExecuteManualOverrideAsync(overrideRequest, cancellationToken);
|
||
if (!overrideResult.IsSuccess)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("OVERRIDE_FAILED", "人工复位执行失败");
|
||
}
|
||
|
||
// 6. 记录审计日志
|
||
await LogManualOverrideAuditAsync(sessionId, overrideRequest, overrideResult.Data, reason, cancellationToken);
|
||
|
||
_logger.LogInformation("人工复位操作成功完成:会话ID={SessionId},操作员={OperatorId}", sessionId, operatorId);
|
||
return transitionResult;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "执行人工复位操作失败。TraceId: {TraceId}", traceId);
|
||
return Result<StateTransitionEvent>.FailWithTrace("MANUAL_RESET_FAILED", "执行人工复位操作失败", traceId);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行人工跳层操作。
|
||
/// </summary>
|
||
public async Task<Result<StateTransitionEvent>> ExecuteManualSkipLayerAsync(Guid sessionId, string operatorId, int targetLayer, string? reason = null, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("开始执行人工跳层操作:会话ID={SessionId},操作员={OperatorId},目标层={TargetLayer}", sessionId, operatorId, targetLayer);
|
||
|
||
// 1. 权限校验
|
||
var permissionResult = await _manualOverrideService.GetOverridePermissionAsync(sessionId, operatorId, cancellationToken);
|
||
if (!permissionResult.IsSuccess || !permissionResult.Data?.HasPermission == true)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("PERMISSION_DENIED", "人工跳层权限校验失败");
|
||
}
|
||
|
||
// 2. 构建人工干预请求
|
||
var overrideRequest = new ManualOverrideRequest
|
||
{
|
||
RequestId = Guid.NewGuid(),
|
||
SessionId = sessionId,
|
||
OperatorId = operatorId,
|
||
OperatorName = operatorId,
|
||
OverrideType = OverrideType.SkipLayer,
|
||
TargetStatus = SessionStatus.Running,
|
||
RequestTimeUtc = DateTime.UtcNow
|
||
};
|
||
|
||
// 3. 条件验证
|
||
var validationResult = await _manualOverrideService.ValidateOverrideConditionsAsync(sessionId, overrideRequest, cancellationToken);
|
||
if (!validationResult.IsSuccess || !validationResult.Data?.IsValid == true)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("VALIDATION_FAILED", "人工跳层条件验证失败");
|
||
}
|
||
|
||
// 4. 执行状态迁移(直接设置目标层)
|
||
lock (_stateLock)
|
||
{
|
||
if (targetLayer < 1 || targetLayer > _options.TotalLayers)
|
||
{
|
||
return Result<StateTransitionEvent>.Fail("INVALID_TARGET_LAYER", $"目标层 {targetLayer} 无效");
|
||
}
|
||
|
||
var previousLayer = _currentLayer;
|
||
_currentLayer = targetLayer;
|
||
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = StateTransitionEventType.LayerForward,
|
||
PreviousState = _currentState,
|
||
NewState = _currentState,
|
||
PreviousLayer = previousLayer,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = DateTime.UtcNow,
|
||
Reason = reason ?? $"人工跳层到第{targetLayer}层",
|
||
Trigger = StateTrigger.ManualIntervention,
|
||
GuardResult = "人工干预跳层"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
_logger.LogInformation("人工跳层成功:{PreviousLayer} -> {NewLayer}", previousLayer, _currentLayer);
|
||
|
||
// 5. 执行人工干预
|
||
var overrideResult = await _manualOverrideService.ExecuteManualOverrideAsync(overrideRequest, cancellationToken);
|
||
|
||
// 6. 记录审计日志
|
||
await LogManualOverrideAuditAsync(sessionId, overrideRequest, overrideResult.Data, reason, cancellationToken);
|
||
|
||
return Result<StateTransitionEvent>.Success(transitionEvent, "人工跳层成功");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "执行人工跳层操作失败。TraceId: {TraceId}", traceId);
|
||
return Result<StateTransitionEvent>.FailWithTrace("MANUAL_SKIP_LAYER_FAILED", "执行人工跳层操作失败", traceId);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 记录人工干预审计日志。
|
||
/// </summary>
|
||
private async Task LogManualOverrideAuditAsync(Guid sessionId, ManualOverrideRequest request, ManualOverrideResult? result, string? reason, CancellationToken cancellationToken)
|
||
{
|
||
try
|
||
{
|
||
// 这里可以通过审计服务记录日志
|
||
// 目前使用日志记录
|
||
_logger.LogInformation(
|
||
"人工干预审计记录:会话ID={SessionId},请求ID={RequestId},操作员={OperatorId},类型={OverrideType},原因={Reason},结果={OverrideResult}",
|
||
sessionId, request.RequestId, request.OperatorId, request.OverrideType, reason, result?.OverrideResult);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "记录人工干预审计日志失败");
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 状态检查方法
|
||
|
||
private bool CanMoveToNextLayer()
|
||
{
|
||
return !_isStopped && !_isPaused && _currentLayer < _options.TotalLayers;
|
||
}
|
||
|
||
private bool CanMoveToPreviousLayer()
|
||
{
|
||
return !_isStopped && !_isPaused && _currentLayer > 1;
|
||
}
|
||
|
||
private bool CanPause()
|
||
{
|
||
return _currentState == RuntimeState.Running && !_isPaused && !_isStopped;
|
||
}
|
||
|
||
private bool CanResume()
|
||
{
|
||
return _currentState == RuntimeState.Paused && _isPaused && !_isStopped;
|
||
}
|
||
|
||
private bool CanReset()
|
||
{
|
||
return true; // 总是可以重置
|
||
}
|
||
|
||
private bool CanStop()
|
||
{
|
||
return _currentState != RuntimeState.Stopped && _currentState != RuntimeState.Completed;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 错误原因获取方法
|
||
|
||
private string GetCannotMoveForwardReason()
|
||
{
|
||
if (_isStopped) return "状态机已停止";
|
||
if (_isPaused) return "状态机已暂停";
|
||
if (_currentLayer >= _options.TotalLayers) return "已到达最后一层";
|
||
return "未知原因";
|
||
}
|
||
|
||
private string GetCannotMoveBackwardReason()
|
||
{
|
||
if (_isStopped) return "状态机已停止";
|
||
if (_isPaused) return "状态机已暂停";
|
||
if (_currentLayer <= 1) return "已在第一层";
|
||
return "未知原因";
|
||
}
|
||
|
||
private string GetCannotPauseReason()
|
||
{
|
||
if (_isPaused) return "状态机已暂停";
|
||
if (_isStopped) return "状态机已停止";
|
||
if (_currentState == RuntimeState.Completed) return "处理已完成";
|
||
if (_currentState != RuntimeState.Running) return "状态机不在运行状态";
|
||
return "未知原因";
|
||
}
|
||
|
||
private string GetCannotResumeReason()
|
||
{
|
||
if (!_isPaused) return "状态机未暂停";
|
||
if (_isStopped) return "状态机已停止";
|
||
return "未知原因";
|
||
}
|
||
|
||
private string GetCannotStopReason()
|
||
{
|
||
if (_isStopped) return "状态机已停止";
|
||
if (_currentState == RuntimeState.Completed) return "处理已完成";
|
||
return "未知原因";
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 状态描述方法
|
||
|
||
private string GetStateDescription(RuntimeState state)
|
||
{
|
||
return state switch
|
||
{
|
||
RuntimeState.Uninitialized => "未初始化",
|
||
RuntimeState.Initializing => "初始化中",
|
||
RuntimeState.Idle => "空闲",
|
||
RuntimeState.Ready => "就绪",
|
||
RuntimeState.WaitingProduct => "等待产品",
|
||
RuntimeState.LayerIdentifying => "层识别中",
|
||
RuntimeState.Running => "运行中",
|
||
RuntimeState.Paused => "已暂停",
|
||
RuntimeState.Stopped => "已停止",
|
||
RuntimeState.Completed => "已完成",
|
||
RuntimeState.NgLocked => "NG锁定",
|
||
RuntimeState.ManualIntervening => "人工干预",
|
||
RuntimeState.Faulted => "故障",
|
||
RuntimeState.Error => "错误",
|
||
RuntimeState.ShuttingDown => "关闭中",
|
||
_ => "未知状态"
|
||
};
|
||
}
|
||
|
||
private string GetDetailedStateDescription(RuntimeState state)
|
||
{
|
||
return state switch
|
||
{
|
||
RuntimeState.Uninitialized => "状态机未初始化,需要执行初始化流程",
|
||
RuntimeState.Initializing => "状态机正在初始化,加载配置和资源",
|
||
RuntimeState.Idle => "状态机处于空闲状态,等待开始处理",
|
||
RuntimeState.Ready => "状态机已就绪,等待产品进入工位",
|
||
RuntimeState.WaitingProduct => "状态机正在等待产品进入检测区域",
|
||
RuntimeState.LayerIdentifying => $"状态机正在识别第 {_currentLayer} 层的部件",
|
||
RuntimeState.Running => $"状态机正在运行,当前处理第 {_currentLayer} 层",
|
||
RuntimeState.Paused => $"状态机已暂停,当前在第 {_currentLayer} 层",
|
||
RuntimeState.Stopped => "状态机已停止,需要重置才能重新开始",
|
||
RuntimeState.Completed => $"所有 {_options.TotalLayers} 层处理已完成",
|
||
RuntimeState.NgLocked => "检测到NG,状态机已锁定,需要人工干预",
|
||
RuntimeState.ManualIntervening => "人工正在进行干预操作",
|
||
RuntimeState.Faulted => "设备发生故障,需要检查并修复",
|
||
RuntimeState.Error => "状态机发生错误,需要检查并重置",
|
||
RuntimeState.ShuttingDown => "状态机正在关闭,清理资源中",
|
||
_ => "状态机处于未知状态"
|
||
};
|
||
}
|
||
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 基于触发器执行状态转换。
|
||
/// </summary>
|
||
public Result<StateTransitionEvent> TriggerTransition(StateTrigger trigger, string? reason = null, object? parameters = null)
|
||
{
|
||
lock (_stateLock)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogDebug("尝试触发状态转换:触发器={Trigger},当前状态={CurrentState}", trigger, _currentState);
|
||
|
||
// 检查转换是否被允许
|
||
var guardResult = EvaluateTransitionGuard(trigger, _currentState, parameters);
|
||
if (!guardResult.IsAllowed)
|
||
{
|
||
_logger.LogWarning("状态转换被守卫条件拒绝:触发器={Trigger},原因={Reason}", trigger, guardResult.Reason);
|
||
return Result<StateTransitionEvent>.Fail("TRANSITION_GUARD_REJECTED", guardResult.Reason);
|
||
}
|
||
|
||
// 获取目标状态
|
||
var targetState = GetTargetState(trigger, _currentState);
|
||
if (targetState == _currentState)
|
||
{
|
||
_logger.LogWarning("状态转换无效果:触发器={Trigger},当前状态={CurrentState}", trigger, _currentState);
|
||
return Result<StateTransitionEvent>.Fail("TRANSITION_NO_EFFECT", "状态转换无效果");
|
||
}
|
||
|
||
// 执行状态转换
|
||
return ExecuteStateTransition(trigger, targetState, reason ?? $"触发器 {trigger} 执行");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "触发状态转换失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "TRIGGER_TRANSITION_FAILED", "触发状态转换失败", traceId);
|
||
return Result<StateTransitionEvent>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 评估状态转换守卫条件。
|
||
/// </summary>
|
||
private GuardResult EvaluateTransitionGuard(StateTrigger trigger, RuntimeState currentState, object? parameters)
|
||
{
|
||
return trigger switch
|
||
{
|
||
StateTrigger.Initialize => CanInitialize(),
|
||
StateTrigger.Start => CanStart(),
|
||
StateTrigger.ProductEntered => CanAcceptProduct(),
|
||
StateTrigger.StartLayerIdentification => CanStartLayerIdentification(),
|
||
StateTrigger.LayerIdentificationCompleted => CanCompleteLayerIdentification(),
|
||
StateTrigger.MoveToNextLayer => CanMoveToNextLayerGuard(),
|
||
StateTrigger.MoveToPreviousLayer => CanMoveToPreviousLayerGuard(),
|
||
StateTrigger.Pause => CanPauseGuard(),
|
||
StateTrigger.Resume => CanResumeGuard(),
|
||
StateTrigger.Stop => CanStopGuard(),
|
||
StateTrigger.NgDetected => CanHandleNg(),
|
||
StateTrigger.ManualIntervention => CanAcceptManualIntervention(),
|
||
StateTrigger.ManualInterventionCompleted => CanCompleteManualIntervention(),
|
||
StateTrigger.Fault => CanHandleFault(),
|
||
StateTrigger.FaultRecovered => CanRecoverFromFault(),
|
||
StateTrigger.Reset => CanResetGuard(),
|
||
StateTrigger.Shutdown => CanShutdown(),
|
||
_ => new GuardResult { IsAllowed = false, Reason = $"未知的触发器: {trigger}" }
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取触发器的目标状态。
|
||
/// </summary>
|
||
private RuntimeState GetTargetState(StateTrigger trigger, RuntimeState currentState)
|
||
{
|
||
return trigger switch
|
||
{
|
||
StateTrigger.Initialize => RuntimeState.Initializing,
|
||
StateTrigger.Initialized => RuntimeState.Idle,
|
||
StateTrigger.Start => RuntimeState.Ready,
|
||
StateTrigger.ProductEntered => RuntimeState.LayerIdentifying,
|
||
StateTrigger.StartLayerIdentification => RuntimeState.LayerIdentifying,
|
||
StateTrigger.LayerIdentificationCompleted => RuntimeState.Running,
|
||
StateTrigger.MoveToNextLayer => RuntimeState.Running,
|
||
StateTrigger.MoveToPreviousLayer => RuntimeState.Running,
|
||
StateTrigger.Pause => RuntimeState.Paused,
|
||
StateTrigger.Resume => RuntimeState.Running,
|
||
StateTrigger.Stop => RuntimeState.Stopped,
|
||
StateTrigger.Complete => RuntimeState.Completed,
|
||
StateTrigger.NgDetected => RuntimeState.NgLocked,
|
||
StateTrigger.ManualIntervention => RuntimeState.ManualIntervening,
|
||
StateTrigger.ManualInterventionCompleted => RuntimeState.Running,
|
||
StateTrigger.Fault => RuntimeState.Faulted,
|
||
StateTrigger.FaultRecovered => RuntimeState.Running,
|
||
StateTrigger.Error => RuntimeState.Error,
|
||
StateTrigger.Reset => RuntimeState.Idle,
|
||
StateTrigger.Shutdown => RuntimeState.ShuttingDown,
|
||
_ => currentState
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行状态转换。
|
||
/// </summary>
|
||
private Result<StateTransitionEvent> ExecuteStateTransition(StateTrigger trigger, RuntimeState targetState, string reason)
|
||
{
|
||
var previousState = _currentState;
|
||
var previousLayer = _currentLayer;
|
||
|
||
// 更新状态
|
||
_currentState = targetState;
|
||
_lastTransitionTime = DateTime.UtcNow;
|
||
|
||
// 特殊处理某些转换
|
||
if (trigger == StateTrigger.MoveToNextLayer)
|
||
{
|
||
_currentLayer++;
|
||
}
|
||
else if (trigger == StateTrigger.MoveToPreviousLayer)
|
||
{
|
||
_currentLayer--;
|
||
}
|
||
else if (trigger == StateTrigger.Reset)
|
||
{
|
||
_currentLayer = 1;
|
||
_isPaused = false;
|
||
_isStopped = false;
|
||
}
|
||
|
||
// 创建转换事件
|
||
var transitionEvent = new StateTransitionEvent
|
||
{
|
||
EventType = GetEventTypeFromTrigger(trigger),
|
||
PreviousState = previousState,
|
||
NewState = targetState,
|
||
PreviousLayer = previousLayer,
|
||
NewLayer = _currentLayer,
|
||
Timestamp = _lastTransitionTime,
|
||
Reason = reason,
|
||
Trigger = trigger,
|
||
GuardResult = "守卫条件通过"
|
||
};
|
||
|
||
_eventHistory.Enqueue(transitionEvent);
|
||
|
||
_logger.LogInformation("状态转换成功:{PreviousState} -> {NewState},触发器={Trigger},原因={Reason}",
|
||
previousState, targetState, trigger, reason);
|
||
|
||
return Result<StateTransitionEvent>.Success(transitionEvent, "状态转换成功");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从触发器获取事件类型。
|
||
/// </summary>
|
||
private StateTransitionEventType GetEventTypeFromTrigger(StateTrigger trigger)
|
||
{
|
||
return trigger switch
|
||
{
|
||
StateTrigger.MoveToNextLayer => StateTransitionEventType.LayerForward,
|
||
StateTrigger.MoveToPreviousLayer => StateTransitionEventType.LayerBackward,
|
||
StateTrigger.Pause => StateTransitionEventType.Pause,
|
||
StateTrigger.Resume => StateTransitionEventType.Resume,
|
||
StateTrigger.Stop => StateTransitionEventType.Stop,
|
||
StateTrigger.Reset => StateTransitionEventType.Reset,
|
||
StateTrigger.Complete => StateTransitionEventType.Complete,
|
||
StateTrigger.NgDetected => StateTransitionEventType.NgLocked,
|
||
StateTrigger.ManualIntervention => StateTransitionEventType.ManualIntervention,
|
||
StateTrigger.Fault => StateTransitionEventType.Fault,
|
||
StateTrigger.Shutdown => StateTransitionEventType.Shutdown,
|
||
_ => StateTransitionEventType.Error
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 释放资源。
|
||
/// </summary>
|
||
public void Dispose()
|
||
{
|
||
try
|
||
{
|
||
_eventHistory.Clear();
|
||
_logger.LogInformation("运行状态机服务已释放");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "释放运行状态机服务资源时发生错误");
|
||
}
|
||
}
|
||
}
|
||
|
||
#region 状态机内部类型
|
||
|
||
/// <summary>
|
||
/// 守卫条件结果。
|
||
/// </summary>
|
||
internal sealed class GuardResult
|
||
{
|
||
public bool IsAllowed { get; init; }
|
||
public string Reason { get; init; } = string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态转换触发器。
|
||
/// </summary>
|
||
public enum StateTrigger
|
||
{
|
||
/// <summary>
|
||
/// 初始化触发器。
|
||
/// </summary>
|
||
Initialize,
|
||
|
||
/// <summary>
|
||
/// 初始化完成触发器。
|
||
/// </summary>
|
||
Initialized,
|
||
|
||
/// <summary>
|
||
/// 启动触发器。
|
||
/// </summary>
|
||
Start,
|
||
|
||
/// <summary>
|
||
/// 产品进入触发器。
|
||
/// </summary>
|
||
ProductEntered,
|
||
|
||
/// <summary>
|
||
/// 开始层识别触发器。
|
||
/// </summary>
|
||
StartLayerIdentification,
|
||
|
||
/// <summary>
|
||
/// 层识别完成触发器。
|
||
/// </summary>
|
||
LayerIdentificationCompleted,
|
||
|
||
/// <summary>
|
||
/// 移动到下一层触发器。
|
||
/// </summary>
|
||
MoveToNextLayer,
|
||
|
||
/// <summary>
|
||
/// 移动到上一层触发器。
|
||
/// </summary>
|
||
MoveToPreviousLayer,
|
||
|
||
/// <summary>
|
||
/// 暂停触发器。
|
||
/// </summary>
|
||
Pause,
|
||
|
||
/// <summary>
|
||
/// 恢复触发器。
|
||
/// </summary>
|
||
Resume,
|
||
|
||
/// <summary>
|
||
/// 停止触发器。
|
||
/// </summary>
|
||
Stop,
|
||
|
||
/// <summary>
|
||
/// 完成触发器。
|
||
/// </summary>
|
||
Complete,
|
||
|
||
/// <summary>
|
||
/// NG检测触发器。
|
||
/// </summary>
|
||
NgDetected,
|
||
|
||
/// <summary>
|
||
/// 人工干预触发器。
|
||
/// </summary>
|
||
ManualIntervention,
|
||
|
||
/// <summary>
|
||
/// 人工干预完成触发器。
|
||
/// </summary>
|
||
ManualInterventionCompleted,
|
||
|
||
/// <summary>
|
||
/// 故障触发器。
|
||
/// </summary>
|
||
Fault,
|
||
|
||
/// <summary>
|
||
/// 故障恢复触发器。
|
||
/// </summary>
|
||
FaultRecovered,
|
||
|
||
/// <summary>
|
||
/// 错误触发器。
|
||
/// </summary>
|
||
Error,
|
||
|
||
/// <summary>
|
||
/// 重置触发器。
|
||
/// </summary>
|
||
Reset,
|
||
|
||
/// <summary>
|
||
/// 关闭触发器。
|
||
/// </summary>
|
||
Shutdown
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态转换事件。
|
||
/// </summary>
|
||
public sealed class StateTransitionEvent
|
||
{
|
||
public StateTransitionEventType EventType { get; init; }
|
||
public RuntimeState PreviousState { get; init; }
|
||
public RuntimeState NewState { get; init; }
|
||
public int PreviousLayer { get; init; }
|
||
public int NewLayer { get; init; }
|
||
public DateTime Timestamp { get; init; }
|
||
public string Reason { get; init; } = string.Empty;
|
||
public StateTrigger Trigger { get; init; }
|
||
public string? GuardResult { get; init; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态转换事件类型。
|
||
/// </summary>
|
||
public enum StateTransitionEventType
|
||
{
|
||
LayerForward,
|
||
LayerBackward,
|
||
Pause,
|
||
Resume,
|
||
Stop,
|
||
Reset,
|
||
Complete,
|
||
Error,
|
||
NgLocked,
|
||
ManualIntervention,
|
||
Fault,
|
||
Shutdown
|
||
}
|
||
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 运行状态枚举。
|
||
/// </summary>
|
||
public enum RuntimeState
|
||
{
|
||
/// <summary>
|
||
/// 未初始化状态。
|
||
/// </summary>
|
||
Uninitialized,
|
||
|
||
/// <summary>
|
||
/// 初始化中状态。
|
||
/// </summary>
|
||
Initializing,
|
||
|
||
/// <summary>
|
||
/// 空闲状态。
|
||
/// </summary>
|
||
Idle,
|
||
|
||
/// <summary>
|
||
/// 就绪状态,等待产品。
|
||
/// </summary>
|
||
Ready,
|
||
|
||
/// <summary>
|
||
/// 等待产品状态。
|
||
/// </summary>
|
||
WaitingProduct,
|
||
|
||
/// <summary>
|
||
/// 层识别中状态。
|
||
/// </summary>
|
||
LayerIdentifying,
|
||
|
||
/// <summary>
|
||
/// 运行中状态。
|
||
/// </summary>
|
||
Running,
|
||
|
||
/// <summary>
|
||
/// 已暂停状态。
|
||
/// </summary>
|
||
Paused,
|
||
|
||
/// <summary>
|
||
/// 已停止状态。
|
||
/// </summary>
|
||
Stopped,
|
||
|
||
/// <summary>
|
||
/// 已完成状态。
|
||
/// </summary>
|
||
Completed,
|
||
|
||
/// <summary>
|
||
/// NG锁定状态。
|
||
/// </summary>
|
||
NgLocked,
|
||
|
||
/// <summary>
|
||
/// 人工干预状态。
|
||
/// </summary>
|
||
ManualIntervening,
|
||
|
||
/// <summary>
|
||
/// 故障状态。
|
||
/// </summary>
|
||
Faulted,
|
||
|
||
/// <summary>
|
||
/// 错误状态。
|
||
/// </summary>
|
||
Error,
|
||
|
||
/// <summary>
|
||
/// 关闭中状态。
|
||
/// </summary>
|
||
ShuttingDown
|
||
}
|
||
#endif
|