using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using SlnMesnac.Business.@base;
using SlnMesnac.Model.domain;
using SlnMesnac.Model.dto.taskType;
using SlnMesnac.Plc;
using SlnMesnac.Serilog;
using SlnMesnac.WCS.Global;
using SlnMesnac.WCS.Library;
using SqlSugar;
using System.Threading.Tasks;
namespace SlnMesnac.WCS.WCS
{
///
/// 根据条件创建任务
///
public class CreateTaskByRecord : BaseBusiness
{
private readonly SerilogHelper _logger;
//3#车间上料点plc
private readonly PlcAbsractFactory workShop3Plc;
//2#计量室相关点位
private readonly PlcAbsractFactory workShop2Plc;
private readonly ISqlSugarClient sqlSugarClient;
public CreateTaskByRecord(IServiceProvider serviceProvider) : base(serviceProvider)
{
workShop3Plc = base.GetPlcByKey("workShop3Plc");
workShop2Plc = base.GetPlcByKey("workShop2Plc");
sqlSugarClient = serviceProvider.GetRequiredService();
_logger = serviceProvider.GetRequiredService();
//test();
}
///
/// 启动扫描监听
///
public void StartPoint()
{
CreateTaskByReadPlcSignal();
//监听2#计量室旋转移栽plc信号,处理相关流程
var CreateProductTaskByLocationCodeThread = new Thread(ListeningWorkShop2TransplantingMachine);
CreateProductTaskByLocationCodeThread.IsBackground = true;
CreateProductTaskByLocationCodeThread.Name = "监听1#2#计量室旋转移栽plc信号处理连廊箱体旋转相关流程";
CreateProductTaskByLocationCodeThread.Start();
}
///
/// 通过读plc条件创建任务
///
///
private void CreateTaskByReadPlcSignal()
{
Task.Run(() =>
{
while (true)
{
try
{
if (workShop3Plc == null || !workShop3Plc.IsConnected)
{
_logger.Plc(DateTime.Now + "3#PLC未连接,请检查网络!");
continue;
}
#region 3#车间补四宫格空箱流程---监听3#1号光电状态
bool signal1 = workShop3Plc.readBoolByAddress(StaticData.GetPlcAddress("3#大料箱进料为空"));
if (signal1)
{
CreateSupplementBigPalletTask();
}
#endregion 3#车间补四宫格空箱流程---监听3#1号光电状态
#region 从下料点到1-16机台送料任务--或者1-12移库任务 --监听3#2号光电状态
bool getBigFlag = workShop3Plc.readBoolByAddress(StaticData.GetPlcAddress("3#大料箱agv取料通知"));
string machineCodeS = workShop3Plc.readInt16ByAddress(StaticData.GetPlcAddress("3#四宫格下料点机台号")).ToString();
string rfidS = workShop3Plc.readStringByAddress(StaticData.GetPlcAddress("3#四宫格下料点RFID号"), 12).Replace("\0", "");
int amount = workShop3Plc.readInt16ByAddress(StaticData.GetPlcAddress("3#四宫格下料点数量"));
if (getBigFlag && machineCodeS != "0" && rfidS.Contains("SH"))
{
CreatDeliverWorkShop3Task(machineCodeS, rfidS, amount);
}
#endregion 从下料点到1-16机台送料任务--或者1-12移库任务 --监听3#2号光电状态
#region 3#往2#计量室送料流程
bool getSmallFlag = workShop3Plc.readBoolByAddress(StaticData.GetPlcAddress("3#小料箱agv取料通知"));
int smallAmount = workShop3Plc.readInt16ByAddress(StaticData.GetPlcAddress("3#小料箱下料点数量"));
string machineCodeX = workShop3Plc.readInt16ByAddress(StaticData.GetPlcAddress("3#小料箱下料点机台号")).ToString();
string rfidX = workShop3Plc.readStringByAddress(StaticData.GetPlcAddress("3#小料箱下料点RFID号"), 12).Replace("\0", "");
if (getSmallFlag && machineCodeX != "0" && rfidX.Contains("SH"))
{
if (machineCodeX == "1")
{
machineCodeX = "1006";
}
CreatDeliverWorkShop2Task(machineCodeX, rfidX);
}
#endregion 3#往2#计量室送料流程
#region 3#补充小空托盘流程--3#车间从色粉存放点补充小托盘任务 或者 3#车间从2#接驳位补充小托盘任务
int work3EmptyAmount = workShop3Plc.readInt16ByAddress(StaticData.GetPlcAddress("3#缓存皮带线库存数"));
int busy3Flag = workShop3Plc.readInt16ByAddress(StaticData.GetPlcAddress("3#线体忙碌状态"));
if ((work3EmptyAmount == 1 && busy3Flag == 0) || work3EmptyAmount == 0)
{
//3#车间从色粉存放点补充小托盘任务 或者 3#车间从2#接驳位补充小托盘任务
CreateSupplySmallPalletToWorkshop3Task();
}
#endregion 3#补充小空托盘流程--3#车间从色粉存放点补充小托盘任务 或者 3#车间从2#接驳位补充小托盘任务
}
catch (Exception ex)
{
_logger.Error($"CreateTaskByReadPlcSignal方法异常:" + ex.StackTrace);
}
finally
{
Thread.Sleep(1000);
}
}
});
}
///
/// 监听2#计量室旋转移栽plc信号,处理连廊箱体旋转相关流程
///
private void ListeningWorkShop2TransplantingMachine()
{
while (true)
{
try
{
if (workShop2Plc == null || !workShop2Plc.IsConnected)
{
continue;
}
#region 2#计量室料箱返回处理流程:空箱入缓存链条线,色粉派送至色粉存放点
//2#接驳位色粉派送至色粉存放点任务
if (workShop2Plc != null && workShop2Plc.IsConnected)
{
bool returnJudgeSignal = workShop2Plc.readBoolByAddress(StaticData.GetPlcAddress("2#料箱运回RFID读取"));
int busy2Flag = workShop2Plc.readInt16ByAddress(StaticData.GetPlcAddress("2#线体忙碌状态"));
int Amount = workShop2Plc.readInt16ByAddress(StaticData.GetPlcAddress("2#缓存链条线库存数"));
//是否还有未在色粉库位的色粉箱体
bool anyTonerPallet = HasAnyTonerInLine();
if (returnJudgeSignal && busy2Flag == 0 && (Amount < 3 || anyTonerPallet))
{
string rfid = ReadEpcStrByRfidKey("2#Transplant");
if (string.IsNullOrEmpty(rfid))
{//二次读取
rfid = ReadEpcStrByRfidKey("2#Transplant");
}
if (!string.IsNullOrEmpty(rfid))
{
int hoistFloor = workShop2Plc.readInt16ByAddress(StaticData.GetPlcAddress("2#提升机当前层"));
if (Amount < 3 && hoistFloor == 1) //如果提升机正好在1楼
{
Thread.Sleep(300);
}
else if (anyTonerPallet) //有色粉空转
{
Thread.Sleep(3500);
}
busy2Flag = workShop2Plc.readInt16ByAddress(StaticData.GetPlcAddress("2#线体忙碌状态"));
if (busy2Flag == 0)
{
// 判断有无色粉, 如果没有色粉,wcs给 旋转移栽方向信号 写2,plc将料箱运到 缓存皮带线。
WmsPalletInfo? wmsPalletInfo = sqlSugarClient.Queryable().First(it => it.PalletInfoCode == rfid);
if (wmsPalletInfo != null && wmsPalletInfo.Amount > 0 && wmsPalletInfo.TonerFlag == 1) //携带色粉
{
//注意:plc上旋转移栽必须锁住线体状态才可以,2#接驳位如果有满料,那么通知plc信号,plc在连廊不再把箱体放到旋转移栽上
//调度系统结合上面缓存链条线库存,如果上面低于3,那么空箱可以上来缓存线
workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("2#线体忙碌状态"), 1);
bool createResult = CreateDeliverTonerTask(rfid);
if (createResult)
{
//3色粉上提升机移栽等待
_logger.Info($"2#移栽===={rfid}携带色粉去往色粉库位");
workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("2#移栽平台任务"), 3);
workShop2Plc.writeBoolByAddress(StaticData.GetPlcAddress("2#料箱运回RFID读取"), false);
}
else
{ //色粉库位无空闲位置,空转一圈
//2空箱转运
_logger.Info($"2#移栽===={rfid}携带色粉,色粉库位无空闲位置,空转一圈");
workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("2#移栽平台任务"), 2);
workShop2Plc.writeBoolByAddress(StaticData.GetPlcAddress("2#料箱运回RFID读取"), false);
}
}
else if (wmsPalletInfo != null && wmsPalletInfo.Amount > 0 && wmsPalletInfo.TonerFlag == 0) //携带满料
{
//2转运
_logger.Info($"2#移栽===={rfid}携带满料,空转一圈");
workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("2#线体忙碌状态"), 1);
workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("2#移栽平台任务"), 2);
workShop2Plc.writeBoolByAddress(StaticData.GetPlcAddress("2#料箱运回RFID读取"), false);
}
else if (wmsPalletInfo != null && wmsPalletInfo.Amount == 0) //空托盘
{
if (Amount < 3)
{
//1上提升机去缓存线
_logger.Info($"2#移栽===={rfid}空箱,去缓存区");
workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("2#线体忙碌状态"), 1);
workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("2#移栽平台任务"), 1);
workShop2Plc.writeBoolByAddress(StaticData.GetPlcAddress("2#料箱运回RFID读取"), false);
}
else
{
//2空箱转运
_logger.Info($"2#移栽===={rfid}空箱,空箱转运");
workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("2#线体忙碌状态"), 1);
workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("2#移栽平台任务"), 2);
workShop2Plc.writeBoolByAddress(StaticData.GetPlcAddress("2#料箱运回RFID读取"), false);
}
}
}
}
else
{
//没读到2空箱转运
// _logger.Info($"1#移栽====没读到,空箱转运");
//workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("2#线体忙碌状态"), 1);
//workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("2#移栽平台任务"), 2);
//workShop2Plc.writeBoolByAddress(StaticData.GetPlcAddress("2#料箱运回RFID读取"), false);
}
}
}
#endregion 2#计量室料箱返回处理流程:空箱入缓存链条线,色粉派送至色粉存放点
#region 1#连廊料箱在计量室连廊移栽处理流程:wcs读RFID判断是否空箱,空箱下plc信号旋转,非空箱通知plc上提升机计量室
if (workShop2Plc != null && workShop2Plc.IsConnected)
{
bool returnJudgeSignal = workShop2Plc.readBoolByAddress(StaticData.GetPlcAddress("2#料箱运进计量室RFID读取"));
int busy1Flag = workShop2Plc.readInt16ByAddress(StaticData.GetPlcAddress("1#提升机忙碌状态"));
if (returnJudgeSignal && busy1Flag == 0)
{
//test
string rfid = ReadEpcStrByRfidKey("1#MetrologyRoom");
if (string.IsNullOrEmpty(rfid))
{
rfid = ReadEpcStrByRfidKey("1#MetrologyRoom");
}
if (!string.IsNullOrEmpty(rfid))
{
// 判断有无料, 如果没有料,wcs下发空箱旋转信号,有料,通知plc上提升机计量室
WmsPalletInfo? wmsPalletInfo = sqlSugarClient.Queryable().First(it => it.PalletInfoCode == rfid);
if (wmsPalletInfo != null && wmsPalletInfo.Amount > 0 && wmsPalletInfo.TonerFlag == 1) //携带色粉
{
//2空箱转运
_logger.Info($"1#移栽===={rfid}携带色粉,空箱转运");
workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("1#移栽平台任务"), 2);
workShop2Plc.writeBoolByAddress(StaticData.GetPlcAddress("2#料箱运进计量室RFID读取"), false);
}
if (wmsPalletInfo != null && wmsPalletInfo.Amount > 0 && wmsPalletInfo.TonerFlag == 0) //携带满料
{
//1#移栽平台任务(1上提升机,2空箱转运)
_logger.Info($"1#移栽===={rfid}携带满料,去提升机计量室");
workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("1#移栽平台任务"), 1);
workShop2Plc.writeBoolByAddress(StaticData.GetPlcAddress("2#料箱运进计量室RFID读取"), false);
}
else if (wmsPalletInfo != null && wmsPalletInfo.Amount == 0)
{
//1#移栽平台任务(1上提升机,2空箱转运)
_logger.Info($"1#移栽===={rfid}空箱,空箱转运");
workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("1#移栽平台任务"), 2);
workShop2Plc.writeBoolByAddress(StaticData.GetPlcAddress("2#料箱运进计量室RFID读取"), false);
}
}
else
{
//没读到,当成空箱子旋转一圈
//1#移栽平台任务(1上提升机,2空箱转运)
// _logger.Info($"1#移栽====没读到,空箱转运");
//workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("1#移栽平台任务"), 2);
//workShop2Plc.writeBoolByAddress(StaticData.GetPlcAddress("2#料箱运进计量室RFID读取"), false);
}
}
}
#endregion 1#连廊料箱在计量室连廊移栽处理流程:wcs读RFID判断是否空箱,空箱下plc信号旋转,非空箱通知plc上提升机计量室
#region 暂时不使用--色粉存放点空托盘派送至2#接驳位
/////如果色粉存放点可用空库位小于等于2个,并且有空托盘在库位,判断2#缓存链条线库存(容量3)低于2个,并且无 从3#接驳位到2#接驳位的送料任务或 色粉存放点到2#缓存链条线任务,
/////2.生成色粉存放点到2#缓存链条线任务
//int canUseAmount = sqlSugarClient.Queryable().Count(it => it.EquipType == 7 && it.EquipStatus == 0 && string.IsNullOrEmpty(it.ContainerCode));
////判断色粉存放处是否有空托盘
//WcsBaseEquip? startEquip = sqlSugarClient.Queryable().InnerJoin(
// (wbe, wpi) => wbe.ContainerCode == wpi.PalletInfoCode && wpi.Amount == 0 && wbe.EquipStatus == 0)
// .Where(wbe => wbe.EquipType == 7 && !string.IsNullOrEmpty(wbe.ContainerCode)).First();
//if (canUseAmount < 2 && startEquip != null)
//{
// int cacheLineAmount = workShop2Plc.readInt16ByAddress(StaticData.GetPlcAddress("2#缓存链条线库存数"));
// bool hasTask = sqlSugarClient.Queryable().Any(it => it.TaskType == StaticTaskType.EmptyReturnFromTonerTask || it.TaskType == StaticTaskType.TransferMaterialMetrologyRoomBoxTask);
// if (cacheLineAmount < 2 && !hasTask)
// {
// try
// {
// sqlSugarClient.AsTenant().BeginTran();
// WcsTask task = new WcsTask();
// task.TaskType = StaticTaskType.EmptyReturnFromTonerTask;
// task.CurrPointNo = startEquip.AgvPositionCode;
// task.EndPointNo = "2DeliverMetrologyRoomPoint";
// task.TaskStatus = 0;
// task.CreatedTime = DateTime.Now;
// task.CreatedBy = "wcs";
// task.TaskName = "色粉存放点空托盘派送至2#接驳位";
// task.PalletInfoCode = startEquip.ContainerCode;
// int id = sqlSugarClient.Insertable(task).ExecuteReturnIdentity();
// WcsTaskLog wcsTaskLog = CoreMapper.Map(task);
// wcsTaskLog.Id = id;
// startEquip.EquipStatus = 1;
// sqlSugarClient.Updateable(startEquip).ExecuteCommand();
// sqlSugarClient.Insertable(wcsTaskLog).ExecuteCommand();
// sqlSugarClient.AsTenant().CommitTran();
// _logger.Agv($"生成{task.TaskName},起点:{task.CurrPointNo},终点:{task.EndPointNo}");
// }
// catch (Exception ex)
// {
// sqlSugarClient.AsTenant().RollbackTran();
// _logger.Error($"色粉存放点空托盘派送至2#接驳位任务提交事务异常{ex.Message}");
// }
// }
//}
#endregion 暂时不使用--色粉存放点空托盘派送至2#接驳位
}
catch (Exception ex)
{
_logger.Error($"ListeningWorkShop2TransplantingMachine方法异常:" + ex.StackTrace);
}
finally
{
Thread.Sleep(1000 * 1);
}
}
}
#region 任务流程
///
/// 3#车间补四宫格空箱流程
///
private async void CreateSupplementBigPalletTask()
{
try
{
//判断agv是否有来这里的任务
bool hasTask = sqlSugarClient.Queryable().Any(it => it.TaskType == StaticTaskType.SupplyEmptyPalletTask && it.EndPointNo == "3SuppleEmptyPalletPoint");
if (hasTask)
{
//_logger.Info("Agv已有3#车间补四宫格空箱任务");
return;
}
#region 寻找机台空托盘
WmsBaseLocation? startLocation = null;
//todo:优化点:为避免送料时尽可能少的移库任务,因此在这里可以先读取下一个料包要去的机台号,提前调度这里的空箱
string nextGoMachineCode = workShop3Plc.readInt16ByAddress(StaticData.GetPlcAddress("3#实时机台号")).ToString();
bool hasAny = StaticData.WmsMachineInfos.Any(x => x.MachineCode == nextGoMachineCode && x.WorkshopId == 3);
if (hasAny)
{
int machineId = StaticData.WmsMachineInfos.First(x => x.MachineCode == nextGoMachineCode).MachineId;
if (machineId >= 12 && machineId <= 16)
{
//12 - 16号机台都送往12号机台
machineId = 12;
}
//判断该机台有无空料箱,优先补充
string sql = $"SELECT wbl.* FROM wms_base_location wbl join wms_pallet_info wpi on wbl.container_code = wpi.pallet_info_code where wbl.container_code is not null and wbl.container_code!='' and wbl.location_status=0 and wbl.machineid ={machineId} and wpi.amount=0";
List startLocations = sqlSugarClient.Ado.SqlQuery(sql).OrderByDescending(x => x.MachineId).ToList();
if (startLocations.Count > 0)
{
startLocation = startLocations[0];
}
}
//1-12机台,优先12
if (startLocation == null)
{
string sql = "SELECT wbl.* FROM wms_base_location wbl join wms_pallet_info wpi on wbl.container_code = wpi.pallet_info_code where wbl.container_code is not null and wbl.container_code!='' and wbl.location_status=0 and wbl.machineid<=12 and wpi.amount=0";
List emptyLocations = sqlSugarClient.Ado.SqlQuery(sql).OrderBy(x => x.MachineId).ToList();
if (emptyLocations.Count == 0)
{
_logger.Info("暂时没有可用空托盘库位");
//todo报警
return;
}
//暂时排序,后期结合小料正在生产的计划提前调度要配送机台的空托盘,或者可以根据实际位置调度最近的空料箱
startLocation = emptyLocations.First();
}
WcsBaseEquip? endEquip = sqlSugarClient.Queryable().Where(it => it.EquipNo == "3SuppleEmptyPalletPoint").ToList().First();
#endregion 寻找机台空托盘
sqlSugarClient.AsTenant().BeginTran();
WcsTask task = new WcsTask();
task.TaskType = StaticTaskType.SupplyEmptyPalletTask;
task.TaskName = StaticTaskType.GetDescription(task.TaskType);
task.CurrPointNo = startLocation.AgvPositionCode;
startLocation.LocationStatus = 1;
sqlSugarClient.Updateable(startLocation).ExecuteCommand();
// task.NextPointNo = agvEquip.AgvPositionCode;
task.EndPointNo = endEquip.AgvPositionCode;
task.TaskStatus = 0;
task.CreatedTime = DateTime.Now;
task.CreatedBy = "wcs";
task.PalletInfoCode = startLocation.ContainerCode;
int id = sqlSugarClient.Insertable(task).ExecuteReturnIdentity();
WcsTaskLog wcsTaskLog = CoreMapper.Map(task);
wcsTaskLog.Id = id;
sqlSugarClient.Insertable(wcsTaskLog).ExecuteCommand();
sqlSugarClient.AsTenant().CommitTran();
_logger.Agv($"生成{task.TaskName},起点:{task.CurrPointNo},终点:{task.EndPointNo}");
}
catch (Exception ex)
{
sqlSugarClient.AsTenant().RollbackTran();
_logger.Error($"生成3#车间补四宫格空箱流程异常{ex.Message}");
}
}
///
/// 从下料点到1-16机台送料任务 创建移库任务
///
private async void CreatDeliverWorkShop3Task(string machineCode, string rfid, int amount)
{
try
{
bool hasMachineCode = StaticData.WmsMachineInfos.Any(x => x.MachineCode == machineCode);
if (!string.IsNullOrEmpty(rfid) && hasMachineCode)
{
//判断该料箱是否已经有送料任务
bool hasTask = sqlSugarClient.Queryable().Any(it => it.TaskType == StaticTaskType.TransferMaterialBoxTask && it.PalletInfoCode == rfid);
if (hasTask)
{
_logger.Info($"该托盘{rfid}已有下料点到1-16机台送料任务");
return;
}
//判断该托盘是否已经在库里
bool isInLocation = sqlSugarClient.Queryable().Any(it => it.ContainerCode == rfid);
if (isInLocation)
{
//todo推送报警
_logger.Info($"该托盘{rfid}已存在库位,请检查托盘号是否重复");
return;
}
List AllWmsBaseLocationList = await sqlSugarClient.Queryable().Where(x => x.MachineId <= 12).ToListAsync();
WmsBaseLocation? targetLocation;
// 根据机台号寻找终点库位、判断机台的两个库位是否有空位置、没有的话先生成移库任务
targetLocation = GetTargetLocation(machineCode, AllWmsBaseLocationList);
if (targetLocation == null)
{
//todo:推送预警
_logger.Info($"机台:{machineCode}没有可用空库位,无法配送");
return;
}
WcsBaseEquip startEquip = sqlSugarClient.Queryable().First(it => it.EquipNo == "3DeliverBigGoodsStartPoint");
WmsPalletInfo wmsPalletInfo = sqlSugarClient.Queryable().First(it => it.PalletInfoCode == rfid);
WcsTask task = new WcsTask();
task.TaskType = StaticTaskType.TransferMaterialBoxTask;
task.CurrPointNo = startEquip.AgvPositionCode;
task.EndPointNo = targetLocation.AgvPositionCode;
task.TaskStatus = 0;
task.CreatedTime = DateTime.Now;
task.CreatedBy = "wcs";
task.TaskName = "下料点到1-16机台送料任务";
task.PalletInfoCode = rfid;
task.MachineCode = machineCode;
sqlSugarClient.AsTenant().BeginTran();
try
{
int id = sqlSugarClient.Insertable(task).ExecuteReturnIdentity();
WcsTaskLog wcsTaskLog = CoreMapper.Map(task);
wcsTaskLog.Id = id;
targetLocation.LocationStatus = 1;
sqlSugarClient.Updateable(targetLocation).ExecuteCommand();
sqlSugarClient.Insertable(wcsTaskLog).ExecuteCommand();
#region 修改托盘信息
if (wmsPalletInfo != null)
{
wmsPalletInfo.Amount = amount != 0 ? amount : 1;
wmsPalletInfo.UpdatedTime = DateTime.Now;
sqlSugarClient.Updateable(wmsPalletInfo).ExecuteCommand();
}
#endregion 修改托盘信息
sqlSugarClient.AsTenant().CommitTran();
workShop3Plc.writeBoolByAddress(StaticData.GetPlcAddress("3#大料箱agv取料通知"), false);
_logger.Agv($"生成{task.TaskName},起点:{task.CurrPointNo},终点:{task.EndPointNo}");
}
catch (Exception ex)
{
sqlSugarClient.AsTenant().RollbackTran();
_logger.Error($"生成3#车间从下料点到1-16机台送料任务提交事务异常{ex.Message}");
}
}
}
catch (Exception ex)
{
sqlSugarClient.AsTenant().RollbackTran();
_logger.Error($"生成3#车间从下料点到1-16机台送料任务异常{ex.Message}");
}
}
///
/// 从3#接驳位到2#计量室接驳位的送料任务
///
private void CreatDeliverWorkShop2Task(string machineCode, string rfid)
{
try
{
bool hasMachineCode = StaticData.WmsMachineInfos.Any(x => x.MachineCode == machineCode);
if (!string.IsNullOrEmpty(rfid) && hasMachineCode)
{
//判断agv是否有来这里的任务
bool hasTask = sqlSugarClient.Queryable().Any(it => it.TaskType == StaticTaskType.TransferMaterialMetrologyRoomBoxTask && it.PalletInfoCode == rfid);
if (hasTask)
{
_logger.Info($"该托盘{rfid}已有3#接驳位到2#计量室接驳位的送料任务");
return;
}
//起点库位 3#车间小料箱取送货接驳点
WcsBaseEquip startEquip = sqlSugarClient.Queryable().First(it => it.EquipNo == "3DeliverSmallGoodsPoint");
//终点库位 2#车间计量室接驳点
WcsBaseEquip endEquip = sqlSugarClient.Queryable().First(it => it.EquipNo == "2DeliverMetrologyRoomPoint");
WmsPalletInfo wmsPalletInfo = sqlSugarClient.Queryable().First(it => it.PalletInfoCode == rfid);
sqlSugarClient.AsTenant().BeginTran();
WcsTask task = new WcsTask();
task.TaskType = StaticTaskType.TransferMaterialMetrologyRoomBoxTask;
task.CurrPointNo = startEquip.AgvPositionCode;
// task.NextPointNo = agvEquip.AgvPositionCode;
task.EndPointNo = endEquip.AgvPositionCode;
task.TaskStatus = 0;
task.CreatedTime = DateTime.Now;
task.CreatedBy = "wcs";
task.TaskName = "3#接驳位到2#计量室接驳位的送料任务";
task.PalletInfoCode = rfid;
task.MachineCode = machineCode;
int id = sqlSugarClient.Insertable(task).ExecuteReturnIdentity();
WcsTaskLog wcsTaskLog = CoreMapper.Map(task);
wcsTaskLog.Id = id;
sqlSugarClient.Insertable(wcsTaskLog).ExecuteCommand();
#region 修改托盘信息
if (wmsPalletInfo != null)
{
wmsPalletInfo.TonerFlag = 0;
wmsPalletInfo.Amount = 1;
wmsPalletInfo.UpdatedTime = DateTime.Now;
sqlSugarClient.Updateable(wmsPalletInfo).ExecuteCommand();
}
#endregion 修改托盘信息
sqlSugarClient.AsTenant().CommitTran();
workShop3Plc.writeBoolByAddress(StaticData.GetPlcAddress("3#小料箱agv取料通知"), false);
_logger.Agv($"生成{task.TaskName},起点:{task.CurrPointNo},终点:{task.EndPointNo}");
}
}
catch (Exception ex)
{
sqlSugarClient.AsTenant().RollbackTran();
_logger.Error($"3#接驳位到2#计量室接驳位的送料任务{ex.Message}");
}
}
///
/// 3#车间从色粉存放点补充小托盘任务 或者 3#车间从2#接驳位补充小托盘任务
/// .wcs检测到 3#缓存皮带线库存数 (容量2)不满时,且色粉存放处有空托盘时,优先生成色粉存放处补充小料箱任务
///2.如果色粉存放处无空托盘,且2#缓存链条线库存数 大于0个,并且 2#线体忙碌状态 0时,2s后 2#线体忙碌状态 0时,wcs把 2#线体忙碌状态 改为1,wcs下发缓存链条线 2#出一个空托盘信号(plc自己复位), wcs并且生成一个3#补充空托盘任务呼叫agv
///
private void CreateSupplySmallPalletToWorkshop3Task()
{
try
{
//判断是否已经有空托盘补充任务
bool hasTask = sqlSugarClient.Queryable().Any(x => x.TaskType == StaticTaskType.SupplySmallPalletTask || x.TaskType == StaticTaskType.SupplySmallPalletFromTonerTask);
if (hasTask)
{
return;
}
//判断色粉存放处是否有空托盘
WcsBaseEquip? emptyPalletEquip = sqlSugarClient.Queryable().InnerJoin(
(wbe, wpi) => wbe.ContainerCode == wpi.PalletInfoCode && wpi.Amount == 0 && wbe.EquipStatus == 0)
.Where(wbe => wbe.EquipType == 7 && !string.IsNullOrEmpty(wbe.ContainerCode)).OrderBy(wbe => wbe.Id).First();
if (emptyPalletEquip != null) //从色粉存放处生成补充空托盘任务
{
WcsTask task = new WcsTask();
task.TaskType = StaticTaskType.SupplySmallPalletFromTonerTask;
task.CurrPointNo = emptyPalletEquip.AgvPositionCode;
task.EndPointNo = "3DeliverSmallGoodsPoint";
task.TaskStatus = 0;
task.CreatedTime = DateTime.Now;
task.CreatedBy = "wcs";
task.TaskName = "3#车间从色粉存放点补充小托盘任务";
task.PalletInfoCode = emptyPalletEquip.ContainerCode;
sqlSugarClient.AsTenant().BeginTran();
try
{
int id = sqlSugarClient.Insertable(task).ExecuteReturnIdentity();
WcsTaskLog wcsTaskLog = CoreMapper.Map(task);
wcsTaskLog.Id = id;
sqlSugarClient.Insertable(wcsTaskLog).ExecuteCommand();
//锁住开始色粉库位
emptyPalletEquip.EquipStatus = 1;
sqlSugarClient.Updateable(emptyPalletEquip).ExecuteCommand();
sqlSugarClient.AsTenant().CommitTran();
}
catch (Exception ex)
{
sqlSugarClient.AsTenant().RollbackTran();
_logger.Error($"3#车间从色粉存放点补充小托盘任务生成提交事务异常{ex.Message}");
}
_logger.Agv($"生成{task.TaskName},起点:{task.CurrPointNo},终点:{task.EndPointNo}");
return;
}
else //从2#缓存链条线生成补充空托盘任务
{
if (workShop2Plc == null || !workShop2Plc.IsConnected)
{
_logger.Plc(DateTime.Now + "2#PLC未连接,请检查网络!");
return;
}
int work2EmptyAmount = workShop2Plc.readInt16ByAddress(StaticData.GetPlcAddress("2#缓存链条线库存数"));
int work2LineBusyFlag = workShop2Plc.readInt16ByAddress(StaticData.GetPlcAddress("2#缓存空箱线体状态"));
if (work2EmptyAmount > 0 && work2LineBusyFlag == 0)
{
//防止抢占其他任务节奏
Thread.Sleep(1000);
work2LineBusyFlag = workShop2Plc.readInt16ByAddress(StaticData.GetPlcAddress("2#缓存空箱线体状态"));
work2EmptyAmount = workShop2Plc.readInt16ByAddress(StaticData.GetPlcAddress("2#缓存链条线库存数"));
if (work2EmptyAmount > 0 && work2LineBusyFlag == 0)
{
bool hasTonerTask = sqlSugarClient.Queryable().Any(x => x.TaskType == StaticTaskType.DeliverTonerTask && x.TaskStatus < 5);
if (hasTask)
{ //如果有agv等着接色粉,暂时不生成补充空托盘任务
return;
}
workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("2#缓存空箱线体状态"), 1);
WcsTask task = new WcsTask();
task.TaskType = StaticTaskType.SupplySmallPalletTask;
task.CurrPointNo = "2DeliverMetrologyRoomPoint";
task.EndPointNo = "3DeliverSmallGoodsPoint";
task.TaskStatus = 0;
task.CreatedTime = DateTime.Now;
task.CreatedBy = "wcs";
task.TaskName = " 3#车间从2#接驳位补充小托盘任务";
sqlSugarClient.AsTenant().BeginTran();
try
{
int id = sqlSugarClient.Insertable(task).ExecuteReturnIdentity();
WcsTaskLog wcsTaskLog = CoreMapper.Map(task);
wcsTaskLog.Id = id;
sqlSugarClient.Insertable(wcsTaskLog).ExecuteCommand();
sqlSugarClient.AsTenant().CommitTran();
}
catch (Exception ex)
{
sqlSugarClient.AsTenant().RollbackTran();
_logger.Error($"3#车间从2#接驳位补充小托盘任务生成提交事务异常{ex.Message}");
workShop2Plc.writeInt16ByAddress(StaticData.GetPlcAddress("2#线体忙碌状态"), 0);
}
_logger.Agv($"生成{task.TaskName},起点:{task.CurrPointNo},终点:{task.EndPointNo}");
return;
}
}
}
}
catch (Exception ex)
{
_logger.Error($"CreateSupplySmallPalletToWorkshop3Task异常{ex.Message}");
}
}
///
/// 从2#接驳位到3#接驳位补小空箱任务 :3#车间补小空箱流程
///
private void CreateSupplementSmallPalletTask()
{
try
{
//判断是否有该任务
bool hasTask = sqlSugarClient.Queryable().Any(it => it.TaskType == StaticTaskType.SupplySmallPalletTask && it.TaskStatus < 5);
if (hasTask)
{
_logger.Info("Agv已有2#接驳位到3#接驳位补小空箱任务");
return;
}
//寻找可用agv
//WcsBaseEquip? agvEquip = GetCanUseAgv();
//if (agvEquip == null)
//{
// _logger.Info("暂时没有可用agv");
// return;
//}
//起点库位 3#车间小料箱取送货接驳点
WcsBaseEquip startEquip = sqlSugarClient.Queryable().First(it => it.EquipNo == "2DeliverMetrologyRoomPoint");
//终点库位 2#车间计量室接驳点
WcsBaseEquip endEquip = sqlSugarClient.Queryable().First(it => it.EquipNo == "3DeliverSmallGoodsPoint");
sqlSugarClient.AsTenant().BeginTran();
WcsTask task = new WcsTask();
task.TaskType = StaticTaskType.SupplySmallPalletTask;
task.CurrPointNo = startEquip.AgvPositionCode;
// task.NextPointNo = agvEquip.AgvPositionCode;
task.EndPointNo = endEquip.AgvPositionCode;
task.TaskStatus = 0;
task.CreatedTime = DateTime.Now;
task.CreatedBy = "wcs";
task.TaskName = "2#接驳位到3#接驳位补小空箱任务";
int id = sqlSugarClient.Insertable(task).ExecuteReturnIdentity();
WcsTaskLog wcsTaskLog = CoreMapper.Map(task);
wcsTaskLog.Id = id;
startEquip.EquipStatus = 1;
endEquip.EquipStatus = 1;
sqlSugarClient.Updateable(startEquip).ExecuteCommand();
sqlSugarClient.Updateable(endEquip).ExecuteCommand();
sqlSugarClient.Insertable(wcsTaskLog).ExecuteCommand();
sqlSugarClient.AsTenant().CommitTran();
_logger.Agv($"生成{task.TaskName},起点:{task.CurrPointNo},终点:{task.EndPointNo}");
}
catch (Exception ex)
{
sqlSugarClient.AsTenant().RollbackTran();
_logger.Error($"2#接驳位到3#接驳位补小空箱任务异常{ex.Message}");
}
}
///
/// 2#色粉派送至色粉存放点任务
///
private bool CreateDeliverTonerTask(string rfid)
{
bool createResult = false;
try
{
//判断是否有该任务
bool hasTask = sqlSugarClient.Queryable().Any(it => it.TaskType == StaticTaskType.DeliverTonerTask && it.PalletInfoCode == rfid);
if (hasTask)
{
_logger.Info($"Agv已有托盘:{rfid}2#色粉派送至色粉存放点任务");
return true;
}
//起点库位 2#计量室车间小料箱取送货接驳点
WcsBaseEquip startEquip = sqlSugarClient.Queryable().First(it => it.EquipNo == "2DeliverMetrologyRoomPoint");
//终点库位 2#返程色粉人工拿取点
WcsBaseEquip? endEquip = sqlSugarClient.Queryable().Where(it => it.EquipStatus == 0 && it.EquipType == 7 && string.IsNullOrEmpty(it.ContainerCode)).OrderBy(x => x.Id).First();
if (endEquip == null)
{
//todo推送报警
_logger.Error("暂时没有可用色粉存放点库位");
return false;
}
sqlSugarClient.AsTenant().BeginTran();
try
{
WcsTask task = new WcsTask();
task.TaskType = StaticTaskType.DeliverTonerTask;
task.CurrPointNo = startEquip.AgvPositionCode;
task.EndPointNo = endEquip.AgvPositionCode;
task.TaskStatus = 0;
task.CreatedTime = DateTime.Now;
task.CreatedBy = "wcs";
task.TaskName = "2#色粉派送至色粉存放点任务";
task.PalletInfoCode = rfid;
int id = sqlSugarClient.Insertable(task).ExecuteReturnIdentity();
WcsTaskLog wcsTaskLog = CoreMapper.Map(task);
wcsTaskLog.Id = id;
startEquip.EquipStatus = 1;
endEquip.EquipStatus = 1;
sqlSugarClient.Updateable(startEquip).ExecuteCommand();
sqlSugarClient.Updateable(endEquip).ExecuteCommand();
sqlSugarClient.Insertable(wcsTaskLog).ExecuteCommand();
sqlSugarClient.AsTenant().CommitTran();
_logger.Agv($"生成{task.TaskName},起点:{task.CurrPointNo},终点:{task.EndPointNo}");
createResult = true;
}
catch (Exception ex)
{
sqlSugarClient.AsTenant().RollbackTran();
_logger.Error($"2#色粉派送至色粉存放点任务提交事务异常{ex.Message}");
}
}
catch (Exception ex)
{
sqlSugarClient.AsTenant().RollbackTran();
_logger.Error($"生成2#色粉派送至色粉存放点并空箱送回2#接驳位任务异常{ex.Message}");
}
return createResult;
}
#endregion 任务流程
#region 辅助方法
///
/// 判断是否还有色粉在连廊输送线或者没在色粉库位
///
///
private bool HasAnyTonerInLine()
{
try
{
// 色粉料箱
List tonerPallets = sqlSugarClient.Queryable().Where(x => x.TonerFlag == 1 && x.Amount > 0).ToList();
// 色粉库位的料箱码
List equipPalletInfos = sqlSugarClient.Queryable().Where(x => x.EquipType == 7 && !string.IsNullOrEmpty(x.ContainerCode)).ToList();
// 获取 tonerPallets 中的所有 PalletInfoCode
var tonerPalletCodes = tonerPallets.Select(x => x.PalletInfoCode).ToList();
// 获取 equipPalletInfos 中的所有 ContainerCode
var equipPalletCodes = equipPalletInfos.Select(x => x.ContainerCode).ToList();
// 检查是否有 tonerPalletCodes 不在 equipPalletCodes 中
bool result = tonerPalletCodes.Any(code => !equipPalletCodes.Contains(code));
return result;
}
catch (Exception ex)
{
return false;
}
}
/////
///// 从12号机台获取空托盘,返回库位信息
/////
/////
/////
//private async Task GetEmptyContainerByMachine12Async(string rfidKey)
//{
// try
// {
// bool flag1 = await ReadSignalByRfidKeyAsync(rfidKey);
// if (flag1)
// {
// string code = await ReadEpcStrByRfidKeyAsync(rfidKey);
// if (!string.IsNullOrEmpty(code))
// {
// // 通过该料箱是否绑定有物料来判断是否为空托盘
// bool hasMaterial = await sqlSugarClient.Queryable().AnyAsync(it => it.PalletInfoCode == code);
// if (!hasMaterial)
// {
// WmsBaseLocation? location = await sqlSugarClient.Queryable().FirstAsync(it => it.EquipKey == rfidKey);
// return location;
// }
// }
// }
// //_logger.Error($"12号机台库位{rfidKey}无空托盘");
// return null;
// }
// catch (Exception ex)
// {
// return null;
// }
//}
///
/// 根据机台号寻找终点库位、判断机台的两个库位是否有空位置、没有的话先生成移库任务
/// machineId为该料箱目的地机台号
///
///
///
private WmsBaseLocation? GetTargetLocation(string machineCode, List AllWmsBaseLocationList)
{
try
{
bool hasMoveTask = sqlSugarClient.Queryable().Any(it => it.TaskType == StaticTaskType.MoveLocationTask && it.TaskStatus < 3);
if (hasMoveTask)
{
_logger.Info($"目标库位无空位置,正在执行移库任务,暂时不生成送料任务,请等待....");
return null;
}
WmsBaseLocation? targetLocation;
//移库起点终点
WmsBaseLocation? moveStartLocation;
WmsBaseLocation? moveEndLocation;
int machineId = StaticData.WmsMachineInfos.First(x => x.MachineCode == machineCode).MachineId;
if (machineId >= 12 && machineId <= 16)
{
//12 - 16号机台都送往12号机台
machineId = 12;
}
//12号机台读RFID判断
//if (machineId >= 12)
//{
// //光电信号
// bool flag1 = await ReadSignalByRfidKeyAsync("12-1");
// bool flag2 = await ReadSignalByRfidKeyAsync("12-2");
// if (!flag1)
// { //12-1有空位
// targetLocation = AllWmsBaseLocationList.First(it => it.EquipKey == "12-1" && it.LocationStatus == 1);
// return targetLocation;
// }
// //if (!flag2) //12-2有空位
// {
// //默认全送到12-2库位,如果有料箱,agv送过去停着,人工取走库位上的箱子
// targetLocation = AllWmsBaseLocationList.First(it => it.EquipKey == "12-2" && it.LocationStatus == 1);
// return targetLocation;
// }
// // 后期考虑优化,12号机台暂不考虑移库,因为库位距离其他机台比较远
//}
//else if (machineId >= 1 && machineId <= 11)
{
targetLocation = AllWmsBaseLocationList.FirstOrDefault(it => it.MachineId == machineId && it.LocationStatus == 0 && string.IsNullOrEmpty(it.ContainerCode));
if (targetLocation != null) return targetLocation;
//目标机台两个都有料箱,判断是否有机台里面的料箱是空的,有空箱可生成移库任务,否则等待
String sql = $"SELECT wbl.* FROM wms_base_location wbl join wms_pallet_info wpi on wbl.container_code = wpi.pallet_info_code where wbl.container_code is not null and wbl.container_code!='' and wbl.location_status=0 and wbl.machineid={machineId} and wpi.amount=0";
moveStartLocation = sqlSugarClient.SqlQueryable(sql).First();
if (moveStartLocation == null)
{
return null;
// todo推送预警 // 目标机台没有空库位,没有可移库的空箱,等待
}
//需要生成从该库位到其他机台的移库任务,找寻移库终点库位
moveEndLocation = AllWmsBaseLocationList.FirstOrDefault(x => x.LocationId != moveStartLocation.LocationId && x.LocationStatus == 0 && string.IsNullOrEmpty(x.ContainerCode));
if (moveEndLocation == null)
{
// 没有可以移库的库位,请等待
return null;
// todo:推送预警
}
else //生成移库任务
{
//二次确认寻找可用agv,避免在这期间agv被其他线程占用
try
{
//WcsBaseEquip? agvEquip = GetCanUseAgv();
//if (agvEquip == null)
//{
// _logger.Info("暂时没有可用agv");
// return null;
//}
WcsTask task = new WcsTask();
task.TaskType = StaticTaskType.MoveLocationTask;
task.CurrPointNo = moveStartLocation.AgvPositionCode;
task.EndPointNo = moveEndLocation.AgvPositionCode;
task.TaskStatus = 0;
task.CreatedTime = DateTime.Now;
task.CreatedBy = "wcs";
task.TaskName = "1-12机台之间空托盘移库任务";
task.PalletInfoCode = moveStartLocation.ContainerCode;
sqlSugarClient.AsTenant().BeginTran();
try
{
int id = sqlSugarClient.Insertable(task).ExecuteReturnIdentity();
WcsTaskLog wcsTaskLog = CoreMapper.Map(task);
wcsTaskLog.Id = id;
//锁定库位
moveStartLocation.LocationStatus = 1;
moveEndLocation.LocationStatus = 1;
sqlSugarClient.Updateable(moveStartLocation).ExecuteCommand();
sqlSugarClient.Updateable(moveEndLocation).ExecuteCommand();
sqlSugarClient.Insertable(wcsTaskLog).ExecuteCommand();
sqlSugarClient.AsTenant().CommitTran();
_logger.Agv($"生成{task.TaskName},起点:{task.CurrPointNo},终点:{task.EndPointNo}");
}
catch (Exception ex)
{
_logger.Error($"生成移库任务提交事务异常:{ex.Message}");
sqlSugarClient.AsTenant().RollbackTran();
}
}
catch (Exception ex)
{
_logger.Error($"生成移库任务异常:{ex.Message}");
return null;
}
}
}
return null;
}
catch (Exception ex)
{
_logger.Error($"GetTargetLocationAsync方法异常:{ex.StackTrace}");
return null;
}
}
#endregion 辅助方法
#region 测试方法
private async void test()
{
// 读RFID条码
// string code = await ReadEpcStrByRfidKeyAsync("1");
//读光电信号
//bool flag = await ReadSignalByRfidKeyAsync("1");
//bool flag1 = await ReadSignalByRfidKeyAsync("1");
//testTransitional();
//testTransitionalRollback();
}
///
/// 测多线程事务影响程度
///
private void testTransitional()
{
Task.Run(() =>
{
try
{
sqlSugarClient.AsTenant().BeginTran();
for (int i = 0; i < 10; i++)
{
Console.WriteLine($"线程1{i}");
//WmsStock stock = new WmsStock();
// stock.WorkshopId = i;
// sqlSugarClient.Insertable(stock).ExecuteCommand();
Thread.Sleep(1000);
}
sqlSugarClient.AsTenant().CommitTran();
}
catch (Exception ex)
{
sqlSugarClient.AsTenant().RollbackTran();
}
});
Task.Run(() =>
{
try
{
sqlSugarClient.AsTenant().BeginTran();
for (int i = 20; i < 30; i++)
{
//Console.WriteLine($"线程2{i}");
//WmsStock stock = new WmsStock();
//stock.WorkshopId = i;
//sqlSugarClient.Insertable(stock).ExecuteCommand();
//Thread.Sleep(1000);
//if (i == 25)
//{
// Console.WriteLine($"事务回滚");
// throw new Exception("事务回滚");
//}
}
sqlSugarClient.AsTenant().CommitTran();
}
catch (Exception ex)
{
sqlSugarClient.AsTenant().RollbackTran();
}
});
}
///
/// 测事务未开启但回滚
///
private void testTransitionalRollback()
{
try
{
throw new Exception("事务回滚");
sqlSugarClient.AsTenant().BeginTran();
for (int i = 0; i < 10; i++)
{
//Console.WriteLine($"线程1{i}");
//WmsStock stock = new WmsStock();
//stock.WorkshopId = i;
//sqlSugarClient.Insertable(stock).ExecuteCommand();
//Thread.Sleep(1000);
}
sqlSugarClient.AsTenant().CommitTran();
}
catch (Exception ex)
{
sqlSugarClient.AsTenant().RollbackTran();
}
}
#endregion 测试方法
}
}