using System.Collections.ObjectModel; using System.Windows; using System.Windows.Controls; namespace OmniScheduler; public partial class TaskEditorWindow : Window { private readonly ScheduledTask _task; private readonly AppSettings _settings; private readonly NotifyClient _client; private bool _loading; private TaskEditorWindow(Window owner, ScheduledTask task, AppSettings settings, NotifyClient client) { InitializeComponent(); Owner = owner; _task = task; _settings = settings; _client = client; KindBox.ItemsSource = Enum.GetValues(); IntervalUnitBox.ItemsSource = Enum.GetValues(); MisfireBox.ItemsSource = Enum.GetValues(); ChannelBox.ItemsSource = owner is MainWindow main ? main.State.Tasks.Select(t => t.Channel).Where(c => !string.IsNullOrWhiteSpace(c)).Distinct().ToList() : null; LoadTask(); } public static bool Edit(Window owner, ScheduledTask task, AppSettings settings, NotifyClient client) { var workingCopy = task.Clone(); workingCopy.Id = task.Id; workingCopy.Name = task.Name; var dialog = new TaskEditorWindow(owner, workingCopy, settings, client); if (dialog.ShowDialog() == true) { task.CopyFrom(workingCopy); return true; } return false; } private void LoadTask() { NameBox.Text = _task.Name; DescriptionBox.Text = _task.Description; EnabledBox.IsChecked = _task.IsEnabled; TargetUrlBox.Text = _settings.OmniNotifyUrl; ChannelBox.Text = _task.Channel; TitleBox.Text = _task.Title; BodyBox.Text = _task.Body; MisfireBox.SelectedItem = _task.MisfireStrategy; TriggersList.ItemsSource = _task.Triggers; TriggersList.SelectedIndex = _task.Triggers.Count > 0 ? 0 : -1; } private void LoadTrigger(TaskTrigger? trigger) { _loading = true; try { if (trigger is null) { return; } KindBox.SelectedItem = trigger.Kind; OneTimeBox.Text = trigger.OneTimeAt.ToString("yyyy-MM-dd HH:mm:ss"); IntervalValueBox.Text = trigger.IntervalValue.ToString(); IntervalUnitBox.SelectedItem = trigger.IntervalUnit; StartsAtBox.Text = trigger.StartsAt?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""; EndsAtBox.Text = trigger.EndsAt?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""; TimeOfDayBox.Text = trigger.TimeOfDay.ToString(@"hh\:mm\:ss"); MonthDayBox.Text = trigger.MonthDay.ToString(); LastBusinessDayBox.IsChecked = trigger.LastBusinessDay; CronBox.Text = trigger.CronExpression; SunBox.IsChecked = trigger.WeekDays.HasFlag(DayOfWeekFlags.Sunday); MonBox.IsChecked = trigger.WeekDays.HasFlag(DayOfWeekFlags.Monday); TueBox.IsChecked = trigger.WeekDays.HasFlag(DayOfWeekFlags.Tuesday); WedBox.IsChecked = trigger.WeekDays.HasFlag(DayOfWeekFlags.Wednesday); ThuBox.IsChecked = trigger.WeekDays.HasFlag(DayOfWeekFlags.Thursday); FriBox.IsChecked = trigger.WeekDays.HasFlag(DayOfWeekFlags.Friday); SatBox.IsChecked = trigger.WeekDays.HasFlag(DayOfWeekFlags.Saturday); } finally { _loading = false; RefreshPreview(); } } private bool SaveTriggerFields() { if (_loading || TriggersList.SelectedItem is not TaskTrigger trigger) { return true; } trigger.Kind = KindBox.SelectedItem is TriggerKind kind ? kind : TriggerKind.Interval; trigger.IntervalUnit = IntervalUnitBox.SelectedItem is IntervalUnit unit ? unit : IntervalUnit.Minutes; trigger.LastBusinessDay = LastBusinessDayBox.IsChecked == true; trigger.CronExpression = CronBox.Text.Trim(); if (int.TryParse(IntervalValueBox.Text, out var interval)) { trigger.IntervalValue = interval; } if (int.TryParse(MonthDayBox.Text, out var monthDay)) { trigger.MonthDay = Math.Clamp(monthDay, 1, 31); } if (DateTime.TryParse(OneTimeBox.Text, out var oneTime)) { trigger.OneTimeAt = oneTime; } trigger.StartsAt = DateTime.TryParse(StartsAtBox.Text, out var startsAt) ? startsAt : null; trigger.EndsAt = DateTime.TryParse(EndsAtBox.Text, out var endsAt) ? endsAt : null; if (TimeSpan.TryParse(TimeOfDayBox.Text, out var time)) { trigger.TimeOfDay = time; } var days = DayOfWeekFlags.None; if (SunBox.IsChecked == true) days |= DayOfWeekFlags.Sunday; if (MonBox.IsChecked == true) days |= DayOfWeekFlags.Monday; if (TueBox.IsChecked == true) days |= DayOfWeekFlags.Tuesday; if (WedBox.IsChecked == true) days |= DayOfWeekFlags.Wednesday; if (ThuBox.IsChecked == true) days |= DayOfWeekFlags.Thursday; if (FriBox.IsChecked == true) days |= DayOfWeekFlags.Friday; if (SatBox.IsChecked == true) days |= DayOfWeekFlags.Saturday; trigger.WeekDays = days; trigger.Notify(nameof(TaskTrigger.Summary)); TriggersList.Items.Refresh(); RefreshPreview(); return true; } private bool SaveTaskFields() { ValidationText.Text = ""; SaveTriggerFields(); if (string.IsNullOrWhiteSpace(NameBox.Text)) { ValidationText.Text = "任务名称不能为空"; return false; } foreach (var trigger in _task.Triggers) { if (trigger.Kind == TriggerKind.Interval && trigger.IntervalValue < 1) { ValidationText.Text = "固定间隔不能小于 1"; return false; } } _task.Name = NameBox.Text.Trim(); _task.Description = DescriptionBox.Text.Trim(); _task.IsEnabled = EnabledBox.IsChecked == true; _task.Channel = ChannelBox.Text.Trim(); _task.Title = TitleBox.Text.Trim(); _task.Body = BodyBox.Text; _task.MisfireStrategy = MisfireBox.SelectedItem is MisfireStrategy strategy ? strategy : MisfireStrategy.DoNothing; return true; } private void TriggersList_SelectionChanged(object sender, SelectionChangedEventArgs e) => LoadTrigger(TriggersList.SelectedItem as TaskTrigger); private void AddTrigger_Click(object sender, RoutedEventArgs e) { var trigger = new TaskTrigger(); _task.Triggers.Add(trigger); TriggersList.SelectedItem = trigger; TriggersList.Items.Refresh(); } private void RemoveTrigger_Click(object sender, RoutedEventArgs e) { if (TriggersList.SelectedItem is TaskTrigger trigger) { _task.Triggers.Remove(trigger); TriggersList.Items.Refresh(); } } private void Field_Changed(object sender, RoutedEventArgs e) { if (!_loading) { SaveTriggerFields(); } } private async void TestSend_Click(object sender, RoutedEventArgs e) { if (!SaveTaskFields()) { return; } TestResultText.Text = "发送中..."; var log = await _client.SendAsync(_task, "Test", _settings.OmniNotifyUrl); TestResultText.Text = log.Level == "INFO" ? "测试发送成功" : log.Message; TestResultText.Foreground = log.Level == "INFO" ? System.Windows.Media.Brushes.ForestGreen : System.Windows.Media.Brushes.Firebrick; } private void Save_Click(object sender, RoutedEventArgs e) { if (!SaveTaskFields()) { return; } DialogResult = true; } private void Cancel_Click(object sender, RoutedEventArgs e) => DialogResult = false; private void RefreshPreview() { if (TriggersList.SelectedItem is not TaskTrigger trigger) { PreviewBox.Text = ""; return; } var preview = NextRunCalculator.Preview(trigger, DateTime.Now); PreviewBox.Text = preview.Count == 0 ? "无法计算未来执行时间,请检查规则。" : string.Join(Environment.NewLine, preview.Select(d => d.ToString("yyyy-MM-dd HH:mm:ss"))); } }