|
|
|
|
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" }); }
|
|
|
|
|
}
|