using Newtonsoft.Json.Serialization; using Prism.Events; using ProximaAnalizer.Helpers; using SqlSugar; using System.Text; using System.Windows; using Universal; namespace ProximaAnalizer.ViewModels; internal partial class DBInfoAlarmViewModel : ObservableObject { public DBInfoAlarmViewModel(DBDataHelper dBDataHelper, TraceData traceData, IEventAggregator eventAggregator, IDialogService dialogService) { this._traceData = traceData; this._DBDataHelper = dBDataHelper; this._dialogService = dialogService; this._eventAggregator = eventAggregator; CurrentChangedQueue = new(CurrentChangedQueueHandler); eventAggregator.GetEvent().Subscribe(InitDisplayData); } private readonly IEventAggregator _eventAggregator; private readonly IDialogService _dialogService; private readonly DBDataHelper _DBDataHelper; private readonly TraceData _traceData; private readonly EventQueue CurrentChangedQueue; private Timer? _AutoPlayTimer; private Pages? _FromPage; private void InitDisplayData() { this.RecipeSteps.Clear(); this.Alarms.Clear(); this.MFCs.Clear(); this.Heaters.Clear(); this.GaslineHeaters.Clear(); this.FFUs.Clear(); this.Valves.Clear(); this.LeakChecks.Clear(); this.Pressures.Clear(); this.APCs.Clear(); this.APCVATGVs.Clear(); RefreshAlarmData alarmData = _eventAggregator.GetEvent(); this._FromPage = alarmData.FromPage; if (_traceData.ProcessData is null) return; this.RecipeName = _traceData.ProcessData.Recipe_Name; if (!this._DBDataHelper.GetRecipeSteps(_traceData.ProcessData.Guid, out string reason, out List? recipeSteps) || recipeSteps is null) { MessageBox.Show(reason, "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); return; } recipeSteps.Foreach(t => this.RecipeSteps.TryAdd(TimeRounder.IngoreMillionSeconds(t.Step_Begin_Time.Ticks), t)); this.Start = recipeSteps.First().Step_Begin_Time; this.End = recipeSteps.Last().Step_End_Time; this._DBDataHelper.SetTimeRange(this.Start, this.End); if (!this._DBDataHelper.GetAlarmData(out List? alarms) || alarms is null) return; foreach (var alarm in alarms) { if (alarm is null || string.IsNullOrEmpty(alarm.Level)) continue; DateTime occorTime = TimeRounder.IngoreMillionSeconds(alarm.Occur_Time.Ticks); if (!this.Alarms.TryGetValue(occorTime, out StringBuilder? events) || events is null) { events = new(); this.Alarms[occorTime] = events; events.Append(alarm.Description); continue; } events.Append(Environment.NewLine); events.Append(alarm.Description); } if (alarmData.Selected is not null) { DateTime time = TimeRounder.IngoreMillionSeconds(alarmData.Selected.Occur_Time.Ticks); this.Current = time; this.CurrentLong = time.Ticks; } else { this.Current = this.Start; this.CurrentLong = this.Start.Ticks; } } [ObservableProperty] private RecipeStepData? _CurrentRecipeStep; [ObservableProperty] private ObservableDictionary _RecipeSteps = []; [ObservableProperty] private ObservableDictionary _Alarms = []; [ObservableProperty] private KeyValuePair? _SelectedAlarm; partial void OnSelectedAlarmChanged(KeyValuePair? value) { if (value is null) return; this.CurrentLong = value.Value.Key.Ticks; } [ObservableProperty] private string? _RecipeName; [ObservableProperty] private DateTime _Start; [ObservableProperty] private DateTime _End; [ObservableProperty] private DateTime _Current; [ObservableProperty] private long _CurrentLong; partial void OnCurrentLongChanged(long value) => this.CurrentChangedQueue.Enqueue(value); private void CurrentChangedQueueHandler(long value) { if (CurrentChangedQueue.Count != 0) return; DateTime time = TimeRounder.IngoreMillionSeconds(value); RecipeStepData? step = this.RecipeSteps.Where(t => t.Key <= this.Current).LastOrDefault().Value; App.Current.Dispatcher?.Invoke(() => { if (this.Alarms.ContainsKey(time)) this.SelectedAlarm = this.Alarms.Where(t => t.Key == time).FirstOrDefault(); else this.SelectedAlarm = null; this.Current = time; this.CurrentRecipeStep = step; }); DateTime startTime = time.AddMilliseconds(-500); DateTime endTime = time.AddMilliseconds(500); this._DBDataHelper.GetSystemData(startTime, endTime, out List? systemData); this._DBDataHelper.GetPMData(startTime, endTime, out List? pmData); Parallel.Invoke( () => this.MFCs.UpdateData(pmData), () => this.Heaters.UpdateData(systemData), () => this.GaslineHeaters.UpdateData(pmData), () => this.FFUs.UpdateData(pmData), () => this.Valves.UpdateData(pmData), () => this.LeakChecks.UpdateData(pmData), () => this.Pressures.UpdateData(pmData), () => this.APCs.UpdateData(pmData), () => this.APCVATGVs.UpdateData(pmData)); } [ObservableProperty] private Visibility _PlayVis = Visibility.Visible; [ObservableProperty] private Visibility _StopVis = Visibility.Collapsed; [RelayCommand] private void Play(string para) { switch (para) { case "play": this._AutoPlayTimer ??= new(TimerCallback, null, 0, 1000); this.PlayVis = Visibility.Collapsed; this.StopVis = Visibility.Visible; break; case "stop": this._AutoPlayTimer?.Dispose(); this._AutoPlayTimer = null; this.PlayVis = Visibility.Visible; this.StopVis = Visibility.Collapsed; break; default: break; } } private void TimerCallback(object? state) { if (this.CurrentLong >= this.End.Ticks) { this.Play("stop"); return; } App.Current.Dispatcher?.Invoke(() => this.CurrentLong += 10000000); } [RelayCommand] private void TimeOpera(string para) { switch (para) { case "+": this.CurrentLong += 10000000; break; case "-": this.CurrentLong -= 10000000; break; case "++": this.CurrentLong += 600000000; break; case "--": this.CurrentLong -= 600000000; break; case "---": { DateTime alarm = this.Alarms.Where(t => t.Key < this.Current).LastOrDefault().Key; if (alarm == DateTime.MinValue) break; this.CurrentLong = alarm.Ticks; } break; case "+++": { DateTime alarm = this.Alarms.Where(t => t.Key > this.Current).FirstOrDefault().Key; if (alarm == DateTime.MinValue) break; this.CurrentLong = alarm.Ticks; } break; default: break; } } [RelayCommand] private void Return() { _eventAggregator.GetEvent().Page = _FromPage is null ? Pages.RecipeStepNavi : _FromPage.Value; _eventAggregator.GetEvent().Publish(); } [ObservableProperty] private DisplayHistroyHelper2 _Heaters = new(1, 2, "Heater"); [ObservableProperty] private DisplayHistroyHelper2 _MFCs = new(1, 2, "MFC"); [ObservableProperty] private DisplayHistroyHelper2 _Valves = new(2, 3, "IoValve"); [ObservableProperty] private DisplayHistroyHelper2 _FFUs = new(1, 2, "FFU"); [ObservableProperty] private DisplayHistroyHelper2 _GaslineHeaters = new(1, 2, "GaslineHeater"); [ObservableProperty] private DisplayHistroyHelper1 _LeakChecks = new(1, 1, ["LeakCheck"]); [ObservableProperty] private DisplayHistroyHelper1 _Pressures = new(1, 1, ["VG", "PS", "PG"]); [ObservableProperty] private DisplayHistroyHelper1 _APCs = new(1, 2, ["APC"]); [ObservableProperty] private DisplayHistroyHelper1 _APCVATGVs = new(1, 2, ["APCVATGV"]); [ObservableProperty] private object? _Selected; partial void OnSelectedChanged(object? value) { switch (value) { case KeyValuePair> sel: break; case KeyValuePair sel: break; default: break; } } } internal class TimeRounder { public static DateTime IngoreMillionSeconds(long ticks) { ticks -= ticks % 10000000; return new(ticks); } }