|
@@ -1,15 +1,67 @@
|
|
|
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(TraceData traceData, SqlSugarCustom sqlSugarCustom) : ObservableObject
|
|
|
+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<RefreshRecipeData>().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<DateTime, SelectRecipeStep> _RecipeSteps = [];
|
|
|
|
|
|
[ObservableProperty]
|
|
@@ -46,35 +98,7 @@ internal partial class DBInfoTraceViewModel(TraceData traceData, SqlSugarCustom
|
|
|
|
|
|
RecipeSteps.Where(t => t.Key >= start && t.Key <= end).Foreach(t => t.Value.IsSelected = true);
|
|
|
|
|
|
- var whereFunc = ObjectFuncModel.Create("Format", "time", ">", "{long}:" + $"{start.Ticks}", "&&", "time", "<", "{long}:" + $"{end.Ticks}");
|
|
|
- dynamic f = sqlSugarCustom.Client.Queryable<dynamic>().AS($"\"{start:yyyyMMdd}.PM1\"").Where(whereFunc).First();
|
|
|
- dynamic system = sqlSugarCustom.Client.Queryable<dynamic>().AS($"\"{start:yyyyMMdd}.System\"").Where(whereFunc).First();
|
|
|
- GeneralProcessData processData = new();
|
|
|
-
|
|
|
- if (f is not IDictionary<string, object> input)
|
|
|
- return;
|
|
|
-
|
|
|
- if (!processData.ToDictionary(input, out Dictionary<string, object>? output) || output is null)
|
|
|
- return;
|
|
|
-
|
|
|
- if (output["PM1"] is not IDictionary<string, object> pmData)
|
|
|
- return;
|
|
|
|
|
|
- if (!processData.ToDictionary(system, out Dictionary<string, object>? systemDic) || systemDic is null)
|
|
|
- return;
|
|
|
-
|
|
|
- Dictionary<string, object> temp = [];
|
|
|
- Dictionary<string, object> PM1 = [];
|
|
|
- Dictionary<string, object> System = [];
|
|
|
- temp.Add("PM1", PM1);
|
|
|
- temp.Add("System", System);
|
|
|
- this.CreateTablePM(pmData, PM1);
|
|
|
- this.CreateTableSystem(systemDic!, System);
|
|
|
- this.Hierachy = temp;
|
|
|
- //this.Left.Clear();
|
|
|
- //this.Right.Clear();
|
|
|
- this.Cache.Clear();
|
|
|
- this.Cache.Push(temp);
|
|
|
this.AutoGenerated = true;
|
|
|
}
|
|
|
|
|
@@ -98,16 +122,49 @@ internal partial class DBInfoTraceViewModel(TraceData traceData, SqlSugarCustom
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- this.Left.TryAdd((string)item.Value, item.Value);
|
|
|
+ //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<string, object> 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<string, object>? 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;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
|
|
@@ -118,6 +175,10 @@ internal partial class DBInfoTraceViewModel(TraceData traceData, SqlSugarCustom
|
|
|
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;
|
|
@@ -125,18 +186,69 @@ internal partial class DBInfoTraceViewModel(TraceData traceData, SqlSugarCustom
|
|
|
long beginTicks = beginTime.Ticks;
|
|
|
long endTicks = endTime.Ticks;
|
|
|
|
|
|
- List<RecipeStepData> recipeSteps = sqlSugarCustom.Client.Queryable<RecipeStepData>().AS("recipe_step_data")
|
|
|
- .Where(t => t.Process_Data_Guid == traceData.ProcessData.Guid)
|
|
|
- .OrderBy(t => t.Step_Begin_Time).ToList();
|
|
|
+ List<RecipeStepData> recipeSteps;
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ recipeSteps = sqlSugarCustom.Client.Queryable<RecipeStepData>().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;
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
- this.RecipeSteps ??= [];
|
|
|
- this.RecipeSteps.Clear();
|
|
|
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<dynamic>().AS($"\"{beginTime:yyyyMMdd}.PM1\"").First();
|
|
|
+ system = sqlSugarCustom.Client.Queryable<dynamic>().AS($"\"{beginTime:yyyyMMdd}.System\"").First();
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ MessageBox.Show($"{beginTime:yyyyMMdd} 记录不存在", "Warning", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ GeneralProcessData processData = new();
|
|
|
+
|
|
|
+ if (f is not IDictionary<string, object> input)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!processData.ToDictionary(input, out Dictionary<string, object>? output) || output is null)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (output["PM1"] is not IDictionary<string, object> pmData)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!processData.ToDictionary(system, out Dictionary<string, object>? systemDic) || systemDic is null)
|
|
|
+ return;
|
|
|
+
|
|
|
+ Dictionary<string, object> temp = [];
|
|
|
+ Dictionary<string, object> PM1 = [];
|
|
|
+ Dictionary<string, object> 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<string, object> data, IDictionary<string, object> cache)
|
|
@@ -308,14 +420,17 @@ internal partial class DBInfoTraceViewModel(TraceData traceData, SqlSugarCustom
|
|
|
[RelayCommand]
|
|
|
private void RemoveLeft(string key)
|
|
|
{
|
|
|
- this.Left.TryRemove(key, out _);
|
|
|
-
|
|
|
+ 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 _);
|
|
|
+ this.Right.TryRemove(key, out object? line);
|
|
|
+ if (line is LineType lineType)
|
|
|
+ lineType.IsEnable = true;
|
|
|
}
|
|
|
|
|
|
[RelayCommand]
|
|
@@ -324,17 +439,116 @@ internal partial class DBInfoTraceViewModel(TraceData traceData, SqlSugarCustom
|
|
|
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<dynamic>().AS($"\"{start:yyyyMMdd}.PM1\"").Where(whereFunc).ToList();
|
|
|
+ var system = sqlSugarCustom.Client.Queryable<dynamic>().AS($"\"{start:yyyyMMdd}.System\"").Where(whereFunc).ToList();
|
|
|
+
|
|
|
+ f.AddRange(system);
|
|
|
+
|
|
|
+ Dictionary<string, List<float>> cacheLeft = [];
|
|
|
+ Dictionary<string, List<float>> cacheRight = [];
|
|
|
+ List<DateTime> time = [];
|
|
|
+ foreach (var item in f)
|
|
|
+ {
|
|
|
+ if (item is not IDictionary<string, object> 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<float>? 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<float>? 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<DateTime> time, List<float> 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<DateTime> time, List<float> 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]
|