using Mapster; using Prism.Dialogs; using ScottPlot; using ScottPlot.Colormaps; using ScottPlot.Plottables; using ScottPlot.WPF; using SqlSugar; using System.Collections.Generic; using System.Text; using System.Windows; using System.Windows.Media; using Universal; using static Dm.FldrStatement; namespace ProximaAnalizer.ViewModels; internal partial class DBInfoTraceViewModel : ObservableObject { public DBInfoTraceViewModel(TraceData traceData, SqlSugarCustom sqlSugarCustom, IEventAggregator eventAggregator, IDialogService dialogService) { this.traceData = traceData; this.sqlSugarCustom = sqlSugarCustom; this.dialogService = dialogService; this.PlotControl = new(); this.InitPlot(); eventAggregator.GetEvent().Subscribe(Search); } private void InitPlot() { this.PlotControl.Plot.Grid.XAxisStyle.MajorLineStyle.Width = 1f; this.PlotControl.Plot.Grid.YAxisStyle.MajorLineStyle.Width = 1f; this.PlotControl.Plot.Axes.Bottom.TickLabelStyle.Alignment = Alignment.MiddleLeft; this.PlotControl.Plot.RenderManager.RenderStarting += (s, e) => { Tick[] ticks = this.PlotControl.Plot.Axes.Bottom.TickGenerator.Ticks; for (int i = 0; i < ticks.Length; i++) { DateTime dt = DateTime.FromOADate(ticks[i].Position); string label = $"{dt:MM-dd HH:mm:ss}"; ticks[i] = new Tick(ticks[i].Position, label); } }; this.PlotControl.Plot.FigureBackground.Color = ScottPlot.Colors.Transparent; this.PlotControl.Plot.Axes.Bottom.TickLabelStyle.Rotation = 90; this.PlotControl.Plot.Axes.Bottom.TickLabelStyle.Alignment = Alignment.MiddleLeft; //PixelPadding padding = new(40, 20, 65, 10); //this.PlotControl.Plot.Layout.Fixed(padding); this.PlotControl.Plot.FigureBackground.Color = ScottPlot.Colors.Transparent; //UpdateDetail(); } [ObservableProperty] private WpfPlot _PlotControl; private readonly TraceData traceData; private readonly SqlSugarCustom sqlSugarCustom; private readonly IDialogService dialogService; [ObservableProperty] private ObservableDictionary _RecipeSteps = []; [ObservableProperty] private IDictionary? _Hierachy; [ObservableProperty] private ObservableDictionary _Left = []; [ObservableProperty] private ObservableDictionary _Right = []; private readonly Stack> Cache = new(); private bool AutoGenerated = false; [RelayCommand] private void Selected(SelectRecipeStep step) { if (RecipeSteps is null) return; if (sqlSugarCustom.Client is null) return; if (AutoGenerated) { UnSelected(step); return; } if (RecipeSteps.Where(t => t.Value.IsSelected).Count() != 2) return; DateTime start = RecipeSteps.Where(t => t.Value.IsSelected).First().Key; DateTime end = RecipeSteps.Where(t => t.Value.IsSelected).Last().Key; RecipeSteps.Where(t => t.Key >= start && t.Key <= end).Foreach(t => t.Value.IsSelected = true); this.AutoGenerated = true; } [RelayCommand] private void UnSelected(SelectRecipeStep step) { RecipeSteps.Where(t => t.Value.IsSelected).Foreach(t => t.Value.IsSelected = false); this.AutoGenerated = false; } [RelayCommand] private void SelectHierachy(KeyValuePair item) { if (this.Hierachy is null) return; if (item.Value is IDictionary next) { this.Cache.Push(this.Hierachy); this.Hierachy = next; return; } //this.Left.TryAdd((string)item.Value, item.Value); //IDialogParameters parameters, Action< IDialogResult > callback IDialogParameters para = new DialogParameters() { { "Line", item.Value } }; dialogService.Show("LinePicker", para, AddLine); } [RelayCommand] private void EditLine(KeyValuePair item) { IDialogParameters para = new DialogParameters() { { "Line", item.Key } }; dialogService.Show("LinePicker", para, AddLine); } private void AddLine(IDialogResult dialogResult) { dialogResult.Parameters.TryGetValue("Line", out LineType? lineType); dialogResult.Parameters.TryGetValue("Name", out string? line); dialogResult.Parameters.TryGetValue("Axis", out string? Axis); if (lineType is null || string.IsNullOrEmpty(line) || string.IsNullOrEmpty(Axis)) return; ObservableDictionary? lineCollection = Axis switch { "L" => Left, "R" => Right, _ => default }; if (lineCollection is null) return; if (lineCollection.TryGetValue(line, out object? oldType) && oldType is LineType oldLine) oldLine.IsEnable = true; lineCollection[line] = lineType; } [RelayCommand] private void Return() { if (this.Cache.TryPop(out var output) && output is not null) this.Hierachy = output; } [RelayCommand] private void Search() { if (traceData.ProcessData is null) return; if (sqlSugarCustom.Client is null) return; this.Cache.Clear(); this.RecipeSteps ??= []; this.RecipeSteps.Clear(); this.Clear(""); DateTime beginTime = traceData.ProcessData.Process_Begin_Time; DateTime endTime = traceData.ProcessData.Process_End_Time; long beginTicks = beginTime.Ticks; long endTicks = endTime.Ticks; List recipeSteps; try { recipeSteps = sqlSugarCustom.Client.Queryable().AS("recipe_step_data") .Where(t => t.Process_Data_Guid == traceData.ProcessData.Guid) .OrderBy(t => t.Step_Begin_Time).ToList(); } catch { MessageBox.Show($"recipe_step_data 记录不存在", "Warning", MessageBoxButton.OK, MessageBoxImage.Error); return; } if (recipeSteps.Count == 0) { MessageBox.Show($"recipe_step 步骤数量为0", "Warning", MessageBoxButton.OK, MessageBoxImage.Error); return; } foreach (var item in recipeSteps) { SelectRecipeStep step = new(); item.Adapt(step); this.RecipeSteps.TryAdd(item.Step_Begin_Time, step); } dynamic f; dynamic system; try { f = sqlSugarCustom.Client.Queryable().AS($"\"{beginTime:yyyyMMdd}.PM1\"").First(); system = sqlSugarCustom.Client.Queryable().AS($"\"{beginTime:yyyyMMdd}.System\"").First(); } catch { MessageBox.Show($"{beginTime:yyyyMMdd} 记录不存在", "Warning", MessageBoxButton.OK, MessageBoxImage.Error); return; } GeneralProcessData processData = new(); if (f is not IDictionary input) return; if (!processData.ToDictionary(input, out Dictionary? output) || output is null) return; if (output["PM1"] is not IDictionary pmData) return; if (!processData.ToDictionary(system, out Dictionary? systemDic) || systemDic is null) return; Dictionary temp = []; Dictionary PM1 = []; Dictionary System = []; temp.Add("PM1", PM1); temp.Add("System", System); this.CreateTablePM(pmData, PM1); this.CreateTableSystem(systemDic!, System); this.Hierachy = temp; this.Cache.Push(temp); } private bool CreateTablePM(IDictionary data, IDictionary cache) { Dictionary ValueSensor = []; Dictionary StatusSensor = []; Dictionary leakCheck = []; Dictionary recipe = []; Dictionary aoValue = []; Dictionary ffu = []; Dictionary mfc = []; Dictionary gaslineHeater = []; Dictionary bufferFoup = []; Dictionary avValue = []; foreach (var item in data) { if (item.Value is not IDictionary values) { switch (item.Key) { case string s when s.EndsWith("Enable"): continue; case string s when s.StartsWith("LeakCheck"): leakCheck.Add(item.Key, item.Value); continue; default: recipe.Add(item.Key, item.Value); continue; } } switch (item.Key) { case "APC": case "APCVATGV": case "BoatElevatorServo": case "BoatRotationServo": case "BufferServo": case "Shutter": CreateTable(cache, item.Key, values); continue; case string s when s.StartsWith("Trig"): if (item.Value is IDictionary value) aoValue.Add(item.Key, value["AOValue"]); continue; case string s when s.StartsWith("FS"): case string s1 when s1.StartsWith("PG"): case string s2 when s2.StartsWith("PS"): case string s3 when s3.StartsWith("VG"): if (item.Value is IDictionary vss) ValueSensor.Add(item.Key, vss["Value"]); continue; case string s when s.StartsWith("Sensor"): if (item.Value is IDictionary status) StatusSensor.Add(item.Key, status["Value"]); continue; case string s when s.StartsWith("MFC"): if (item.Value is IDictionary mfcs) mfcs.Foreach(t => mfc.Add($"{item.Key}_{t.Key}", t.Value)); continue; case string s when s.StartsWith("FFU"): if (item.Value is IDictionary ffus) ffus.Foreach(t => ffu.Add($"{item.Key}_{t.Key}", t.Value)); continue; case string s when s.StartsWith("GaselineHeater"): if (item.Value is IDictionary gaslines) gaslines.Foreach(t => gaslineHeater.Add($"{item.Key}_{t.Key}", t.Value)); continue; case string s when s.StartsWith("Valve"): if (item.Value is IDictionary valves) valves.Foreach(t => avValue.Add($"{item.Key}_{t.Key}", t.Value)); continue; default: continue; } } CreateTable(cache, "MFC", mfc); CreateTable(cache, "FFU", ffu); CreateTable(cache, "Valve", avValue); CreateTable(cache, "GaselineHeater", gaslineHeater); CreateTable(cache, "ValueSensor", ValueSensor); CreateTable(cache, "StatusSensor", StatusSensor); CreateTable(cache, "LeakCheck", leakCheck); CreateTable(cache, "AoValue", aoValue); CreateTable(cache, "Recipe", recipe); return true; } private void CreateTableSystem(IDictionary data, IDictionary cache) { Dictionary systemCollection = []; Dictionary alarmCollection = []; Dictionary Heater = []; Dictionary Stocker = []; Dictionary LoadPort = []; Dictionary FIMS = []; foreach (var item in data) { if (item.Value is not IDictionary values) continue; switch (item.Key) { case "Boat": case "CarrierRobot": case "Scheduler": case "WaferRobot": CreateTable(cache, item.Key, values); continue; case string s when s.StartsWith("Stocker"): Stocker.Add(item.Key, values); continue; case string s when s.StartsWith("LP"): LoadPort.Add(item.Key, values); continue; //case string s when s.StartsWith("FIMS"): // FIMS.Add(item.Key, values); // continue; case "System": if (values is not IDictionary systems) continue; foreach (var system in systems) { switch (system.Key) { case string s when s.StartsWith("Heater"): Heater.Add(system.Key, system.Value); continue; case string s when s.StartsWith("AlarmSignalHeater"): alarmCollection.Add(system.Key, ((IDictionary)system.Value)["Value"] ??= false); continue; default: systemCollection.Add(system.Key, system.Value); break; } } continue; default: break; } //CreateTable(cache, "FIMS", FIMS); CreateTable(cache, "Heater", Heater); CreateTable(cache, "LoadPort", LoadPort); CreateTable(cache, "Stocker", Stocker); CreateTable(cache, "System", systemCollection); CreateTable(cache, "AlarmSignalHeater", alarmCollection); } } private bool CreateTable(IDictionary cache, string key, object value) { return cache.TryAdd(key, value); } [RelayCommand] private void RemoveLeft(string key) { this.Left.TryRemove(key, out object? line); if (line is LineType lineType) lineType.IsEnable = true; } [RelayCommand] private void RemoveRight(string key) { this.Right.TryRemove(key, out object? line); if (line is LineType lineType) lineType.IsEnable = true; } [RelayCommand] private void Clear(string para) { switch (para) { case "L": this.Left.Foreach(t => ((LineType)t.Value).IsEnable = true); this.Left.Clear(); break; case "R": this.Right.Foreach(t => ((LineType)t.Value).IsEnable = true); this.Right.Clear(); break; default: this.Right.Foreach(t => ((LineType)t.Value).IsEnable = true); this.Right.Clear(); this.Left.Foreach(t => ((LineType)t.Value).IsEnable = true); this.Left.Clear(); break; } } [RelayCommand] private void GeneratePlot() { if (this.sqlSugarCustom.Client is null) return; if (!this.RecipeSteps.Any(t => t.Value.IsSelected)) return; DateTime start = this.RecipeSteps.Where(t => t.Value.IsSelected).First().Key; DateTime end = this.RecipeSteps.Where(t => t.Value.IsSelected).Last().Key; var whereFunc = ObjectFuncModel.Create("Format", "time", ">", "{long}:" + $"{start.Ticks}", "&&", "time", "<", "{long}:" + $"{end.Ticks}"); var f = sqlSugarCustom.Client.Queryable().AS($"\"{start:yyyyMMdd}.PM1\"").Where(whereFunc).ToList(); var system = sqlSugarCustom.Client.Queryable().AS($"\"{start:yyyyMMdd}.System\"").Where(whereFunc).ToList(); f.AddRange(system); Dictionary> cacheLeft = []; Dictionary> cacheRight = []; List time = []; foreach (var item in f) { if (item is not IDictionary data) continue; time.Add(new DateTime((long)data["time"])); foreach (string key in Left.Keys) { if (data.TryGetValue(key, out object? value) && value is not null) { if (!cacheLeft.TryGetValue(key, out List? collections) || collections is null) { collections = []; cacheLeft[key] = collections; } collections.Add((float)value); } } foreach (string key in Right.Keys) { if (data.TryGetValue(key, out object? value) && value is not null) { if (!cacheRight.TryGetValue(key, out List? collections) || collections is null) { collections = []; cacheRight[key] = collections; } collections.Add((float)value); } } } this.PlotControl.Plot.Clear(); foreach (var item in cacheLeft) this.SetLeftLine(time, item.Value, ((LineType)Left[item.Key])!.LinePattern, MarkerStyle.None, 2f, ((LineType)Left[item.Key])!.HexRGB); foreach (var item in cacheRight) this.SetRightLine(time, item.Value, ((LineType)Right[item.Key])!.LinePattern, MarkerStyle.None, 2f, ((LineType)Right[item.Key])!.HexRGB); this.PlotControl.Plot.Axes.Bottom.TickLabelStyle.OffsetY= 0; //this.PlotControl.Plot. this.PlotControl.Plot.Axes.AutoScale(); PlotControl.Refresh(); } private void SetLeftLine(List time, List value, LinePattern linePattern, MarkerStyle markerStyle, float lineWidth, string color) { Scatter mainScatter = this.PlotControl.Plot.Add.Scatter(time, value); mainScatter.MarkerStyle = markerStyle; mainScatter.LineWidth = lineWidth; mainScatter.LinePattern = linePattern; mainScatter.Color = new ScottPlot.Color(color); mainScatter.Axes.YAxis = this.PlotControl.Plot.Axes.Left; } private void SetRightLine(List time, List value, LinePattern linePattern, MarkerStyle markerStyle, float lineWidth, string color) { Scatter mainScatter = this.PlotControl.Plot.Add.Scatter(time, value); mainScatter.MarkerStyle = markerStyle; mainScatter.LineWidth = lineWidth; mainScatter.LinePattern = linePattern; mainScatter.Color = new ScottPlot.Color(color); mainScatter.Axes.YAxis = this.PlotControl.Plot.Axes.Right; } } public partial class SelectRecipeStep : ObservableObject { [ObservableProperty] private bool _IsSelected; public string? Guid { get; set; } public DateTime Step_Begin_Time { get; set; } public DateTime Step_End_Time { get; set; } public string? Step_Name { get; set; } public float Step_Time { get; set; } public int Step_Number { get; set; } public string? Sub_Recipe_Step_Time { get; set; } public string? Sub_Recipe_Step_Number { get; set; } public string? Sub_Recipe_Step_Name { get; set; } public string? Sub_Recipe_Loop_Info { get; set; } public string? Temp_correction { get; set; } public string? Temp_pid { get; set; } } public class DBProcessData(char spilter, int skip) where T_Hierarchy : IDictionary, new() { public bool ToDictionary(IDictionary input, out T_Hierarchy? output) { output = default; if (input is null) return false; T_Hierarchy cache = []; foreach (KeyValuePair rawData in input) { Span source = rawData.Key.Split(spilter).AsSpan()[skip..]; ColumAnalizer(cache, source, rawData.Key); } output = cache; return true; } private static void ColumAnalizer(/*ref*/ T_Hierarchy cache, Span seprated, object value) { if (seprated.Length <= 1) { cache[seprated[0]] = value; return; } if (!cache.TryGetValue(seprated[0], out object? output) || output is not T_Hierarchy hierarchy) { hierarchy = []; cache[seprated[0]] = hierarchy; } cache = hierarchy; ColumAnalizer(cache, seprated[1..], value); } } public class GeneralProcessData(int skip = 0) : DBProcessData>('.', skip) { }