Sic.Framework-Nanjing-Baishi/MECF.Framework.UI.Client/CenterViews/Editors/Recipe/RecipeCompareViewModel.cs

517 lines
17 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Caliburn.Micro;
using DocumentFormat.OpenXml.EMMA;
using MECF.Framework.Common.DataCenter;
using MECF.Framework.UI.Client.CenterViews.Configs.Roles;
using MECF.Framework.UI.Client.CenterViews.Editors.Sequence;
using MECF.Framework.UI.Client.ClientBase;
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel;
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel.Params;
using MECF.Framework.UI.Core.Accounts;
using OpenSEMI.ClientBase;
using OpenSEMI.ClientBase.Command;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;
namespace MECF.Framework.UI.Client.CenterViews.Editors.Recipe
{
public class RecipeCompareViewModel : UiViewModelBase
{
private readonly RecipeType _fileTypes;
private readonly bool _isFolderOnly;
private readonly bool _isShowRootNode;
private FileNode _currentFileNode;
private readonly RecipeProvider _recipeProvider;
public object View { get; set; }
public ObservableCollection<string> Chambers { get; set; }
private string labSelectRecipeNames;
public string LabSelectRecipeNames
{
get => labSelectRecipeNames;
set
{
labSelectRecipeNames = value;
NotifyOfPropertyChange();
}
}
private RecipeData _recipeHeaders;
/// <summary>
/// Recipe表头
/// </summary>
public RecipeData RecipeHeaders
{
get => _recipeHeaders;
set
{
_recipeHeaders = value;
NotifyOfPropertyChange();
}
}
private RecipeData _comparRecipeHeader;
/// <summary>
/// Recipe表头
/// </summary>
public RecipeData ComparRecipeHeader
{
get => _comparRecipeHeader;
set
{
_comparRecipeHeader = value;
NotifyOfPropertyChange();
}
}
private RecipeData _comparRecipe1;
/// <summary>
/// 选择要Recipe-1
/// </summary>
public RecipeData ComparRecipe1
{
get => _comparRecipe1;
set
{
_comparRecipe1 = value;
NotifyOfPropertyChange();
}
}
private RecipeData _comparRecipe2;
/// <summary>
/// 选择要Recipe-2
/// </summary>
public RecipeData ComparRecipe2
{
get => _comparRecipe2;
set
{
_comparRecipe2 = value;
NotifyOfPropertyChange();
}
}
private double[] _scrollViewerOffset;
/// <summary>
/// ScrollViewer滑动偏移
/// </summary>
public double[] ScrollViewerOffset
{
get => _scrollViewerOffset;
set
{
_scrollViewerOffset = value;
NotifyOfPropertyChange();
}
}
public RecipeHistory RecipeHistory { get; set; }
private ICommand _recipeHistoryCommand;
public ICommand RecipeHistoryCommand
{
get
{
if (_recipeHistoryCommand == null)
_recipeHistoryCommand = new BaseCommand(() => RecipeHistoryViewShow());
return _recipeHistoryCommand;
}
}
public int ProcessTypeIndexSelection { get; set; }
public RecipeType CurrentProcessType => ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType;
public int ChamberTypeIndexSelection { get; set; }
public ObservableCollection<string> ChamberType { get; set; }
public string CurrentChamberType => ChamberType[ChamberTypeIndexSelection];
public string SelectedChamber { get; set; }
public ObservableCollection<FileNode> SelectRecipeNameList { get; set; } = new ObservableCollection<FileNode>();
public FileNode DGSelectRecipeName { get; set; }
public List<ProcessTypeFileItem> ProcessTypeFileList { get; set; }
public RecipeCompareViewModel()
{
_fileTypes = RecipeType.Process | RecipeType.Routine;
_isFolderOnly = false;
_isShowRootNode = false;
_recipeProvider = new RecipeProvider();
var chamberType = QueryDataClient.Instance.Service.GetConfig("System.Recipe.SupportedChamberType");
if (chamberType == null)
{
ChamberType = new ObservableCollection<string>() { "Default" };
}
else
{
ChamberType = new ObservableCollection<string>(((string)(chamberType)).Split(','));
}
BuildFileTree(_isShowRootNode, _isFolderOnly, _fileTypes);
UpdateRecipeFormat();
}
protected override void OnViewLoaded(object view)
{
View = view;
base.OnViewLoaded(view);
}
protected override void OnDeactivate(bool close)
{
base.OnDeactivate(close);
// 锁定编辑器
((RecipeCompareView)View).editorLocker.Lock();
}
protected override void OnInitialize()
{
base.OnInitialize();
}
private void StoryboardClose()
{
var getString = (Storyboard)((RecipeCompareView)View).FindResource("MenuClose");
getString.Begin();
}
private void RecipeHistoryViewShow()
{
if (_currentFileNode == null)
return;
var dialog = new RecipeHistoryViewModel(_currentFileNode.FullPath.Replace("\\", "-"));
var wm = new WindowManager();
dynamic settings = new ExpandoObject();
settings.WindowStartupLocation = WindowStartupLocation.CenterOwner;
settings.Title = "Recipe历史数据对比选择一个(选择项和当前使用项对比),选择两个(两个选择项对比)";
settings.ResizeMode = ResizeMode.NoResize;
settings.ShowInTaskbar = false;
StoryboardClose();
var bret = wm.ShowDialog(dialog, null, settings);
if ((bool)bret)
{
if (dialog.SelectRecipeMemorieList.Count == 1)
RecipeSelectAndHistory(dialog.SelectRecipeMemorieList[0]);
else if (dialog.SelectRecipeMemorieList.Count == 2)
RecipeBothHistory(dialog.SelectRecipeMemorieList);
}
}
private async void RecipeSelectAndHistory(RecipeHistory recipeHistory)
{
RecipeHistory = recipeHistory;
LabSelectRecipeNames = _currentFileNode.FullPath + " / " + RecipeHistory.RecipeName + ": " +RecipeHistory.CreateTime;
await LoadRecipe(ComparRecipe1, _currentFileNode.PrefixPath, _currentFileNode.FullPath);
await LoadRecipe(ComparRecipe2, RecipeHistory);
StartComper(ComparRecipe1, ComparRecipe2);
}
private async void RecipeBothHistory(List<RecipeHistory> recipeHistoryList)
{
LabSelectRecipeNames = recipeHistoryList[0].RecipeName + ": " + recipeHistoryList[0].CreateTime + " / " + recipeHistoryList[1].RecipeName + ": " + recipeHistoryList[1].CreateTime;
await LoadRecipe(ComparRecipe1, recipeHistoryList[0]);
await LoadRecipe(ComparRecipe2, recipeHistoryList[1]);
StartComper(ComparRecipe1, ComparRecipe2);
}
public void TreeSelectChanged(FileNode file)
{
_currentFileNode = file;
RecipeHistoryViewShow();
}
public void TreeRightMouseDown(MouseButtonEventArgs e)
{
var item = GetParentObjectEx<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;
if (item != null)
{
item.Focus();
}
}
private TreeViewItem GetParentObjectEx<TreeViewItem>(DependencyObject obj) where TreeViewItem : FrameworkElement
{
var parent = VisualTreeHelper.GetParent(obj);
while (parent != null)
{
if (parent is TreeViewItem)
{
return (TreeViewItem)parent;
}
parent = VisualTreeHelper.GetParent(parent);
}
return null;
}
private void BuildFileTree(bool isShowRootNode, bool isFolderOnly, RecipeType fileType)
{
var recipeProvider = new RecipeProvider();
var scProcessType = QueryDataClient.Instance.Service.GetConfig("System.Recipe.SupportedProcessType").ToString();
var supportedRecipeType = new List<RecipeType>(new[] { RecipeType.Process, RecipeType.Routine });
if (!string.IsNullOrEmpty(scProcessType))
{
supportedRecipeType.Clear();
if (fileType.HasFlag(RecipeType.Process) && scProcessType.Contains(RecipeType.Process.ToString()))
supportedRecipeType.Add(RecipeType.Process);
if (fileType.HasFlag(RecipeType.Routine) && scProcessType.Contains(RecipeType.Routine.ToString()))
supportedRecipeType.Add(RecipeType.Routine);
}
var processTypeFileList = new List<ProcessTypeFileItem>();
for (var i = 0; i < supportedRecipeType.Count; i++)
{
var type = new ProcessTypeFileItem
{
ProcessType = supportedRecipeType[i]
};
var prefix = $"Sic\\{supportedRecipeType[i]}";
var recipes = recipeProvider.GetXmlRecipeList(prefix);
type.FileListByProcessType = RecipeSequenceTreeBuilder.BuildFileNode(prefix, "", false, recipes, isFolderOnly, isShowRootNode)[0].Files;
processTypeFileList.Add(type);
}
this.ProcessTypeFileList = processTypeFileList;
}
protected override void OnActivate()
{
base.OnActivate();
}
public void UpdateRecipeFormat()
{
var chamber = QueryDataClient.Instance.Service.GetConfig("System.Recipe.ChamberModules");
if (chamber == null)
{
chamber = "PM1";
}
Chambers = new ObservableCollection<string>(((string)chamber).Split(','));
if (Chambers.Count > 1)
{
for (var i = 0; i < Chambers.Count; i++)
{
var isPmInstall =
(bool)QueryDataClient.Instance.Service.GetConfig(
$"System.SetUp.Is{Chambers[i].ToString()}Installed");
{
if (!isPmInstall)
{
Chambers.RemoveAt(i);
}
}
}
}
if (Chambers.Count == 0)
{
Chambers = new ObservableCollection<string>(new string[] { "PM1" });
}
SelectedChamber = Chambers[0];
#region Create RecipeData
ComparRecipeHeader = CreateRecipe();
ComparRecipeHeader.AddStep();
ComparRecipe1 = CreateRecipe();
ComparRecipe2 = CreateRecipe();
#endregion Create RecipeData
}
private RecipeData CreateRecipe()
{
var role = AccountClient.Instance.Service.GetRoleByID(BaseApp.Instance.UserContext.Role.RoleId);
var recipeData = new RecipeData(null, CurrentProcessType);
recipeData.BuildFormat($"{CurrentChamberType}\\{CurrentProcessType}", SelectedChamber, role);
//得到当前登录的RoleItem
//var role = _roleManager.GetRoleByName(BaseApp.Instance.UserContext.RoleName);
return recipeData;
}
private async Task LoadRecipe(RecipeData recipeData, string prefixPath, string recipeName)
{
recipeData.Clear();
recipeData.Steps.Save(); // 重置为已保存状态
var recipeContent = _recipeProvider.ReadRecipeFile(prefixPath, recipeName);
if (string.IsNullOrEmpty(recipeContent))
{
MessageBox.Show($"{prefixPath}\\{recipeName} is empty, please confirm the file is valid.",
"Error",
MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
var role = AccountClient.Instance.Service.GetRoleByID(BaseApp.Instance.UserContext.Role.RoleId);
await recipeData.LoadFile(prefixPath, recipeName, recipeContent, SelectedChamber, role,
GetLoadingDispatcher());
}
private async Task LoadRecipe(RecipeData recipeData,RecipeHistory recipeHistory)
{
recipeData.Clear();
recipeData.Steps.Save(); // 重置为已保存状态
var role = AccountClient.Instance.Service.GetRoleByID(BaseApp.Instance.UserContext.Role.RoleId);
await recipeData.LoadFile(recipeHistory, SelectedChamber, role,
GetLoadingDispatcher());
}
private static Dispatcher GetLoadingDispatcher()
{
// 判断Step呈现方式
var isCascadeLoading = (bool)QueryDataClient.Instance.Service.GetConfig("System.RecipeCascadeLoading");
var dispatcher = isCascadeLoading ? Dispatcher.CurrentDispatcher : null;
return dispatcher;
}
public async void ComperSelectRecipe()
{
SelectRecipeNameList.Clear();
foreach (var ProcessTypeFile in ProcessTypeFileList)
{
GetSelectRecipeName(ProcessTypeFile.FileListByProcessType);
}
if (SelectRecipeNameList.Count != 2)
{
DialogBox.ShowError("Only 2 comparisons are supported");
return;
}
StoryboardClose();
LabSelectRecipeNames = SelectRecipeNameList[0].Name + " / " + SelectRecipeNameList[1].Name;
await LoadRecipe(ComparRecipe1, GetRecipeFullPath(SelectRecipeNameList[0]), SelectRecipeNameList[0].Name);
await LoadRecipe(ComparRecipe2, GetRecipeFullPath(SelectRecipeNameList[1]), SelectRecipeNameList[1].Name);
StartComper(ComparRecipe1, ComparRecipe2);
}
/// <summary>
/// 递归获取选择的Recipe
/// </summary>
/// <param name="fileNodes"></param>
private void GetSelectRecipeName(ObservableCollection<FileNode> fileNodes)
{
foreach (var item in fileNodes)
{
if (item.Files != null && item.Files.Count > 0)
GetSelectRecipeName(item.Files);
if (item.IsSelected)
SelectRecipeNameList.Add(item);
}
}
private string GetRecipeFullPath(FileNode fileNodes)
{
return fileNodes.PrefixPath + (fileNodes.Parent.FullPath == "" ? "" : "\\" + fileNodes.Parent.FullPath);
}
public void StartComper(RecipeData recipeData1, RecipeData recipeData2)
{
int stepsCount = 0;//缓存较短Recipe步数
RecipeData recipeDataExcess;//缓存较长步数Recipe
if (recipeData1.Steps.Count <= recipeData2.Steps.Count)
{
stepsCount = recipeData1.Steps.Count;
recipeDataExcess = recipeData2;
}
else
{
stepsCount = recipeData2.Steps.Count;
recipeDataExcess = recipeData1;
}
for (int i = 0; i < stepsCount; i++)
{
RecipeStep recipe1step = recipeData1.Steps[i];
RecipeStep recipe2step = recipeData2.Steps[i];
for (int j = 0; j < recipe1step.Count; j++)
{
object obj1 = GetValue(recipe1step[j]);//获取单元格中的数值object类型
object obj2 = GetValue(recipe2step[j]);
if (!(Comparer<object>.Default.Compare(obj1, obj2) == 0))
{
//recipe1step[j].Highlight();//不同部分高亮
//recipe2step[j].Highlight();
recipe1step[j].CompareDifferent();
recipe2step[j].CompareDifferent();
}
}
}
//步数多余部分高亮显示 使用缓存步数和缓存Recipe
for (int i = stepsCount; i < recipeDataExcess.Steps.Count; i++)
{
for (int j = 0; j < recipeDataExcess.Steps[i].Count; j++)
{
recipeDataExcess.Steps[i][j].CompareDifferent();
}
}
}
private object GetValue(Param param)
{
object Value = null;
if (param is IValueParam vp)
Value = vp.GetValue();
return Value;
}
}
}