1184 lines
42 KiB
C#
1184 lines
42 KiB
C#
using Aitex.Core.RT.Log;
|
|
using Aitex.Core.UI.ControlDataContext;
|
|
using Aitex.Core.Util;
|
|
using Aitex.Core.Utilities;
|
|
using Caliburn.Micro.Core;
|
|
using MECF.Framework.Common.ControlDataContext;
|
|
using MECF.Framework.Common.DataCenter;
|
|
using MECF.Framework.UI.Client.CenterViews.DataLogs.ProcessHistory;
|
|
using MECF.Framework.UI.Client.ClientBase;
|
|
using SciChart.Charting.ChartModifiers;
|
|
using SciChart.Charting.Common.Helpers;
|
|
using SciChart.Charting.ViewportManagers;
|
|
using SciChart.Charting.Visuals.Annotations;
|
|
using SciChart.Charting.Visuals.Axes;
|
|
using SciChart.Charting.Visuals.RenderableSeries;
|
|
using SciChart.Data.Model;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Data;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using System.Windows.Data;
|
|
using Cali = Caliburn.Micro;
|
|
|
|
namespace SicUI.Models.PMs.Charting
|
|
{
|
|
public class RecipeItemSic : RecipeItem
|
|
{
|
|
public string SyncStep { get; set; }
|
|
public string ProcessGuid { get; set; }
|
|
}
|
|
|
|
[Serializable]
|
|
public class PMNodeInfo : PropertyChangedBase
|
|
{
|
|
private bool _selected = false;
|
|
public bool Selected
|
|
{
|
|
get { return _selected; }
|
|
set
|
|
{
|
|
_selected = value;
|
|
NotifyOfPropertyChange("Selected");
|
|
}
|
|
}
|
|
|
|
public string NodeStr { get; set; }
|
|
|
|
|
|
private bool _isMatch = true;
|
|
public bool IsMatch
|
|
{
|
|
get { return _isMatch; }
|
|
set { _isMatch = value; NotifyOfPropertyChange("IsMatch"); }
|
|
}
|
|
|
|
public void ApplyCriteria(string criteria)
|
|
{
|
|
if (IsCriteriaMatched(criteria))
|
|
{
|
|
IsMatch = true;
|
|
}
|
|
else
|
|
{
|
|
IsMatch = false;
|
|
}
|
|
}
|
|
|
|
private bool IsCriteriaMatched(string criteria)
|
|
{
|
|
return !string.IsNullOrEmpty(criteria) && NodeStr.ToLower().Contains(criteria.ToLower()) || string.IsNullOrEmpty(criteria);
|
|
}
|
|
}
|
|
|
|
public class DataDetail
|
|
{
|
|
public string ProcessGuid { get; set; }
|
|
public double xValue { get; set; }
|
|
public double yValue { get; set; }
|
|
}
|
|
|
|
public class PMChartingViewModel : SicModuleUIViewModelBase, ISupportMultipleSystem
|
|
{
|
|
private class QueryIndexer
|
|
{
|
|
public DateTime StartTime { get; set; }
|
|
public DateTime EndTime { get; set; }
|
|
public string Module { get; set; }
|
|
public string ColumneName { get; set; }
|
|
public string ProcessGuid { get; set; }
|
|
public List<string> DateList { get; set; }
|
|
public long currentTimeTicks { get; set; }
|
|
}
|
|
|
|
|
|
public PMChartingViewModel()
|
|
{
|
|
DisplayName = "Process History";
|
|
|
|
DataDetailVisbleCommand = new ActionCommand(SetDataDetailVisble);
|
|
DefaultZoomCommand = new ActionCommand(Zoom);
|
|
ShowLegendCommand = new ActionCommand(SetLegendAvalible);
|
|
ShowAlarmCommand = new ActionCommand(AddAlarmInfo);
|
|
|
|
GetPMNode();
|
|
|
|
SelectedData = new ObservableCollection<IRenderableSeries>();
|
|
Recipes = new ObservableCollection<RecipeItemSic>();
|
|
|
|
AutoRangeX = AutoRange.Always;
|
|
AutoRangeY = AutoRange.Always;
|
|
|
|
VisibleRangeX = new DoubleRange(0, 10000);
|
|
VisibleRangeY = new DoubleRange(-10, 500);
|
|
VisibleRangeXLimit = new DoubleRange(0, 10000);
|
|
VisibleRangeYLimit = new DoubleRange(-10, 500);
|
|
|
|
AddRangeAnnotation();
|
|
|
|
_thread = new PeriodicJob(200, MonitorHistoryData, "History", true);
|
|
_threadReal = new PeriodicJob(TrendInterval, MonitorRealTimeData, "RealTime", true);
|
|
}
|
|
|
|
private PeriodicJob _thread;
|
|
private PeriodicJob _threadReal;
|
|
//DeviceTimer dt = new DeviceTimer();
|
|
private const int MAX_PARAMETERS = 20;
|
|
public DateTime _queryDateTimeToken;
|
|
|
|
private readonly IViewportManager _viewportManager = new DefaultViewportManager();
|
|
public IViewportManager ViewportManager
|
|
{
|
|
get { return _viewportManager; }
|
|
}
|
|
|
|
#region Properties
|
|
[IgnorePropertyChange]
|
|
public int TrendInterval { get; set; } = 5000;
|
|
public bool IntervalSaved { get; set; }
|
|
private DateTime _realTimeStart = DateTime.MaxValue;
|
|
private string _realTimeGuid = "";
|
|
private long _realTimeTick = 0;
|
|
private List<string> _seletedItemName = new List<string>();
|
|
|
|
ConcurrentBag<QueryIndexer> _lstTokenTimeData = new ConcurrentBag<QueryIndexer>();
|
|
//ConcurrentBag<QueryIndexer> _lstRealTimeData = new ConcurrentBag<QueryIndexer>();
|
|
//List<string> _lstRemoveRecipe = new List<string>();
|
|
|
|
|
|
public ObservableCollection<DataDetail> QueryDataDetail { get; set; }
|
|
public ObservableCollection<IRenderableSeries> SelectedData { get; set; }
|
|
public ObservableCollection<RecipeItemSic> Recipes { get; set; }
|
|
|
|
private AnnotationCollection _alarmAnnotation;
|
|
public AnnotationCollection AlarmAnnotation
|
|
{
|
|
get { return _alarmAnnotation; }
|
|
set
|
|
{
|
|
_alarmAnnotation = value;
|
|
NotifyOfPropertyChange(nameof(AlarmAnnotation));
|
|
}
|
|
}
|
|
|
|
private RecipeItemSic _selectedProcessData;
|
|
public RecipeItemSic SelectedProcessData
|
|
{
|
|
get { return _selectedProcessData; }
|
|
set
|
|
{
|
|
_selectedProcessData = value;
|
|
NotifyOfPropertyChange(nameof(SelectedProcessData));
|
|
}
|
|
}
|
|
|
|
private List<PMNodeInfo> _ConfigNodes = new List<PMNodeInfo>();
|
|
public List<PMNodeInfo> ConfigNodes
|
|
{
|
|
get { return _ConfigNodes; }
|
|
set { _ConfigNodes = value; NotifyOfPropertyChange("ConfigNodes"); }
|
|
}
|
|
|
|
private IRange _visibleRangeXLimit;
|
|
public IRange VisibleRangeXLimit
|
|
{
|
|
get { return _visibleRangeXLimit; }
|
|
set { _visibleRangeXLimit = value; NotifyOfPropertyChange(nameof(VisibleRangeXLimit)); }
|
|
}
|
|
|
|
private IRange _visibleRangeYLimit;
|
|
public IRange VisibleRangeYLimit
|
|
{
|
|
get { return _visibleRangeYLimit; }
|
|
set { _visibleRangeYLimit = value; NotifyOfPropertyChange(nameof(VisibleRangeYLimit)); }
|
|
}
|
|
|
|
private IRange _visibleRangeX;
|
|
public IRange VisibleRangeX
|
|
{
|
|
get { return _visibleRangeX; }
|
|
set { _visibleRangeX = value; NotifyOfPropertyChange(nameof(VisibleRangeX)); }
|
|
}
|
|
private IRange _visibleRangeY;
|
|
public IRange VisibleRangeY
|
|
{
|
|
get { return _visibleRangeY; }
|
|
set { _visibleRangeY = value; NotifyOfPropertyChange(nameof(VisibleRangeY)); }
|
|
}
|
|
|
|
public string UseSetX1
|
|
{
|
|
get;set;
|
|
}
|
|
public string UseSetX2
|
|
{
|
|
get; set;
|
|
}
|
|
public string UseSetY1
|
|
{
|
|
get; set;
|
|
}
|
|
public string UseSetY2
|
|
{
|
|
get; set;
|
|
}
|
|
|
|
private AutoRange _autoRangeX;
|
|
public AutoRange AutoRangeX
|
|
{
|
|
get => _autoRangeX;
|
|
set { _autoRangeX = value; NotifyOfPropertyChange(nameof(AutoRangeX)); }
|
|
}
|
|
|
|
private AutoRange _autoRangeY;
|
|
public AutoRange AutoRangeY
|
|
{
|
|
get => _autoRangeY;
|
|
set { _autoRangeY = value; NotifyOfPropertyChange(nameof(AutoRangeY)); }
|
|
}
|
|
|
|
private bool _enableAutoZoom = true;
|
|
public bool EnableAutoZoom
|
|
{
|
|
get { return _enableAutoZoom; }
|
|
|
|
set
|
|
{
|
|
_enableAutoZoom = value;
|
|
NotifyOfPropertyChange(nameof(EnableAutoZoom));
|
|
NotifyOfPropertyChange(nameof(ChartAutoRange));
|
|
}
|
|
}
|
|
|
|
|
|
private AutoRange _chartAutoRange = AutoRange.Never;
|
|
public AutoRange ChartAutoRange
|
|
{
|
|
get { return _chartAutoRange; }
|
|
set
|
|
{
|
|
_chartAutoRange = value;
|
|
NotifyOfPropertyChange(nameof(ChartAutoRange));
|
|
}
|
|
}
|
|
|
|
private bool _realTimeMode;
|
|
public bool RealTimeMode
|
|
{
|
|
get { return _realTimeMode; }
|
|
set
|
|
{
|
|
_realTimeMode = value;
|
|
NotifyOfPropertyChange(nameof(RealTimeMode));
|
|
if (_realTimeMode)
|
|
{
|
|
AddRealTimeInfo();
|
|
}
|
|
else
|
|
{
|
|
ClearRealTimeInfo();
|
|
}
|
|
}
|
|
}
|
|
|
|
private string _currentCriteria = String.Empty;
|
|
public string CurrentCriteria
|
|
{
|
|
get { return _currentCriteria; }
|
|
set
|
|
{
|
|
if (value == _currentCriteria)
|
|
return;
|
|
|
|
_currentCriteria = value;
|
|
NotifyOfPropertyChange("CurrentCriteria");
|
|
ApplyFilter();
|
|
}
|
|
}
|
|
|
|
private double _realTimeX;
|
|
public double RealTimeX
|
|
{
|
|
get { return _realTimeX; }
|
|
set
|
|
{
|
|
_realTimeX = value;
|
|
NotifyOfPropertyChange(nameof(RealTimeX));
|
|
}
|
|
}
|
|
|
|
private double _thresholdX1;
|
|
public double ThresholdX1
|
|
{
|
|
get { return _thresholdX1; }
|
|
set
|
|
{
|
|
_thresholdX1 = value;
|
|
NotifyOfPropertyChange(nameof(ThresholdX1));
|
|
}
|
|
}
|
|
|
|
private double _thresholdX2;
|
|
public double ThresholdX2
|
|
{
|
|
get { return _thresholdX2; }
|
|
set
|
|
{
|
|
_thresholdX2 = value;
|
|
NotifyOfPropertyChange(nameof(ThresholdX2));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private bool _showLegendInfo;
|
|
public bool ShowLegendInfo
|
|
{
|
|
get { return _showLegendInfo; }
|
|
set
|
|
{
|
|
_showLegendInfo = value;
|
|
NotifyOfPropertyChange(nameof(ShowLegendInfo));
|
|
}
|
|
}
|
|
|
|
private Visibility _dataDetailVisbility = Visibility.Collapsed;
|
|
public Visibility DataDetailVisbility
|
|
{
|
|
get { return _dataDetailVisbility; }
|
|
set
|
|
{
|
|
_dataDetailVisbility = value;
|
|
NotifyOfPropertyChange(nameof(DataDetailVisbility));
|
|
}
|
|
}
|
|
|
|
private Dictionary<string, string> keyValuesAlarm = new Dictionary<string, string>();
|
|
|
|
private Queue<Color> colorQueue = new Queue<Color>(new Color[]{Color.Red,Color.Orange,Color.Green,Color.Blue,Color.Purple,Color.Aqua,Color.Bisque,Color.Brown,Color.BurlyWood,Color.CadetBlue,
|
|
Color.CornflowerBlue,Color.DarkBlue,Color.DarkCyan,Color.DarkGray,Color.DarkGreen,Color.DarkKhaki,Color.DarkMagenta,Color.DarkOliveGreen, Color.DarkOrange,
|
|
Color.DarkSeaGreen,Color.DarkSlateBlue,Color.DarkSlateGray,Color.DarkViolet,Color.DeepPink,Color.DeepSkyBlue,Color.DimGray, Color.DodgerBlue,Color.ForestGreen, Color.Gold,
|
|
Color.Gray,Color.GreenYellow,Color.HotPink,Color.Indigo,Color.Khaki,
|
|
Color.LimeGreen,Color.MediumOrchid,Color.MediumPurple,Color.MediumSeaGreen,Color.MediumSlateBlue,Color.MediumSpringGreen,
|
|
Color.MediumTurquoise,Color.Moccasin,Color.NavajoWhite,Color.Olive,Color.OliveDrab,Color.OrangeRed,Color.Orchid,Color.PaleGoldenrod,Color.PaleGreen,
|
|
Color.PeachPuff,Color.Peru,Color.Plum,Color.PowderBlue,Color.RosyBrown,Color.RoyalBlue,Color.SaddleBrown,Color.Salmon,Color.SeaGreen, Color.Sienna,
|
|
Color.SkyBlue,Color.SlateBlue,Color.SlateGray,Color.SpringGreen,Color.Teal,Color.Aquamarine,Color.Tomato,Color.Turquoise,Color.Violet,Color.Wheat, Color.YellowGreen});
|
|
#endregion Properties
|
|
|
|
|
|
Cali.WindowManager wm = new Cali.WindowManager();
|
|
ChartingSelectDataViewModel selectDataDlg = new ChartingSelectDataViewModel();
|
|
|
|
#region 界面按钮
|
|
public void Add()
|
|
{
|
|
selectDataDlg.CheckAllRecipeFlag = false;
|
|
selectDataDlg.SelectedRecipes.Clear();
|
|
selectDataDlg.SelectedParameters.Clear();
|
|
|
|
var settings = new Dictionary<string, object> { { "Title", "Select Recipe Data" } };
|
|
bool? ret = wm.ShowDialog(selectDataDlg, null, settings);
|
|
if (ret == null || !ret.Value)
|
|
return;
|
|
|
|
|
|
for (int j = SelectedData.Count - 1; j >= 0; j--)
|
|
{
|
|
if (!(SelectedData[j] as ChartDataLineX).RecName.Contains("RealTime"))
|
|
{
|
|
SelectedData.RemoveAt(j);
|
|
}
|
|
}
|
|
|
|
GetXRange();
|
|
|
|
|
|
foreach (PMNodeInfo node in ConfigNodes)
|
|
{
|
|
if (node.Selected)
|
|
{
|
|
ParameterCheck(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 删除所有的ProcessData信息
|
|
/// </summary>
|
|
public void RemoveAllProcessData()
|
|
{
|
|
Recipes.Clear();
|
|
this.SelectedData.Clear();
|
|
foreach (PMNodeInfo node in ConfigNodes)
|
|
{
|
|
node.Selected = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 清除所有选择的节点
|
|
/// </summary>
|
|
public void RemoveAllLine()
|
|
{
|
|
this.SelectedData.Clear();
|
|
foreach (PMNodeInfo node in ConfigNodes)
|
|
{
|
|
node.Selected = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 删除单个ProcessData
|
|
/// </summary>
|
|
public void DeleteProcessData(RecipeItemSic item)
|
|
{
|
|
if (Recipes.Contains(item))
|
|
{
|
|
lock (_lockSelection)
|
|
{
|
|
for (int j = SelectedData.Count - 1; j >= 0; j--)
|
|
{
|
|
if ((SelectedData[j] as ChartDataLineX).ProcessGuid.Contains(item.ProcessGuid))
|
|
{
|
|
SelectedData.RemoveAt(j);
|
|
}
|
|
}
|
|
|
|
}
|
|
this.Recipes.Remove(item);
|
|
}
|
|
}
|
|
|
|
public void Template()
|
|
{
|
|
ChartingTemplateViewModel templateDataDlg = new ChartingTemplateViewModel();
|
|
templateDataDlg.CurrentDataInfo = ConfigNodes;
|
|
|
|
Cali.WindowManager wm = new Cali.WindowManager();
|
|
bool? bret = wm.ShowDialog(templateDataDlg);
|
|
if (!bret.HasValue || !bret.Value)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
ConfigNodes = templateDataDlg.CurrentDataInfo;
|
|
|
|
if (SelectedData.Count > 0)
|
|
{
|
|
lock (_lockSelection)
|
|
{
|
|
foreach (var node in ConfigNodes)
|
|
{
|
|
if (!node.Selected)
|
|
{
|
|
for (int j = SelectedData.Count - 1; j >= 0; j--)
|
|
{
|
|
if (!(SelectedData[j] as ChartDataLineX).ProcessGuid.Contains(node.NodeStr))
|
|
{
|
|
SelectedData.RemoveAt(j);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var node in ConfigNodes)
|
|
{
|
|
ParameterCheck(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ClearRealTimeInfo()
|
|
{
|
|
_realTimeStart = DateTime.MaxValue;
|
|
lock (_lockSelection)
|
|
{
|
|
for (int i = SelectedData.Count - 1; i >= 0; i--)
|
|
{
|
|
if ((SelectedData[i] as ChartDataLineX).RecName == "RealTime")
|
|
{
|
|
SelectedData.RemoveAt(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private void GetXRange()
|
|
{
|
|
double maxXValue = 0;
|
|
foreach (var recipe in selectDataDlg.SelectedRecipes)
|
|
{
|
|
if (Recipes.FirstOrDefault(x => x.ProcessGuid == recipe.ProcessGuid) != null)
|
|
{
|
|
continue;
|
|
}
|
|
this.Recipes.Add(recipe);
|
|
|
|
long curTickCount = (DateTime.Parse(recipe.EndTime).Ticks - DateTime.Parse(recipe.StartTime).Ticks) / 10000000;
|
|
if (maxXValue < curTickCount)
|
|
{
|
|
maxXValue = curTickCount;
|
|
}
|
|
}
|
|
|
|
VisibleRangeX = new DoubleRange(0, maxXValue);
|
|
VisibleRangeXLimit = new DoubleRange(0, maxXValue);
|
|
}
|
|
|
|
private void AddRealTimeInfo()
|
|
{
|
|
_realTimeStart = DateTime.MaxValue;
|
|
string sqlStr= String.Format("SELECT \"process_data\".\"process_begin_time\",\"process_data\".\"guid\" ,\"process_data\".\"process_in\" " +
|
|
"FROM \"process_data\",\"cj_data\",\"pj_data\",\"wafer_data\" where \"process_data\".\"wafer_data_guid\" = \"wafer_data\".\"guid\" " +
|
|
"and \"wafer_data\".\"pj_data_guid\" = \"pj_data\".\"guid\" and \"cj_data\".\"guid\" = \"pj_data\".\"cj_data_guid\" " +
|
|
"and \"process_data\".\"process_begin_time\" >= '{0}' and \"process_data\".\"process_end_time\" is null " +
|
|
"order by \"process_data\".\"process_begin_time\" DESC", DateTime.Now.AddHours(-3).ToString("yyyy-MM-dd HH:mm:ss"));
|
|
DataTable dataTable = QueryDataClient.Instance.Service.QueryData(sqlStr);
|
|
if (dataTable != null && dataTable.Rows.Count > 0)
|
|
{
|
|
_realTimeStart = (DateTime)dataTable.Rows[0]["process_begin_time"];
|
|
_realTimeGuid = dataTable.Rows[0]["guid"].ToString();
|
|
string _realTimeChamber = dataTable.Rows[0]["process_in"].ToString();
|
|
|
|
DateTime _realHisEndTime = DateTime.Now;
|
|
_realTimeTick = _realHisEndTime.Ticks+1;
|
|
|
|
lock (_lockSelection)
|
|
{
|
|
foreach (PMNodeInfo node in ConfigNodes)
|
|
{
|
|
if (node.Selected)
|
|
{
|
|
string nodeStr = _realTimeChamber + "." + node.NodeStr; //字段名称
|
|
string nodeWithGuid = node.NodeStr + "_" + _realTimeGuid;
|
|
|
|
bool isExist = SelectedData.FirstOrDefault(x => (x as ChartDataLineX).ProcessGuid == nodeWithGuid) != null;
|
|
if (!isExist)
|
|
{
|
|
var line = new ChartDataLineX(nodeStr);
|
|
line.ProcessGuid = nodeWithGuid;
|
|
line.RecName = "RealTime";
|
|
line.Tag = node;
|
|
SelectedData.Add(line);
|
|
SelectedDataChanged();
|
|
QueryIndexer indexer = _lstTokenTimeData.FirstOrDefault(x => x.ProcessGuid == line.ProcessGuid);
|
|
|
|
if (indexer == null)
|
|
{
|
|
indexer = new QueryIndexer()
|
|
{
|
|
Module = line.Module,
|
|
StartTime = _realTimeStart,
|
|
EndTime = _realHisEndTime,
|
|
ProcessGuid = line.ProcessGuid,
|
|
ColumneName = nodeStr,
|
|
DateList = GetDateList(_realTimeStart, _realHisEndTime)
|
|
};
|
|
|
|
_lstTokenTimeData.Add(indexer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_realTimeStart = DateTime.MaxValue;
|
|
}
|
|
}
|
|
#endregion 界面按钮
|
|
|
|
|
|
|
|
|
|
private void SelectedDataChanged()
|
|
{
|
|
foreach (var item in SelectedData)
|
|
{
|
|
if (item.Stroke.Equals(System.Windows.Media.Color.FromArgb(255, 0, 0, 255)))
|
|
{
|
|
Color drawingColor = colorQueue.Peek();
|
|
item.Stroke = System.Windows.Media.Color.FromRgb(drawingColor.R, drawingColor.G, drawingColor.B);
|
|
colorQueue.Enqueue(colorQueue.Dequeue());
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 加载PM的Device名称
|
|
/// </summary>
|
|
private void GetPMNode()
|
|
{
|
|
List<string> dataList = (List<string>)QueryDataClient.Instance.Service.GetConfig("System.NumericDataList");
|
|
dataList.Sort();
|
|
List<string> lstNode = new List<string>();
|
|
foreach (string dataName in dataList)
|
|
{
|
|
string[] nodeName = dataName.Split('.');
|
|
if (nodeName.Length > 1 && nodeName[0].IndexOf("PM") == 0)
|
|
{
|
|
string nodeStr = dataName.Substring(dataName.IndexOf('.') + 1);
|
|
if (!lstNode.Contains(nodeStr))
|
|
{
|
|
ConfigNodes.Add(new PMNodeInfo() { NodeStr = nodeStr });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private object _lockSelection = new object();
|
|
//private object _lockRealtime = new object();
|
|
|
|
|
|
protected bool MonitorHistoryData()
|
|
{
|
|
try
|
|
{
|
|
if (_lstTokenTimeData.Count > 0)
|
|
{
|
|
lock (_lockSelection)
|
|
{
|
|
foreach (var item in _lstTokenTimeData)
|
|
{
|
|
DateTime timeFrom = item.StartTime;
|
|
DateTime timeTo = item.EndTime;
|
|
|
|
GetHistoryData(item.DateList, timeFrom, timeTo, item.Module, item.ColumneName, item.ProcessGuid);
|
|
GetHistoryAlarmData(item.ProcessGuid, timeFrom, timeTo, item.Module);
|
|
_lstTokenTimeData.TryTake(out _);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LOG.Error(ex.Message);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
protected bool MonitorRealTimeData()
|
|
{
|
|
try
|
|
{
|
|
if (RealTimeMode && _realTimeStart < DateTime.Now && _lstTokenTimeData.Count == 0)
|
|
{
|
|
lock (_lockSelection)
|
|
{
|
|
GetRealTimeData();
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LOG.Error(ex.Message);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void GetRealTimeData()
|
|
{
|
|
long nowTickCount = DateTime.Now.Ticks;
|
|
string colName = "";
|
|
string module = "PM1";
|
|
|
|
List<string> lstColumn = GetColumnList(module);
|
|
if (lstColumn.Count <= 0)
|
|
{
|
|
return;
|
|
}
|
|
colName = String.Join(",", lstColumn);
|
|
|
|
string sql = String.Format("select time AS InternalTimeStamp,{0}", colName);
|
|
sql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc",
|
|
DateTime.Now.ToString("yyyyMMdd") + "." + module, _realTimeTick, nowTickCount);
|
|
|
|
_realTimeTick = nowTickCount;
|
|
|
|
Dictionary<string, List<DataDetail>> historyData = new Dictionary<string, List<DataDetail>>();
|
|
|
|
DataTable dataTable = QueryDataClient.Instance.Service.QueryData(sql);
|
|
if (dataTable == null || dataTable.Rows.Count == 0 || dataTable.Columns.Count < 2)
|
|
{
|
|
return;
|
|
}
|
|
|
|
RealTimeX = ((long)dataTable.Rows[dataTable.Rows.Count - 1][0] - _realTimeStart.Ticks) / 10000000;
|
|
|
|
for (int j = 1; j < dataTable.Columns.Count; j++)
|
|
{
|
|
List<DataDetail> lstDataDetail = new List<DataDetail>();
|
|
for (int i = 0; i < dataTable.Rows.Count; i++)
|
|
{
|
|
DataDetail data = new DataDetail();
|
|
long ticks = (long)dataTable.Rows[i][0] - _realTimeStart.Ticks;
|
|
data.xValue = ticks / 10000000;
|
|
|
|
if (dataTable.Rows[i][j] is DBNull || dataTable.Rows[i][j] is null)
|
|
{
|
|
data.yValue = 0;
|
|
}
|
|
else if (dataTable.Rows[i][j] is bool)
|
|
{
|
|
data.yValue = (bool)dataTable.Rows[i][j] ? 1 : 0;
|
|
}
|
|
else
|
|
{
|
|
data.yValue = float.Parse(dataTable.Rows[i][j].ToString());
|
|
}
|
|
lstDataDetail.Add(data);
|
|
}
|
|
historyData.Add(dataTable.Columns[j].ColumnName.Replace("PM1.","")+"_"+ _realTimeGuid, lstDataDetail);
|
|
}
|
|
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
|
{
|
|
try
|
|
{
|
|
foreach (var item in SelectedData)
|
|
{
|
|
var seriesItem = item as ChartDataLineX;
|
|
|
|
if (seriesItem == null)
|
|
continue;
|
|
foreach (var data in historyData)
|
|
{
|
|
if (data.Key != seriesItem.ProcessGuid)
|
|
continue;
|
|
|
|
seriesItem.Capacity += data.Value.Count;
|
|
|
|
foreach (var detailDataItem in data.Value)
|
|
{
|
|
seriesItem.Append(detailDataItem.xValue, detailDataItem.yValue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LOG.Write(ex);
|
|
}
|
|
}));
|
|
}
|
|
|
|
private void GetHistoryData(List<string> lstDayStr, DateTime from, DateTime to, string module, string colName, string processGuid)
|
|
{
|
|
Dictionary<string, List<DataDetail>> historyData = new Dictionary<string, List<DataDetail>>();
|
|
List<DataDetail> lstDataDetail = new List<DataDetail>();
|
|
|
|
foreach (string cDate in lstDayStr)
|
|
{
|
|
string sql = String.Format("select time AS InternalTimeStamp,\"{0}\"", colName);
|
|
sql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc",
|
|
cDate + "." + module, from.Ticks, to.Ticks);
|
|
|
|
DataTable dataTable = QueryDataClient.Instance.Service.QueryData(sql);
|
|
if (dataTable == null || dataTable.Rows.Count == 0 || dataTable.Columns.Count < 2)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < dataTable.Rows.Count; i++)
|
|
{
|
|
DataDetail data = new DataDetail();
|
|
long ticks = (long)dataTable.Rows[i][0] - from.Ticks;
|
|
data.xValue = ticks / 10000000;
|
|
if (dataTable.Rows[i][1] is DBNull || dataTable.Rows[i][1] is null)
|
|
{
|
|
data.yValue = 0;
|
|
}
|
|
else if (dataTable.Rows[i][1] is bool)
|
|
{
|
|
data.yValue = (bool)dataTable.Rows[i][1] ? 1 : 0;
|
|
}
|
|
else
|
|
{
|
|
data.yValue = float.Parse(dataTable.Rows[i][1].ToString());
|
|
}
|
|
lstDataDetail.Add(data);
|
|
}
|
|
}
|
|
|
|
historyData.Add(processGuid, lstDataDetail);
|
|
|
|
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
|
{
|
|
try
|
|
{
|
|
foreach (var item in SelectedData)
|
|
{
|
|
var seriesItem = item as ChartDataLineX;
|
|
|
|
if (seriesItem == null)
|
|
continue;
|
|
foreach (var data in historyData)
|
|
{
|
|
if (data.Key != seriesItem.ProcessGuid)
|
|
continue;
|
|
|
|
seriesItem.Capacity += data.Value.Count;
|
|
|
|
foreach (var detailDataItem in data.Value)
|
|
{
|
|
seriesItem.Append(detailDataItem.xValue, detailDataItem.yValue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LOG.Write(ex);
|
|
}
|
|
}));
|
|
}
|
|
|
|
private void GetHistoryAlarmData(string processguid,DateTime from, DateTime to, string module)
|
|
{
|
|
string sql = String.Format("select occur_time,description from public.event_data where source='{0}' and level='Alarm' and occur_time>'{1}' and occur_time<'{2}'",
|
|
module, from, to);
|
|
DataTable dataTable = QueryDataClient.Instance.Service.QueryData(sql);
|
|
if (dataTable == null || dataTable.Rows.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
|
{
|
|
try
|
|
{
|
|
foreach (var item in SelectedData)
|
|
{
|
|
var seriesItem = item as ChartDataLineX;
|
|
if (seriesItem.ProcessGuid == processguid)
|
|
{
|
|
for (int i = 0; i < dataTable.Rows.Count; i++)
|
|
{
|
|
long time = (((DateTime)dataTable.Rows[i]["occur_time"]).Ticks - from.Ticks) / 10000000;
|
|
seriesItem.AppedAlarm(time, dataTable.Rows[i]["description"].ToString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LOG.Write(ex);
|
|
}
|
|
}));
|
|
}
|
|
|
|
public bool ParameterCheck(PMNodeInfo node)
|
|
{
|
|
if (Recipes.Count <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if(node.Selected)
|
|
{
|
|
foreach (RecipeItemSic itemSic in Recipes)
|
|
{
|
|
string nodeStr = itemSic.Chamber + "." + node.NodeStr; //字段名称
|
|
string nodeStr_1 = itemSic.LotID; //显示名称
|
|
string nodeWithGuid = node.NodeStr + "_" + itemSic.ProcessGuid; //字段名+ Guid (唯一ID)
|
|
DateTime dtStartTime = DateTime.Parse(itemSic.StartTime);
|
|
DateTime dtEndTime = DateTime.Parse(itemSic.EndTime);
|
|
|
|
|
|
lock (_lockSelection)
|
|
{
|
|
bool isExist = SelectedData.FirstOrDefault(x => (x as ChartDataLineX).ProcessGuid == nodeWithGuid) != null;
|
|
if (!isExist)
|
|
{
|
|
if (SelectedData.Count < MAX_PARAMETERS)
|
|
{
|
|
var line = new ChartDataLineX(nodeStr);
|
|
line.ProcessGuid = nodeWithGuid;
|
|
line.RecName = nodeStr_1;
|
|
line.Tag = node;
|
|
SelectedData.Add(line);
|
|
SelectedDataChanged();
|
|
QueryIndexer indexer = _lstTokenTimeData.FirstOrDefault(x => x.ProcessGuid == line.ProcessGuid);
|
|
|
|
if (indexer == null)
|
|
{
|
|
indexer = new QueryIndexer()
|
|
{
|
|
Module = line.Module,
|
|
StartTime = dtStartTime,
|
|
EndTime = dtEndTime,
|
|
ProcessGuid = line.ProcessGuid,
|
|
ColumneName = nodeStr,
|
|
DateList = GetDateList(dtStartTime, dtEndTime)
|
|
};
|
|
|
|
_lstTokenTimeData.Add(indexer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lock (_lockSelection)
|
|
{
|
|
for (int i = SelectedData.Count - 1; i >= 0; i--)
|
|
{
|
|
if ((SelectedData[i] as ChartDataLineX).DataName.Contains(node.NodeStr))
|
|
{
|
|
SelectedData.RemoveAt(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public void SelectColor(ChartDataLineX cp)
|
|
{
|
|
if (cp == null)
|
|
return;
|
|
|
|
var dlg = new System.Windows.Forms.ColorDialog();
|
|
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
cp.Stroke = new System.Windows.Media.Color() { A = dlg.Color.A, B = dlg.Color.B, G = dlg.Color.G, R = dlg.Color.R };
|
|
}
|
|
}
|
|
|
|
public void SetYValue()
|
|
{
|
|
VisibleRangeYLimit = new DoubleRange(Convert.ToDouble(UseSetY1), Convert.ToDouble(UseSetY2));
|
|
}
|
|
|
|
public void SetXValue()
|
|
{
|
|
VisibleRangeXLimit = new DoubleRange(Convert.ToDouble(UseSetX1), Convert.ToDouble(UseSetX2));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取开始时间和结束时间之间的所有日期
|
|
/// </summary>
|
|
/// <param name="timeStart"></param>
|
|
/// <param name="timeEnd"></param>
|
|
/// <returns></returns>
|
|
private List<string> GetDateList(DateTime timeStart, DateTime timeEnd)
|
|
{
|
|
List<string> lstTime = new List<string>();
|
|
string dtEndStr = timeEnd.ToString("yyyyMMdd");
|
|
int timeSpan = (int)(timeEnd - timeStart).TotalDays + 1;
|
|
for (int i = 0; i <= timeSpan; i++)
|
|
{
|
|
string dt = timeStart.AddDays(i).ToString("yyyyMMdd");
|
|
lstTime.Add(dt);
|
|
if (dt == dtEndStr)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return lstTime;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取所有的列名
|
|
/// </summary>
|
|
private List<string> GetColumnList(string modleName)
|
|
{
|
|
List<string> _seletedItemName = new List<string>();
|
|
foreach (PMNodeInfo node in ConfigNodes)
|
|
{
|
|
if (node.Selected)
|
|
{
|
|
_seletedItemName.Add("\""+ modleName + "."+node.NodeStr+"\"");
|
|
}
|
|
}
|
|
return _seletedItemName;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 搜索
|
|
/// </summary>
|
|
private void ApplyFilter()
|
|
{
|
|
foreach (var node in ConfigNodes)
|
|
node.ApplyCriteria(CurrentCriteria);
|
|
}
|
|
|
|
public void SetTimeSpan()
|
|
{
|
|
if (TrendInterval < 1000)
|
|
{
|
|
TrendInterval = 1000;
|
|
}
|
|
else if (TrendInterval > 60000)
|
|
{
|
|
TrendInterval = 60000;
|
|
}
|
|
_threadReal.ChangeInterval(TrendInterval);
|
|
}
|
|
|
|
|
|
|
|
public ActionCommand DefaultZoomCommand { get; private set; }
|
|
public ActionCommand ShowLegendCommand { get; private set; }
|
|
public ActionCommand DataDetailVisbleCommand { get; private set; }
|
|
public ActionCommand ShowAlarmCommand { get; private set; }
|
|
|
|
private void SetDataDetailVisble()
|
|
{
|
|
if (DataDetailVisbility == Visibility.Collapsed)
|
|
{
|
|
DataDetailVisbility = Visibility.Visible;
|
|
}
|
|
else
|
|
{
|
|
DataDetailVisbility = Visibility.Collapsed;
|
|
}
|
|
}
|
|
|
|
private void SetLegendAvalible()
|
|
{
|
|
ShowLegendInfo = !ShowLegendInfo;
|
|
}
|
|
|
|
private void Zoom()
|
|
{
|
|
ViewportManager.AnimateZoomExtents(TimeSpan.FromMilliseconds(500));
|
|
}
|
|
|
|
public void DataStatistics()
|
|
{
|
|
foreach (var item in SelectedData)
|
|
{
|
|
(item as ChartDataLineX).Caculate(ThresholdX1, ThresholdX2);
|
|
}
|
|
}
|
|
|
|
public void DataStatisticsReset()
|
|
{
|
|
ThresholdX1 = 0;
|
|
ThresholdX2 = 1;
|
|
}
|
|
|
|
//public void DataStatisticsCurrent()
|
|
//{
|
|
|
|
//}
|
|
|
|
public void AddRangeAnnotation()
|
|
{
|
|
AlarmAnnotation = new AnnotationCollection();
|
|
VerticalLineAnnotation lineX1 = new VerticalLineAnnotation()
|
|
{
|
|
X1 = ThresholdX1,
|
|
VerticalAlignment = VerticalAlignment.Stretch,
|
|
FontSize = 13,
|
|
FontWeight = FontWeights.Bold,
|
|
IsEditable = true,
|
|
LabelPlacement = LabelPlacement.Axis,
|
|
LabelTextFormatting = "0.00",
|
|
ShowLabel = true,
|
|
StrokeThickness = 2,
|
|
Stroke = System.Windows.Media.Brushes.Blue,
|
|
Foreground = System.Windows.Media.Brushes.White,
|
|
};
|
|
|
|
lineX1.SetBinding(VerticalLineAnnotation.X1Property, new Binding("ThresholdX1") { Mode = BindingMode.TwoWay });
|
|
|
|
AlarmAnnotation.Add(lineX1);
|
|
|
|
VerticalLineAnnotation lineX2 = new VerticalLineAnnotation()
|
|
{
|
|
X1 = ThresholdX1,
|
|
VerticalAlignment = VerticalAlignment.Stretch,
|
|
FontSize = 13,
|
|
FontWeight = FontWeights.Bold,
|
|
IsEditable = true,
|
|
LabelPlacement = LabelPlacement.Axis,
|
|
LabelTextFormatting = "0.00",
|
|
ShowLabel = true,
|
|
StrokeThickness = 2,
|
|
Stroke = System.Windows.Media.Brushes.Blue,
|
|
Foreground = System.Windows.Media.Brushes.White,
|
|
};
|
|
lineX2.SetBinding(VerticalLineAnnotation.X1Property, new Binding("ThresholdX2") { Mode = BindingMode.TwoWay });
|
|
AlarmAnnotation.Add(lineX2);
|
|
}
|
|
|
|
private List<string> lstAlarmAdded = new List<string>();
|
|
private bool _showAlarm = false;
|
|
|
|
public void AddAlarmInfo()
|
|
{
|
|
lstAlarmAdded = new List<string>();
|
|
while (AlarmAnnotation.Count > 2)
|
|
{
|
|
AlarmAnnotation.RemoveAt(AlarmAnnotation.Count - 1);
|
|
}
|
|
|
|
_showAlarm = !_showAlarm;
|
|
if (_showAlarm)
|
|
{
|
|
lock (_lockSelection)
|
|
{
|
|
foreach (var item in SelectedData)
|
|
{
|
|
var data = item as ChartDataLineX;
|
|
if (data.IsVisible && data.ProcessGuid.Split('_').Length == 2 && !lstAlarmAdded.Contains(data.ProcessGuid.Split('_')[1]))
|
|
{
|
|
lstAlarmAdded.Add(data.ProcessGuid.Split('_')[1]);//同一个Guid不重复添加
|
|
|
|
for (int i = 0; i < data._alarmData.Count; i++)
|
|
{
|
|
System.Windows.Media.DoubleCollection dc = new System.Windows.Media.DoubleCollection();
|
|
dc.Add(5);
|
|
dc.Add(5);
|
|
|
|
AnnotationLabel lb = new AnnotationLabel() { LabelPlacement = LabelPlacement.TopRight, Text = "Alarm" + data._alarmData[i].Item2 };
|
|
VerticalLineAnnotation alarm1 = new VerticalLineAnnotation()
|
|
{
|
|
X1 = data._alarmData[i].Item1,
|
|
VerticalAlignment = VerticalAlignment.Stretch,
|
|
FontSize = 13,
|
|
FontWeight = FontWeights.Bold,
|
|
IsEditable = true,
|
|
LabelPlacement = LabelPlacement.Axis,
|
|
StrokeThickness = 1,
|
|
Stroke = System.Windows.Media.Brushes.Brown,
|
|
Foreground = System.Windows.Media.Brushes.White,
|
|
StrokeDashArray = dc,
|
|
AnnotationLabels = new ObservableCollection<AnnotationLabel>(new List<AnnotationLabel>() { lb }),
|
|
};
|
|
alarm1.IsEnabled = false;
|
|
AlarmAnnotation.Add(alarm1);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|