@@ -0,0 +1,32 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace BPA.Model.Enums | |||
{ | |||
public enum BatchStep:int | |||
{ | |||
/// <summary> | |||
/// 等待配料 | |||
/// </summary> | |||
WaitBatch=0, | |||
/// <summary> | |||
/// 写入配料参数。 | |||
/// </summary> | |||
WriteBatchParam=100, | |||
/// <summary> | |||
/// 开始配料。 | |||
/// </summary> | |||
StartBatch=200, | |||
/// <summary> | |||
/// 等待配料完成。 | |||
/// </summary> | |||
WaitBatchComplete=300, | |||
/// <summary> | |||
/// 配料完成。 | |||
/// </summary> | |||
BatchCompleted=400 | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace BPA.Model.Enums | |||
{ | |||
public enum MoveConveyer:int | |||
{ | |||
WaitMove=0, | |||
Moveing=100, | |||
MoveComplete=200, | |||
} | |||
} |
@@ -4,11 +4,25 @@ using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using System.Collections.Concurrent; | |||
using BPA.Model.Recipe; | |||
using BPA.Model.Enums; | |||
namespace BPA.Model | |||
{ | |||
public class GlobalData | |||
public class GlobalData | |||
{ | |||
public static ConcurrentQueue<GoodsModel> GoodsModels { get; set; } = new ConcurrentQueue<GoodsModel>(); | |||
public ConcurrentQueue<GoodsModel> GoodsModels { get; set; } = new ConcurrentQueue<GoodsModel>(); | |||
/// <summary> | |||
/// 需要执行的配方队列。 | |||
/// </summary> | |||
public ConcurrentQueue<RecipeData> RecipeQueue { get; set; } = new(); | |||
#region 配料机 | |||
#endregion | |||
#region 传送带 | |||
public MoveConveyer MoveConveyerStep { get; set; } | |||
#endregion | |||
} | |||
} |
@@ -0,0 +1,47 @@ | |||
using BPA.Model.Enums; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace BPA.Model.Recipe | |||
{ | |||
/// <summary> | |||
/// 根据设备生成的配方数据。 | |||
/// </summary> | |||
public class RecipeData | |||
{ | |||
public string ID { get; set; } | |||
public string Name { get; set; } | |||
/// <summary> | |||
/// 该配方当前所在的工位。 | |||
/// </summary> | |||
public int CurrentStation { get; set; } | |||
/// <summary> | |||
/// 配方对应的各设备的下料数据,键为设备编号,值为设备下各个料仓的下料重量。 | |||
/// </summary> | |||
public Dictionary<int, ushort[]> MaterialData { get; set; } | |||
/// <summary> | |||
/// 各个设备是否下料完成。 | |||
/// </summary> | |||
public bool[] IsMakeComplete { get; set; } | |||
public Dictionary<int,BatchStep> BatchStatus { get; set; } | |||
public RecipeData(string id,string name, Dictionary<int, ushort[]> materialData,int stationCount=5) | |||
{ | |||
ID = id; | |||
Name = name; | |||
MaterialData = materialData; | |||
//取决于工位数量,本案例中,有五个工位,但是第三个工位没有设备。 | |||
IsMakeComplete = new bool[stationCount]; | |||
BatchStatus = new(); | |||
for (int i = 1; i <= stationCount; i++) | |||
{ | |||
BatchStatus.Add(i, BatchStep.WaitBatch); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,30 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace BPA.Model | |||
{ | |||
/// <summary> | |||
/// 配料线程服务类。 | |||
/// </summary> | |||
public class TaskServer | |||
{ | |||
public int ID { get; set; } | |||
/// <summary> | |||
/// 任务名称 | |||
/// </summary> | |||
public string TaskName { get; set; } | |||
/// <summary> | |||
/// 是否结束。 | |||
/// </summary> | |||
public bool IsCompleted { get; set; } | |||
public Task RunTask { get; set; } | |||
/// <summary> | |||
/// 任务取消标识 | |||
/// </summary> | |||
public CancellationTokenSource Cts { get; set; } = new CancellationTokenSource(); | |||
} | |||
} |
@@ -43,7 +43,17 @@ namespace BPA.SingleDevice | |||
base.OnStartup(e); | |||
SqlHelper.GetInstance.Init(); | |||
MainControl.GetInstance.Start(); | |||
//MainControl.GetInstance.Start(); | |||
#region 注册调试日志。 | |||
ILogService logService = App.Current.Services.GetService<ILogService>(); | |||
MessageLog.GetInstance.NotifyShow = (string str) => | |||
{ | |||
logService.LogDebugInfo(str); | |||
}; | |||
#endregion | |||
Current.Services.GetService<IProcessControl>().Inital(); | |||
MainView mv = new MainView(); | |||
mv.Show(); | |||
} | |||
@@ -51,7 +61,7 @@ namespace BPA.SingleDevice | |||
protected override void OnExit(ExitEventArgs e) | |||
{ | |||
base.OnExit(e); | |||
MainControl.GetInstance.Stop(); | |||
//MainControl.GetInstance.Stop(); | |||
} | |||
private static IServiceProvider ConfigurServices() | |||
@@ -61,15 +71,20 @@ namespace BPA.SingleDevice | |||
//services.AddSingleton<ISqlHelper, SqlHelper>(); | |||
services.AddSingleton<ILogService, LogService>(); | |||
services.AddSingleton<RawMaterialManagementViewModel>(); | |||
services.AddSingleton<OrderMainViewModel>(); | |||
services.AddSingleton<ParamsSetViewModel>(); | |||
services.AddSingleton<RunLogViewModel>(); | |||
services.AddSingleton<AlarmLogViewModel>(); | |||
services.AddSingleton<RecipeCompleteViewModel>(); | |||
services.AddSingleton<UserLogViewModel>(); | |||
services.AddSingleton<DebugLogViewModel>(); | |||
services.AddSingleton<VarMonitorViewModel>(); | |||
services.AddSingleton<DebugViewModel>(); | |||
services.AddSingleton<IProcessControl,ProcessControl>(); | |||
services.AddSingleton<GlobalData>(); | |||
return services.BuildServiceProvider(); | |||
} | |||
@@ -0,0 +1,75 @@ | |||
using BPA.SingleDevice.Interface; | |||
using BPA.SingleDevice.Services; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace BPA.SingleDevice.Business | |||
{ | |||
/// <summary> | |||
/// 配料机,在这个程序中,指的是味魔方。 | |||
/// </summary> | |||
public class Batcher : IBatchcer | |||
{ | |||
public int ID { get; set; } | |||
public bool BatchComplete { get; set; } | |||
public bool AllowBatching { get; set; } | |||
public bool IsConnected { get => modbus.IsConnected(); } | |||
string iP="192.168.6.100"; | |||
int port=502; | |||
ModbusTcp modbus = new(); | |||
public async Task Initial() | |||
{ | |||
await Task.Run(() => | |||
{ | |||
modbus.WithModbusTcp(iP, port).UseConnected(() => | |||
{ | |||
TaskManage.GetInstance.StartLong(() => | |||
{ | |||
BatchComplete = modbus.Read<bool>("LB1000".ToModbusAdd()).Content; | |||
}, $"Batcher【{ID}】:ReadData", true); | |||
}); | |||
}); | |||
} | |||
public bool StartBatching() | |||
{ | |||
try | |||
{ | |||
var result = modbus.Write<bool>("LB1001".ToModbusAdd(), true); | |||
return result.IsSuccess; | |||
} | |||
catch (Exception ex) | |||
{ | |||
return false; | |||
} | |||
} | |||
public bool WriteBatchData(ushort[] value) | |||
{ | |||
try | |||
{ | |||
var result = modbus.Write<ushort[]>("LW1000".ToModbusAdd(), value); | |||
return result.IsSuccess; | |||
} | |||
catch(Exception ex) | |||
{ | |||
return false; | |||
} | |||
} | |||
public void SetCommParam(int id,string ip, int port = 502) | |||
{ | |||
this.iP = ip; | |||
this.port = port; | |||
this.ID = id; | |||
} | |||
} | |||
} |
@@ -0,0 +1,138 @@ | |||
using BPA.SingleDevice.Interface; | |||
using BPA.SingleDevice.Services; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace BPA.SingleDevice.Business | |||
{ | |||
public class Conveyer : IConveyer | |||
{ | |||
public int ID { get; set; } | |||
public bool[] HaveVessel { get; set; } | |||
public int IsReverse { get; set ; } | |||
public float InchSpeed { get; set; } | |||
public float MoveSpeed { get; set; } | |||
public int AccTime { get; set; } | |||
public int MoveLength { get; set; } | |||
public bool MoveComplete { get;set; } | |||
public bool AllowMove { get; set; } | |||
public bool IsConnected => modbus.IsConnected(); | |||
string iP = "192.168.6.104"; | |||
int port = 502; | |||
ModbusTcp modbus = new(); | |||
public async Task Initial() | |||
{ | |||
//因为设备中间有个空位。虽然是4台设备,但是需要设置5个位置。 | |||
HaveVessel = new bool[5]; | |||
//这里还需写入默认参数,从文件读取,如移动速度等。 | |||
await Task.Run(() => | |||
{ | |||
modbus.WithModbusTcp(iP, port).UseConnected(() => | |||
{ | |||
TaskManage.GetInstance.StartLong(() => | |||
{ | |||
modbus.Read<ushort>("VW300".ToModbusAdd()).OnSuccess((haveVessel) => | |||
{ | |||
HaveVessel[0] = haveVessel.GetBitValue(1); | |||
HaveVessel[1] = haveVessel.GetBitValue(2); | |||
//HaveVessel[2] = false; | |||
HaveVessel[3] = haveVessel.GetBitValue(4); | |||
HaveVessel[4] = haveVessel.GetBitValue(5); | |||
}); | |||
modbus.Read<bool>("M0.2".ToModbusAdd()).OnSuccess((moveComplete) => | |||
{ | |||
MoveComplete = moveComplete; | |||
}); | |||
}, $"Conveyer【{ID}】:ReadData", true); | |||
}); | |||
}); | |||
} | |||
public void SetCommParam(int id, string ip, int port = 502) | |||
{ | |||
this.iP = ip; | |||
this.port = port; | |||
this.ID = id; | |||
} | |||
public void InchMove() | |||
{ | |||
if (IsConnected) | |||
{ | |||
try | |||
{ | |||
modbus.Write<ushort>("VW0".ToModbusAdd(), 1); | |||
} | |||
catch (Exception ex) | |||
{ | |||
} | |||
} | |||
} | |||
public bool MoveOnce() | |||
{ | |||
if (IsConnected) | |||
{ | |||
try | |||
{ | |||
return modbus.Write<ushort>("VW0".ToModbusAdd(), 2).IsSuccess; | |||
} | |||
catch (Exception ex) | |||
{ | |||
} | |||
} | |||
return false; | |||
} | |||
public bool SetInchParam(int isReverse, float inchSpeed) | |||
{ | |||
if (IsConnected) | |||
{ | |||
try | |||
{ | |||
var result1= modbus.Write<float>("VD100".ToModbusAdd(), inchSpeed); | |||
var result2= modbus.Write<int>("VW200".ToModbusAdd(), isReverse); | |||
return result1.IsSuccess && result2.IsSuccess; | |||
} | |||
catch (Exception ex) | |||
{ | |||
} | |||
} | |||
return false; | |||
} | |||
public bool SetMoveParam(float moveSpeed, int accTime, int moveLength) | |||
{ | |||
if (IsConnected) | |||
{ | |||
try | |||
{ | |||
var result1 = modbus.Write<float>("VD104".ToModbusAdd(), moveSpeed); | |||
var result2 = modbus.Write<int>("VW122".ToModbusAdd(), accTime); | |||
var result3 = modbus.Write<int>("VD108".ToModbusAdd(), moveLength); | |||
return result1.IsSuccess && result2.IsSuccess && result3.IsSuccess; | |||
} | |||
catch (Exception ex) | |||
{ | |||
} | |||
} | |||
return false; | |||
} | |||
} | |||
} |
@@ -27,11 +27,11 @@ namespace BPA.SingleDevice.Business | |||
private void CommInit() | |||
{ | |||
Enum.GetNames(typeof(EDeviceType)).ToList().ForEach(x => { Comm.TryAdd(x.ToEnum<EDeviceType>(), new DeviceControl()); }); | |||
Comm[EDeviceType.WeimoCube1].SetPar("192.168.1.100", EDeviceType.WeimoCube1); | |||
Comm[EDeviceType.WeimoCube2].SetPar("192.168.1.100", EDeviceType.WeimoCube2); | |||
Comm[EDeviceType.WeimoCube3].SetPar("192.168.1.100", EDeviceType.WeimoCube3); | |||
Comm[EDeviceType.WeimoCube4].SetPar("192.168.1.100", EDeviceType.WeimoCube4); | |||
Comm[EDeviceType.Conveyor].SetPar("192.168.1.100", EDeviceType.Conveyor); | |||
Comm[EDeviceType.WeimoCube1].SetPar("192.168.6.100", EDeviceType.WeimoCube1); | |||
Comm[EDeviceType.WeimoCube2].SetPar("192.168.6.101", EDeviceType.WeimoCube2); | |||
Comm[EDeviceType.WeimoCube3].SetPar("192.168.6.102", EDeviceType.WeimoCube3); | |||
Comm[EDeviceType.WeimoCube4].SetPar("192.168.6.103", EDeviceType.WeimoCube4); | |||
Comm[EDeviceType.Conveyor].SetPar("192.168.6.104", EDeviceType.Conveyor); | |||
Task.Run(() => | |||
{ | |||
Parallel.ForEach(Comm, (s) => { s.Value.Stop(); }); | |||
@@ -40,43 +40,43 @@ namespace BPA.SingleDevice.Business | |||
public void Start() | |||
{ | |||
CommInit(); | |||
TaskManage.GetInstance.StartLong(() => | |||
{ | |||
while (GlobalData.GoodsModels.Count > 0 && !Comm[EDeviceType.Conveyor].AllowBatching) | |||
{ | |||
Task.Run(() => | |||
{ | |||
if (GlobalData.GoodsModels.TryDequeue(out GoodsModel gm)) | |||
{ | |||
//对设备进行分组,筛选出对应设备所需要的料仓中的原料信息 | |||
var res = gm.RawMaters.GroupBy(p => p.DeviceNum).ToDictionary(p => p.Key, p => p.ToList()); | |||
res.ToList().ForEach(item => | |||
{ | |||
int index = item.Key - 1; | |||
if (index >= 0 && index < Comm[EDeviceType.Conveyor].DeviceStationDetection.Length) | |||
{ | |||
if (Comm[EDeviceType.Conveyor].DeviceStationDetection[index]) | |||
{ | |||
Comm[EDeviceType.Conveyor].ConveyorControl(false); | |||
ushort[] weights = new ushort[14]; | |||
item.Value.ForEach(s => | |||
{ | |||
int tempIndex = s.WarehouseNum - 1; | |||
if (tempIndex >= 0 && tempIndex < weights.Length) | |||
{ | |||
weights[tempIndex] = s.Weight; | |||
} | |||
}); | |||
Comm[(EDeviceType)item.Key].WriteControl(weights); | |||
} | |||
} | |||
}); | |||
} | |||
}); | |||
} | |||
Thread.Sleep(10); | |||
}, "配料任务", true); | |||
//CommInit(); | |||
//TaskManage.GetInstance.StartLong(() => | |||
//{ | |||
// while (GlobalData.GoodsModels.Count > 0 && !Comm[EDeviceType.Conveyor].AllowBatching) | |||
// { | |||
// Task.Run(() => | |||
// { | |||
// if (GlobalData.GoodsModels.TryDequeue(out GoodsModel gm)) | |||
// { | |||
// //对设备进行分组,筛选出对应设备所需要的料仓中的原料信息 | |||
// var res = gm.RawMaters.GroupBy(p => p.DeviceNum).ToDictionary(p => p.Key, p => p.ToList()); | |||
// res.ToList().ForEach(item => | |||
// { | |||
// int index = item.Key - 1; | |||
// if (index >= 0 && index < Comm[EDeviceType.Conveyor].DeviceStationDetection.Length) | |||
// { | |||
// if (Comm[EDeviceType.Conveyor].DeviceStationDetection[index]) | |||
// { | |||
// Comm[EDeviceType.Conveyor].ConveyorControl(false); | |||
// ushort[] weights = new ushort[14]; | |||
// item.Value.ForEach(s => | |||
// { | |||
// int tempIndex = s.WarehouseNum - 1; | |||
// if (tempIndex >= 0 && tempIndex < weights.Length) | |||
// { | |||
// weights[tempIndex] = s.Weight; | |||
// } | |||
// }); | |||
// Comm[(EDeviceType)item.Key].WriteControl(weights); | |||
// } | |||
// } | |||
// }); | |||
// } | |||
// }); | |||
// } | |||
// Thread.Sleep(10); | |||
//}, "配料任务", true); | |||
} | |||
public void Stop() | |||
@@ -0,0 +1,311 @@ | |||
using BPA.Model.Enums; | |||
using BPA.Model.Recipe; | |||
using BPA.SingleDevice.Interface; | |||
using BPA.SingleDevice.Services; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace BPA.SingleDevice.Business | |||
{ | |||
/// <summary> | |||
/// 配料流程控制 | |||
/// </summary> | |||
public class ProcessControl : IProcessControl | |||
{ | |||
public ProcessControl(ILogService logService,GlobalData global) | |||
{ | |||
this.logService = logService; | |||
this.global = global; | |||
} | |||
/// <summary> | |||
/// 键就是配料设备对应的ID。这里分别为1,2,4,5。 | |||
/// </summary> | |||
ConcurrentDictionary<int, IBatchcer> batchers = new(); | |||
//List<TaskServer> currentTask = new(); | |||
//ConcurrentDictionary<int, TaskServer> test = new(); | |||
IConveyer conveyer = new Conveyer(); | |||
private readonly ILogService logService; | |||
private GlobalData global; | |||
RecipeData currentRecipe; | |||
CancellationTokenSource cts; | |||
Task runTask; | |||
public async void Inital() | |||
{ | |||
#region 实例初始化配料机 | |||
batchers.TryAdd(1, new Batcher()); | |||
batchers.TryAdd(2, new Batcher()); | |||
batchers.TryAdd(4, new Batcher()); | |||
batchers.TryAdd(5, new Batcher()); | |||
//SetBatcherComm(1, "192.168.6.100"); | |||
//SetBatcherComm(2, "192.168.6.101"); | |||
//SetBatcherComm(4, "192.168.6.102"); | |||
//SetBatcherComm(5, "192.168.6.103"); | |||
SetBatcherComm(1, "127.0.0.1", 503); | |||
SetBatcherComm(2, "127.0.0.1", 504); | |||
SetBatcherComm(4, "127.0.0.1", 505); | |||
SetBatcherComm(5, "127.0.0.1", 506); | |||
foreach (var batcher in batchers.Values) | |||
{ | |||
await batcher.Initial(); | |||
} | |||
#endregion | |||
//conveyer.SetCommParam(1, "192.168.6.104"); | |||
conveyer.SetCommParam(1, "127.0.0.1",510); | |||
await conveyer.Initial(); | |||
//currentTask.Clear(); | |||
ActionRegister(); | |||
TaskManage.GetInstance.StartLong(() => | |||
{ | |||
if (global.RecipeQueue.Count>0 && currentRecipe is null ) | |||
{ | |||
//多配方情况下,必须在工位1没有碗位置,才能进行下发,否则会与之前的配方冲突。 | |||
if (/*!conveyer.HaveVessel[0] &&*/ global.RecipeQueue.ElementAt(0) is not null && global.RecipeQueue.ElementAt(0) is RecipeData) | |||
{ | |||
global.RecipeQueue.TryDequeue(out currentRecipe); | |||
//currentTask.Add(new TaskServer() {RunTask=Task.Run(() => { Batching(recipe); }) ,TaskName=$"{recipe.Name}"}); | |||
cts = new(); | |||
Task.Run(() => { Batching(currentRecipe); }, cts.Token); | |||
logService.LogRunInfo($"配方【{currentRecipe.Name}】-- 开始执行配料。"); | |||
} | |||
} | |||
}, "MonitorRecipeIssue", true); | |||
} | |||
/// <summary> | |||
/// 配料。 | |||
/// </summary> | |||
/// <param name="recipe">需要配料的配方</param> | |||
private async void Batching(RecipeData recipe) | |||
{ | |||
if (recipe is null) | |||
{ | |||
logService.LogRunInfo($"参数<recipe>值为null,配料流程结束。"); | |||
return; | |||
} | |||
while (recipe.IsMakeComplete[0] == false) | |||
{ | |||
await StationBatching(recipe, 1); | |||
} | |||
for (int stationNum = 2; stationNum <= 5; stationNum++) | |||
{ | |||
await MoveOnceAndBatach(recipe, stationNum); | |||
} | |||
//ToDo:如果最后需要移动一次才能出餐,在这里添加一次移动传送带。 | |||
logService.LogRunInfo($"配方【{recipe.Name}】配料完成。"); | |||
logService.LogRecipeCompleteInfo($"【{recipe.Name}】"); | |||
currentRecipe = null; | |||
} | |||
/// <summary> | |||
/// 单工位配料 | |||
/// </summary> | |||
/// <param name="recipe">配方</param> | |||
/// <param name="stationNum">工位数。</param> | |||
private async Task StationBatching(RecipeData recipe,int stationNum) | |||
{ | |||
#region 数据验证 | |||
if (recipe is null) | |||
{ | |||
logService.LogRunInfo($"参数<recipe>值为null,配料流程结束。"); | |||
return; | |||
} | |||
//如果配料机里没连接该工位的配料机,则直接完成。 | |||
if (!batchers.ContainsKey(stationNum)) | |||
{ | |||
recipe.BatchStatus[stationNum] = BatchStep.BatchCompleted; | |||
recipe.IsMakeComplete[stationNum - 1] = true; | |||
logService.LogRunInfo($"参数<stationNum>值为[{stationNum}],目前该工位无配料机或连接配料机失败。"); | |||
//工位3无到位检测。 | |||
recipe.CurrentStation = stationNum; | |||
return; | |||
} | |||
#endregion | |||
//数组起始索引是0,工位起始ID是1。 | |||
if (conveyer.HaveVessel[stationNum-1]) | |||
{ | |||
recipe.CurrentStation = stationNum; | |||
ushort[] materialList=new ushort[14]; | |||
//获取工位需要的配料数据。 | |||
if (recipe.MaterialData.ContainsKey(stationNum)) | |||
{ | |||
materialList = recipe.MaterialData[stationNum]; | |||
} | |||
//如果该工位不需要配料,直接完成就行。 | |||
else | |||
{ | |||
recipe.BatchStatus[stationNum] = BatchStep.BatchCompleted; | |||
recipe.IsMakeComplete[stationNum - 1] = true; | |||
logService.LogRunInfo($"参数<stationNum>值为[{stationNum}],该配方无该工位配料需求。"); | |||
return; | |||
} | |||
//配料完成的上升沿检测。 | |||
var completeTrig =RTrig.GetInstance($"Batchers[{stationNum}].BatchComplete").Start(batchers[stationNum].BatchComplete); | |||
//配料流程。 | |||
switch (recipe.BatchStatus[stationNum]) | |||
{ | |||
case BatchStep.WaitBatch: | |||
recipe.BatchStatus[stationNum] = BatchStep.WriteBatchParam; | |||
break; | |||
case BatchStep.WriteBatchParam: | |||
if (materialList is not null && materialList.Length == 14) | |||
{ | |||
if (batchers[stationNum].WriteBatchData(materialList)) | |||
{ | |||
recipe.BatchStatus[stationNum] = BatchStep.StartBatch; | |||
logService.LogRunInfo($"配方【{recipe.Name}】写入工位【{stationNum}】的下料参数【{String.Join(',',materialList)}】成功。"); | |||
} | |||
else | |||
{ | |||
logService.LogRunInfo($"配方【{recipe.Name}】写入工位【{stationNum}】的下料参数失败,稍后重试。"); | |||
await Task.Delay(3000); | |||
} | |||
} | |||
else | |||
{ | |||
logService.LogRunInfo($"配方【{recipe.Name}】写入工位【{stationNum}】的下料参数失败,参数长度错误或为Null。"); | |||
return; | |||
} | |||
break; | |||
case BatchStep.StartBatch: | |||
if (batchers[stationNum].StartBatching()) | |||
{ | |||
recipe.BatchStatus[stationNum] = BatchStep.WaitBatchComplete; | |||
logService.LogRunInfo($"配方【{recipe.Name}】工位【{stationNum}】的开始配料,等待配料完成信号上升沿。"); | |||
} | |||
else | |||
{ | |||
logService.LogRunInfo($"配方【{recipe.Name}】写入工位【{stationNum}】的开始配料失败,3S后重试。"); | |||
await Task.Delay(3000); | |||
} | |||
break; | |||
case BatchStep.WaitBatchComplete: | |||
//先延时,以免味魔方还没开始工作,未把配料完成写为false。 | |||
//await Task.Delay(500); | |||
//if (batchers[stationNum].BatchComplete) | |||
if (completeTrig) | |||
{ | |||
logService.LogRunInfo($"配方【{recipe.Name}】工位【{stationNum}】的配料完成。"); | |||
recipe.BatchStatus[stationNum] = BatchStep.BatchCompleted; | |||
} | |||
break; | |||
case BatchStep.BatchCompleted: | |||
recipe.IsMakeComplete[stationNum - 1] = true; | |||
break; | |||
} | |||
} | |||
else | |||
{ | |||
logService.LogRunInfo($"配方【{recipe.Name}】工位【{stationNum}】未检测到容器到位,请检查,3秒后重新检测。"); | |||
await Task.Delay(3000); | |||
} | |||
} | |||
private async Task MoveOnceAndBatach(RecipeData recipe,int stationNum) | |||
{ | |||
global.MoveConveyerStep = MoveConveyer.WaitMove; | |||
while (global.MoveConveyerStep != MoveConveyer.MoveComplete) | |||
{ | |||
var moveCompleteTrig = RTrig.GetInstance("MoveCompleted").Start(conveyer.MoveComplete); | |||
switch (global.MoveConveyerStep) | |||
{ | |||
case MoveConveyer.WaitMove: | |||
if (conveyer.MoveOnce()) | |||
{ | |||
logService.LogRunInfo($"配方【{recipe.Name}】控制传送带去下个工位,等待动作完成信号上升沿。"); | |||
global.MoveConveyerStep = MoveConveyer.Moveing; | |||
} | |||
else | |||
{ | |||
logService.LogRunInfo($"配方【{recipe.Name}】控制传送带去下个工位失败,3S后重试。"); | |||
await Task.Delay(3000); | |||
} | |||
break; | |||
case MoveConveyer.Moveing: | |||
if (moveCompleteTrig) | |||
{ | |||
logService.LogRunInfo($"配方【{recipe.Name}】控制传送带移动结束。"); | |||
while (recipe.IsMakeComplete[stationNum - 1] == false) | |||
{ | |||
await StationBatching(recipe, stationNum); | |||
} | |||
global.MoveConveyerStep = MoveConveyer.MoveComplete; | |||
} | |||
break; | |||
case MoveConveyer.MoveComplete: | |||
//logService.LogRunInfo($"配方【{recipe.Name}】控制传送带移动结束。"); | |||
//await StationBatching(recipe, stationNum); | |||
break; | |||
} | |||
} | |||
} | |||
/// <summary> | |||
/// 设置相应设备ID的配料机的通讯参数。 | |||
/// </summary> | |||
/// <param name="id">该设备对应的工位ID。</param> | |||
/// <param name="ip">IP地址</param> | |||
/// <param name="port">端口号,默认为502。</param> | |||
private void SetBatcherComm(int id,string ip,int port=502) | |||
{ | |||
if (batchers.ContainsKey(id)) | |||
{ | |||
batchers[id].SetCommParam(id, ip, port); | |||
} | |||
else | |||
{ | |||
logService.LogDebugInfo($"设置配料机设备【{id}】的通讯参数失败,未在集合中找到此ID对应的设备。"); | |||
} | |||
} | |||
private void ActionRegister() | |||
{ | |||
ActionManage.GetInstance.Register<bool>(new Func<bool>(() => | |||
{ | |||
//目前如果工位1 没有碗或者当前没配方就可以下配方。 | |||
bool result =! (conveyer.HaveVessel[0]) || (currentRecipe==null); | |||
return result; | |||
}), "CanIssueRecipe", true); | |||
} | |||
/// <summary> | |||
/// 传送带和配料机之间的信号交互。 | |||
/// </summary> | |||
private void InterActive() | |||
{ | |||
#region 配料机 | |||
#endregion | |||
#region 传送带 | |||
conveyer.AllowMove = conveyer.MoveComplete; | |||
#endregion | |||
} | |||
private void SingleDetect() | |||
{ | |||
//TODO:上升沿信号检测。 | |||
} | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
using MongoDB.Driver; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace BPA.SingleDevice.Interface | |||
{ | |||
public interface IBatchcer | |||
{ | |||
/// <summary> | |||
/// 设备ID | |||
/// </summary> | |||
public int ID { get; set; } | |||
/// <summary> | |||
/// 配料完成 | |||
/// </summary> | |||
public bool BatchComplete { get; set; } | |||
/// <summary> | |||
/// 允许下料。 | |||
/// </summary> | |||
public bool AllowBatching { get; set; } | |||
/// <summary> | |||
/// 是否连接。 | |||
/// </summary> | |||
bool IsConnected { get; } | |||
/// <summary> | |||
/// 设置通讯参数 | |||
/// </summary> | |||
void SetCommParam(int id,string ip, int port = 502); | |||
/// <summary> | |||
/// 写入下料数据。 | |||
/// </summary> | |||
/// <param name="value"></param> | |||
/// <returns></returns> | |||
bool WriteBatchData(ushort[] value); | |||
/// <summary> | |||
/// 开始配料 | |||
/// </summary> | |||
/// <returns></returns> | |||
bool StartBatching(); | |||
/// <summary> | |||
/// 设备初始化 | |||
/// </summary> | |||
Task Initial(); | |||
} | |||
} |
@@ -0,0 +1,84 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace BPA.SingleDevice.Interface | |||
{ | |||
public interface IConveyer | |||
{ | |||
/// <summary> | |||
/// 设备ID | |||
/// </summary> | |||
public int ID { get; set; } | |||
/// <summary> | |||
/// 位置有容器,这个程序里容器是碗。 | |||
/// </summary> | |||
bool[] HaveVessel { get; set; } | |||
/// <summary> | |||
/// 寸动是否反转,值为1时是反转,为0时则为正转。 | |||
/// </summary> | |||
int IsReverse { get;set; } | |||
/// <summary> | |||
/// 寸动速度。 | |||
/// </summary> | |||
float InchSpeed { get; set; } | |||
/// <summary> | |||
/// 传动带移动速度。 | |||
/// </summary> | |||
float MoveSpeed { get; set; } | |||
/// <summary> | |||
/// 加速时间,一般不改动。 | |||
/// </summary> | |||
int AccTime { get; set; } | |||
/// <summary> | |||
/// 传动带移动一次的长度,单位:脉冲。 | |||
/// </summary> | |||
int MoveLength { get; set; } | |||
/// <summary> | |||
/// 移动结束。 | |||
/// </summary> | |||
bool MoveComplete { get; set; } | |||
/// <summary> | |||
/// 是否连接。 | |||
/// </summary> | |||
bool IsConnected { get;} | |||
/// <summary> | |||
/// 允许移动。 | |||
/// </summary> | |||
bool AllowMove { get; set; } | |||
/// <summary> | |||
/// 设备初始化 | |||
/// </summary> | |||
Task Initial(); | |||
/// <summary> | |||
/// 设置通讯参数 | |||
/// </summary> | |||
void SetCommParam(int id, string ip, int port = 502); | |||
/// <summary> | |||
/// 寸动【调试状态】 | |||
/// </summary> | |||
void InchMove(); | |||
/// <summary> | |||
/// 设置寸动参数 | |||
/// </summary> | |||
/// <param name="isReverse">是否反转</param> | |||
/// <param name="inchSpeed">寸动速度</param> | |||
/// <returns>设置是否成功</returns> | |||
bool SetInchParam(int isReverse,float inchSpeed); | |||
/// <summary> | |||
/// 设置移动参数 | |||
/// </summary> | |||
/// <param name="moveSpeed">移动速度</param> | |||
/// <param name="accTime">移动加速时间</param> | |||
/// <param name="moveLength">移动长度</param> | |||
/// <returns>设置是否成功</returns> | |||
bool SetMoveParam(float moveSpeed, int accTime, int moveLength); | |||
/// <summary> | |||
/// 移动一次。 | |||
/// </summary> | |||
bool MoveOnce(); | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace BPA.SingleDevice.Interface | |||
{ | |||
public interface IProcessControl | |||
{ | |||
/// <summary> | |||
/// 初始化即开始。 | |||
/// </summary> | |||
void Inital(); | |||
} | |||
} |
@@ -0,0 +1,30 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace BPA.SingleDevice.Json | |||
{ | |||
public class ConnectConfig | |||
{ | |||
} | |||
public class BatcherConfig | |||
{ | |||
/// <summary> | |||
/// 对应工位ID | |||
/// </summary> | |||
public int StationID { get; set; } | |||
/// <summary> | |||
/// IP地址 | |||
/// </summary> | |||
public string IP { get; set; } | |||
/// <summary> | |||
/// 端口号 | |||
/// </summary> | |||
public int Port { get; set; } | |||
} | |||
} |
@@ -21,6 +21,6 @@ namespace BPA.SingleDevice.Services | |||
void LogRecipeCompleteInfo(string info); | |||
void LogDebugInfo(string info); | |||
Task<List<T>> GetAllLog<T>(); | |||
Task<List<T>> GetAllLog<T>() where T:LogBase; | |||
} | |||
} |
@@ -132,7 +132,7 @@ namespace BPA.SingleDevice.Services | |||
} | |||
} | |||
public async Task<List<T>> GetAllLog<T>() | |||
public async Task<List<T>> GetAllLog<T>() where T:LogBase | |||
{ | |||
var logs= await sqlHelper.GetListAsync<T>(); | |||
if (logs.IsSuccess) | |||
@@ -48,7 +48,7 @@ | |||
HorizontalAlignment="Right" | |||
FontSize="16" | |||
Foreground="#ddd" | |||
Text="设备编号:" /> | |||
Text="设备对应工位:" /> | |||
<ComboBox | |||
Grid.Row="1" | |||
Grid.Column="1" | |||
@@ -0,0 +1,43 @@ | |||
<UserControl | |||
x:Class="BPA.SingleDevice.View.DebugView" | |||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||
xmlns:bpa="http://BPAUIControl.io/winfx/xaml/toolkit" | |||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |||
xmlns:local="clr-namespace:BPA.SingleDevice.View" | |||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |||
xmlns:vm="clr-namespace:BPA.SingleDevice.ViewModel" | |||
d:DesignHeight="450" | |||
d:DesignWidth="800" | |||
mc:Ignorable="d"> | |||
<Grid> | |||
<Grid.RowDefinitions> | |||
<RowDefinition Height="1*" /> | |||
<RowDefinition Height="1*" /> | |||
</Grid.RowDefinitions> | |||
<!-- 流水线手动控制移动 --> | |||
<StackPanel VerticalAlignment="Top" Orientation="Horizontal"> | |||
<Button | |||
Width="100" | |||
Height="50" | |||
Margin="10" | |||
Command="{Binding MoveInchCommand}" | |||
Content="流水线寸动" /> | |||
<ToggleButton | |||
Margin="10" | |||
bpa:ToggleButtonHelper.CheckedContent="反转" | |||
Content="正转" | |||
IsChecked="{Binding IsReverse}" | |||
Style="{DynamicResource SwitchAccentToggleButton}" /> | |||
<TextBlock | |||
FontSize="16" | |||
Foreground="White" | |||
Text="寸动速度:" /> | |||
</StackPanel> | |||
<!--味魔方手动控制--> | |||
<StackPanel VerticalAlignment="Top" Orientation="Horizontal" Grid.Row="1"> | |||
</StackPanel> | |||
</Grid> | |||
</UserControl> |
@@ -0,0 +1,30 @@ | |||
using Microsoft.Extensions.DependencyInjection; | |||
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 BPA.SingleDevice.View | |||
{ | |||
/// <summary> | |||
/// DebugView.xaml 的交互逻辑 | |||
/// </summary> | |||
public partial class DebugView : UserControl | |||
{ | |||
public DebugView() | |||
{ | |||
InitializeComponent(); | |||
this.DataContext = App.Current.Services.GetService<DebugViewModel>(); | |||
} | |||
} | |||
} |
@@ -11,9 +11,9 @@ | |||
d:DesignWidth="800" | |||
mc:Ignorable="d"> | |||
<UserControl.DataContext> | |||
<!--<UserControl.DataContext> | |||
<vm:OrderMainViewModel /> | |||
</UserControl.DataContext> | |||
</UserControl.DataContext>--> | |||
<Grid Margin="10"> | |||
<ListView | |||
@@ -51,15 +51,15 @@ | |||
Grid.Row="2" | |||
Margin="0,5,0,0" | |||
bpa:GridHelper.ColumnDefinitions="*,*"> | |||
<bpa:NumericBox | |||
<!--<bpa:NumericBox | |||
bpa:ControlHelper.FocusBorderBrush="{DynamicResource Secondary}" | |||
BorderThickness="0" | |||
IsReadOnly="True" | |||
Style="{StaticResource FrontBackNumericBox}" | |||
Value="{Binding Count}" /> | |||
Value="{Binding Count}" />--> | |||
<Button | |||
Grid.Column="1" | |||
Margin="10,0,0,0" | |||
Grid.Column="0" Grid.ColumnSpan="2" | |||
Margin="10,0" | |||
Command="{Binding DataContext.DownRecipeCommand, RelativeSource={RelativeSource AncestorType=local:OrderMainView}}" | |||
CommandParameter="{Binding Id}" | |||
Content="开始下单" | |||
@@ -1,4 +1,5 @@ | |||
using System; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
@@ -23,6 +24,7 @@ namespace BPA.SingleDevice.View | |||
public OrderMainView() | |||
{ | |||
InitializeComponent(); | |||
this.DataContext = App.Current.Services.GetService<OrderMainViewModel>(); | |||
} | |||
} | |||
} |
@@ -11,9 +11,9 @@ | |||
d:DesignWidth="800" | |||
mc:Ignorable="d"> | |||
<UserControl.DataContext> | |||
<!--<UserControl.DataContext> | |||
<vm:RawMaterialManagementViewModel /> | |||
</UserControl.DataContext> | |||
</UserControl.DataContext>--> | |||
<bpa:DialogContainer> | |||
<Grid Margin="10"> | |||
@@ -1,4 +1,5 @@ | |||
using System; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
@@ -23,6 +24,7 @@ namespace BPA.SingleDevice.View | |||
public RawMaterialManagementView() | |||
{ | |||
InitializeComponent(); | |||
this.DataContext = App.Current.Services.GetService<RawMaterialManagementViewModel>(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
<UserControl x:Class="BPA.SingleDevice.View.VarMonitorView" | |||
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:BPA.SingleDevice.View" | |||
mc:Ignorable="d" | |||
d:DesignHeight="450" d:DesignWidth="800"> | |||
<Grid> | |||
</Grid> | |||
</UserControl> |
@@ -0,0 +1,30 @@ | |||
using Microsoft.Extensions.DependencyInjection; | |||
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 BPA.SingleDevice.View | |||
{ | |||
/// <summary> | |||
/// VarMonitorView.xaml 的交互逻辑 | |||
/// </summary> | |||
public partial class VarMonitorView : UserControl | |||
{ | |||
public VarMonitorView() | |||
{ | |||
InitializeComponent(); | |||
this.DataContext = App.Current.Services.GetService<VarMonitorViewModel>(); | |||
} | |||
} | |||
} |
@@ -13,7 +13,8 @@ namespace BPA.SingleDevice.ViewModel | |||
{ | |||
public AddRawMaterialDialogViewModel() | |||
{ | |||
for (int i = 1; i <= 4; i++) { DeviceNums.Add(i); } | |||
for (int i = 1; i <= 2; i++) { DeviceNums.Add(i); } | |||
for (int i = 4; i <= 5; i++) { DeviceNums.Add(i); } | |||
for (int i = 1; i <= 14; i++) { ChNum.Add(i); } | |||
SaveCommand = new BPARelayCommand(() => { RequestClose?.Invoke(RawMaterResultInfo); }); | |||
CancelCommand = new BPARelayCommand(() => { RequestClose?.Invoke(null); }); | |||
@@ -11,18 +11,18 @@ namespace BPA.SingleDevice.ViewModel | |||
public AlarmLogViewModel() | |||
{ | |||
AlarmLogs = new(); | |||
for (int i = 1; i <= 100; i++) | |||
{ | |||
AlarmLogs.Add(new() | |||
{ | |||
ID = i, | |||
Date = DateTime.Now.Date.ToString("yyyy-MM-dd"), | |||
Time = DateTime.Now.ToString("HH:mm:ss"), | |||
Value = "108", | |||
Info = "测试用报警信息", | |||
Grade = "一般报警" | |||
}); | |||
} | |||
//for (int i = 1; i <= 100; i++) | |||
//{ | |||
// AlarmLogs.Add(new() | |||
// { | |||
// ID = i, | |||
// Date = DateTime.Now.Date.ToString("yyyy-MM-dd"), | |||
// Time = DateTime.Now.ToString("HH:mm:ss"), | |||
// Value = "108", | |||
// Info = "测试用报警信息", | |||
// Grade = "一般报警" | |||
// }); | |||
//} | |||
ViewHistoryCommand = new(() => | |||
{ | |||
@@ -0,0 +1,27 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace BPA.SingleDevice.ViewModel | |||
{ | |||
public class DebugViewModel:NotifyBase | |||
{ | |||
public DebugViewModel() | |||
{ | |||
MoveInchCommand = new(() => | |||
{ | |||
}); | |||
} | |||
/// <summary> | |||
/// 流水线寸动。 | |||
/// </summary> | |||
public BPARelayCommand MoveInchCommand { get; set; } | |||
/// <summary> | |||
/// 寸动是否反转。 | |||
/// </summary> | |||
public bool IsReverse { get; set; } | |||
} | |||
} |
@@ -23,10 +23,13 @@ namespace BPA.SingleDevice.ViewModel | |||
new ViewItem("原料管理", new RawMaterialManagementView(), IconType.ReservedFill), | |||
new ViewItem("运行日志",new RunLogView(),IconType.FileTextLine), | |||
new ViewItem("操作日志",new UserLogView(),IconType.AccountPinCircleLine), | |||
new ViewItem("报警日志",new AlarmLogView(),IconType.AlarmWarningLine), | |||
//new ViewItem("报警日志",new AlarmLogView(),IconType.AlarmWarningLine), | |||
new ViewItem("调试日志",new DebugLogView(),IconType.BugLine), | |||
new ViewItem("配方完成日志",new RecipeCompletView(),IconType.TaskLine), | |||
new ViewItem("参数设置",new ParamsSetView(),IconType.Settings4Line) | |||
new ViewItem("变量监控",new VarMonitorView(),IconType.Dashboard3Line), | |||
new ViewItem("参数设置",new ParamsSetView(),IconType.Settings4Line), | |||
new ViewItem("调试界面",new DebugView(),IconType.Settings4Line) | |||
}; | |||
SelecteCommand = new BPARelayCommand<object>(DoNavChanged); | |||
@@ -8,13 +8,22 @@ using System.Collections.ObjectModel; | |||
using BPA.Model.Table; | |||
using BPA.SingleDevice.Helper; | |||
using BPA.Model; | |||
using BPA.Model.Recipe; | |||
using BPA.SingleDevice.Services; | |||
using System.Net.WebSockets; | |||
using System.Windows; | |||
namespace BPA.SingleDevice.ViewModel | |||
{ | |||
public class OrderMainViewModel : NotifyBase | |||
{ | |||
public OrderMainViewModel() | |||
private readonly ILogService logService; | |||
private readonly GlobalData global; | |||
public OrderMainViewModel(ILogService logService,GlobalData global) | |||
{ | |||
this.logService = logService; | |||
this.global = global; | |||
SqlHelper.GetInstance.GetListAsync<RecipeTB>().Result.OnSuccess(s => | |||
{ | |||
s.ForEach(item => | |||
@@ -30,54 +39,146 @@ namespace BPA.SingleDevice.ViewModel | |||
{ | |||
if (o != null && !string.IsNullOrEmpty(o.ToString())) | |||
{ | |||
var res = Goods.FirstOrDefault(p => p.Id == o.ToString()); | |||
if (res != null) | |||
if (MessageBoxR.ConfirmGlobal("是否该下发配方?","提示")==MessageBoxResult.Yes) | |||
{ | |||
List<RawMaterModel> rawMaters = new List<RawMaterModel>(); | |||
SqlHelper.GetInstance.GetRawMaterIds(res.Id).Result.OnSuccess(s => | |||
var result= ActionManage.GetInstance.Send<bool>("CanIssueRecipe"); | |||
if (result != null && result.IsSuccess && result.Content==true) | |||
{ | |||
s.ForEach(item => | |||
{ | |||
var rmtb = RawMaters.FirstOrDefault(p => p.Id == item.RawMaterId); | |||
if (rmtb != null) | |||
{ | |||
rawMaters.Add(new RawMaterModel() | |||
{ | |||
Weight = item.Weight, | |||
DeviceNum = rmtb.DeviceNum, | |||
Id = rmtb.Id, | |||
LastModified = rmtb.LastModified, | |||
Name = rmtb.Name, | |||
WarehouseNum = rmtb.WarehouseNum, | |||
}); | |||
} | |||
}); | |||
}); | |||
GenerateRecipe(o.ToString()!); | |||
} | |||
else | |||
{ | |||
Message.ErrorGlobal("下发配方失败,下发配方时工位【1】不可有碗,请检查后重试。"); | |||
} | |||
} | |||
} | |||
}); | |||
} | |||
private List<RawMaterTB> RawMaters { get; set; } = new List<RawMaterTB>(); | |||
public ObservableCollection<RecipeModel> Goods { get; set; } = new ObservableCollection<RecipeModel>(); | |||
public BPARelayCommand<object> DownRecipeCommand { get; set; } | |||
for (int i = 0; i < res.Count; i++) | |||
private RecipeData GenerateRecipe(string recipeID) | |||
{ | |||
if (string.IsNullOrEmpty(recipeID)) | |||
{ | |||
logService.LogDebugInfo($"解析配方数据失败,参数<recipeID>是Null或者Empty,在<OrderMainViewModel.GenerateRecipe()>中。"); | |||
} | |||
else | |||
{ | |||
//验证指定的配方号是否在配方列表中。 | |||
var res = Goods.FirstOrDefault(p => p.Id == recipeID); | |||
var recipeName = res.Name; | |||
if (res != null) | |||
{ | |||
//该配方所有物料集合。 | |||
List<RawMaterModel> allMaterial = new List<RawMaterModel>(); | |||
//根据配方号获取所有的物料。 | |||
SqlHelper.GetInstance.GetRawMaterIds(res.Id).Result.OnSuccess(s => | |||
{ | |||
s.ForEach(item => | |||
{ | |||
List<RawMaterModel> temp = new List<RawMaterModel>(); | |||
rawMaters.ForEach(item => | |||
var rmtb = RawMaters.FirstOrDefault(p => p.Id == item.RawMaterId); | |||
if (rmtb != null) | |||
{ | |||
temp.Add(new RawMaterModel() | |||
allMaterial.Add(new RawMaterModel() | |||
{ | |||
Weight = item.Weight, | |||
WarehouseNum = item.WarehouseNum, | |||
Name = item.Name, | |||
LastModified = item.LastModified, | |||
Id = item.Id, | |||
DeviceNum = item.DeviceNum | |||
DeviceNum = rmtb.DeviceNum, | |||
Id = rmtb.Id, | |||
LastModified = rmtb.LastModified, | |||
Name = rmtb.Name, | |||
WarehouseNum = rmtb.WarehouseNum, | |||
}); | |||
}); | |||
GlobalData.GoodsModels.Enqueue(new GoodsModel() { RawMaters = temp }); | |||
} | |||
}); | |||
}); | |||
Dictionary<int, ushort[]> materialData = new(); | |||
//根据设备和通道分类。 | |||
var temp= allMaterial.GroupBy(p => p.DeviceNum); | |||
foreach (var device in temp) | |||
{ | |||
ushort[] channelWeight = new ushort[14]; | |||
//根据通道排序后的物料设备分组表。 | |||
var orderedMaterial= device.OrderBy(p => p.WarehouseNum); | |||
for (int i = 0; i < 14; i++) | |||
{ | |||
var channel= orderedMaterial.FirstOrDefault(p => p.WarehouseNum == (i+1)); | |||
if (channel is not null) | |||
{ | |||
channelWeight[i]=(channel.Weight); | |||
} | |||
else | |||
{ | |||
channelWeight[i]=0; | |||
} | |||
} | |||
materialData.Add(device.Key, channelWeight); | |||
} | |||
RecipeData recipeData = new(recipeID, recipeName, materialData); | |||
global.RecipeQueue.Enqueue(recipeData); | |||
Message.SuccessGlobal($"下发配方【{recipeName}】成功。"); | |||
logService.LogUserInfo($"下发配方【{recipeName}】成功。"); | |||
} | |||
}); | |||
else | |||
{ | |||
logService.LogRunInfo($"解析配方数据失败,未找到【{recipeID}】对应的配方。"); | |||
} | |||
} | |||
return null; | |||
} | |||
private List<RawMaterTB> RawMaters { get; set; } = new List<RawMaterTB>(); | |||
public ObservableCollection<RecipeModel> Goods { get; set; } = new ObservableCollection<RecipeModel>(); | |||
/// <summary> | |||
/// 之前的配方数据解析。 | |||
/// </summary> | |||
/// <param name="o"></param> | |||
private void OldDataPrase(object o) | |||
{ | |||
var res = Goods.FirstOrDefault(p => p.Id == o.ToString()); | |||
if (res != null) | |||
{ | |||
List<RawMaterModel> rawMaters = new List<RawMaterModel>(); | |||
SqlHelper.GetInstance.GetRawMaterIds(res.Id).Result.OnSuccess(s => | |||
{ | |||
s.ForEach(item => | |||
{ | |||
var rmtb = RawMaters.FirstOrDefault(p => p.Id == item.RawMaterId); | |||
if (rmtb != null) | |||
{ | |||
rawMaters.Add(new RawMaterModel() | |||
{ | |||
Weight = item.Weight, | |||
DeviceNum = rmtb.DeviceNum, | |||
Id = rmtb.Id, | |||
LastModified = rmtb.LastModified, | |||
Name = rmtb.Name, | |||
WarehouseNum = rmtb.WarehouseNum, | |||
}); | |||
} | |||
}); | |||
}); | |||
public BPARelayCommand<object> DownRecipeCommand { get; set; } | |||
for (int i = 0; i < res.Count; i++) | |||
{ | |||
List<RawMaterModel> temp = new List<RawMaterModel>(); | |||
rawMaters.ForEach(item => | |||
{ | |||
temp.Add(new RawMaterModel() | |||
{ | |||
Weight = item.Weight, | |||
WarehouseNum = item.WarehouseNum, | |||
Name = item.Name, | |||
LastModified = item.LastModified, | |||
Id = item.Id, | |||
DeviceNum = item.DeviceNum | |||
}); | |||
}); | |||
global.GoodsModels.Enqueue(new GoodsModel() { RawMaters = temp }); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -11,14 +11,18 @@ using NetTaste; | |||
using BPA.SingleDevice.Helper; | |||
using BPA.Model.Table; | |||
using Microsoft.EntityFrameworkCore.Metadata.Conventions; | |||
using BPA.SingleDevice.Services; | |||
namespace BPA.SingleDevice.ViewModel | |||
{ | |||
public class RawMaterialManagementViewModel : NotifyBase | |||
{ | |||
public RawMaterialManagementViewModel() | |||
private readonly ILogService logService; | |||
public RawMaterialManagementViewModel(ILogService logService) | |||
{ | |||
this.logService = logService; | |||
SqlHelper.GetInstance.GetListAsync<RawMaterTB>().Result.OnSuccess(s => | |||
{ | |||
s.ForEach(item => | |||
@@ -46,6 +50,8 @@ namespace BPA.SingleDevice.ViewModel | |||
}).Result.OnSuccess(() => | |||
{ | |||
RawMaterInfos.Add(new RawMaterInfo(id, rm.Name, rm.DeviceNum, rm.ChNum, time)); | |||
Message.Success("RawMaterialManagementView", $"添加物料【{rm.Name}】成功。"); | |||
logService.LogUserInfo($"成功添加物料【{rm.Name}】,设备号【{rm.DeviceNum}】,通道号【{rm.ChNum}】。"); | |||
}).OnFail(s => { Message.Error("RawMaterialManagementView", $"添加失败:{s}"); }); | |||
} | |||
}); | |||
@@ -82,6 +88,8 @@ namespace BPA.SingleDevice.ViewModel | |||
RawMaterInfos[index].DeviceNum = rm.DeviceNum; | |||
RawMaterInfos[index].WarehouseNum = rm.ChNum; | |||
RawMaterInfos[index].LastModified = time; | |||
Message.Success("RawMaterialManagementView", $"修改物料【{rm.Name}】成功。"); | |||
logService.LogUserInfo($"成功修改物料【{rm.Name}】,设备号【{rm.DeviceNum}】,通道号【{rm.ChNum}】。"); | |||
}).OnFail(s => { Message.Error("RawMaterialManagementView", $"修改失败:{s}"); }); | |||
} | |||
}); | |||
@@ -101,13 +109,16 @@ namespace BPA.SingleDevice.ViewModel | |||
{ | |||
SqlHelper.GetInstance.DeleteAsync<RawMaterTB>(o.ToString()).OnSuccess(() => | |||
{ | |||
var name = RawMaterInfos[index].Name; | |||
RawMaterInfos.RemoveAt(index); | |||
Message.Success("RawMaterialManagementView", $"删除物料【{name}】成功。"); | |||
logService.LogUserInfo($"成功移除物料【{name}】。"); | |||
}).OnFail(s => { Message.Error("RawMaterialManagementView", $"删除失败:{s}"); }); | |||
} | |||
} | |||
} | |||
}); | |||
} | |||
public ObservableCollection<RawMaterInfo> RawMaterInfos { get; set; } = new ObservableCollection<RawMaterInfo>(); | |||
@@ -0,0 +1,13 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace BPA.SingleDevice.ViewModel | |||
{ | |||
public class VarMonitorViewModel:NotifyBase | |||
{ | |||
} | |||
} |