zcbot/windows-node/Zcbot.WindowsNode/Presentation/ViewModels/AnsysAcceptanceViewModel.cs

170 lines
5.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Security;
using System.Text.Json;
using System.Windows.Input;
namespace Zcbot.WindowsNode;
internal sealed class AnsysAcceptanceViewModel : ObservableObject, IDisposable
{
private readonly IAnsysAcceptanceService service;
private readonly AsyncCommand runCommand;
private readonly RelayCommand cancelCommand;
private readonly RelayCommand enableGateCommand;
private CancellationTokenSource? stop;
private string? passedReportPath;
private string message;
private string tone;
internal AnsysAcceptanceViewModel(IAnsysAcceptanceService service)
{
this.service = service;
(message, tone) = GateStatus();
runCommand = new AsyncCommand(RunAsync, () => IsAvailable && !IsRunning);
cancelCommand = new RelayCommand(Cancel, () => IsRunning);
enableGateCommand = new RelayCommand(EnableGate, () => CanEnableGate);
RunCommand = runCommand;
CancelCommand = cancelCommand;
EnableGateCommand = enableGateCommand;
}
internal event Func<string?>? ChooseReportDirectoryRequested;
internal event Func<bool>? ConfirmRunRequested;
internal event Func<bool>? ConfirmEnableGateRequested;
public bool IsAvailable => service.IsAvailable;
public bool IsRunning => stop is not null;
public bool IsGateEnabled => service.IsGateEnabled;
public bool CanEnableGate => passedReportPath is not null && !IsGateEnabled && !IsRunning;
public string Message
{
get => message;
private set => SetProperty(ref message, value);
}
public string Tone
{
get => tone;
private set => SetProperty(ref tone, value);
}
public ICommand RunCommand { get; }
public ICommand CancelCommand { get; }
public ICommand EnableGateCommand { get; }
internal void RefreshStatus()
{
if (IsRunning) return;
var status = GateStatus();
Message = status.Message;
Tone = status.Tone;
RaiseStateChanged();
}
internal void Cancel() => stop?.Cancel();
public void Dispose()
{
stop?.Cancel();
stop?.Dispose();
stop = null;
}
private async Task RunAsync()
{
if (!IsAvailable)
{
Message = "当前安装包没有 ANSYS 验收工具。请先安装新版完整 Node 包。";
Tone = "error";
return;
}
var parent = ChooseReportDirectoryRequested?.Invoke();
if (string.IsNullOrWhiteSpace(parent) || ConfirmRunRequested?.Invoke() != true)
{
return;
}
var workRoot = Path.Combine(
parent,
$"zcbot-ansys-acceptance-{DateTime.Now:yyyyMMdd-HHmmss}");
stop?.Dispose();
stop = new CancellationTokenSource();
passedReportPath = null;
Message = "正在启动真机验收…";
Tone = "warning";
RaiseStateChanged();
var progress = new Progress<string>(line => Message = line);
try
{
var result = await service.RunAsync(workRoot, progress, stop.Token);
passedReportPath = result.Passed ? result.ReportPath : null;
Tone = result.Passed ? "success" : "error";
Message = result.Passed
? $"验收通过。报告:{result.ReportPath}\n请确认许可证管理端席位已释放再开启执行门。"
: $"验收未通过:{result.Detail}\n报告{result.ReportPath}";
}
catch (OperationCanceledException)
{
passedReportPath = null;
Tone = "neutral";
Message = "验收已停止,执行门保持关闭。";
}
catch (Exception exception) when (
exception is IOException
or InvalidDataException
or InvalidOperationException
or JsonException
or UnauthorizedAccessException)
{
passedReportPath = null;
Tone = "error";
Message = $"验收启动或执行失败:{exception.Message}";
}
finally
{
stop.Dispose();
stop = null;
RaiseStateChanged();
}
}
private void EnableGate()
{
if (passedReportPath is null || ConfirmEnableGateRequested?.Invoke() != true)
{
return;
}
try
{
service.EnableGate(passedReportPath);
Tone = "success";
Message = "机器级执行门已写入。请从托盘退出 Node 后重新启动;重启后 ANSYS 应显示可用。";
}
catch (Exception exception) when (
exception is InvalidDataException
or SecurityException
or UnauthorizedAccessException)
{
Tone = "error";
Message = exception is SecurityException or UnauthorizedAccessException
? $"写入机器级环境变量需要管理员权限:{exception.Message}\n请退出 Node以管理员身份启动后再次点击。"
: exception.Message;
}
RaiseStateChanged();
}
private (string Message, string Tone) GateStatus() => IsGateEnabled
? ("当前执行门已开启。Node 重启并且 probe 正常后可接收 ANSYS 任务。", "success")
: ("当前执行门:关闭。安装成功不代表验收通过,请先运行本页验收。", "neutral");
private void RaiseStateChanged()
{
OnPropertyChanged(nameof(IsRunning));
OnPropertyChanged(nameof(IsGateEnabled));
OnPropertyChanged(nameof(CanEnableGate));
runCommand.RaiseCanExecuteChanged();
cancelCommand.RaiseCanExecuteChanged();
enableGateCommand.RaiseCanExecuteChanged();
}
}