121 lines
3.9 KiB
C#
121 lines
3.9 KiB
C#
using System.Collections.ObjectModel;
|
||
using System.Windows.Input;
|
||
|
||
namespace Zcbot.WindowsNode;
|
||
|
||
internal sealed class LocalJobItemViewModel(JobDisplaySnapshot snapshot)
|
||
{
|
||
internal JobDisplaySnapshot Snapshot { get; } = snapshot;
|
||
|
||
public Guid JobId => Snapshot.JobId;
|
||
public string StageText => FormatStage(Snapshot.Stage);
|
||
public string Title => Snapshot.Title;
|
||
public string InputFilename => Snapshot.InputFilename;
|
||
public string ProgressText => Snapshot.Stage == "software_running"
|
||
? $"已执行 {FormatElapsed(DateTimeOffset.UtcNow - Snapshot.UpdatedAt)}"
|
||
: $"{Snapshot.Progress}%";
|
||
public string AcceptedAtText => Snapshot.AcceptedAt.LocalDateTime.ToString("MM-dd HH:mm");
|
||
public string ShortId => Snapshot.JobId.ToString("N")[..8];
|
||
public string Tone => Snapshot.Stage switch
|
||
{
|
||
"failed" or "cloud_terminal" => "error",
|
||
"succeeded" => "success",
|
||
"cancelled" => "neutral",
|
||
_ => "active",
|
||
};
|
||
public string DetailText => string.Join("\n", [
|
||
$"{StageText} · {Snapshot.Detail}",
|
||
$"能力:{Snapshot.Capability}",
|
||
$"Job ID:{Snapshot.JobId}",
|
||
$"更新时间:{Snapshot.UpdatedAt.LocalDateTime:yyyy-MM-dd HH:mm:ss}",
|
||
]);
|
||
|
||
private static string FormatElapsed(TimeSpan elapsed)
|
||
{
|
||
if (elapsed < TimeSpan.Zero) elapsed = TimeSpan.Zero;
|
||
return elapsed.TotalHours >= 1
|
||
? $"{(int)elapsed.TotalHours}:{elapsed.Minutes:00}:{elapsed.Seconds:00}"
|
||
: $"{elapsed.Minutes:00}:{elapsed.Seconds:00}";
|
||
}
|
||
|
||
private static string FormatStage(string stage) => stage switch
|
||
{
|
||
"accepted" => "等待处理",
|
||
"downloading_inputs" => "下载输入",
|
||
"ready_to_run" => "准备执行",
|
||
"software_running" => "软件执行中",
|
||
"uploading_outputs" => "上传结果",
|
||
"succeeded" => "成功",
|
||
"failed" => "失败",
|
||
"cloud_terminal" => "云端已终止",
|
||
"cancelled" => "已取消",
|
||
_ => stage,
|
||
};
|
||
}
|
||
|
||
internal sealed class JobPageViewModel : ObservableObject
|
||
{
|
||
private readonly IJobMonitorService service;
|
||
private LocalJobItemViewModel? selectedJob;
|
||
private string summary = "正在读取本机任务…";
|
||
|
||
internal JobPageViewModel(IJobMonitorService service)
|
||
{
|
||
this.service = service;
|
||
RefreshCommand = new RelayCommand(Refresh);
|
||
}
|
||
|
||
public ObservableCollection<LocalJobItemViewModel> Jobs { get; } = [];
|
||
|
||
public LocalJobItemViewModel? SelectedJob
|
||
{
|
||
get => selectedJob;
|
||
set
|
||
{
|
||
if (SetProperty(ref selectedJob, value))
|
||
{
|
||
OnPropertyChanged(nameof(SelectedDetail));
|
||
}
|
||
}
|
||
}
|
||
|
||
public string Summary
|
||
{
|
||
get => summary;
|
||
private set => SetProperty(ref summary, value);
|
||
}
|
||
|
||
public string SelectedDetail => SelectedJob?.DetailText
|
||
?? "选择任务后可查看执行阶段、更新时间和完整 Job ID。";
|
||
|
||
public ICommand RefreshCommand { get; }
|
||
|
||
internal void Refresh()
|
||
{
|
||
var selectedId = SelectedJob?.JobId;
|
||
IReadOnlyList<JobDisplaySnapshot> snapshots;
|
||
try
|
||
{
|
||
snapshots = service.ReadSnapshots();
|
||
}
|
||
catch (Exception exception) when (
|
||
exception is IOException or UnauthorizedAccessException)
|
||
{
|
||
Summary = $"无法读取本机任务:{exception.Message}";
|
||
return;
|
||
}
|
||
|
||
Jobs.Clear();
|
||
foreach (var snapshot in snapshots)
|
||
{
|
||
Jobs.Add(new LocalJobItemViewModel(snapshot));
|
||
}
|
||
var active = snapshots.Count(item => item.IsActive);
|
||
Summary = snapshots.Count == 0
|
||
? "暂无本机任务"
|
||
: $"活动任务 {active} 个 · 最近记录 {snapshots.Count} 条";
|
||
SelectedJob = Jobs.FirstOrDefault(item => item.JobId == selectedId)
|
||
?? Jobs.FirstOrDefault();
|
||
}
|
||
}
|