首次提交:添加src文件夹代码

This commit is contained in:
2026-02-27 14:02:43 +08:00
commit d330cfbca7
4184 changed files with 5546478 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /></startup>
<entityFramework>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
<provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.EntityFramework, Version=8.0.28.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"></provider>
</providers>
</entityFramework>
<connectionStrings>
<add name="BakingEntities" connectionString="metadata=res://*/DBMappering.csdl|res://*/DBMappering.ssdl|res://*/DBMappering.msl;provider=MySql.Data.MySqlClient;provider connection string=&quot;server=127.0.0.1;user id=root;password=123456;Persist Security Info=True;AllowPublicKeyRetrieval=True;sslmode=none;database=6098-6&quot;" providerName="System.Data.EntityClient" />
</connectionStrings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Text.Encoding.CodePages" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="HandyControl" publicKeyToken="45be8712787a1e5b" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.5.1.0" newVersion="3.5.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="AvalonDock" publicKeyToken="3e4669d2f30244f4" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.72.1.0" newVersion="4.72.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

24
Cowain.Bake.Main/App.xaml Normal file
View File

@@ -0,0 +1,24 @@
<prism:PrismApplication x:Class="Cowain.Bake.Main.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Cowain.Bake.Main"
xmlns:prism="http://prismlibrary.com/">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!--HandyControl-->
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
<!--Fluent-->
<ResourceDictionary Source="pack://application:,,,/Fluent;component/Themes/Generic.xaml" />
<!--<ResourceDictionary Source="pack://application:,,,/Fluent;component/Themes/Themes/Light.Green.xaml" />-->
<!--<ResourceDictionary Source="pack://application:,,,/Fluent;component/Themes/Themes/Dark.Green.xaml" />-->
<!--AvalonDock-->
<ResourceDictionary Source="pack://application:,,,/AvalonDock.Themes.Aero;component/Theme.xaml"/>
<ResourceDictionary Source="/Cowain.Bake.Main;component/Views/ComboBoxDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</prism:PrismApplication>

View File

@@ -0,0 +1,274 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Interface;
using Cowain.Bake.Main.Station;
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;
using Prism.Unity;
using System.Threading.Tasks;
using System;
using System.Windows;
using Unity;
using Cowain.Bake.Common;
using Cowain.Bake.Main.Views;
using Cowain.Bake.Main.ViewModels;
using Cowain.Bake.Main.Common;
using Cowain.Bake.Communication.MOM;
using Cowain.Bake.Main.Models;
using System.Reflection;
using AutoUpdaterDotNET;
using System.Diagnostics;
using Prism.Services.Dialogs;
namespace Cowain.Bake.Main
{
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : PrismApplication
{
protected override Window CreateShell() //3
{
//UI线程未捕获异常处理事件
this.DispatcherUnhandledException += OnDispatcherUnhandledException;
//Task线程内未捕获异常处理事件
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
//多线程异常
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
this.Exit += App_Exit;
if (SettingProvider.Instance.AutoUpdate)
{
AutoUpdaterFun();
}
CheckExistProcess();
//IsAskPath(); //正式运行,要放开这,
return Container.Resolve<MainWindow>();
}
private void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
//通常全局异常捕捉的都是致命信息
LogHelper.Instance.GetCurrentClassFatal($"{e.Exception.StackTrace},{e.Exception.Message}");
}
public static Process GetRunningInstance()
{
Process current = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName(current.ProcessName);
foreach (Process process in processes)
{
if (process.Id != current.Id)
if (Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == current.MainModule.FileName)
return process;
}
return null;
}
bool CheckExistProcess()
{
Process instance = GetRunningInstance();
if (instance != null)//没有已经开启的实例
{
HandyControl.Controls.MessageBox.Warning("程序已在运行,若要重新运行程序请在后台关闭程序进程!", "警告");
Environment.Exit(0);
return true;
}
return false;
}
//是否要求路径运行
bool IsAskPath()
{
string path = System.AppDomain.CurrentDomain.BaseDirectory;
if (path.Contains(MyPath.MAIN_APP))
{
return true;
}
HandyControl.Controls.MessageBox.Warning($"程序必须放在[{ MyPath.MAIN_APP}]路径下运行!", "警告");
Environment.Exit(0);
return false;
}
private void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
// 处理未观察到的异常
Console.WriteLine("Unobserved task exception occurred: " + e.Exception);
LogHelper.Instance.GetCurrentClassFatal($"{e.Exception}");
// 获取异常的具体信息
if (e.Exception is AggregateException aggregateException)
{
foreach (var innerException in aggregateException.InnerExceptions)
{
LogHelper.Instance.GetCurrentClassFatal("Exception: " + innerException.Message);
LogHelper.Instance.GetCurrentClassFatal("StackTrace: " + innerException.StackTrace);
}
}
// 标记异常已被处理
e.SetObserved();
//LogHelper.Instance.GetCurrentClassFatal($"{e.Exception.StackTrace},{e.Exception.Message},{e.Exception.Source}");
}
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = e.ExceptionObject as Exception;
LogHelper.Instance.GetCurrentClassFatal($"{ex.StackTrace},{ex.Message}");
//记录dump文件
MiniDump.TryDump($"dumps\\CowainPreheat_{DateTime.Now.ToString("HH-mm-ss-ms")}.dmp");
}
private void App_Exit(object sender, ExitEventArgs e)
{
//程序退出时需要处理的业务
}
protected override void OnInitialized() //5
{
Container.Resolve<IDialogService>(); // 确保对话框服务已注册 20260121
var regionManager = Container.Resolve<IRegionManager>();
regionManager.RegisterViewWithRegion("MainHeaderRegion", typeof(Views.MainHeaderView));
regionManager.RegisterViewWithRegion("BasicInfoRegion", typeof(Views.BasicInfoView));
//regionManager.RegisterViewWithRegion("StationInfoRegion", typeof(EquipmentMonitorView));
Container.Resolve<MainRowDefinition>();
Container.Resolve<UploadMesStation>();
Container.Resolve<DataCollectStation>();
Container.Resolve<BakingStation>(); //加了他会实例化二次
Container.Resolve<AlarmStation>();
Container.Resolve<LoadingStation>();
Container.Resolve<UnLoadingStation>();
Container.Resolve<LifeCycleStation>();
Container.Resolve<TaskStation>();
Container.Resolve<MesCollectStation>();
base.OnInitialized();
regionManager.RegisterViewWithRegion("StationInfoRegion", typeof(EquipmentMonitorView)); //Loaded,会触发一次
if (!HslCommunication.Authorization.SetAuthorizationCode("ac963114-3a46-4444-9a16-080a0ce99535"))
{
LogHelper.Instance.Fatal("PLC授权失败", true);
}
}
protected override void InitializeShell(Window shell)
{
// 先打开登录窗口,如果登录成功,则打开主窗口
if (Container.Resolve<Cowain.Bake.UI.Home.Views.LoginView>().ShowDialog() == false) //4
{
Environment.Exit(0);
//Application.Current?.Shutdown();
}
else
{
base.InitializeShell(shell);
}
}
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) //2
{
// 可以改为自动扫描
moduleCatalog.AddModule<Bake.BLL.BLLModule>();
moduleCatalog.AddModule<Bake.UI.UI>();
moduleCatalog.AddModule<Bake.Communication.CommunicationModule>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry) //1
{
// 1. 把 Window 注册为“对话框外壳”——仅此一句
//containerRegistry.RegisterDialog<CavityDtlView, CavityDtlViewModel>();
//containerRegistry.RegisterDialog<MoistureValueView, MoistureValueViewMode>();
containerRegistry.RegisterSingleton<MainWindow>();
containerRegistry.RegisterSingleton<MemoryDataProvider>();
containerRegistry.RegisterSingleton<BasicInfoViewModel>();
containerRegistry.RegisterSingleton<EquipmentMonitorView>();
containerRegistry.RegisterSingleton<EquipmentMonitorViewModel>();
containerRegistry.RegisterSingleton<MainWindowViewModel>();
containerRegistry.RegisterSingleton<TaskStation>();
containerRegistry.RegisterSingleton<MainRowDefinition>();
containerRegistry.RegisterSingleton<Views.MainHeaderView>();
containerRegistry.RegisterSingleton<SettingProvider>();
containerRegistry.RegisterSingleton<UpdateStation>();
containerRegistry.RegisterSingleton<ITrigService, TrigStation>();
containerRegistry.RegisterSingleton<UploadMesStation>();
containerRegistry.RegisterSingleton<MESProcess>();
containerRegistry.RegisterSingleton<UploadMesStation>();
containerRegistry.RegisterSingleton<ICommonFun, ExecCommonFun>();
containerRegistry.RegisterSingleton<AlarmStation>();
containerRegistry.RegisterSingleton<DataCollectStation>();
//containerRegistry.RegisterSingleton<CavityDtlView>();
containerRegistry.RegisterSingleton<LoadingStation>();
containerRegistry.RegisterSingleton<UnLoadingStation>();
containerRegistry.RegisterSingleton<LifeCycleStation>();
containerRegistry.RegisterSingleton<CmdFactories>();
containerRegistry.RegisterSingleton<MesCollectStation>();
containerRegistry.RegisterSingleton<BakingStation>();
}
private void AutoUpdaterFun()
{
string updateXmlUrl = SettingProvider.Instance.AutoUpdateUrl; // 替换为你的实际 URL
//AutoUpdater.AppTitle = "我的WPF应用程序";
AutoUpdater.Start(updateXmlUrl);
//AutoUpdater.OpenDownloadPage = true; // 不打开浏览器
//AutoUpdater.UpdateMode = Mode.ForcedDownload; //常规模式,会显示标准更新对话框
//AutoUpdater.UpdateFormSize = new System.Drawing.Size(200, 100);
AutoUpdater.Mandatory = true; // 强制更新
AutoUpdater.ShowSkipButton = false; // 隐藏跳过按钮
AutoUpdater.ShowRemindLaterButton = false; // 隐藏稍后提醒按钮
// 事件订阅
AutoUpdater.CheckForUpdateEvent += OnCheckForUpdate;
AutoUpdater.ApplicationExitEvent += AutoUpdater_CheckForUpdateEvent;
}
private void AutoUpdater_CheckForUpdateEvent()
{
// 确保应用程序完全退出
System.Windows.Forms.Application.Exit();
}
private void OnCheckForUpdate(UpdateInfoEventArgs args)
{
if (args.Error != null)
{
if (args.Error is System.Net.WebException)
{
// 网络错误,稍后重试
LogHelper.Instance.Fatal("无法连接更新服务器,请检查网络连接", true);
}
return;
}
if (!args.IsUpdateAvailable)
{
LogHelper.Instance.Fatal($"当前已是最新版本,服务器版本:{args.CurrentVersion},本程序版本:{args.InstalledVersion},本程序版本:" +
Assembly.GetExecutingAssembly().GetName().Version);
return;
}
MessageBox.Show($"发现新版本,服务器版本:{args.CurrentVersion},本程序版本:" +
Assembly.GetExecutingAssembly().GetName().Version, "新版本", MessageBoxButton.OK, MessageBoxImage.Asterisk);
// 可以在这里添加自定义逻辑,比如备份配置文件等
//BackupApplicationFiles();
// 自动开始下载更新
try
{
AutoUpdater.DownloadUpdate(args);
Environment.Exit(0); //有用
}
catch (Exception ex)
{
LogHelper.Instance.Fatal($"下载更新失败: {ex.Message}", true);
}
}
}
}

View File

@@ -0,0 +1,244 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Communication.Interface;
using Cowain.Bake.Model;
using Cowain.Bake.Model.Models;
using HslCommunication;
using System.Linq;
using Unity;
namespace Cowain.Bake.Main.Common
{
public class CmdFactories
{
IUnityContainer _unityContainer { get; set; }
//IPLCDevice agv = null;
public CmdFactories(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
public bool StartBaking(IPLCDevice plc, int stationId, bool[] bakeEanble, bool manual = false)
{
if (!Write<bool[]>(plc, EStoveSignal.HeatEnableStep.ToString(), stationId, 1, bakeEanble).IsSuccess)
{
LogHelper.Instance.Error($"层烘烤使能失败plc:{plc.Name}", true);
return false;
}
if (!Write<bool>(plc, EStoveSignal.BakingStart.ToString(), stationId, 1, true).IsSuccess)
{
LogHelper.Instance.GetCurrentClassError($"下发开始烘烤失败plc:{plc.Name}", true);
return false;
}
if (manual)
{
LogHelper.Instance.Info($"下发开始烘烤成功!", true);
}
return true;
}
//public bool EndBaking(int stationId)
//{
// TDeviceConfig conf = _unityContainer.Resolve<DeviceConfigService>().GetConfig(stationId);
// IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(conf.Name);
// if (plc == null || !plc.IsConnect)
// {
// LogHelper.Instance.GetCurrentClassError($"连接PLC失败plc:{plc.Name}", true);
// return false;
// }
// if (!Write<bool>(plc, EStoveSignal.BakingEnd.ToString(), stationId, true).IsSuccess)
// {
// LogHelper.Instance.GetCurrentClassError($"下发结束烘烤失败plc:{plc.Name}", true);
// return false;
// }
// LogHelper.Instance.Info($"下发结束烘烤成功!", true);
// return true;
//}
//复位结束烘烤
public bool ResetEndBaking(int machineId)
{
TDeviceConfig conf = _unityContainer.Resolve<DeviceConfigService>().GetConfig(machineId);
IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(conf.Name);
if (plc == null || !plc.IsConnect)
{
LogHelper.Instance.GetCurrentClassError($"连接PLC失败plc:{plc.Name}", true);
return false;
}
if (!Write<bool>(plc, EStoveSignal.BakingMark.ToString(), machineId, 1, false).IsSuccess)
{
LogHelper.Instance.GetCurrentClassError($"下发复位结束烘烤失败plc:{plc.Name}", true);
return false;
}
return true;
}
public bool OpenDoor(int stationId, int layer)
{
TDeviceConfig fromDev = _unityContainer.Resolve<DeviceConfigService>().GetConfig(stationId);
IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(fromDev.Name);
if (plc == null || !plc.IsConnect)
{
LogHelper.Instance.GetCurrentClassError($"连接PLC失败plc:{plc.Name},layer:{layer}", true);
return false;
}
if (!CommonFun.Instance.IsStoveQualified(plc, stationId, layer, false, true)) //不在工作中
{
return false;
}
if (Write<bool>(plc, EStoveSignal.OpenDoor.ToString(), stationId,1, true).IsSuccess)
{
HandyControl.Controls.MessageBox.Show($@"下发开门指令成功!", "操作提示");
return false;
}
else
{
HandyControl.Controls.MessageBox.Error($@"下发开门指令失败。", "操作提示");
LogHelper.Instance.GetCurrentClassError($"下发开门指令失败plc:{plc.Name},layer:{layer}");
}
return true;
}
public bool CloseDoor(int machineId, int layer)
{
TDeviceConfig fromDev = _unityContainer.Resolve<DeviceConfigService>().GetConfig(machineId);
IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(fromDev.Name);
if (plc == null || !plc.IsConnect)
{
LogHelper.Instance.GetCurrentClassError($"连接PLC失败plc:{plc.Name},layer:{layer}", true);
return false;
}
if (!CommonFun.Instance.IsStoveQualified(plc, machineId, layer, false, true)) //不在工作中
{
return false;
}
if (Write<bool>(plc, EStoveSignal.CloseDoor.ToString(), machineId, 1, true).IsSuccess)
{
HandyControl.Controls.MessageBox.Show($@"下发关门指令成功!", "操作提示");
return true;
}
else
{
HandyControl.Controls.MessageBox.Error($@"下发关门指令失败。", "操作提示");
LogHelper.Instance.GetCurrentClassError($"下发关门指令失败plc:{plc.Name},layer:{layer}");
return false;
}
}
public bool InitStove(int stationId, int layer)
{
TDeviceConfig dev = _unityContainer.Resolve<DeviceConfigService>().GetConfig(stationId);
IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(dev.Name);
if (plc == null || !plc.IsConnect)
{
LogHelper.Instance.GetCurrentClassError($"连接PLC失败plc:{plc.Name}");
return false;
}
if (!CommonFun.Instance.IsStoveQualified(plc, stationId, layer, false, true)) //不在工作中
{
return false;
}
if (Write<bool>(plc, EStoveSignal.Initial.ToString(), stationId, 1, true).IsSuccess)
{
HandyControl.Controls.MessageBox.Show($@"下发初始化请求指令成功!", "操作提示");
return true;
}
else
{
HandyControl.Controls.MessageBox.Error($@"下发初始化请求指令失败。", "操作提示");
LogHelper.Instance.GetCurrentClassError($"下发初始化请求指令失败plc:{plc.Name}");
return false;
}
}
//public bool NotifyPLCHavePallet(int machineId, int layer, int number)
//{
// TDeviceConfig dev = _unityContainer.Resolve<DeviceConfigService>().GetConfig(machineId);
// IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(dev.Name);
// if (plc == null || !plc.IsConnect)
// {
// LogHelper.Instance.GetCurrentClassError($"连接PLC失败plc:{plc.Name},layer:{layer}");
// return false;
// }
// if (!CommonFun.Instance.IsStoveQualified(plc, machineId, layer))
// {
// return false;
// }
// string Tray = number == 1 ? EStoveSignal.Tray1.ToString() : EStoveSignal.Tray2.ToString();
// if (Write<bool>(plc, Tray, machineId,layer,true).IsSuccess)
// {
// HandyControl.Controls.MessageBox.Show($@"下发托盘记忆成功!", "操作提示");
// return true;
// }
// else
// {
// HandyControl.Controls.MessageBox.Error($@"下发托盘记忆失败。", "操作提示");
// LogHelper.Instance.GetCurrentClassError($"下发托盘记忆失败plc:{plc.Name},layer:{layer}");
// return false;
// }
//}
//public bool NotifyPLCDontHavePallet(int machineId, int layer, int number)
//{
// TDeviceConfig dev = _unityContainer.Resolve<DeviceConfigService>().GetConfig(machineId);
// IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(dev.Name);
// if (plc == null || !plc.IsConnect)
// {
// LogHelper.Instance.GetCurrentClassError($"连接PLC失败plc:{plc.Name},layer:{layer}");
// return false;
// }
// if (!CommonFun.Instance.IsStoveQualified(plc, machineId, layer))
// {
// return false;
// }
// string Tray = number == 1 ? EStoveSignal.Tray1.ToString() : EStoveSignal.Tray2.ToString();
// if (Write<bool>(plc, Tray, machineId, layer, false).IsSuccess)
// {
// HandyControl.Controls.MessageBox.Show($@"下发托盘记忆成功!", "操作提示");
// return true;
// }
// else
// {
// HandyControl.Controls.MessageBox.Error($@"下发清除托盘记忆失败。", "操作提示");
// LogHelper.Instance.GetCurrentClassError($"下发清除托盘记忆失败plc:{plc.Name},layer:{layer}");
// return false;
// }
//}
public OperateResult Write<T>(IPLCDevice plc, string paramName, int machineId, int layer, T data)
{
string nodeAddr = "";
OperateResult result = new OperateResult()
{
IsSuccess = false,
};
Variable node = null;
node = (from storage in plc.Storages
from item in storage.VariableList
where storage.StationId == machineId && item.ParamName == paramName && item.Number == layer
select item).FirstOrDefault();
if (null == node)
{
return result;
}
nodeAddr = $"{node.Address}{node.VarName}";
return plc.Write<T>(nodeAddr, data);
}
}
}

View File

@@ -0,0 +1,179 @@
using ControlzEx.Standard;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Communication.Interface;
using Cowain.Bake.Main.Models;
using Cowain.Bake.Main.Station;
using Cowain.Bake.Model.Models;
using HslCommunication;
using Opc.Ua;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Unity;
namespace Cowain.Bake.Main.Common
{
public class CommonFun
{
private static CommonFun instance;
public static CommonFun Instance
{
get
{
if (instance == null)
{
instance = new CommonFun();
}
return instance;
}
}
//public OperateResult Writes(IUnityContainer unityContainer, string reply, object[] values)
//{
// //string[] arrayAddress = reply.Address1.Split(',');
// //var plc = unityContainer.Resolve<IPLCDevice>(reply.PLCName);
// //EDataType dt = (EDataType)Enum.Parse(typeof(EDataType), reply.AddressType);
// //Type type = Type.GetType(dt.GetDescription());
// //var mi = this.GetType().GetMethod(ReflexFun.OPC_WRITE_NODES).MakeGenericMethod(new Type[] { type }); //反射;
// //return (OperateResult)mi.Invoke(this, new object[]
// //{
// // plc,
// // arrayAddress,
// // values
// //});
// return null;
//}
//public OperateResult Write(IUnityContainer unityContainer, string reply, object value)
//{
// //var plc = unityContainer.Resolve<IPLCDevice>(reply.PLCName);
// //EDataType dt = (EDataType)Enum.Parse(typeof(EDataType), reply.AddressType);
// //Type type = Type.GetType(dt.GetDescription());
// //var mi = this.GetType().GetMethod(ReflexFun.OPC_WRITE_NODE).MakeGenericMethod(new Type[] { type }); //反射;
// //return (OperateResult)mi.Invoke(this, new object[]
// //{
// // plc,
// // reply.Address,
// // value
// //});
// return null;
//}
//烘箱是否具备条件
public bool IsStoveQualified(IPLCDevice plc, int machineId, int layer, bool isWork, bool popupScreen = false) //popupScreen:人工下发指令要弹屏
{
//远程/本地模式
var mode = plc.GetValue<bool>(EStoveSignal.Remote.ToString(), machineId, layer);
if (!mode.IsSuccess) //本地
{
//LogHelper.Instance.Error("读取远程模式失败或本地模式!", null, true);
return false ;
}
if (!mode.Content) //true:远程, false:本地
{
if (popupScreen)
{
LogHelper.Instance.Error("本地模式,不能执行指令操作!", true);
}
//return false; //add by lsm 20250926 test
}
//0 / 空闲 1 / 待机 2 / 停止 3 / 工作 4 / 保压
var workStatus = plc.GetValue<Int16>(EStoveSignal.CavityStatus.ToString(), machineId, layer);
if (!workStatus.IsSuccess) //系统状态寄存器
{
if (popupScreen)
{
LogHelper.Instance.Error("读取烘箱工作状态失败!", true);
}
return false ;
}
if (isWork) //
{
if ((int)EStoveWorkMode.Standby >= workStatus.Content) //工作当中判断,0,1
{
if (popupScreen)
{
LogHelper.Instance.Error("判断要在工作当中,却为空闲,所以不满足条件执行!");
}
return false;
}
}
else //要求不是工作状态
{
if ((int)EStoveWorkMode.Standby < workStatus.Content) //非工作当中判断,2,3,4
{
if (popupScreen)
{
LogHelper.Instance.Error("判断要在空闲当中,却为工作,所以不满足条件执行!");
}
return false;
}
}
return true;
}
public bool IsStoveQualified(IPLCDevice plc, int machineId, int layer)
{
//远程/本地模式 var mode = plc.GetValue<bool>(EStoveSignal.CavityStatus.ToString(), item.Key, layer);
var mode = plc.GetValue<bool>(EStoveSignal.Remote.ToString(), machineId, layer);
if (!mode.IsSuccess) //本地
{
LogHelper.Instance.Error("读取远程模式失败或本地模式!", true);
return false;
}
if (!mode.Content) //true:远程, false:本地
{
LogHelper.Instance.Error("本地模式,不能执行其操作!", true);
return false;
}
return true;
}
//发送一个节点,数据可以是单个,也可以是数组
//public OperateResult WriteNode<T>(IPLCDevice plc, string address, object value)
//{
// if (value is Array)
// {
// T[] t = (T[])Convert.ChangeType(value, typeof(T[]));
// return plc.Write<T[]>(address, t);
// }
// else
// {
// T t = (T)Convert.ChangeType(value, typeof(T));
// return plc.Write<T>(address, t);
// }
//}
//public OperateResult WriteNodes<T>(IPLCDevice plc, string[] tags, object[] values)
//{
// //T t = (T)Convert.ChangeType(value, typeof(T));
// return plc.Writes(tags, values);
//}
public float[] UShortToFloat(Int16[] datas)
{
List<float> f = new List<float>();
for (int i = 1; i < datas.Count(); i++)
{
f.Add(datas[i] / 1.0f / 100);
}
return f.ToArray();
}
}
}

View File

@@ -0,0 +1,79 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Interface;
using Cowain.Bake.Communication.MOM;
using Cowain.Bake.Main.Station;
using Cowain.Bake.Main.ViewModels;
using Cowain.Bake.Main.Views;
using Cowain.Bake.Model;
using System.Collections.Generic;
using System.Linq;
using Unity;
using JSON = Newtonsoft.Json.JsonConvert;
using static Cowain.Bake.Common.Models.MESModel;
namespace Cowain.Bake.Main.Common
{
public class ExecCommonFun : ICommonFun
{
readonly IUnityContainer _unityContainer;
public ExecCommonFun(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
public void ModifyOrderNum()
{
var basicInfoViewModel = _unityContainer.Resolve<BasicInfoViewModel>();
var memory = _unityContainer.Resolve<MemoryDataProvider>();
basicInfoViewModel.CurrentJobNum = memory.CurrentUser.JobNum;
basicInfoViewModel.CurrentOperation = memory.CurrentUser.ProcessParamName;
SettingProvider.Instance.WaterPallet = 0;
}
public bool ManualTaskCmd(TTaskRecord task, short stepId)
{
return _unityContainer.Resolve<TaskStation>().ManualTaskCmd(task, stepId); //发送
}
public void InitWindows()
{
_unityContainer.Resolve<MainHeaderView>().ClearWindows(); //
_unityContainer.Resolve<MainHeaderView>().Init(); //
}
public void SetBatteryCodeLen()
{
_unityContainer.Resolve<LoadingStation>().SetBatteryCodeLen(); //
}
public string ManualMesOutUnBinding(TPalletInfo palletInfo, TBatteryInfo battery)
{
string msg = "";
List<TBatteryInfo> betterys = new List<TBatteryInfo>() ;
betterys.Add(battery);
var mesResult = _unityContainer.Resolve<UnLoadingStation>().MesOutUnBinding(palletInfo, betterys, true);
if (mesResult == null)
{
msg = $"出站MOM返回超时,电芯条码:{string.Join(",", betterys.Select(x => x.BatteryCode).ToList())}";
LogHelper.Instance.Error(msg); //偶尔会返回空,
}
else if (mesResult.Info.ResultFlag.ToUpper() == "NG")
{
msg = $"出站MOM返回信息异常,信息:{JSON.SerializeObject(mesResult)}";
}
else
{
msg = $"信息:{JSON.SerializeObject(mesResult)}";
}
return msg;
}
public MESReturnCmdModel SendData(string info)
{
return _unityContainer.Resolve<MESProcess>().SendData(info); //发送
}
}
}

View File

@@ -0,0 +1,106 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Main.Station;
using Cowain.Bake.Main.ViewModels;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity;
namespace Cowain.Bake.Main.Common
{
public class HeaderCMD
{
private readonly IUnityContainer _unityContainer;
public HeaderCMD(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
//_basicInfo = basicInfo;
}
public void Auto(string JSON)
{
Views.MainHeaderView.ribbonButtonDic["Auto"].IsEnabled = false;
Views.MainHeaderView.ribbonButtonDic["Manual"].IsEnabled = true;
Bake.Common.Core.SettingProvider.Instance.DispMode = EDispatchMode.Auto;
HandyControl.Controls.MessageBox.Success("自动调度", "切换调度模式");
_unityContainer.Resolve<TaskStation>()._newTaskEvent.Set();
_unityContainer.Resolve<BasicInfoViewModel>().DispMode= EDispatchMode.Auto.GetDescription();
}
public void Manual(string JSON)
{
if (System.Windows.MessageBoxResult.OK ==HandyControl.Controls.MessageBox.Ask("调度机器人将停下来,您确定手动调度?", "切换调度模式"))
{
Views.MainHeaderView.ribbonButtonDic["Manual"].IsEnabled = false;
Views.MainHeaderView.ribbonButtonDic["Auto"].IsEnabled = true;
Bake.Common.Core.SettingProvider.Instance.DispMode = EDispatchMode.Manual;
_unityContainer.Resolve<BasicInfoViewModel>().DispMode = EDispatchMode.Manual.GetDescription();
}
}
public void ScanCodeMode(string JSON)
{
string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name;
UpdateSwitch(JSON, Cowain.Bake.Common.Enums.ESysSetup.ScanCodeMode.ToString(), methodName);
_unityContainer.Resolve<LogService>().AddLog($@"切换【{Cowain.Bake.Common.Enums.ESysSetup.ScanCodeMode.GetDescription()}】!", E_LogType.Operate.ToString());
}
private bool UpdateSwitch(string JSON, string paraID, string methodName)
{
DataTable table = _unityContainer.Resolve<Cowain.Bake.BLL.MenuInfoService>().GetLabelName(methodName);
string labelName = table.Rows[0]["Header"].ToString();
var service = _unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>();
if (Views.MainHeaderView.toggleButtonLabelDic[labelName].Content.ToString()
== table.Rows[0]["Value0"].ToString())
{
Views.MainHeaderView.toggleButtonLabelDic[labelName].Content = table.Rows[0]["Value1"].ToString();
return service.UpdateValue(paraID, "1");
}
else
{
Views.MainHeaderView.toggleButtonLabelDic[labelName].Content = table.Rows[0]["Value0"].ToString();
return service.UpdateValue(paraID, "0");
}
}
public void DebugMode(string JSON)
{
string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name;
DataTable table = _unityContainer.Resolve<Cowain.Bake.BLL.MenuInfoService>().GetLabelName(methodName);
string labelName = table.Rows[0]["Header"].ToString();
if (Views.MainHeaderView.toggleButtonLabelDic[labelName].Content.ToString()
== table.Rows[0]["Value0"].ToString())
{
Views.MainHeaderView.toggleButtonLabelDic[labelName].Content = table.Rows[0]["Value1"].ToString();
_unityContainer.Resolve<BLL.SysSetupService>().UpdateValue(ESysSetup.DebugMode.ToString(), ((int)EProductionMode.Normal).ToString());
}
else
{
Views.MainHeaderView.toggleButtonLabelDic[labelName].Content = table.Rows[0]["Value0"].ToString();
_unityContainer.Resolve<BLL.SysSetupService>().UpdateValue(ESysSetup.DebugMode.ToString(), ((int)EProductionMode.Debug).ToString());
}
}
public void MOMEnable(string JSON)
{
string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name;
DataTable table = _unityContainer.Resolve<Cowain.Bake.BLL.MenuInfoService>().GetLabelName(methodName);
string labelName = table.Rows[0]["Header"].ToString();
if (Views.MainHeaderView.toggleButtonLabelDic[labelName].Content.ToString()
== table.Rows[0]["Value0"].ToString())
{
Views.MainHeaderView.toggleButtonLabelDic[labelName].Content = table.Rows[0]["Value1"].ToString();
_unityContainer.Resolve<BLL.SysSetupService>().UpdateValue(ESysSetup.MOMEnable.ToString(), ((int)EMOMEnable.Enable).ToString());
}
else
{
Views.MainHeaderView.toggleButtonLabelDic[labelName].Content = table.Rows[0]["Value0"].ToString();
_unityContainer.Resolve<BLL.SysSetupService>().UpdateValue(ESysSetup.MOMEnable.ToString(), ((int)EMOMEnable.Disable).ToString());
}
}
}
}

View File

@@ -0,0 +1,392 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8E1456EF-EDF6-4DC3-BF95-62655997D912}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>Cowain.Bake.Main</RootNamespace>
<AssemblyName>Cowain.Bake.Main</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>cowain.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="AutoUpdater.NET, Version=1.9.2.0, Culture=neutral, PublicKeyToken=501435c91b35f4bc, processorArchitecture=MSIL">
<HintPath>..\packages\Autoupdater.NET.Official.1.9.2\lib\net462\AutoUpdater.NET.dll</HintPath>
</Reference>
<Reference Include="AvalonDock, Version=4.72.1.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
<HintPath>..\packages\Dirkster.AvalonDock.4.72.1\lib\net40\AvalonDock.dll</HintPath>
</Reference>
<Reference Include="AvalonDock.Themes.Aero, Version=4.72.1.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
<HintPath>..\packages\Dirkster.AvalonDock.Themes.Aero.4.72.1\lib\net40\AvalonDock.Themes.Aero.dll</HintPath>
</Reference>
<Reference Include="AvalonDock.Themes.Expression, Version=4.72.1.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
<HintPath>..\packages\Dirkster.AvalonDock.Themes.Expression.4.72.1\lib\net40\AvalonDock.Themes.Expression.dll</HintPath>
</Reference>
<Reference Include="AvalonDock.Themes.Metro, Version=4.71.2.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
<HintPath>..\packages\Dirkster.AvalonDock.Themes.Metro.4.71.2\lib\net40\AvalonDock.Themes.Metro.dll</HintPath>
</Reference>
<Reference Include="AvalonDock.Themes.VS2013, Version=4.72.1.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
<HintPath>..\packages\Dirkster.AvalonDock.Themes.VS2013.4.72.1\lib\net40\AvalonDock.Themes.VS2013.dll</HintPath>
</Reference>
<Reference Include="ControlzEx, Version=5.0.0.0, Culture=neutral, PublicKeyToken=69f1c32f803d307e, processorArchitecture=MSIL">
<HintPath>..\packages\ControlzEx.5.0.1\lib\net462\ControlzEx.dll</HintPath>
</Reference>
<Reference Include="Cowain.Bake.BLL">
<HintPath>..\Cowain.Bake.BLL\bin\Debug\Cowain.Bake.BLL.dll</HintPath>
</Reference>
<Reference Include="Cowain.Bake.Common">
<HintPath>..\Cowain.Bake.Common\bin\Debug\Cowain.Bake.Common.dll</HintPath>
</Reference>
<Reference Include="Cowain.Bake.Communication">
<HintPath>..\Cowain.Bake.Communication\bin\Debug\Cowain.Bake.Communication.dll</HintPath>
</Reference>
<Reference Include="Cowain.Bake.Model">
<HintPath>..\Cowain.Bake.Model\bin\Debug\Cowain.Bake.Model.dll</HintPath>
</Reference>
<Reference Include="Cowain.Bake.UI">
<HintPath>..\Cowain.Bake.UI\bin\Debug\Cowain.Bake.UI.dll</HintPath>
</Reference>
<Reference Include="CsvHelper">
<HintPath>..\Libs\CsvHelper.dll</HintPath>
</Reference>
<Reference Include="Fluent, Version=9.0.0.0, Culture=neutral, PublicKeyToken=3e436e32a8c5546f, processorArchitecture=MSIL">
<HintPath>..\packages\Fluent.Ribbon.9.0.4\lib\net462\Fluent.dll</HintPath>
</Reference>
<Reference Include="Google.Protobuf, Version=3.14.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
<HintPath>..\packages\Google.Protobuf.3.14.0\lib\net45\Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="HandyControl, Version=3.5.1.0, Culture=neutral, PublicKeyToken=45be8712787a1e5b, processorArchitecture=MSIL">
<HintPath>..\packages\HandyControl.3.5.1\lib\net472\HandyControl.dll</HintPath>
</Reference>
<Reference Include="HslCommunication">
<HintPath>..\Libs\HslCommunication.dll</HintPath>
</Reference>
<Reference Include="K4os.Compression.LZ4, Version=1.2.6.0, Culture=neutral, PublicKeyToken=2186fa9121ef231d, processorArchitecture=MSIL">
<HintPath>..\packages\K4os.Compression.LZ4.1.2.6\lib\net46\K4os.Compression.LZ4.dll</HintPath>
</Reference>
<Reference Include="K4os.Compression.LZ4.Streams, Version=1.2.6.0, Culture=neutral, PublicKeyToken=2186fa9121ef231d, processorArchitecture=MSIL">
<HintPath>..\packages\K4os.Compression.LZ4.Streams.1.2.6\lib\net46\K4os.Compression.LZ4.Streams.dll</HintPath>
</Reference>
<Reference Include="K4os.Hash.xxHash, Version=1.0.6.0, Culture=neutral, PublicKeyToken=32cd54395057cec3, processorArchitecture=MSIL">
<HintPath>..\packages\K4os.Hash.xxHash.1.0.6\lib\net46\K4os.Hash.xxHash.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.7.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.HashCode">
<HintPath>..\Libs\Microsoft.Bcl.HashCode.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="Microsoft.Web.WebView2.Core, Version=1.0.2592.51, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.2592.51\lib\net462\Microsoft.Web.WebView2.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.WebView2.WinForms, Version=1.0.2592.51, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.2592.51\lib\net462\Microsoft.Web.WebView2.WinForms.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.WebView2.Wpf, Version=1.0.2592.51, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.2592.51\lib\net462\Microsoft.Web.WebView2.Wpf.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Xaml.Behaviors, Version=1.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Xaml.Behaviors.Wpf.1.1.31\lib\net45\Microsoft.Xaml.Behaviors.dll</HintPath>
</Reference>
<Reference Include="MySql.Data, Version=8.0.28.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libs\MySql.Data.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Opc.Ua.Core">
<HintPath>..\Libs\Opc.Ua.Core.dll</HintPath>
</Reference>
<Reference Include="Prism">
<HintPath>..\Libs\Prism.dll</HintPath>
</Reference>
<Reference Include="Prism.Unity.Wpf">
<HintPath>..\Libs\Prism.Unity.Wpf.dll</HintPath>
</Reference>
<Reference Include="Prism.Wpf">
<HintPath>..\Libs\Prism.Wpf.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Configuration" />
<Reference Include="System.Configuration.Install" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Text.Encodings.Web, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encodings.Web.7.0.0\lib\net462\System.Text.Encodings.Web.dll</HintPath>
</Reference>
<Reference Include="System.Text.Json, Version=7.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Json.7.0.2\lib\net462\System.Text.Json.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Transactions" />
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="Ubiety.Dns.Core, Version=2.2.1.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libs\Ubiety.Dns.Core.dll</HintPath>
</Reference>
<Reference Include="UIAutomationProvider" />
<Reference Include="UIAutomationTypes" />
<Reference Include="Unity.Abstractions, Version=5.11.7.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0, processorArchitecture=MSIL">
<HintPath>..\packages\Unity.Abstractions.5.11.7\lib\net47\Unity.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Unity.Container, Version=5.11.11.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0, processorArchitecture=MSIL">
<HintPath>..\packages\Unity.Container.5.11.11\lib\net47\Unity.Container.dll</HintPath>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="WindowsFormsIntegration" />
<Reference Include="ZstdNet, Version=1.4.5.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libs\ZstdNet.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Common\CmdFactories.cs" />
<Compile Include="Common\CommonFun.cs" />
<Compile Include="Common\ExecCommonFun.cs" />
<Compile Include="Common\HeaderCMD.cs" />
<Compile Include="Models\LogModel.cs" />
<Compile Include="Models\MainHeaderModel.cs" />
<Compile Include="Models\MainRowDefinition.cs" />
<Compile Include="Models\MultiComboBox.cs" />
<Compile Include="Models\PallletTemp.cs" />
<Compile Include="Station\AlarmStation.cs" />
<Compile Include="Station\BakingStation.cs" />
<Compile Include="Station\DataCollectStation.cs" />
<Compile Include="Station\LifeCycleStation.cs" />
<Compile Include="Station\MesCollectStation.cs" />
<Compile Include="Station\LoadingStation.cs" />
<Compile Include="Station\StoveProcessParam.cs" />
<Compile Include="Station\TaskStation.cs" />
<Compile Include="Station\TrigStation.cs" />
<Compile Include="Station\UnLoadingStation.cs" />
<Compile Include="Station\UpdateStation.cs" />
<Compile Include="Station\UploadMesStation.cs" />
<Compile Include="ViewModels\AddBatteryViewModel.cs" />
<Compile Include="ViewModels\BasicInfoViewModel.cs" />
<Compile Include="ViewModels\EquipmentMonitorViewModel.cs" />
<Compile Include="ViewModels\MainWindowViewModel.cs" />
<Compile Include="ViewModels\ManualTaskViewModel.cs" />
<Compile Include="ViewModels\MoistureValueViewMode.cs" />
<Compile Include="ViewModels\CavityDtlViewModel.cs" />
<Compile Include="ViewModels\PalletIdInputWindowViewModel.cs" />
<Compile Include="Views\AddBatteryView.xaml.cs">
<DependentUpon>AddBatteryView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\BasicInfoView.xaml.cs">
<DependentUpon>BasicInfoView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CavityDtlView.xaml.cs">
<DependentUpon>CavityDtlView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\EquipmentMonitorView.xaml.cs">
<DependentUpon>EquipmentMonitorView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\LogManagement.xaml.cs">
<DependentUpon>LogManagement.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ManualTask.xaml.cs">
<DependentUpon>ManualTask.xaml</DependentUpon>
</Compile>
<Compile Include="Views\MoistureValueView.xaml.cs">
<DependentUpon>MoistureValueView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\PalletIdInputWindow.xaml.cs">
<DependentUpon>PalletIdInputWindow.xaml</DependentUpon>
</Compile>
<Page Include="Views\AddBatteryView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\BasicInfoView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CavityDtlView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\ComboBoxDictionary.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\EquipmentMonitorView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\LogManagement.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\MainHeaderView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Models\MenuItemModel.cs" />
<Compile Include="ViewModels\MainHeaderViewModel.cs" />
<Compile Include="Views\MainHeaderView.xaml.cs">
<DependentUpon>MainHeaderView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="Views\ManualTask.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\MoistureValueView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\PalletIdInputWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Resource Include="Images\Images\Navigation\Backward_16x16.png" />
<Resource Include="Images\Images\Navigation\Backward_32x32.png" />
<Resource Include="Images\Images\Navigation\DocumentMap_16x16.png" />
<Resource Include="Images\Images\Navigation\DocumentMap_32x32.png" />
<Resource Include="Images\Images\Navigation\Forward_16x16.png" />
<Resource Include="Images\Images\Navigation\Forward_32x32.png" />
<Resource Include="Images\Images\Navigation\Home_16x16.png" />
<Resource Include="Images\Images\Navigation\Home_32x32.png" />
<Resource Include="Images\Images\Navigation\NavigationBar_16x16.png" />
<Resource Include="Images\Images\Navigation\NavigationBar_32x32.png" />
<Resource Include="Images\Images\Navigation\Next_16x16.png" />
<Resource Include="Images\Images\Navigation\Next_32x32.png" />
<Resource Include="Images\Images\Navigation\Previous_16x16.png" />
<Resource Include="Images\Images\Navigation\Previous_32x32.png" />
<Resource Include="Images\Images\Navigation\Up_16x16.png" />
<Resource Include="Images\Images\Navigation\Up_32x32.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="cowain.ico" />
</ItemGroup>
<ItemGroup>
<Resource Include="Images\png\RgvError.png" />
<Resource Include="Images\png\RgvMove.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Images\png\RgvWait.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Microsoft.Web.WebView2.1.0.2592.51\build\Microsoft.Web.WebView2.targets" Condition="Exists('..\packages\Microsoft.Web.WebView2.1.0.2592.51\build\Microsoft.Web.WebView2.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Web.WebView2.1.0.2592.51\build\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Web.WebView2.1.0.2592.51\build\Microsoft.Web.WebView2.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectView>ProjectFiles</ProjectView>
</PropertyGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1000 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 856 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1002 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 842 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -0,0 +1,50 @@
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Cowain.Bake.Main.Models
{
public class LogModel : BindableBase
{
private DateTime logTime;
/// <summary>
/// 日志时间
/// </summary>
public DateTime LogTime
{
get => logTime;
set => SetProperty(ref logTime, value);
}
private string logText;
/// <summary>
/// 日志内容
/// </summary>
public string LogText
{
get => logText;
set => SetProperty(ref logText, value);
}
private string logLevel;
/// <summary>
/// 日志等级
/// </summary>
public string LogLevel
{
get => logLevel;
set => SetProperty(ref logLevel, value);
}
private string fontColor;
/// <summary>
/// 日志等级字体颜色
/// </summary>
public string FontColor
{
get => fontColor;
set => SetProperty(ref fontColor, value);
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Cowain.Bake.Main.Models
{
public class RibbonMenuModel
{
public string Name { get; set; }
public string GroupName { get; set; }
public double MenuWidth { get; set; }
public string Content { get; set; }
public string Header { get; set; }
public string FilePath { get; set; }
}
}

View File

@@ -0,0 +1,25 @@
using Cowain.Bake.BLL;
using System.Linq;
using Unity;
namespace Cowain.Bake.Main.Models
{
public class MainRowDefinition
{
public static float UpperSpacing = 6;
public static float UpperHeight = 0;
public static float MidHeight = 3;
public static float LowerHeight = 0;
public static float LowerSpacing = 1.5f;
public static float TotalHeight = 0;
public MainRowDefinition(IUnityContainer unityContainer)
{
var memory = unityContainer.Resolve<MemoryDataProvider>();
UpperHeight = memory.AllStation.Where(x => x.PosX == 1).Max(x => x.Layers)+1;
LowerHeight = memory.AllStation.Where(x => x.PosX == 3).Max(x => x.Layers)+1; //1:就是抬头
TotalHeight = UpperSpacing + LowerSpacing + UpperHeight + LowerHeight + MidHeight;
}
}
}

View File

@@ -0,0 +1,58 @@
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Cowain.Bake.Main.Models
{
public class MenuItemModel : BindableBase
{
public string MenuIcon { get; set; }
public string MenuHeader { get; set; }
public string HeaderName { get; set; }
public string TargetView { get; set; }
private bool isExpanded;
public bool IsExpanded
{
get { return isExpanded; }
set { SetProperty(ref isExpanded, value); }
}
private bool isDefault;
public bool IsDefault
{
get { return isDefault; }
set { SetProperty(ref isDefault, value); }
}
public List<MenuItemModel> Children { get; set; }
public ICommand OpenViewCommand
{
get => new DelegateCommand(() =>
{
if ((this.Children == null || this.Children.Count == 0) &&
!string.IsNullOrEmpty(this.TargetView))
{
// 页面跳转 使用IRegionManager.RequestNavigate()跳转到目标页面
_regionManager.RequestNavigate("MainContentRegion", this.TargetView);
}
else
this.IsExpanded = !this.IsExpanded;
});
}
IRegionManager _regionManager = null;
public MenuItemModel(IRegionManager regionManager)
{
_regionManager = regionManager;
}
}
}

View File

@@ -0,0 +1,127 @@
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;
namespace Cowain.Bake.Main.Views
{
public class MultiComboBox:ComboBox
{
static MultiComboBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiComboBox), new FrameworkPropertyMetadata(typeof(MultiComboBox)));
}
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.SetValue(e.Property, e.NewValue);
}
/// <summary>
/// 选中项列表
/// </summary>
public ObservableCollection<MultiCbxBaseData> ChekedItems = new ObservableCollection<MultiCbxBaseData>();
/// <summary>
/// ListBox竖向列表
/// </summary>
private ListBox _ListBoxV;
/// <summary>
/// ListBox横向列表
/// </summary>
private ListBox _ListBoxH;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_ListBoxV = Template.FindName("PART_ListBox", this) as ListBox;
_ListBoxH = Template.FindName("PART_ListBoxChk", this) as ListBox;
_ListBoxH.ItemsSource = ChekedItems;
_ListBoxV.SelectionChanged += _ListBoxV_SelectionChanged;
_ListBoxH.SelectionChanged += _ListBoxH_SelectionChanged;
if (ItemsSource != null)
{
foreach (var item in ItemsSource)
{
MultiCbxBaseData bdc = item as MultiCbxBaseData;
if (bdc.IsCheck)
{
_ListBoxV.SelectedItems.Add(bdc);
}
}
}
}
private void _ListBoxH_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.RemovedItems)
{
MultiCbxBaseData datachk = item as MultiCbxBaseData;
for (int i = 0; i < _ListBoxV.SelectedItems.Count; i++)
{
MultiCbxBaseData datachklist = _ListBoxV.SelectedItems[i] as MultiCbxBaseData;
if (datachklist.Id == datachk.Id)
{
_ListBoxV.SelectedItems.Remove(_ListBoxV.SelectedItems[i]);
}
}
}
}
void _ListBoxV_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.AddedItems)
{
MultiCbxBaseData datachk = item as MultiCbxBaseData;
datachk.IsCheck = true;
if (ChekedItems.IndexOf(datachk) < 0)
{
ChekedItems.Add(datachk);
}
}
foreach (var item in e.RemovedItems)
{
MultiCbxBaseData datachk = item as MultiCbxBaseData;
datachk.IsCheck = false;
ChekedItems.Remove(datachk);
}
}
public class MultiCbxBaseData
{
private int _id;
public int Id
{
get { return _id; }
set { _id = value; }
}
private string _viewName;
public string ViewName
{
get { return _viewName; }
set
{
_viewName = value;
}
}
private bool _isCheck;
/// <summary>
/// 是否选中
/// </summary>
public bool IsCheck
{
get { return _isCheck; }
set { _isCheck = value; }
}
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Cowain.Bake.Main.Common
{
public class PallletTemp
{
public string HeadName { set; get; }
public float Value { set; get; }
}
}

View File

@@ -0,0 +1,55 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("Cowain.Bake")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Cowain.Bake")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
//若要开始生成可本地化的应用程序,请设置
//.csproj 文件中的 <UICulture>CultureYouAreCodingWith</UICulture>
//例如,如果您在源文件中使用的是美国英语,
//使用的是美国英语,请将 <UICulture> 设置为 en-US。 然后取消
//对以下 NeutralResourceLanguage 特性的注释。 更新
//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //主题特定资源词典所处位置
//(未在页面中找到资源时使用,
//或应用程序资源字典中找到时使用)
ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
//(未在页面中找到资源时使用,
//、应用程序或任何主题专用资源字典中找到时使用)
)]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.1")]
[assembly: AssemblyFileVersion("1.0.0.1")]

View File

@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Cowain.Bake.Main.Properties {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Cowain.Bake.Main.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Cowain.Bake.Main.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -0,0 +1,190 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Common.Interface;
using Cowain.Bake.Communication.MOM;
using Cowain.Bake.Model;
using Cowain.Bake.Model.Models;
using Opc.Ua;
using Prism.Ioc;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Unity;
using JSON = Newtonsoft.Json.JsonConvert;
using static Cowain.Bake.Common.Models.MESModel;
namespace Cowain.Bake.Main.Station
{
public class AlarmStation : IServerManager
{
readonly ConcurrentDictionary<string, bool[]> _alarmValues;
public string Name { get; set; } = "";
List<TAlarm> _allAlarms { get; set; } //ConcurrentBag //验证如果还报线程问题就用ConcurrentBag
List<TAlarmContent> _allAlarmContent { get; set; }
public IUnityContainer _unityContainer { get; set; }
List<AlertInfoModel> _arrayAlert = new List<AlertInfoModel>();
private readonly Prism.Events.IEventAggregator _eventAggregator;
readonly static object _objLock = new object();
public AlarmStation(IUnityContainer unityContainer, Prism.Events.IEventAggregator eventAggregator)
{
_unityContainer = unityContainer;
_alarmValues = new ConcurrentDictionary<string, bool[]>();
_eventAggregator = eventAggregator;
Start();
}
public void Start()
{
_allAlarms = _unityContainer.Resolve<AlarmService>().GetAllInAlarms();
_allAlarmContent = _unityContainer.Resolve<AlarmContentService>().GetAll();
foreach(var item in _allAlarms)
{
_eventAggregator.GetEvent<AlarmAddEvent>().Publish(item);//2.界面刷新,发布事件(发送消息)
}
}
//报警可能是一个数组TAlarmContent也可能是一个点(TTagList)。
public void AlarmInfo(DataValue data, Variable node)
{
if (1 == data.WrappedValue.TypeInfo.ValueRank) //数组
{
lock (_objLock)
{
AlarmArray(data, node); //会导致恢复后,一条报警信息会显示二次
}
}
else
{
LogHelper.Instance.Warn("没有单个数据报警!");
}
}
public TAlarmContent GetAlarmContent(int nodeId, int offset)
{
return _allAlarmContent.Where(m => m.Offset == offset
&& m.TagIds.Split(',').Any(x => x == nodeId.ToString())
&& !string.IsNullOrEmpty(m.Desc)).FirstOrDefault();
}
AlertInfoModel AssembleAlertModel(int code, string reset, string message)
{
return new AlertInfoModel()
{
AlertCode = code.ToString(),
AlertReset = reset,
AlertMessage = message,
};
}
//一个数组报警(订阅的是一个数组) --TAlarmContent
private void AlarmArray(DataValue data, Variable node)
{
string key = "";
_arrayAlert.Clear();
bool[] value = data.WrappedValue.Value as bool[];
if (data.WrappedValue.Value is bool[] v)
{
value = v;
}
else
{
LogHelper.Instance.Warn($"数组报警类型异常:{data.WrappedValue.Value.GetType().Name}");
return;
}
//LogHelper.Instance.Warn($"数组报警:{JSON.SerializeObject(value)}");
key = $"StationId:{node.StationId},Id:{node.Id}";
if (_alarmValues.TryGetValue(key, out bool[] oldValue)) //有
{
if (oldValue.Count() != value.Count())
{
LogHelper.Instance.Error($"报警老值与新值长度不匹配key:{key},desc:{node.VarDesc}");
return;
}
var diffs = value.Zip(oldValue, (a, b) => a != b).Select((b, i) => new { Value = b, Index = i }).Where(x => x.Value);
foreach (var item in diffs)
{
DealAlarmNode(node, item.Index, value[item.Index]);
}
}
else //第一次进入
{
for (int i = 0; i < value.Count(); ++i)
{
DealAlarmNode(node, i, value[i]);
}
}
_alarmValues[key] = value;
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable)
{
_unityContainer.Resolve<MESProcess>().MESEqptAlert(_arrayAlert);
}
}
void DealAlarmNode(Variable node, int offset, bool value)
{
TAlarmContent alarmContent = GetAlarmContent(node.Id, offset); //找到报警信息
if (alarmContent == null)
{
return;
}
//报警三种处理1入库2.上传MOM3.界面显示报警
if (value)
{
AddAlarm(offset, node.StationId, alarmContent.Desc);
}
else
{
DeleteAlarm(offset, node.StationId, alarmContent.Desc);
}
}
public void AddAlarm(int errCode, int stationId, string desc)
{
var alarm = _allAlarms.Find(x => x.StationId == stationId && x.Desc == desc);
if (null == alarm)
{
TAlarm currentAlarm = new TAlarm()
{
StationId = stationId,
Desc = desc,
StartTime = DateTime.Now,
Status = EAlarmStatus.Alert.GetDescription(),
};
_allAlarms.Add(currentAlarm); //增加到内存
_arrayAlert.Add(AssembleAlertModel(errCode, ((int)EAlarmStatus.Alert).ToString(), desc)); //上传到MES
_unityContainer.Resolve<AlarmService>().Insert<TAlarm>(currentAlarm); //增加到DB
_eventAggregator.GetEvent<AlarmAddEvent>().Publish(currentAlarm);//.界面刷新,发布事件(发送消息)
}
}
public void DeleteAlarm(int errCode, int stationId, string desc)
{
TAlarm alarm = _allAlarms.Find(x => x.StationId == stationId
&& x.Desc == desc);
if (null != alarm)
{
_allAlarms.Remove(alarm);
_arrayAlert.Add(AssembleAlertModel(errCode, ((int)EAlarmStatus.Renew).ToString(), desc));
_unityContainer.Resolve<AlarmService>().CancelAlarm(alarm);
_eventAggregator.GetEvent<AlarmCancelEvent>().Publish(alarm);
}
}
public void Stop()
{
}
}
}

View File

@@ -0,0 +1,307 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Common.Interface;
using Cowain.Bake.Communication.Interface;
using Cowain.Bake.Main.Common;
using Cowain.Bake.Model.Models;
using Opc.Ua;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Unity;
namespace Cowain.Bake.Main.Station
{
public class BakingStation : IServerManager
{
public string Name { get; set; }
readonly StoveProcessParam processParam = null;
public IUnityContainer _unityContainer { get; set; }
readonly CmdFactories cmdFactories;
readonly CancellationTokenSource cts = new CancellationTokenSource();
public BakingStation(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
processParam = _unityContainer.Resolve<StoveProcessParam>();
cmdFactories = _unityContainer.Resolve<CmdFactories>();
Start();
}
public void Start()
{
Task.Run(async () =>
{
while (!cts.Token.IsCancellationRequested)
{
try
{
if (Global.AppExit)
{
return;
}
await Task.Delay(6 * 1000);
List<ExCavityInfoModel> details = _unityContainer.Resolve<CavityInfoService>().GetAllExInfo().Where(
x => x.Type == (int)EStationType.Stove
&& x.Enable == true
&& x.CavityEnable == true).ToList();
//ProcessEndBaking(details);
ProcessStartBaking(details);
}
catch (Exception ex)
{
LogHelper.Instance.Error("BakingStation:Start:工艺参数,异常" + ex.ToString());
_unityContainer.Resolve<LogService>().AddLog("BakingStation:Start:工艺参数,异常" + ex.Message, E_LogType.Debug.ToString());
//throw;
}
}
}, cts.Token);
}
void ProcessStartBaking(List<ExCavityInfoModel> stoveDetails)
{
List<bool> bakeFlag = new List<bool>();
bool[] bakeEnable = new bool[Global.STOVE_MAX_LAYERS];
List<ExCavityInfoModel> layers = null;
var stoves = stoveDetails.GroupBy(p => new { p.StationId }).Select(s => s.FirstOrDefault()).ToList();
foreach (var stove in stoves) //烘烤以层为单位,所以以层为单位循环,这样简单
{
var conf = _unityContainer.Resolve<DeviceConfigService>().GetConfig(stove.StationId);
IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(conf.Name);
if (null == plc || !plc.IsConnect)
{
continue;
}
//远程/本地模式 //0 / 空闲 1 / 待机 2 / 停止 3 / 工作 4 / 保压
if (!CommonFun.Instance.IsStoveQualified(plc, stove.StationId, 1, false))//工作当中就退出
{
continue;
}
layers = stoveDetails.Where(x => x.StationId == stove.StationId).OrderBy(x => x.Layer).ToList();//一炉子的夹具信息
bakeFlag.Clear();
//一层的夹具信息
foreach (var detail in layers)
{
//bakeFlag = new bool[layers.Count]; //每一层有多少个可以烘烤的层
if (0 == detail.PalletId)
{
continue;
}
if (0 != detail.PalletId && !detail.IsLoad) //有托盘,无信号
{
LogHelper.Instance.Error($"有夹具,却没有信号或者没有读到信号,machineId:{stove.StationId},layer:{stove.Layer}");
continue;
}
if (detail.PalletStatus != (int)EPalletStatus.Advisable
&& detail.PalletStatus != (int)EPalletStatus.TestNG)
{
continue;
}
bakeEnable[detail.Layer] = true;
//if (detail.LastFlag ?? false)
//{
// bakeFlag = Enumerable.Repeat(true, layers.Count).ToArray();
// //break; //为了bakeEnable所以不退出
//}
bakeFlag.Add(true);
//bakeFlag[detail.Layer - 1] = true;
}
if (0 == bakeFlag.Count)
{
continue;
}
//因为当每个夹具都放水的时候,可能存在一个要复烘,一个不需要,这个时候就有为false
if (bakeFlag.Count != layers.Count // (bakeFlag.Contains(false))
&& null == layers.Find(x => x.LastFlag == true)) //不是最后一盘
{
//复烘逻辑:1.有NG2.没锁3.无有其它盘
var failPallet = layers.Where(x => x.PalletStatus == (int)EPalletStatus.TestNG).ToList();
if (0 == failPallet.Count) //没有测试NG的
{
continue;
}
if (layers.Any(x => x.Lock)) //有锁,也就是还有回炉的夹具
{
continue;
}
int countPallets = layers.Where(x => x.PalletId != 0 && x.IsLoad == true && x.PalletStatus != (int)EPalletStatus.BlankOver).Count();
if (failPallet.Count != countPallets)//有其它状态盘,如烘烤完成,也不开始烘烤
{
continue;
}
//复烘逻辑满足:1.有NG2.没锁3.无有其它状态盘
}
//if (!IsCanBaking(plc, stove.StationId, stove.Layer))
//{
// continue;
//}
#region
//清料时,可能为会空,
ExCavityInfoModel palletProceParam = stoveDetails.Where(x => !string.IsNullOrEmpty(x.JobNum)
&& x.PalletId != 0 && x.StationId == stove.StationId).FirstOrDefault();
if (!processParam.SendStoveProcessParam(plc, palletProceParam)) //成功了要改变夹具状态 EPalletStatus.
{
continue;
}
//启动烤炉自动流程/下发工艺参数完成信号(开始烘烤)
if (!cmdFactories.StartBaking(plc, stove.StationId, bakeEnable))
{
continue;
}
//去复位“烘烤完成”
cmdFactories.ResetEndBaking(stove.StationId);
//托盘绑定烤箱位置
List<int> ids = layers.Select(x => x.PalletId).ToList(); //修改夹具状态
LogHelper.Instance.Info($"下发工艺参数成功!工站:{stove.Name},工单:{stove.JobNum},托盘号:{JsonSerializer.Serialize(ids)}");
int updateResult = _unityContainer.Resolve<PalletInfoService>().UpdateStartBakingInfo(
layers.Where(x => x.PalletStatus == (int)EPalletStatus.Advisable
|| x.PalletStatus == (int)EPalletStatus.TestNG).ToList()); //托盘绑定烤箱位置,状态,时间
if (updateResult <= 0)
{
LogHelper.Instance.Warn($"修改夹具{string.Join(",", ids)}状态失败!");
}
#endregion
}
}
bool IsCanBaking(IPLCDevice plc, int mainCode, int layer)
{
return true;
}
public void TrigEndBaking(DataValue data, Variable node)
{
if (!((bool)data.WrappedValue.Value))
{
return;
}
List<ExCavityInfoModel> stoveCavitys = _unityContainer.Resolve<CavityInfoService>().GetAllExInfo().Where(
x => x.Type == (int)EStationType.Stove
&& x.Enable == true
&& x.CavityEnable == true
&& x.StationId == node.StationId).ToList();
if (0 == stoveCavitys.Count)
{
LogHelper.Instance.Error($"{node.StationId}#炉没有可能的腔体,烘烤完成失效!");
return;
}
int[] ids = stoveCavitys.Where(x =>
x.PalletStatus == (int)EPalletStatus.Bake
&& x.PalletId != 0).Select(x => x.PalletId).ToArray(); //修改夹具状态,BlankOver清料时会有这状态
if (0 == ids.Count())
{
LogHelper.Instance.Error($"{node.StationId}#炉没有找到【烘烤中】的腔体,烘烤完成失效!");
return;
}
int updateResult = _unityContainer.Resolve<PalletInfoService>().UpdateBakingOverTime(ids);
if (updateResult <= 0)
{
LogHelper.Instance.Warn($"修改夹具为烘烤完成,{string.Join(",", ids)}状态失败!");
};
}
//void ProcessEndBaking(List<ExCavityInfoModel> stoveDetails)
//{
// bool[] bakeFlag = new bool[Global.STOVE_LAYERS];
// List<ExCavityInfoModel> layers = null;
// var stoves = stoveDetails.GroupBy(p => new { p.StationId }).Select(s => s.FirstOrDefault()).ToList();
// foreach (var stove in stoves) //烘烤以炉子为单位,所以以炉子为单位循环,这样简单
// {
// Array.Clear(bakeFlag, 0, Global.STOVE_LAYERS);
// var conf = _unityContainer.Resolve<DeviceConfigService>().GetConfig(stove.StationId);
// IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(conf.Name);
// if (null == plc || !plc.IsConnect)
// {
// continue;
// }
// //远程/本地模式 //0 / 空闲 1 / 待机 2 / 停止 3 / 工作 4 / 保压
// if (!CommonFun.Instance.IsStoveQualified(plc, stove.StationId, 1, false)) //工作当中就退出
// {
// continue;
// }
// //烘烤完成信号
// var resultBool = plc.GetValue<bool>(EStoveSignal.BakingMark.ToString(), stove.StationId); //stove.Layer
// if (!resultBool.IsSuccess || !resultBool.Content)
// {
// continue;
// }
// layers = stoveDetails.Where(x => x.StationId == stove.StationId).OrderBy(x => x.Layer).ToList();//一个炉子的夹具信息
// foreach (var detail in layers)
// {
// //只有在烘烤中的,才会有烘烤完成
// if (detail.PalletStatus != (int)EPalletStatus.Bake //detail.PalletStatus != (int)EPalletStatus.Advisable
// || 0 == detail.PalletId) //detail.PalletStatus != (int)EPalletStatus.Bake
// {
// continue;
// }
// if (detail.LastFlag ?? false)
// {
// bakeFlag = Enumerable.Repeat(true, Global.STOVE_LAYERS).ToArray();
// break;
// }
// bakeFlag[detail.Number - 1] = true;
// }
// if (bakeFlag.Contains(true)) //有假表示有夹具。
// {
// int[] ids = layers.Where(x =>
// x.PalletStatus == (int)EPalletStatus.Bake
// && x.PalletId != 0).Select(x => x.PalletId).ToArray(); //修改夹具状态,BlankOver清料时会有这状态
// int updateResult = _unityContainer.Resolve<PalletInfoService>().UpdateBakingOverTime(ids);
// if (updateResult <= 0)
// {
// LogHelper.Instance.Warn($"修改夹具{string.Join(",", ids)}状态失败!");
// };
// }
// }
//}
public void Stop()
{
// 在需要取消任务的时候,调用以下代码:
cts.Cancel();
}
}
}

View File

@@ -0,0 +1,312 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Common.Interface;
using Cowain.Bake.Communication.Interface;
using Cowain.Bake.Communication.MOM;
using Cowain.Bake.Main.Common;
using Cowain.Bake.Main.ViewModels;
using Cowain.Bake.Model;
using Cowain.Bake.Model.Models;
using HslCommunication;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Unity;
namespace Cowain.Bake.Main.Station
{
public class DataCollectStation : IServerManager
{
public string Name { get; set; }
public IUnityContainer _unityContainer { get; set; }
readonly List<TDeviceConfig> stoveConfs = null;
readonly CancellationTokenSource cts = new CancellationTokenSource();
readonly List<TStoveSctualPatrol> listStoveTemp = new List<TStoveSctualPatrol>();
private Dictionary<int, StoveDataModel> cacheStoveData { set; get; } = new Dictionary<int, StoveDataModel>();//如果只有一个保存炉子的真空值,数据容易不及时,且冲突
//private Dictionary<int, int> cacheElectricEnergyData { set; get; } = new Dictionary<int, int>();
private readonly Prism.Events.IEventAggregator _eventAggregator;
public DataCollectStation(IUnityContainer unityContainer, Prism.Events.IEventAggregator eventAggregator)
{
_unityContainer = unityContainer;
_eventAggregator = eventAggregator;
stoveConfs = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.PLC, EStationType.Stove.ToString());//
Start();
}
public void Start()
{
string tempCycle = _unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>()
.GetValueByParaID(Cowain.Bake.Common.Enums.ESysSetup.DataCollectionCycle.ToString());
int tempCycleValue = int.Parse(tempCycle);
Task.Run(async () =>
{
await Task.Delay(20 * 1000); //等待去读PLC的数据
while (!cts.Token.IsCancellationRequested)
{
await Task.Delay(tempCycleValue * 1000);
if (Global.AppExit)
{
return;
}
CollectTemp();
}
});
}
void CollectTemp()
{
bool isWork = false;
float vacuum = 0;
UInt16 workTime = 0;
UInt16 totalWorkTime = 0;
float[] temps = null;
OperateResult<Int16[]> resultTemp;
listStoveTemp.Clear();
cacheStoveData.Clear();
foreach (var conf in stoveConfs)
{
IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(conf.Name);
if (null == plc || !plc.IsConnect)
{
continue;
}
var stoves = (from v in plc.Storages
group v by v.StationId
into a
orderby a.Key
select a).ToList();
//每个炉子都循环
foreach (var item in stoves) //一个PLC控制二台炉子(一台炉子)
{
//0 / 空闲 1 / 待机 2 / 停止 3 / 工作 4 / 保压
var workStatus = plc.GetValue<Int16>(EStoveSignal.CavityStatus.ToString(), item.Key);
if (!workStatus.IsSuccess || (int)EStoveWorkMode.Standby >= workStatus.Content) //系统状态寄存器
{
isWork = false;
}
else
{
isWork = true;
}
if (item.Key == Global.DEW_STOVE_NUMBER) //IP:70
{
//露点温度
var dewTemp = plc.GetValue<float>(EStoveSignal.DewTemperature.ToString(), item.Key);
if (!dewTemp.IsSuccess)
{
LogHelper.Instance.Error($"读取露点温度失败!{dewTemp.Message}");
_unityContainer.Resolve<BasicInfoViewModel>().SetTempData("-0");
}
else
{
DealDewTemp(dewTemp.Content);
_unityContainer.Resolve<BasicInfoViewModel>().SetTempData(Math.Round(dewTemp.Content,2).ToString());
}
}
//真空值
var result = plc.GetValue<int>(EStoveSignal.Vacuum.ToString(), item.Key);
if (!result.IsSuccess)
{
LogHelper.Instance.Error($"读取真空值失败!{result.Message}");
continue;
}
vacuum = (float)(result.Content);
//工作时长
var workTimeResult = plc.GetValue<UInt16>(EStoveSignal.WorkTime.ToString(), item.Key);
var totalTimeResult = plc.GetValue<UInt16>(EStoveSignal.TotalWorkTime.ToString(), item.Key);
if (!workTimeResult.IsSuccess
|| !totalTimeResult.IsSuccess)
{
LogHelper.Instance.Error($"读取工作时长失败!{workTimeResult.Message},{totalTimeResult.Message}");
continue;
}
workTime = workTimeResult.Content;
totalWorkTime = totalTimeResult.Content;
//获取一个炉子的温度节点
var stoveTempNode = (from storage in plc.Storages
from itemTemp in storage.VariableList
where storage.StationId == item.Key
&& itemTemp.TagType == (int)ETagType.Temperature //&& itemTemp.Number == layer
select itemTemp).ToList();
foreach (var tempParam in stoveTempNode) //每一层的温度
{
int layer = tempParam.Number;
int cavityId = _unityContainer.Resolve<CavityInfoService>().GetCavityId(item.Key, layer);
TPalletInfo palletInfo = _unityContainer.Resolve<PalletInfoService>().GetPalletCode(cavityId);
if (null == palletInfo
|| 0 == palletInfo.Id) //没有托盘
{
continue;
}
if (palletInfo.BakingBeginTime == null //没有烘烤开始时间的不用上传
|| 0 == palletInfo.VirtualId) //没有绑定电芯
{
continue;
}
//PID
var resultPID = plc.GetValue<float[]>(EStoveSignal.PID.ToString() + layer, item.Key, layer);
if (!resultPID.IsSuccess)
{
LogHelper.Instance.GetCurrentClassError("读取PID失败");
continue;
}
//温度
resultTemp = plc.GetValue<Int16[]>(tempParam.ParamName, item.Key, layer); //温度
if (!resultTemp.IsSuccess)
{
LogHelper.Instance.GetCurrentClassError("读取温度失败!");
continue;
}
if (resultTemp.Content.All(x => x == 0)
|| resultPID.Content.All(x => x == 0))
{
//LogHelper.Instance.GetCurrentClassError("读取温度异常全为0");
continue;
}
temps = CommonFun.Instance.UShortToFloat(resultTemp.Content);
cacheStoveData[cavityId] = new StoveDataModel() //少了两个条件1.VirtualId为02.工作状态
{
Temps = temps,
Vacuum = vacuum,
WorkTime = workTime,
TotalWorkTime = totalWorkTime
};
if (isWork) //add by lsm 20250926, 测试用
{
string tempData = MakeJsonTemperature(tempParam.VarDesc, temps);
string pid = MakeJsonPid(EStoveSignal.PID.ToString(), resultPID.Content);
listStoveTemp.Add(MakeTStoveSctualPatrol(palletInfo.VirtualId, cavityId, palletInfo.PalletCode, vacuum, tempData, pid));
}
}
}
}
//UploadProcessData(cacheStoveData); //1.上传Mom //太多,太卡,不上传
_eventAggregator.GetEvent<StoveDataEvent>().Publish(cacheStoveData);//2.界面刷新,发布事件(发送消息)
if (0 != listStoveTemp.Count)
{
_unityContainer.Resolve<StoveSctualPatrolService>().Insert(listStoveTemp);//批量插入数据
}
}
static bool? failDev;
void DealDewTemp(float value)
{
float target = float.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DewTempAlarmTargetValue.ToString()));
TAlarm alarm = new TAlarm()
{
StationId = (int)EAlarmStationId.DevTemp,
Desc = "露点温度超标,请检查压缩空气!",
StartTime = DateTime.Now,
Status = EAlarmStatus.Alert.GetDescription(),
};
if (value <= target) //正常
{
if (false != failDev)
{
failDev = false;
_eventAggregator.GetEvent<AlarmCancelEvent>().Publish(alarm);
}
}
else //异常
{
if (true != failDev)
{
failDev = true;
_eventAggregator.GetEvent<AlarmAddEvent>().Publish(alarm);
}
}
}
//上转Mom
public void UploadProcessData(Dictionary<int, StoveDataModel> datas)
{
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable)
{
foreach (var item in datas)
{
string cavityName = _unityContainer.Resolve<MemoryDataProvider>().CavityInfo.Find(x => x.Id == item.Key).Name;
_unityContainer.Resolve<MESProcess>().MESBakingParameter(item.Value.Vacuum, item.Value.Temps, cavityName);
}
}
}
TStoveSctualPatrol MakeTStoveSctualPatrol(int palletVirtualId, int cavityId, string palletCode, float vacuum, string temperature,string pid)
{
return new TStoveSctualPatrol()
{
PalletVirtualId = palletVirtualId,
CavityId = cavityId,
PalletCode = palletCode,
Vacuum = vacuum,
Temperature = temperature,
CreateTime = DateTime.Now,
PID = pid
};
}
public string MakeJsonTemperature(string headName, float[] value)
{
headName = Regex.Replace(headName, @"\d", "");
List<PallletTemp> listTemp = new List<PallletTemp>();
for (int i = 0; i < value.Length; i++)
{
listTemp.Add(new PallletTemp()
{
HeadName = $"{headName}{i + 1}",
Value = value[i]
});
}
return JsonConvert.SerializeObject(listTemp);
}
public string MakeJsonPid(string headName, float[] value)
{
//headName = Regex.Replace(headName, @"\d", "");
List<PallletTemp> listTemp = new List<PallletTemp>();
for (int i = 1; i < value.Length; i++) //数组0不使用
{
listTemp.Add(new PallletTemp()
{
HeadName = $"{headName}{i}",
Value = value[i]
});
}
return JsonConvert.SerializeObject(listTemp);
}
public void Stop()
{
// 在需要取消任务的时候,调用以下代码:
cts.Cancel();
}
}
}

View File

@@ -0,0 +1,215 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Common.Interface;
using Cowain.Bake.Communication.Interface;
using Cowain.Bake.Model;
using Cowain.Bake.Model.Models;
using HslCommunication;
using Newtonsoft.Json;
using Opc.Ua;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Unity;
namespace Cowain.Bake.Main.Station
{
public class LifeCycleStation : IServerManager
{
public string Name { get; set; }
public List<TStation> _station = null;
public IUnityContainer _unityContainer { get; set; }
public LifeCycleStation(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
_station = _unityContainer.Resolve<MemoryDataProvider>().AllStation;
}
// 心跳
public void LifeCycle(DataValue data, Variable node)
{
OperateResult writeResult = null;
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
Int16 value = 0;
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int16)
{
value = (System.Int16)data.WrappedValue.Value;
}
else
{
LogHelper.Instance.Warn($"没有找到生命周期信号这个数据类型,节点名为{node.VarDesc}");
}
var config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(node.StationId);
var plc = _unityContainer.Resolve<IPLCDevice>(config.Name);
writeResult = plc.Write<Int16>((string)d.WriteHeart, value); //回复为接收到的计数
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"LifeCycle-{node.StationId}-{value}-{(string)d.WriteHeart}:{writeResult.Message}");
}
}
//向上位机请求任务,PLC请求命令:0=无意义10=无托盘20=有托盘
public void ReqTask(DataValue data, Variable node)
{
//bool IsAccord = false; //是否符合取放盘
try
{
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
Int16 value = 0;
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int16)
{
value = (System.Int16)data.WrappedValue.Value;
}
else
{
LogHelper.Instance.Warn($"没有找到请求任务信号这个数据类型,节点名为{node.VarDesc}");
return;
}
TStation station = _station.Where(p => p.Id == node.StationId).FirstOrDefault();
LogHelper.Instance.Warn($"取放盘,值:{value},station:{node.StationId},层{node.Number}");
//是否符合取放盘
//if (_unityContainer.Resolve<CavityInfoService>().IsAccordReq(station, node.Number, (sbyte)value))
{
//IsAccord = true;
//修改取放盘状态
if (!_unityContainer.Resolve<CavityInfoService>().UpdateReqStatus(station, node.Number, (sbyte)value))
{
LogHelper.Instance.GetCurrentClassError($"修改请求任务失败,StationId:{node.StationId},Number:{node.Number},value:{value}");
return;
}
}
//else
//{
// LogHelper.Instance.GetCurrentClassError($"不符合取放盘,StationId:{node.StationId},Number:{node.Number},value:{value}");
//}
//DealPalletRequest(value, node); //取消这个,不然上位机启动,会报异常
var config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(node.StationId);
var plc = _unityContainer.Resolve<IPLCDevice>(config.Name);
var writeResult = plc.Write<int>((string)d.WriteRetCommand, value); //收到什么反馈什么。
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"ReqTask-{(string)d.WriteRetCommand}:{writeResult.Message}");
}
value = (short)(value == 0 ? -1 : 1); //1=OK,2=重新上传如果PLC请求命令是0WCS返回-1
writeResult = plc.Write<int>((string)d.WriteResult, value); //收到什么反馈什么。
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"ReqTask-{(string)d.WriteResult}:{writeResult.Message}");
}
}
catch(Exception ex)
{
LogHelper.Instance.Error($"请求解析出错:{node.Json},{node.TrigJson},{ex.Message}");
}
}
void DealPalletRequest(int value, Variable node)
{
switch (value)
{
case (int)ECavityStatus.RequestPick:
DealPick(node);
break;
case (int)ECavityStatus.RequestPlace:
//DealPlace(station, json);
break;
case (int)ECavityStatus.None:
break;
default:
break;
}
}
public void DealPlace(TStation station, string json)
{
}
public void DealPick(Variable node)
{
MethodInfo mi = null;
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.TrigJson);
string service = d.ReflexService;
string func = d.ReflexFunc;
string param = d.Param; //方法的参数,如果是扫码,则是扫码的编号
if (string.IsNullOrEmpty(service))
{
return;
}
LogHelper.Instance.Info($"请求取盘触发事件:{node.TrigJson}");
var instnce = _unityContainer.Resolve<TrigStation>();
Type type = Type.GetType(MyPath.SIGNAL_TRIGGER + service);
mi = this.GetType().GetMethod(ReflexFun.TRIG_REPLY).MakeGenericMethod(new Type[] { type }); //回复信息;
mi.Invoke(this, new object[]
{
func,
1,
param,
node
});
}
public void TrigReply<T>(string func, int curValue, string param, Variable node)
{
//取得实例
var instnce = _unityContainer.Resolve<T>(); //上下料实例
Type t = instnce.GetType();
//取得方法
MethodInfo mi = t.GetMethod(func);
//调用方法
mi.Invoke(instnce, new object[]
{
curValue,
param,
node
});
}
//心跳
public void Alive(DataValue data, Variable node)
{
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
Int16 value = 0;
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int16)
{
value = (System.Int16)data.WrappedValue.Value;
}
else
{
LogHelper.Instance.Warn($"收到心跳解析出错,工站:{node.StationId},节点名为{node.VarDesc}");
return;
}
var config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(node.StationId);
var plc = _unityContainer.Resolve<IPLCDevice>(config.Name);
var writeResult = plc.Write<int>(d.RetCommand, value); //收到什么反馈什么。
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"Alive-{d.WriteResult}:{writeResult.Message}");
}
}
public void Start()
{
}
public void Stop()
{
}
}
}

View File

@@ -0,0 +1,553 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Common.Interface;
using Cowain.Bake.Communication.Interface;
using Cowain.Bake.Communication.MOM;
using Cowain.Bake.Main.ViewModels;
using Cowain.Bake.Main.Views;
using Cowain.Bake.Model;
using Cowain.Bake.Model.Models;
using Cowain.Bake.UI.CsvMap;
using HslCommunication;
using Newtonsoft.Json;
using Prism.Ioc;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows;
using Unity;
using static Cowain.Bake.Common.Models.MESModel;
using JSON = Newtonsoft.Json.JsonConvert;
namespace Cowain.Bake.Main.Station
{
public class LoadingStation : IServerManager
{
private int _batteryCodeLen = 0;
public string Name { get; set; }
IPLCDevice PLC { get; set; }
readonly List<IScanCodeBase> _deviceScann = new List<IScanCodeBase>();
public IUnityContainer _unityContainer { get; set; }
public LoadingStation(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
TDeviceConfig config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.PLC, EDeviceName.Loading)[0];
Name = config.Name;
SetBatteryCodeLen();
Start();
}
public void SetBatteryCodeLen()
{
_batteryCodeLen = int.Parse(_unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>().GetValueByParaID(ESysSetup.BatteryCodeLen.ToString()));
}
bool IsConnectPLC()
{
if (null == PLC || !PLC.IsConnect)
{
LogHelper.Instance.Error($"PalletVirtualId:{PLC.Name},PLC为空!");
return false;
}
return true;
}
public void Start()
{
var configScann = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.SCANNER).OrderBy(x => x.Id).Take((int)EScanCode.PalletScan2).ToList();
foreach (var item in configScann)
{
IScanCodeBase device = _unityContainer.Resolve<IScanCodeBase>(item.Name);
_deviceScann.Add(device);
}
PLC = _unityContainer.Resolve<IPLCDevice>(Name); //上料PLC
}
public void Stop()
{
}
/*
* 编译器自动在方法入口/出口加 lock(this),简单但锁粒度粗;
* 高频调用或重入场景容易成瓶颈,只适合做原型或低并发工具类。
*/
//托盘满盘信号
[MethodImpl(MethodImplOptions.Synchronized)]
public void ExecuteFullPallet(int curValue, string param, Variable node)
{
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
LogHelper.Instance.Warn($"LoadingStation:ExecuteFullPallet:开始,线程ID:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
int result ;
int batteryQty;
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("开始:" + node.VarDesc);
int palletId = _unityContainer.Resolve<CavityInfoService>().GetPalletId((int)EStationType.Loading, int.Parse(param));
TPalletInfo palletInfo = _unityContainer.Resolve<BLL.PalletInfoService>().GetPalletInfo(palletId);
if (null == palletInfo) //如果当前夹具状态为"满夹具可取",就退出,上位机重启会重复触发!
{
LogHelper.Instance.Warn($"托盘满信号,上料平台无夹具,异常");
return;
}
if ((int)EPalletStatus.Advisable == palletInfo.PalletStatus) //如果当前夹具状态为"满夹具可取",就退出,上位机重启会重复触发!
{
//LogHelper.Instance.Warn($"托盘满信号,当前托盘为满夹具夹,异常");
//return;
}
try
{
int debugMode = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DebugMode.ToString())); //0
if (!IsConnectPLC()) return;
var resultBatterys = PLC.Read<int[]>((string)d.ReadVirtualIds); //可以改成直接读PLC
var resultPalletVirtualId = PLC.Read<int>((string)d.ReadPalletVirtualId); //这是直接读PLC
var lastFlag = PLC.Read<Int16>((string)d.ReadLastFlag).Content; //这是直接读PLC
if (!resultBatterys.IsSuccess || !resultPalletVirtualId.IsSuccess)
{
LogHelper.Instance.Error($"PalletVirtualId:{resultPalletVirtualId.Content},没有读取电芯信息或托盘信息!");
return;
}
if (0 == resultPalletVirtualId.Content ||
1 == resultPalletVirtualId.Content)
{
LogHelper.Instance.Error($"托盘满盘信号异常, 托盘虚拟码为【{resultPalletVirtualId.Content}】!", true);
return;
}
//批量更新电芯表
batteryQty = _unityContainer.Resolve<BatteryInfoService>().InsertBatch(resultBatterys.Content, resultPalletVirtualId.Content); //add by lsm 20250219 要300耗秒以上
SavePalletInfo(resultPalletVirtualId.Content);
if (0 == batteryQty)
{
//HandyControl.Controls.MessageBox.Error("触发满盘时没有电芯数据!"); //启动上位机时,会触发这个东西。
LogHelper.Instance.Error($"启动上位机时,上料:{resultPalletVirtualId.Content},电芯地址里没有电芯数据!");
return;
}
if (Global.PALLET_TOTAL_BATTERYS != batteryQty)
{
LogHelper.Instance.Error($"PalletVirtualId:{resultPalletVirtualId.Content},{batteryQty},上料电芯是{Global.PALLET_TOTAL_BATTERYS}!", false);
}
result = _unityContainer.Resolve<PalletInfoService>().LoadingUpdatePalletStatus(resultPalletVirtualId.Content, (int)EPalletStatus.Advisable, batteryQty, lastFlag == 1);
if (0 == result)
{
LogHelper.Instance.Error($"PalletVirtualId:{resultPalletVirtualId.Content},修改托盘状态失败!");
}
//writeResult = PLC.Write<bool>((string)d.WriteResult, true);//回复收到托盘1满盘信号
//if (!writeResult.IsSuccess)
//{
// LogHelper.Instance.GetCurrentClassWarn($"{(string)d.WriteResult}:{writeResult.Message}");
//}
}
catch(Exception ex)
{
LogHelper.Instance.GetCurrentClassWarn($",{ex.Message}:{ex.StackTrace}");
}
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
}
//假电芯扫码 验证数据库OK
public void ExecuteScanDummy(int curValue, string param, Variable node)
{
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
if (!IsConnectPLC()) return;
int virtualId;
OperateResult writeResult = null;
EScanCode scanName = EScanCode.DummyScan; //(EScanCode)(int.Parse(param));
IScanCodeBase scanDevice = _deviceScann.Find(x => x.Name == scanName.ToString());
HslCommunication.OperateResult<string> scanResult = new HslCommunication.OperateResult<string>()
{
IsSuccess = false,
};
scanResult.IsSuccess = true;
scanResult.Content = System.Guid.NewGuid().ToString("N").Substring(0, 12);
if (scanResult.IsSuccess)
{
virtualId = _unityContainer.Resolve<BatteryInfoService>().InsertBattery(scanResult.Content, (int)EBatteryStatus.ScanOver, (int)EDummyState.Have, "");
writeResult = PLC.Write<int>((string)d.WriteVirtualId, virtualId); //假电芯虚拟码
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"写假电芯虚拟码失败,{(string)d.WriteVirtualId}:{writeResult.Message}");
}
}
writeResult = PLC.Write<Int16>((string)d.WriteResult, scanResult.IsSuccess ? (Int16)EResult.OK : (Int16)EResult.NG); //假电芯结果
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"{(string)d.WriteResult}:{writeResult.Message}");
}
writeResult = PLC.Write<Int16>((string)d.WriteAsk, 1); //回复
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"ExecuteScanDummy-{(string)d.WriteAsk}:{writeResult.Message}");
}
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
}
//托盘扫码
public void ExecuteScanPallet(int curValue, string param, Variable node)
{
string msg = "";
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
_unityContainer.Resolve<LogService>().AddLog("LoadingStation:ExecuteScanPallet:托盘扫码开始", E_LogType.Info.ToString());
string palletCode = "";
int VID = 0;
OperateResult writeResult = null;
HslCommunication.OperateResult<string> scanResult = new HslCommunication.OperateResult<string>()
{
IsSuccess = false,
};
EScanCode scanName = (EScanCode)((int)EScanCode.PalletScan1 + int.Parse(param) - 1); //param这个就是扫码枪的编号
try
{
IScanCodeBase scanDevice = _deviceScann.Find(x => x.Name == scanName.ToString());
while (!scanDevice.IsConnect)
{
msg = $"获取{scanName.GetDescription()}连接异常!";
LogHelper.Instance.Error(msg);
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
scanDevice.Connect();
}
scanResult = scanDevice.ReadCode();
////------------------------ //add by lsm
//scanResult.IsSuccess = true;
//scanResult.Content = System.Guid.NewGuid().ToString("N").Substring(0, 6); // add by lsm测试用
//------------------------
palletCode = scanResult.Content;
//夹具扫码异常处理
while (string.IsNullOrEmpty(palletCode))
{
Application.Current.Dispatcher.Invoke((Action)(() =>
{
PalletIdInputWindow f = new PalletIdInputWindow("托盘码输入框", "请输入托盘码", "确定输入托盘码?")
{
WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen,
};
f.ShowDialog();
palletCode = f.PalletId;
}));
}
//绑定托盘
VID = _unityContainer.Resolve<PalletInfoService>().BindingPallet(palletCode, (int)EPalletStatus.Loading, (int)EStationType.Loading, int.Parse(param)); //防呆
if (0 == VID)
{
LogHelper.Instance.Debug($"===ProcBindPallet卡死,{palletCode},{int.Parse(param)},VID:{VID}");
return; //此时会卡死上位机
}
LogHelper.Instance.Debug($"===ProcBindPallet,{palletCode},{(int)EPalletStatus.Loading},{int.Parse(param)},VID:{VID}");
if (CurrentWeaterPallet())
{
Int16 DummyLocationX = Int16.Parse(_unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>().GetValueByParaID(ESysSetup.DummyLocationX.ToString()));
writeResult = PLC.Write<Int16>((string)d.WriteDummyX, DummyLocationX); //假电芯行号
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"假电芯行号:{(string)d.WriteDummyX}:{writeResult.Message},失败");
}
Int16 DummyLocationY = Int16.Parse(_unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>().GetValueByParaID(ESysSetup.DummyLocationY.ToString()));
writeResult = PLC.Write<Int16>((string)d.WriteDummyY, DummyLocationY); //假电芯列号
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"假电芯列号:{(string)d.WriteDummyY}:{writeResult.Message},失败");
}
}
writeResult = PLC.Write<int>((string)d.WritePattleVirtualId, VID); //托盘1托盘虚拟码
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"{(string)d.WritePattleVirtualId}:{writeResult.Message}");
}
writeResult = PLC.Write<Int16>((string)d.WriteResult, 1); //托盘1扫码结果
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"{(string)d.WriteResult}:{writeResult.Message}");
}
writeResult = PLC.Write<Int16>((string)d.WriteAsk, 1); //回复
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"ExecuteScanPallet-{(string)d.WriteAsk}:{writeResult.Message}");
}
}
catch(Exception ex)
{
LogHelper.Instance.GetCurrentClassWarn($"ExecuteScanPallet:{ex},{scanResult.Content},{scanResult.Message}");
}
_unityContainer.Resolve<MainWindowViewModel>().DeletePromptContent();
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
}
/// <summary>
/// 根据工单判断是否放水含量
/// </summary>
/// <returns></returns>
public bool CurrentWeaterPallet()
{
bool IsWaertPallet = false;
var productionInformation = _unityContainer.Resolve<ProductionInformationService>().GetCurrentProductInfo();
if (productionInformation.DummyRule == (int)DummyPlaceRule.DEFAULT_EVERY_STOVE_LAYER_PLACED_ONE)
{
if (SettingProvider.Instance.WaterPallet % 2 == 1)
{
IsWaertPallet = true;
}
SettingProvider.Instance.WaterPallet++;
}
else if (productionInformation.DummyRule == (int)DummyPlaceRule.EVERY_PALLET_PLACED_ONE)
{
IsWaertPallet = true;
}
return IsWaertPallet;
}
//电芯扫码
public async Task ExecutScanBattery(int curValue, string param, Variable node)
{
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
if (!IsConnectPLC()) return;
int scannIndex = 0;
OperateResult writeResult = null;
int mesIndex = 0;
int index = 1; //1..4,第0个索引不用
string[] codeBatterys = new string[Global.ONCE_SCAN_BATTERY + 1];
Int16[] result = new Int16[Global.ONCE_SCAN_BATTERY + 1];
Int16[] ask = new Int16[Global.ONCE_SCAN_BATTERY + 1];
int[] batteryVirtualIds = new int[Global.ONCE_SCAN_BATTERY + 1];
result = Enumerable.Repeat<Int16>(3, Global.ONCE_SCAN_BATTERY + 1).ToArray();
Array.Clear(ask, 0, Global.ONCE_SCAN_BATTERY + 1); //3:无电芯
Array.Clear(batteryVirtualIds, 0, Global.ONCE_SCAN_BATTERY + 1);
List<OperateResult<string>> scannList = new List<OperateResult<string>>();
List<MESReturnCmdModel> mesResultList = new List<MESReturnCmdModel>();
List<Task<OperateResult<string>>> scannTasks = new List<Task<OperateResult<string>>>();
List<Task<MESReturnCmdModel>> mesResultTasks = new List<Task<MESReturnCmdModel>>();
int mesEnable = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString()));
int debugMode = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DebugMode.ToString())); //0为测试模式1为正式模式
Array.Clear(codeBatterys, 0, Global.ONCE_SCAN_BATTERY + 1); //几个条码一起保存
HslCommunication.OperateResult<string> scanResult = new HslCommunication.OperateResult<string>()
{
IsSuccess = false,
};
if (mesEnable == (int)EMOMEnable.Enable
&& (int)EProductionMode.Debug == debugMode)
{
LogHelper.Instance.Error($"MOM【在线模式】设备模式却是【调试模式】模式不匹配,请修改!", true);
return;
}
try
{
index = 1;
for (EScanCode s = EScanCode.LoadingBatteryScan1; s <= EScanCode.LoadingBatteryScan8; s++, index++)
{
if (((curValue >> index) & 1) != 1) //第index位不是1,就是不需要扫码
{
continue;
}
ask[(int)s] = 1;
IScanCodeBase scanDevice = _deviceScann.Find(x => x.Name == s.ToString());
if (!scanDevice.IsConnect)
{
string msg = $"获取{s.GetDescription()}失败,请检测线路!";
LogHelper.Instance.Error(msg, true); //弹屏,人为处理好后,再次触发
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
scanDevice.Connect();
--s; //再次获取
continue;
}
if ((int)EProductionMode.Debug == debugMode) //调试模式
{
scanResult.IsSuccess = true;
scanResult.Content = System.Guid.NewGuid().ToString("N").Substring(0, _batteryCodeLen);
scannList.Add(scanResult);
}
else
{
//scanResult = scanDevice.ReadCode();
scannTasks.Add(Task.Run(() => scanDevice.ReadCode())); // 启动并行任务
}
}
if ((int)EProductionMode.Normal == debugMode)
{
await Task.WhenAll(scannTasks); //等待所有任务(扫码)完成
foreach (var task in scannTasks)
{
scannList.Add(task.Result);
}
}
#region MOM
if (mesEnable == (int)EMOMEnable.Enable)//生产模式才会请求MES(不是离线就要请求)
{
foreach (var item in scannList) //四个电芯扫码结果
{
if (item.IsSuccess) //可能是三个扫码OK一个扫码NG所以只有三个电芯请求到MOM
{
mesResultTasks.Add(Task.Run(() => _unityContainer.Resolve<MESProcess>().GetBatteryStatus(item.Content))); //多线程入库,会有先后顺序的
}
}
if (0 != mesResultTasks.Count)
{
MESReturnCmdModel[] tt = await Task.WhenAll(mesResultTasks); // //发送MES等待所有的MES请求。
foreach (var item in mesResultTasks) //发送MOM不一定是四个
{
mesResultList.Add(item.Result);
}
}
}
#endregion
index = 1; //1..4,第0个索引不用
for (EScanCode s = EScanCode.LoadingBatteryScan1; s <= EScanCode.LoadingBatteryScan8; s++, index++)
{
if (((curValue >> index) & 1) != 1) //第index位不是1,就是不需要扫码
{
continue;
}
scanResult = scannList[scannIndex++];
result[index] = scanResult.IsSuccess ? (Int16)EResult.OK : (Int16)EResult.NG;
if (scanResult.IsSuccess) //扫码成功
{
//长度判断
//if (_batteryCodeLen != scanResult.Content.Length)
//{
// result[index] = (Int32)EResult.NG; //长度不对赋NG
// _unityContainer.Resolve<BatteryNGService>().Insert("入站拦截", scanResult.Content, $"要求电芯条码长度为{_batteryCodeLen},实际长度为:{scanResult.Content.Length}");
// continue;
//}
//0:正常扫码1:复投扫码
if ("0" == _unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>().GetValueByParaID(Cowain.Bake.Common.Enums.ESysSetup.ScanCodeMode.ToString()))
{
if (_unityContainer.Resolve<BatteryInfoService>().IsBatteryCodeRepeat(scanResult.Content))
{
result[index] = (Int32)EResult.NG; //有相同电芯赋NG
LogHelper.Instance.Warn($"{s.GetDescription()},电芯条码:[{scanResult.Content}]重复扫码,将会排出到NG位;"); //不要弹屏
_unityContainer.Resolve<BatteryNGService>().Insert("入站拦截", scanResult.Content, $"重复扫码,将会排出到NG位");
}
}
//MES结果判断
if (mesEnable == (int)EMOMEnable.Enable) ////mes-mom 7.电芯状态获取 只有联机才调用MES接口MES返回成功失败
{
MESReturnCmdModel mesResult = mesResultList[mesIndex++];//_unityContainer.Resolve<MESProcess>().MESCellState(scanResult.Content);
if (mesResult == null)
{
result[index] = (int)EResult.NG;
_unityContainer.Resolve<BatteryNGService>().Insert("入站拦截", scanResult.Content, "MOM返回信息为空请判断MOM是否离线未离线则是MOM回复异常");
continue;
}
if (mesResult.Info.ResultFlag != EResultFlag.OK.ToString())
{
result[index] = (int)EResult.NG;
_unityContainer.Resolve<BatteryNGService>().Insert("入站拦截", scanResult.Content, JSON.SerializeObject(mesResult));
continue;
}
}
codeBatterys[index] = scanResult.Content; //MES判断OK的电芯才放到电芯表中。
}
}
batteryVirtualIds = _unityContainer.Resolve<BatteryInfoService>().InsertBattery(string.Join(",", codeBatterys)).ToArray(); //新加的,四个一起存,并返回虚拟码
//InsertBattery//四个电芯一起存数据库
LogHelper.Instance.Info($"电芯虚拟码写入到PLC:{string.Join(",", batteryVirtualIds)}codes={string.Join(",", codeBatterys)},扫码状态:{string.Join(",", result)}");
writeResult = PLC.Write<int[]>((string)d.WriteVirtualIds, batteryVirtualIds); //电芯1...4虚拟码
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"写虚拟地址-{(string)d.WriteVirtualIds}:{writeResult.Message}");
}
//g_U01_HMI.UpLoadFromWcs.iCell_ScanCodeResults
writeResult = PLC.Write<Int16[]>((string)d.WriteResult, result); //电芯1...8扫码结果
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"ExecutScanBattery-{(string)d.WriteResult}:{writeResult.Message}");
}
writeResult = PLC.Write<Int16[]>((string)d.WriteAsk, ask); //回复
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"ExecutScanBattery-{(string)d.WriteAsk}:{writeResult.Message}");
}
_unityContainer.Resolve<MainWindowViewModel>().DeletePromptContent();
}
catch(Exception ex)
{
LogHelper.Instance.Fatal($"ExecutScanBattery-出错-param:{param}:{ex.Message},{index}");
}
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
}
//保存组盘信息
private void SavePalletInfo(int palletVID)
{
string dateFile;
string filePath;
try
{
List<TBatteryInfo> batterys = _unityContainer.Resolve<BatteryInfoService>().GetBatteryInfos(palletVID);
if (0 == batterys.Count)
{
return;
}
string path = _unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DataFilePath.ToString());
path += "\\组盘";
dateFile = DateTime.Now.ToString("yyyyMMdd");
filePath = path + $"\\{dateFile}.csv";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
CSVHelper.WriteMap<TBatteryInfo, BatteryInfoMap>(batterys, filePath);
}
catch(Exception ex)
{
LogHelper.Instance.Error($"SavePalletInfo:{ex.Message},{ex.StackTrace}");
}
}
}
}

View File

@@ -0,0 +1,73 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Communication.MOM;
using Cowain.Bake.Main.ViewModels;
using Cowain.Bake.Model;
using Cowain.Bake.Model.Models;
using Opc.Ua;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Unity;
using JSON = Newtonsoft.Json.JsonConvert;
namespace Cowain.Bake.Main.Station
{
public class MesCollectStation
{
readonly CancellationTokenSource cts = new CancellationTokenSource();
readonly List<TDeviceConfig> stoveConfs = null;
IUnityContainer _unityContainer { get; set; }
public MesCollectStation(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
stoveConfs = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.PLC, EDeviceName.StovePlc1);
}
/*
1 运行状态
2 待机状态
3 报警状态
4 停机状态
*/
//mes-mom 2.设备状态 只有联机才调用MES接口MOM返回成功失败
public void EqptStatus(DataValue data, Variable node)
{
Int16 value = (Int16)data.WrappedValue.Value;
List<TAlarm> models = null;
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable)
{
if ((int)EStatusCode.Warn == value)
{
var alarms = _unityContainer.Resolve<MainWindowViewModel>().Alarms.Where(x=>x.StationId == node.StationId).ToList();
models = JSON.DeserializeObject<List<TAlarm>>(JSON.SerializeObject(alarms));
}
//_unityContainer.Resolve<MESProcess>().MESEqptStatus((UInt16)value, models); //经常超时 2026-2-9
}
_unityContainer.Resolve<BasicInfoViewModel>().DeviceStatusName = ((EStatusCode)value).GetDescription();
}
//public string MakeJsonTemperature(string headName, float[] value)
//{
// headName = Regex.Replace(headName, @"\d", "");
// List<PallletTemp> listTemp = new List<PallletTemp>();
// for (int i = 1; i <= value.Length; i++)
// {
// listTemp.Add(new PallletTemp()
// {
// HeadName = $"{headName}{i}",
// Value = value[i - 1]
// });
// }
// return JsonConvert.SerializeObject(listTemp);
//}
public void Stop()
{
// 在需要取消任务的时候,调用以下代码:
cts.Cancel();
}
}
}

View File

@@ -0,0 +1,397 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Common.Models;
using Cowain.Bake.Communication.Interface;
using Cowain.Bake.Model;
using Cowain.Bake.Model.Models;
using HslCommunication;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Unity;
using JSON = System.Text.Json.JsonSerializer;
namespace Cowain.Bake.Main.Station
{
public class StoveProcessParam
{
const int PROCESS_PARAM_NUM = 21;
//ProcessParamService procParamService;
public IUnityContainer _unityContainer { get; set; }
public StoveProcessParam(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
//procParamService = _unityContainer.Resolve<ProcessParamService>();
}
public bool SendStoveProcessParam(IPLCDevice plc, ExCavityInfoModel palletProceParam)
{
ProceParamList proceParam = null;
TProcessParameter proceParamModel = null;
//_unityContainer.Resolve<LogService>().AddLog("StoveProcessParam:SendStoveProcessParam:下发工艺参数开始"
// , E_LogType.Info.ToString());
OperateResult<AddrValue> operateResult = null;
Model.Models.Variable node = null;
List<AddrValue> makeAddrValues = new List<AddrValue>();
List<ProceParamList> listParams = null;
if (null == palletProceParam)
{
LogHelper.Instance.GetCurrentClassWarn("发送工艺参数时,没有获取到托盘信息!");
return false;
}
//判断是否是复烘
if (palletProceParam.PalletStatus == (int)EPalletStatus.TestNG)
{
//使用复烘工艺
proceParamModel = _unityContainer.Resolve<ProcessParamService>().GetReProcessParam(palletProceParam.JobNum);
}
else
{
proceParamModel = _unityContainer.Resolve<ProcessParamService>().GetProcessParam(palletProceParam.JobNum);
}
if (null == proceParamModel)
{
LogHelper.Instance.GetCurrentClassWarn("没有找到工艺参数列表!");
return false;
}
try
{
listParams = JSON.Deserialize<List<ProceParamList>>(proceParamModel.Parameters);
}
catch(Exception ex)
{
LogHelper.Instance.GetCurrentClassFatal(ex.Message);
return false;
}
//温度上限预警值
node = plc.GetVariable(EStoveSignal.TemperatureUpperWarnValue.ToString(), palletProceParam.StationId);
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.TemperatureUpperWarnValue.ToString().ToLower()).FirstOrDefault();
operateResult = SetNodeValue(node, proceParam);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//真空上限预警值
node = plc.GetVariable(EStoveSignal.VacuumUpperWarnValue.ToString(), palletProceParam.StationId);
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.VacuumUpperWarnValue.ToString().ToLower()).FirstOrDefault();
operateResult = SetNodeValue(node, proceParam);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
////参数_设定温度
node = plc.GetVariable(EStoveSignal.SetTemp.ToString(), palletProceParam.StationId);
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.SetTemp.ToString().ToLower()).FirstOrDefault();
operateResult = SetNodeValue(node, proceParam, 100); //乘以100设定10000表示100度
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_温度公差
node = plc.GetVariable(EStoveSignal.TemperatureTolerance.ToString(), palletProceParam.StationId);
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.TemperatureTolerance.ToString().ToLower()).FirstOrDefault();
operateResult = SetNodeValue(node, proceParam, 100); //乘以100设定10000
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_温度上限
node = plc.GetVariable(EStoveSignal.TemperatureLimit.ToString(), palletProceParam.StationId);
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.TemperatureLimit.ToString().ToLower()).FirstOrDefault();
operateResult = SetNodeValue(node, proceParam, 100); //乘以100设定10000
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_真空到达值
node = plc.GetVariable(EStoveSignal.VacuumArriveValue.ToString(), palletProceParam.StationId);
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.VacuumArriveValue.ToString().ToLower()).FirstOrDefault();
operateResult = SetNodeValue(node, proceParam);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_真空上限
node = plc.GetVariable(EStoveSignal.VacuumUpValue.ToString(), palletProceParam.StationId);
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.VacuumUpValue.ToString().ToLower()).FirstOrDefault();
operateResult = SetNodeValue(node, proceParam);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_真空下限
node = plc.GetVariable(EStoveSignal.VacuumDownValue.ToString(), palletProceParam.StationId);
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.VacuumDownValue.ToString().ToLower()).FirstOrDefault();
operateResult = SetNodeValue(node, proceParam);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_氮气到达值
node = plc.GetVariable(EStoveSignal.NitrogenArriveValue.ToString(), palletProceParam.StationId);
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.NitrogenArriveValue.ToString().ToLower()).FirstOrDefault();
operateResult = SetNodeValue(node, proceParam);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_氮气上限
node = plc.GetVariable(EStoveSignal.NitrogenUpValue.ToString(), palletProceParam.StationId);
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.NitrogenUpValue.ToString().ToLower()).FirstOrDefault();
operateResult = SetNodeValue(node, proceParam);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_氮气下限
node = plc.GetVariable(EStoveSignal.NitrogenDownValue.ToString(), palletProceParam.StationId);
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.NitrogenDownValue.ToString().ToLower()).FirstOrDefault();
operateResult = SetNodeValue(node, proceParam);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_常压到达值
node = plc.GetVariable(EStoveSignal.AtmosphericArriveValue.ToString(), palletProceParam.StationId);
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.AtmosphericArriveValue.ToString().ToLower()).FirstOrDefault();
operateResult = SetNodeValue(node, proceParam);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_常压上限
node = plc.GetVariable(EStoveSignal.AtmosphericUpValue.ToString(), palletProceParam.StationId);
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.AtmosphericUpValue.ToString().ToLower()).FirstOrDefault();
operateResult = SetNodeValue(node, proceParam);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_常压下限
node = plc.GetVariable(EStoveSignal.AtmosphericDownValue.ToString(), palletProceParam.StationId);
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.AtmosphericDownValue.ToString().ToLower()).FirstOrDefault();
operateResult = SetNodeValue(node, proceParam);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_循环启动工步
node = plc.GetVariable(EStoveSignal.CycleStartStep.ToString(), palletProceParam.StationId);
operateResult = SetNodeValues(node, listParams, EStoveSignal.CycleStartStep.ToString(), false);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_循环结束工步
node = plc.GetVariable(EStoveSignal.CycleEndStep.ToString(), palletProceParam.StationId);
operateResult = SetNodeValues(node, listParams, EStoveSignal.CycleEndStep.ToString(), false);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_循环次数
node = plc.GetVariable(EStoveSignal.CycleNumber.ToString(), palletProceParam.StationId);
operateResult = SetNodeValues(node, listParams, EStoveSignal.CycleNumber.ToString(), false);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_加热启用
node = plc.GetVariable(EStoveSignal.HeatingEnabled.ToString(), palletProceParam.StationId);
operateResult = SetNodeValues(node, listParams, EStoveSignal.HeatingEnabled.ToString(), true);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_真空启用
node = plc.GetVariable(EStoveSignal.VacuumEnabled.ToString(), palletProceParam.StationId);
operateResult = SetNodeValues(node, listParams, EStoveSignal.VacuumEnabled.ToString(), true);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_氮气启用
node = plc.GetVariable(EStoveSignal.NitrogenEnabled.ToString(), palletProceParam.StationId);
operateResult = SetNodeValues(node, listParams, EStoveSignal.NitrogenEnabled.ToString(), true);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
//参数_工步时间
node = plc.GetVariable(EStoveSignal.StepWorkTime.ToString(), palletProceParam.StationId);
operateResult = SetNodeValues(node, listParams, EStoveSignal.StepWorkTime.ToString(), true);
if (operateResult.IsSuccess)
{
makeAddrValues.Add(operateResult.Content);
}
if (PROCESS_PARAM_NUM != makeAddrValues.Count)
{
LogHelper.Instance.GetCurrentClassError("发送工艺数据项不够!", true);
return false;
}
OperateResult result = plc.Writes(makeAddrValues.Select(x => x.Addr).ToArray(), makeAddrValues.Select(x => x.Value).ToArray());
if (!result.IsSuccess)
{
LogHelper.Instance.GetCurrentClassError($"发送工艺数据失败,{result.Message}");
return false;
}
_unityContainer.Resolve<LogService>().AddLog("StoveProcessParam:SendStoveProcessParam:下发工艺参数结束", E_LogType.Info.ToString());
return true;
}
OperateResult<AddrValue> SetNodeValues(Model.Models.Variable node, List<ProceParamList> proceParams, string key, bool fristNull)
{
object obj;
EDataType dt = EDataType.UINT32;
OperateResult<AddrValue> result = new OperateResult<AddrValue>() { IsSuccess = false };
AddrValue nodeValue = new AddrValue();
List<object> vaules = new List<object>();
if (fristNull)
{
vaules.Add(StringToObject("0", node.VarType));
}
foreach (var item in proceParams)
{
if (item.ParameterCode.ToLower().StartsWith(key.ToLower())) //在JOSN里面数组一定要按顺序排或者顺序乱了
{
dt = (EDataType)System.Enum.Parse(typeof(EDataType), node.VarType);
obj = StringToObject(item.TargetValue, node.VarType);
if (null == obj)
{
continue;
}
vaules.Add(obj);
}
}
if (vaules.Count == 0)
{
return result;
}
nodeValue.Addr = node.Address + node.VarName;
System.Type type = System.Type.GetType(dt.GetDescription());
MethodInfo mi = this.GetType().GetMethod(ReflexFun.OBJECT_TO_T).MakeGenericMethod(new System.Type[] { type }); //如果不转T直接object会写不进去
nodeValue.Value = mi.Invoke(this, new object[]
{
vaules
});
result.Content = nodeValue;
result.IsSuccess = true;
return result;
}
public T[] ObjectToT<T>(List<object> vaules) //where T : class
{
return vaules.OfType<T>().ToArray(); //object[]转T[]
}
object StringToObject(string value, string varType, float multiples = 1)
{
object obj = null;
EDataType dt = (EDataType)Enum.Parse(typeof(EDataType), varType);
try
{
switch (dt)
{
case EDataType.BOOL:
obj = (value == "1");
break;
case EDataType.UINT16:
obj = (UInt16)(System.Convert.ToSingle(value) * multiples);
break;
case EDataType.INT16:
obj = (Int16)(System.Convert.ToSingle(value) * multiples);
break;
case EDataType.INT32:
obj = (Int32)(System.Convert.ToSingle(value) * multiples);
break;
case EDataType.UINT32:
obj = (UInt32)(System.Convert.ToSingle(value) * multiples);
break;
case EDataType.FLOAT:
case EDataType.REAL:
obj = (float)(System.Convert.ToSingle(value) * multiples);
break;
default:
LogHelper.Instance.Fatal($"没有这种数据类型:{varType}");
break;
}
if (null == obj)
{
LogHelper.Instance.GetCurrentClassError("获取工艺数据的值为空");
}
}
catch(Exception ex)
{
LogHelper.Instance.GetCurrentClassDebug(ex.Message);
}
return obj;
}
OperateResult<AddrValue> SetNodeValue(Model.Models.Variable node, ProceParamList proceParam, float multiples = 1)
{
OperateResult<AddrValue> result = new OperateResult<AddrValue>() { IsSuccess = false};
AddrValue nodeValue = new AddrValue();
if (null == node)
{
LogHelper.Instance.GetCurrentClassError("获取节点数据失败");
return result;
}
if (null == proceParam)
{
LogHelper.Instance.GetCurrentClassError("获取工艺数据失败");
return result;
}
nodeValue.Addr = node.Address + node.VarName;
nodeValue.Value = StringToObject(proceParam.TargetValue, node.VarType, multiples);
if (null == nodeValue.Value)
{
return result;
}
result.IsSuccess = true;
result.Content = nodeValue;
return result;
}
}
}

View File

@@ -0,0 +1,582 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Common.Interface;
using Cowain.Bake.Common.Models;
using Cowain.Bake.Communication.Interface;
using Cowain.Bake.Communication.MOM;
using Cowain.Bake.Main.ViewModels;
using Cowain.Bake.Model;
using Cowain.Bake.Model.Entity;
using Cowain.Bake.Model.Models;
using HslCommunication;
using Newtonsoft.Json;
using Opc.Ua;
using Prism.Ioc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Unity;
using JSON = Newtonsoft.Json.JsonConvert;
namespace Cowain.Bake.Main.Station
{
public class TaskStation: IServerManager
{
public string Name { get; set; }
static Int16 _lastStepId = 0;
public IUnityContainer _unityContainer { get; set; }
readonly CancellationTokenSource cts = new CancellationTokenSource();
readonly TDeviceConfig config;
IPLCDevice agv = null;
readonly List<CavityInfoModel> _stationCavity;
public List<TStation> _station = null;
public AutoResetEvent _newTaskEvent = new AutoResetEvent(true);
public TaskStation(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
_station = _unityContainer.Resolve<MemoryDataProvider>().AllStation;
config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.PLC, EDeviceName.AGV)[0];
_stationCavity = _unityContainer.Resolve<CavityInfoService>().GetAllStation();
Start();
StartNewTask();
}
public void Start()
{
var task = _unityContainer.Resolve<TaskRecordService>().UnexecuteTask();
if (null == task)
{
_lastStepId = (int)ETaskStep.None;
}
else
{
_lastStepId = (short)task.StepId;
}
agv = _unityContainer.Resolve<IPLCDevice>(config.Name);
//TTaskRecord task = await GenerateTask(); #测试
}
public async Task DealTask(DataValue data, Variable node)
{
bool dealResult = false; //进去这里,看会不会触发别的
LogHelper.Instance.Info($"开始任务--------------信号,线程ID:{System.Threading.Thread.CurrentThread.ManagedThreadId},{node.VarDesc}");
do
{
// 启动任务并等待结果
//dealResult = await Task.Run(() => ThreadDealTask(data, node));
dealResult = ThreadDealTask(data, node);
if (!dealResult)
{
LogHelper.Instance.Error("-------------------------处理任务异常!");
await Task.Delay(2 * 1000);
}
} while(!dealResult);
LogHelper.Instance.Info($"完成任务--------------信号,线程ID:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
}
void StartNewTask()
{
Task.Run( () =>
{
agv = _unityContainer.Resolve<IPLCDevice>(config.Name);
while (!cts.Token.IsCancellationRequested)
{
if (Global.AppExit)
{
return;
}
DealNewTask();
}
});
}
public void DealNewTask()
{
_newTaskEvent.WaitOne(10*1000);
Variable nodeTemp = (from secondaryList in agv.Storages //不能做触发,因为没有任务。要地直运行里面,来检测是否有任务
from item in secondaryList.VariableList
where item.ParamName == EAgvPLC.RetCount.ToString()
select item).FirstOrDefault();
Variable node = BasicFramework.DeepCopy<Variable>(nodeTemp);
if (null == node || !node.Quality || null == node.CurValue) //无值,退出
{
return;
}
TTaskRecord oldTask = _unityContainer.Resolve<TaskRecordService>().UnexecuteTask();
//1.有任务 + 自动 ,退出
//2.有任务 + 手动 + 任务执行中: 退出
if (null != oldTask)
{
if (oldTask.Status != (int)ETaskStatus.UnExecute)
{
return;
}
}
TaskEntity task = GetTask();
if (null == task)
{
return;
}
CommonCoreHelper.Instance.BlockTask.Add(task); //更新界面(任务未执行)
SetCount(node);
_lastStepId = (int)ETaskStep.MoveFrom; //StepId手动第一次为1自动第一次为10
if (!SendNextStep(task, node.Json, false)) //发送第一步
{
return; //发送失败
}
//一条任务第一次发任务时
if (!_unityContainer.Resolve<TaskRecordService>().ModifyTaskStatus(ETaskStatus.Executing)) //更新任务状态为执行中
{
LogHelper.Instance.Fatal("更改任务状态失败");
}
CommonCoreHelper.Instance.BlockTask.Add(task); //任务没有执行完。所以不需要更新界面
}
void SetCount(Variable node)
{
var model = agv.Read<Int16>(node.Address + node.VarName);
if (!model.IsSuccess
|| 1 != model.Content)
{
SettingProvider.Instance.CountCmd = 0; //每条任务从1开始
}
else
{
SettingProvider.Instance.CountCmd = 100;
}
}
private TaskEntity GetTask()
{
if (SettingProvider.Instance.DispMode == EDispatchMode.Auto)
{
var oldTask = _unityContainer.Resolve<TaskRecordService>().UnexecuteTask();
if (oldTask != null)
{
return GetStationManualTask(oldTask);
}
//看到过有任务还生成
return _unityContainer.Resolve<TaskRecordService>().GetTask(); //获得调度任务,并插入一条任务进任务记录表
}
else //手动从数据库获取
{
TTaskRecord manualTask = _unityContainer.Resolve<TaskRecordService>().UnexecuteTask();
if (null == manualTask)
{
return null; //没有任务(手动任务),就退出
}
return GetStationManualTask(manualTask);
}
}
/*
//1.执行中:机器人正在执行任务中, 如果上位机重启,会触发,
//2.无务任或任务执行完成:计命令计算为0或最后一步执行完成更新状态(无任务不需要),生成任务,下发下一步指令
//3.一步任务完成: 更新状态, 下发下一步指令
*/
public bool ThreadDealTask(DataValue data, Variable node)
{
string msg = "";
LogHelper.Instance.Error("开始接收调度机器人信息!");
Int16 countValue ;
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.TrigJson);
if (null == agv || !agv.IsConnect)
{
msg = "连接机器人的PLC断开!";
LogHelper.Instance.Error(msg);
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
return false;
}
try
{
var stepValue = agv.Read<Int16>((string)d.ReadCmd); //可以改成直接读PLC [命令地址]
var resultValue = agv.Read<int>((string)d.ReadResult); //这是直接读PLC [执行命令结果]
if (!stepValue.IsSuccess || !resultValue.IsSuccess)
{
LogHelper.Instance.Error($"PLC反馈任务时读取失败!,失败原因:{stepValue.Message},{stepValue.Message}");
return false;
}
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int16)
{
countValue = (Int16)data.WrappedValue.Value;
LogHelper.Instance.Debug($"接收任务信息:计数:{countValue},命令步:{stepValue.Content},结果:{resultValue.Content},当前命令步:{_lastStepId},当前计数:{SettingProvider.Instance.CountCmd}");
}
else
{
LogHelper.Instance.Warn($"没有找到这个数据类型,节点名为{node.VarDesc}", true);
return false;
}
if (!EnumHelper.IsDefined<ETaskStep>(stepValue.Content)) //不在范围内
{
LogHelper.Instance.Warn($"获取PLC的命令有问题值:{countValue}", true);
return false;
}
_unityContainer.Resolve<EquipmentMonitorViewModel>().SetAgvImage(resultValue.Content);
if (resultValue.Content == (int)EAgvMoveStatus.Error) // -1:表示没有完成
{
//if (countValue > SettingProvider.Instance.CountCmd) 此时上位机是1PLC是3。 如果执行下面后续PLC执行1就不会任务了
//{
// SettingProvider.Instance.CountCmd = countValue;
// LogHelper.Instance.Debug($"更改当前计数:{SettingProvider.Instance.CountCmd}");
//}
return false;
}
//1.机器人正在执行任务中, 如果上位机重启,此时又有任务
//如果:countValue=3000,Instance.CountCmd=1,时,到下面退出,也不影响。
if (countValue == SettingProvider.Instance.CountCmd - 1) //(重启上位机,任务在执行中)
{
LogHelper.Instance.Warn($"重启上位机,此时又有任务在执行中!");
return true;
}
if (_lastStepId == (int)ETaskStep.None)
{
LogHelper.Instance.Warn($"重启上位机, 没有任务在执行!");
return true;
}
//表示执行完成了,执行下一个; 或无任务
if (
countValue >= SettingProvider.Instance.CountCmd
&& stepValue.Content == _lastStepId
)
{
SettingProvider.Instance.CountCmd = countValue; //PLC跳步
TTaskRecord task = _unityContainer.Resolve<TaskRecordService>().UnexecuteTask();
if (null == task) //无任务:不需要做什么,有任务:更新状态
{
LogHelper.Instance.Fatal($"此时应该数据库中要有未执行的任务,计数:{countValue},命令:{stepValue}");
return true;
}
TaskEntity detailTask = GetStationManualTask(task); //通过任务,获取工站信息
detailTask.StepId = (sbyte)stepValue.Content;
if (!DealFinishCmd(detailTask, _lastStepId))
{
return false;
}
if (_lastStepId == (int)ETaskStep.Place //表示当前是一个任务的最后一条命令
/* || 0 == countCmd*/) //PLC重启为0一条完整的任务完成了,将获取最后一条指令
{
detailTask.StepId = (int)ETaskStep.Finish;
CommonCoreHelper.Instance.BlockTask.Add(detailTask); //机器人界面显示
CommonCoreHelper.Instance.MainViewAutoEvent.Set();
_newTaskEvent.Set();
return true; //完成了一条完整的任务,另外一个方法生成新的任务
}
//发送下一步命令
if (!SendNextStep(detailTask, node.Json))
{
return false;
}
CommonCoreHelper.Instance.BlockTask.Add(detailTask); //机器人界面显示
CommonCoreHelper.Instance.MainViewAutoEvent.Set();
LogHelper.Instance.Error("处理完接收调度机器人信息!");
}
else
{
LogHelper.Instance.Error($"接收到的信息PLC的调试任务异常,plc cmd:{stepValue},plc 计数:{countValue};\r" +
$"上位机 cmd:{_lastStepId},上位机 计数:{SettingProvider.Instance.CountCmd},正常不会执行到这里!");
}
}
catch(Exception ex)
{
LogHelper.Instance.GetCurrentClassError($"{ex.Message}-{ex.StackTrace}");
return false;
}
return true;
}
public bool SendNextStep(TaskEntity detailTask, string json, bool next = true)
{
LogHelper.Instance.Info($"发送步骤:{detailTask.StepId},命令计数:{SettingProvider.Instance.CountCmd}");
detailTask = SetNextStep(detailTask, next); //会设置CountCmd StepId
if (!SendTask(detailTask, json)) //发送任务
{
LogHelper.Instance.Error($"发送任务信息失败,{JsonConvert.SerializeObject(detailTask)}!");
return false;
}
_lastStepId = detailTask.StepId;
SettingProvider.Instance.CountCmd = detailTask.CountCmd;
LogHelper.Instance.Debug($"计数改变:{SettingProvider.Instance.CountCmd}");
return StartStep(detailTask);
}
public bool ManualTaskCmd(TTaskRecord task, short stepId) //界面上指定再发送一次时,
{
Variable nodeCountCmd = (from secondaryList in agv.Storages //不能做触发,因为没有任务。要地直运行里面,来检测是否有任务
from item in secondaryList.VariableList
where item.ParamName == EAgvPLC.RetCount.ToString()
select item).FirstOrDefault();
_lastStepId = (short)stepId;
TaskEntity detailTask = GetStationManualTask(task); //通过任务,获取工站信息
return SendNextStep(detailTask, nodeCountCmd.Json, false);
}
bool DealFinishCmd(TaskEntity detailTask, Int16 cmdValue)
{
if (0 >= _unityContainer.Resolve<TaskStepService>().UpdateEndTime(detailTask.Id, (ETaskStep)cmdValue))
{
LogHelper.Instance.Error($"修改命令结束时间失败任务ID:{detailTask.Id},命令:{_lastStepId}");
}
return UpdateFinishStep(detailTask);
}
bool StartStep(TaskEntity detailTask)
{
if (0 >= _unityContainer.Resolve<TaskStepService>().UpdateStartTime((int)detailTask.Id, detailTask.CountCmd, detailTask.StepId))
{
LogHelper.Instance.Error($"修改命令开始时间失败任务ID:{detailTask.Id},命令:{detailTask.StepId},命令计算:{detailTask.CountCmd}");
return false;
}
return true;
}
bool UpdateFinishStep(TaskEntity stationTask)
{
int result = 0;
switch (stationTask.StepId)
{
case (int)ETaskStep.MoveFrom:
//修改机器人的位置,给界面发信号
result =_unityContainer.Resolve<CavityInfoService>().SetRobotPos(stationTask.FromStationNumber);
break;
case (int)ETaskStep.Pick:
UpdateOutStoveTime(stationTask); //更改出炉时间
result = _unityContainer.Resolve<TaskRecordService>().BindPalletToRobot(); //将夹具绑定在机器人上
break;
case (int)ETaskStep.MoveTo:
result = _unityContainer.Resolve<CavityInfoService>().SetRobotPos(stationTask.ToStationNumber);
break;
case (int)ETaskStep.Place:
result = _unityContainer.Resolve<TaskRecordService>().UpdateTask(); //1.加锁解锁2.绑定解绑夹具3.更新机器人的位置,4.更新任务状态完成,
SendIntoStove(stationTask); //如果是满载夹具,要将调用烘烤进站接口
_unityContainer.Resolve<TaskRecordService>().UpdateFinishStepId(stationTask.Id); //修改任务步为完成
break;
default:
break;
}
if (result <= 0)
{
LogHelper.Instance.Error($"接到任务完成,但处理异常:{result},cmd:{stationTask.StepId}");
//return false;
}
return true;
}
void UpdateOutStoveTime(TaskEntity stationTask)
{
var cavityStove = _stationCavity.Where(x => x.Id == stationTask.Source && x.Type == (int)EStationType.Stove).FirstOrDefault();
if (null != cavityStove) //更改出炉时间
{
_unityContainer.Resolve<PalletInfoService>().UpdateOutStoveTime(cavityStove.PalletId);
}
}
void SendIntoStove(TaskEntity stationTask)
{
//if (!_unityContainer.Resolve<TaskTypeService>().IsPullInBaker(stationTask.TaskTypeId))
if (1 != stationTask.TaskTypeId)// 1: 上料满夹具->烤箱
{
return ;
}
var cavityInfo = _stationCavity.Where(x=>x.Id == stationTask.Target).FirstOrDefault();
var palletInfo = _unityContainer.Resolve<PalletInfoService>().GetPalletInfo(stationTask.PalletId);
List<string> batteryCodes = _unityContainer.Resolve<BatteryInfoService>().GetBatteryInfos(palletInfo.VirtualId).Select(x=>x.BatteryCode).ToList();
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable
&& 0 != batteryCodes.Count)
{
_unityContainer.Resolve<MESProcess>().MESBakingInput(cavityInfo.CavityName, palletInfo.PalletCode, batteryCodes, _unityContainer.Resolve<BasicInfoViewModel>().CurrentOperation);
}
}
public TaskEntity GetStationManualTask(TTaskRecord task)
{
TaskEntity taskEn = JSON.DeserializeObject<TaskEntity>(JSON.SerializeObject(task));
var sourceDetail = _unityContainer.Resolve<CavityInfoService>().GetStationDetailById(task.Source);
var targetDetail = _unityContainer.Resolve<CavityInfoService>().GetStationDetailById(task.Target);
var stationTask = MakeManualTask(taskEn, sourceDetail, targetDetail);
//stationTask.Copy(task, stationTask);
return stationTask;
}
TaskEntity SetNextStep(TaskEntity task, bool isNext = true)
{
sbyte nextStepId = (sbyte)_lastStepId;
if (isNext)
{
nextStepId = (sbyte)_unityContainer.Resolve<RgvActionService>().GetNext(_lastStepId); //下一步
}
task.CountCmd = SettingProvider.Instance.CountCmd + 1; //下一个计数
task.StepId = (sbyte)nextStepId;
return task;
}
public TaskEntity MakeManualTask(TaskEntity taskEn, TCavityInfo src, TCavityInfo desc)
{
taskEn.FromStationNumber = src.StationNumber;
taskEn.FromRow = src.Layer;
taskEn.FromColumn = src.Column;
taskEn.ToStationNumber = desc.StationNumber;
taskEn.ToRow = desc.Layer;
taskEn.ToColumn = desc.Column;
return taskEn;
}
public bool SendTask(TaskEntity task, string json)
{
LogHelper.Instance.Info($"发送任务开始");
List<AddrValue> makeAddrValues = new List<AddrValue>();
dynamic d = JsonConvert.DeserializeObject<dynamic>(json);
string fromStation = d.FromStation;
string fromLayer = d.FromRow;
string fromColumn = d.FromColumn;
string toStation = d.ToStation;
string toLayer = d.ToRow;
string toColumn = d.ToColumn;
string cmd = d.Cmd;
string countAddr = d.Count;
makeAddrValues.Add(new AddrValue()
{
Addr = fromStation,
Value = (int)task.FromStationNumber,
});
var from = _station.Where(p => p.Id == (int)task.FromStationNumber).FirstOrDefault();
if (from.Type == (int)EStationType.Loading
|| from.Type == (int)EStationType.UnLoading)
{
makeAddrValues.Add(new AddrValue()
{
Addr = fromLayer,
Value = (int)task.FromRow,
});
makeAddrValues.Add(new AddrValue()
{
Addr = fromColumn,
Value = (int)task.FromColumn,
});
}
else
{
makeAddrValues.Add(new AddrValue()
{
Addr = fromLayer,
Value = (int)task.FromColumn,
});
makeAddrValues.Add(new AddrValue()
{
Addr = fromColumn,
Value = (int)task.FromRow,
});
}
makeAddrValues.Add(new AddrValue()
{
Addr = toStation,
Value = (int)task.ToStationNumber,
});
var to = _station.Where(p => p.Id == (int)task.ToStationNumber).FirstOrDefault();
if (to.Type == (int)EStationType.Loading
|| to.Type == (int)EStationType.UnLoading)
{
makeAddrValues.Add(new AddrValue()
{
Addr = toLayer,
Value = (int)task.ToRow,
});
makeAddrValues.Add(new AddrValue()
{
Addr = toColumn,
Value = (int)task.ToColumn,
});
}
else
{
makeAddrValues.Add(new AddrValue()
{
Addr = toLayer,
Value = (int)task.ToColumn,
});
makeAddrValues.Add(new AddrValue()
{
Addr = toColumn,
Value = (int)task.ToRow,
});
}
makeAddrValues.Add(new AddrValue()
{
Addr = cmd,
Value = (Int16)task.StepId,
});
//makeAddrValues.Add(new AddrValue()
//{
// Addr = countAddr,
// Value = (Int16)task.CountCmd, //必须最后一个写
//});
OperateResult result = agv.Writes(makeAddrValues.Select(x => x.Addr).ToArray(), makeAddrValues.Select(x => x.Value).ToArray());
if (!result.IsSuccess)
{
LogHelper.Instance.Fatal($"写任务步骤失败:{JsonConvert.SerializeObject(makeAddrValues)},{JsonConvert.SerializeObject(makeAddrValues)}");
}
result = agv.Write<Int16>(countAddr, (Int16)task.CountCmd);
if (!result.IsSuccess)
{
LogHelper.Instance.Fatal($"写任务计数失败:{JsonConvert.SerializeObject(makeAddrValues)},{JsonConvert.SerializeObject(makeAddrValues)}");
}
LogHelper.Instance.Debug($"发送任务:{JsonConvert.SerializeObject(makeAddrValues)}");
LogHelper.Instance.Debug($"发送计数:{countAddr}:{(Int16)task.CountCmd}");
//_unityContainer.Resolve<LogService>().AddLog("TaskStation:SendTask:发送任务结束", E_LogType.Info.ToString());
return result.IsSuccess;
}
public void Stop()
{
// 在需要取消任务的时候,调用以下代码:
cts.Cancel();
}
}
}

View File

@@ -0,0 +1,225 @@
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Interface;
using Cowain.Bake.Communication.PLC;
using Cowain.Bake.Main.ViewModels;
using Cowain.Bake.Model.Models;
using Newtonsoft.Json;
using Opc.Ua;
using System;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Unity;
namespace Cowain.Bake.Main.Station
{
public class TrigStation : ITrigService
{
IUnityContainer _unityContainer;
readonly CancellationTokenSource cts = new CancellationTokenSource();
public TrigStation(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
//怕消息先后导致异常,所以只能单个去
//for (int i = 0; i < 3; i++) //还有心跳,就放开这个功能
{
Start();
}
}
public void Start()
{
Task.Run( () =>
{
while (true)
{
if (Global.AppExit)
{
return;
}
BlockData item = _unityContainer.Resolve<PLCBlockingCollection>().MsgBlock.Take();
int msgCount = _unityContainer.Resolve<PLCBlockingCollection>().MsgBlock.Count;
if ("Heart" == item.Node.ParamName) //消息队列太多,就删除心跳
{
if (msgCount >= 5)
{
LogHelper.Instance.Error($"----------消费者消息数:{msgCount}");
continue;
}
Task.Run(() => ExecuteHeartTask(item.Data, item.Node));
}
else
{
RecvTrigInfo(item.Data, item.Node);
}
}
});
}
void ExecuteHeartTask(DataValue data, Variable node)
{
RecvTrigInfo(data, node);
}
//多线程处理
public void RecvTrigInfo(DataValue data, Variable node)
{
int value = 0;
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.TrigJson);
string service = d.Service;
string func = d.Func;
string trigValue = d.TrigValue;
string param = d.Param; //方法的参数,如果是扫码,则是扫码的编号
MethodInfo mi = null;
if (string.IsNullOrEmpty(service)
|| string.IsNullOrEmpty(func))
{
LogHelper.Instance.Error("解析触发信号信息失败!解析内容:" + node.TrigJson);
return;
}
Type type = Type.GetType(MyPath.SIGNAL_TRIGGER + service);
if (!string.IsNullOrEmpty(trigValue))
{
value = GetTrigValue(data);
if (data.Value.GetType().IsArray)
{
if (value == 0) //节点的值跟所触发的信号相同(6098,扫码是数组)
{
return;
}
}
else
{
if (value != int.Parse(trigValue)) //节点值
{
return;
}
}
//LogHelper.Instance.Info($"5--------------信号,线程ID:{System.Threading.Thread.CurrentThread.ManagedThreadId},{node.VarDesc}:{param},func:{func},value:{value},{node.Json}"); //执行到这,信号都会丢,
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("开始:" + node.VarDesc);
mi = this.GetType().GetMethod(ReflexFun.TRIG_REPLY).MakeGenericMethod(new Type[] { type }); //回复信息;
mi.Invoke(this, new object[]
{
func,
value,
param,
node
});
//_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束0:" + node.VarDesc);
}
else
{
mi = this.GetType().GetMethod(ReflexFun.TRIG_INSTANCE).MakeGenericMethod(new Type[] { type }); //夹具信号,报警这些;
mi.Invoke(this, new object[]
{
func,
data,
node
});
}
}
public void TrigInstance<T>(string func, DataValue data, Variable node)
{
//取得实例
var instnce = _unityContainer.Resolve<T>();
Type t = instnce.GetType();
//取得方法
MethodInfo mi = t.GetMethod(func);
//调用方法
mi.Invoke(instnce, new object[]
{
data,
node
});
}
public void TrigReply<T>(string func, int curValue, string param, Variable node)
{
//取得实例
var instnce = _unityContainer.Resolve<T>(); //上下料实例
Type t = instnce.GetType();
//取得方法
MethodInfo mi = t.GetMethod(func);
//调用方法
mi.Invoke(instnce, new object[]
{
curValue,
param,
node
});
}
private int GetTrigValue(DataValue data)
{
int value = 0;
if (data.WrappedValue.TypeInfo.ValueRank == 1) //数组
{
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Boolean) //下料扫码
{
bool[] values = (bool[])data.Value;
for (int i = 0; i < values.Count(); i++)
{
if (values[i])
{
double temp = Math.Pow(2, i); //o
value += (int)temp;
}
}
}
else //上料扫码
{
Int16[] values = (Int16[])data.Value;
for (int i = 0; i < values.Count(); i++)
{
double temp = values[i] * Math.Pow(2, i); //ok
value += (int)temp;
}
LogHelper.Instance.Fatal($"接收扫码信号:{string.Join(",", values)},{value}");
}
}
else
{
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.UInt16)
{
value = (UInt16)data.WrappedValue.Value;
}
else if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int16)
{
value = (Int16)data.WrappedValue.Value;
}
else if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int32)
{
value = (Int32)data.WrappedValue.Value;
}
else if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.UInt32)
{
value = (int)data.WrappedValue.Value;
}
else if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Boolean)
{
value = ((bool)data.WrappedValue.Value) ? 1 : 0;
}
else
{
value = (int)data.WrappedValue.Value;
}
}
return value;
}
}
}

View File

@@ -0,0 +1,772 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Common.Interface;
using Cowain.Bake.Common.Models;
using Cowain.Bake.Communication.Interface;
using Cowain.Bake.Communication.MOM;
using Cowain.Bake.Main.ViewModels;
using Cowain.Bake.Main.Views;
using Cowain.Bake.Model;
using Cowain.Bake.Model.Entity;
using Cowain.Bake.Model.Models;
using Cowain.Bake.UI.CsvMap;
using HslCommunication;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Unity;
using static Cowain.Bake.Common.Models.MESModel;
using JSON = Newtonsoft.Json.JsonConvert;
namespace Cowain.Bake.Main.Station
{
public class UnLoadingStation : IServerManager
{
IPLCDevice PLC { get; set; }
const int DUMMY_POS_SIZE = 3;
private int _batteryCodeLen = 0;
List<IScanCodeBase> _deviceScann = new List<IScanCodeBase>();
List<TBatteryInfo> _tempList = new List<TBatteryInfo>();
public string Name { get; set; }
public IUnityContainer _unityContainer { get; set; }
private readonly Prism.Events.IEventAggregator _eventAggregator;
public UnLoadingStation(IUnityContainer unityContainer, Prism.Events.IEventAggregator eventAggregator)
{
_unityContainer = unityContainer;
_eventAggregator = eventAggregator;
TDeviceConfig config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.PLC, EDeviceName.Loading)[0]; //上下料一个PLC
Name = config.Name;
SetBatteryCodeLen();
Start();
}
bool IsConnectPLC()
{
if (null == PLC || !PLC.IsConnect)
{
LogHelper.Instance.Error($"PalletVirtualId:{PLC.Name},PLC为空!");
return false;
}
return true;
}
public void Start()
{
var configScann = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.SCANNER).OrderByDescending(x => x.Id).Take(8).ToList();
foreach (var item in configScann)
{
IScanCodeBase device = _unityContainer.Resolve<IScanCodeBase>(item.Name);
_deviceScann.Add(device);
}
PLC = _unityContainer.Resolve<IPLCDevice>(Name); //下料PLC
System.Threading.Tasks.Task.Run(() => BuildRecordFile());
}
void BuildRecordFile()
{
string dateFile = "";
string filePath = "";
string path = _unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DataFilePath.ToString());//
path += "\\出站";
while (true)
{
Thread.Sleep(1000 * 60);
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
dateFile = DateTime.Now.ToString("yyyyMMdd");
filePath = path + $"\\{dateFile}.csv";
var batteryList = _unityContainer.Resolve<BatteryInfoService>().GetOutbound();
if (null == batteryList)
{
continue;
}
try
{
CSVHelper.WriteMap<BatteryInfoEntity, BatteryInfoDetailMap>(batteryList, filePath);
foreach (var item in batteryList)
{
if (0 == _unityContainer.Resolve<BatteryInfoService>().UpdateStatus(item.Id, (int)EBatteryStatus.OutBoundRecord))
{
LogHelper.Instance.Fatal("修改记录出站状态失败!");
}
}
}
catch (Exception ex)
{
LogHelper.Instance.Fatal($"BuildRecordFile{ex.Message}");
}
}
}
void SetDummyToWaterPlatform(string param)
{
int number = int.Parse(param);
int palletId = _unityContainer.Resolve<CavityInfoService>().GetPalletId((int)EStationType.UnLoading, number);
_unityContainer.Resolve<BLL.BatteryInfoService>().SetDummyToWaterPlatform(palletId);
}
//开始下料 ,,验证数据库OK (分二次执行,一次取假电芯,一次取正常电芯)
public void ExecuteUnLoading(int curValue, string param, Variable node)
{
//Int16 batteryType = 1; //1:假电芯, 0:正常电芯
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
if (!IsConnectPLC()) return;
try
{
if (GetUnloadBattery(param, node.Json, out bool isUnLodingDummy, out TPalletInfo palletInfo))
{
_unityContainer.Resolve<LogService>().AddLog("ExecuteUnLoading:下料写入托盘电池信息!", E_LogType.Info.ToString());
WriteBatteryPostionToPLC(palletInfo, node.Json, isUnLodingDummy);
}
else
{
//SetEmptyPallet(node.Json); //如果上料中写了下料电芯数据,此时再重启上位机,状态为“下料中”,会清除,所以注释
}
var writeResult = PLC.Write<Int16>((string)d.WriteResult, 1);
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Error($"ExecuteScanPallet-写数据失败:{(string)d.WriteResult}:{writeResult.Message}");
}
}
catch (Exception ex)
{
LogHelper.Instance.Error($"ExecuteUnLoading出错,{ex.Message},param{param},{node.Json}");
}
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
}
/// <summary>
/// 结果数据上传到MOM烘烤开始时间烘烤结束时间烘烤温度真空值,出炉冷却后温度
/// </summary>BakingOutputCmd,MESReturnCmdModel
/// <param name="batterys"></param>
/// <param name="palletInfo"></param>
public MESReturnCmdModel MesOutUnBinding(TPalletInfo palletInfo, List<TBatteryInfo> betterys, bool realTimeSend = false)
{
if (0 == palletInfo.BakingPosition.Value)
{
palletInfo.BakingPosition = 1; //防呆
LogHelper.Instance.Error("手动触发烘烤完成,没有烘烤位置!");
}
TCavityInfo cavityInfo = _unityContainer.Resolve<CavityInfoService>().GetStationDetailById(palletInfo.BakingPosition.Value);
if (null == cavityInfo)
{
LogHelper.Instance.GetCurrentClassError("通过烘烤位置查找托盘位置失败");
return null;
}
return _unityContainer.Resolve<MESProcess>().MESBakingOutput(cavityInfo.Name, palletInfo, betterys, true, realTimeSend);
}
//请求下料,出现异常处理
TPalletInfo DealStartUnloadFail(int number)
{
//去机器人上获取夹具信息,此时没有转移。
TPalletInfo palletInfo = _unityContainer.Resolve<BLL.PalletInfoService>().GetRobotPallet();
if (null != palletInfo)
{
LogHelper.Instance.Error("请求下料的夹具在机器人上面!");
return palletInfo;
}
//如果还没有,再到下料获取。
int palletId = _unityContainer.Resolve<CavityInfoService>().GetPalletId((int)EStationType.UnLoading, number);
return _unityContainer.Resolve<BLL.PalletInfoService>().GetPalletInfo(palletId);
}
private bool GetUnloadBattery(string param, string reply, out bool isUnLodingDummy, out TPalletInfo palletInfo)
{
isUnLodingDummy = false;
dynamic d = JsonConvert.DeserializeObject<dynamic>(reply);
OperateResult operateResultX = null, operateResultY = null;
OperateResult operateResult = null;
List<TBatteryInfo> batterys = null;
TBatteryInfo dummy;
Int16 batteryType = 1; //1:假电芯, 0:正常电芯
int number = int.Parse(param);
Int16[] dummyPos = new Int16[DUMMY_POS_SIZE];
int[] batteryVirtualId = new int[Global.PALLET_MAX_BATTERYS];
Array.Clear(batteryVirtualId, 0, Global.PALLET_MAX_BATTERYS);
int palletId = _unityContainer.Resolve<CavityInfoService>().GetPalletId((int)EStationType.UnLoading, number);
palletInfo = _unityContainer.Resolve<BLL.PalletInfoService>().GetPalletInfo(palletId);
//要求PLC必须在上位机反馈任务完成之后再请求托盘参数
if (null == palletInfo) //会出现异常(发触发下料,再告诉上位机放)
{
palletInfo = DealStartUnloadFail(number);
if (null == palletInfo) //
{
LogHelper.Instance.Error($"接收到下料信号,但获取不到下料工站{param}的夹具信息!", true);
return false;
}
}
batterys = _unityContainer.Resolve<BLL.BatteryInfoService>().GetBatteryInfos(palletInfo.VirtualId);
if (0 == batterys.Count)
{
_unityContainer.Resolve<LogService>().AddLog($"下料工站{param},找不到电池位置数据!", E_LogType.Info.ToString());
return false;
}
//要满足下料条件
if (palletInfo.PalletStatus != (int)EPalletStatus.BakeOver
&& palletInfo.PalletStatus != (int)EPalletStatus.TestOK)
{
LogHelper.Instance.Fatal($"下料夹具状态不对,请人为处理,要求状态:{EPalletStatus.BakeOver.GetDescription()},{EPalletStatus.TestOK.GetDescription()},实际状态:" +
$"{((EPalletStatus)palletInfo.PalletStatus).GetDescription()}");
return false;
}
if (palletInfo.PalletStatus == (int)EPalletStatus.BakeOver
&& _unityContainer.Resolve<BLL.BatteryInfoService>().IsPalletDummy(palletInfo.VirtualId)) //带水含量电芯,要测试
{
dummy = _unityContainer.Resolve<BLL.BatteryInfoService>().FindDummy(palletInfo, batterys);
isUnLodingDummy = true;
if (null == dummy)
{
LogHelper.Instance.Fatal("获取假电芯信息失败!");
return false;
}
dummyPos[1] = (Int16)dummy.PositionX.Value;
dummyPos[2] = (Int16)dummy.PositionY.Value;
operateResultX = PLC.Write<Int16>((string)d.WriteDummyX, dummyPos[1]); //托盘假电池行列数
operateResultY = PLC.Write<Int16>((string)d.WriteDummyY, dummyPos[2]); //托盘假电池行列数
if (!operateResultX.IsSuccess
|| !operateResultY.IsSuccess)
{
LogHelper.Instance.Debug($"设置托盘假电池行列数失败:{operateResultX.Message},{operateResultY.Message}");
return false;
}
}
else
{
batteryType = 0; //正常电芯
_unityContainer.Resolve<BLL.PalletInfoService>().UpdateUnLoadingBegingTime(palletInfo.Id);
List<TBatteryInfo> normalBatterys = (from b in batterys
where b.BatteryStatus <= (int)EBatteryStatus.ToPallet
select b).ToList();
if (Global.PALLET_ROWS < Global.PALLET_COLS) //7行24列:行少列多
{
foreach (var item in normalBatterys)
{
batteryVirtualId[(item.PositionX.Value - 1) * Global.PALLET_COLS + item.PositionY.Value] = item.Id;
}
}
else//48行,2列: 行少列多
{
foreach (var item in normalBatterys)
{
batteryVirtualId[(item.PositionY.Value - 1) * Global.PALLET_ROWS + item.PositionX.Value] = item.Id;
}
}
LogHelper.Instance.Info("下料写入电芯位置:" + JSON.SerializeObject(batteryVirtualId));
}
//水含量电芯时全为0
operateResult = PLC.Write<int[]>((string)d.WriteVirtualIds, batteryVirtualId); //托盘_有无电池[1-120]
if (!operateResult.IsSuccess)
{
LogHelper.Instance.Error($"设置托盘_有无电池失败:{operateResult.Message}");
}
//电芯类型
operateResult = PLC.Write<Int16>((string)d.WriteType, batteryType); //托盘1正常电芯下料
if (!operateResult.IsSuccess)
{
LogHelper.Instance.Error($"写下料电芯类型失败:{(string)d.WriteType},{operateResult.Message}");
return false;
}
return true;
}
//写下料位置的电池位置信息给PLC
private void WriteBatteryPostionToPLC(TPalletInfo palletInfo, string reply, bool isUnLodingDummy)
{
Int16 lastValue = 0;
dynamic d = JsonConvert.DeserializeObject<dynamic>(reply);
OperateResult operateResult = null;
////水含量电芯时全为0
//operateResult = PLC.Write<int[]>((string)d.WriteVirtualIds, batteryVirtualId); //托盘_有无电池[1-120]
//if (!operateResult.IsSuccess)
//{
// LogHelper.Instance.Error($"设置托盘_有无电池失败:{operateResult.Message}");
//}
if (!isUnLodingDummy)
{
lastValue = (Int16)(palletInfo.LastFlag ? 1 : 0);
}
operateResult = PLC.Write<Int16>((string)d.WriteLastFlag, lastValue); //最后一盘
if (!operateResult.IsSuccess)
{
LogHelper.Instance.Error($"设置托盘最后一盘失败:{operateResult.Message},{operateResult.Message}");
}
//在给下料参数成功之后,再更新托盘状态。
if (0 == _unityContainer.Resolve<BLL.PalletInfoService>().UpdatePalletStatus(palletInfo.Id, (int)EPalletStatus.Blank))
{
LogHelper.Instance.Error($"在给下料参数成功之后,再更新托盘状态:{operateResult.Message},{operateResult.Message}");
}
}
public void SetEmptyPallet(string reply)
{
_unityContainer.Resolve<LogService>().AddLog("SetEmptyPallet:设置空托盘", E_LogType.Info.ToString());
dynamic d = JsonConvert.DeserializeObject<dynamic>(reply);
List<AddrValue> makeAddrValues = new List<AddrValue>();
int[] batteryVirtualId = new int[Global.PALLET_MAX_BATTERYS];
Array.Clear(batteryVirtualId, 0, Global.PALLET_MAX_BATTERYS);
makeAddrValues.Add(new AddrValue()
{
Addr = (string)d.WriteDummyX,
Value = (Int16)0
});
makeAddrValues.Add(new AddrValue()
{
Addr = (string)d.WriteDummyY,
Value = (Int16)0
});
makeAddrValues.Add(new AddrValue()
{
Addr = (string)d.WriteType,
Value = (Int16)0
});
makeAddrValues.Add(new AddrValue()
{
Addr = (string)d.WriteVirtualIds,
Value = batteryVirtualId
});
makeAddrValues.Add(new AddrValue()
{
Addr = (string)d.WriteResult,
Value = true
});
OperateResult result = PLC.Writes(makeAddrValues.Select(x => x.Addr).ToArray(), makeAddrValues.Select(x => x.Value).ToArray());
if (!result.IsSuccess)
{
LogHelper.Instance.GetCurrentClassError("清空托盘失败!");
}
}
public void ExecuteUnLoadingFinish(int curValue, string param, Variable node)
{
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
//-----------------------------------------------------------------------------
int debugMode = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DebugMode.ToString())); //0为测试模式1为正式模式
if (!IsConnectPLC()) return;
//得到这个工站的夹具,通过夹具得到电芯
int number = int.Parse(param);
int palletId = _unityContainer.Resolve<BLL.CavityInfoService>().GetPalletId((int)EStationType.UnLoading, number);
TPalletInfo palletInfo = _unityContainer.Resolve<BLL.PalletInfoService>().GetPalletInfo(palletId);
if (null == palletInfo)
{
LogHelper.Instance.Error($"托盘为空, 下料{number}#工站,palletId:{palletId}");
return;
}
_unityContainer.Resolve<BLL.PalletInfoService>().UpdateUnLoadingOverTime(palletInfo.Id);
if (0 == palletInfo.VirtualId
|| 1 == palletInfo.Id)
{
LogHelper.Instance.Error($"下料夹具异常, 下料托盘的虚拟码为0或下料托盘为【新夹具】");
}
else
{
_unityContainer.Resolve<BLL.PalletInfoService>().PalletInfoToHistory(palletInfo.VirtualId,
(int)EPalletStatus.BlankOver, (int)EBatteryStatus.Over, (int)EStationType.UnLoading, number);
}
var writeResult = PLC.Write<Int16>((string)d.WriteResult, 1);
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"ExecuteUnLoadingFinish-{(string)d.WriteResult}:{writeResult.Message}");
}
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
}
/// <summary>
/// 核对电芯条码,下料扫码
/// </summary>
//void VerifyBatteryCode(int curValue, string param, string reply)
//{
// dynamic d = JsonConvert.DeserializeObject<dynamic>(reply);
// var result = DealVerify(reply);
// var writeResult = PLC.Write<bool[]>((string)d.WriteResult, result.Result);//
// if (!writeResult.IsSuccess)
// {
// LogHelper.Instance.GetCurrentClassWarn($"{(string)d.WriteResult}:{writeResult.Message}");
// }
//}
//async Task<bool[]> DealVerify(string reply)
//{
// int index = 0, j = 0;
// bool[] results = new bool[Global.ONCE_SCAN_BATTERY];
// Array.Clear(results, 0, Global.ONCE_SCAN_BATTERY);
// List<Task<OperateResult<string>>> scannTasks = new List<Task<OperateResult<string>>>();
// dynamic d = JsonConvert.DeserializeObject<dynamic>(reply);
// if (!IsConnectPLC()) return results;
// OperateResult<Int32[]> batterys = PLC.Read<Int32[]>((string)d.ReadVirtualIds); //下料处电芯虚拟码 读取下料温度[1..8]
// if (!batterys.IsSuccess)
// {
// LogHelper.Instance.Warn($"核对电芯条码时,读取电芯虚拟码错误:{batterys.Message}");
// return results;
// }
// if (batterys.Content.All(x => x == 0)) //True 全部为0
// {
// LogHelper.Instance.Warn($"核对电芯条码时读取电芯虚拟码异常全部虚拟码都为0");
// return results;
// }
// //读条码
// for (EScanCode s = EScanCode.UnLoadingBatteryScan1; s <= EScanCode.UnLoadingBatteryScan8; s++, index++)
// {
// if (0 == batterys.Content[index])
// {
// continue;
// }
// IScanCodeBase scanDevice = _deviceScann.Find(x => x.Name == s.ToString());
// if (!scanDevice.IsConnect)
// {
// string msg = $"获取{s.GetDescription()}失败,请检测线路!";
// LogHelper.Instance.Error(msg, true); //弹屏,人为处理好后,再次触发
// _unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
// scanDevice.Connect();
// --s; //再次获取
// continue;
// }
// scannTasks.Add(Task.Run(() => scanDevice.ReadCode())); // 启动并行任务
// }
// await Task.WhenAll(scannTasks); //等待所有任务(扫码)完成
// index = 0;
// var batteryCodes = GetBatteryCode(batterys.Content);//获取PLC传过来的虚拟码
// //比较条码
// for (EScanCode s = EScanCode.UnLoadingBatteryScan1; s <= EScanCode.UnLoadingBatteryScan8; s++, j++)
// {
// if (0 == batterys.Content[index])
// {
// continue;
// }
// if (!batteryCodes.Contains(scannTasks[index++].Result.Content)) //没有用等于号,是因为这样兼容更好一点
// {
// LogHelper.Instance.Warn($"下料核对电芯异常PLC电芯:{string.Join(",", batteryCodes)},扫码电芯:{JSON.SerializeObject(scannTasks)}");
// //continue; //异常
// }
// else
// {
// results[j] = true;
// }
// }
// _unityContainer.Resolve<MainWindowViewModel>().DeletePromptContent();
// return results;
//}
//取假电芯完成验证数据库OK
public void ExecuteTakeDummyFinish(int curValue, string param, Variable node)
{
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
if (!IsConnectPLC()) return;
_unityContainer.Resolve<LogService>().AddLog("UnLoadingStation:ExecuteTakeDummyFinish:取假电池开始:" + param, E_LogType.Info.ToString());
int number = int.Parse(param);
int palletId = _unityContainer.Resolve<BLL.CavityInfoService>().GetPalletId((int)EStationType.UnLoading, number);
TPalletInfo palletInfo = _unityContainer.Resolve<BLL.PalletInfoService>().GetPalletInfo(palletId);
if (null == palletInfo)
{
LogHelper.Instance.Error($"接收下料{number}工站取假电芯完成信号,但获取不到下料夹具!", true);
return;
}
//这里再改假电芯状态
SetDummyToWaterPlatform(param);
//重启后可能再次收到1#托盘取假电池完成信号待水含量测试此时状态可能测试OK或NG
if (palletInfo.PalletStatus == (int)EPalletStatus.BakeOver
|| palletInfo.PalletStatus == (int)EPalletStatus.Blank) //取水含量电芯时,也是下料中状态
{
_unityContainer.Resolve<BLL.PalletInfoService>().UpdatePalletStatus(palletInfo.Id, (int)EPalletStatus.WaitTest);
}
var writeResult = PLC.Write<Int16>((string)d.WriteResult, 1);
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"ExecuteTakeDummyFinish-{(string)d.WriteResult}:{writeResult.Message}");
}
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
}
public void SetBatteryCodeLen()
{
_batteryCodeLen = int.Parse(_unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>().GetValueByParaID(ESysSetup.BatteryCodeLen.ToString()));
}
public async Task<List<OperateResult<string>>> GetScannResult(int curValue)
{
int index = 1;
List<string> batteryCodes = new List<string>();
List<OperateResult<string>> scannList = new List<OperateResult<string>>();
List<Task<OperateResult<string>>> scannTasks = new List<Task<OperateResult<string>>>();
OperateResult<string> scanResult = new OperateResult<string>()
{
IsSuccess = false,
};
for (EScanCode s = EScanCode.UnLoadingBatteryScan1; s <= EScanCode.UnLoadingBatteryScan8; s++, index++)
{
if (((curValue >> index) & 1) != 1) //第index位不是1,就是不需要扫码
{
continue;
}
IScanCodeBase scanDevice = _deviceScann.Find(x => x.Name == s.ToString());
if (!scanDevice.IsConnect)
{
string msg = $"获取{s.GetDescription()}失败,请检测线路!";
LogHelper.Instance.Error(msg, true); //弹屏,人为处理好后,再次触发
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
scanDevice.Connect();
--s; //再次获取
continue;
}
scannTasks.Add(Task.Run(() => scanDevice.ReadCode())); // 启动并行任务
}
await Task.WhenAll(scannTasks); //等待所有任务(扫码)完成
foreach (var task in scannTasks)
{
scannList.Add(task.Result);
}
return scannList;
}
public async Task<bool[]> DealTemp(IPLCDevice plc, int curValue, string reply)
{
string msg = "";
int index = 1;
int scannIndex = 0;
bool[] repResults = new bool[Global.ONCE_SCAN_BATTERY + 1];
dynamic d = JsonConvert.DeserializeObject<dynamic>(reply);
List<string> batteryCodes = null;
List<OperateResult<string>> scannList;
MESReturnCmdModel result = null;
bool isDummy = false;
Array.Clear(repResults, 0, Global.ONCE_SCAN_BATTERY + 1);
int debugMode = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DebugMode.ToString())); //0为测试模式1为正式模式
_tempList.Clear();
try
{
if (!IsConnectPLC()) return null;
OperateResult<float[]> readTemps = plc.Read<float[]>((string)d.ReadTemp); //下料处电芯温度,读取下料温度[1..4]
if (!readTemps.IsSuccess)
{
LogHelper.Instance.Warn("读取下料温度失败");
return null;
}
if ((int)EProductionMode.Debug == debugMode) //调试模式
{
repResults[1] = true;
return repResults;
}
scannList = await GetScannResult(curValue); //
for (EScanCode s = EScanCode.UnLoadingBatteryScan1; s <= EScanCode.UnLoadingBatteryScan8; s++, index++)
{
if (((curValue >> index) & 1) != 1) //第index位不是1,就是不需要扫码
{
continue;
}
repResults[index] = true;
if (scannList[scannIndex].IsSuccess)
{
_tempList.Add(new TBatteryInfo()
{
BatteryCode = scannList[scannIndex].Content, //实际要扫码
CoolTemp = readTemps.Content[index] //1...8排序
});
}
else
{
if (MessageBoxResult.Yes == HandyControl.Controls.MessageBox.Show($"[{s.GetDescription()}]扫码失败,您确定此位置是否有电芯?", "提示", MessageBoxButton.YesNo, MessageBoxImage.Information))
{
_tempList.Add(new TBatteryInfo()
{
BatteryCode = GetBatteryCode(s.GetDescription()), //弹屏,输入电芯条码
CoolTemp = readTemps.Content[index] //1...8排序
});
}
else //无电芯
{
repResults[index] = false; //扫码NG并人为确认无电芯
}
}
scannIndex++;
}
batteryCodes = _tempList.Select(x => x.BatteryCode).ToList();
LogHelper.Instance.Info($"读取下料PLC的电芯虚拟码:{string.Join(",", batteryCodes)}");
List<TBatteryInfo> currentBatterys = _unityContainer.Resolve<BatteryInfoService>().GetBatterys(batteryCodes); //8个电芯(最多),可能会来自多个托盘
if (null == currentBatterys
|| currentBatterys.Count == 0) //PLC有BUG有时为0导致上位机没办法回复会PLC超时
{
msg = $"下发温度读取失败,{Global.ONCE_SCAN_BATTERY}个电池虚拟码为0!";
LogHelper.Instance.Error("下发温度读取完成失败,电池虚拟码为0!");
_unityContainer.Resolve<LogService>().AddLog("下发温度读取完成失败,电池虚拟码为0!", E_LogType.Fatal.ToString());
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
return repResults;
}
else if (currentBatterys.Count == 1) //一个电芯,判断是否是假电芯
{
if (_unityContainer.Resolve<BatteryInfoService>().IsDummy(currentBatterys[0].Id))
{
isDummy = true;
return repResults; //假电芯就不上传了
}
}
_unityContainer.Resolve<BatteryInfoService>().UpdateCoolTempAndUnBindingTime(currentBatterys, _tempList);// temps);
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable)
{
var batterySort = currentBatterys.GroupBy(p => new { p.PalletVirtualId }).Select(s => s.FirstOrDefault()).ToList(); //获取一个托盘中的一个电芯
foreach (var item in batterySort) //一个托盘只返回第一个电芯
{
var palletBatterys = currentBatterys.Where(x => batteryCodes.Contains(x.BatteryCode) && x.PalletVirtualId == item.PalletVirtualId).ToList(); //获取一个托盘中的电芯
TPalletInfo palletInfo = _unityContainer.Resolve<BLL.PalletInfoService>().GetPalletInfoByBatteryVirtualId(item.PalletVirtualId); //此时托盘可能已经转历史盘托了
if (null == palletInfo)
{
msg = $"MOM上传冷却温度时,找不到电芯所在托盘,电芯:{string.Join(",", palletBatterys.Select(x => x.BatteryCode).ToList())}!";
LogHelper.Instance.Fatal(msg);
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
return null;
}
var mesResult = MesOutUnBinding(palletInfo, palletBatterys);//组装数据 发送
//因为没有等MOM所以注掉下面代码
//if (mesResult == null)
//{
// LogHelper.Instance.Error($"自动出站MOM返回超时,电芯条码:{string.Join(",", palletBatterys.Select(x => x.BatteryCode).ToList())}"); //偶尔会返回空,导致人为要处理,麻烦,所以只保存到日志
//}
//else if (mesResult.Info.ResultFlag.ToUpper() == "NG" && (!isDummy))
//{
// msg = $"自动出站MOM返回信息异常,信息:{JSON.SerializeObject(result)}";
// LogHelper.Instance.Error(msg);
// _unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
//}
//else
//{
// _unityContainer.Resolve<MainWindowViewModel>().DeletePromptContent();
//}
}
}
}
catch (Exception e)
{
LogHelper.Instance.Fatal($"读温失败:{e.Message},{e.StackTrace}");
}
return repResults;
}
public string GetBatteryCode(string desc)
{
string batteryCode = "";
while (string.IsNullOrEmpty(batteryCode))
{
Application.Current.Dispatcher.Invoke((Action)(() =>
{
PalletIdInputWindow f = new PalletIdInputWindow("电芯码输入框", $"{desc}扫码失败," + "请输入电芯条码", "确定输入电芯条码?")
{
WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen,
};
f.ShowDialog();
batteryCode = f.PalletId;
}));
if (!_unityContainer.Resolve<BatteryInfoService>().IsBatteryCodeRepeat(batteryCode))
{
LogHelper.Instance.Error($"【{batteryCode}】,不存在,请重新输入!", true);
batteryCode = "";
}
}
return batteryCode;
}
//获取下料温度
public async Task GetTemp(int curValue, string param, Variable node)
{
OperateResult operateResult = null;
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>((string)d.PLCName); //上料PLC
var result = await DealTemp(plc, curValue, node.Json);
if (result == null)
{
return;
}
operateResult = plc.Write<bool[]>((string)d.WriteResult, result); //MOM没有返回数据导致
if (!operateResult.IsSuccess)
{
LogHelper.Instance.Error("下发温度读取完成失败!");
return;
}
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
}
public void Stop()
{
}
}
}

View File

@@ -0,0 +1,200 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Common.Interface;
using Cowain.Bake.Communication.Interface;
using Cowain.Bake.Model.Models;
using Newtonsoft.Json;
using Opc.Ua;
using System;
using System.Collections.Concurrent;
using System.Linq;
using Unity;
namespace Cowain.Bake.Main.Station
{
public class UpdateStation : IServerManager
{
readonly ConcurrentDictionary<int, bool[]> _stovePalletSignal;
public string Name { get; set; }
public IUnityContainer _unityContainer { get; set; }
public UpdateStation(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
_stovePalletSignal = new ConcurrentDictionary<int, bool[]>();
}
bool IsConnectPLC(IPLCDevice PLC)
{
if (null == PLC || !PLC.IsConnect)
{
LogHelper.Instance.GetCurrentClassError($"连接PLC失败:{PLC.Name},PLC为空!");
return false;
}
return true;
}
//LifeCycle PLC请求命令:0=无意义10=无托盘20=有托盘
public int UpdateCavityStatus(DataValue data, Variable node)
{
Int16 signalValue = 0;
Int16 result = (Int16)EResult.OK; //1=OK,2=重新上传
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.TrigJson); //生命周期
dynamic reply = JsonConvert.DeserializeObject<dynamic>(node.Json); //反馈收到PLC的周期信号,反馈PLC的命令,0也要反馈,1=OK,2=重新上传
var config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(node.StationId);
IPLCDevice PLC = _unityContainer.Resolve<IPLCDevice>(config.Name);
if (!IsConnectPLC(PLC)) return 0;
var countCavitySignal = PLC.GetValue<System.Int16>((string)d.CountCavitySignal, node.StationId, node.Number);
if (!countCavitySignal.IsSuccess)
{
result = (Int16)EResult.NG;
LogHelper.Instance.Error($"读取腔体的信号计数失败!原因:{countCavitySignal.Message}");
}
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int16)
{
signalValue = (System.Int16)data.WrappedValue.Value;
}
else
{
result = (Int16)EResult.NG;
LogHelper.Instance.Warn($"没有找到夹具信号这个数据类型,节点名为{node.VarDesc}");
}
var writeResult = PLC.Write<Int16>(reply.CountCavitySignal, countCavitySignal.Content);
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"写腔体的信号计数失败,地址:{reply.CountCavitySignal},值:{countCavitySignal.Content},{writeResult.Message}");
}
writeResult = PLC.Write<Int16>(reply.SignalValue, signalValue);
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"写腔体的信号失败,地址:{reply.SignalValue},值:{signalValue},{writeResult.Message}");
}
writeResult = PLC.Write<Int16>(reply.CavitySignalResult, result);
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"写回复腔体的信号失败,地址:{reply.CavitySignalResult},值:{result},{writeResult.Message}");
}
return _unityContainer.Resolve<CavityInfoService>().UpdateCavitySignal(node.StationId, node.Number, signalValue);
}
public int UpdateDoorStatus(DataValue data, Variable node)
{
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.TrigJson);
string layer = d.Layer;
bool status = false;
if (string.IsNullOrEmpty(layer))
{
LogHelper.Instance.Warn($"触发夹具到位信号,但获取相关信息失败{node.TrigJson}");
return 0;
}
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Boolean)
{
status = (bool)data.WrappedValue.Value;
}
else
{
LogHelper.Instance.Warn($"没有找到开/关门这个数据类型,节点名为{node.VarDesc}");
return 0;
}
if (!status)
{
return 0;
}
if (node.ParamName == EStoveSignal.OpenDoorPlace.ToString())
{
status = true;
}
return _unityContainer.Resolve<CavityInfoService>().UpdateDoorStatus(node.StationId, int.Parse(layer), status);
}
public int UpdateLoadStatus(DataValue data, Variable node)
{
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.TrigJson);
string layer = d.Layer;
string number = d.Number;
bool[] status = null;
if (data.WrappedValue.TypeInfo.ValueRank == 1) //数组,炉子夹具传感器信号
{
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Boolean)
{
status = (bool[])data.WrappedValue.Value;
}
if (_stovePalletSignal.TryGetValue(node.StationId, out bool[] oldValue)) //有
{
if (oldValue.Count() != status.Count())
{
LogHelper.Instance.Error($"烤箱到位信号老值与新值长度不匹配,工站:{node.StationId},desc:{string.Join(",", status)}");
return 0;
}
_stovePalletSignal[node.StationId] = status;
var diffs = status.Zip(oldValue, (a, b) => a != b).Select((b, i) => new { Value = b, Index = i }).Where(x => x.Value);
foreach (var item in diffs)
{
if (0 == item.Index)
{
continue; //第一个不用
}
int result = _unityContainer.Resolve<CavityInfoService>().UpdateLoadStatus(node.StationId, item.Index, 1, status[item.Index]);
if (0 != result)
{
LogHelper.Instance.Warn($"修改状态数据失败,StationId:{node.StationId},layer:{item.Index}{status[item.Index]}");
}
}
}
else //重启时,更新所有信号
{
_stovePalletSignal[node.StationId] = status;
for (int i = 1; i <= Global.STOVE_LAYERS; ++i) //上位机启动
{
int result = _unityContainer.Resolve<CavityInfoService>().UpdateLoadStatus(node.StationId, i, 1, status[i]);
if (0 != result)
{
LogHelper.Instance.Warn($"修改状态数据失败,StationId:{node.StationId},layer:{i}{status[i]}");
}
}
}
}
else //上下料和人工夹具平台
{
var value = (bool)data.WrappedValue.Value;
int result = _unityContainer.Resolve<CavityInfoService>().UpdateLoadStatus(node.StationId, int.Parse(layer), int.Parse(number), value);
if (0 != result)
{
LogHelper.Instance.Warn($"修改状态数据失败,StationId:{node.StationId},layer:{layer}{number},{value}");
}
}
return 1;
}
public void Start()
{
}
public void Stop()
{
}
}
}

View File

@@ -0,0 +1,227 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Common.Models;
using Cowain.Bake.Model;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using Unity;
using JSON = Newtonsoft.Json.JsonConvert;
using Cowain.Bake.Main.ViewModels;
using static Cowain.Bake.Common.Models.MESModel;
using Cowain.Bake.Communication.MOM;
using Cowain.Bake.Model.Models;
namespace Cowain.Bake.Main.Station
{
//自动上传模块
public class UploadMesStation
{
public bool? OrdeIsMesOnline { get; set; }
public string Name { get; set; }
public bool haveWarn = true;
public string IpAddress { get; set; }
public int Port { get; set; }
public string URL { get; set; }
public IUnityContainer _unityContainer { get; set; }
public int Id { get; set; }
List<ProceParamList> listParams = new List<ProceParamList>();
private readonly Prism.Events.IEventAggregator _eventAggregator;
public UploadMesStation(IUnityContainer unityContainer, Prism.Events.IEventAggregator eventAggregator)
{
bool IsMesOnline = false;
_unityContainer = unityContainer;
TDeviceConfig dev = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.MOM)[0];
Id = dev.Id;
Name = dev.Name;
_eventAggregator = eventAggregator;
Task.Run(async () =>
{
while (true)
{
if (Global.AppExit)
{
return;
}
IsMesOnline = false;
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable)
{
MESReturnCmdModel mesResult = _unityContainer.Resolve<MESProcess>().Alive();
IsMesOnline = DealAlive(mesResult);
}
if (OrdeIsMesOnline != IsMesOnline)
{
;
OrdeIsMesOnline = IsMesOnline;
_unityContainer.Resolve<DeviceConfigService>().UpdateStatus(this.Id, IsMesOnline);
_unityContainer.Resolve<BasicInfoViewModel>().MesStatus = IsMesOnline;
}
await Task.Delay(5000); //放这里的目的,是心跳后,再执行上传
}
});
Task.Run(async () =>
{
while (true)
{
await Task.Delay(3000);
if (Global.AppExit)
{
return;
}
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable)
{
Run();
}
}
});
}
//MOM在回复心跳时通过KeyFlag= 2提醒设备需要调用MOM的工艺参数下发接口
//MOM在回复心跳时通过KeyFlag= 2提醒设备需要调用MOM的工艺参数下发接口
bool DealAlive(MESReturnCmdModel mesResult)
{
if (null == mesResult)
{
LogHelper.Instance.Warn($"MES不在线:{JSON.SerializeObject(mesResult)}");
return false;
}
else if (((int)EKeyFlag.NG).ToString() == mesResult.Info.KeyFlag)
{
TAlarm model = new TAlarm()
{
StationId = (int)EAlarmStationId.Mom,
Desc = $"MOM心跳报警->{mesResult.Info.MOMMessage}", //会存在多次不同的报警
StartTime = DateTime.Now,
Status = EAlarmStatus.Alert.GetDescription(),
};
haveWarn = true;
_eventAggregator.GetEvent<AlarmAddEvent>().Publish(model);//2.界面刷新,发布事件(发送消息)
_unityContainer.Resolve<AlarmService>().Insert(model);
return true;
}
else if (((int)EKeyFlag.ProcessParam).ToString() == mesResult.Info.KeyFlag) //心跳时通过KeyFlag= 2提醒设备需要调用MOM的工艺参数下发接口
{
listParams.Clear();
EqptParameterReturnCmd resultModel = _unityContainer.Resolve<MESProcess>().GetProcessParam();//获取返回的JOSN
if (null == resultModel)
{
return true;
}
TProductionInformation model = _unityContainer.Resolve<ProductionInformationService>().GetCurrentProductInfo();//实例化工单类
if (!_unityContainer.Resolve<ProcessParamService>().UpdateProcessParam(model.ProcessParamId, JSON.SerializeObject(resultModel.Info.ParameterInfo)))
{
LogHelper.Instance.Warn("保存工艺参数失败!");
}
}
if (haveWarn && ((int)EKeyFlag.NG).ToString() != mesResult.Info.KeyFlag)
{
_eventAggregator.GetEvent<AlarmStaionCancelEvent>().Publish((int)EAlarmStationId.Mom);//2.界面刷新,发布事件(发送消息)
var alarms = _unityContainer.Resolve<AlarmService>().GetInAlarm((int)EAlarmStationId.Mom);
foreach (var item in alarms)
{
_unityContainer.Resolve<AlarmService>().CancelAlarm(item);
}
haveWarn = false;
}
return true;
}
//public void GetJsonParam(string param)
//{
// dynamic d = JsonConvert.DeserializeObject<dynamic>(param);
// this.IpAddress = d.Ip;
// this.Port = d.Port;
// this.URL = d.URL;
//}
void Run()
{
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) != (int)EMOMEnable.Enable)
{
return;
}
List<TMesData> uploadItems = _unityContainer.Resolve<MesDataService>().GetUpLoadData();
foreach (var item in uploadItems)
{
dynamic d = JsonConvert.DeserializeObject<dynamic>(item.CommandType);
string service = d.Service;
string func = d.Func;
string url = d.UrlCmd;
Type type = Type.GetType(MyPath.SIGNAL_TRIGGER + service);
MethodInfo mi = this.GetType().GetMethod("ExecuteUpload").MakeGenericMethod(new Type[] { type }); //回复信息;
mi.Invoke(this, new object[]
{
func,
url,
item,
});
}
}
public void ExecuteUpload<T>(string func, string url, TMesData mesModel)
{
//取得实例
var instnce = _unityContainer.Resolve<T>(); //上下料实例
Type t = instnce.GetType();
//取得方法
MethodInfo mi = t.GetMethod(func);
//调用方法
mi.Invoke(instnce, new object[] //这里会去执行哪个方法上传,参数只有发送的信息
{
url,
mesModel
});
}
public void UploadCommon(string url, TMesData mesModel)
{
try
{
//这里就是调用上传的接口
mesModel.SendTime = DateTime.Now;
string result = HttpClientHelper.HttpPost(url, mesModel.Content);
if (string.IsNullOrEmpty(result)) //请求失败
{
mesModel.SendFlag = (sbyte)EMesUpLoadStatus.Fail;
}
else //请求成功
{
mesModel.SendFlag = (sbyte)EMesUpLoadStatus.Success;
mesModel.RecvContent = result;
mesModel.RecvTime = DateTime.Now;
_unityContainer.Resolve<MESProcess>().WriteRequestLog(mesModel.Content);
_unityContainer.Resolve<MESProcess>().WriteResponseLog(result);
}
_unityContainer.Resolve<MesDataService>().Update(mesModel);
}
catch (Exception ex)
{
LogHelper.Instance.GetCurrentClassError(ex.Message);
}
}
}
}

View File

@@ -0,0 +1,165 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Model;
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity;
using JSON = Newtonsoft.Json.JsonConvert;
namespace Cowain.Bake.Main.ViewModels
{
public class AddBatteryViewModel : BindableBase
{
private EBatteryStatus selectedEnum;
public EBatteryStatus SelectedEnum
{
get { return selectedEnum; }
set { SetProperty(ref selectedEnum, value); }
}
public List<object> Options { get; set; }
private object selectedOption;
public object SelectedOption
{
get { return selectedOption; }
set { SetProperty(ref selectedOption, value); }
}
public string batteryCode;
public string BatteryCode
{
get => batteryCode;
set => SetProperty(ref batteryCode, value);
}
int _palletID = 0;
int _palletVID = 0;
private IUnityContainer _unityContainer;
public AddBatteryViewModel(IUnityContainer unityContainer, int palletId, int VID)
{
_unityContainer = unityContainer;
_palletID = palletId;
_palletVID = VID;
SelectedEnum = EBatteryStatus.ToPallet;
SelectedPositionX = 1;
SelectedPositionY = 2;
Options = new List<object> { "否", "是" };
SelectedOption = "否";
}
public DelegateCommand<object> AddCommand => new DelegateCommand<object>((x) =>
{
if (string.IsNullOrEmpty(BatteryCode))
{
HandyControl.Controls.MessageBox.Warning("请输入电芯条码!");
return;
}
if (_unityContainer.Resolve<BatteryInfoService>().IsExistBattery(_palletVID, SelectedPositionX, SelectedPositionY))
{
HandyControl.Controls.MessageBox.Warning("夹具位置存在电芯,此位置不能再增加电芯!");
return;
}
if (0 == _palletVID)
{
HandyControl.Controls.MessageBox.Warning("此夹具的虚拟ID为0不能增加电芯!");
return;
}
TBatteryInfo batteryInfo = new TBatteryInfo()
{
PalletVirtualId = _palletVID,
BatteryCode = BatteryCode,
BatteryStatus = (sbyte)SelectedEnum,
PositionX = (sbyte)SelectedPositionX,
PositionY = (sbyte)SelectedPositionY,
ScanTime = DateTime.Now,
BindingTime = DateTime.Now,
DummyFlag = (SelectedOption?.ToString() == "是") ? true : false
};
if(0 == _unityContainer.Resolve<BatteryInfoService>().Insert(batteryInfo))
{
LogHelper.Instance.Debug($"手动增加电芯:【{BatteryCode}】失败!", true);
}
else
{
LogHelper.Instance.Info($"手动增加电芯:【{BatteryCode}】成功!", true);
_unityContainer.Resolve<LogService>().AddLog($"手动增加电芯成功,{ JSON.SerializeObject(batteryInfo)}", E_LogType.Operate.ToString());
_unityContainer.Resolve<PalletInfoService>().ModifyBatteryQty(_palletID); //数据减1
}
});
public List<KeyValuePair<EBatteryStatus, string>> EnumOptions
{
get
{
var enumType = typeof(EBatteryStatus);
var options = new List<KeyValuePair<EBatteryStatus, string>>();
foreach (var value in Enum.GetValues(enumType))
{
var field = enumType.GetField(value.ToString());
var attributes = field.GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = ((DescriptionAttribute)attributes[0]).Description;
options.Add(new KeyValuePair<EBatteryStatus, string>((EBatteryStatus)value, description));
}
return options;
}
}
private int selectedPositionY;
public int SelectedPositionY
{
get { return selectedPositionY; }
set { SetProperty(ref selectedPositionY, value); }
}
private int selectedPositionX;
public int SelectedPositionX
{
get { return selectedPositionX; }
set { SetProperty(ref selectedPositionX, value); }
}
public List<int> PositionYRange
{
get
{
List<int> numbers = new List<int>();
for (int i = 1; i <= Global.PALLET_COLS; i++)
{
numbers.Add(i);
}
return numbers;
}
}
public List<int> PositionXRange
{
get
{
List<int> numbers = new List<int>();
for (int i = 1; i <= Global.PALLET_ROWS; i++)
{
numbers.Add(i);
}
return numbers;
}
}
}
}

View File

@@ -0,0 +1,155 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Model.Entity;
using Prism.Mvvm;
using System;
using System.Collections.ObjectModel;
using System.Windows.Media;
using Unity;
namespace Cowain.Bake.Main.ViewModels
{
public class BasicInfoViewModel : BindableBase
{
public static ObservableCollection<string> EventListNoticfication = new ObservableCollection<string>();
private string _userName;
public string UserName
{
get { return _userName; }
set { SetProperty<string>(ref _userName, value); }
}
private string _currentJobNum;
public string CurrentJobNum
{
get { return _currentJobNum; }
set { SetProperty<string>(ref _currentJobNum, value); }
}
private string _dispMode;
public string DispMode
{
get { return _dispMode; }
set { SetProperty<string>(ref _dispMode, value); }
}
private string _currentOperation;
public string CurrentOperation
{
get { return _currentOperation; }
set { SetProperty<string>(ref _currentOperation, value); }
}
private string _userId;
public string UserId
{
get { return _userId; }
set { SetProperty<string>(ref _userId, value); }
}
private string _startStatusName;
public string StartStatusName
{
get { return _startStatusName; }
set { SetProperty<string>(ref _startStatusName, value); }
}
private string _failPointData;
public string FailPointData
{
get { return _failPointData; }
set { SetProperty<string>(ref _failPointData, value); }
}
private string _deviceStatusName;
public string DeviceStatusName
{
get { return _deviceStatusName; }
set { SetProperty<string>(ref _deviceStatusName, value); }
}
//EventList
private ObservableCollection<string> _eventList = new ObservableCollection<string>();
public ObservableCollection<string> EventList
{
get => _eventList;
set => SetProperty(ref _eventList, value);
}
private bool _mesStatus;
public bool MesStatus
{
get { return _mesStatus; }
set { SetProperty(ref _mesStatus, value); RaisePropertyChanged(nameof(StatusColor)); }
}
public SolidColorBrush StatusColor
{
get
{
if (!MesStatus)
{
return new SolidColorBrush(Colors.Red);
}
else
{
return new SolidColorBrush(Colors.Green);
}
}
}
private readonly IUnityContainer _unityContainer;
public BasicInfoViewModel(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
ShowInfo();
}
public void ShowInfo()
{
UserEntity userInfo = _unityContainer.Resolve<MemoryDataProvider>().CurrentUser;
userInfo.JobNum = _unityContainer.Resolve<ProductionInformationService>().GetCurrentProductInfo().JobNum;
userInfo.ProcessParamName = _unityContainer.Resolve<ProcessParamService>().Get(_unityContainer.Resolve<ProductionInformationService>().GetCurrentProductInfo().ProcessParamId).ProcessParamName;
FailPointData = "0";
UserName = userInfo.UserName;
UserId = userInfo.UserId;
CurrentJobNum = userInfo.JobNum;
CurrentOperation = userInfo.ProcessParamName;
DeviceStatusName = EDeviceStatus.None.GetDescription();
DispMode = SettingProvider.Instance.DispMode.GetDescription();
}
public void SetTempData(string value)
{
System.Threading.SynchronizationContext.SetSynchronizationContext(new
System.Windows.Threading.DispatcherSynchronizationContext(System.Windows.Application.Current.Dispatcher));
System.Threading.SynchronizationContext.Current.Post(p1 =>
{
FailPointData = value;
}, null);
}
public void SetEvent(string msg)
{
// 在第一个位置插入新元素
System.Threading.SynchronizationContext.SetSynchronizationContext(new
System.Windows.Threading.DispatcherSynchronizationContext(System.Windows.Application.Current.Dispatcher));
System.Threading.SynchronizationContext.Current.Post(p1 =>
{
/*
RemoveAt:放在外面,会崩
该类型的 CollectionView 不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改。, 在 System.Windows.Data.CollectionView.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args)
在 System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)
在 System.Collections.ObjectModel.ObservableCollection`1.RemoveItem(Int32 index)
*/
if (EventList.Count > Bake.Common.Global.MAX_QUEUE_SIGNAL)
{
EventList.RemoveAt(EventList.Count - 1);
}
EventList.Insert(0, $"{ DateTime.Now.ToString("HH:mm:ss")}: {msg}");
}, null);
}
}
}

View File

@@ -0,0 +1,769 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Communication.Interface;
using Cowain.Bake.Main.Views;
using Cowain.Bake.Model;
using Cowain.Bake.Model.Entity;
using Cowain.Bake.Model.Models;
using HandyControl.Controls;
using HslCommunication;
using Prism.Commands;
using Prism.Mvvm;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Windows;
using Unity;
namespace Cowain.Bake.Main.ViewModels
{
public class CavityDtlViewModel: BindableBase//, Prism.Services.Dialogs.IDialogAware
{
private string stationName;
private string palletCode;
private string stationEnable;
private string batteryCount;
private int _virtualId;
private string selectedValue;
private string selectedJobNum;
private string isWaterValue;
private List<string> arrJobNum;
private List<string> palletStatus;
private List<string> lastPalletList;
private string lastValue;
private int _bakingCount;
private bool _isEnabled ;
private bool _isEnabledAdd;
private bool _lastEnabled;
List<CavityInfoModel> _cavityInfo;
CavityHeaderModel _cavityHeaderInfo = null;
private IUnityContainer _unityContainer;
public string Title => "工站明细";
// 弹窗打开时触发:读取传递的参数
//public void OnDialogOpened(IDialogParameters parameters)
//{
// if (parameters.TryGetValue<string>("StatinName", out var text))
// {
// StationName = text; // 赋值后界面自动更新
// GetInfo();
// }
//}
//// 允许关闭弹窗返回true即可
//public bool CanCloseDialog() => true;
//// 弹窗关闭后清理资源(可选)
//public void OnDialogClosed() { }
//// Prism 8中用于触发弹窗关闭的事件
//public event Action<IDialogResult> RequestClose;
//// 关闭弹窗的逻辑
//public DelegateCommand CloseCommand =>
// new DelegateCommand(() =>
// RequestClose?.Invoke(new DialogResult(ButtonResult.OK)));
//private readonly IDialogService _dialogService;
public CavityDtlViewModel(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
//_dialogService = dialogService;
_cavityInfo = _unityContainer.Resolve<CavityInfoService>().GetAllStation();
}
private ObservableCollection<string> palletList;
public ObservableCollection<string> PalletList
{
get => palletList;
set => SetProperty(ref palletList, value);
}
public string SelectedValue
{
get => selectedValue;
set => SetProperty(ref selectedValue, value);
}
public string SelectedJobNum
{
get => selectedJobNum;
set => SetProperty(ref selectedJobNum, value);
}
public string IsWaterValue
{
get => isWaterValue;
set => SetProperty(ref isWaterValue, value);
}
public List<string> PalletStatus
{
get => palletStatus;
set => SetProperty(ref palletStatus, value);
}
public List<string> ArrJobNum
{
get => arrJobNum;
set => SetProperty(ref arrJobNum, value);
}
public string StationName
{
get => stationName;
set => SetProperty(ref stationName, value);
}
public string BatteryCount
{
get => batteryCount;
set => SetProperty(ref batteryCount, value);
}
public string WaterValueModel;
public string StationEnable
{
get => stationEnable;
set => SetProperty(ref stationEnable, value);
}
public string remark;
public string Remark
{
get => remark;
set => SetProperty(ref remark, value);
}
public string PalletCode
{
get { return palletCode; }
set
{
SetProperty(ref palletCode, value);
// 在属性更改时调用需要执行的方法
//SetPalletList();
}
}
public int BakingCount
{
get => _bakingCount;
set => SetProperty(ref _bakingCount, value);
}
public bool IsEnabled
{
get { return _isEnabled; }
set { SetProperty(ref _isEnabled, value); }
}
public bool IsEnabledAdd
{
get { return _isEnabledAdd; }
set { SetProperty(ref _isEnabledAdd, value); }
}
public bool LastEnabled
{
get { return _lastEnabled; }
set { SetProperty(ref _lastEnabled, value); }
}
public List<string> LastPalletList
{
get => lastPalletList;
set => SetProperty(ref lastPalletList, value);
}
public string LastValue
{
get { return lastValue; }
set
{
SetProperty(ref lastValue, value);
if (lastValue != "")
{
UpdateLastPallet();
}
}
}
public int VirtualId
{
get => _virtualId;
set => SetProperty(ref _virtualId, value);
}
public event PropertyChangedEventHandler NotifyPropertyChanged;
public void OnPropertyChanged(string propName)
{
if (NotifyPropertyChanged != null)
{
NotifyPropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
private BatteryInfoEntity batteryInfoSelectedItem;
public BatteryInfoEntity BatteryInfoSelectedItem
{
get { return batteryInfoSelectedItem; }
set
{
if (value != null)
{
batteryInfoSelectedItem = value;
OnPropertyChanged("BatteryInfoSelectedItem");
}
}
}
public void GetInfo()
{
SetPalletCodeCombox();
SetPalletStatusCombox();
SetPalletLastCombox();
SetJobNumCombox();
GetHeaderInfo();
FillGridView();
}
private void SetPalletCodeCombox()
{
PalletList = new ObservableCollection<string>();
_unityContainer.Resolve<PalletInfoService>().GetAll().ForEach(item => PalletList.Add(item.PalletCode));
}
private void SetPalletLastCombox()
{
LastPalletList = new List<string>();
foreach (EPalletLast ePalletStatus in System.Enum.GetValues(typeof(EPalletLast)))
{
LastPalletList.Add(ePalletStatus.GetDescription());
}
}
private void SetPalletStatusCombox()
{
PalletStatus = new List<string>();
foreach (EPalletStatus ePalletStatus in System.Enum.GetValues(typeof(EPalletStatus)))
{
PalletStatus.Add(ePalletStatus.GetDescription());
}
}
private void SetJobNumCombox()
{
var jobNums = _unityContainer.Resolve<ProductionInformationService>().GeAll();
ArrJobNum = jobNums.Select(x => x.JobNum).ToList();
}
bool IsPassWordPass()
{
// 创建输入对话框
//string pwd = Microsoft.VisualBasic.Interaction.InputBox("请您输入密码!", "修改");
//if (pwd != SettingProvider.Instance.PWD)
//{
// LogHelper.Instance.Warn("您输入的密码错误!",true);
// return false;
//}
return true;
}
public DelegateCommand<object> UpdatePalletStatus => new DelegateCommand<object>((x) =>
{
if (1 == _cavityHeaderInfo.PalletId)
{
LogHelper.Instance.Warn("新夹具,不能修改夹具状态!",true);
return;
}
if (0 == _cavityHeaderInfo.PalletId)
{
LogHelper.Instance.Error("此机台未绑定托盘!", true);
return;
}
if (!IsPassWordPass())
{
return;
}
CavityInfoModel stationDetail = _cavityInfo.Where(y => y.CavityName == StationName).FirstOrDefault();
var list = EnumHelper.GetEnumList<EPalletStatus>().Where(item => item.EnumDesc == SelectedValue);
int palletStatus = list.FirstOrDefault().EnumIntValue;
if (palletStatus == (int)EPalletStatus.BlankOver) //将清空夹具里的电芯,是确认是否要改成下料完成
{
if (_unityContainer.Resolve<BatteryInfoService>().IsIntoStation(VirtualId))
{
if (MessageBoxResult.OK == HandyControl.Controls.MessageBox.Ask("夹具中有电芯,如果改成【下料完成】,将设置电芯为出站,\n请确认是否要改状态", "操作提示"))
{
_unityContainer.Resolve<BatteryInfoService>().SetBatteryOutBound(VirtualId);
}
}
_unityContainer.Resolve<PalletInfoService>().SetUnBinding(_cavityHeaderInfo.PalletId);
}
else if (palletStatus == (int)EPalletStatus.WaitTest)
{
if (IsUnLoading(stationDetail))
{
LogHelper.Instance.Error("禁止将在下料机台的托盘状态更改为‘待测水含量!’", true);
return;
}
}
else if (palletStatus == (int)EPalletStatus.Advisable)
{
_unityContainer.Resolve<PalletInfoService>().UpdateNowJobNum(VirtualId);
var memory = _unityContainer.Resolve<MemoryDataProvider>();
SelectedJobNum = memory.CurrentUser.JobNum;
}
else if (palletStatus == (int)EPalletStatus.Bake) //烘烤中,设置夹具烘烤位置
{
TStation station = _unityContainer.Resolve<StationService>().GetStationByCavityId(_cavityHeaderInfo.Id);
if (station.Type == (int)EStationType.Stove)
{
if (0 == _unityContainer.Resolve<PalletInfoService>().UpdateBakingPos(_cavityHeaderInfo.PalletCode,
_cavityHeaderInfo.Id))
{
LogHelper.Instance.Error($"修改烘烤位置失败!");
}
}
}
_unityContainer.Resolve<CavityInfoService>().UpdatePalletStatus(_cavityHeaderInfo.PalletId, StationName, palletStatus);
HandyControl.Controls.Growl.Success("更新成功!");
_unityContainer.Resolve<LogService>().AddLog("人为修改状态:" + stationName
+ ";" + ((EPalletStatus)palletStatus).GetDescription(), E_LogType.Operate.ToString());
BotnnVisible(palletStatus);
GetHeaderInfo();
FillGridView();
});
public DelegateCommand<object> UpdatePalletCode => new DelegateCommand<object>((x) =>
{
if (string.IsNullOrEmpty(palletCode))
{
LogHelper.Instance.Error("请选托盘编码!", true);
return;
}
if (_cavityHeaderInfo.Lock)
{
LogHelper.Instance.Error("该位置已有调度任务锁定,无法绑定托盘!", true);
return;
}
_unityContainer.Resolve<CavityInfoService>().UpdateStationPalletCode(stationName, PalletCode);
GetHeaderInfo();
FillGridView();
var list = EnumHelper.GetEnumList<EPalletStatus>().Where(item => item.EnumDesc == SelectedValue);
int palletStatus = list.FirstOrDefault().EnumIntValue;
if (palletStatus == (int)EPalletStatus.BakeOver || palletStatus == (int)EPalletStatus.Bake)
{
CavityInfoModel machine = _cavityInfo.Where(y => y.Id ==_cavityHeaderInfo.Id).FirstOrDefault();
if (machine.Type == (int)EStationType.Stove)
{
_unityContainer.Resolve<PalletInfoService>().UpdateBakingPos(PalletCode, _cavityHeaderInfo.Id);
}
}
HandyControl.Controls.MessageBox.Success("已更新!");
_unityContainer.Resolve<LogService>().AddLog("人为绑定托盘:" + stationName
+";"+palletCode, E_LogType.Operate.ToString());
});
public DelegateCommand<object> BindJobNum => new DelegateCommand<object>((x) =>
{
if (!IsPassWordPass())
{
return;
}
if (0 == _unityContainer.Resolve<PalletInfoService>().SetJobNum(stationName, selectedJobNum))
{
LogHelper.Instance.Error("此机台未绑定托盘!", true);
return;
}
HandyControl.Controls.MessageBox.Success("已更新!");
_unityContainer.Resolve<LogService>().AddLog($"人为绑定工单,工站:{stationName},工单:{selectedJobNum}"
, E_LogType.Operate.ToString());
});
public DelegateCommand<object> UnBindJobNum => new DelegateCommand<object>((x) =>
{
if (0 == _unityContainer.Resolve<PalletInfoService>().SetJobNum(stationName, ""))
{
LogHelper.Instance.Error("此机台未绑定托盘!", true);
return;
}
HandyControl.Controls.MessageBox.Success("已更新!");
GetHeaderInfo();
_unityContainer.Resolve<LogService>().AddLog($"人为解绑工单,工站:{stationName},工单:{selectedJobNum}"
, E_LogType.Operate.ToString());
});
public DelegateCommand<object> AddBatteryCommand => new DelegateCommand<object>((x) =>
{
if (!IsPassWordPass())
{
return;
}
var viewModel = new AddBatteryViewModel(_unityContainer, _cavityHeaderInfo.PalletId, VirtualId);
AddBatteryView dlg = new AddBatteryView { DataContext = viewModel };
dlg.ShowDialog();
GetHeaderInfo(); //刷新数量
FillGridView();
});
public DelegateCommand<object> AddRemark => new DelegateCommand<object>((x) =>
{
if (50 <= remark.Length)
{
HandyControl.Controls.MessageBox.Error($@"输入的备注长度不能大于50个字符!", "操作提示");
return;
}
if (0 == _unityContainer.Resolve<CavityInfoService>().UpdateRemark(stationName, remark))
{
LogHelper.Instance.Error("修改备注失败!" ,true);
}
else
{
LogHelper.Instance.Info("修改备注成功!", true);
}
});
public DelegateCommand<object> UpdatePalletNoneCode => new DelegateCommand<object>((x) =>
{
if (!IsPassWordPass())
{
return;
}
if (0 == _cavityHeaderInfo.PalletId)
{
LogHelper.Instance.Error("此机台未绑定托盘!", true);
return;
}
_unityContainer.Resolve<CavityInfoService>().UpdateStationNonePallet(stationName);
GetHeaderInfo();
HandyControl.Controls.MessageBox.Success("已更新为无托盘!");
_unityContainer.Resolve<LogService>().AddLog("人为解绑," + stationName
, E_LogType.Operate.ToString());
});
public DelegateCommand<object> UpdateVirtualId => new DelegateCommand<object>((x) =>
{
if (!IsPassWordPass())
{
return;
}
if (1 == _cavityHeaderInfo.PalletId)
{
LogHelper.Instance.Warn("新夹具不能修改夹具信息ID", true);
return;
}
if (string.IsNullOrEmpty(palletCode))
{
LogHelper.Instance.Error("请选托盘编码!", true);
return;
}
var BatteryList = _unityContainer.Resolve<BatteryInfoService>().GetBatteryInfos(VirtualId);
if (BatteryList.Count < 1)
{
//LogHelper.Instance.Error("所输入的虚拟夹具号没有电芯信息!", true);
//return; //add by lsm 后面要开放,暂时为了测温度数据
}
if (_unityContainer.Resolve<PalletInfoService>().UpdateVirtualId(VirtualId, PalletCode) < 1)
{
HandyControl.Controls.MessageBox.Error("同一个虚拟码或更新失败!");
_unityContainer.Resolve<LogService>().AddLog($"更新失败,人为绑定托盘虚拟码,{stationName},托盘虚拟码:{VirtualId}"
, E_LogType.Operate.ToString());
return;
}
GetHeaderInfo();
FillGridView();
HandyControl.Controls.MessageBox.Success("已更新!");
_unityContainer.Resolve<LogService>().AddLog($"人为绑定托盘虚拟码,{stationName},托盘虚拟码:{VirtualId}"
, E_LogType.Operate.ToString());
});
private void GetHeaderInfo()
{
_cavityHeaderInfo = _unityContainer.Resolve<CavityInfoService>().GetHeadInfo(StationName);
BatteryCount = _cavityHeaderInfo.BatteryQty.ToString();
SelectedJobNum = _cavityHeaderInfo.JobNum;
stationEnable = _cavityHeaderInfo.Enable;
IsWaterValue = _cavityHeaderInfo.IsWater;
PalletCode = _cavityHeaderInfo.PalletCode;
WaterValueModel = _cavityHeaderInfo.WaterValue;
BakingCount = _cavityHeaderInfo.BakingCount;
Remark = _cavityHeaderInfo.Remark;
VirtualId = _cavityHeaderInfo.VirtualId;
SelectedValue = "";
if (null != _cavityHeaderInfo.PalletStatus)
{
int enumValue = _cavityHeaderInfo.PalletStatus ?? 1;
SelectedValue = EnumHelper.GetEnumList<EPalletStatus>()
.Where(item => item.EnumIntValue == enumValue).FirstOrDefault().EnumDesc;
BotnnVisible(enumValue);
}
if (null != _cavityHeaderInfo.LastFlag)
{
int enumValue = (_cavityHeaderInfo.LastFlag ?? false) ? 1 : 0;
LastValue = EnumHelper.GetEnumList<EPalletLast>()
.Where(item => item.EnumIntValue == enumValue).FirstOrDefault().EnumDesc;
}
CommonCoreHelper.Instance.MainViewAutoEvent.Set();
IsEnabledAdd = ((0 == VirtualId) || (Global.PALLET_TOTAL_BATTERYS == int.Parse(BatteryCount))) ? false : true;
}
private ObservableCollection<BatteryInfoEntity> batteryDtl2 = new ObservableCollection<BatteryInfoEntity>();
public ObservableCollection<BatteryInfoEntity> BatteryDtl2
{
get => batteryDtl2;
set => SetProperty(ref batteryDtl2, value);
}
private void FillGridView()
{
List<TBatteryInfo> table = _unityContainer.Resolve<BatteryInfoService>().GetBatteryInfos(VirtualId).
OrderBy(x=>x.PositionY).OrderBy(x=>x.PositionX).ToList();
//_unityContainer.Resolve<BatteryInfoService>().GetCavityBattery(StationName);
BatteryDtl2.Clear();
if (table.Count == 0)
{
return;
}
foreach (var item in table)
{
if ((int)EBatteryStatus.Over != item.BatteryStatus)
{
BatteryInfoEntity batteryInfoEntity = new BatteryInfoEntity();
batteryInfoEntity.Id = item.Id;
batteryInfoEntity.BatteryCode = item.BatteryCode;
batteryInfoEntity.BatteryStatus = item.BatteryStatus;
batteryInfoEntity.PositionX = item.PositionX;
batteryInfoEntity.PositionY = item.PositionY;
batteryInfoEntity.DummyFlag = item.DummyFlag ;
batteryInfoEntity.BindingTime =item.BindingTime;
BatteryDtl2.Add(batteryInfoEntity);
}
}
}
private void BotnnVisible(int enumValue)
{
CavityInfoModel stationDetail = _cavityInfo.Where(y => y.CavityName == StationName).FirstOrDefault();
//不是待测水含量不能使用判断按钮
IsEnabled = (int)EPalletStatus.WaitTest == enumValue ? true: false;
if (!_unityContainer.Resolve<BLL.BatteryInfoService>().IsPalletDummy(VirtualId))//不带水的不能使用判断按钮
{
IsEnabled = false;
}
//在上料或下料工站的不能修改为最后一盘
if (stationDetail.Type == (int)EStationType.Loading
|| stationDetail.Type == (int)EStationType.UnLoading)
{
LastEnabled = false; //显示“最后一盘” Enabled
}
else
{
LastEnabled = true;
}
}
public DelegateCommand<object> MoistureInput => new DelegateCommand<object>((x) =>
{
MoistureValueView moisture = new MoistureValueView( _unityContainer, this);
moisture.ShowDialog();
//var p = new DialogParameters
//{
// { "this", this }
// //{ "waterValue", WaterValueModel }
//};
//_dialogService.ShowDialog(nameof(MoistureValueView), p, r => { /*回调*/ });
GetHeaderInfo();
BotnnVisible(_cavityHeaderInfo.PalletStatus??10);
});
/*
解锁重点 add by lsm 调度锁放有效,锁对取盘无效
5.种状态1.在烤箱水含量OK2.在烤箱水含量NG 3.在下料位水含量OK4.在下料位水含量NG5.在下料位待测水含量
只有测试OK才解锁
1.ProcUpdateTask,烤箱夹具(水含量测试OK)->下料,3.在下料位而且是测试ok,
NG或待测不解锁245
*/
public void MoistureRuturn(int palletstaus,string moistureValue )
{
if (!UpdatePalletState(palletstaus, moistureValue))
{
return;
}
CavityInfoModel stationDetail = _cavityInfo.Where(y => y.CavityName == StationName).FirstOrDefault();
if (IsUnLoading(stationDetail))
{
var conf = _unityContainer.Resolve<DeviceConfigService>().GetConfig(stationDetail.StationId);
IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(conf.Name);
if (SelectedValue == EPalletStatus.TestOK.GetDescription())
{
OperateResult operateResult = plc.Write<bool>($"ns=4;s=PC_IN_Par_Request{stationDetail.Column}", true);
if (!operateResult.IsSuccess)
{
LogHelper.Instance.Debug($"设置请求参数下发失败:{operateResult.Message}");
HandyControl.Controls.Growl.Success("设置请求参数下发失败!");
}
else
{
//解除锁定
_unityContainer.Resolve<CavityInfoService>().GetPalletBakingPosAndUpdateLock(PalletCode); //夹具在下料,解除炉子的锁
}
}
}
}
/// <summary>
/// 改变托盘状态以及保存水分值
/// </summary>
private bool UpdatePalletState(int palletstaus, string moistureValue) //未将对象引用设置到对象的实例
{
var proceParamModel = _unityContainer.Resolve<ProductionInformationService>().GetProductionInformation(SelectedJobNum);
try
{
if (null == proceParamModel)
{
LogHelper.Instance.Error($"查询工单信息失败!,工单号:【{SelectedJobNum}】", true);
return false;
}
if (proceParamModel.DummyRule == (int)DummyPlaceRule.DEFAULT_EVERY_STOVE_LAYER_PLACED_ONE)//判断是不是一个炉层放一个水含量规则
{
int updateResult = _unityContainer.Resolve<PalletInfoService>().UpdateDummyLayerValue(_cavityHeaderInfo.BakingPosition, palletstaus, moistureValue, _cavityHeaderInfo.PalletId);
if (updateResult <= 0)
{
LogHelper.Instance.Warn($"修改夹具状态失败!烘烤位置:{_cavityHeaderInfo.BakingPosition},夹具ID:{_cavityHeaderInfo.PalletId}");
}
}
else
{
if (0 >= _unityContainer.Resolve<PalletInfoService>().UpdateWaterValue(_cavityHeaderInfo.PalletId, palletstaus, moistureValue))
{
LogHelper.Instance.Warn($"修改夹具:{_cavityHeaderInfo.Id},状态:{palletstaus}失败!");
}
}
HandyControl.Controls.Growl.Success("更新成功!");
}
catch(Exception ex)
{
LogHelper.Instance.Error($"修改托盘水含量信息失败,{ex.Message}", true);
return false;
}
return true;
}
private void UpdateLastPallet()
{
var service = _unityContainer.Resolve<PalletInfoService>();
TPalletInfo palletInfo = service.GetPalletInfo(palletCode);
int i = palletInfo.LastFlag ? 1 : 0;
string palletLast = EnumHelper.GetEnumList<EPalletLast>()
.Where(item => item.EnumIntValue == i).FirstOrDefault().EnumDesc;
//判断当前和数据库内的值是否相等,不相等就执行更改
if (LastValue != palletLast && LastValue != "")
{
service.UpdateLast(palletCode, LastValue);
HandyControl.Controls.MessageBox.Success("修改成功!");
}
}
private bool IsUnLoading(CavityInfoModel cavityInfo)
{
if (cavityInfo.Type == (int)EStationType.UnLoading)
{
return true;
}
return false;
}
public DelegateCommand<object> DeleteCommand => new DelegateCommand<object>((x) =>
{
if (!IsPassWordPass())
{
return;
}
var result = HandyControl.Controls.MessageBox.Ask($@"确定删除?", "操作提示");
if (result == System.Windows.MessageBoxResult.Cancel)
{
return;
}
var t = x as BatteryInfoEntity;
if (t != null)
{
if (_unityContainer.Resolve<BatteryInfoService>().Delete<TBatteryInfo>(t.Id) > 0)
{
batteryDtl2.Remove(t);
Growl.Success("删除成功!");
_unityContainer.Resolve<PalletInfoService>().ModifyBatteryQty(_cavityHeaderInfo.PalletId, -1); //数据减1
GetHeaderInfo(); //刷新界面
}
else
{
Growl.Fatal("删除失败!");
}
}
else
{
Growl.Fatal("删除失败!");
}
});
public DelegateCommand<object> ChangeDummyCommand => new DelegateCommand<object>((x) =>
{
if (null == BatteryInfoSelectedItem)
{
Growl.Warning("选择失败!");
return;
}
if (_unityContainer.Resolve<BLL.BatteryInfoService>().IsPalletDummy(VirtualId))
{
Growl.Warning("夹具有水含量电芯,不能再设置水含量电芯");
FillGridView();
return;
}
if (MessageBoxResult.Cancel == HandyControl.Controls.MessageBox.Ask("是否确定要设置此电芯为【水含量电芯】?", "提示"))
{
FillGridView();
return;
}
if (_unityContainer.Resolve<BLL.BatteryInfoService>().SetDummy(BatteryInfoSelectedItem.Id) > 0)
{
Growl.Info("设置为水含量电芯成功!");
}
else
{
Growl.Fatal("设置为水含量电芯失败!");
}
FillGridView(); //刷新界面
});
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
using Prism.Mvvm;
using Prism.Regions;
using Unity;
namespace Cowain.Bake.Main.ViewModels
{
public class MainHeaderViewModel : BindableBase
{
IUnityContainer _unityContainer;
public MainHeaderViewModel(IUnityContainer unityContainer, IRegionManager regionManager)
{
_unityContainer = unityContainer;
//userInfo = _unityContainer.Resolve<GlobalEntity>();
////可以看到这种声明方式提供了一个ObservesProperty方法不需要显示调用命令状态改变事件ObservesProperty属性观察
////属性观察,如果有变化就触发CanExecute
//ExecuteAutoCommand = new DelegateCommand(AutoExecute, AutoCanExecute).ObservesProperty(() => IsAutoEnabled);
//ExecuteManualCommand = new DelegateCommand(ManualExecute, ManualCanExecute).ObservesProperty(() => IsManualEnabled);
}
}
}

View File

@@ -0,0 +1,262 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Main.Models;
using Cowain.Bake.Main.Views;
using Cowain.Bake.Model;
using Cowain.Bake.Model.Models;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using Unity;
namespace Cowain.Bake.Main.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private string promptContent = "";
public string PromptContent
{
get { return promptContent; }
set { SetProperty<string>(ref promptContent, value); }
}
private string recentMsg; //最新的消息
readonly IUnityContainer _unityContainer;
private SubscriptionToken _subscriptionToken;
private readonly IEventAggregator _eventAggregator;
//缩放因子,用于调整在不同分辨率屏幕的位置
public MainWindowViewModel(IUnityContainer unityContainer, IEventAggregator eventAggregator)
{
_unityContainer = unityContainer;
//Global.STOVE_LAYERS = _unityContainer.Resolve<MemoryDataProvider>().AllStation.Find(x => x.Type ==(int)EStationType.Stove).Layers;
MainTitle = SettingProvider.Instance.ProductionLineName + Global.VS;
SetlogDict();
LogHelper.Instance.Warn($"-------------{Global.VS}------------------");
LogHelper.Instance.Debug($"-------------{Global.VS}------------------");
LogHelper.Instance.Error($"-------------{Global.VS}------------------");
LogHelper.Instance.Fatal($"-------------{Global.VS}------------------");
LogHelper.Instance.Info($"-------------{Global.VS}------------------");
InitializeLogLevels();
_eventAggregator = eventAggregator;
_subscriptionToken = _eventAggregator.GetEvent<AlarmAddEvent>() //Unsubscribe: 取消订阅(如在组件销毁时)
.Subscribe(OnAddAlarm, ThreadOption.UIThread); //事件触发时执行的方法,ThreadOption.UIThread,(默认):在发布事件的线程执行
_subscriptionToken = _eventAggregator.GetEvent<AlarmCancelEvent>()
.Subscribe(OnCancelAlarm, ThreadOption.UIThread);
_subscriptionToken = _eventAggregator.GetEvent<AlarmStaionCancelEvent>()
.Subscribe(OnCancelAlarm, ThreadOption.UIThread);
}
private void OnAddAlarm(TAlarm alarm)
{
var model = Alarms.Where(item => item.StationId == alarm.StationId && item.Desc == alarm.Desc).FirstOrDefault();
if (null == model)
{
Alarms.Add(alarm);
}
//ShowPromptContent();
}
private void OnCancelAlarm(TAlarm alarm)
{
var model = Alarms.Where(item => item.StationId == alarm.StationId && item.Desc == alarm.Desc).FirstOrDefault();
if (null != model)
{
Alarms.Remove(model);
}
//ShowPromptContent();
}
private void OnCancelAlarm(int stationId)
{
var models = Alarms.Where(item => item.StationId == stationId).ToList();
foreach (var model in models)
{
Alarms.Remove(model);
}
//ShowPromptContent();
}
public void ShowPromptContent()
{
int index = 0;
PromptContent = "";
foreach (var item in Alarms.Reverse())
{
if (++index > 2)
{
return; //数据太多了,就会卡,所以只让显示二条数据
}
PromptContent += item.Desc + " "; //太多了,界面卡
}
}
public void AddPromptContent(string msg)
{
//string addContent = promptContent;
//if (string.IsNullOrEmpty(addContent))
//{
// addContent = msg;
//}
//else
//{
// var parts = addContent.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
// if (!parts.Contains(msg))
// {
// addContent += "|" + msg;
// }
//}
//if (promptContent == addContent)
//{
// return;
//}
;
PromptContent = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} : {msg}";
}
public void DeletePromptContent(string msg ="")
{
string deleteContent = promptContent;
if (string.IsNullOrEmpty(deleteContent))
{
return;
}
//if (!deleteContent.Contains(msg))
//{
// return;
//}
//var parts = deleteContent.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
// .Select(p => p.Trim())
// .Where(p => p != msg)
// .ToList();
//deleteContent = string.Join("|", parts);
PromptContent = "";
}
private void InitializeLogLevels()
{
var logTypes = EnumHelper.GetEnumList<E_LogType>();
for (int i = 0; i < (logTypes.Count - 3); i++)
{
LogLevelModel1.Add(new MultiComboBox.MultiCbxBaseData
{
Id = i,
IsCheck = true,
ViewName = logTypes[i].EnumString.ToString()
});
}
LogHelper.Instance.OnShowInvoke = LogShow;
}
private Dictionary<E_LogType, (string FontColor, MessageBoxImage Image)> logDict;
private void SetlogDict()
{
logDict = new Dictionary<E_LogType, (string, MessageBoxImage)>
{
{ E_LogType.Debug, ("#5352ed", MessageBoxImage.Exclamation) },
{ E_LogType.Info, ("#1abc9c", MessageBoxImage.Information) },
{ E_LogType.Warn, ("#eccc68", MessageBoxImage.Warning) },
{ E_LogType.Error, ("red", MessageBoxImage.Error) },
{ E_LogType.Fatal, ("red", MessageBoxImage.Error) }
};
}
private void LogShow(string log, bool ispopup, E_LogType logType)
{
if (recentMsg == log && !ispopup)
{
return;
}
recentMsg = log;
DateTime date = DateTime.Now;
if (logDict.TryGetValue(logType, out var logInfo))
{
InfoLogModel = new LogModel
{
LogLevel = logType.ToString(),
LogText = log,
LogTime = date,
FontColor = logInfo.FontColor
};
if (ispopup)
{
Application.Current.Dispatcher.Invoke(() =>
{
HandyControl.Controls.MessageBox.Show(log, logType.GetDescription(), MessageBoxButton.OK, logInfo.Image);
});
}
}
}
public DelegateCommand<object> AlarmQueryCommand => new DelegateCommand<object>((x) =>
{
HistoryAlarmsData.Clear();
var service = _unityContainer.Resolve<AlarmService>();
service.GetAlarmReport(AlarmStartTime, AlarmEndTime).ForEach(item => HistoryAlarmsData.Add(item));
});
#region
private string mainTitle;
public string MainTitle
{
get => mainTitle;
set => SetProperty(ref mainTitle, value);
}
private LogModel logModel1;
public LogModel InfoLogModel
{
get => logModel1;
set => SetProperty(ref logModel1, value);
}
private ObservableCollection<MultiComboBox.MultiCbxBaseData> logLevelModel1 = new ObservableCollection<MultiComboBox.MultiCbxBaseData>();
public ObservableCollection<MultiComboBox.MultiCbxBaseData> LogLevelModel1
{
get => logLevelModel1;
set => SetProperty(ref logLevelModel1, value);
}
private string alarmStartTime = DateTime.Now.ToString("yyyy-MM-dd");
public string AlarmStartTime
{
get => alarmStartTime;
set => SetProperty(ref alarmStartTime, value);
}
private string alarmEndTime = DateTime.Now.ToString("yyyy-MM-dd");
public string AlarmEndTime
{
get => alarmEndTime;
set => SetProperty(ref alarmEndTime, value);
}
private ObservableCollection<TAlarm> alarms = new ObservableCollection<TAlarm>();
public ObservableCollection<TAlarm> Alarms
{
get => alarms;
set => SetProperty(ref alarms, value);
}
private ObservableCollection<TAlarm> historyAlarms = new ObservableCollection<TAlarm>();
public ObservableCollection<TAlarm> HistoryAlarmsData
{
get => historyAlarms;
set => SetProperty(ref historyAlarms, value);
}
#endregion
}
}

View File

@@ -0,0 +1,123 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Main.Station;
using Cowain.Bake.Model;
using Cowain.Bake.Model.Entity;
using Cowain.Bake.Model.Models;
using Newtonsoft.Json;
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Data;
using Unity;
namespace Cowain.Bake.Main.ViewModels
{
public class ManualTaskViewModel: BindableBase
{
private IUnityContainer _unityContainer;
private string selectFromValue;
public string SelectFromValue
{
get => selectFromValue;
set => SetProperty(ref selectFromValue, value);
}
private string selectToValue;
public string SelectToValue
{
get => selectToValue;
set => SetProperty(ref selectToValue, value);
}
//不写set;get还设置不了这里的值
public List<string> StationDtl { set; get; } = new List<string>();
public void GetStationDtl()
{
List<string> table = _unityContainer.Resolve<CavityInfoService>().GetCanUseStationName();
foreach (var item in table)
{
StationDtl.Add(item);
}
}
public ManualTaskViewModel(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
public DelegateCommand GenerateTaskCommand => new DelegateCommand(() =>
{
GenerateTask();
});
private void GenerateTask()
{
if (SettingProvider.Instance.DispMode == EDispatchMode.Auto)
{
HandyControl.Controls.Growl.Warning("自动调度,不能手动生成任务!");
return;
}
if (string.IsNullOrEmpty(selectFromValue)
|| string.IsNullOrEmpty(SelectToValue))
{
HandyControl.Controls.Growl.Error("取放为空,不能手动生成任务!");
return;
}
if (_unityContainer.Resolve<TaskRecordService>().UnexecuteTask() != null)
{
HandyControl.Controls.Growl.Warning("还有调度任务没有执行完成,不能手动生成任务!");
return;
}
TCavityInfo fromTable = _unityContainer.Resolve<CavityInfoService>().GetStationID(selectFromValue);
TCavityInfo toTable = _unityContainer.Resolve<CavityInfoService>().GetStationID(SelectToValue);
Cowain.Bake.Model.TTaskRecord taskRecord = new Model.TTaskRecord();
if (0 == fromTable.PalletId)
{
LogHelper.Instance.Error("添加失败,取位置无托盘记忆!", true);
return;
}
if (!fromTable.IsLoad)
{
LogHelper.Instance.Error("添加失败,取位置感应不到夹具到位!", true);
return;
}
if (0 != toTable.PalletId || toTable.IsLoad)
{
LogHelper.Instance.Error("添加失败,放位置有托盘信息!", true);
return;
}
TPalletInfo palletInfo = _unityContainer.Resolve<PalletInfoService>().GetPalletInfo(fromTable.PalletId);
if (palletInfo.PalletStatus == (int)EPalletStatus.Bake)
{
LogHelper.Instance.Error("添加失败,无法将在烘烤中的托盘添加到任务!", true);
return;
}
taskRecord.PalletId = fromTable.PalletId;
taskRecord.TaskTypeId = 0;
taskRecord.Source = fromTable.Id;
taskRecord.Target = toTable.Id;
taskRecord.Status = (int)ETaskStatus.UnExecute;
taskRecord.BuildTime = DateTime.Now;
taskRecord.StepId = (int)ETaskStep.Unexecuted;
if (0 == _unityContainer.Resolve<TaskRecordService>().Insert(taskRecord))
{
LogHelper.Instance.Error("插入任务到数据库失败!", true);
return;
}
_unityContainer.Resolve<TaskStation>()._newTaskEvent.Set();
LogHelper.Instance.Info($"插入任务成功!{JsonConvert.SerializeObject(taskRecord)}");
HandyControl.Controls.MessageBox.Success("已添加成功!");
}
}
}

View File

@@ -0,0 +1,156 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Model;
using Cowain.Bake.Model.Models;
using Newtonsoft.Json;
using Prism.Commands;
using Prism.Mvvm;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using Unity;
namespace Cowain.Bake.Main.ViewModels
{
internal class MoistureValueViewMode: BindableBase//, Prism.Services.Dialogs.IDialogAware
{
private readonly IUnityContainer _unityContainer;
private float? septumwaterJudge;
private float? cathodewaterJudge;
private float? anodewaterJudge ;
//public string WaterValueModel;
List<WaterModel> waterModels = null;
public CavityDtlViewModel thatParent = null;
//public string Title => "输入水含量值";
//// 弹窗打开时触发:读取传递的参数
//public void OnDialogOpened(IDialogParameters parameters)
//{
// thatParent = parameters.GetValue<CavityDtlViewModel>("this");
// WaterValueModel = thatParent.WaterValueModel ?? "";
//}
//// 允许关闭弹窗返回true即可
//public bool CanCloseDialog() => true;
//// 弹窗关闭后清理资源(可选)
//public void OnDialogClosed() { }
//// Prism 8中用于触发弹窗关闭的事件
//public event Action<IDialogResult> RequestClose;
//public DelegateCommand CloseCommand =>
// new DelegateCommand(() =>
// RequestClose?.Invoke(new DialogResult(ButtonResult.OK)));
public MoistureValueViewMode(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
public float? SeptumWaterJudge //隔离膜水分
{
get => septumwaterJudge;
set => SetProperty(ref septumwaterJudge, value);
}
public float? AnodeWaterJudge //正极水分
{
get => anodewaterJudge;
set => SetProperty(ref anodewaterJudge, value);
}
public float? CathodeWaterJudge //负极水分
{
get => cathodewaterJudge;
set => SetProperty(ref cathodewaterJudge, value);
}
public DelegateCommand<object> Judge => new DelegateCommand<object>((x) =>
{
int septumwaterTargetValue = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.SeptumwaterTargetJudge.ToString()));
int cathodewaterTargetValue = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.CathodewaterTargetJudge.ToString()));
int anodewaterTargetValue = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.AnodewaterTargetJudge.ToString()));
//MessageBoxResult result = HandyControl.Controls.MessageBox.Ask($@"是否确定为手动输入的水含量值?", "操作提示");
//if (result == System.Windows.MessageBoxResult.Cancel)
//{
// return;
//}
LogHelper.Instance.Warn($"开始测水含量0!");
if (!septumwaterJudge.HasValue
|| !anodewaterJudge.HasValue
|| !cathodewaterJudge.HasValue
)
{
HandyControl.Controls.MessageBox.Warning("数值为空, 请人工输入!");
return;
}
var WaterModel = new WaterModel();
WaterModel.AnodeWaterValue = anodewaterJudge.ToString();
WaterModel.CathodeWaterValue = cathodewaterJudge.ToString();
WaterModel.SeptumWaterValue = septumwaterJudge.ToString();
int palletStatus = (int)EPalletStatus.TestOK;
if (septumwaterJudge >= septumwaterTargetValue
|| cathodewaterJudge >= cathodewaterTargetValue
|| anodewaterJudge >= anodewaterTargetValue)
{
palletStatus = (int)EPalletStatus.TestNG;
MessageBoxResult judgeResult = HandyControl.Controls.MessageBox.Ask($@"本次判定水含量值为NG,请确认!", "判定提示");
if (judgeResult == System.Windows.MessageBoxResult.Cancel)
{
return;
}
}
//WaterValueModel,在这个界面点【判定】,会刷新这个值。也就是这个判断结果会累加,但在【工站明细】中不会
waterModels = JsonConvert.DeserializeObject<List<WaterModel>>(thatParent.WaterValueModel??""); //WaterValueModel:数据库中的水含量数据
WaterModel.BatteryCode = GetBatteryCode(waterModels);
if (null == waterModels)
{
waterModels = new List<WaterModel>();
}
else
{
WaterModel.Id = waterModels.Max(w => w.Id) + 1;
}
waterModels.Add(WaterModel);
thatParent.MoistureRuturn(palletStatus, JsonConvert.SerializeObject(waterModels));
HandyControl.Controls.MessageBox.Info("设置测试水含量成功");
});
string GetBatteryCode(List<WaterModel> waterList)
{
var dummys = _unityContainer.Resolve<BatteryInfoService>().GetWaterBatteryCode(thatParent.VirtualId);
if (0 == dummys.Count)
{
return "";
}
if (waterList == null
|| 0 == waterList.Count)
{
return dummys[0].BatteryCode;
}
List<string> dummyCodes = dummys.Select(x => x.BatteryCode).ToList();
List<string> waterCodes = waterList.Select(x => x.BatteryCode).ToList();
// 查找 list1 中不在 list2 中的字符串 var notInList2 = list1.Except(list2);
var batteryCode = dummyCodes.Except(waterCodes);
if (0 ==batteryCode.Count())
{
return waterList.OrderByDescending(x => x.Id).FirstOrDefault().BatteryCode;//最后一次的假电芯码
}
return batteryCode.First();
}
}
}

View File

@@ -0,0 +1,28 @@
using Cowain.Bake.Common;
using Prism.Regions;
using Unity;
namespace Cowain.Bake.Main.ViewModels
{
public class PalletIdInputWindowViewModel : ViewModelBase
{
private string _title;
public string Title
{
get => _title;
set => SetProperty(ref _title, value);
}
private string _msgContent;
public string MsgContent
{
get => _msgContent;
set => SetProperty(ref _msgContent, value);
}
public PalletIdInputWindowViewModel(IUnityContainer unityContainer, IRegionManager regionManager) : base(unityContainer, regionManager)
{
}
}
}

View File

@@ -0,0 +1,49 @@
<Window x:Class="Cowain.Bake.Main.Views.AddBatteryView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Cowain.Bake.Main.Views"
xmlns:prism ="http://prismlibrary.com/"
mc:Ignorable="d"
Title="添加电芯" Height="336" Width="380" ResizeMode="NoResize" WindowStartupLocation="CenterScreen">
<Grid Background="DodgerBlue">
<Grid.RowDefinitions>
<RowDefinition Height="4*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<StackPanel>
<WrapPanel Margin="10,30,0,0" >
<TextBlock Text="电芯条码:" Margin="50,10,10,0" ></TextBlock>
<TextBox HorizontalAlignment="Center" Text="{Binding BatteryCode}" Width="230" ></TextBox>
</WrapPanel>
<WrapPanel Margin="10,10,0,0" >
<TextBlock Text="夹具行号:" Margin="50,10,10,0" ></TextBlock>
<ComboBox HorizontalAlignment="Center" ItemsSource="{Binding PositionXRange}" SelectedValue="{Binding SelectedPositionX, Mode=TwoWay}" VerticalAlignment="Center" Width="230"></ComboBox>
</WrapPanel>
<WrapPanel Margin="10,10,0,0" >
<TextBlock Text="夹具列号:" Margin="50,10,10,0" ></TextBlock>
<ComboBox HorizontalAlignment="Center" ItemsSource="{Binding PositionYRange}" SelectedValue="{Binding SelectedPositionY, Mode=TwoWay}" VerticalAlignment="Center" Width="230"></ComboBox>
</WrapPanel>
<WrapPanel Margin="10,10,0,0" >
<TextBlock Text="电芯状态:" Margin="50,10,10,0" ></TextBlock>
<ComboBox HorizontalAlignment="Center" ItemsSource="{Binding EnumOptions}"
DisplayMemberPath="Value"
SelectedValuePath="Key"
SelectedValue="{Binding SelectedEnum, Mode=TwoWay}" VerticalAlignment="Center" Width="230"></ComboBox>
</WrapPanel>
<WrapPanel Margin="10,10,0,0" >
<TextBlock Text="是否水含量电芯:" Margin="15,10,10,0" ></TextBlock>
<ComboBox HorizontalAlignment="Center" VerticalAlignment="Center" Width="230" SelectedItem="{Binding SelectedOption}" ItemsSource="{Binding Options}">
</ComboBox>
</WrapPanel>
</StackPanel>
<Grid Grid.Row="1">
<WrapPanel Margin="10,10,0,0" >
<Button Content="增 加" Margin="135,10,10,0" Width="80" Command="{Binding AddCommand}"></Button>
</WrapPanel>
</Grid>
</Grid>
</Window>

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace Cowain.Bake.Main.Views
{
/// <summary>
/// AddBatteryView.xaml 的交互逻辑
/// </summary>
public partial class AddBatteryView : Window
{
public AddBatteryView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,70 @@
<UserControl x:Class="Cowain.Bake.Main.Views.BasicInfoView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Cowain.Bake.Main.Views"
mc:Ignorable="d"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="#66FFFFFF">
<Grid.RowDefinitions>
<RowDefinition Height="0.03*"/>
<RowDefinition Height="0.07*"/>
<RowDefinition Height="0.07*"/>
<RowDefinition Height="0.07*"/>
<RowDefinition Height="0.07*"/>
<RowDefinition Height="0.07*"/>
<RowDefinition Height="0.07*"/>
<RowDefinition Height="0.07*"/>
<RowDefinition Height="0.07*"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.05*"/>
<ColumnDefinition Width="0.4*"/>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.05*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1" Text="用户:" Grid.Row="1"
Height="34" FontSize="16" Background="Transparent"/>
<TextBlock Grid.Column="2" Text="{Binding UserId,UpdateSourceTrigger=PropertyChanged}" Grid.Row="1"
Height="34" FontSize="16" Background="Transparent"/>
<TextBlock Grid.Column="1" Text="姓名:" Grid.Row="2"
Height="34" FontSize="16" Background="Transparent"/>
<TextBlock Grid.Column="2" Text="{Binding UserName,UpdateSourceTrigger=PropertyChanged}" Grid.Row="2"
Height="34" FontSize="16" Background="Transparent"/>
<TextBlock Text="工单:" Grid.Row="3" FontSize="16" Background="Transparent" Grid.Column="1"/>
<TextBlock Grid.Column="2" Text="{Binding CurrentJobNum,UpdateSourceTrigger=PropertyChanged}" Grid.Row="3"
Height="34" FontSize="16" Background="Transparent"/>
<TextBlock Text="工艺:" Grid.Row="4" FontSize="16" Background="Transparent" Grid.Column="1"/>
<TextBlock Grid.Column="2" Text="{Binding CurrentOperation,UpdateSourceTrigger=PropertyChanged}" Grid.Row="4"
Height="34" FontSize="16" Background="Transparent"/>
<TextBlock Text="露点温度:" Grid.Row="5" FontSize="16" Background="Transparent" Grid.Column="1"/>
<TextBlock Grid.Column="2" Text="{Binding FailPointData,UpdateSourceTrigger=PropertyChanged}" Grid.Row="5"
Height="34" FontSize="16" Background="Transparent"/>
<TextBlock Text="设备状态:" Grid.Row="6" FontSize="16" Background="Transparent" Grid.Column="1"/>
<TextBlock Grid.Column="2" Text="{Binding DeviceStatusName,UpdateSourceTrigger=PropertyChanged}" Grid.Row="6"
Height="34" FontSize="16" Background="Transparent"/>
<TextBlock Text="调度模式:" Grid.Row="7" FontSize="16" Background="Transparent" Grid.Column="1"/>
<TextBlock Grid.Column="2" Text="{Binding DispMode,UpdateSourceTrigger=PropertyChanged}" Grid.Row="7" FontWeight="Bold"
Height="34" FontSize="16" Background="Transparent" Foreground="Blue"/>
<TextBlock Text="MOM状态" FontSize="16" Grid.Row="8" Grid.Column="1"/>
<Border Grid.Row="8" Grid.Column="2" CornerRadius="20" HorizontalAlignment="Left" Margin="4,0,0,13" Background="{Binding StatusColor}" Height="15" Width="15" />
<GroupBox Header="触发信号" Grid.ColumnSpan="4" Grid.Row="9">
<ListBox ItemsSource="{Binding EventList}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</GroupBox>
</Grid>
</UserControl>

View File

@@ -0,0 +1,25 @@
using Prism.Regions;
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 Unity;
namespace Cowain.Bake.Main.Views
{
/// <summary>
/// BasicInfoView.xaml 的交互逻辑
/// </summary>
public partial class BasicInfoView : UserControl
{
public BasicInfoView(IUnityContainer unityContainer, IRegionManager regionManager)
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,97 @@
<Window x:Class="Cowain.Bake.Main.Views.CavityDtlView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:convertor="clr-namespace:Cowain.Bake.Common.Converter;assembly=Cowain.Bake.Common"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Height="586" Width="1000"
MinWidth="1000"
MaxWidth="1000"
MinHeight="586"
MaxHeight="586">
<Window.Resources>
<convertor:BatteryStatusConvertor x:Key="cellStatusConvertor"></convertor:BatteryStatusConvertor>
</Window.Resources>
<Grid Background="DodgerBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="101*"/>
<ColumnDefinition Width="66*"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="stationName" FontWeight="Bold" IsReadOnly="True" HorizontalAlignment="Left" Height="23" Margin="90,15,0,0" TextWrapping="Wrap" Text="{Binding StationName,Mode=TwoWay}" VerticalAlignment="Top" Width="120"/>
<DataGrid x:Name="mainGrid" IsReadOnly="True" ItemsSource="{Binding BatteryDtl2}" AutoGenerateColumns="False" HorizontalAlignment="Left" Height="435" Margin="7,145,0,0"
SelectedItem="{Binding BatteryInfoSelectedItem, Mode=TwoWay}" VerticalAlignment="Top" Width="990" Grid.ColumnSpan="2">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding BatteryCode}" Width="220" Header="电池条码"/>
<DataGridTextColumn Binding="{Binding BatteryStatus, Converter={StaticResource cellStatusConvertor}}" Width="100" Header="电池状态"/>
<DataGridTextColumn Binding="{Binding PositionX}" Width="95" Header="电池行坐标"/>
<DataGridTextColumn Binding="{Binding PositionY}" Width="95" Header="电池列坐标"/>
<!--<DataGridTextColumn Binding="{Binding DummyFlag}" Width="95" Header="水含量电芯"/>-->
<DataGridTemplateColumn Header="水含量电芯" Width="80" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding DummyFlag,Mode=TwoWay}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding DataContext.ChangeDummyCommand, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Binding="{Binding BindingTime,StringFormat='yyyy-MM-dd HH:mm:ss'}" Width="170" Header="与托盘绑定时间"/>
<DataGridTemplateColumn Header="操作" Width="80">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Grid.Column="4" VerticalAlignment="Center" HorizontalAlignment="Center" Orientation="Horizontal">
<TextBlock Margin="3,0" >
<Hyperlink Foreground="Red" Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" CommandParameter="{Binding}">删除</Hyperlink>
</TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Label Content="工站名称:" Foreground="White" FontWeight="Bold" Style="{DynamicResource BaseStyle}" HorizontalContentAlignment="Right" HorizontalAlignment="Left" Margin="0,16,0,0" VerticalAlignment="Top" Width="90"/>
<Label Content="托盘条码:" Foreground="White" FontWeight="Bold" Style="{DynamicResource BaseStyle}" HorizontalContentAlignment="Right" HorizontalAlignment="Left" Margin="190,16,0,0" VerticalAlignment="Top" Width="90"/>
<!--<TextBox Text="{Binding PalletCode}" FontWeight="Bold" HorizontalAlignment="Left" Height="23" Margin="285,15,0,0" VerticalAlignment="Top" Width="101"/>-->
<ComboBox x:Name="palletCode" SelectedValue="{Binding PalletCode}" ItemsSource="{Binding PalletList}" FontWeight="Bold" IsReadOnly="True" HorizontalAlignment="Left" Height="23" Margin="285,15,0,0" VerticalAlignment="Top" Width="135"/>
<Label Content="是否可用:" Foreground="White" FontWeight="Bold" Style="{DynamicResource BaseStyle}" HorizontalContentAlignment="Right" HorizontalAlignment="Left" Margin="540,16,0,0" VerticalAlignment="Top" Width="64"/>
<TextBox x:Name="stationEnable" Text="{Binding StationEnable}" FontWeight="Bold" IsEnabled="False" HorizontalAlignment="Left" Height="23" Margin="3.2,15,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="55" Grid.Column="1"/>
<Label Content="当前烘次:" Foreground="White" FontWeight="Bold" Style="{DynamicResource BaseStyle}" HorizontalContentAlignment="Right" HorizontalAlignment="Left" Margin="66,16,0,0" VerticalAlignment="Top" Width="64" Grid.Column="1"/>
<TextBlock x:Name="rebakingNum" Text="{Binding BakingCount}" FontWeight="Bold" HorizontalAlignment="Left" Height="23" Margin="130.2,21,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="45" Grid.Column="1"/>
<TextBlock x:Name="bakingBatteryNum" Text="{Binding BatteryCount}" FontWeight="Bold" HorizontalAlignment="Left" Height="24" Margin="216,21,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="40" Grid.Column="1"/>
<Label Content="最后一盘:" Foreground="White" FontWeight="Bold" Style="{DynamicResource BaseStyle}" HorizontalContentAlignment="Right" HorizontalAlignment="Left" Margin="250,15,0,0" VerticalAlignment="Top" Width="66" Grid.Column="1"/>
<ComboBox ItemsSource="{Binding LastPalletList}" IsEnabled ="{Binding LastEnabled}" FontWeight="Bold" SelectedValue="{Binding LastValue,Mode=TwoWay}" HorizontalAlignment="Left" Margin="325,15,0,0" VerticalAlignment="Top" Width="60" Grid.Column="1"/>
<Label Content="电芯数量:" Foreground="White" FontWeight="Bold" Style="{DynamicResource BaseStyle}" HorizontalContentAlignment="Right" HorizontalAlignment="Left" Margin="146,15,0,0" VerticalAlignment="Top" Width="66" Grid.Column="1"/>
<Label Content="所属工单:" Foreground="White" FontWeight="Bold" Style="{DynamicResource BaseStyle}" HorizontalContentAlignment="Right" HorizontalAlignment="Left" Margin="514,62,0,0" VerticalAlignment="Top" Width="90"/>
<ComboBox ItemsSource="{Binding ArrJobNum}" SelectedValue="{Binding SelectedJobNum,Mode=TwoWay}" FontWeight="Bold" IsReadOnly="True" HorizontalAlignment="Left" Height="23" Margin="4.2,62,0,0" VerticalAlignment="Top" Width="228" Grid.Column="1"/>
<Button Content="绑定" Command="{Binding BindJobNum}" HorizontalAlignment="Left" Width="66" Margin="250,62,0,0" VerticalAlignment="Top" Grid.Column="1"/>
<Button Content="解绑" Command="{Binding UnBindJobNum}" HorizontalAlignment="Left" Width="66" Margin="320,62,0,0" VerticalAlignment="Top" Grid.Column="1"/>
<ComboBox ItemsSource="{Binding PalletStatus}" FontWeight="Bold" SelectedValue="{Binding SelectedValue,Mode=TwoWay}" IsReadOnly="True" HorizontalAlignment="Left" Margin="285,57,0,0" VerticalAlignment="Top" Width="135"/>
<Label Content="托盘状态:" Foreground="White" FontWeight="Bold" Style="{DynamicResource BaseStyle}" HorizontalContentAlignment="Right" HorizontalAlignment="Left" Margin="214,62,0,0" VerticalAlignment="Top" Width="66"/>
<Button Content="更新" Command="{Binding UpdatePalletStatus}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="56" Margin="422,57,0,0" />
<Label Content="水份判断:" Foreground="White" FontWeight="Bold" Style="{DynamicResource BaseStyle}" HorizontalContentAlignment="Right" HorizontalAlignment="Left" Margin="0,62,0,0" VerticalAlignment="Top" Width="90"/>
<Button Content="水分值输入" x:Name="moistureInput" IsEnabled ="{Binding IsEnabled}" Command="{Binding MoistureInput}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" Margin="90,60,0,0"/>
<Button Content="绑定" Command="{Binding UpdatePalletCode}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="56" Margin="421,15,0,0"/>
<Button Content="解绑" Command="{Binding UpdatePalletNoneCode}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="56" Margin="477,15,0,0"/>
<Label Content="是否带水:" Foreground="White" FontWeight="Bold" Style="{DynamicResource BaseStyle}" HorizontalContentAlignment="Right" HorizontalAlignment="Left" Margin="25,102,0,0" VerticalAlignment="Top" Width="66"/>
<TextBox x:Name="IsWater" Text="{Binding IsWaterValue}" FontWeight="Bold" IsEnabled="False" HorizontalAlignment="Left" Height="23" Margin="90,100,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="50"/>
<Button Content="增加电芯" Command="{Binding AddBatteryCommand}" IsEnabled ="{Binding IsEnabledAdd}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="70" Margin="145,100,0,0"/>
<Label Content="信息绑定:" Foreground="White" FontWeight="Bold" Style="{DynamicResource BaseStyle}" HorizontalContentAlignment="Right" HorizontalAlignment="Left" Margin="190,102,0,0" VerticalAlignment="Top" Width="90"/>
<TextBox Text="{Binding VirtualId}" FontWeight="Bold" HorizontalAlignment="Left" Height="23" Margin="285,100,0,0" VerticalAlignment="Top" Width="135"/>
<Button Content="绑定" Command="{Binding UpdateVirtualId}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="56" Margin="421,100,0,0"/>
<Label Content="工站备注:" Foreground="White" FontWeight="Bold" Style="{DynamicResource BaseStyle}" HorizontalContentAlignment="Right" HorizontalAlignment="Left" Margin="534,102,0,0" VerticalAlignment="Top" Width="66"/>
<TextBox x:Name="stationRemark" FontWeight="Bold" HorizontalAlignment="Left" Height="23" Margin="5,102,0,0" TextWrapping="Wrap" Text="{Binding Remark,Mode=TwoWay}" VerticalAlignment="Top" Width="310" Grid.Column="1"/>
<Button Content="备注" Command="{Binding AddRemark}" HorizontalAlignment="Left" Width="66" Margin="320,102,0,0" VerticalAlignment="Top" Grid.Column="1"/>
</Grid>
</Window>

View File

@@ -0,0 +1,34 @@
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Unity;
namespace Cowain.Bake.Main.Views
{
/// <summary>
/// StationDtl.xaml 的交互逻辑
/// </summary>
public partial class CavityDtlView : Window
{
ViewModels.CavityDtlViewModel viewModel = null;
public CavityDtlView(string stationNameIn, IUnityContainer unityContainer)
{
InitializeComponent();
viewModel = new ViewModels.CavityDtlViewModel(unityContainer);
this.DataContext = viewModel;
viewModel.StationName = stationNameIn;
viewModel.GetInfo();
}
}
}

View File

@@ -0,0 +1,152 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Cowain.Bake.Main.Views">
<!--ComboBox-->
<!--ComBoBox项选中背景色-->
<SolidColorBrush x:Key="ComboBoxSelectdBackground" Color="#ff8c69"/>
<!--ComBoBox项鼠标经过背景色-->
<SolidColorBrush x:Key="ComboBoxMouseOverBackground" Color="#ff3030"/>
<!--ComBoBox项选中前景色-->
<SolidColorBrush x:Key="ComboBoxSelectedForeground" Color="Black"/>
<!--ComBoBox项鼠标经过前景色-->
<SolidColorBrush x:Key="ComboBoxMouseOverForegrond" Color="White"/>
<ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
<Grid Height="25" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<Border Background="White" Grid.ColumnSpan="2" Opacity="0"/>
<Path x:Name="Arrow" Grid.Column="1" Data="M 0 0 6 6 12 0 Z" VerticalAlignment="Center" HorizontalAlignment="Center" Stretch="None" Fill="#999" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter TargetName="Arrow" Property="RenderTransform">
<Setter.Value>
<RotateTransform CenterX="6" CenterY="3" Angle="180"></RotateTransform>
</Setter.Value>
</Setter>
<Setter TargetName="Arrow" Property="Margin" Value="0 0 0 2"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!--MultiComboBox普通样式-->
<Style TargetType="{x:Type controls:MultiComboBox}">
<Setter Property="Width" Value="200" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="MaxDropDownHeight" Value="400" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:MultiComboBox}">
<Grid>
<Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"
BorderBrush="#E0E0E0" CornerRadius="4"
BorderThickness="1" >
<Grid x:Name="PART_Root">
<Grid x:Name="PART_InnerGrid" Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="0.3*" MaxWidth="30" />
</Grid.ColumnDefinitions>
<ListBox Margin="1" x:Name="PART_ListBoxChk" Background="#ADE5EF" SelectionMode="Multiple" BorderThickness="0" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" VirtualizingStackPanel.IsVirtualizing="True" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="IsSelected" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<CheckBox BorderThickness="0" Background="#212f3e" Foreground="Gray" VerticalAlignment="Center" HorizontalAlignment="Center" Content="{Binding ViewName}" IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<!--下拉按钮-->
<ToggleButton x:Name="PART_DropDownToggle" IsTabStop="False"
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
Grid.Column="1" Template="{StaticResource ComboBoxToggleButton}" />
</Grid>
</Grid>
</Border>
<!--弹出多选列表-->
<Popup x:Name="PART_Popup" AllowsTransparency="True" Focusable="False" StaysOpen="False"
IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"
PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
<Grid Width="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}" MaxHeight="{Binding MaxDropDownHeight, RelativeSource={RelativeSource TemplatedParent}}" >
<ListBox x:Name="PART_ListBox" SelectionMode="Multiple" BorderThickness="1 0 1 1" Background="White" ItemsSource="{Binding ItemsSource,RelativeSource={RelativeSource TemplatedParent}}"
MaxHeight="{TemplateBinding MaxDropDownHeight}" BorderBrush="#eaeaea" >
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}" >
<Grid Height="22">
<Border x:Name="bg" BorderBrush="#eaeaea" BorderThickness="0"/>
<ContentPresenter x:Name="content" />
<Border Background="White" Opacity="0"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="bg" Property="Background" Value="#ADD6FF" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="true" />
<Condition Property="IsSelected" Value="false"/>
</MultiTrigger.Conditions>
<Setter TargetName="bg" Property="Background" Value="#009BDB" />
<Setter TargetName="bg" Property="Opacity" Value="0.7"/>
<Setter Property="Foreground" Value="White" />
</MultiTrigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="bg" Property="Opacity" Value="0.3" />
<Setter Property="Foreground" Value="Gray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<CheckBox x:Name="chk" Visibility="Hidden" IsChecked="{Binding IsCheck,Mode=TwoWay}" VerticalAlignment="Center"/>
<CheckBox VerticalAlignment="Center" Foreground="{Binding Foreground,RelativeSource={RelativeSource AncestorType=ListBoxItem}}" IsChecked="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsSelected,Mode=TwoWay}" Content="{Binding Path=ViewName}" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsSelected}" Value="true">
<Setter TargetName="chk" Property="IsChecked" Value="true"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsSelected}" Value="false">
<Setter TargetName="chk" Property="IsChecked" Value="false"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,208 @@
<UserControl x:Class="Cowain.Bake.Main.Views.EquipmentMonitorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:prism="http://prismlibrary.com/"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:hc="https://handyorg.github.io/handycontrol"
mc:Ignorable="d"
prism:ViewModelLocator.AutoWireViewModel="True"
Loaded="EquipmentMonitorView_Loaded"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<Style x:Key="DefaultToolTipStyle" TargetType="{x:Type ToolTip}">
<Setter Property="Foreground" Value="Yellow"/>
<Setter Property = "Background" Value="Blue"/>
<Setter Property = "FontSize" Value="14"/>
<Setter Property="BorderBrush" Value="White"/>
</Style>
<Style x:Key="MyButton" TargetType="Button">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightBlue"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Canvas x:Name="mainCanvas" Margin="0,0,0,0" Height="auto" Width="auto" Loaded="Canvas_Loaded">
<Canvas.Background>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<!-- 起点颜色 -->
<GradientStop Color="LightBlue" Offset="0" />
<!-- 终点颜色 -->
<GradientStop Color="LightBlue" Offset="1" />
</LinearGradientBrush>
</Canvas.Background>
<Grid Canvas.Left="0" Canvas.Top="0" Width="700" Height="30">
<!-- 定义一行七列 -->
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- 为每一列设置单独的背景色和内容 -->
<Border Grid.Column="0" Background="White">
<TextBlock Text="空夹具" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Black" FontSize="16"/>
</Border>
<Border Grid.Column="1" Background="Bisque">
<TextBlock Text="上料中" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Black" FontSize="16"/>
</Border>
<Border Grid.Column="2" Background="Purple">
<TextBlock Text="满载" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16"/>
</Border>
<Border Grid.Column="3" Background="DarkOrange">
<TextBlock Text="烘烤中" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16"/>
</Border>
<Border Grid.Column="4" Background="Green">
<TextBlock Text="烘烤完成" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16"/>
</Border>
<Border Grid.Column="5" Background="gold">
<TextBlock Text="待测结果" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16"/>
</Border>
<Border Grid.Column="6" Background="PaleGreen">
<TextBlock Text="检测OK" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16"/>
</Border>
<Border Grid.Column="7" Background="DeepPink">
<TextBlock Text="检测NG" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16"/>
</Border>
<Border Grid.Column="8" Background="LightSteelBlue">
<TextBlock Text="下料中" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16"/>
</Border>
<Border Grid.Column="9" Background="Tan">
<TextBlock Text="维修中" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16"/>
</Border>
<Border Grid.Column="10" Background="red">
<TextBlock Text="异常" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16"/>
</Border>
</Grid>
<Grid Canvas.Left="0" Canvas.Top="45" Width="500" Height="60">
<hc:StepBar x:Name="StepBarControl" StepIndex="{Binding StepIndex}" >
<hc:StepBarItem Content="无任务"/>
<hc:StepBarItem Content="移至取位">
<hc:StepBarItem.ContextMenu>
<ContextMenu>
<MenuItem Header="发送指令" Command="{Binding ReSendCommand}"
CommandParameter="10" />
</ContextMenu>
</hc:StepBarItem.ContextMenu>
</hc:StepBarItem>
<hc:StepBarItem Content="取盘">
<hc:StepBarItem.ContextMenu>
<ContextMenu>
<MenuItem Header="发送指令" Command="{Binding ReSendCommand}"
CommandParameter="20"/>
</ContextMenu>
</hc:StepBarItem.ContextMenu>
</hc:StepBarItem>
<hc:StepBarItem Content="移至放位">
<hc:StepBarItem.ContextMenu>
<ContextMenu>
<MenuItem Header="发送指令" Command="{Binding ReSendCommand}"
CommandParameter="11" />
</ContextMenu>
</hc:StepBarItem.ContextMenu>
</hc:StepBarItem>
<hc:StepBarItem Content="放盘">
<hc:StepBarItem.ContextMenu>
<ContextMenu>
<MenuItem Header="发送指令" Command="{Binding ReSendCommand}"
CommandParameter="30" />
</ContextMenu>
</hc:StepBarItem.ContextMenu>
</hc:StepBarItem>
<hc:StepBarItem Content="完成"/>
</hc:StepBar>
</Grid>
<Grid Canvas.Right="0" Canvas.Top="40" Width="700" Height="50">
<!-- 定义一行七列 -->
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1.5*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1.2*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<!-- 为每一列设置单独的背景色和内容 -->
<Border Grid.Row="0" Background="Transparent">
<TextBlock Text="取盘位置:" HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="White" FontSize="14"/>
</Border>
<Border Grid.Row="0" Grid.Column="1" Background="Transparent">
<TextBlock Text="{Binding CavitySourceName}" HorizontalAlignment="Left" FontWeight="Bold" VerticalAlignment="Center" Foreground="White" FontSize="16"/>
</Border>
<Border Grid.Row="0" Grid.Column="2" Background="Transparent">
<TextBlock Text="任务状态:" HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="White" FontSize="14"/>
</Border>
<Border Grid.Row="0" Grid.Column="3" Background="Transparent">
<TextBlock Text="{Binding TaskStatusName}" HorizontalAlignment="Left" FontWeight="Bold" VerticalAlignment="Center" Foreground="White" FontSize="16"/>
</Border>
<Border Grid.Row="0" Grid.Column="4" Background="Transparent">
<TextBlock Text="任务类型:" HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="White" FontSize="14"/>
</Border>
<Border Grid.Row="0" Grid.Column="5" Background="Transparent">
<TextBlock Text="{Binding TaskTypeName}" HorizontalAlignment="Left" FontWeight="Bold" VerticalAlignment="Center" Foreground="White" FontSize="16"/>
</Border>
<Border Grid.Row="1" Grid.Column="0" Background="Transparent">
<TextBlock Text="放盘位置:" HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="White" FontSize="14"/>
</Border>
<Border Grid.Row="1" Grid.Column="1" Background="Transparent">
<TextBlock Text="{Binding CavityTargetName}" HorizontalAlignment="Left" FontWeight="Bold" VerticalAlignment="Center" Foreground="White" FontSize="16"/>
</Border>
<Border Grid.Row="1" Grid.Column="2" Background="Transparent">
<TextBlock Text="夹具条码:" HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="White" FontSize="14"/>
</Border>
<Border Grid.Row="1" Grid.Column="3" Background="Transparent">
<TextBlock Text="{Binding PalletCode}" HorizontalAlignment="Left" FontWeight="Bold" VerticalAlignment="Center" Foreground="White" FontSize="16"/>
</Border>
<Border Grid.Row="1" Grid.Column="4" Background="Transparent">
<TextBlock Text="开始时间:" HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="White" FontSize="14"/>
</Border>
<Border Grid.Row="1" Grid.Column="5" Background="Transparent">
<TextBlock Text="{Binding StartTime,StringFormat=yyyy-MM-dd HH:mm:ss}" HorizontalAlignment="Left" FontWeight="Bold" VerticalAlignment="Center" Foreground="White" FontSize="16"/>
</Border>
</Grid>
<Button Content="" x:Name="AGV" HorizontalAlignment="Left"
VerticalAlignment="Top" Width="80" Height="73" Canvas.Left="14" Canvas.Top="{Binding HandMachineYLocation}" Panel.ZIndex="101">
<Button.RenderTransform>
<TranslateTransform x:Name="machineAnimation"/>
</Button.RenderTransform>
<Button.Template>
<ControlTemplate>
<Grid>
<Label Name="handMachineLabel" Panel.ZIndex="100" HorizontalContentAlignment="Center" Foreground="Black" FontSize="13px" Content="{Binding RgvPalletCode}" Width="80" Height="30" Style="{StaticResource BaseStyle}" Margin="0,0,0,0">
</Label>
<Image Source="{Binding ImageSource}"></Image>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
<Canvas x:Name="pathCanvas" Panel.ZIndex="99" Margin="0,0,0,0" Height="auto" Width="auto"></Canvas>
</Canvas>
</UserControl>

View File

@@ -0,0 +1,39 @@
using Cowain.Bake.Main.ViewModels;
using Prism.Regions;
using System.Windows;
using System.Windows.Controls;
using Unity;
namespace Cowain.Bake.Main.Views
{
/// <summary>
/// CutAndFlodView.xaml 的交互逻辑
/// </summary>
public partial class EquipmentMonitorView : UserControl, IRegionMemberLifetime
{
//IUnityContainer _unityContainer = null;
public EquipmentMonitorViewModel vm;
public bool KeepAlive => false; // 确保视图被缓存
public EquipmentMonitorView(IUnityContainer unityContainer, Prism.Events.IEventAggregator eventAggregator)
{
InitializeComponent();
vm = this.DataContext as EquipmentMonitorViewModel;
vm.frameworkElement = this;
vm.machineAnimation = machineAnimation;
vm.mainCanvas = mainCanvas;
vm.pathCanvas = pathCanvas;
}
private void Canvas_Loaded(object sender, RoutedEventArgs e)
{
}
private void EquipmentMonitorView_Loaded(object sender, RoutedEventArgs e)
{
vm._localScreenWidth = mainCanvas.ActualWidth;// SystemParameters.PrimaryScreenWidth; //1536
vm._localScreenHeight = mainCanvas.ActualHeight;// SystemParameters.PrimaryScreenHeight;
vm.Init();
Loaded -= EquipmentMonitorView_Loaded; //不加这个,切换到主界面时,会触发多次
}
}
}

View File

@@ -0,0 +1,64 @@
<UserControl x:Class="Cowain.Bake.Main.Views.LogManagement"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Cowain.Bake.Main.Views"
xmlns:hc="https://handyorg.github.io/handycontrol"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Height="30">
<!--<Label Content="{DynamicResource DateTime}" BorderThickness="0" Background="Transparent"
Margin="10,0,0,0" Foreground="Gray" Visibility="Collapsed"/>
<hc:DatePicker Width="150" x:Name="datePick" Visibility="Collapsed"/>
<Button Content="{DynamicResource Query}" Margin="10,0,0,0" Click="findLog_Click" x:Name="findLog" Visibility="Collapsed"/>
<Button Content="{DynamicResource RealTimeLog}" Margin="10,0,0,0" Click="realTime_Click" x:Name="realTime" Visibility="Collapsed"/>-->
<!--<hc:Divider Orientation="Vertical" LineStrokeThickness="5"
LineStroke="#3D99A0"/>-->
<!--<Label Content="{DynamicResource Filter}" BorderThickness="0" Background="Transparent"
Margin="0,0,0,0" Foreground="Gray"/>-->
<local:MultiComboBox x:Name="mucombo" SelectionChanged="mucombo_SelectionChanged" Margin="5,0,0,0.4" Width="200"/>
<Label x:Name="labstate" Background="Transparent" BorderThickness="0"
Margin="10,0,0,0" Foreground="YellowGreen"/>
</StackPanel>
<hc:ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto"
CanMouseWheel="true"
IsInertiaEnabled="True"
>
<ListBox x:Name="loglist" Background="LightGray"
hc:ScrollViewer.IsInertiaEnabled="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Line X1="0" X2="0" Y1="0" Y2="{Binding ActualHeight,RelativeSource={RelativeSource Mode=Self}}"
StrokeThickness="1" Stroke="#551e90ff" HorizontalAlignment="Center"/>
<Ellipse Width="6" Height="6" Fill="#AA1e90ff" VerticalAlignment="Top" Margin="0,4,1,0"/>
<StackPanel Grid.Column="1">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding LogLevel}" FontSize="12" Foreground="{Binding FontColor}" Margin="5,0,0,0"></TextBlock>
<TextBlock></TextBlock>
<TextBlock Text="{Binding LogText,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" TextWrapping="Wrap"
Foreground="{Binding Foreground, ElementName=onelogs}"
FontSize="12" Margin="0,0,0,5"/>
</StackPanel>
<TextBlock Text="{Binding LogTime,StringFormat='yyyy-MM-dd HH:mm:ss'}" FontSize="11" Margin="5,5,0,10" Opacity="0.6" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</hc:ScrollViewer>
</Grid>
</UserControl>

View File

@@ -0,0 +1,172 @@
using Cowain.Bake.Common.Core;
using Prism.Mvvm;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using Cowain.Bake.Main.Views;
using Cowain.Bake.Main.Models;
using Cowain.Bake.Common;
namespace Cowain.Bake.Main.Views
{
/// <summary>
/// LogManagement.xaml 的交互逻辑
/// </summary>
public partial class LogManagement : UserControl
{
/// <summary>
/// 绑定数据
/// </summary>
private ObservableCollection<LogModel> bindingData { set; get; } = new ObservableCollection<LogModel>();
/// <summary>
/// 实时数据
/// </summary>
private List<LogModel> realTimeDatas { set; get; } = new List<LogModel>();
private BlockingCollection<LogModel> logQueue = new BlockingCollection<LogModel>();
private Dictionary<string, MultiComboBox.MultiCbxBaseData> IsHaveKeyDic { set; get; } = new Dictionary<string, MultiComboBox.MultiCbxBaseData>();
public LogManagement()
{
InitializeComponent();
if (loglist.ItemsSource == null)
{
loglist.ItemsSource = bindingData;
}
Task.Run(() => DispatcherTimer_Tick());
Unloaded += LogManagement_Unloaded;
}
private void LogManagement_Unloaded(object sender, RoutedEventArgs e)
{
}
/// <summary>
/// 刷新队列
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void DispatcherTimer_Tick()
{
while (true)
{
if (Global.AppExit)
{
return;
}
LogModel model = logQueue.Take();
if (null == model)
{
continue;
}
var item = realTimeDatas.Find(x => x.LogText == model.LogText);
if (null != item) //表示有相同的数据
{
continue;
}
//显示数据
if (IsHaveKeyDic.ContainsKey(model.LogLevel) && IsHaveKeyDic[model.LogLevel].IsCheck)
{
Application.Current.Dispatcher.Invoke(() =>
{
bindingData.Insert(0, model);
if (bindingData.Count > Global.MAX_LOG_QTY)
{
bindingData.RemoveAt(bindingData.Count - 1);
}
});
}
//实时数据
realTimeDatas.Insert(0, model);
if (realTimeDatas.Count > Global.MAX_LOG_QTY)
{
realTimeDatas.RemoveAt(realTimeDatas.Count - 1);
}
}
}
#region []
private static readonly DependencyProperty LoglistItemProperty = DependencyProperty.Register(
"LoglistItem", typeof(LogModel), typeof(LogManagement), new PropertyMetadata(null, OnLoglistSourceChange));
private static void OnLoglistSourceChange(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
if (o is LogManagement log)
{
var model = e.NewValue as LogModel;
//入队
log.logQueue.Add(model);
}
}
public LogModel LoglistItem
{
get => (LogModel)GetValue(LoglistItemProperty);
set => SetValue(LoglistItemProperty, value);
}
#endregion
#region []
private static readonly DependencyProperty LogLevelSourceProperty = DependencyProperty.Register(
"LogLevelSource", typeof(ObservableCollection<MultiComboBox.MultiCbxBaseData>), typeof(LogManagement),
new PropertyMetadata(null, OnLogLevelSourceChange));
private static void OnLogLevelSourceChange(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
if (o is LogManagement log)
{
log.mucombo.ItemsSource = e.NewValue as ObservableCollection<MultiComboBox.MultiCbxBaseData>;
}
}
public ObservableCollection<MultiComboBox.MultiCbxBaseData> LogLevelSource
{
get => (ObservableCollection<MultiComboBox.MultiCbxBaseData>)GetValue(LogLevelSourceProperty);
set => SetValue(LogLevelSourceProperty, value);
}
#endregion
private void mucombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.Source is MultiComboBox multiComboBox && multiComboBox.ItemsSource is ObservableCollection<MultiComboBox.MultiCbxBaseData> list)
{
IsHaveKeyDic = list.ToDictionary(d => d.ViewName, d => d);
bindingData.Clear();
foreach (var item in realTimeDatas)
{
if (IsHaveKeyDic.ContainsKey(item.LogLevel) && IsHaveKeyDic[item.LogLevel].IsCheck)
{
bindingData.Add(item);
}
}
}
}
}
}

View File

@@ -0,0 +1,31 @@
<UserControl x:Class="Cowain.Bake.Main.Views.MainHeaderView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:Fluent="urn:fluent-ribbon"
xmlns:local="clr-namespace:Cowain.Bake.Main.Views"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
xmlns:hc="https://handyorg.github.io/handycontrol"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Cowain.Bake.Common;component/Styles/BaseResources.xaml"/>
<ResourceDictionary Source="pack://application:,,,/Cowain.Bake.Common;component/Styles/ToggleButtonStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid x:Name="maingrid" >
<Fluent:Ribbon Height="auto" BorderBrush="LightGray" BorderThickness="1" Grid.Row="0" x:Name="mainRibbon" ShowQuickAccessToolBarAboveRibbon="True" SelectedTabIndex="2">
<Fluent:Ribbon.Menu>
<Fluent:Backstage Header="工具栏"></Fluent:Backstage>
</Fluent:Ribbon.Menu>
</Fluent:Ribbon>
</Grid>
</UserControl>

View File

@@ -0,0 +1,496 @@
using Cowain.Bake.BLL;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Model;
using Fluent;
using Prism.Ioc;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using Unity;
using System.Linq;
using System.Windows.Media;
using Newtonsoft.Json;
using Cowain.Bake.Main.ViewModels;
namespace Cowain.Bake.Main.Views
{
/// <summary>
/// MainHeaderView.xaml 的交互逻辑
/// </summary>
public partial class MainHeaderView : UserControl
{
private static Dictionary<string, RibbonGroupBox> parentGroupBoxDic = new Dictionary<string, RibbonGroupBox>();
private static IUnityContainer _unityContainer;
public static Dictionary<string, Label> toggleButtonLabelDic = new Dictionary<string, Label>();
public static Dictionary<string, Fluent.Button> ribbonButtonDic = new Dictionary<string, Fluent.Button>();
private static List<Fluent.ToggleButton> toggleButton = new List<Fluent.ToggleButton>();
private static Views.MainHeaderView MainHeaderViewForPublic;
private static List<Label> toggleBtnLabel = new List<Label>();
private static List<TMenuInfo> menuInfos;
public static Dictionary<int, StackPanel> dicStackPanel = new Dictionary<int, StackPanel>();
Fluent.DropDownButton splitButton = new Fluent.DropDownButton();
private static IRegionManager _regionManager = null;
private List<string> _theme = new List<string>();
public MainHeaderView(IUnityContainer unityContainer, IRegionManager regionManager)
{
InitializeComponent();
_regionManager = regionManager;
_unityContainer = unityContainer;
//mainRibbonForPublic = mainRibbon;
MainHeaderViewForPublic = this;
menuInfos = _unityContainer.Resolve<MenuInfoService>().GetMenuInfoList();
GenerateMenuImage();
ClearWindows();
Init();
SetTheme();
}
void SetTheme()
{
/*
“Red”, “Green”, “Blue”, “Purple”, “Orange”, “Lime”, “Emerald”, “Teal”, “Cyan”, “Cobalt”, “Indigo”, “Violet”, “Pink”, “Magenta”, “Crimson”, “Amber”, “Yellow”, “Brown”, “Olive”, “Steel”, “Mauve”, “Taupe”, “Sienna”
and these base colors: “Light”, “Dark”
*/
//var theme = ControlzEx.Theming.ThemeManager.Current.DetectTheme(Application.Current);
_theme.Add("Light.Blue");
_theme.Add("Light.Amber");
_theme.Add("Light.Magenta");
_theme.Add("Dark.Green");
_theme.Add("Light.Green");
_theme.Add("Dark.Lime");
ChangeSkin(SettingProvider.Instance.SkinType);
_unityContainer.Resolve<MainWindow>().ChangeSkin(SettingProvider.Instance.SkinType);
}
public void ChangeSkin(int i)
{
ControlzEx.Theming.ThemeManager.Current.ChangeTheme(App.Current, _theme[i]);
}
public void ClearWindows()
{
parentGroupBoxDic.Clear();
toggleButtonLabelDic.Clear();
ribbonButtonDic.Clear();
mainRibbon.Tabs.Clear();
dicStackPanel.Clear();
}
public void Init()
{
AddMenuFatherLabelItems();
AddStackPanel();
AddMenuGroupBoxItems();
MainWindow.mainShowWindow.Title = "产量查询";
_regionManager.RequestNavigate("MainContentRegion", "ProductionsInfoView");
if (EDispatchMode.Manual == SettingProvider.Instance.DispMode)
{
ribbonButtonDic["Manual"].IsEnabled = false;
ribbonButtonDic["Auto"].IsEnabled = true;
}
else
{
ribbonButtonDic["Manual"].IsEnabled = true;
ribbonButtonDic["Auto"].IsEnabled = false;
}
mainRibbon.Tabs[0].IsSelected = true;
}
/// <summary>
/// 添加菜单标签列表
/// </summary>
/// <param name="parentId"></param>
private void AddMenuFatherLabelItems(int parentId = 0)
{
var menuParentInfos = menuInfos.Where(p => p.ParentId == parentId);
foreach (var item in menuParentInfos)
{
RibbonTabItem ribbonTabItem = new RibbonTabItem()
{
Header = item.Header,
Name = item.HeaderName
};
RibbonGroupBox ribbonGroupBox = new RibbonGroupBox();
ribbonGroupBox.Name = $"{item.Header}GroupBox";
ribbonTabItem.Groups.Add(ribbonGroupBox);
mainRibbon.Tabs.Add(ribbonTabItem);
parentGroupBoxDic.Add(item.Id.ToString(), ribbonGroupBox);
}
}
/// <summary>
/// 添加工具栏功能列表
/// </summary>
private void AddMenuGroupBoxItems()
{
var roleContainNodes = _unityContainer.Resolve<UserService>().GetCurrentUserAuthority();
//var strTolist = CommonCoreHelper.Instance.StringToListConverter(roleContainNodes); && strTolist.Contains(p.HeaderName)
var menuParentIds = menuInfos.Where(p => p.ParentId == 0).ToList();
var btnContentMenuItems = menuInfos.Where(p => menuParentIds.Select(x => x.Id).Contains(p.ParentId)).OrderBy(p => p.ParentId).ThenBy(p => p.MenuIndex);
foreach (var item in btnContentMenuItems)
{
switch ((EMenuType)item.MenuType)
{
case EMenuType.Cmd:
case EMenuType.Region:
case EMenuType.ShowDialog:
FillRibbonButton(item);
break;
case EMenuType.FunctionSwitch:
DrawToggleButton(item);
break;
case EMenuType.DropDown:
DrawSplitButton(item);
break;
default:
break;
}
}
}
#region
//0.按键:弹界面
//1.按键:功能,如开始,停止
//2.开关:功能开关如是否启用MOM
private static void RibbonButton_Click(object sender, RoutedEventArgs e)
{
try
{
string btnName = "";
var type = sender.GetType();
if (type == typeof(Fluent.Button))
{
btnName = (sender as Fluent.Button).Name;
}
else
{
btnName = (sender as Fluent.ToggleButton).Name;
}
TMenuInfo menuInfo = menuInfos.FirstOrDefault(p => p.HeaderName == btnName);
if (null == menuInfo)
{
LogHelper.Instance.GetCurrentClassWarn("查找按键信息失败!", true);
return;
}
switch ((EMenuType)menuInfo.MenuType)
{
case EMenuType.ShowDialog:
ShowDialog(menuInfo);
break;
case EMenuType.Region:
ShowWindowsRegion(menuInfo);
break;
case EMenuType.Cmd:
case EMenuType.FunctionSwitch:
ExecuteMethod(menuInfo);
break;
default:
LogHelper.Instance.Warn($"没有这个菜单[{btnName}]类型:{(int)menuInfo.MenuType}");
break;
}
}
catch (Exception ex)
{
LogHelper.Instance.GetCurrentClassDebug(ex.Message);
}
}
private static void ShowDialog(TMenuInfo menuInfo)
{
TMenuInfo asmBaseName = menuInfos.FirstOrDefault(p => p.ParentId == 0 && p.Id == menuInfo.ParentId);
if (null == asmBaseName)
{
HandyControl.Controls.MessageBox.Info($"当前'{asmBaseName.Header}'目标路径不正确,请在数据库中重新配置!!");
return;
}
System.Reflection.Assembly asm = System.Reflection.Assembly.Load(asmBaseName.TargetView);// 通过类型的完整限定名和程序集获取类型
Type viewNameType = asm.GetType(menuInfo.TargetView);
if (null == viewNameType)
{
LogHelper.Instance.Info($"当前'{menuInfo.Header}'类型的完整限定名不正确,请在数据库中重新配置!", true);
return;
}
var dlg = (System.Windows.Window)_unityContainer.Resolve(viewNameType);
if (dlg.ShowDialog().Value)
{
_unityContainer.Resolve<BasicInfoViewModel>().ShowInfo();
HandyControl.Controls.MessageBox.Success("切换用户成功");
_unityContainer.Resolve<LogService>().AddLog($@"切换用户成功!", E_LogType.Operate.ToString());
}
//object typeInstance = Activator.CreateInstance(viewNameType); //不会传参数
//Window dlg = typeInstance as Window;
//dlg.ShowDialog();
}
private static void ShowWindowsRegion(TMenuInfo menuInfo)
{
MainWindow.mainShowWindow.Title = menuInfo.Header;
_regionManager.RequestNavigate("MainContentRegion", menuInfo.TargetView);
}
private static void ExecuteMethod(TMenuInfo menuInfo)
{
dynamic d = JsonConvert.DeserializeObject<dynamic>(menuInfo.JSON);
string methodName = d.CMD;
string param = d.Parameter;
Type type = Type.GetType(Cowain.Bake.Common.MyPath.HEAD_CMD);
object[] instancePara = new object[1];
instancePara[0] = _unityContainer;
object obj = System.Activator.CreateInstance(type, instancePara);
MethodInfo method = type.GetMethod(methodName, new Type[] { typeof(string) });
object[] parameters = new object[] { param };
method.Invoke(obj, parameters);
}
#endregion
#region
private void FillRibbonButton(TMenuInfo menuInfo)
{
var ribbonGroup = parentGroupBoxDic[menuInfo.ParentId.ToString()];
Fluent.Button button = new Fluent.Button();
button.Name = menuInfo.HeaderName;
button.Header = menuInfo.Header;
button.Width = 60; //MyAppContainer.Current.Resolve<UserService>().IsHasAuthority(menuInfo.HeaderName == null ? "" : menuInfo.HeaderName);
button.IsEnabled = _unityContainer.Resolve<UserService>().IsHasAuthority(menuInfo.HeaderName == null ? "" : menuInfo.HeaderName);
string imagePath = Environment.CurrentDirectory + $@"\images\{menuInfo.Header}.png";
if (File.Exists(imagePath))
{
button.LargeIcon = imagePath; //imagePath;
}
button.Click += RibbonButton_Click;
if (ribbonGroup != null)
{
ribbonGroup.Items.Add(button);
}
if (!ribbonButtonDic.ContainsKey(menuInfo.HeaderName))
{
ribbonButtonDic.Add(menuInfo.HeaderName, button);
}
}
private void SplitButton_Click(object sender, RoutedEventArgs e)
{
//if (sender is Fluent.MenuItem item)
//{
// var name = item.Tag.ToString().Replace("_", ".");
// maingrid.Background = new ImageBrush
// {
// ImageSource = new System.Windows.Media.Imaging.BitmapImage(new Uri($"pack://application:,,,/Cowain.Bake.Main;component/Images/UserControls/{name}"))
// };
//}
Fluent.MenuItem currentMenu = (Fluent.MenuItem)sender;
splitButton.IsDropDownOpen = false;
for (int i = 0; i < splitButton.Items.Count; ++i)
{
Fluent.MenuItem menu = (Fluent.MenuItem)splitButton.Items.GetItemAt(i);
if (menu.Header != currentMenu.Header
&& menu.IsChecked)
{
menu.IsChecked = false;
}
}
if (currentMenu.IsChecked)
{
int value = (int)EnumHelper.GetValueByDescription<ESkin>((string)currentMenu.Header);
ChangeSkin(value);
_unityContainer.Resolve<MainWindow>().ChangeSkin(value);
SettingProvider.Instance.SkinType = value;
}
}
private Fluent.MenuItem CreateSplitButtonMenu(ESkin eskin, bool isCheck)
{
var menu = new Fluent.MenuItem
{
Header = eskin.GetDescription(),
Tag = eskin.ToString(),
IsCheckable = true,
IsChecked = isCheck, // 默认选中
};
menu.Click += SplitButton_Click;
return menu;
}
private void DrawSplitButton(TMenuInfo menuInfo)
{
splitButton.Header = menuInfo.Header;
// 设置大图标LargeIconnew BitmapImage(new Uri("pack://application:,,,/Images/LargeIcon.png"));
splitButton.LargeIcon = new System.Windows.Media.Imaging.BitmapImage
(new Uri(Environment.CurrentDirectory + $@"\images\{menuInfo.Header}.png"));
// 其他属性(尺寸、边距等)
splitButton.Width = 60;
//splitButton.Margin = new Thickness(1);
//splitButton.HorizontalAlignment = HorizontalAlignment.Left;
//splitButton.VerticalAlignment = VerticalAlignment.Top;
foreach (ESkin skin in System.Enum.GetValues(typeof(ESkin)))
{
splitButton.Items.Add(CreateSplitButtonMenu(skin, SettingProvider.Instance.SkinType == (int)skin));
}
var ribbonGroup = parentGroupBoxDic[menuInfo.ParentId.ToString()];
ribbonGroup.Items.Add(splitButton);
}
private static void AddStackPanel()
{
var toggles = menuInfos.Where(x => x.MenuType == (int)EMenuType.FunctionSwitch && x.State == true).ToList();
int count = toggles.Count();
var ribbonGroupBox = parentGroupBoxDic[toggles[0].ParentId.ToString()];
count = (int)Math.Ceiling((double)count / 2); //两个一组
StackPanel h = new StackPanel { Orientation = Orientation.Horizontal }; //行
ribbonGroupBox.Items.Add(h);
for (int i = 1; i <= count; i++ )
{
StackPanel v = new StackPanel { Orientation = Orientation.Vertical }; //列
h.Children.Add(v);
dicStackPanel[i] = v;
}
}
private static void DrawToggleButton(TMenuInfo item)
{
var header = item.Header;
var model = Newtonsoft.Json.JsonConvert.DeserializeObject<ParaJSON>(item.JSON);
var ribbonGroupBox = parentGroupBoxDic[item.ParentId.ToString()];
if (ribbonGroupBox == null) return;
var paraValue = _unityContainer.Resolve<MenuInfoService>().GetMenuParam(header);
var isChecked = paraValue == 1;
var labelContent = isChecked ? model.Value1 : model.Value0;
var toggleButton = CreateToggleButton(item, isChecked);
var labelRight = CreateLabel(header, labelContent);
var labelLeft = CreateLabelLeft(header, model.Text);
var canvas = new Canvas { Height = 25, Width = 200 };
canvas.Children.Add(toggleButton);
canvas.Children.Add(labelLeft);
canvas.Children.Add(labelRight);
//ribbonGroupBox.Items.Add(canvas);
toggleButtonLabelDic.Add(header, labelRight);
int index = (int)Math.Ceiling((double)item.MenuIndex / 2);
if (dicStackPanel.ContainsKey(index)) //如果MenuIndex编号乱编会导致溢出
{
dicStackPanel[index].Children.Add(canvas);
}
}
private static Label CreateLabelLeft(string header, object content)
{
var label = new Label
{
BorderThickness = new Thickness(0),
Name = header + "HeaderLabelLeft",
Content = content
};
label.SetValue(System.Windows.Window.LeftProperty, 0d);
label.SetValue(System.Windows.Window.TopProperty, 0d);
return label;
}
private static Label CreateLabel(string header, object content)
{
var label = new Label
{
BorderThickness = new Thickness(0),
Name = header + "HeaderLabel",
Content = content
};
label.SetValue(System.Windows.Window.LeftProperty, 120d);
label.SetValue(System.Windows.Window.TopProperty, 0d);
return label;
}
private static ToggleButton CreateToggleButton(TMenuInfo item, bool isChecked)
{
var toggleButton = new ToggleButton
{
Name = item.HeaderName,
Content = item.Header,
Header = item.Header,
Width = 50,
Style = MainHeaderViewForPublic.FindResource("ToggleButtonStyle") as Style,
IsChecked = isChecked
};
toggleButton.Click += RibbonButton_Click;
toggleButton.SetValue(System.Windows.Window.LeftProperty, 69d);
toggleButton.SetValue(System.Windows.Window.TopProperty, 5d);
return toggleButton;
}
private void ChangeModeColor(Fluent.ComboBox comboBox)
{
string comboBoxColor = Colors.Black.ToString();
switch ((int)comboBox.SelectedValue)
{
case (int)EMOMMode.OnLine:
comboBoxColor = Colors.Green.ToString();
break;
case (int)EMOMMode.OffLine:
comboBoxColor = Colors.Red.ToString();
break;
}
comboBox.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString(comboBoxColor));
}
#endregion
#region
private void GenerateMenuImage()//获取菜单图标
{
var table = _unityContainer.Resolve<MenuInfoService>().GetImage();
byte[] imageByte = null;
string path = Environment.CurrentDirectory + "/images";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
foreach (DataRow item in table.Rows)
{
imageByte = Newtonsoft.Json.JsonConvert.DeserializeObject<byte[]>(item["MenuImage"].ToString());
CreateFile(imageByte, path + "/" + item["Header"] + ".png");
}
}
private static void CreateFile(byte[] fileBuffer, string newFilePath)
{
if (File.Exists(newFilePath))
{
File.Delete(newFilePath);
}
FileStream fs = new FileStream(newFilePath, FileMode.CreateNew);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(fileBuffer, 0, fileBuffer.Length); //用文件流生成一个文件
bw.Close();
fs.Close();
}
#endregion
}
public class ParaJSON
{
public string CMD { get; set; }
public string Parameter { get; set; }
public string Value0 { get; set; }
public string Value1 { get; set; }
public string Text { get; set; }
}
}

View File

@@ -0,0 +1,185 @@
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
xmlns:ad="https://github.com/Dirkster99/AvalonDock"
xmlns:hc="https://handyorg.github.io/handycontrol"
x:Class="Cowain.Bake.Main.Views.MainWindow"
xmlns:converter="clr-namespace:Cowain.Bake.Common.Converter;assembly=Cowain.Bake.Common"
xmlns:bllConverter="clr-namespace:Cowain.Bake.BLL.Converter;assembly=Cowain.Bake.BLL"
xmlns:control="clr-namespace:Cowain.Bake.Main.Views"
xmlns:local="clr-namespace:Cowain.Bake.Main.ViewModels"
mc:Ignorable="d"
WindowState="Maximized"
Closing="Window_Closing"
Title="{Binding MainTitle}" Height="900" Width="1600" Loaded="Window_Loaded">
<Window.Resources>
<converter:BindingColor x:Key="ColorConverter"/>
<bllConverter:StationIdConverter x:Key="StationIdConverter"/>
<Style x:Key="DefaultToolTipStyle" TargetType="{x:Type ToolTip}">
<Setter Property="Foreground" Value="Yellow"/>
<Setter Property = "Background" Value="Blue"/>
<Setter Property = "FontSize" Value="14"/>
<Setter Property="BorderBrush" Value="White"/>
</Style>
<Style x:Key="MyButton" TargetType="Button">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightBlue"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type TabItem}" x:Key="BaseTabItem">
<Setter Property="Header" Value="{Binding DataContext.PageTitle}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Margin" Value="2,0"/>
<Setter Property="Foreground" Value="#444"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="auto" MaxWidth="30" MinWidth="10"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{TemplateBinding Header}" VerticalAlignment="Center" Margin="10,5"/>
<Grid Grid.Column="1" x:Name="close_grid" Width="30" Visibility="Collapsed">
<Button Foreground="{TemplateBinding Foreground}"
Visibility="Collapsed" x:Name="close_btn" Height="24"
Command="{Binding DataContext.CloseCommand}"
CommandParameter="{Binding DataContext.NavUri}"/>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding DataContext.IsCanClose}" Value="True">
<Setter TargetName="close_grid" Property="Visibility" Value="Visible"/>
</DataTrigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Visibility" Value="Visible" TargetName="close_btn"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Visibility" Value="Visible" TargetName="close_btn"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#EEE"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#FF0ABEFF"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="88" />
<RowDefinition Height="*" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<ContentControl prism:RegionManager.RegionName="MainHeaderRegion" Grid.Row="0"></ContentControl>
<!--工作窗口-->
<DockingManager x:Name="dockingManager" Grid.Row="1">
<DockingManager.Background>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<!-- 起点颜色 -->
<GradientStop Color="LightBlue" Offset="0" />
<!-- 终点颜色 -->
<GradientStop Color="LightBlue" Offset="1" />
</LinearGradientBrush>
</DockingManager.Background>
<DockingManager.Theme>
<Vs2013BlueTheme/>
</DockingManager.Theme>
<LayoutRoot>
<LayoutPanel Orientation="Horizontal">
<LayoutAnchorablePane DockWidth="200">
<!--<LayoutAnchorable Title="菜单栏" CanClose="False" CanFloat="False" CanHide="False" ContentId="Solution">
-->
<!--放置菜单的区域-->
<!--
<ContentControl prism:RegionManager.RegionName="LeftMenuTreeRegion"/>
</LayoutAnchorable>-->
<LayoutAnchorable Title="基础信息" CanClose="False" CanFloat="False" CanHide="False" ContentId="Solution">
<!--基础-->
<ContentControl prism:RegionManager.RegionName="BasicInfoRegion"/>
</LayoutAnchorable>
<LayoutAnchorable Title="日志信息" CanClose="False" CanFloat="False" CanHide="False" ContentId="Solution">
<!--日志-->
<control:LogManagement x:Name="logManagement1" LogLevelSource="{Binding LogLevelModel1}"
LoglistItem="{Binding InfoLogModel,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<!--<ContentControl prism:RegionManager.RegionName="LogInfoRegion" x:Name="logManagement1"/>-->
</LayoutAnchorable>
</LayoutAnchorablePane>
<LayoutPanel Orientation="Vertical">
<LayoutDocumentPane IsMaximized="True" x:Name="tabPanel">
<LayoutDocument Title="主窗口" CanClose="False" ContentId="second" IsSelected="True">
<ContentControl prism:RegionManager.RegionName="StationInfoRegion"/>
</LayoutDocument>
<LayoutDocument Title="报警窗口" CanClose="False" ContentId="second">
<Grid>
<TabControl>
<TabItem Header="实时告警">
<DataGrid ItemsSource="{Binding Alarms}" AutoGenerateColumns="False" IsReadOnly="True" HorizontalAlignment="Left" Height="850" VerticalAlignment="Top" Width="1387" Margin="15,15,15,15">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Blue"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
<Setter Property="Foreground" Value="{Binding Status, Converter={StaticResource ColorConverter}}"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="工站名称" Binding="{Binding StationId,Converter={StaticResource StationIdConverter}}" Width="100" Visibility="Visible"/>
<DataGridTextColumn Header="报警内容" Binding="{Binding Desc}" Width="500"/>
<DataGridTextColumn Header="开始时间" Binding="{Binding StartTime,StringFormat='yyyy/MM/dd HH:mm:ss'}" Width="200"/>
<DataGridTextColumn Header="结束时间" Binding="{Binding StopTime,StringFormat='yyyy/MM/dd HH:mm:ss'}" Width="200" Visibility="Hidden"/>
<DataGridTextColumn Header="状态" Binding="{Binding Status}" Width="100"/>
</DataGrid.Columns>
</DataGrid>
</TabItem>
<TabItem Header="记录查询">
<Grid>
<DataGrid Margin="0,50,0,0" AutoGenerateColumns="False" ItemsSource="{Binding HistoryAlarmsData}">
<DataGrid.Columns>
<DataGridTextColumn Header="工站名称" Binding="{Binding StationId,Converter={StaticResource StationIdConverter}}" Width="100"/>
<DataGridTextColumn Header="报警内容" Binding="{Binding Desc}" Width="500"/>
<DataGridTextColumn Header="开始时间" Binding="{Binding StartTime,StringFormat='yyyy/MM/dd HH:mm:ss'}" Width="200"/>
<DataGridTextColumn Header="结束时间" Binding="{Binding StopTime,StringFormat='yyyy/MM/dd HH:mm:ss'}" Width="200" />
<DataGridTextColumn Header="状态" Binding="{Binding Status}" Width="100"/>
</DataGrid.Columns>
</DataGrid>
<hc:DatePicker HorizontalAlignment="Left" Text="{Binding AlarmStartTime,Mode=TwoWay}" VerticalAlignment="Top" Width="131" Margin="8,9,0,0"/>
<hc:DatePicker HorizontalAlignment="Left" Text="{Binding AlarmEndTime,Mode=TwoWay}" VerticalAlignment="Top" Width="140" Margin="144,9,0,0"/>
<Button Content="查询" Style="{StaticResource ButtonInfo}" Name="alarmReport" Command="{Binding AlarmQueryCommand}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="297,9,0,0"/>
<Button Content="导出Excel" Style="{StaticResource ButtonInfo}" x:Name="alarmExportExcel" Command="{Binding AlarmExportExcel}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="391,10,0,0"/>
</Grid>
</TabItem>
<hc:DateTimePicker HorizontalAlignment="Left" VerticalAlignment="Top" Width="195"/>
</TabControl>
</Grid>
</LayoutDocument>
<LayoutDocument x:Name="showWindow" Title="" CanClose="False" ContentId="second">
<!--数据展示-->
<ContentControl prism:RegionManager.RegionName="MainContentRegion" />
</LayoutDocument>
</LayoutDocumentPane>
</LayoutPanel>
</LayoutPanel>
</LayoutRoot>
</DockingManager>
<!--底部消息-->
<!--<hc:RunningBlock AutoReverse="False" Grid.Row="2" Height="50" Content="{Binding PromptContent,Mode=TwoWay}" FontSize="18" FontWeight="Bold" Foreground="OrangeRed" Duration="0:0:20" VerticalAlignment="Center"/>-->
</Grid>
</Window>

View File

@@ -0,0 +1,76 @@
using AvalonDock.Layout;
using AvalonDock.Themes;
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Communication.Interface;
using Cowain.Bake.Model;
using System.Collections.Generic;
using System.Threading;
using System.Windows;
using Unity;
namespace Cowain.Bake.Main.Views
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public static LayoutDocument mainShowWindow; //为了设置Title直接Binding无效
IUnityContainer _unityContainer = null;
List<Theme> _theme = new List<Theme>();
//public static MainWindowViewModel mainWindowModel = null;
public MainWindow(IUnityContainer unityContainer)
{
InitializeComponent();
_unityContainer = unityContainer;
mainShowWindow = showWindow;
_theme.Add(new MetroTheme()); //GenericTheme
_theme.Add(new AeroTheme());
_theme.Add(new Vs2013BlueTheme());
_theme.Add(new Vs2013DarkTheme());
_theme.Add(new Vs2013LightTheme());
_theme.Add(new ExpressionDarkTheme());
}
public void ChangeSkin(int i)
{
dockingManager.Theme = _theme[i]; //MetroTheme
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
}
void CloseAllHandle()
{
System.Collections.Generic.List<TDeviceConfig> plcList = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.PLC);
foreach (var item in plcList)
{
IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(item.Name); //几个PLC就实例化几个
if (null != plc && plc.IsConnect)
{
plc.Close();
}
}
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// 执行窗体的 Closing 事件的逻辑
if (MessageBoxResult.OK == HandyControl.Controls.MessageBox.Ask("是否退出自动真空烘烤系统?", "退出"))
{
Global.AppExit = true;
CloseAllHandle();
//Thread.Sleep(3000);
//await Task.Delay(10000); async
e.Cancel = false;
}
else
{
e.Cancel = true;
}
}
}
}

View File

@@ -0,0 +1,17 @@
<Window x:Class="Cowain.Bake.Main.Views.ManualTask"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Cowain.Bake.Main.Views"
mc:Ignorable="d"
Title="手动任务" Height="300" Width="380" WindowStartupLocation="CenterScreen">
<Grid>
<Label Content="取:" Style="{StaticResource BaseStyle}" HorizontalContentAlignment="Right" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="40,60,0,0" Width="30"/>
<Label Content="放:" Style="{StaticResource BaseStyle}" HorizontalContentAlignment="Right" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="40,136,0,0" Width="30"/>
<TextBox FontWeight="Bold" Foreground="Black" IsReadOnly="True" Text="{Binding SelectFromValue,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="75,60,0,0" VerticalAlignment="Top" Width="215"/>
<ComboBox ItemsSource="{Binding StationDtl}" SelectedValue="{Binding SelectToValue,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="80,131,0,0" VerticalAlignment="Top" Width="210"/>
<Button Content="生成任务" Command="{Binding GenerateTaskCommand}" Style="{StaticResource ButtonInfo}" HorizontalAlignment="Left" Height="35" Margin="80,195,0,0" VerticalAlignment="Top" Width="210"/>
</Grid>
</Window>

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Unity;
namespace Cowain.Bake.Main.Views
{
/// <summary>
/// ManualTask.xaml 的交互逻辑
/// </summary>
public partial class ManualTask : Window
{
ViewModels.ManualTaskViewModel manualTaskViewModel = null;
//private IUnityContainer _unityContainer;
public ManualTask(string fromStation, IUnityContainer unityContainer)
{
InitializeComponent();
//_unityContainer = unityContainer;
manualTaskViewModel = new ViewModels.ManualTaskViewModel(unityContainer);
manualTaskViewModel.GetStationDtl();
manualTaskViewModel.SelectFromValue = fromStation;
this.DataContext = manualTaskViewModel;
}
}
}

View File

@@ -0,0 +1,119 @@
<Window x:Class="Cowain.Bake.Main.Views.MoistureValueView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:prism="http://prismlibrary.com/"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
prism:ViewModelLocator.AutoWireViewModel="True"
Height="220" Width="420" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="70"/>
<RowDefinition Height="60"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DockPanel Grid.Row="0" Grid.Column="0">
<Label Content="正极水分:"
Foreground="Black"
FontWeight="Bold"
Style="{DynamicResource BaseStyle}"
Margin="0,25,0,0"
Width="65" />
<TextBox
Text="{Binding AnodeWaterJudge}"
FontWeight="Bold" Height="30"
TextWrapping="Wrap"
Width="65" />
</DockPanel>
<DockPanel Grid.Row="0" Grid.Column="1">
<Label
Content="负极水分:"
Foreground="Black"
FontWeight="Bold"
Style="{DynamicResource BaseStyle}"
Margin="0,25,0,0"
Width="65" />
<TextBox
Text="{Binding CathodeWaterJudge}"
FontWeight="Bold"
TextWrapping="Wrap"
VerticalAlignment="Center"
Width="65"/>
</DockPanel>
<DockPanel Grid.Row="0" Grid.Column="2">
<Label
Content="隔膜水分:"
Foreground="Black"
FontWeight="Bold"
Style="{DynamicResource BaseStyle}"
Margin="0,25,0,0"
Width="65" />
<TextBox
Text="{Binding SeptumWaterJudge}"
FontWeight="Bold"
TextWrapping="Wrap"
VerticalAlignment="Center"
Width="65" />
</DockPanel>
<DockPanel Grid.Row="1" Grid.Column="0" Visibility="Hidden">
<Label Content="正极水分2:"
Foreground="Black"
FontWeight="Bold"
Style="{DynamicResource BaseStyle}"
Margin="0,25,0,0"
Width="65" />
<TextBox
Text="{Binding AnodeWaterJudge2}"
FontWeight="Bold" Height="30"
TextWrapping="Wrap"
Width="65" />
</DockPanel>
<DockPanel Grid.Row="1" Grid.Column="1" Visibility="Hidden">
<Label
Content="负极水分2:"
Foreground="Black"
FontWeight="Bold"
Style="{DynamicResource BaseStyle}"
Margin="0,25,0,0"
Width="65" />
<TextBox
Text="{Binding CathodeWaterJudge2}"
FontWeight="Bold"
TextWrapping="Wrap"
VerticalAlignment="Center"
Width="65"/>
</DockPanel>
<DockPanel Grid.Row="1" Grid.Column="2" Visibility="Hidden">
<Label
Content="隔膜水分2:"
Foreground="Black"
FontWeight="Bold"
Style="{DynamicResource BaseStyle}"
Margin="0,25,0,0"
Width="65" />
<TextBox
Text="{Binding SeptumWaterJudge2}"
FontWeight="Bold"
TextWrapping="Wrap"
VerticalAlignment="Center"
Width="65" />
</DockPanel>
<StackPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal">
<Button Content="判定" x:Name="judge" Background="DeepSkyBlue" Command="{Binding Judge}" Margin="20,0,0,0" Width="90" />
<!--<Button Content="退出" x:Name="Close" Background="DeepSkyBlue" Command="{Binding CloseCommand}" Margin="30,0,0,0" Width="90" />-->
</StackPanel>
</Grid>
</Window>

View File

@@ -0,0 +1,35 @@
using Cowain.Bake.Main.ViewModels;
using Opc.Ua;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Unity;
namespace Cowain.Bake.Main.Views
{
/// <summary>
/// MoistureValue.xaml 的交互逻辑
/// </summary>
public partial class MoistureValueView : Window
{
ViewModels.MoistureValueViewMode viewModel = null;
public MoistureValueView(IUnityContainer unityContainer, CavityDtlViewModel station)
{
InitializeComponent();
viewModel = new ViewModels.MoistureValueViewMode(unityContainer);
//viewModel.WaterValueModel = WaterValueModel;
viewModel.thatParent = station;
this.DataContext = viewModel;
}
}
}

View File

@@ -0,0 +1,124 @@
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:prism="http://prismlibrary.com/"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:hc="https://handyorg.github.io/handycontrol"
x:Class="Cowain.Bake.Main.Views.PalletIdInputWindow"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
Background="#5f94c3"
Title="{Binding Title}" Height="170" Width="380">
<Window.Resources>
<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Style.BasedOn>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="{DynamicResource RegionBrush}"/>
<Setter Property="hc:BorderElement.CornerRadius" Value="4"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<hc:SimplePanel>
<Border Background="{TemplateBinding Background}" CornerRadius="{Binding (hc:BorderElement.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}"/>
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{Binding (hc:BorderElement.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}">
<StackPanel HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Orientation="Horizontal" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Path x:Name="PathMain" Data="{TemplateBinding hc:IconElement.Geometry}" Fill="{TemplateBinding Foreground}" Height="{TemplateBinding hc:IconElement.Height}" Stretch="Uniform" SnapsToDevicePixels="True" Width="{TemplateBinding hc:IconElement.Width}"/>
<ContentPresenter x:Name="ContentPresenterMain" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Margin="6,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
</StackPanel>
</Border>
</hc:SimplePanel>
<ControlTemplate.Triggers>
<Trigger Property="Content" Value="{x:Null}">
<Setter Property="Visibility" TargetName="ContentPresenterMain" Value="Collapsed"/>
</Trigger>
<Trigger Property="hc:IconElement.Geometry" Value="{x:Null}">
<Setter Property="Visibility" TargetName="PathMain" Value="Collapsed"/>
<Setter Property="Margin" TargetName="ContentPresenterMain" Value="0"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#5f62c3"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.BasedOn>
<Style TargetType="{x:Type ButtonBase}">
<Setter Property="Height" Value="30"/>
<Setter Property="BorderBrush" Value="{DynamicResource BorderBrush}"/>
<Setter Property="Padding" Value="10,6"/>
<Setter Property="Foreground" Value="{DynamicResource TextIconBrush}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Style.BasedOn>
<Style TargetType="{x:Type Control}">
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="FocusVisualStyle">
<Setter.Value>
<Style>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle RadiusY="4" RadiusX="4">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Margin" Value="-2"/>
<Setter Property="Opacity" Value="0.6"/>
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="Stroke" Value="{DynamicResource SecondaryBorderBrush}"/>
<Setter Property="StrokeThickness" Value="2"/>
<Setter Property="StrokeDashArray" Value="1 1"/>
</Style>
</Rectangle.Style>
</Rectangle>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
</Style.BasedOn>
</Style>
</Style.BasedOn>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.9"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Opacity" Value="0.6"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.4"/>
</Trigger>
</Style.Triggers>
</Style>
</Style.BasedOn>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource SecondaryRegionBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{DynamicResource BorderBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<StackPanel Orientation="Vertical">
<DockPanel HorizontalAlignment="Center" Margin="3,20,0,20">
<Label DockPanel.Dock="Left" Background="#5f94c3" BorderThickness="0" FontSize="15" Content="{Binding MsgContent}" Margin="0,0,0,0"/>
<Button DockPanel.Dock="Right" Click="Button_Click" Width=" 50" Height="29" Foreground="White" Background="#6e9bc5" Margin="20,0,0,0" Content="确定" Style="{DynamicResource ButtonStyle1}" BorderThickness="0" />
</DockPanel>
<TextBox x:Name="InputBox" Width="300" Height="30" Margin="0,0,0,10"/>
</StackPanel>
</Grid>
</Window>

View File

@@ -0,0 +1,51 @@
using Cowain.Bake.Main.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace Cowain.Bake.Main.Views
{
/// <summary>
/// PalletIdInputWindow.xaml 的交互逻辑
/// </summary>
public partial class PalletIdInputWindow : Window
{
public string _btnMsg = "";
public string PalletId { get; set; }
public PalletIdInputWindow(string title, string msg, string btnMsg)
{
InitializeComponent();
PalletIdInputWindowViewModel vm = this.DataContext as PalletIdInputWindowViewModel;
vm.Title = title; //;
vm.MsgContent = msg; // ;
_btnMsg = btnMsg;
}
public string ConfirmPalletId()
{
return PalletId;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBoxResult result = HandyControl.Controls.MessageBox.Show(_btnMsg, "确认", MessageBoxButton.YesNo,MessageBoxImage.Information);
if (result == MessageBoxResult.Yes)
{
PalletId = InputBox.Text;
this.Close();
}
}
}
}

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
</configSections>
<entityFramework>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer"/>
</providers>
</entityFramework>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup></configuration>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Text.Encoding.CodePages" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /></startup></configuration>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" throwExceptions="true">
<targets xsi:type="AsyncWrapper">
<!--保存至文件-->
<target name="log_file" xsi:type="File"
archiveFileName="../Logs/Archive/${shortdate} ${level:uppercase=false:padding=-5}.log"
maxArchiveFiles="30"
archiveEvery="Day"
fileName="../Logs/${level:uppercase=false:padding=-5}.log"
layout="${longdate} | ${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}" />
<!--输出至Debugger-->
<target name="debugger" xsi:type="Debugger"
layout="NLog: ${date:format=HH\:mm\:ss} | ${message}" />
<!--输出至控制台-->
<target name="console" xsi:type="ColoredConsole" layout="${longdate} ${message} ${exception:format=tostring}"></target>
<!--输出至邮件-->
<target xsi:type="File"
name="hourlyFile"
fileName="../Logs/EqptAlive/${date:format=yyyyMMdd}/${date:format=HH}.log"
layout="${date:format=yyyy-MM-dd HH\:mm\:ss}${message}"
createDirs="true" />
<!-- Define a fallback target if logging fails -->
</targets>
<rules>
<logger name="*" levels="Debug" writeTo="log_file" />
<logger name="*" level="Fatal" writeTo="log_file" />
<logger name="*" level="Warn" writeTo="log_file" />
<logger name="*" level="Error" writeTo="log_file" />
<logger name="*" level="Info" writeTo="log_file" />
<logger name="*" level="Trace" writeTo="hourlyFile" />
</rules>
</nlog>

View File

@@ -0,0 +1,20 @@
v1.0.0.2 (2026-02-01)
- 新增:露点温度
- 作者: 刘少明
v1.0.0.3 (2026-02-02)
- 修复:手动手成任务,快速响应
- 作者: 刘少明
v1.0.0.4 (2026-02-03)
- 修复:报警记录显示工站名称
- 作者: 刘少明
v1.0.0.5 (2026-02-04)
- 新增:预计结束烘烤时间
- 作者: 刘少明
v1.0.0.6 (2026-02-05)
- 修复:数据连接异常,取消登入时密码加密功能!
- 作者: 刘少明

View File

@@ -0,0 +1,17 @@
[Main]
PassWord=dy123
DispatchMode=Manual
ProductionLineName=得壹二期全自动真空烘烤L7-1线
WaterPallet=0
CountCmd=5
SkinType=0
AutoUpdate=false
AutoUpdateUrl=https://wwww.163.com
StoveLayers=17
PalletRows=48
PalletCols=2
# 0:正向, 1:反向
StoveDispDirection = 0
# 0:不反序1反序
IsReverseOrder = 1

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More