441 lines
14 KiB
C#
441 lines
14 KiB
C#
using Caliburn.Micro;
|
|
using DocumentFormat.OpenXml.EMMA;
|
|
using MECF.Framework.Common.DataCenter;
|
|
using MECF.Framework.Common.OperationCenter;
|
|
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.DGExtension.CustomColumn;
|
|
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel;
|
|
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel.Params;
|
|
using OpenSEMI.ClientBase;
|
|
using OpenSEMI.ClientBase.Command;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Input;
|
|
using System.Windows.Threading;
|
|
|
|
|
|
namespace MECF.Framework.UI.Client.CenterViews.Editors.Recipe
|
|
{
|
|
public class RecipeComparViewModel : UiViewModelBase
|
|
{
|
|
private readonly RoleManager _roleManager = new();
|
|
private readonly RecipeType _fileTypes;
|
|
private readonly bool _isFolderOnly;
|
|
private readonly bool _isShowRootNode;
|
|
private FileNode _currentFileNode;
|
|
private EditMode _editMode;
|
|
private readonly RecipeProvider _recipeProvider;
|
|
|
|
public ObservableCollection<string> Chambers { get; set; }
|
|
|
|
private RecipeData _currentRecipe;
|
|
public RecipeData CurrentRecipe
|
|
{
|
|
get => _currentRecipe;
|
|
set
|
|
{
|
|
_currentRecipe = value;
|
|
NotifyOfPropertyChange();
|
|
}
|
|
}
|
|
|
|
private RecipeData _currentRecipe2;
|
|
public RecipeData CurrentRecipe2
|
|
{
|
|
get => _currentRecipe2;
|
|
set
|
|
{
|
|
_currentRecipe2 = value;
|
|
NotifyOfPropertyChange();
|
|
}
|
|
}
|
|
|
|
private double[] _scrollviewerPositionOffset;
|
|
public double[] ScrollviewerPositionOffset2
|
|
{
|
|
get => _scrollviewerPositionOffset;
|
|
set
|
|
{
|
|
_scrollviewerPositionOffset = value;
|
|
NotifyOfPropertyChange();
|
|
}
|
|
}
|
|
|
|
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 RecipeComparViewModel()
|
|
{
|
|
_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(','));
|
|
}
|
|
|
|
//_loadRecipeHelp = new LoadRecipeHelp("PM1");
|
|
|
|
}
|
|
|
|
|
|
protected override void OnInitialize()
|
|
{
|
|
base.OnInitialize();
|
|
_roleManager.Initialize();
|
|
BuildFileTree(_isShowRootNode, _isFolderOnly, _fileTypes);
|
|
|
|
}
|
|
|
|
protected override void OnActivate()
|
|
{
|
|
UpdateRecipeFormat();
|
|
|
|
// 根据角色权限设置判断是否显示按钮。
|
|
//IsShowCellAccessPermEditButton = GetCapeModeButtonPerm();
|
|
//NotifyOfPropertyChange(nameof(IsShowCellAccessPermEditButton));
|
|
|
|
//UpdateView();
|
|
|
|
base.OnActivate();
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
public async void TreeSelectChanged(FileNode node)
|
|
{
|
|
//if (IsChanged)
|
|
//{
|
|
// var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No,
|
|
// DialogType.CONFIRM,
|
|
// $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
|
|
|
// if (selection == DialogButton.Yes)
|
|
// {
|
|
// CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
|
// CurrentRecipe.ReviseTime = DateTime.Now;
|
|
// Save(CurrentRecipe, false);
|
|
// }
|
|
//}
|
|
|
|
//CurrentFileNode = node;
|
|
|
|
//if (node != null && node.IsFile)
|
|
//{
|
|
// await LoadRecipe(node.PrefixPath, node.FullPath);
|
|
//}
|
|
//else
|
|
//{
|
|
// ClearData();
|
|
// //_editMode = EditMode.None;
|
|
//}
|
|
|
|
|
|
}
|
|
private void ClearData()
|
|
{
|
|
//_editMode = EditMode.None;
|
|
ClearData();
|
|
}
|
|
|
|
private async Task LoadRecipe(string prefixPath, string recipeName)
|
|
{
|
|
//IsLoading = true;
|
|
|
|
CurrentRecipe.Clear();
|
|
CurrentRecipe.Steps.Save(); // 重置为已保存状态
|
|
|
|
CurrentRecipe2.Clear();
|
|
CurrentRecipe2.Steps.Save(); // 重置为已保存状态
|
|
//ErrorsCount = 0;
|
|
//SelectRecipeNameList
|
|
|
|
string recipeName1 = SelectRecipeNameList[0].Name;
|
|
string recipeName2 = SelectRecipeNameList[1].Name;
|
|
|
|
var recipeContent1 = _recipeProvider.ReadRecipeFile(prefixPath, recipeName1);
|
|
var recipeContent2 = _recipeProvider.ReadRecipeFile(prefixPath, recipeName2);
|
|
|
|
|
|
if (string.IsNullOrEmpty(recipeContent1))
|
|
{
|
|
MessageBox.Show($"{prefixPath}\\{recipeName} is empty, please confirm the file is valid.",
|
|
"Error",
|
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
return;
|
|
}
|
|
|
|
await CurrentRecipe.LoadFile(prefixPath, recipeName1, recipeContent1, SelectedChamber,
|
|
GetLoadingDispatcher());
|
|
|
|
await CurrentRecipe2.LoadFile(prefixPath, recipeName2, recipeContent2, SelectedChamber,
|
|
GetLoadingDispatcher());
|
|
|
|
//_editMode = EditMode.Normal;
|
|
//IsLoading = false;
|
|
}
|
|
|
|
//private async Task LoadRecipe(string prefixPath, string recipeName)
|
|
//{
|
|
// //IsLoading = true;
|
|
|
|
// CurrentRecipe.Clear();
|
|
// CurrentRecipe.Steps.Save(); // 重置为已保存状态
|
|
|
|
// CurrentRecipe2.Clear();
|
|
// CurrentRecipe2.Steps.Save(); // 重置为已保存状态
|
|
// //ErrorsCount = 0;
|
|
// //SelectRecipeNameList
|
|
// 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;
|
|
// }
|
|
|
|
// await CurrentRecipe.LoadFile(prefixPath, recipeName, recipeContent, SelectedChamber,
|
|
// GetLoadingDispatcher());
|
|
|
|
// await CurrentRecipe2.LoadFile(prefixPath, recipeName, recipeContent, SelectedChamber,
|
|
// GetLoadingDispatcher());
|
|
|
|
// //_editMode = EditMode.Normal;
|
|
// //IsLoading = false;
|
|
//}
|
|
|
|
private static Dispatcher GetLoadingDispatcher()
|
|
{
|
|
// 判断Step呈现方式
|
|
var isCascadeLoading = (bool)QueryDataClient.Instance.Service.GetConfig("System.RecipeCascadeLoading");
|
|
var dispatcher = isCascadeLoading ? Dispatcher.CurrentDispatcher : null;
|
|
return dispatcher;
|
|
}
|
|
|
|
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
|
|
|
|
var recipeData = new RecipeData(CurrentProcessType);
|
|
recipeData.BuildFormat($"{CurrentChamberType}\\{CurrentProcessType}", SelectedChamber, BaseApp.Instance.UserContext.RoleName);
|
|
|
|
//得到当前登录的RoleItem
|
|
var role = _roleManager.GetRoleByName(BaseApp.Instance.UserContext.RoleName);
|
|
recipeData.ReloadRolePermission(role);
|
|
|
|
|
|
|
|
|
|
|
|
var recipeData2 = new RecipeData(CurrentProcessType);
|
|
recipeData2.BuildFormat($"{CurrentChamberType}\\{CurrentProcessType}", SelectedChamber, BaseApp.Instance.UserContext.RoleName);
|
|
|
|
//得到当前登录的RoleItem
|
|
var role2 = _roleManager.GetRoleByName(BaseApp.Instance.UserContext.RoleName);
|
|
recipeData2.ReloadRolePermission(role);
|
|
|
|
|
|
|
|
|
|
|
|
CurrentRecipe = recipeData;
|
|
CurrentRecipe2 = recipeData2;
|
|
#endregion
|
|
}
|
|
|
|
//public void TreeSelectChanged(FileNode file)
|
|
//{
|
|
// _currentFileNode = file;
|
|
//}
|
|
//public void TreeMouseDoubleClick(FileNode file)
|
|
//{
|
|
// DGAdd(file);
|
|
//}
|
|
|
|
//public void AddRecipeToCompar()
|
|
//{
|
|
// DGAdd(_currentFileNode);
|
|
//}
|
|
|
|
private void DGAdd(FileNode file)
|
|
{
|
|
if (SelectRecipeNameList == null)
|
|
SelectRecipeNameList = new ObservableCollection<FileNode>();
|
|
|
|
SelectRecipeNameList.Add(file);
|
|
}
|
|
|
|
//public void RemoveSelectRecipe()
|
|
//{
|
|
|
|
// var v = DGSelectRecipeName;
|
|
// SelectRecipeNameList.Remove(DGSelectRecipeName);
|
|
//}
|
|
//public void ClearSelectRecipe()
|
|
//{
|
|
// SelectRecipeNameList.Clear();
|
|
//}
|
|
|
|
public async void ComperSelectRecipe()
|
|
{
|
|
SelectRecipeNameList.Clear();
|
|
foreach (var ProcessTypeFile in ProcessTypeFileList)
|
|
{
|
|
foreach (var item in ProcessTypeFile.FileListByProcessType)
|
|
{
|
|
if (item.IsSelected)
|
|
SelectRecipeNameList.Add(item);
|
|
}
|
|
}
|
|
|
|
|
|
await LoadRecipe(SelectRecipeNameList[0].PrefixPath, SelectRecipeNameList[0].Name);
|
|
|
|
Start(CurrentRecipe, CurrentRecipe2);
|
|
}
|
|
|
|
public void Start(RecipeData recipeData1, RecipeData recipeData2)
|
|
{
|
|
RecipeStep v = CurrentRecipe.Steps[3];
|
|
|
|
|
|
int stepsCount = recipeData1.Steps.Count <= recipeData2.Steps.Count ? recipeData1.Steps.Count : recipeData2.Steps.Count;
|
|
|
|
for (int i = 0; i < stepsCount; i++)
|
|
{
|
|
|
|
|
|
RecipeStep step1 = recipeData1.Steps[i];
|
|
RecipeStep step2 = recipeData2.Steps[i];
|
|
|
|
|
|
for (int j = 0; j < step1.Count; j++)
|
|
{
|
|
object obj1= GetValue(step1[j]);
|
|
object obj2 = GetValue(step2[j]);
|
|
|
|
if ( !(Comparer<object>.Default.Compare(obj1, obj2) == 0) )
|
|
{
|
|
step1[j].Highlight();
|
|
step2[j].Highlight();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private object GetValue(Param param)
|
|
{
|
|
object Value = null;
|
|
if (param is IValueParam vp)
|
|
Value = vp.GetValue();
|
|
|
|
return Value;
|
|
|
|
|
|
}
|
|
}
|
|
}
|