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.

543 lines
19 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Admin.Core.Common;
using Admin.Core.Common.Helper;
using Admin.Core.IService;
using Admin.Core.Model;
using Admin.Core.Model.Model_New;
using Admin.Core.Service;
using Admin.Core.Socket;
using Aucma.Core.HwPLc;
using Aucma.Core.Palletiz.config;
using Aucma.Core.Palletiz.Models;
using Aucma.Core.Palletiz.ViewModels;
using log4net;
using Microsoft.Extensions.DependencyInjection;
using NPOI.SS.Formula.UDF;
using NPOI.SS.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Interop;
using TouchSocket.Sockets;
namespace Aucma.Core.Palletiz.Business
{
internal class InStoreBusiness
{
private static readonly log4net.ILog _logger = LogManager.GetLogger(typeof(InStoreBusiness));
private readonly IProductOffLineServices _offlineService;
private readonly IBaseSpaceInfoServices _spaceinfoService;
private readonly AppConfig _appConfig;
private AppConfig appConfig = new AppConfig();
public string storeCode = Appsettings.app("StoreInfo", "PalletizStoreCodeA");
// 过点数据表物料完成记录MaterialCompletion
private readonly IMaterialCompletionServices? _iMaterialCompletionServices = App.ServiceProvider.GetService<IMaterialCompletionServices>();
private readonly IPrintBarCodeServices? _printBarCodeServices = App.ServiceProvider.GetService<IPrintBarCodeServices>();
private readonly ICodeBindingRecordServices? _codeBindingServices = App.ServiceProvider.GetService<ICodeBindingRecordServices>();
private readonly IRecordInStoreServices? _recordInstoreServices = App.ServiceProvider.GetService<IRecordInStoreServices>();
#region 委托事件
/// <summary>
/// 扫码信息刷新
/// </summary>
public delegate void RefreshProductInfo(string productCode, string productModel, string orderCode);
public static event RefreshProductInfo? RefreshProductInfoEvent;
/// <summary>
/// 提示信息刷新
/// </summary>
public delegate void RefreshMsg(string msg);
public static event RefreshMsg? RefreshMsgEvent;
/// <summary>
///入库时DataGrid添加一条DataGrid记录
/// </summary>
public delegate void AddData(RecordInStore record);
public static event AddData? AddDataEvent;
#endregion
// private const string BarcodeRef = "6933973114570;1621240AP0098E3D3497";
private PlcModel plcCon = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("InStoreAPlc"));
public InStoreBusiness()
{
_appConfig = new AppConfig();
_spaceinfoService = App.ServiceProvider.GetService<IBaseSpaceInfoServices>();
_offlineService = App.ServiceProvider.GetService<IProductOffLineServices>();
HandPalletizViewModel.HandSendEvent += InStore;
// string AA = ExtractNumber("FD01_012");
}
public void Init()
{
TouchSocketService.ReceivedClientBufferEvent += ReceivedBuffer;
}
/// <summary>
/// Buffer缓冲
/// </summary>
/// <param name="buffer"></param>
private void ReceivedBuffer(SocketClient client, byte[] buffer)
{
try
{
//_logger.LogInformation($"接收客户端:{client.Id};原始报文:{_stringChange.bytesToHexStr(buffer, buffer.Length)}");
do
{
string asciiStr = Encoding.ASCII.GetString(buffer);
if (asciiStr.Contains("heartbeat"))
{
// _logger.Info($"收到客户端:{client.Id};心跳指令:{asciiStr}");
continue;
}
if (asciiStr.Contains("NoRead"))
{
NoReadHandle(client.Id);
continue;
}
// _logger.Info($"收到客户端:{client.Id}条码信息:{asciiStr}");
InStore(client.Id, asciiStr);
} while (false);
}
catch (Exception e)
{
_logger.Error($"Buffer缓冲异常:{e.Message}");
}
}
/// <summary>
/// 入库申请
/// </summary>
/// <param name="spaceArea">货道区域</param>
/// <param name="asciiStr">20位是正常扫码传输的条码,手动入库传的是人工选择的成品型号</param>
private void InStore(string spaceArea, string asciiStr)
{
RecordInStore recordInstore = new RecordInStore();
String msg = string.Empty;
try
{
if (string.IsNullOrEmpty(asciiStr))
{
throw new ArgumentException($"入库申请处理异常:条码信息为空");
}
if (string.IsNullOrEmpty(spaceArea))
{
throw new ArgumentException($"入库申请处理异常:货道区域为空");
}
_offlineService.GetProductInfosBySnCode(asciiStr, out ProductOffline prodInfo);
if (prodInfo == null)
{
throw new ArgumentException($"入库申请处理异常:根据成品码获取成品信息为空");
}
RefreshProductInfoEvent?.Invoke(asciiStr,prodInfo.ProductModel,prodInfo.ProductOrderNo);
GetSpaceInfoByMaterialType(spaceArea, prodInfo, out BaseSpaceInfo laseSpaceinfo,
out BaseSpaceInfo spaceinfo);
bool result = false;
SendInStoreTask(asciiStr,spaceinfo, ref result,Convert.ToInt32(prodInfo.ProductMasterModel),ref msg,out int range);
#region 添加入库记录
recordInstore.StoreCode = storeCode;
recordInstore.StoreArea = spaceArea;
recordInstore.SpaceCode = spaceinfo.SpaceCode;
recordInstore.MaterialType = spaceinfo.MaterialType;
recordInstore.MaterialCode = spaceinfo.MaterialType;
recordInstore.InStoreTime = DateTime.Now;
recordInstore.BarCodeCode = asciiStr;
recordInstore.MaterialName = prodInfo.ProductName;
recordInstore.InStoreAmount = range ;
recordInstore.IsFlag = 0;
recordInstore.CreatedTime = DateTime.Now;
if (asciiStr.Length < 20)
{
recordInstore.EntryPattern = 1;
}
else
{
recordInstore.EntryPattern = 0;
}
#endregion
if (!result)
{
msg = msg + "放行失败";
RefreshMsgEvent?.Invoke(msg);
throw new ArgumentException($"入库申请处理异常:入库任务下发至PLC失败");
}
else
{
msg = msg + "放行成功";
RefreshMsgEvent?.Invoke(msg);
List<BaseSpaceInfo> spaceinfos = new List<BaseSpaceInfo>();
if (laseSpaceinfo != null)
{
laseSpaceinfo.InStoreFlag = 1;
spaceinfos.Add(laseSpaceinfo);
}
spaceinfo.InStoreFlag = 3;
spaceinfos.Add(spaceinfo);
_spaceinfoService.UpdateSpaceInfo(spaceinfos);
//刷新页面
AddDataEvent?.Invoke(recordInstore);
}
_ = _recordInstoreServices.AddAsync(recordInstore).Result;
}
catch (Exception e)
{
msg =$"入库逻辑处理异常:{e.Message}";
RefreshMsgEvent?.Invoke(msg);
}
}
/// <summary>
/// 添加过点数据,暂不添加
/// </summary>
/// <returns></returns>
public async Task AddCompleteData(string ProductSnCode)
{
CodeBindingRecord bindingRecord1 = _codeBindingServices.FirstAsync(x => x.ProductCode == ProductSnCode).Result;
#region 更新过点数据
if (bindingRecord1 != null && bindingRecord1.BoxCode != "")
{
PrintBarCode print = _printBarCodeServices.FirstAsync(x => x.MaterialBarcode == bindingRecord1.BoxCode).Result;
if (print != null)
{
MaterialCompletion completion = new MaterialCompletion();
completion.OrderCode = print.OrderCode;
completion.MaterialBarcode = bindingRecord1.BoxCode;
completion.MaterialCode = print.MaterialCode;
completion.MaterialName = print.MaterialName;
// completion.StationName = "1009";
completion.CompleteDate = DateTime.Now;
completion.ProductLineCode = "CX_02";
completion.isDownLine = 1;
completion.ProductionCode = ProductSnCode;
_ = _iMaterialCompletionServices.AddAsync(completion).Result;
}
}
#endregion
}
/// <summary>
/// 通过物料型号获取货道信息
/// </summary>
/// <param name="spaceArea"></param>
/// <param name="prodInfo"></param>
/// <param name="laseSpaceinfo"></param>
/// <param name="spaceinfo"></param>
/// <param name="isBig"></param>
/// <exception cref="ArgumentException"></exception>
private void GetSpaceInfoByMaterialType(string spaceArea, ProductOffline prodInfo, out BaseSpaceInfo laseSpaceinfo, out BaseSpaceInfo spaceinfo, bool isBig = false)
{
List<BaseSpaceInfo> spaceinfos = null;
if (isBig)
{
_spaceinfoService.GetSpaceInfosByExpression(out spaceinfos, x => x.StoreCode == _appConfig.storeCode && x.SpaceArea == spaceArea && x.MaterialType == prodInfo.ProductCode && x.SpaceType == 2);
}
else
{
_spaceinfoService.GetSpaceInfosByExpression(out spaceinfos, x => x.StoreCode == _appConfig.storeCode && x.SpaceArea == spaceArea && x.MaterialType == prodInfo.ProductCode);
}
if (spaceinfos == null || spaceinfos.Count==0)
{
throw new ArgumentException($"通过物料型号获取货道信息异常:根据成品信息获取货道信息为空");
}
spaceinfos = spaceinfos.OrderBy(x => x.ObjId).ToList();
MatchSpaceInfoByPlc(ref spaceinfos);
if (spaceinfos == null || spaceinfos.Count==0)
{
throw new ArgumentException($"通过物料型号获取货道信息异常:通过PLC匹配可用货道信息为空");
}
FiltrateSpaceInfo(spaceinfos, out laseSpaceinfo, out spaceinfo);
if (spaceinfo == null || spaceinfos.Count==0)
{
throw new ArgumentException($"通过物料型号获取货道信息异常:未获取到匹配的货道信息");
}
}
/// <summary>
/// 通过PLC匹配获取去除已满的货道
/// </summary>
/// <param name="spaceinfos"></param>
private void MatchSpaceInfoByPlc(ref List<BaseSpaceInfo> spaceinfos)
{
if (plcCon == null)
{
Task.Delay(1000 * 3).Wait();
plcCon = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("InStoreAPlc"));
if(plcCon == null)
{
throw new ArgumentException($"通过PLC匹配获取货道信息异常:Plc连接为空");
}
}
var _plc = plcCon.plc;
foreach (var item in spaceinfos)
{
item.SpaceCode = ExtractNumber(item.SpaceName);
var plcAddress = _appConfig.plcAddr.Where(x => x.spaceCode.ToString() == item.SpaceCode && x.spaceArea == item.SpaceArea).First();
bool isFlag = _plc.ReadBool(plcAddress.address);
if (isFlag)
{
item.SpaceStatus = 3;
}
}
spaceinfos = spaceinfos.Where(x => x.SpaceStatus != 3).ToList();
}
/// <summary>
/// 筛选货道信息
/// </summary>
/// <param name="spaceinfos"></param>
/// <param name="spaceinfo"></param>
/// <exception cref="ArgumentException"></exception>
private void FiltrateSpaceInfo(List<BaseSpaceInfo> spaceinfos, out BaseSpaceInfo laseSpaceinfo, out BaseSpaceInfo spaceinfo)
{
if (spaceinfos == null || spaceinfos.Count == 0)
{
throw new ArgumentException($"筛选货道信息异常:传入货道信息参数为空");
}
int count = spaceinfos.Where(x => x.InStoreFlag == 3).ToList().Count;
if (count > 0)
{
int index = spaceinfos.FindIndex(entity => entity.InStoreFlag == 3);
laseSpaceinfo = spaceinfos[index];
int nextIndex = (index + 1) % spaceinfos.Count;
spaceinfo = spaceinfos[nextIndex];
}
else
{
laseSpaceinfo = null;
spaceinfo = spaceinfos.First();
}
}
/// <summary>
/// 下发入库任务至PLC
/// </summary>
/// <param name="spaceinfo"></param>
/// <param name="result"></param>
/// <exception cref="ArgumentException"></exception>
private void SendInStoreTask(string asciiStr, BaseSpaceInfo spaceinfo, ref bool result,int prodWeight,ref string msg,out int rangeResult)
{
int spinFlag = -1;
rangeResult = 0;
if (plcCon == null)
{
throw new ArgumentException($"下发入库任务至PLC逻辑异常:Plc连接为空");
}
var _plc = plcCon.plc;
bool isFlag = true;
int spaceCode = StringChange.ParseToInt(spaceinfo.SpaceCode);
spinFlag =JudgeRotation(spaceCode, prodWeight, out int ranges);
rangeResult = ranges;
if (spinFlag == -1)
{
msg = $"成品码:{asciiStr},仓库区域:{spaceinfo.SpaceArea},匹配货道:{spaceinfo.SpaceCode};旋转角度匹配失败,请先设置该型号旋转规则!";
RefreshMsgEvent?.Invoke(msg);
return;
}
msg = $"成品码:{asciiStr},仓库区域:{spaceinfo.SpaceArea},匹配货道:{spaceinfo.SpaceCode};旋转:{(spinFlag == 3 ? "0°" : "180°")};下发plc放行信号";
RefreshMsgEvent?.Invoke(msg);
DateTime startTime = DateTime.Now;
while (isFlag)
{
if((DateTime.Now - startTime).TotalSeconds > 15)
{
result = false;
return;
}
bool answerFlag = _plc.ReadBool("B1000");
if (answerFlag)
{
isFlag = false;
}
Task.Delay(500).Wait();
}
if (spaceinfo.SpaceArea == "A")
{
if (!_plc.WriteInt16("D2", spinFlag.ToString()))
{
throw new ArgumentException($"旋转角度下发至PLC失败");
}
if (!_plc.WriteInt16("D29", spaceCode.ToString()))
{
throw new ArgumentException($"货道号下发至PLC失败");
}
_plc.WriteInt16("B1001", "1");//发送完成信号
result = true;
}
else if (spaceinfo.SpaceArea == "B")
{
result = false;
}
}
/// <summary>
/// 根据货物容积确定旋转规则 转180度发1不转发3
/// </summary>
/// <param name="prodWeight"></param>
/// <returns></returns>
public int JudgeRotation(int spaceCode,int prodWeight, out int ranges)
{
try
{
List<JumpRange> list = appConfig.GetJumpRanges();
foreach (JumpRange range in list)
{
if (range.MinModel <= prodWeight && range.MaxModel > prodWeight) // 找到该型号规则
{
if (spaceCode % 2 == 0) // 偶数货道
{
ranges = range.EvenSpaceRange;
return RangeToInt(range.EvenSpaceRange);
}
else
{
ranges = range.OddSpaceRange;
return RangeToInt(range.OddSpaceRange);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("JudgeRotation"+ex.Message);
}
ranges = 0;
return -1;
}
public int RangeToInt(int range)
{
int result = -1;
switch (range) {
case 0: result = 3; break;
case 90: result = 1; break;
case 180: result = 4; break;
case 270: result = 2; break;
}
return result;
}
/// <summary>
/// 提取货道号
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private static string ExtractNumber(string input)
{
string pattern = @"\d+";
Match match = Regex.Match(input, pattern);
if (match.Success)
{
return match.Value.TrimStart('0');
}
else
{
return null; // 或者返回默认值,如"0"
}
}
/// <summary>
/// 读取失败处理
/// </summary>
/// <param name="client"></param>
private void NoReadHandle(string client)
{
_logger.Error($"客户端:{client};读取失败!!!!!!");
}
/// <summary>
/// 获取成品库指定区域的货道信息
/// </summary>
/// <param name="spaceArea"></param>
/// <returns></returns>
public List<BaseSpaceInfo> GetBaseSpaceinfos(string spaceArea)
{
_spaceinfoService.GetSpaceInfosByExpression(out List<BaseSpaceInfo> spaceinfos, x => x.StoreCode == _appConfig.storeCode && x.SpaceArea == spaceArea);
return spaceinfos;
}
/// <summary>
/// 获取货道信息
/// </summary>
/// <param name="spaceArea"></param>
/// <returns></returns>
public BaseSpaceInfo GetSpaceinfosById(int id)
{
BaseSpaceInfo spaceInfo = _spaceinfoService.FirstAsync(x=>x.ObjId==id).Result;
return spaceInfo;
}
}
}