using OrpaonVision.SiteApp.Runtime.Services; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows.Media; namespace OrpaonVision.SiteApp.ViewModels { /// /// 运行端主窗口 ViewModel。 /// public sealed class MainWindowViewModel : INotifyPropertyChanged { private readonly ICameraService _cameraService; private readonly IInferenceService _inferenceService; private readonly IRuleEngineService _ruleEngineService; private readonly IRuntimeStateMachineService _runtimeStateMachineService; private string _statusText = "准备就绪。"; private Brush _statusBrush = Brushes.DarkGreen; private string _layerText = "1/1"; private string _inferenceText = "-"; private string _decisionText = "-"; /// /// 构造函数。 /// public MainWindowViewModel( ICameraService cameraService, IInferenceService inferenceService, IRuleEngineService ruleEngineService, IRuntimeStateMachineService runtimeStateMachineService) { _cameraService = cameraService; _inferenceService = inferenceService; _ruleEngineService = ruleEngineService; _runtimeStateMachineService = runtimeStateMachineService; RefreshSnapshot(); } /// /// 状态文本。 /// public string StatusText { get => _statusText; private set => SetProperty(ref _statusText, value); } /// /// 状态颜色。 /// public Brush StatusBrush { get => _statusBrush; private set => SetProperty(ref _statusBrush, value); } /// /// 当前层显示文本。 /// public string LayerText { get => _layerText; private set => SetProperty(ref _layerText, value); } /// /// 最近一次推理结果。 /// public string InferenceText { get => _inferenceText; private set => SetProperty(ref _inferenceText, value); } /// /// 最近一次规则判定结果。 /// public string DecisionText { get => _decisionText; private set => SetProperty(ref _decisionText, value); } /// /// 执行一轮采集-推理-规则判定。 /// public void RunOneCycle() { var snapshot = _runtimeStateMachineService.GetSnapshot(); var captureResult = _cameraService.CaptureFrame(); if (!captureResult.Succeeded || captureResult.Data is null) { SetError("相机采图失败。", captureResult.Message); return; } var predictResult = _inferenceService.Predict(captureResult.Data); if (!predictResult.Succeeded || predictResult.Data is null) { SetError("模型推理失败。", predictResult.Message); return; } var inference = predictResult.Data; InferenceText = $"{inference.Label} (置信度: {inference.Confidence:P0})"; var decisionResult = _ruleEngineService.Evaluate(snapshot.CurrentLayer, inference); if (!decisionResult.Succeeded || decisionResult.Data is null) { SetError("规则判定失败。", decisionResult.Message); return; } var decision = decisionResult.Data; DecisionText = $"{decision.Code} - {decision.Message}"; StatusBrush = decision.IsPass ? Brushes.DarkGreen : Brushes.OrangeRed; StatusText = decision.IsPass ? "当前层判定通过。" : "当前层判定 NG,请人工复核。"; } /// /// 推进到下一层。 /// public void MoveToNextLayer() { var moveResult = _runtimeStateMachineService.MoveToNextLayer(); if (!moveResult.Succeeded) { SetError("状态机切层失败。", moveResult.Message); return; } RefreshSnapshot(); StatusBrush = Brushes.DarkGreen; StatusText = moveResult.Message; } /// /// 重置运行状态。 /// public void ResetRuntime() { _runtimeStateMachineService.Reset(); InferenceText = "-"; DecisionText = "-"; RefreshSnapshot(); StatusBrush = Brushes.DarkGreen; StatusText = "运行状态已重置。"; } /// public event PropertyChangedEventHandler? PropertyChanged; private void RefreshSnapshot() { var snapshot = _runtimeStateMachineService.GetSnapshot(); LayerText = $"{snapshot.CurrentLayer}/{snapshot.TotalLayers}"; } private void SetError(string title, string message) { StatusBrush = Brushes.OrangeRed; StatusText = $"{title} {message}"; } private void SetProperty(ref T field, T value, [CallerMemberName] string? propertyName = null) { if (EqualityComparer.Default.Equals(field, value)) { return; } field = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }