diff --git a/BPASmartClient.DosingSystem/App.xaml b/BPASmartClient.DosingSystem/App.xaml
new file mode 100644
index 00000000..b4732c63
--- /dev/null
+++ b/BPASmartClient.DosingSystem/App.xaml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BPASmartClient.DosingSystem/App.xaml.cs b/BPASmartClient.DosingSystem/App.xaml.cs
new file mode 100644
index 00000000..e590be97
--- /dev/null
+++ b/BPASmartClient.DosingSystem/App.xaml.cs
@@ -0,0 +1,188 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+using BPASmartClient.CustomResource.Pages.Enums;
+using BPASmartClient.CustomResource.Pages.Model;
+using BPASmartClient.CustomResource.Pages.View;
+using BPASmartClient.DosingSystem.Model;
+using BPASmartClient.DosingSystem.View;
+using BPASmartClient.Helper;
+
+namespace BPASmartClient.DosingSystem
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ protected override void OnStartup(StartupEventArgs e)
+ {
+ base.OnStartup(e);
+ MenuInit();
+ DataInit();
+
+ MainView mv = new MainView();
+ LoginView lv = new LoginView();
+ var res = lv.ShowDialog();
+ if (res != null && res == true)
+ mv.Show();
+ else
+ mv.Close();
+
+
+
+ //MainWindow mw = new MainWindow();
+ //LoginView lv = new LoginView();
+ //var res = lv.ShowDialog();
+ //if (res != null && res == true)
+ // mw.Show();
+ //else
+ // mw.Close();
+ }
+
+ protected override void OnExit(ExitEventArgs e)
+ {
+ base.OnExit(e);
+ Json.Save();
+ MessageLog.GetInstance.LogSave();
+ }
+
+ private void MenuInit()
+ {
+
+ #region 配方管理菜单
+ ObservableCollection RecipeManage = new ObservableCollection();
+ RecipeManage.Add(new SubMenumodel()
+ {
+ SubMenuName = "配方管理",
+ SubMenuPermission = new Permission[] { Permission.管理员 },
+ AssemblyName = "BPASmartClient.DosingSystem",
+ ToggleWindowPath = "View.RecipeSettingsView"
+ });
+
+ RecipeManage.Add(new SubMenumodel()
+ {
+ SubMenuName = "配方下发",
+ SubMenuPermission = new Permission[] { Permission.操作员 },
+ AssemblyName = "BPASmartClient.DosingSystem",
+ ToggleWindowPath = "View.RecipeControlView"
+ });
+
+ MenuManage.GetInstance.menuModels.Add(new MenuModel()
+ {
+ MainMenuIcon = "",
+ MainMenuName = "配方管理",
+ Alias = "Recipe Management",
+ MainMenuPermission = new Permission[] { Permission.管理员, Permission.操作员 },
+ subMenumodels = RecipeManage,
+ });
+ #endregion
+
+ #region 消息日志
+ ObservableCollection InfoLog = new ObservableCollection();
+ InfoLog.Add(new SubMenumodel()
+ {
+ SubMenuName = "操作日志",
+ SubMenuPermission = new Permission[] { Permission.操作员, Permission.管理员, Permission.技术员 },
+ AssemblyName = "BPASmartClient.CustomResource",
+ ToggleWindowPath = "Pages.View.UserLogView"
+ });
+
+ InfoLog.Add(new SubMenumodel()
+ {
+ SubMenuName = "运行日志",
+ SubMenuPermission = new Permission[] { Permission.操作员, Permission.管理员, Permission.技术员 },
+ AssemblyName = "BPASmartClient.CustomResource",
+ ToggleWindowPath = "Pages.View.RunLogView"
+ });
+
+ InfoLog.Add(new SubMenumodel()
+ {
+ SubMenuName = "报警记录",
+ SubMenuPermission = new Permission[] { Permission.操作员, Permission.管理员, Permission.技术员 },
+ AssemblyName = "BPASmartClient.CustomResource",
+ ToggleWindowPath = "Pages.View.AlarmView"
+ });
+
+ MenuManage.GetInstance.menuModels.Add(new MenuModel()
+ {
+ MainMenuIcon = "",
+ MainMenuName = "消息日志",
+ Alias = "Message Log",
+ MainMenuPermission = new Permission[] { Permission.管理员, Permission.操作员, Permission.技术员 },
+ subMenumodels = InfoLog,
+ });
+ #endregion
+
+ #region 硬件设备监控
+ ObservableCollection DeviceMonitor = new ObservableCollection();
+ DeviceMonitor.Add(new SubMenumodel()
+ {
+ SubMenuName = "原料设备列表",
+ SubMenuPermission = new Permission[] { Permission.管理员, Permission.操作员, Permission.技术员 },
+ AssemblyName = "BPASmartClient.DosingSystem",
+ ToggleWindowPath = "View.DeviceListView"
+ });
+
+ DeviceMonitor.Add(new SubMenumodel()
+ {
+ SubMenuName = "设备状态",
+ SubMenuPermission = new Permission[] { Permission.管理员, Permission.操作员, Permission.技术员 },
+ AssemblyName = "BPASmartClient.DosingSystem",
+ ToggleWindowPath = "View.HardwareStatusView"
+ });
+
+
+ MenuManage.GetInstance.menuModels.Add(new MenuModel()
+ {
+ MainMenuIcon = "",
+ MainMenuName = "设备监控",
+ Alias = "Device Monitor",
+ MainMenuPermission = new Permission[] { Permission.管理员, Permission.操作员, Permission.技术员 },
+ subMenumodels = DeviceMonitor,
+ });
+ #endregion
+
+ #region 用户管理
+ ObservableCollection UserManager = new ObservableCollection();
+ UserManager.Add(new SubMenumodel()
+ {
+ SubMenuName = "用户登录",
+ SubMenuPermission = new Permission[] { Permission.管理员, Permission.操作员, Permission.技术员 },
+ AssemblyName = "BPASmartClient.CustomResource",
+ ToggleWindowPath = "Pages.View.LoginView"
+ });
+
+ UserManager.Add(new SubMenumodel()
+ {
+ SubMenuName = "密码修改",
+ SubMenuPermission = new Permission[] { Permission.管理员, Permission.操作员, Permission.技术员 },
+ AssemblyName = "BPASmartClient.CustomResource",
+ ToggleWindowPath = "Pages.View.PasswordChangeView"
+ });
+
+
+ MenuManage.GetInstance.menuModels.Add(new MenuModel()
+ {
+ MainMenuIcon = "",
+ MainMenuName = "用户管理",
+ Alias = "User Management",
+ MainMenuPermission = new Permission[] { Permission.管理员, Permission.操作员, Permission.技术员 },
+ subMenumodels = UserManager,
+ });
+ #endregion
+ }
+
+ private void DataInit()
+ {
+ Config.GetInstance.Init();
+ Json.Read();
+ }
+
+ }
+}
diff --git a/BPASmartClient.DosingSystem/AssemblyInfo.cs b/BPASmartClient.DosingSystem/AssemblyInfo.cs
new file mode 100644
index 00000000..8b5504ec
--- /dev/null
+++ b/BPASmartClient.DosingSystem/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/BPASmartClient.DosingSystem/BPASmartClient.DosingSystem.csproj b/BPASmartClient.DosingSystem/BPASmartClient.DosingSystem.csproj
new file mode 100644
index 00000000..37d3b321
--- /dev/null
+++ b/BPASmartClient.DosingSystem/BPASmartClient.DosingSystem.csproj
@@ -0,0 +1,28 @@
+
+
+
+ WinExe
+ net6.0-windows
+ enable
+ true
+ app.manifest
+ hbl.ico
+ AnyCPU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BPASmartClient.DosingSystem/Model/ActionMenu.cs b/BPASmartClient.DosingSystem/Model/ActionMenu.cs
new file mode 100644
index 00000000..00113337
--- /dev/null
+++ b/BPASmartClient.DosingSystem/Model/ActionMenu.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+using Microsoft.Toolkit.Mvvm.Input;
+
+namespace BPASmartClient.DosingSystem.Model
+{
+ public class ActionMenu : ObservableObject
+ {
+ public string CommandParameter { get { return _mCommandParameter; } set { _mCommandParameter = value; OnPropertyChanged(); } }
+ private string _mCommandParameter;
+
+ //public Permission[] permission { get { return _mpermission; } set { _mpermission = value; OnPropertyChanged(); } }
+ //private Permission[] _mpermission;
+
+ public string MenuName { get { return _mMenuName; } set { _mMenuName = value; OnPropertyChanged(); } }
+ private string _mMenuName;
+
+
+ //public string NameSpace { get { return _mNameSpace; } set { _mNameSpace = value; OnPropertyChanged(); } }
+ //private string _mNameSpace;
+
+
+ }
+}
diff --git a/BPASmartClient.DosingSystem/Model/DeviceAddress.cs b/BPASmartClient.DosingSystem/Model/DeviceAddress.cs
new file mode 100644
index 00000000..7c57aaa8
--- /dev/null
+++ b/BPASmartClient.DosingSystem/Model/DeviceAddress.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BPASmartClient.DosingSystem.Model
+{
+ public class DeviceAddress
+ {
+ ///
+ /// 设备名称起始地址
+ ///
+ public static string DeviceName { get; set; } = "LW0";
+
+ ///
+ /// 料仓重量反馈起始地址
+ ///
+ public static string WeightFeedback { get; set; } = "LW204";
+
+ ///
+ /// 重量设置地址
+ ///
+ public static string WeightSet { get; set; } = "LW200";
+
+ ///
+ /// 启动信号地址
+ ///
+ public static string Start { get; set; } = "LW210";
+
+ ///
+ /// 下料重量反馈地址
+ ///
+ public static string CutWeightFeedback { get; set; } = "LW202";
+
+ ///
+ /// 设备运行状态地址
+ ///
+ public static string RunStatus { get; set; } = "LW206";
+ }
+
+
+
+}
diff --git a/BPASmartClient.DosingSystem/Model/DeviceInquire.cs b/BPASmartClient.DosingSystem/Model/DeviceInquire.cs
new file mode 100644
index 00000000..181abeda
--- /dev/null
+++ b/BPASmartClient.DosingSystem/Model/DeviceInquire.cs
@@ -0,0 +1,221 @@
+using BPASmartClient.Helper;
+using BPASmartClient.Message;
+using BPASmartClient.Modbus;
+using BPASmartClient.DosingSystem.ViewModel;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Net.NetworkInformation;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace BPASmartClient.DosingSystem.Model
+{
+ public class DeviceInquire
+ {
+ private volatile static DeviceInquire _Instance;
+ public static DeviceInquire GetInstance => _Instance ?? (_Instance = new DeviceInquire());
+ private DeviceInquire() { }
+
+ string IPSegment = "192.168.0.";
+
+ ConcurrentDictionary DeviceLists = new ConcurrentDictionary();
+ List InvalidIP = new List();//无效 IP 集合
+ List IPLists = new List();//启动 Ping 任务IP集合
+ ConcurrentQueue IPQueues = new ConcurrentQueue();//pincomplete 完成队列
+
+ public void Init()
+ {
+ IpAddressLines();
+ ThreadManage.GetInstance().StartLong(new Action(() =>
+ {
+ if (IPQueues.Count >= IPLists.Count)
+ IpAddressLines();
+ Thread.Sleep(5000);
+ }), "配料机设备上线监听", true);
+ }
+
+ public void Rescan()
+ {
+ InvalidIP.Clear();
+ }
+
+ public DeviceStatus GetDevice(string ip)
+ {
+ if (ip != null)
+ {
+ var res = DeviceLists.Values.FirstOrDefault(p => p.IpAddress == ip);
+ if (res != null) return res;
+ }
+ return new DeviceStatus();
+ }
+
+ private void IpAddressLines()
+ {
+ IPLists.Clear();
+ IPQueues.Clear();
+ for (int i = 1; i <= 255; i++)
+ {
+ if (!InvalidIP.Contains($"{IPSegment}{i}") && !DeviceLists.ContainsKey($"{IPSegment}{i}"))
+ {
+ IPLists.Add($"{IPSegment}{i}");
+ }
+ }
+
+ IPLists.ForEach((item) =>
+ {
+ Ping myPing = new Ping();
+ myPing.PingCompleted += new PingCompletedEventHandler(_myPing_PingCompleted);
+ myPing.SendAsync(item, 1000, null);
+ });
+ }
+
+ private void _myPing_PingCompleted(object sender, PingCompletedEventArgs e)
+ {
+ if (e.Reply.Status == IPStatus.Success)
+ {
+ string ip = e.Reply.Address.ToString();
+ if (!DeviceLists.ContainsKey(ip))
+ {
+ DeviceStatus DS = new DeviceStatus();
+ DS.modbusTcp.IsReconnect = false;
+
+ DS.modbusTcp.ConnectOk = new Action(() =>
+ {
+ string DeviceName = DS.modbusTcp.GetString(DeviceAddress.DeviceName, 20);
+ if (DeviceName.Length > 0)
+ {
+ DeviceLists.TryAdd(ip, DS);
+ DeviceLists[ip].Init(DeviceName);
+ DeviceLists[ip].modbusTcp.IsReconnect = false;
+ App.Current.Dispatcher.Invoke(new Action(() =>
+ {
+ DeviceListViewModel.devices.Add(new Devices()
+ {
+ DeviceName = DeviceName,
+ IpAddress = ip
+ });
+
+ for (int i = 0; i < Json.Data.Recipes.Count; i++)
+ {
+ for (int m = 0; m < Json.Data.Recipes.ElementAt(i).RawMaterials.Count; m++)
+ {
+ if (Json.Data.Recipes.ElementAt(i).RawMaterials.ElementAt(m).DeviceIp == ip)
+ {
+ Json.Data.Recipes.ElementAt(i).RawMaterials.ElementAt(m).RawMaterialName = DeviceName;
+ }
+ }
+ }
+
+ if (!NewRecipeViewModel.RawMaterialNames.Contains(DeviceName))
+ NewRecipeViewModel.RawMaterialNames.Add(DeviceName);
+
+ }));
+ }
+ else
+ {
+ if (!InvalidIP.Contains(ip)) InvalidIP.Add(ip);
+ }
+ });
+
+ DS.modbusTcp.ConnectFail = new Action(() =>
+ {
+ if (!InvalidIP.Contains(ip)) InvalidIP.Add(ip);
+ MessageLog.GetInstance.Show($"{ip}连接失败");
+ });
+
+ DS.modbusTcp.Disconnect = new Action(() =>
+ {
+ if (InvalidIP.Contains(ip)) InvalidIP.Remove(ip);
+ var res = DeviceListViewModel.devices.FirstOrDefault(P => P.IpAddress == ip);
+ if (res != null && DeviceListViewModel.devices.Contains(res))
+ App.Current.Dispatcher.Invoke(new Action(() =>
+ {
+ DeviceListViewModel.devices.Remove(res);
+ if (!NewRecipeViewModel.RawMaterialNames.Contains(res.DeviceName))
+ NewRecipeViewModel.RawMaterialNames.Remove(res.DeviceName);
+ }));
+ if (DeviceLists.ContainsKey(ip)) DeviceLists[ip].Dispose();
+ });
+
+ Task.Run(new Action(() =>
+ {
+ DS.modbusTcp.ModbusTcpConnect(ip, 502);
+ IPQueues.Enqueue(e.Reply.Address.ToString());
+ }));
+ }
+ else IPQueues.Enqueue(e.Reply.Address.ToString());
+ }
+ else IPQueues.Enqueue(e.Reply.Address.ToString());
+ }
+ }
+
+ public class DeviceStatus
+ {
+
+ #region 对象属性声明
+ public string DeviceName = String.Empty;
+ public string IpAddress => modbusTcp.IPAdress;
+
+ ///
+ /// 设备状态
+ ///
+ public RawMaterialDeviceStatus deviceStatus { get; set; } = new RawMaterialDeviceStatus();
+
+ public ModbusTcp modbusTcp = new ModbusTcp();
+
+ public bool IsConnected => modbusTcp.Connected;
+ #endregion
+
+ public void Init(string DeviceName)
+ {
+ this.DeviceName = DeviceName;
+ if (modbusTcp.Connected)
+ {
+ ThreadManage.GetInstance().StartLong(new Action(() =>
+ {
+ //获取设备运行状态
+ var res = this.modbusTcp.Read(DeviceAddress.RunStatus);
+ if (res != null && res is ushort[] ushortValue)
+ {
+ if (ushortValue.Length >= 1) deviceStatus.RunStatus = ushortValue[0];
+ }
+
+ //获取设备料仓剩余重量
+ deviceStatus.WeightFeedback = this.modbusTcp.GetUint(DeviceAddress.WeightFeedback) * 10;
+
+ Thread.Sleep(100);
+ }), $"{DeviceName} 开始监听", true);
+ }
+ }
+
+ public void SetDeviceName(string name)
+ {
+ this.modbusTcp.Write(DeviceAddress.DeviceName, new ushort[20]);
+ this.modbusTcp.SetString(DeviceAddress.DeviceName, name);
+ }
+
+ public void StatusReset()
+ {
+ this.modbusTcp.Write(DeviceAddress.RunStatus, (ushort)0);
+ }
+
+ public void Dispose()
+ {
+ ThreadManage.GetInstance().StopTask($"{DeviceName} 开始监听");
+ }
+
+ public void Start(uint Value)
+ {
+ if (modbusTcp.Connected)
+ {
+ modbusTcp.SetUint(DeviceAddress.WeightSet, Value);//写入配方量
+ modbusTcp.Write(DeviceAddress.Start, (ushort)1);//设备启动写入
+ }
+ }
+ }
+
+}
diff --git a/BPASmartClient.DosingSystem/Model/LocaPar.cs b/BPASmartClient.DosingSystem/Model/LocaPar.cs
new file mode 100644
index 00000000..31815e0c
--- /dev/null
+++ b/BPASmartClient.DosingSystem/Model/LocaPar.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Collections.ObjectModel;
+using BPASmartClient.DosingSystem.ViewModel;
+
+namespace BPASmartClient.DosingSystem.Model
+{
+ public class LocaPar
+ {
+ public ObservableCollection Recipes { get; set; } = new ObservableCollection();
+ }
+}
diff --git a/BPASmartClient.DosingSystem/Model/RawMaterialDeviceStatus.cs b/BPASmartClient.DosingSystem/Model/RawMaterialDeviceStatus.cs
new file mode 100644
index 00000000..1febc8a9
--- /dev/null
+++ b/BPASmartClient.DosingSystem/Model/RawMaterialDeviceStatus.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BPASmartClient.DosingSystem.Model
+{
+ public class RawMaterialDeviceStatus
+ {
+
+ ///
+ /// 原料类型
+ /// 1:液体
+ /// 2:膏体
+ /// 3:粉体
+ ///
+ public ushort RawMaterialType { get; set; }
+
+ ///
+ /// 料仓重量反馈
+ ///
+ public float WeightFeedback { get; set; }
+
+ ///
+ /// 上限反馈
+ ///
+ public bool UpLimitFeedback { get; set; }
+
+ ///
+ /// 下限反馈
+ ///
+ public bool DownLimitFeedback { get; set; }
+
+ ///
+ /// 下料重量反馈
+ ///
+ public float CutWeightFeedback { get; set; }
+
+ ///
+ /// 设备运行状态
+ ///
+ public ushort RunStatus { get; set; }
+ }
+}
diff --git a/BPASmartClient.DosingSystem/Model/RawMaterialModel.cs b/BPASmartClient.DosingSystem/Model/RawMaterialModel.cs
new file mode 100644
index 00000000..7b5f3eb5
--- /dev/null
+++ b/BPASmartClient.DosingSystem/Model/RawMaterialModel.cs
@@ -0,0 +1,88 @@
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BPASmartClient.DosingSystem.Model
+{
+ ///
+ /// 原料模块
+ ///
+ public class RawMaterialModel : ObservableObject
+ {
+ ///
+ /// 原料名称
+ ///
+ public string RawMaterialName { get { return _mRawMaterialName; } set { _mRawMaterialName = value; OnPropertyChanged(); } }
+ private string _mRawMaterialName;
+
+ ///
+ /// 原料设备IP
+ ///
+ public string DeviceIp { get; set; }
+
+ ///
+ /// 原料重量设置
+ ///
+ public uint RawMaterialWeight { get { return _mRawMaterialWeight; } set { _mRawMaterialWeight = value; OnPropertyChanged(); } }
+ private uint _mRawMaterialWeight;
+
+ ///
+ /// 原料类型 MW18
+ /// 1:液体
+ /// 2:膏体
+ /// 3:粉体
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ public ushort RawMaterialType { get { return _mRawMaterialType; } set { _mRawMaterialType = value; OnPropertyChanged(); } }
+ private ushort _mRawMaterialType;
+
+ ///
+ /// 料仓重量反馈 MD40
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ public float WeightFeedback { get { return _mWeightFeedback; } set { _mWeightFeedback = value; OnPropertyChanged(); } }
+ private float _mWeightFeedback;
+
+ ///
+ /// 上限反馈
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ public bool UpLimtFeedback { get { return _mUpLimtFeedback; } set { _mUpLimtFeedback = value; OnPropertyChanged(); } }
+ private bool _mUpLimtFeedback;
+
+ ///
+ /// 下限反馈
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ public bool DownLimtFeedback { get { return _mDownLimtFeedback; } set { _mDownLimtFeedback = value; OnPropertyChanged(); } }
+ private bool _mDownLimtFeedback;
+
+ ///
+ /// 下料重量反馈 MD52
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ public float UpLimtWeightFeedback { get { return _mUpLimtWeightFeedback; } set { _mUpLimtWeightFeedback = value; OnPropertyChanged(); } }
+ private float _mUpLimtWeightFeedback;
+
+
+ ///
+ /// 原料ID
+ ///
+ public string RawMaterialId { get { return _mRawMaterialId; } set { _mRawMaterialId = value; OnPropertyChanged(); } }
+ private string _mRawMaterialId;
+
+ ///
+ /// 原料设备执行状态
+ /// 1:空闲状态
+ /// 2:下料中
+ /// 3:下料完成
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ public ushort RecipeStatus { get { return _mRecipeStatus; } set { _mRecipeStatus = value; OnPropertyChanged(); } }
+ private ushort _mRecipeStatus = 1;
+
+ }
+}
diff --git a/BPASmartClient.DosingSystem/Model/RecipeModel.cs b/BPASmartClient.DosingSystem/Model/RecipeModel.cs
new file mode 100644
index 00000000..203d4658
--- /dev/null
+++ b/BPASmartClient.DosingSystem/Model/RecipeModel.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using BPASmartClient.DosingSystem.ViewModel;
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+
+namespace BPASmartClient.DosingSystem.Model
+{
+ ///
+ /// 配方模块
+ ///
+ public class RecipeModel : ObservableObject
+ {
+ [Newtonsoft.Json.JsonIgnore]
+ public bool IsEnable { get { return _mIsEnable; } set { _mIsEnable = value; OnPropertyChanged(); } }
+ private bool _mIsEnable = true;
+
+ ///
+ /// 序号
+ ///
+ public int SerialNum { get { return _mSerialNum; } set { _mSerialNum = value; OnPropertyChanged(); } }
+ private int _mSerialNum;
+
+ ///
+ /// 配方名称
+ ///
+ public string RecipeName { get { return _mRecipeName; } set { _mRecipeName = value; OnPropertyChanged(); } }
+ private string _mRecipeName;
+
+ ///
+ /// 配方编码
+ ///
+ public string RecipCode { get { return _mRecipCode; } set { _mRecipCode = value; OnPropertyChanged(); } }
+ private string _mRecipCode;
+
+ [Newtonsoft.Json.JsonIgnore]
+ public AutoResetEvent Are { get; set; } = new AutoResetEvent(false);
+
+ ///
+ /// 原料集合
+ ///
+ public ObservableCollection RawMaterials { get; set; } = new ObservableCollection();
+
+
+
+ }
+}
diff --git a/BPASmartClient.DosingSystem/View/AlarmRecordView.xaml b/BPASmartClient.DosingSystem/View/AlarmRecordView.xaml
new file mode 100644
index 00000000..bfdfa310
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/AlarmRecordView.xaml
@@ -0,0 +1,380 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BPASmartClient.DosingSystem/View/AlarmRecordView.xaml.cs b/BPASmartClient.DosingSystem/View/AlarmRecordView.xaml.cs
new file mode 100644
index 00000000..d30b0210
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/AlarmRecordView.xaml.cs
@@ -0,0 +1,28 @@
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace BPASmartClient.DosingSystem.View
+{
+ ///
+ /// AlarmRecordView.xaml 的交互逻辑
+ ///
+ public partial class AlarmRecordView : UserControl
+ {
+ public AlarmRecordView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/BPASmartClient.DosingSystem/View/ChangeDeviceNameView.xaml b/BPASmartClient.DosingSystem/View/ChangeDeviceNameView.xaml
new file mode 100644
index 00000000..5538aa49
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/ChangeDeviceNameView.xaml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BPASmartClient.DosingSystem/View/ChangeDeviceNameView.xaml.cs b/BPASmartClient.DosingSystem/View/ChangeDeviceNameView.xaml.cs
new file mode 100644
index 00000000..d8ecd4ac
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/ChangeDeviceNameView.xaml.cs
@@ -0,0 +1,31 @@
+using BPASmartClient.Helper;
+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 BPASmartClient.DosingSystem.View
+{
+ ///
+ /// ChangeDeviceNameView.xaml 的交互逻辑
+ ///
+ public partial class ChangeDeviceNameView : Window
+ {
+ public ChangeDeviceNameView()
+ {
+ InitializeComponent();
+ ActionManage.GetInstance.CancelRegister("ChangeDeviceNameViewClose");
+ ActionManage.GetInstance.Register(new Action(() => { this.Close(); }), "ChangeDeviceNameViewClose");
+ this.br.MouseLeftButtonDown += (o, e) => { if (e.LeftButton == MouseButtonState.Pressed) this.DragMove(); };
+ }
+ }
+}
diff --git a/BPASmartClient.DosingSystem/View/DeviceListView.xaml b/BPASmartClient.DosingSystem/View/DeviceListView.xaml
new file mode 100644
index 00000000..f232d604
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/DeviceListView.xaml
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BPASmartClient.DosingSystem/View/DeviceListView.xaml.cs b/BPASmartClient.DosingSystem/View/DeviceListView.xaml.cs
new file mode 100644
index 00000000..16366e98
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/DeviceListView.xaml.cs
@@ -0,0 +1,28 @@
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace BPASmartClient.DosingSystem.View
+{
+ ///
+ /// DeviceListView.xaml 的交互逻辑
+ ///
+ public partial class DeviceListView : UserControl
+ {
+ public DeviceListView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/BPASmartClient.DosingSystem/View/HardwareStatusView.xaml b/BPASmartClient.DosingSystem/View/HardwareStatusView.xaml
new file mode 100644
index 00000000..347782e3
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/HardwareStatusView.xaml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/BPASmartClient.DosingSystem/View/HardwareStatusView.xaml.cs b/BPASmartClient.DosingSystem/View/HardwareStatusView.xaml.cs
new file mode 100644
index 00000000..c0faa0fd
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/HardwareStatusView.xaml.cs
@@ -0,0 +1,28 @@
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace BPASmartClient.DosingSystem.View
+{
+ ///
+ /// HardwareStatusView.xaml 的交互逻辑
+ ///
+ public partial class HardwareStatusView : UserControl
+ {
+ public HardwareStatusView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/BPASmartClient.DosingSystem/View/MainWindow.xaml b/BPASmartClient.DosingSystem/View/MainWindow.xaml
new file mode 100644
index 00000000..3db6b7a5
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/MainWindow.xaml
@@ -0,0 +1,251 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BPASmartClient.DosingSystem/View/MainWindow.xaml.cs b/BPASmartClient.DosingSystem/View/MainWindow.xaml.cs
new file mode 100644
index 00000000..93d7cf1e
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/MainWindow.xaml.cs
@@ -0,0 +1,48 @@
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace BPASmartClient.DosingSystem.View
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ InitializeComponent();
+ this.ButClose.Click += (o, e) => { this.Close(); };
+
+ this.MaxWidth = SystemParameters.WorkArea.Width;
+ this.MaxHeight = SystemParameters.WorkArea.Height;
+
+ this.br.MouseLeftButtonDown += (o, e) =>
+ {
+ if (e.ClickCount > 1)
+ {
+ if (this.WindowState == WindowState.Maximized)
+ this.WindowState = WindowState.Normal;
+ else if (this.WindowState == WindowState.Normal)
+ this.WindowState = WindowState.Maximized;
+ }
+ if (e.LeftButton == MouseButtonState.Pressed) this.DragMove();
+ };
+ }
+
+
+
+
+ }
+}
diff --git a/BPASmartClient.DosingSystem/View/NewRecipeView.xaml b/BPASmartClient.DosingSystem/View/NewRecipeView.xaml
new file mode 100644
index 00000000..c017cb65
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/NewRecipeView.xaml
@@ -0,0 +1,222 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BPASmartClient.DosingSystem/View/NewRecipeView.xaml.cs b/BPASmartClient.DosingSystem/View/NewRecipeView.xaml.cs
new file mode 100644
index 00000000..180cdbf7
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/NewRecipeView.xaml.cs
@@ -0,0 +1,32 @@
+using BPASmartClient.Helper;
+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 BPASmartClient.DosingSystem.View
+{
+ ///
+ /// NewRecipeView.xaml 的交互逻辑
+ ///
+ public partial class NewRecipeView : Window
+ {
+ public NewRecipeView()
+ {
+ InitializeComponent();
+ this.btClose.Click += (o, e) => { this.Close(); };
+ this.br.MouseLeftButtonDown += (o, e) => { if (e.LeftButton == MouseButtonState.Pressed) this.DragMove(); };
+ ActionManage.GetInstance.CancelRegister("CloseNewRecipeView");
+ ActionManage.GetInstance.Register(new Action(() => { this.Close(); }), "CloseNewRecipeView");
+ }
+ }
+}
diff --git a/BPASmartClient.DosingSystem/View/RecipeControlView.xaml b/BPASmartClient.DosingSystem/View/RecipeControlView.xaml
new file mode 100644
index 00000000..d705a4bc
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/RecipeControlView.xaml
@@ -0,0 +1,188 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BPASmartClient.DosingSystem/View/RecipeControlView.xaml.cs b/BPASmartClient.DosingSystem/View/RecipeControlView.xaml.cs
new file mode 100644
index 00000000..6e9330e3
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/RecipeControlView.xaml.cs
@@ -0,0 +1,28 @@
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace BPASmartClient.DosingSystem.View
+{
+ ///
+ /// RecipeControlView.xaml 的交互逻辑
+ ///
+ public partial class RecipeControlView : UserControl
+ {
+ public RecipeControlView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/BPASmartClient.DosingSystem/View/RecipeSettingsView.xaml b/BPASmartClient.DosingSystem/View/RecipeSettingsView.xaml
new file mode 100644
index 00000000..b1fcdd49
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/RecipeSettingsView.xaml
@@ -0,0 +1,246 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BPASmartClient.DosingSystem/View/RecipeSettingsView.xaml.cs b/BPASmartClient.DosingSystem/View/RecipeSettingsView.xaml.cs
new file mode 100644
index 00000000..3785ab57
--- /dev/null
+++ b/BPASmartClient.DosingSystem/View/RecipeSettingsView.xaml.cs
@@ -0,0 +1,28 @@
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace BPASmartClient.DosingSystem.View
+{
+ ///
+ /// RecipeSettingsView.xaml 的交互逻辑
+ ///
+ public partial class RecipeSettingsView : UserControl
+ {
+ public RecipeSettingsView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/BPASmartClient.DosingSystem/ViewModel/AlarmRecordViewModel.cs b/BPASmartClient.DosingSystem/ViewModel/AlarmRecordViewModel.cs
new file mode 100644
index 00000000..977c6ecf
--- /dev/null
+++ b/BPASmartClient.DosingSystem/ViewModel/AlarmRecordViewModel.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+using System.Collections.Concurrent;
+using System.Collections.ObjectModel;
+using System.Windows;
+using BPASmartClient.Helper;
+using Microsoft.Toolkit.Mvvm.Input;
+
+namespace BPASmartClient.DosingSystem.ViewModel
+{
+ public class AlarmRecordViewModel : ObservableObject
+ {
+ }
+}
diff --git a/BPASmartClient.DosingSystem/ViewModel/ChangeDeviceNameViewModel.cs b/BPASmartClient.DosingSystem/ViewModel/ChangeDeviceNameViewModel.cs
new file mode 100644
index 00000000..3344882e
--- /dev/null
+++ b/BPASmartClient.DosingSystem/ViewModel/ChangeDeviceNameViewModel.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using BPASmartClient.Helper;
+using BPASmartClient.DosingSystem.Model;
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+using Microsoft.Toolkit.Mvvm.Input;
+
+namespace BPASmartClient.DosingSystem.ViewModel
+{
+ public class ChangeDeviceNameViewModel : ObservableObject
+ {
+ public ChangeDeviceNameViewModel()
+ {
+ ActionManage.GetInstance.Register(new Action