You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

576 lines
22 KiB
C#

using Admin.Core.Common;
using Admin.Core.IService;
using Admin.Core.Model;
using Aucma.Core.HwPLc;
using Aucma.Core.Scanner;
using log4net;
using Microsoft.Extensions.DependencyInjection;
using StackExchange.Profiling.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Aucma.Core.Palletiz.Business
{
/// <summary>
///分垛入库业务处理
/// </summary>
public class InstoreBusiness
{
#region 单例实现
private static readonly InstoreBusiness lazy = new InstoreBusiness();
public static InstoreBusiness Instance
{
get
{
return lazy;
}
}
#endregion
#region 初始化对象
11 months ago
private static readonly log4net.ILog logHelper = LogManager.GetLogger(typeof(InstoreBusiness));
private readonly IBaseSpaceInfoServices? _baseSpaceInfoServices;
private readonly ICodeBindingRecordServices? _codeBindingServices;
11 months ago
private readonly IRecordInStoreServices? _recordInstoreServices;
#endregion
11 months ago
#region 构造函数
public InstoreBusiness()
{
_baseSpaceInfoServices = App.ServiceProvider.GetService<IBaseSpaceInfoServices>();
_codeBindingServices = App.ServiceProvider.GetService<ICodeBindingRecordServices>();
_recordInstoreServices = App.ServiceProvider.GetService<IRecordInStoreServices>();
MvCodeHelper.HandlePalletizDelegateEvent += ScannerInStore;//注册扫码器扫码后业务处理事件
}
#endregion
11 months ago
#region 变量定义
public readonly List<ScannerModel> allScanners = Appsettings.app<ScannerModel>("ScannerServer").ToList();
public readonly string storeCodeA = Appsettings.app("StoreInfo", "PalletizStoreCodeA");//分垛库A
public readonly string storeCodeB = Appsettings.app("StoreInfo", "PalletizStoreCodeB");//分垛库B
private static bool flagA = true;
private static bool flagB = true;
#endregion
#region 事件
#region 更新提醒信息
/// <summary>
/// 日志事件
/// </summary>
public delegate void LogInStoreInfoDelegate(string message, string color);
public static event LogInStoreInfoDelegate LogInStoreInfoDelegateEvent;
#endregion
#region 更新扫码信息
/// <summary>
/// 刷新扫码信息——图表和表格
/// </summary>
public delegate void ResherStoreInfoDelegate();
public static event ResherStoreInfoDelegate ResherStoreInfoDelegateEvent;
#endregion
#endregion
#region Test
[Obsolete("正式环境下使用ScannerInStore(string SNCode,string IP)")]
public void test()
{
// B240101 8302501416 0001 SN:16160030000000910999
Task.Run(async () =>
{
Thread.Sleep(3000);
await InStore("16160030000000910999", "192.168.1.19");
});
}
#endregion
#region 扫码入库
/// <summary>
/// 扫码入库
/// </summary>
/// <param name="SNCode">成品码</param>
/// <param name="IP">扫码器IP</param>
public void ScannerInStore(string SNCode,string IP)
{
Task.Run(async () =>
{
Thread.Sleep(3000);
await InStore(SNCode, IP);
});
}
#endregion
#region 扫码入库处理
/// <summary>
/// 扫码入库处理
/// </summary>
/// <param name="SNCode">成品码</param>
/// <param name="scannerIp">扫码器ip</param>
/// <returns></returns>
public async Task InStore(string SNCode, string scannerIp)
{
Console.WriteLine($"上位机接收到扫码器传入的成品码:{SNCode};扫码器IP:{scannerIp}");
LogInStoreInfoDelegateEvent?.Invoke($"上位机接收到扫码器传入的成品码:{SNCode};扫码器IP:{scannerIp}","White");
bool plcResult = false;// plc下发结果
List<int> spaceNumList = new List<int>();// 下发plc的货道号
RecordInStore recordInstore = new RecordInStore();// 入库记录
try
{
12 months ago
// 刷新页面
List<ScannerModel> allScanners = Appsettings.app<ScannerModel>("ScannerServer").ToList();
ScannerModel model = allScanners.First(x => x.Ip == scannerIp);
Console.WriteLine($"上位机获取配置的扫码器【IP:{model.ToJson()}》名称:{model.Name}】");
LogInStoreInfoDelegateEvent?.Invoke($"上位机获取配置的扫码器【IP:{model.ToJson()}》名称:{model.Name}】","White");
//1.根据成品码找货道
List<BaseSpaceInfo>? spaceList = GetSpaceBySNCode(SNCode, recordInstore);
Console.WriteLine($"上位机获取配置的货道数量【{spaceList.Count}】");
// 根据货道信息判断下发plc信号
if (spaceList == null || spaceList.Count == 0)
{
logHelper.Error("未找到匹配货道,请手动入库!");
// 刷新页面提示信息
Console.WriteLine("未找到匹配货道,请手动入库!");
LogInStoreInfoDelegateEvent?.Invoke("未找到匹配货道,请手动入库!", "White");
return;
}
// 过滤货道,找到最终需要下发的货道
BaseSpaceInfo finalSpace = FilterSpace(spaceList);
Console.WriteLine($"上位机获取需要下发的货道【货道名称:{finalSpace.SpaceName}》货道库存:{finalSpace.SpaceStock}》货道状态:{finalSpace.SpaceStatus}》货道类型:{finalSpace.SpaceType}》所属仓库:{finalSpace.StoreCode}】");
LogInStoreInfoDelegateEvent?.Invoke($"是否为大产品:【{finalSpace.IsTwoSpace}】", "White");
Console.WriteLine($"是否为大产品:【{finalSpace.IsTwoSpace}】");
LogInStoreInfoDelegateEvent?.Invoke($"下发的货道:【货道名称:{finalSpace.SpaceName}", "White");
// 大产品占两道
if (finalSpace.IsTwoSpace == 1)
{
spaceNumList.Add(int.Parse(finalSpace.SpaceCode.Substring(5, 3)));
spaceNumList.Add(int.Parse(GetOtherSpace(finalSpace, spaceList).SpaceCode.Substring(5, 3)));
plcResult = SendAndAnswerPlc(scannerIp, spaceList[0].RotationRange, spaceNumList);
recordInstore.SpaceCode = finalSpace.SpaceCode;
recordInstore.StoreCode = finalSpace.StoreCode;
// 更新货道信息,大产品last存objId大的储存上一个货道的主键 如货道7,8存8
BaseSpaceInfo otherSpace = GetOtherSpace(finalSpace, spaceList);
Console.WriteLine($"大产品入库信息:【{finalSpace.ToJson()}】【{spaceList.ToJson()}】");
if (otherSpace != null)
{
UpdateSapceList(otherSpace.ObjId, spaceList);
Console.WriteLine("更新货道信息成功!");
LogInStoreInfoDelegateEvent?.Invoke("更新货道信息成功!", "White");
}
}
else
{
// last不等于自己可以先入自己否则入另一条货道
if (IsOddNumber(finalSpace))
{
spaceNumList.Add(int.Parse(finalSpace.SpaceCode.Substring(5, 3)));
spaceNumList.Add(0);
plcResult = SendAndAnswerPlc(scannerIp, finalSpace.RotationRange, spaceNumList);
UpdateSapceList(finalSpace.ObjId, spaceList);
Console.WriteLine("更新货道信息成功!");
LogInStoreInfoDelegateEvent?.Invoke("更新货道信息成功!", "White");
}
else
{
spaceNumList.Add(0);
spaceNumList.Add(int.Parse(finalSpace.SpaceCode.Substring(5, 3)));
plcResult = SendAndAnswerPlc(scannerIp, finalSpace.RotationRange, spaceNumList);//给PLC下传入库信号
UpdateSapceList(finalSpace.ObjId, spaceList);
Console.WriteLine("更新货道信息成功!");
LogInStoreInfoDelegateEvent?.Invoke("更新货道信息成功!", "White");
}
}
if (plcResult == true)
{
// 更新入库记录,刷新界面
#region 添加入库记录
recordInstore.SpaceCode = finalSpace.SpaceCode;
recordInstore.StoreCode = finalSpace.StoreCode;
recordInstore.InStoreAmount = 1;
recordInstore.InStoreTime = DateTime.Now;
recordInstore.CreatedTime = DateTime.Now;
recordInstore.UpdateTime = DateTime.Now;
await _recordInstoreServices.AddAsync(recordInstore);
#endregion
}
else
{
// 界面提示手动入库
LogInStoreInfoDelegateEvent?.Invoke("界面提示手动入库!", "Red");
}
}
catch (Exception ex)
{
logHelper.Error(ex.Message.ToString());
return;
}
}
#region 根据成品码找货道
/// <summary>
/// 根据成品码找货道
/// </summary>
/// <param name="SNCode"></param>
/// <returns></returns>
private List<BaseSpaceInfo>? GetSpaceBySNCode(string SNCode, RecordInStore recordInstore)
{
try
{
CodeBindingRecord bindingRecord = _codeBindingServices.FirstAsync(c => c.ProductCode.Equals(SNCode)).Result;
if (bindingRecord == null) return null;
recordInstore.BarCodeCode = bindingRecord.BoxCode;
recordInstore.MaterialCode = bindingRecord.BoxCode;
recordInstore.MaterialType = bindingRecord.BoxCode.Substring(7, 10);
recordInstore.MaterialName = bindingRecord.BoxName;
string mType = bindingRecord.BoxCode.Substring(7, 10);
List<BaseSpaceInfo> bsInfo = _baseSpaceInfoServices.Query(s => (s.MaterialType.Equals(mType) && (s.StoreCode.Equals(storeCodeA)) || s.StoreCode.Equals(storeCodeB)));
if (bsInfo.Count > 0)
return bsInfo.OrderBy(x => x.ObjId).ToList();
else
return null;
}
catch (Exception ex)
{
logHelper.Error(ex.Message.ToString());
Console.WriteLine(ex.Message.ToString());
return null;
}
}
#endregion
private BaseSpaceInfo FilterSpace(List<BaseSpaceInfo> spaceInfos)
{
BaseSpaceInfo spaceInfo = spaceInfos.First();
if (spaceInfos.Count == 1 || string.IsNullOrEmpty(spaceInfo.LastSpace))
{
return spaceInfo;
}
List<BaseSpaceInfo> spaceList = spaceInfos.Where(s => s.ObjId > int.Parse(spaceInfo.LastSpace)).ToList();
if (spaceList == null || spaceList.Count == 0)
{
return spaceInfo;
}
else
{
return spaceInfo;
}
}
/// <summary>
/// 大产品占据两条货道,根据一条货道找到另一条货道
/// </summary>
/// <param name="spaceInfo"></param>
private BaseSpaceInfo GetOtherSpace(BaseSpaceInfo spaceInfo, List<BaseSpaceInfo> spaceList)
{
try
{
// 找到当前货道匹配的另一条货道
int num = int.Parse(spaceInfo.SpaceCode.Substring(5, 3));
string otherSpaceCode = string.Empty;
if (num % 2 == 0) // 偶数如7,8当前8找7
{
otherSpaceCode = spaceInfo.SpaceCode.Substring(0, 5) + (num - 1).ToString("D3");
}
else
{
otherSpaceCode = spaceInfo.SpaceCode.Substring(0, 5) + (num + 1).ToString("D3");
}
spaceList = spaceList.Where(s => s.SpaceCode.Equals(otherSpaceCode)).ToList();
if (spaceList.Count > 0)
{
return spaceList[0];
}
else
{
return null;
}
}
catch (Exception ex)
{
logHelper.Error(ex.Message.ToString());
Console.WriteLine($"大产品根据一条货道找到另一条货道异常:{ex.Message}");
return null;
}
}
/// <summary>
/// 判断货道编号是否为奇数
/// </summary>
/// <param name="space"></param>
/// <returns></returns>
private bool IsOddNumber(BaseSpaceInfo space)
{
int num = int.Parse(space.SpaceCode.Substring(5, 3));
if (num % 2 == 0)
{
return false;
}
else
{
return true;
}
}
/// <summary>
/// 将该物料的所有货道列表的last修改为上次入库货道objId
/// </summary>
/// <param name="objId"></param>
/// <param name="spaceList"></param>
/// <returns></returns>
private bool UpdateSapceList(int objId, List<BaseSpaceInfo> spaceList)
{
foreach (BaseSpaceInfo space in spaceList)
{
space.LastSpace = objId.ToString();
}
return _baseSpaceInfoServices.UpdateAsync(spaceList).Result;
}
#endregion
#region plc信号下发
#region 下发plc入库信号
/// <summary>
/// 下发plc入库信号
/// </summary>
/// <param name="scannerIp">扫码器ip</param>
/// <param name="range">转向角度</param>
/// <param name="spaceNum">货道号int集合</param>
/// <returns></returns>
private bool SendAndAnswerPlc(string scannerIp, int range, List<int> spaceNum)
{
bool result = false;
try
{
PlcModel obj = GetPlcByScanner(scannerIp);
if (obj != null)
{
if (SendPlc(obj, range, spaceNum))
{
result = WaitAnswerPlc(obj);
}
}
else
{
logHelper.Error("plc未连接");
return false;
}
return result;
}
catch (Exception ex)
{
logHelper.Error(ex.Message.ToString());
return result;
}
}
#endregion
#region 下发plc信号
/// <summary>
/// 下发plc信号
/// </summary>
/// <param name="obj"></param>
/// <param name="range"></param>
/// <param name="spaceNum"></param>
/// <returns></returns>
private bool SendPlc(PlcModel obj, int range, List<int> spaceNum)
{
try
{
bool result = false;
DateTime targetTime = DateTime.Now.AddSeconds(8);
while (true)
{
if (DateTime.Now > targetTime) // plc超最大时限无反馈
{
logHelper.Error("等待plc放行反馈信号超时");
Console.WriteLine("等待plc放行反馈信号超时");
return false;
}
// 应答字允许下发
Console.WriteLine($"读取应答字是否下传成功!【{obj.plc.ReadInt32("D102")}】");
if (obj.plc.ReadInt32("D102") == 1)
{
//obj.plc.WriteInt32("D110", range);//旋转角度暂时不赋值由PLC转向
obj.plc.WriteInt32("D112", spaceNum[0]); //货道号
obj.plc.WriteInt32("D114", spaceNum[1]); //货道号
Console.WriteLine($"plc信号货道信号下发成功!【D112:{spaceNum[0]}】D114:{spaceNum[1]}");
result = true;
break;
}
Thread.Sleep(500);
}
return result;
}
catch (Exception ex)
{
logHelper.Error(ex.Message);
return false;
}
}
#endregion
#region 等待plc信号反馈
/// <summary>
/// 等待plc信号反馈
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
private bool WaitAnswerPlc(PlcModel obj)
{
try
{
bool result = false;
DateTime targetTime = DateTime.Now.AddSeconds(8);
while (true)
{
if (DateTime.Now > targetTime) // plc超最大时限无反馈
{
logHelper.Error("等待plc放行反馈信号超时");
Console.WriteLine("等待plc放行反馈信号超时");
return false;
}
// 应答字允许下发
if (obj.plc.ReadInt32("D102") == 2)
{
result = true;
Console.WriteLine("下发成功!");
break;
}
Thread.Sleep(500);
}
return result;
}
catch (Exception ex)
{
logHelper.Error(ex.Message.ToString());
return false;
}
}
#endregion
#region 根据扫码器ip确定是属于哪个plc
/// <summary>
/// 根据扫码器ip确定是属于哪个plc
/// </summary>
/// <param name="scannerIp"></param>
/// <returns></returns>
private PlcModel GetPlcByScanner(string scannerIp)
{
PlcModel obj = null;
ScannerModel model = allScanners.FirstOrDefault(x => x.Ip == scannerIp);
if (model.Id < 3)
{
obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("InStoreAPlc"));
}
else
{
obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("InStoreBPlc"));
}
return obj;
}
#endregion
#endregion
#region 手动写入货道号给PLC数据
/// <summary>
/// 手动写入PLC数据
/// </summary>
/// <returns></returns>
public static bool WritePlc(Models.StackInfoModel tempStackInfo)
{
var obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("InStorePlc"));
//写入PLC
if (obj.plc.IsConnected)
{
//1、判断是否为大产品、占用两个货道 上位机两条道设置为相同型号
if (tempStackInfo.IsLargeProducts)
{
obj.plc.WriteInt16("D7000", tempStackInfo.BinNo.ToString());//写入货道
obj.plc.WriteInt16("D7100", tempStackInfo.BinNo.ToString());//写入货道
}
else
{
//判断入库货道
if (tempStackInfo.BinNo / 2 == 0)
{
obj.plc.WriteInt16("D7000", tempStackInfo.BinNo.ToString());//写入货道
obj.plc.WriteInt16("D7100", "0");//写入货道
}
else
{
obj.plc.WriteInt16("D7000", "0");//写入货道
obj.plc.WriteInt16("D7100", tempStackInfo.BinNo.ToString());//写入货道
}
}
obj.plc.WriteInt16("D7020", "1");//同时写入应答字
Console.WriteLine("手动写入PLC成功");
do
{
#region 1号区域码垛——A
int responseWord1 = obj.plc.ReadInt16("D7020");//读取1号区域码垛 等待应答字回去
Console.WriteLine($"获取应答信号:{responseWord1}");
if (responseWord1 == 2)
{
//清空货道
obj.plc.WriteInt16("D7000", "0");
obj.plc.WriteInt16("D7100", "0");
flagA = false;
}
#endregion
} while (flagA);
}
//更新货道
return false;
}
private static void GetResposeB()
{
var obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("InStorePlc"));
//写入PLC
if (obj.plc.IsConnected)
{
do
{
#region 2号区域码垛——B
int responseWord2 = obj.plc.ReadInt16("D7120");//读取1号区域码垛 等待应答字回去
Console.WriteLine("手动写入PLC成功");
if (responseWord2 == 2)
{
obj.plc.WriteInt16("D7000", "0");//清空
}
#endregion
} while (flagA);
}
}
#endregion
}
}