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