using LogLibrary.Log; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Text; using WIDESEA_Common; using WIDESEA_Core; using WIDESEA_Core.Enums; using WIDESEA_Core.Helper; using WIDESEA_DTO.AGV; using WIDESEA_DTO; using WIDESEA_IStorageBasicRepository; using WIDESEA_IStorageSocketServices; using WIDESEA_IStorageTaskRepository; using WIDESEA_Model.Models.AGV; using WIDESEA_Model.Models; using WIDESEAWCS_BasicInfoRepository; using WIDESEAWCS_Model.Models; using WIDESEA_Core.BaseRepository; using AutoMapper; using Mapster; namespace WIDESEA_StorageSocketServices { public class SocketClientService : ISocketClientServices { System.Net.Sockets.Socket socket; const byte STX = 2; const byte ETX = 3; private readonly ILogger _logger; private readonly LogFactory LogFactory = new LogFactory(); //private readonly IDt_TaskService _taskService; private readonly IDt_StationManagerRepository _stationManagerRepository; private readonly IDt_TaskRepository BaseDal; Connection connection = AppSettings.Configuration.GetSection("Connection").Get(); string url = AppSettings.Configuration["AGVIP"]; private readonly IUnitOfWorkManage _unitOfWorkManage; private readonly IStockInfoRepository _stockInfoRepository; private readonly IDt_Task_HtyRepository _task_HtyRepository; private readonly IMapper _mapper; private readonly ILocationInfoRepository _locationRepository; public SocketClientService(IDt_TaskRepository TaskRepository, IDt_StationManagerRepository stationManagerRepository, ILogger logger) { BaseDal = TaskRepository; _stationManagerRepository = stationManagerRepository; _logger = logger; } public void ConnectServer(string IP, int Port) { try { // 检查是否已连接,避免重复创建 if (socket != null && socket.Connected) { //Console.WriteLine("Socket已连接,无需重复创建"); ConsoleHelper.WriteErrorLine($"Socket已处于连接状态"); return; } //创建负责通信的socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress ip = IPAddress.Parse(IP); IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(Port)); //获得要连接的远程服务器应用程序的IP地址和端口号 socket.Connect(point); _logger.LogInformation("Socket连接成功"); ConsoleHelper.WriteSuccessLine("Socket连接成功"); RequestCommunication(); DeviceStateReport("I"); //开启一个新的线程不停的接收服务端发来的信息 Thread th = new Thread(Receive); th.IsBackground = true; th.Start(); ConsoleHelper.WriteErrorLine($"Socket启动"); return; } catch (Exception ex) { ConsoleHelper.WriteErrorLine($"Socket连接失败{ex.Message}"); HandleDisconnection(); } } void Receive() { while (true) { try { byte[] buffer = new byte[1024]; // 接收缓冲区 int bytesReceived = socket.Receive(buffer); // 接收数据 byte[] receivedData = new byte[bytesReceived]; Array.Copy(buffer, receivedData, bytesReceived); // 复制有效数据 var Y = Encoding.UTF8.GetString(receivedData); // 检查是否以 STX 开头、ETX 结尾 if (receivedData[0] == STX && receivedData[receivedData.Length - 1] == ETX) { int newLength = receivedData.Length - 2; int newCheckSumLength = receivedData.Length - 3; if (newLength < 0) { throw new ArgumentException("数组长度不足,无法去掉最后两位。"); } byte[] newArray = new byte[newLength]; Array.Copy(receivedData, 1, newArray, 0, newLength); string calculatedChecksum = GetCheckSumone(newArray); var str = Encoding.UTF8.GetString(newArray); string receivedChecksum = str.Substring(str.Length - 2); if (calculatedChecksum == receivedChecksum) { var x = Encoding.UTF8.GetString(newArray); ParseMessage parseMessage = new ParseMessage() { bDir = x.Substring(0, 1), bObjID = x.Substring(2, 10), bReply = x.Substring(11, 1), bCmdID = x.Substring(12, 3), nSeqNo = x.Substring(15, 5), }; ProcessCommand(parseMessage.bCmdID, x); } else { LogFactory.GetLog("Socket接收数据").Error(true, "校验失败"); } } else { LogFactory.GetLog("Socket接收数据").Error(true, $"无效报文格式:{JsonConvert.SerializeObject(Y)}"); } } catch { HandleDisconnection(); } } } private void ProcessCommand(string cmdId, string x) { switch (cmdId) { case "102": ReceiveCommandResponse(x); break; case "906": AGVJobStartOrEndResponse(x.Substring(21, 1), x.Substring(22, 1)); break; case "902": DataReportResponse(x.Substring(21, 1)); break; case "935": DeviceStationStatusInvite(x.Substring(15, 5)); break; case "103": HOSTOutBoundTask(x); break; case "106": RecreateGetLocation(x); break; case "108": RecreateGetLocation(x.Substring(21, 1)); break; case "909": DeviceStatusReportRequest(); break; default: break; } } private void HandleDisconnection() { int attempts = 5; do { string message = "连接已断开..." + '\n'; message += "等待5秒后重新连接" + '\n'; Console.WriteLine(message); // 关闭当前连接 try { socket?.Close(); } catch { } // 等待5秒 Thread.Sleep(5000); // 尝试重新连接 ConnectServer(connection.IP, connection.Port); attempts--; } while (!socket.Connected && attempts > 0); } //private void CheckTimeout(object state) //{ // TimeSpan elapsed = DateTime.Now - _lastActivityTime; // if (elapsed.TotalSeconds > 180) // 3分钟超时 // { // Console.WriteLine("超时未收到数据,触发909命令并尝试重新连接..."); // // 触发909命令 // _workTaskService.DeviceStatusReportRequest(); // // 尝试重新连接 // HandleDisconnection(); // } //} public void clientSend(byte[] buffer) { var Y = Encoding.UTF8.GetString(buffer); LogFactory.GetLog("Socket发送数据").Info(true, Y); socket.Send(buffer); } public string GetCheckSumone(byte[] x) { int sum = 0; try { for (int i = 0; i < x.Length - 2; i++) { sum += x[i]; } string str = sum.ToString(); return str.Substring(str.Length - 2); } catch (Exception ex) { throw new Exception(ex.Message); } } #region 常量 //public const byte STX = 2; //public const byte ETX = 3; /// /// 作业任务ID 预留 /// public const string JobOrderID = "0000000000000000"; /// /// 优先级 预留 /// public const string priority = "1"; /// /// 托盘个数 预留 /// public const string TrayCnt = "1"; /// /// 设备编号 /// public const string DeviceID = "0013130010"; /// /// 发送不需要回复 /// public const string SendNotReply = "1" + DeviceID + "0"; /// /// 发送需要回复 /// public const string SendandReply = "1" + DeviceID + "1"; /// /// 出库站台启用已分配任务 /// public const string OutBoundStationEnableDistribution = "1000"; /// /// 出库站台启用未分配任务 /// public const string OutBoundStationEnableUndistributed = "1100"; /// /// 出库站台禁用 /// public const string OutBoundStationDisabled = "0000"; /// /// 入库站台个数 /// public const string InBoundStationCount = "1"; /// /// 入库站台状态 /// public const string InBoundStationStatus = "1010001"; /// /// 预留 /// public const string Spare1 = "0000000000000000000000000000000000000000000000000000000000000000000000"; /// /// 出库站台预留 /// public const string OutStationSpare2 = "000000000000"; /// /// 预留 /// public const string Spare3 = "000"; /// /// 托盘号 /// public const string Spare4 = "0000000000"; #endregion #region WMS下发HOST方法 /// /// 设备请求入库 工序101 /// /// 托盘号 /// 入库站台 public void DeviceRequestInbound(HOSTAGVStatus Agvstatus, List outStations, InStationStatus inStation) { try { string str = SendandReply + "101" + BaseDal.GetSeqNo().Result.ToString("D5") + GetFieldsAsString(Agvstatus) + GetListStringOutStation(outStations) + "1" + GetFieldsAsString(inStation); clientSend(MakeStringToByteMsg(str)); } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// 请求通讯 工序925 /// /// 托盘号 /// 入库站台 public void RequestCommunication() { try { string str = SendandReply + "925" + BaseDal.GetSeqNo().Result.ToString("D5"); clientSend(MakeStringToByteMsg(str)); } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// 不允许下发任务 工序915 /// /// 命令 /// public void JobReady(string Command) { try { string str = SendNotReply + "915" + BaseDal.GetSeqNo().Result.ToString("D5") + Command; clientSend(MakeStringToByteMsg(str)); } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// 设备状态上报 工序913 /// /// 状态\、R运行 /// public void DeviceStateReport(string Status) { try { string str = SendNotReply + "913" + BaseDal.GetSeqNo().Result.ToString("D5") + Status; clientSend(MakeStringToByteMsg(str)); } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// 设备状态上报 工序917 /// /// 状态\、R运行 /// public void DeviceAutoStatusReport(string Status) { try { string str = SendNotReply + "917" + BaseDal.GetSeqNo().Result.ToString("D5") + Status; clientSend(MakeStringToByteMsg(str)); } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// /// 作业开始或结束 工序905 /// /// 状态 L指AGV将托盘叉到货叉上、U指AGV将托盘放到库位上 /// 起点 /// 终点 /// 任务类型 I入库、O出库、S站台到站台、R移库 /// 托盘号 public void JobStartOrEnd(string Status, string FormLocation, string ToLocation, string TaskType, string PallteCode) { try { string str = SendandReply + "905" + BaseDal.GetSeqNo().Result.ToString("D5") + Status + JobOrderID + priority + FormLocation + ToLocation + TaskType + TrayCnt + PallteCode; clientSend(MakeStringToByteMsg(str)); } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// 托盘动作上报 工序907 /// /// 状态 L指AGV将托盘叉到货叉上、U指AGV将托盘放到库位上 /// 起点 /// 终点 /// 任务类型 I入库、O出库、S站台到站台、R移库 /// 托盘号 /// public void PalletActionReport(string Status, string FormLocation, string ToLocation, string TaskType, string PallteCode) { try { string str = SendNotReply + "907" + BaseDal.GetSeqNo().Result.ToString("D5") + Status + JobOrderID + priority + FormLocation + ToLocation + TaskType + TrayCnt + PallteCode; clientSend(MakeStringToByteMsg(str)); } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// 作业完成上报 工序901 /// /// 起点 /// 终点 /// 任务类型 I入库、O出库、S站台到站台、R移库 /// 托盘号 /// public void PalletActionReport(string FormLocation, string ToLocation, string TaskType, string PallteCode) { try { string str = SendandReply + "901" + BaseDal.GetSeqNo().Result.ToString("D5") + "0" + JobOrderID + priority + FormLocation + ToLocation + TaskType + TrayCnt + PallteCode; clientSend(MakeStringToByteMsg(str)); } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// 设备站台状态上报 工序936 /// /// 起点 /// 终点 /// 任务类型 I入库、O出库、S站台到站台、R移库 /// 托盘号 /// public void DeviceStationStatusReport(HOSTAGVStatus Agvstatus, List outStations, List inStation, string sGetSeqNo) { try { var agvstatus = GetFieldsAsString(Agvstatus); var outstation = GetListStringOutStation(outStations); var instation = GetListStringInStation(inStation); string str = SendNotReply + "936" + sGetSeqNo + agvstatus + outstation + OutStationSpare2 + "2" + instation; clientSend(MakeStringToByteMsg(str)); } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// /// 重新获取货位信息 工序105 /// /// 起点 /// 终点 /// 任务类型 I入库、O出库、S站台到站台、R移库 /// 托盘号 public void RecreateGetLocation(string FormLocation, string ToLocation, string TaskType, string PallteCode) { try { string str = SendandReply + "105" + BaseDal.GetSeqNo().Result.ToString("D5") + "R" + JobOrderID + priority + FormLocation + ToLocation + TaskType + TrayCnt + PallteCode; clientSend(MakeStringToByteMsg(str)); } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// /// 异常上报 工序985 /// /// 起点 /// 终点 /// 00表示AGV错误、01-08表示站台错误、99表示作业接收前数据错误 public void ErrorReport(string Trouble, string Level, string Location) { try { string str = SendNotReply + "985" + BaseDal.GetSeqNo().Result.ToString("D5") + Trouble + Level + Location; clientSend(MakeStringToByteMsg(str)); } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// 接收HOST工序103回馈响应 工序104 /// /// 0表示OK接收作业、1表示拒绝、9表示作业任务验证有误 /// public void DeviceReceiveJobResponse(string Statues) { try { string str = SendNotReply + "104" + BaseDal.GetSeqNo().Result.ToString("D5") + Statues; clientSend(MakeStringToByteMsg(str)); } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// /// 空出库 工序107 /// /// 起点 /// 终点 /// 任务类型 I入库、O出库、S站台到站台、R移库 /// 托盘号 public void EmptyOutBound(string FormLocation, string ToLocation, string PallteCode) { try { string str = SendandReply + "107" + BaseDal.GetSeqNo().Result.ToString("D5") + "1" + JobOrderID + priority + FormLocation + ToLocation + "O" + TrayCnt + PallteCode; clientSend(MakeStringToByteMsg(str)); } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// 回复HOST909工序 工序910 /// /// public void DeviceStatusReportResponse(HOSTAGVStatus AgvStatus, string X, string Y) { string str = SendNotReply + "910" + BaseDal.GetSeqNo().Result.ToString("D5") + GetFieldsAsString(AgvStatus) + X + Y; clientSend(MakeStringToByteMsg(str)); } #endregion #region WMS接收HOST回传方法 /// /// 接收HOST 响应请求 工序102 回复工序101 /// /// public void ReceiveCommandResponse(string message) { var parseMessage = GetParse(message); switch (parseMessage.body.ret) { //OK case "0": var location = _locationRepository.QueryFirst(x => x.LocationCode == parseMessage.body.ToLocation); if (location == null) { return; } if (location.LocationStatus == (int)LocationEnum.Free) { InsertWMSTask(parseMessage); Thread.Sleep(500); //915 JobReady("0"); return; } else { //todo货位有货重复入库 return; } //NG case "1": break; //无库位分配 case "2": break; //站台到站台,出库站台未准备好 case "3": break; //非常温工程 case "4": break; case "9": break; default: break; } } /// /// 接收HOST响应AGV作业开始或启动 工序906 回复工序905 /// public void AGVJobStartOrEndResponse(string status, string message) { switch (message) { //OK case "0": if (status == "E") { DeviceStateReport("I"); Thread.Sleep(3000); JobReady("1"); } break; //NG case "1": //调用AGV暂停接口 break; case "9": break; default: break; } } /// /// 数据报告响应 工序902 回复工序901 /// public void DataReportResponse(string message) { Dt_Task task = BaseDal.QueryFirst(x => x.TaskState == (int)TaskOutStatusEnum.AGV_OutFinish || x.TaskState == (int)TaskRelocationStatusEnum.AGV_RelocationFinish || x.TaskState == (int)TaskInStatusEnum.AGV_InFinish); if (task != null) { switch (task.TaskType) { case (int)TaskInboundTypeEnum.Inbound: //入库 task.TaskState = (int)TaskInStatusEnum.AGV_InFinish; if (message == "0") { JobStartOrEnd("E", task.SourceAddress, task.TargetAddress, "O", task.PalletCode); } CompleteInboundTask(task); break; case (int)TaskOutboundTypeEnum.Outbound: //出库 if (message == "0") { JobStartOrEnd("E", task.SourceAddress, task.TargetAddress, "O", task.PalletCode); } task.TaskState = (int)TaskOutStatusEnum.AGV_OutFinish; CompleteOutboundTask(task); break; case (int)TaskRelocationTypeEnum.Relocation: if (message == "0") { JobStartOrEnd("E", task.SourceAddress, task.TargetAddress, "O", task.PalletCode); } task.TaskState = (int)TaskRelocationStatusEnum.AGV_RelocationFinish; CompleteRelocationboundTask(task); break; case (int)TaskStationTypeEnum.StationToStation: if (message == "0") { JobStartOrEnd("E", task.SourceAddress, task.TargetAddress, "O", task.PalletCode); } task.TaskState = (int)TaskOutStatusEnum.AGV_OutFinish; TaskMoveHty(task); break; default: break; } } } /// /// HOST下发出库任务 工序103 /// /// public void HOSTOutBoundTask(string message) { try { var parseMessage = GetParse(message); switch (parseMessage.body.ret) { //OK case "0": var location = _locationRepository.QueryFirst(x => x.LocationCode == parseMessage.body.ToLocation); if (location == null) { return; } if (location.LocationStatus == (int)LocationEnum.InStock) { var task = InsertWMSTask(parseMessage); BaseDal.AddData(task); InsertAGVTask(task); Thread.Sleep(500); //915 JobReady("0"); Thread.Sleep(500); //104 DeviceReceiveJobResponse("0"); } else { //todo货位无货空出库 return; } break; default: break; } } catch (Exception) { DeviceReceiveJobResponse("1"); } } /// /// HOST设备状态获取 工序935 /// /// public void DeviceStationStatusInvite(string sSeqNo) { try { //回复936 List outStationStatus = new List(); List inStationStatus = new List(); StationStatus stationIn = GetStationStatus("B002"); inStationStatus.Add(new InStationStatus() { StationName = "02", StationEnable = stationIn.WorkstationO == "1" ? "0" : "1", IsDistributionTask = "0", PallteCode = "0000000000", }); inStationStatus.Add(new InStationStatus() { StationName = "01", StationEnable = stationIn.WorkstationT == "1" ? "0" : "1", IsDistributionTask = "0", PallteCode = "0000000000", }); StationStatus stationOut = GetStationStatus("B001"); var taskOutStationO = BaseDal.QueryFirst(x => x.SourceAddress == "B001::1" || x.TargetAddress == "B001::1"); var taskOutStationT = BaseDal.QueryFirst(x => x.SourceAddress == "B001::2" || x.TargetAddress == "B001::2"); outStationStatus.Add(new OutStationStatus() { StationName = "04", StationEnable = stationOut.WorkstationO == "1" ? "0" : "1", IsDistributionTask = taskOutStationO == null ? "0" : "1", Spare1 = "00" }); outStationStatus.Add(new OutStationStatus() { StationName = "03", StationEnable = stationOut.WorkstationT == "1" ? "0" : "1", IsDistributionTask = taskOutStationT == null ? "0" : "1", Spare1 = "00" }); AGVStatusRespone status = GetAGVStatus(); HOSTAGVStatus AgvStatus = new HOSTAGVStatus() { RuntimeStatus = CapitalizeFirstLetter(status.RuntimeStatus), AutoStatus = status.AutoStatus == "MaintenanceMode" ? "1" : "0", Ready = status.AutoStatus == "MaintenanceMode" ? "0" : "1", }; DeviceStationStatusReport(AgvStatus, outStationStatus, inStationStatus, sSeqNo); } catch (Exception) { DeviceReceiveJobResponse("1"); } } /// /// 接收HOST重新分配货位 工序106 /// /// public void RecreateGetLocation(string message) { try { var parseMessage = GetParse(message); switch (parseMessage.body.ret) { //OK case "0": UpdateTaskLocation(parseMessage); break; //NG case "1": break; //无库位分配 case "2": break; case "9": break; default: break; } } catch (Exception) { DeviceReceiveJobResponse("1"); } } /// /// HOST空出库响应 工序108 /// /// public void EmptyOutBoundResponse(string message) { if (message != null && message == "0") { DeviceStateReport("I"); Thread.Sleep(500); JobReady("1"); } } /// /// HOST获取设备状态 工序909 /// public void DeviceStatusReportRequest() { AGVStatusRespone status = GetAGVStatus(); HOSTAGVStatus AgvStatus = new HOSTAGVStatus() { RuntimeStatus = CapitalizeFirstLetter(status.RuntimeStatus), AutoStatus = status.AutoStatus == "MaintenanceMode" ? "1" : "0", Ready = status.AutoStatus == "MaintenanceMode" ? "0" : "1", }; string axis = "000000"; DeviceStatusReportResponse(AgvStatus, axis, axis); } #endregion #region 全局方法 /// /// 拼接报文 /// /// /// /// public byte[] MakeStringToByteMsg(string Message) { try { byte[] byt = Encoding.UTF8.GetBytes(Message); // 使用 UTF-8 避免编码问题 string checksum = GetCheckSum(byt); string str = Message + checksum; byte[] buffer = Encoding.UTF8.GetBytes(str); byte newFirstByte = 2; // 新的第一位数据 byte newLastByte = 3; // 新的最后一位数据 // 创建一个新数组,长度比原始数组多2 byte[] newArray = new byte[buffer.Length + 2]; // 将新的数据插入到新数组的第一位 newArray[0] = newFirstByte; // 将新的数据插入到新数组的最后一位 newArray[newArray.Length - 1] = newLastByte; // 复制原始数组的所有数据到新数组的中间部分 Array.Copy(buffer, 0, newArray, 1, buffer.Length); //var parseMessage = GetParse(str); LogFactory.GetLog("Socket发送报文").Info(true, str); return newArray; } catch (Exception ex) { throw new Exception(ex.Message); } } public string GetListStringOutStation(List outStationStatus) { return string.Join("", outStationStatus.Select(status => $"{status.StationName}{status.StationEnable}{status.IsDistributionTask}{status.Spare1}")); } public string GetListStringInStation(List inStationStatus) { return string.Join("", inStationStatus.Select(status => $"{status.StationName}{status.StationEnable}{status.IsDistributionTask}{status.IsHasPallte}{status.Spare1}{status.StationPallteCount}{status.PallteCode}{status.Spare2}")); } /// /// 将对象值凭拼接 /// /// /// public static string GetFieldsAsString(object obj) { if (obj == null) { return "Object is null"; } StringBuilder builder = new StringBuilder(); Type type = obj.GetType(); foreach (PropertyInfo property in type.GetProperties()) { if (property.CanRead) { object value = property.GetValue(obj); if (value != null) { builder.Append(value); } } } return builder.ToString(); } /// /// 获取CheckSum值 /// /// /// /// public string GetCheckSum(byte[] data) { int sum = 0; try { for (int i = 0; i < data.Length; i++) { sum += data[i]; } string str = sum.ToString(); return str.Substring(str.Length - 2); } catch (Exception ex) { throw new Exception(ex.Message); } } public ParseMessage SubString(string Y) { const string STX = "0x02"; const string ETX = "0x03"; // 检查是否以 STX 开头、ETX 结尾 if (Y.Substring(0, 4) == STX && Y.Substring(Y.Length - 4) == ETX) { string str = Y.Substring(4, Y.Length - 8); byte[] message = Encoding.UTF8.GetBytes(str); int newLength = message.Length - 2; if (newLength < 0) { throw new ArgumentException("数组长度不足,无法去掉最后两位。"); } byte[] newArray = new byte[newLength]; Array.Copy(message, 0, newArray, 0, newLength); string calculatedChecksum = GetCheckSum(newArray); string receivedChecksum = str.Substring(str.Length - 2); if (calculatedChecksum == receivedChecksum) { var x = Encoding.UTF8.GetString(newArray); ParseMessage parseMessage = new ParseMessage() { bDir = x.Substring(0, 1), bObjID = x.Substring(2, 10), bReply = x.Substring(11, 1), bCmdID = x.Substring(12, 3), nSeqNo = x.Substring(15, 5), //Body = x.Substring(21), }; return parseMessage; } else { Console.WriteLine("校验失败!"); return null; } } else { Console.WriteLine("无效报文格式!"); return null; } } #endregion #region 定义对象 #endregion #region 私有方法 private void UpdateTaskLocation(ParseMessage parseMessage) { var task = BaseDal.QueryFirst(x => x.SeqNo == Convert.ToInt32(parseMessage.nSeqNo) && x.PalletCode.Contains(parseMessage.body.TrayIdList)); if (task != null) { task.TargetAddress = parseMessage.body.ToLocation; task_call agvtask = SqlSugarHelper.DbAGV.Queryable().Where(it => it.d_involed5 == task.TaskNum).First(); BaseDal.Update(task); SqlSugarHelper.DbAGV.Updateable(agvtask).ExecuteCommand(); } } private Dt_Task InsertWMSTask(ParseMessage parseMessage) { //var task = BaseDal.QueryFirst(x => x.PalletCode.Contains(parseMessage.body.TrayIdList)); int taskType = 0; int taskState = 0; if (parseMessage.body.JobType == "I") { taskType = (int)TaskInboundTypeEnum.Inbound; taskState = (int)TaskInStatusEnum.InNew; } else if (parseMessage.body.JobType == "O") { taskType = (int)TaskOutboundTypeEnum.Outbound; taskState = (int)TaskOutStatusEnum.OutNew; } else if (parseMessage.body.JobType == "S") { taskType = (int)TaskStationTypeEnum.StationToStation; taskState = (int)TaskOutStatusEnum.OutNew; } else if (parseMessage.body.JobType == "R") { taskType = (int)TaskRelocationTypeEnum.Relocation; taskState = (int)TaskRelocationStatusEnum.RelocationNew; } else { throw new Exception("未知库位"); } return new Dt_Task() { TaskNum = BaseDal.GetTaskNo().Result, SourceAddress = parseMessage.body.FromLocation, TargetAddress = parseMessage.body.ToLocation, PalletCode = parseMessage.body.TrayIdList.Substring(0, 10), TaskType = taskType, TaskState = taskState, Dispatchertime = DateTime.Now, SeqNo = Convert.ToInt32(parseMessage.nSeqNo), CommandID = Convert.ToInt32(parseMessage.bCmdID) }; } /// /// 添加AGV任务 /// /// 任务对象 /// private int InsertAGVTask(Dt_Task task) { string SourceAddress = string.Empty; string TargetAddress = string.Empty; if (task.TaskType == (int)TaskInboundTypeEnum.Inbound) { TargetAddress = InsertHyphenEveryTwoChars(task.TargetAddress); } else if (task.TaskType == (int)TaskOutboundTypeEnum.Outbound) { SourceAddress = InsertHyphenEveryTwoChars(task.SourceAddress); } else if (task.TaskType == (int)TaskRelocationTypeEnum.Relocation) { TargetAddress = InsertHyphenEveryTwoChars(task.TargetAddress); SourceAddress = InsertHyphenEveryTwoChars(task.SourceAddress); } else if (task.TaskType == (int)TaskStationTypeEnum.StationToStation) { TargetAddress = task.TargetAddress; SourceAddress = task.SourceAddress; } task_call task_Call = new task_call() { d_task_type = task.TaskType == (int)TaskTypeEnum.Inbound ? 1 : 2, d_floor = 1, d_involed1 = SourceAddress, d_involed2 = TargetAddress, d_involed5 = task.TaskNum, }; return SqlSugarHelper.DbAGV.Insertable(task_Call).ExecuteCommand(); } public ParseMessage GetParse(string x) { return new ParseMessage() { bDir = x.Substring(0, 1), bObjID = x.Substring(2, 10), bReply = x.Substring(11, 1), bCmdID = x.Substring(12, 3), nSeqNo = x.Substring(15, 5), body = new ReceiveBody { ret = x.Substring(21, 1), JobOrderID = x.Substring(22, 16), priority = x.Substring(39, 1), FromLocation = x.Substring(40, 6), ToLocation = x.Substring(47, 6), JobType = x.Substring(54, 1), TrayCnt = x.Substring(55, 1), TrayIdList = x.Substring(56) }, }; } public AGVStatusRespone GetAGVStatus() { string urlnew = url + "/ilns/AGV/getState"; var result = HttpsClient.PostAsync(urlnew, JsonConvert.DeserializeObject>(new { getStatus = "1" }.ToJson())).Result; return JsonConvert.DeserializeObject(result.ToString()); } public StationStatus GetStationStatus(string stationName) { string urlnew = url + "/ilns/ctrl/getState"; var result = HttpsClient.PostAsync(urlnew, JsonConvert.DeserializeObject>(new { ctrlName = "B001" }.ToJson())).Result; return JsonConvert.DeserializeObject(result.ToString()); } public string CapitalizeFirstLetter(string s) { if (string.IsNullOrEmpty(s)) { return ""; } char firstChar = s[0]; return char.ToUpper(firstChar).ToString(); } public string InsertHyphenEveryTwoChars(string input) { if (string.IsNullOrEmpty(input)) { return input; } StringBuilder result = new StringBuilder(); for (int i = 0; i < input.Length; i += 2) { // 添加两个字符 result.Append(input.Substring(i, 2)); // 如果不是最后两个字符,添加一个连字符 if (i + 2 < input.Length) { result.Append('-'); } } return result.ToString(); } #region 外部接口方法 public WebResponseContent CompleteInboundTask(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { _unitOfWorkManage.BeginTran(); var locationInf = _locationRepository.QueryFirst(x => x.LocationCode == task.TargetAddress); locationInf.LocationStatus = (int)LocationEnum.InStock; var stock = new DtStockInfo() { PalletCode = task.PalletCode, LocationCode = task.TargetAddress, CreateDate = DateTime.Now, Creater = "system", LocationId = locationInf.Id, }; _stockInfoRepository.AddData(stock); _locationRepository.UpdateData(locationInf); TaskMoveHty(task); _unitOfWorkManage.CommitTran(); return content.OK(); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return content.Error(ex.Message); } } public WebResponseContent CompleteOutboundTask(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { _unitOfWorkManage.BeginTran(); var locationInf = _locationRepository.QueryFirst(x => x.LocationCode == task.TargetAddress); locationInf.LocationStatus = (int)LocationEnum.Free; var stock = _stockInfoRepository.QueryFirst(x => x.PalletCode == task.PalletCode); DtStockInfo_Hty stockInfo_Hty = stock.Adapt(); stockInfo_Hty.ModifyDate = DateTime.Now; AddStockInfoHty(stockInfo_Hty); _stockInfoRepository.DeleteData(stock); _locationRepository.UpdateData(locationInf); TaskMoveHty(task); _unitOfWorkManage.CommitTran(); return content.OK(); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return content.Error(ex.Message); } } public WebResponseContent CompleteRelocationboundTask(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { _unitOfWorkManage.BeginTran(); var locationInf = _locationRepository.QueryFirst(x => x.LocationCode == task.TargetAddress); var location = _locationRepository.QueryFirst(x => x.LocationCode == task.SourceAddress); locationInf.LocationStatus = (int)LocationEnum.InStock; location.LocationStatus = (int)LocationEnum.Free; var stock = _stockInfoRepository.QueryFirst(x => x.PalletCode == task.PalletCode); stock.LocationCode = locationInf.LocationCode; stock.LocationId = locationInf.Id; _stockInfoRepository.UpdateData(stock); _locationRepository.UpdateData(locationInf); _locationRepository.UpdateData(location); TaskMoveHty(task); _unitOfWorkManage.CommitTran(); return content.OK(); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return content.Error(ex.Message); } } public WebResponseContent TaskMoveHty(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { _unitOfWorkManage.BeginTran(); var taskHtyNG = CreateHistoricalTask(task); var isTaskHtyAdd = _task_HtyRepository.AddData(taskHtyNG) > 0; var isTaskDelete = Delete(task.TaskId); var AgvTask = SqlSugarHelper.DbAGV.Queryable().Where(x => x.d_involed5 == task.TaskNum).First(); if (AgvTask != null) { SqlSugarHelper.DbAGV.Deleteable(AgvTask).ExecuteCommand(); } _unitOfWorkManage.CommitTran(); return content.OK(); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return content.Error(ex.Message); } } #endregion 外部接口方法 #region private 内部方法 /// /// 创建历史任务记录 /// /// /// public Dt_Task_Hty CreateHistoricalTask(Dt_Task task, bool isHand = false) { task.CurrentAddress = task.NextAddress; // 创建历史任务 var taskHty = _mapper.Map(task); taskHty.FinishTime = DateTime.Now; taskHty.TaskId = 0; taskHty.OperateType = isHand ? (int)OperateTypeEnum.人工删除 : App.User.UserName != null ? (int)OperateTypeEnum.人工完成 : (int)OperateTypeEnum.自动完成; taskHty.SourceId = task.TaskId; if (isHand) { taskHty.Creater = App.User.UserName != null ? App.User.UserName : "System"; } return taskHty; } /// /// 删除一个任务 /// /// 任务ID /// 是否删除成功 public bool Delete(int id) { return BaseDal.Delete(id); } private void AddStockInfoHty(DtStockInfo_Hty dtStock) { var isStockAdd = SqlSugarHelper.DbWMS.InsertNav(dtStock).IncludesAllFirstLayer().ExecuteCommand(); if (!isStockAdd) { throw new Exception("库存历史信息添加失败"); } } #endregion private 内部方法 #endregion } }