You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

141 lines
5.5 KiB
C#

using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Sln.Wcs.UI.Services;
namespace Sln.Wcs.UI.ViewModels;
public partial class SystemMonitorViewModel : ObservableObject
{
private readonly IEngineProcessService _hoistEngine;
private readonly IAgvEngineProcessService _agvEngine;
[ObservableProperty]
private ObservableCollection<LogEntry> _logs = new();
[ObservableProperty]
private int _logCount;
[ObservableProperty]
private bool _autoScroll = true;
// ---- Hoist ----
[ObservableProperty] private bool _isHoistRunning;
[ObservableProperty] private string _hoistStatusText = "已停止";
public string HoistStatusColor => IsHoistRunning ? "#00E676" : "#FF5252";
// ---- AGV ----
[ObservableProperty] private bool _isAgvRunning;
[ObservableProperty] private string _agvStatusText = "已停止";
public string AgvStatusColor => IsAgvRunning ? "#00E676" : "#FF5252";
private const int MaxLogs = 5000;
public SystemMonitorViewModel(IEngineProcessService hoistEngine, IAgvEngineProcessService agvEngine)
{
_hoistEngine = hoistEngine;
_agvEngine = agvEngine;
_hoistEngine.StateChanged += () => RefreshHoist();
_hoistEngine.OutputReceived += msg => AddLog($"[提升机] {msg}");
_agvEngine.StateChanged += () => RefreshAgv();
_agvEngine.OutputReceived += msg => AddLog($"[AGV] {msg}");
StartHoistCommand = new AsyncRelayCommand(StartHoistAsync, () => !IsHoistRunning);
StopHoistCommand = new RelayCommand(StopHoist, () => IsHoistRunning);
StartAgvCommand = new AsyncRelayCommand(StartAgvAsync, () => !IsAgvRunning);
StopAgvCommand = new RelayCommand(StopAgv, () => IsAgvRunning);
var original = Console.Out;
var writer = new LogTextWriter(original, entry =>
{
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
{
Logs.Add(entry);
if (Logs.Count > MaxLogs) Logs.RemoveAt(0);
LogCount = Logs.Count;
});
});
Console.SetOut(writer);
}
private void RefreshHoist()
{
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
{
IsHoistRunning = _hoistEngine.IsRunning;
HoistStatusText = _hoistEngine.StatusText;
OnPropertyChanged(nameof(HoistStatusColor));
StartHoistCommand.NotifyCanExecuteChanged();
StopHoistCommand.NotifyCanExecuteChanged();
});
}
private void RefreshAgv()
{
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
{
IsAgvRunning = _agvEngine.IsRunning;
AgvStatusText = _agvEngine.StatusText;
OnPropertyChanged(nameof(AgvStatusColor));
StartAgvCommand.NotifyCanExecuteChanged();
StopAgvCommand.NotifyCanExecuteChanged();
});
}
// ---- Hoist Commands ----
public IAsyncRelayCommand StartHoistCommand { get; }
public IRelayCommand StopHoistCommand { get; }
private async System.Threading.Tasks.Task StartHoistAsync()
{
try { AddLog("正在启动 HoistServer..."); await _hoistEngine.StartAsync(); AddLog("HoistServer 启动成功"); }
catch (Exception ex) { AddLog($"Hoist 启动失败: {ex.Message}", "ERROR"); if (_hoistEngine.LastError != null) AddLog(_hoistEngine.LastError, "ERROR"); }
}
private void StopHoist() { _hoistEngine.Stop(); AddLog("HoistServer 已停止"); }
// ---- AGV Commands ----
public IAsyncRelayCommand StartAgvCommand { get; }
public IRelayCommand StopAgvCommand { get; }
private async System.Threading.Tasks.Task StartAgvAsync()
{
try { AddLog("正在启动 HikRoBotServer..."); await _agvEngine.StartAsync(); AddLog("HikRoBotServer 启动成功"); }
catch (Exception ex) { AddLog($"AGV 启动失败: {ex.Message}", "ERROR"); if (_agvEngine.LastError != null) AddLog(_agvEngine.LastError, "ERROR"); }
}
private void StopAgv() { _agvEngine.Stop(); AddLog("HikRoBotServer 已停止"); }
private void AddLog(string msg, string level = "INFO")
{
Logs.Add(new LogEntry { Time = DateTime.Now, Message = msg, Level = level });
if (Logs.Count > MaxLogs) Logs.RemoveAt(0);
LogCount = Logs.Count;
}
[RelayCommand] private void Clear() { Logs.Clear(); LogCount = 0; }
[RelayCommand] private void ToggleAutoScroll() { AutoScroll = !AutoScroll; }
}
public class LogEntry
{
public DateTime Time { get; set; }
public string TimeText => Time.ToString("HH:mm:ss.fff");
public string Message { get; set; } = string.Empty;
public string Level { get; set; } = "INFO";
}
internal class LogTextWriter : TextWriter
{
private readonly TextWriter _original;
private readonly Action<LogEntry> _onWrite;
private readonly StringBuilder _buffer = new();
public LogTextWriter(TextWriter o, Action<LogEntry> cb) { _original = o; _onWrite = cb; }
public override Encoding Encoding => Encoding.UTF8;
public override void Write(char v) { _original.Write(v); if (v == '\n') Flush(); else if (v != '\r') _buffer.Append(v); }
public override void WriteLine(string? m) { _original.WriteLine(m); if (m != null) _onWrite(new LogEntry { Time = DateTime.Now, Message = m, Level = "INFO" }); }
private void Flush() { var m = _buffer.ToString(); _buffer.Clear(); if (m.Length > 0) _onWrite(new LogEntry { Time = DateTime.Now, Message = m, Level = "INFO" }); }
}