using ServiceCenter.Extensions;
using ServiceCenter.Logs;
using ServiceCenter.SqlSugars;
using System.ComponentModel;
using WCS.Core;
using WCS.Entity;
using WCS.Entity.Protocol.BCR;
using WCS.Entity.Protocol.RGV;
using WCS.Entity.Protocol.Robot;
using WCS.Entity.Protocol.Station;
using WCS.Entity.Protocol.Truss;
using WCS.WorkEngineering.Extensions;
using WCS.WorkEngineering.Worlds;
using DeviceFlags = WCS.WorkEngineering.Extensions.DeviceFlags;
using TaskStatus = WCS.Entity.TaskStatus;
namespace WCS.WorkEngineering.Systems
{
///
/// RGV交互系统
///
[BelongTo(typeof(RgvWorld))]
[Description("RGV交互系统")]
public class RGVSystems : DeviceSystem>
{
protected override bool ParallelDo => true;
protected override bool SaveLogsToFile => true;
///
/// 取货点设备集合
///
private readonly Dictionary>> _pickUpDevices = new();
public RGVSystems()
{
//获取所有的巷道集合
var rgvList = Device.All.Where(v => v.HasFlag(DeviceFlags.RGV));
foreach (var rgv in rgvList)
{
_pickUpDevices.Add(rgv.Code, rgv.Sources.Where(v => v.HasFlag(DeviceFlags.输送机)).Select(v => new Device(v, this.World)).ToList());
}
}
public override void Do(Device obj)
{
try
{
if (obj.Data.VoucherNo != obj.Data2.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{obj.Data.VoucherNo}-DB521:{obj.Data2.VoucherNo}", LogLevelEnum.High);
if (obj.Data2.WorkMode != RGVWorkMode.Automatic) return;
if (obj.Data.RES1 == 1) return; //wcs任务完成确认信号未清除
if (obj.Data2.Status.HasFlag(RGVStatus.Taskfinishi))
{
switch (obj.Data2.CmdType)
{
case RGVCmdType.PickGoods: //单独取货任务完成,默认只有空托盘才会下发单独取货任务
//开始申请读码信息
var bcrCode = obj.Data3.GetBCRCode();
var taskNumber = 0;
SqlSugarHelper.Do(_db =>
{
var db = _db.Default;
var dev = Device.All.First(x => x.Code == obj.Data2.DestPosition.ToString());
if (dev.HasFlag(DeviceFlags.桁架码垛位))
{
//开始绑定任务,并下发新的任务信息到小车
var palletizingInfo = db.Queryable().Single(x => x.Id == obj.Data2.TaskNumber);
if (palletizingInfo == null) return;
palletizingInfo.PalleCode = bcrCode;
db.Updateable(palletizingInfo).ExecuteCommand();
taskNumber = palletizingInfo.Id;
}
else if (dev.HasFlag(DeviceFlags.环形库码垛工位))
{
//开始处理对应的搬运任务信息
var task = db.Queryable().First(x => x.Type == TaskType.Delivery && x.ID == obj.Data2.TaskNumber && x.AddrTo == obj.Data2.DestPosition.ToString());
if (task == null) throw new KnownException($"未找到对应的任务{obj.Data2.TaskNumber}", LogLevelEnum.Mid);
task.BarCode = bcrCode;
db.Updateable(task).ExecuteCommand();
task.AddWCS_TASK_DTL(db, obj.Entity.Code, obj.Data2.DestPosition.ToString(), $"环形库码垛位{obj.Data2.DestPosition}搬运任务绑定条码信息{bcrCode}");
taskNumber = task.ID;
}
});
if (taskNumber == 0) return;
//清空起始点信息
var staDev = new Device(Device.All.FirstOrDefault(x => x.Code == obj.Data2.DestPosition.ToString())!, World);
staDev.Data.TaskNumber = 0;
staDev.Data.GoodsStart = 0;
staDev.Data.GoodsEnd = 0;
obj.Data2.TaskNumber = taskNumber;
obj.Data.RES1 = 1;
break;
case RGVCmdType.PutGoods:
try
{
WCS_TaskInfo finishiTask = null;
var startPosition = Device.All.Where(x => x.Code == obj.Data2.StartPosition.ToString())
.Select(x => new Device(x, World))
.FirstOrDefault();
var destPosition = Device.All.FirstOrDefault(x => x.Code == obj.Data2.DestPosition.ToString());
var isPalletizing = destPosition!.HasFlag(DeviceFlags.桁架码垛位, DeviceFlags.环形库码垛工位);
short countQty = 0;
short shortCode = 0;
SqlSugarHelper.Do(_db =>
{
var db = _db.Default;
if (isPalletizing)
{
if (destPosition.HasFlag(DeviceFlags.桁架码垛位))
{
var palletizingInfo = db.Queryable()
.First(x => x.Id == obj.Data.TaskNumber);
countQty = palletizingInfo.CountQty.ToShort();
shortCode = palletizingInfo.ShortCode;
}
else if (destPosition.HasFlag(DeviceFlags.环形库码垛工位))
{
var deliveryTask = db.Queryable()
.First(x => x.ID == obj.Data.TaskNumber);
countQty = deliveryTask.FullQty;
shortCode = deliveryTask.PalletType;
deliveryTask.Status = TaskStatus.RgvCompleted;
deliveryTask.EditTime = DateTime.Now;
deliveryTask.LastInteractionPoint = obj.Entity.Code;
db.Updateable(deliveryTask).ExecuteCommand();
deliveryTask.AddWCS_TASK_DTL(db, deliveryTask.AddrTo, $"RGV任务执行结束");
}
}
});
if (startPosition.Data.TaskNumber == obj.Data.TaskNumber) //初始化起始点信息
{
startPosition.Data.TaskNumber = 0;
startPosition.Data.GoodsEnd = 0;
}
//目标地址是码垛工位
if (isPalletizing)
{
if (destPosition.HasFlag(DeviceFlags.桁架码垛位))
{
var dest = new Device(destPosition!, World);
dest.Data.MaxQuantity = countQty;
dest.Data.Quantity = 0;
dest.Data.Type = shortCode;
dest.Data.VoucherNo++;
}
else if (destPosition.HasFlag(DeviceFlags.环形库码垛工位))
{
var dest = new Device(destPosition!, World);
dest.Data.MaxQuantity = countQty;
dest.Data.Type = shortCode;
dest.Data.VoucherNo++;
}
}
}
catch (Exception e)
{
throw new KnownException($"处理小车放货完成是出现错误:{e.Message}-{e.StackTrace}", LogLevelEnum.High);
}
obj.Data.RES1 = 1;
break;
case RGVCmdType.Move:
obj.Data.RES1 = 1;
break;
case RGVCmdType.ChangePutGoods:
break;
case RGVCmdType.ChangePickGoods:
break;
case RGVCmdType.PickPutGoods:
var statDev = Device.All.FirstOrDefault(x => x.Code == obj.Data.StartPosition.ToString());
if (statDev.HasFlag(DeviceFlags.二次码垛RGV取货口))
{
var dev = new Device(statDev, World);
WCS_Palletizing pall = new WCS_Palletizing();
//获取码垛信息
SqlSugarHelper.Do(_db =>
{
var db = _db.Default;
pall = db.Queryable().Includes(x => x.Layers, x => x.Rows, x => x.Locs)
.First(x => x.Id == obj.Data2.TaskNumber) ?? throw new KnownException($"未找到对应任务{obj.Data2.TaskNumber}", LogLevelEnum.High);
});
var pallLoc = pall.Layers.SelectMany(x => x.Rows).SelectMany(x => x.Locs).Select(x => new { XYNo = x.XYNo.ToShort(), x.Finish }).ToList();
foreach (var loc in pallLoc)
{
dev.Data3.GetType().GetProperty($"IsGoods{loc.XYNo - 1}").SetValue(obj.Data3, loc.Finish);
}
dev.Data3.MaxQuantity = pall.CountQty.ToShort();
dev.Data3.Quantity = pallLoc.Count(x => x.Finish).ToShort();
dev.Data3.Type = pall.ShortCode;
dev.Data3.VoucherNo++;
}
else
{
var destDev = new Device(Device.All.FirstOrDefault(x => x.Code == obj.Data.DestPosition.ToString())!, World);
destDev.Data.TaskNumber = 0;
destDev.Data.GoodsStart = 0;
destDev.Data.GoodsEnd = 0;
}
obj.Data.RES1 = 1;
break;
default:
throw new ArgumentOutOfRangeException();
}
return;
}
if (obj.Data2.SystemStatus != RGVSystemStatus.空闲) return;
if (obj.Data2.Status.HasFlag(RGVStatus.RES1)) //离开非安全区域
{
obj.Data.TaskNumber = obj.Data.TaskNumber;
obj.Data.CmdType = RGVCmdType.Move;
obj.Data.DestPosition = obj.Entity.Code switch
{
"RGV1" => 1668,
"RGV2" => 1683,
"RGV3" => 1698,
"RGV4" => 1713,
"RGV5" => 1728,
"RGV6" => 1743,
_ => throw new ArgumentOutOfRangeException()
};
obj.Data.VoucherNo++;
return;
}
if (obj.Data2.CmdType == RGVCmdType.PickGoods && !obj.Data2.Status.HasFlag(RGVStatus.Taskfinishi))
{
if (obj.Data2.Status.HasFlag(RGVStatus.PH_Status))
{
obj.Data.TaskNumber = obj.Data.TaskNumber;
obj.Data.CmdType = RGVCmdType.PutGoods;
obj.Data.StartPosition = obj.Data2.StartPosition;
obj.Data.DestPosition = obj.Data2.DestPosition;
obj.Data.VoucherNo++;
return;
}
}
var pickUpDevices = _pickUpDevices.FirstOrDefault(x => x.Key == obj.Entity.Code).Value;
//有货且需要搬运货物的站台
var devs = pickUpDevices.Where(v => v.Data3.Status.HasFlag(StationStatus.PH_Status) && v.Data.TaskNumber != 0)
.Where(v => v.Entity.Code.ToShort() != v.Data.GoodsEnd && v.Data.GoodsEnd != 0)
.ToList();
//筛选出目标站台无货的站台
var putDev = obj.Entity.Targets.Where(x => x.HasFlag(DeviceFlags.输送机))
.Select(x => new Device(x, World))
.Where(x => !x.Data3.Status.HasFlag(StationStatus.PH_Status))
.Select(x => x.Entity.Code.ToShort());
var devList = devs.OrderBy(x => x.Entity.Code).Where(x => putDev.Contains(x.Data.GoodsEnd));
foreach (var dev in devList)
{
//区分任务是拆盘机到码垛工位,还是码垛工位到拆盘机
if (dev.Entity.HasFlag(DeviceFlags.拆盘机))
{
obj.Data.TaskNumber = dev.Data.TaskNumber;
obj.Data.CmdType = RGVCmdType.PickGoods;
obj.Data.StartPosition = dev.Entity.Code.ToShort();
obj.Data.DestPosition = dev.Data.GoodsEnd;
obj.Data.VoucherNo++;
return;
}
if (dev.Entity.HasFlag(DeviceFlags.二次码垛RGV取货口))
{
obj.Data.TaskNumber = dev.Data.TaskNumber;
obj.Data.CmdType = RGVCmdType.PickPutGoods;
obj.Data.StartPosition = dev.Entity.Code.ToShort();
obj.Data.DestPosition = dev.Data.GoodsEnd;
obj.Data.VoucherNo++;
return;
}
//非拆盘机起始任务
//站台中的任务号
WCS_TaskInfo task = null;
SqlSugarHelper.Do(_db =>
{
var db = _db.Default;
var taskInfo = db.Queryable().First(p => p.ID == dev.Data.TaskNumber && p.Status == TaskStatus.ConveyorExecution);
if (taskInfo == null) return;
taskInfo.Status = TaskStatus.RgvExecution;
taskInfo.AddrNext = obj.Entity.Code;
taskInfo.EditWho = "WCS";
taskInfo.EditTime = DateTime.Now; ;
db.Updateable(taskInfo).ExecuteCommand();
taskInfo.AddWCS_TASK_DTL(db, dev.Entity.Code, obj.Entity.Code, $"任务分配至{obj.Entity.Code}");
task = taskInfo;
});
if (task == null) continue;
obj.Data.TaskNumber = task.ID;
obj.Data.CmdType = RGVCmdType.PickPutGoods;
obj.Data.StartPosition = dev.Entity.Code.ToShort();
obj.Data.DestPosition = dev.Data.GoodsEnd;
obj.Data.VoucherNo++;
return;
}
}
catch (Exception ex)
{
if (ex.Message == "Destination array was not long enough. Check the destination index, length, and the array's lower bounds")
{
World.Log($"未知异常:{ex.StackTrace}");
}
else if (ex.Message == "Number was less than the array's lower bound in the first dimension")
{
World.Log($"未知异常:{ex.StackTrace}");
}
else throw new KnownException(ex.Message, LogLevelEnum.Mid);
}
}
public override bool Select(Device dev)
{
return dev.Code is "RGV1" or "RGV2" or "RGV3" or "RGV4" or "RGV5" or "RGV6";
//return dev.HasFlag(Extensions.DeviceFlags.RGV);
}
}
}