소스 검색

1. 单机配方流程编写及单体设备控制。

master
Nah 1 년 전
부모
커밋
3676a3061b
32개의 변경된 파일1246개의 추가작업 그리고 116개의 파일을 삭제
  1. +32
    -0
      BPA.Model/Enums/BatchStep.cs
  2. +15
    -0
      BPA.Model/Enums/MoveConveyer.cs
  3. +16
    -2
      BPA.Model/GlobalData.cs
  4. +47
    -0
      BPA.Model/Recipe/RecipeData.cs
  5. +30
    -0
      BPA.Model/TaskServer.cs
  6. +19
    -4
      BPA.SingleDevice/App.xaml.cs
  7. +75
    -0
      BPA.SingleDevice/Business/Batcher.cs
  8. +138
    -0
      BPA.SingleDevice/Business/Conveyer.cs
  9. +42
    -42
      BPA.SingleDevice/Business/MainControl.cs
  10. +311
    -0
      BPA.SingleDevice/Business/ProcessControl.cs
  11. +48
    -0
      BPA.SingleDevice/Interface/IBatchcer.cs
  12. +84
    -0
      BPA.SingleDevice/Interface/IConveyer.cs
  13. +16
    -0
      BPA.SingleDevice/Interface/IProcessControl.cs
  14. +30
    -0
      BPA.SingleDevice/Json/ConnectConfig.cs
  15. +1
    -1
      BPA.SingleDevice/Services/ILogService.cs
  16. +1
    -1
      BPA.SingleDevice/Services/LogService.cs
  17. +1
    -1
      BPA.SingleDevice/View/AddRawMaterialDialogView.xaml
  18. +43
    -0
      BPA.SingleDevice/View/DebugView.xaml
  19. +30
    -0
      BPA.SingleDevice/View/DebugView.xaml.cs
  20. +6
    -6
      BPA.SingleDevice/View/OrderMainView.xaml
  21. +3
    -1
      BPA.SingleDevice/View/OrderMainView.xaml.cs
  22. +2
    -2
      BPA.SingleDevice/View/RawMaterialManagementView.xaml
  23. +3
    -1
      BPA.SingleDevice/View/RawMaterialManagementView.xaml.cs
  24. +12
    -0
      BPA.SingleDevice/View/VarMonitorView.xaml
  25. +30
    -0
      BPA.SingleDevice/View/VarMonitorView.xaml.cs
  26. +2
    -1
      BPA.SingleDevice/ViewModel/AddRawMaterialDialogViewModel.cs
  27. +12
    -12
      BPA.SingleDevice/ViewModel/AlarmLogViewModel.cs
  28. +27
    -0
      BPA.SingleDevice/ViewModel/DebugViewModel.cs
  29. +5
    -2
      BPA.SingleDevice/ViewModel/MainViewModel.cs
  30. +138
    -37
      BPA.SingleDevice/ViewModel/OrderMainViewModel.cs
  31. +14
    -3
      BPA.SingleDevice/ViewModel/RawMaterialManagementViewModel.cs
  32. +13
    -0
      BPA.SingleDevice/ViewModel/VarMonitorViewModel.cs

+ 32
- 0
BPA.Model/Enums/BatchStep.cs 파일 보기

@@ -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
}
}

+ 15
- 0
BPA.Model/Enums/MoveConveyer.cs 파일 보기

@@ -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,
}
}

+ 16
- 2
BPA.Model/GlobalData.cs 파일 보기

@@ -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
}
}

+ 47
- 0
BPA.Model/Recipe/RecipeData.cs 파일 보기

@@ -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);
}
}

}
}

+ 30
- 0
BPA.Model/TaskServer.cs 파일 보기

@@ -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();
}
}

+ 19
- 4
BPA.SingleDevice/App.xaml.cs 파일 보기

@@ -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();
}


+ 75
- 0
BPA.SingleDevice/Business/Batcher.cs 파일 보기

@@ -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;
}
}
}

+ 138
- 0
BPA.SingleDevice/Business/Conveyer.cs 파일 보기

@@ -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;
}
}
}

+ 42
- 42
BPA.SingleDevice/Business/MainControl.cs 파일 보기

@@ -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()


+ 311
- 0
BPA.SingleDevice/Business/ProcessControl.cs 파일 보기

@@ -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:上升沿信号检测。
}
}

}

+ 48
- 0
BPA.SingleDevice/Interface/IBatchcer.cs 파일 보기

@@ -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();
}
}

+ 84
- 0
BPA.SingleDevice/Interface/IConveyer.cs 파일 보기

@@ -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();
}
}

+ 16
- 0
BPA.SingleDevice/Interface/IProcessControl.cs 파일 보기

@@ -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();
}
}

+ 30
- 0
BPA.SingleDevice/Json/ConnectConfig.cs 파일 보기

@@ -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; }
}
}

+ 1
- 1
BPA.SingleDevice/Services/ILogService.cs 파일 보기

@@ -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;
}
}

+ 1
- 1
BPA.SingleDevice/Services/LogService.cs 파일 보기

@@ -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)


+ 1
- 1
BPA.SingleDevice/View/AddRawMaterialDialogView.xaml 파일 보기

@@ -48,7 +48,7 @@
HorizontalAlignment="Right"
FontSize="16"
Foreground="#ddd"
Text="设备编号:" />
Text="设备对应工位:" />
<ComboBox
Grid.Row="1"
Grid.Column="1"


+ 43
- 0
BPA.SingleDevice/View/DebugView.xaml 파일 보기

@@ -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>

+ 30
- 0
BPA.SingleDevice/View/DebugView.xaml.cs 파일 보기

@@ -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>();
}
}
}

+ 6
- 6
BPA.SingleDevice/View/OrderMainView.xaml 파일 보기

@@ -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="开始下单"


+ 3
- 1
BPA.SingleDevice/View/OrderMainView.xaml.cs 파일 보기

@@ -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>();
}
}
}

+ 2
- 2
BPA.SingleDevice/View/RawMaterialManagementView.xaml 파일 보기

@@ -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">


+ 3
- 1
BPA.SingleDevice/View/RawMaterialManagementView.xaml.cs 파일 보기

@@ -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>();
}
}
}

+ 12
- 0
BPA.SingleDevice/View/VarMonitorView.xaml 파일 보기

@@ -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>

+ 30
- 0
BPA.SingleDevice/View/VarMonitorView.xaml.cs 파일 보기

@@ -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>();
}
}
}

+ 2
- 1
BPA.SingleDevice/ViewModel/AddRawMaterialDialogViewModel.cs 파일 보기

@@ -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); });


+ 12
- 12
BPA.SingleDevice/ViewModel/AlarmLogViewModel.cs 파일 보기

@@ -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(() =>
{


+ 27
- 0
BPA.SingleDevice/ViewModel/DebugViewModel.cs 파일 보기

@@ -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; }
}
}

+ 5
- 2
BPA.SingleDevice/ViewModel/MainViewModel.cs 파일 보기

@@ -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);


+ 138
- 37
BPA.SingleDevice/ViewModel/OrderMainViewModel.cs 파일 보기

@@ -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 });
}
}
}
}
}

+ 14
- 3
BPA.SingleDevice/ViewModel/RawMaterialManagementViewModel.cs 파일 보기

@@ -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>();


+ 13
- 0
BPA.SingleDevice/ViewModel/VarMonitorViewModel.cs 파일 보기

@@ -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
{

}
}

불러오는 중...
취소
저장