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.

391 lines
16 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 Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SlnMesnac.Business.@base;
using SlnMesnac.Common;
using SlnMesnac.Config;
using SlnMesnac.Model.domain;
using SlnMesnac.Model.dto;
using SlnMesnac.Plc;
using SlnMesnac.Repository.service;
using SlnMesnac.Rfid;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using static System.Net.Mime.MediaTypeNames;
#region << 版 本 注 释 >>
/*--------------------------------------------------------------------
* 版权所有 (c) 2024 WenJY 保留所有权利。
* CLR版本4.0.30319.42000
* 机器名称LAPTOP-E0N2L34V
* 命名空间SlnMesnac.Business
* 唯一标识f79d6d97-d9b0-4b0b-a442-e6bb1c1c79e6
*
* 创建者WenJY
* 电子邮箱wenjy@mesnac.com
* 创建时间2024-04-10 16:36:01
* 版本V1.0.0
* 描述:
*
*--------------------------------------------------------------------
* 修改人:
* 时间:
* 修改说明:
*
* 版本V1.0.0
*--------------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
namespace SlnMesnac.Business
{
/// <summary>
/// 设备产出业务逻辑
/// </summary>
public class ProdCompletionBusiness : BaseBusiness
{
private readonly IMesProductPlanService _mesProductPlanService;
private readonly IMesProductOrderService _mesProductOrderService;
private readonly IMesPrdBarCodeService _barCodeTaskService;
private readonly IMesBaseBarcodeInfoService _mesBaseBarcodeInfoService;
public readonly IMesPrdBarCodeService _mesPrdBarCodeService;
private readonly IRealPalletTaskService _realPalletTaskService;
private ISqlSugarClient sqlSugarClient;
public ProdCompletionBusiness(ISqlSugarClient _sqlSugarClient,ILogger<BaseBusiness> logger, AppConfig appConfig, List<PlcAbsractFactory> plcFactories, List<RfidAbsractFactory> rfidFactories, IMesProductPlanService mesProductPlanService, IMesPrdBarCodeService barCodeTaskService, IServiceProvider serviceProvider) : base(logger, appConfig, plcFactories, rfidFactories, serviceProvider)
{
sqlSugarClient = _sqlSugarClient;
_mesProductPlanService = mesProductPlanService;
_barCodeTaskService = barCodeTaskService;
_realPalletTaskService = serviceProvider.GetRequiredService<IRealPalletTaskService>();
_mesBaseBarcodeInfoService = serviceProvider.GetRequiredService<IMesBaseBarcodeInfoService>();
_mesPrdBarCodeService = serviceProvider.GetRequiredService<IMesPrdBarCodeService>();
_mesProductOrderService = serviceProvider.GetRequiredService<IMesProductOrderService>();
Init();
}
private void test()
{
string epc = "A123456";
_mesProductPlanService.GetStartedProdPlan(out MesProductPlanDto productPlanDto);
string bigCode = GenerateBigBarcode(productPlanDto, epc);
BindingBarCode(bigCode, epc);
}
public void Init()
{
Task.Run(() =>
{
EmptyPalletHandle();
});
Task.Run(() =>
{
DeviceOutPutHandle();
});
}
/// <summary>
/// 设备产出逻辑处理
/// </summary>
private async void DeviceOutPutHandle()
{
// 读取RFID失败重试次数超过5次推送报警
int readRfidAmount = 0;
while(true)
{
try
{
var plc = base.GetPlcByKey("plc");
if (plc == null)
{
_logger.LogInformation("读取小包出口信号,PLC连接信息为空......");
Thread.Sleep(3000);
continue;
}
if (plc.readByteByAddress(GetPlcAddressByConfigKey("2楼小包出口到位信号"))!=1)
{
_logger.LogInformation("等待小包出口信号触发......");
Thread.Sleep(5000);
continue;
}
string epcStr = await ReadEpcStrByRfidKeyAsync("secondFloorOut");
if (string.IsNullOrEmpty(epcStr))
{
_logger.LogError("小包出口到位信号触发,读取RFID失败......");
//判断前一位置是否有托盘缓存
RealPalletTask realPalletTask = _realPalletTaskService.Query().FirstOrDefault();
if (realPalletTask != null)
{
epcStr = realPalletTask.PalletCode;
}
else
{
readRfidAmount++;
if(readRfidAmount == 5)
{
//TODO 推送报警
_logger.LogError("小包出口到位信号触发,读取RFID失败超过5次......");
}
Thread.Sleep(1000 * 5);
continue;
}
}
RefreshMessage($"小包出口读取到RFID条码{epcStr},开始绑定流程:");
_mesProductPlanService.GetStartedProdPlan(out MesProductPlanDto productPlanDto);
if (productPlanDto == null)
{
//TODO:没有计划的话,处理方式待定
throw new ArgumentException($"未获取到正在执行的生产计划");
}
#region 开启事务
sqlSugarClient.AsTenant().BeginTran();
//1.生成大条码插入mes_barcode_info
string bigCode =GenerateBigBarcode(productPlanDto, epcStr);
//2.40个小条码及大条码绑定托盘号,小条码绑定大条码
BindingBarCode(bigCode,epcStr);
//3.更新mes_product_plan及mes_product_order表更新已生产数量
UpdatePlanInfoAndOrder(productPlanDto);
// 删除正在使用的数据库托盘号
RealPalletTask realPallet = _realPalletTaskService.Query(x => x.PalletCode == epcStr).FirstOrDefault();
if (realPallet != null)
{
sqlSugarClient.AsTenant().GetConnection("mes").Deleteable(realPallet).ExecuteCommand();
}
// 写入PLC RFID号供调度使用
plc.writeStringByAddress(GetPlcAddressByConfigKey("2楼码垛出口RFID条码地址"), epcStr);
plc.writeByteByAddress(GetPlcAddressByConfigKey("2楼小包出口到位信号"),2);
readRfidAmount = 0;
sqlSugarClient.AsTenant().CommitTran();
#endregion
}
catch (Exception ex)
{
sqlSugarClient.AsTenant().RollbackTran();
// TODO:推送报警
_logger.LogError($"DeviceOutPutHandle异常:{ex.Message}");
}
Thread.Sleep(1000 * 5);
}
}
/// <summary>
/// 生成大条码插入mes_barcode_info
/// </summary>
/// <param name="productPlanDto"></param>
/// <param name="epcStr"></param>
/// <returns></returns>
private string GenerateBigBarcode(MesProductPlanDto productPlanDto,string epcStr)
{
string bigBarcode = productPlanDto.PlanCode+DateTime.Now.ToString("_MMddHHmmss");
MesBaseBarcodeInfo mesBaseBarcodeInfo = new MesBaseBarcodeInfo();
mesBaseBarcodeInfo.printTime = DateTime.Now;
mesBaseBarcodeInfo.printPerson = "SlnMesnac";
mesBaseBarcodeInfo.printFlag = "1";
mesBaseBarcodeInfo.batchFlag = "0";
mesBaseBarcodeInfo.barcodeType = "3";
mesBaseBarcodeInfo.barcodeInfo = bigBarcode;
mesBaseBarcodeInfo.batchCode = bigBarcode;
mesBaseBarcodeInfo.palletInfoCode = epcStr;
mesBaseBarcodeInfo.materialId = productPlanDto.MaterialId;
mesBaseBarcodeInfo.amount = 1;
mesBaseBarcodeInfo.printNumber = 1;
mesBaseBarcodeInfo.productionDate = DateTime.Now;
mesBaseBarcodeInfo.acceptedDate = DateTime.Now;
mesBaseBarcodeInfo.planCode = productPlanDto.PlanCode;
mesBaseBarcodeInfo.safeFlag = productPlanDto.SaleOrderId ==0 ?"1" : "0";
mesBaseBarcodeInfo.saleOrderId = productPlanDto.SaleOrderId;
mesBaseBarcodeInfo.saleorderCode = productPlanDto.SaleorderCode;
mesBaseBarcodeInfo.bindStatus = "1";
mesBaseBarcodeInfo.bindTime = DateTime.Now;
mesBaseBarcodeInfo.updateBy = "SlnMesnac";
mesBaseBarcodeInfo.updateTime = DateTime.Now;
mesBaseBarcodeInfo.completeFlag = "1";
mesBaseBarcodeInfo.singleFlag = "0";
// 改成spec
mesBaseBarcodeInfo.barcodeSpec = productPlanDto.MaterialName;
sqlSugarClient.AsTenant().GetConnection("mes").Insertable(mesBaseBarcodeInfo).ExecuteCommand();
return bigBarcode;
}
/// <summary>
/// 40个小条码及大条码绑定托盘号小条码绑定大条码
/// </summary>
/// <param name="bigBarcode"></param>
/// <param name="epcStr"></param>
private void BindingBarCode(string bigBarcode,string epcStr)
{
List<MesPrdBarcodeInfo> list = _mesPrdBarCodeService.GetUseBarCodeList();
if(list==null || list.Count == 0)
{
throw new InvalidOperationException("托盘未找到可以绑定的小条码");
}
if (list.Where(x => x.PrintFlag == "1").ToList().Count < 40)
{
// TODO推送低级别报警
}
foreach (var item in list)
{
item.PalletInfoCode = epcStr;
item.MesBarcodeInfo = bigBarcode;
item.BindTime = DateTime.Now;
item.BindStatus = 1;
}
sqlSugarClient.AsTenant().GetConnection("mes").Updateable(list).ExecuteCommand();
}
private void UpdatePlanInfoAndOrder(MesProductPlanDto productPlanDto)
{
MesProductPlan productPlan = _mesProductPlanService.Query(x => x.PlanCode == productPlanDto.PlanCode).FirstOrDefault();
if(productPlan == null)
{
throw new InvalidOperationException("未找到该生产计划!");
}
MesProductOrder productOrder = _mesProductOrderService.Query(x => x.ProductOrderId == productPlan.ProductOrderId).FirstOrDefault();
if (productPlan == null)
{
throw new InvalidOperationException("未找到该生产计划对应的生产工单!");
}
#region 更新生产计划
if (productPlan.CompleteAmount == 0)
{
productPlan.RealBeginTime = DateTime.Now;
}
productPlan.CompleteAmount++;
if(productPlan.CompleteAmount == productPlan.PlanAmount)
{
productPlan.RealEndTime = DateTime.Now;
productPlan.PlanStatus = Model.enums.PlanStatusEnum.;
}
productPlan.UpdateTime = DateTime.Now;
productPlan.UpdateBy = "SlnMesnac";
sqlSugarClient.AsTenant().GetConnection("mes").Updateable(productPlan).ExecuteCommand();
#endregion
#region 更新生产工单
if (productOrder.CompleteAmount == 0)
{
productOrder.RealBeginTime = DateTime.Now;
}
productOrder.CompleteAmount++;
if(productOrder.CompleteAmount== productOrder.PlanAmount)
{
productOrder.RealEndTime = DateTime.Now;
productOrder.OrderStatus = "2";
}
productOrder.UpdateTime = DateTime.Now;
productOrder.UpdateBy = "SlnMesnac";
sqlSugarClient.AsTenant().GetConnection("mes").Updateable(productOrder).ExecuteCommand();
#endregion
}
/// <summary>
/// 空托盘进入码垛位,读取RFID备用
/// </summary>
private async void EmptyPalletHandle()
{
//读取PLC空托盘流转信号
while (true)
{
try
{
var plc = base.GetPlcByKey("plc");
if (plc == null)
{
_logger.LogInformation("读取PLC空托盘码垛到位信号,PLC连接信息为空......");
Thread.Sleep(5000);
continue;
}
if (!plc.readBoolByAddress(GetPlcAddressByConfigKey("2楼码垛到位信号")))
{
_logger.LogInformation("等待空托盘到位信号触发......");
Thread.Sleep(5000);
continue;
}
//读取RFID、获取当前正在执行的计划、将当前计划、工单等信息与托盘绑定
RefreshMessage("空托盘到位信号触发成功,读取托盘RFID信息");
string epcStr = await ReadEpcStrByRfidKeyAsync("secondFloorPallet");
if (string.IsNullOrEmpty(epcStr))
{
_logger.LogError("空托盘到位信号触发,读取RFID失败......");
Thread.Sleep(1000*10);
continue;
}
RefreshMessage($"空托盘RFID信息读取成功标签信息{epcStr}");
// 插入一条托盘记录
RealPalletTask realPalletTask = new RealPalletTask()
{
PalletCode = epcStr,
RecordTime = DateTime.Now,
};
bool result = _realPalletTaskService.Insert(realPalletTask);
if (result)
{
plc.writeBoolByAddress(GetPlcAddressByConfigKey("2楼码垛到位信号"), false);
}
}
catch (Exception e)
{
RefreshMessage($"空托盘进入码垛位处理异常:{e.Message}");
}
Thread.Sleep(1000*5);
}
}
/// <summary>
/// 根据条码提取序列
/// </summary>
/// <param name="barCode"></param>
/// <param name="result"></param>
/// <exception cref="InvalidOperationException"></exception>
private void ExtractNumber(string barCode,out int result)
{
string pattern = @"\b0*(\d{1,6})\b$";
Match match = Regex.Match(barCode, pattern);
if (match.Success)
{
result = Convert.ToInt32(match.Groups[1].Value)+1;
}
else
{
throw new InvalidOperationException($"通过条码:{barCode}提取当前序列异常:未找到匹配的数字");
}
}
}
}