diff --git a/Tools/LogTool/WcsLog.cs b/Tools/LogTool/WcsLog.cs
index ba5cd73..2286ebc 100644
--- a/Tools/LogTool/WcsLog.cs
+++ b/Tools/LogTool/WcsLog.cs
@@ -27,20 +27,20 @@ public class WcsLog
lock (writeLog)
{
string LogAddress = AppDomain.CurrentDomain.BaseDirectory + "Log\\" + LogName;
+ DirectoryInfo di = new(LogAddress);
+ if (di.Exists == false) { di.Create(); }
StringBuilder logBuilder = new();
if (addTime)
{
logBuilder.AppendLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss:fff}]");
}
logBuilder.AppendLine($"{strLog}");
- DirectoryInfo di = new(LogAddress);
- if (di.Exists == false) { di.Create(); }
string logFileName = LogAddress + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + ".log";
using FileStream fs = new(logFileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
using StreamWriter sw = new(fs);
try
{
- sw.WriteLine(logBuilder);
+ sw.Write(logBuilder);
}
catch (Exception ex)
{
diff --git a/WcsMain/ApiServe/Controllers/Dto/WcsDto/Location/GetLocationWithPageRequest.cs b/WcsMain/ApiServe/Controllers/Dto/WcsDto/Location/GetLocationWithPageRequest.cs
index 4b40dd0..8a39603 100644
--- a/WcsMain/ApiServe/Controllers/Dto/WcsDto/Location/GetLocationWithPageRequest.cs
+++ b/WcsMain/ApiServe/Controllers/Dto/WcsDto/Location/GetLocationWithPageRequest.cs
@@ -15,10 +15,16 @@ public class GetLocationWithPageRequest
public string? SearchStr { get; set; }
///
- /// 任务类型
+ /// 点位状态
///
[JsonPropertyName("locationStatus")]
- public List? LocationStatus { get; set; }
+ public List? LocationStatus { get; set; }
+
+ ///
+ /// 点位类型
+ ///
+ [JsonPropertyName("locationType")]
+ public List? LocationType { get; set; }
///
/// 分页信息
diff --git a/WcsMain/ApiServe/Controllers/Dto/WcsDto/Stacker/GetStackerStatusResponse.cs b/WcsMain/ApiServe/Controllers/Dto/WcsDto/Stacker/GetStackerStatusResponse.cs
new file mode 100644
index 0000000..2e36547
--- /dev/null
+++ b/WcsMain/ApiServe/Controllers/Dto/WcsDto/Stacker/GetStackerStatusResponse.cs
@@ -0,0 +1,101 @@
+using System.Text.Json.Serialization;
+
+namespace WcsMain.ApiServe.Controllers.Dto.WcsDto.Stacker;
+
+///
+/// 查询堆垛机状态的返回实体
+///
+public class GetStackerStatusResponse
+{
+
+ ///
+ /// 设备编号
+ ///
+ [JsonPropertyName("stackerId")]
+ public int? StackerId { get; set; }
+
+ ///
+ /// 堆垛机名称
+ ///
+ [JsonPropertyName("stackerName")]
+ public string? StackerName { get; set; }
+
+ ///
+ /// 堆垛机状态
+ ///
+ ///
+ /// 0 - 禁用
+ /// 1 - 启用
+ ///
+ [JsonPropertyName("stackerStatus")]
+ public int? StackerStatus { get; set; }
+
+ ///
+ /// 货叉状态
+ ///
+ [JsonPropertyName("forkStatus")]
+ public string? ForkStatus { get; set; }
+
+ ///
+ /// 查询结果
+ ///
+ [JsonPropertyName("msg")]
+ public string? Message { get; set; } = "-";
+
+ ///
+ /// 当前运行任务号
+ ///
+ [JsonPropertyName("plcId")]
+ public string? PlcId { get; set; }
+
+ ///
+ /// 控制方式
+ ///
+ [JsonPropertyName("controlModel")]
+ public string? ControlModel { get; set; } = "0";
+
+ ///
+ /// 设备状态
+ ///
+ [JsonPropertyName("stackerStatusEquip")]
+ public string? StackerStatusEquip { get; set; } = "0";
+
+ ///
+ /// 排
+ ///
+ [JsonPropertyName("queue")]
+ public int? Queue { get; set; }
+
+ ///
+ /// 列
+ ///
+ [JsonPropertyName("line")]
+ public int? Line { get; set; }
+
+ ///
+ /// 层
+ ///
+ [JsonPropertyName("layer")]
+ public int? Layer { get; set; }
+
+ ///
+ /// 深
+ ///
+ [JsonPropertyName("depth")]
+ public int? Depth { get; set; }
+
+ ///
+ /// 条码
+ ///
+ [JsonPropertyName("code")]
+ public string? Code { get; set; }
+
+ ///
+ /// 报警编号
+ ///
+ [JsonPropertyName("errCode")]
+ public int? ErrCode { get; set; }
+
+
+
+}
diff --git a/WcsMain/ApiServe/Controllers/WcsController/StackerController.cs b/WcsMain/ApiServe/Controllers/WcsController/StackerController.cs
index afe644f..653e288 100644
--- a/WcsMain/ApiServe/Controllers/WcsController/StackerController.cs
+++ b/WcsMain/ApiServe/Controllers/WcsController/StackerController.cs
@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using WcsMain.ApiServe.ControllerFilter.ExceptionFilter;
using WcsMain.ApiServe.Controllers.Dto;
+using WcsMain.ApiServe.Controllers.Dto.WcsDto.Stacker;
using WcsMain.ApiServe.Service.WcsService;
using WcsMain.DataBase.TableEntity;
@@ -24,4 +25,14 @@ public class StackerController(StackerService stackerService) : ControllerBase
{
return _stackerService.GetStacker();
}
+
+ ///
+ /// 查询所有的 堆垛机状态信息 ---- 从设备返回
+ ///
+ ///
+ [HttpGet("getStackerStatus")]
+ public WcsApiResponse> GetStackerStatus()
+ {
+ return _stackerService.GetStackerStatus();
+ }
}
\ No newline at end of file
diff --git a/WcsMain/ApiServe/Service/WcsService/StackerService.cs b/WcsMain/ApiServe/Service/WcsService/StackerService.cs
index 618b90c..e454e3d 100644
--- a/WcsMain/ApiServe/Service/WcsService/StackerService.cs
+++ b/WcsMain/ApiServe/Service/WcsService/StackerService.cs
@@ -1,16 +1,20 @@
-using WcsMain.ApiServe.Controllers.Dto;
+using System.Collections.Generic;
+using WcsMain.ApiServe.Controllers.Dto;
+using WcsMain.ApiServe.Controllers.Dto.WcsDto.Stacker;
using WcsMain.ApiServe.Factory;
using WcsMain.DataBase.Dao;
using WcsMain.DataBase.TableEntity;
+using WcsMain.PlcOperation.Stacker;
using WcsMain.WcsAttribute.AutoFacAttribute;
namespace WcsMain.ApiServe.Service.WcsService;
[Service]
-public class StackerService(AppStackerDao stackerDao)
+public class StackerService(AppStackerDao stackerDao, StackerOperation stackerOperation)
{
private readonly AppStackerDao _stackerDao = stackerDao;
+ private readonly StackerOperation _stackerOperation = stackerOperation;
///
/// 查询所有的 堆垛机信息
@@ -26,4 +30,49 @@ public class StackerService(AppStackerDao stackerDao)
return WcsApiResponseFactory.Success(stackers, "查询成功");
}
+ ///
+ /// 查询所有的 堆垛机状态信息 ---- 从设备返回
+ ///
+ ///
+ public WcsApiResponse> GetStackerStatus()
+ {
+ List? stackers = _stackerDao.Select(new AppStacker());
+ if (stackers == default)
+ {
+ return WcsApiResponseFactory.DataBaseErr>();
+ }
+ List getStackerStatusResponses = [];
+ foreach(AppStacker stacker in stackers)
+ {
+ GetStackerStatusResponse stackerStatusResponse = new()
+ {
+ StackerId = stacker.StackerId,
+ StackerName = stacker.StackerName,
+ StackerStatus = stacker.StackerStatus,
+ ForkStatus = stacker.ForkStatus,
+ };
+ /* 获取堆垛机状态 */
+ var (errMsg, stackerInfo) = _stackerOperation.GetStackerInfo((int)stacker.StackerId!);
+ if(string.IsNullOrEmpty(errMsg) && stackerInfo != default)
+ {
+ stackerStatusResponse.Message = "查询成功";
+ stackerStatusResponse.PlcId = stackerInfo.PlcId.ToString();
+ stackerStatusResponse.ControlModel = stackerInfo.ControlModel.ToString();
+ stackerStatusResponse.StackerStatusEquip = stackerInfo.StackerStatus.ToString();
+ stackerStatusResponse.Queue = stackerInfo.Row;
+ stackerStatusResponse.Line = stackerInfo.Line;
+ stackerStatusResponse.Layer = stackerInfo.Layer;
+ stackerStatusResponse.Depth = stackerInfo.Depth;
+ stackerStatusResponse.Code = stackerInfo.Code.ToString();
+ stackerStatusResponse.ErrCode = stackerInfo.ErrCode;
+ }
+ else
+ {
+ stackerStatusResponse.Message = errMsg;
+ }
+ getStackerStatusResponses.Add(stackerStatusResponse);
+ }
+ return WcsApiResponseFactory.Success(getStackerStatusResponses, "查询成功");
+ }
+
}
diff --git a/WcsMain/AppEntity/SystemData/AppSettingJsonEntity.cs b/WcsMain/AppEntity/SystemData/AppSettingJsonEntity.cs
index 70b6e5a..9e21809 100644
--- a/WcsMain/AppEntity/SystemData/AppSettingJsonEntity.cs
+++ b/WcsMain/AppEntity/SystemData/AppSettingJsonEntity.cs
@@ -46,4 +46,9 @@ public class ApplicationConfig
/// 是否仅以 api 形式运行,此状态下不会运行 Wcs 相关内容
///
public bool? ApiOnly { get; set; }
+
+ ///
+ /// 程序的语言
+ ///
+ public string? Language { get; set; } = "zh-CN";
}
\ No newline at end of file
diff --git a/WcsMain/Business/CirculationTask/CommonCirculation/HeartBeat.cs b/WcsMain/Business/CirculationTask/CommonCirculation/HeartBeat.cs
index af0b03d..45e385b 100644
--- a/WcsMain/Business/CirculationTask/CommonCirculation/HeartBeat.cs
+++ b/WcsMain/Business/CirculationTask/CommonCirculation/HeartBeat.cs
@@ -4,13 +4,14 @@ using WcsMain.PlcOperation;
namespace WcsMain.Business.CirculationTask.CommonCirculation;
[Circulation]
-public class HeartBeat
+public class HeartBeat(ConveyOperation conveyOperation)
{
+ private readonly ConveyOperation _conveyOperation = conveyOperation;
- //[Circulation("输送机心跳", 1000)]
+ [Circulation("输送机心跳", 1000)]
public bool ConveyHeartBeat()
{
- ConveyOperation.Instance().WriteHeartBeat();
+ _conveyOperation.WriteHeartBeat();
return true;
}
diff --git a/WcsMain/Business/CirculationTask/Stacker/ExeTaskDoubleFork.cs b/WcsMain/Business/CirculationTask/Stacker/ExeTaskDoubleFork.cs
new file mode 100644
index 0000000..a27c296
--- /dev/null
+++ b/WcsMain/Business/CirculationTask/Stacker/ExeTaskDoubleFork.cs
@@ -0,0 +1,469 @@
+using CirculateTool;
+using WcsMain.Business.CommonAction;
+using WcsMain.Common;
+using WcsMain.DataBase.Dao;
+using WcsMain.DataBase.MixDao;
+using WcsMain.DataBase.TableEntity;
+using WcsMain.DataService;
+using WcsMain.Enum.Stacker;
+using WcsMain.Enum.TaskEnum;
+using WcsMain.ExtendMethod;
+using WcsMain.PlcOperation;
+using WcsMain.PlcOperation.Entity.Stacker;
+using WcsMain.PlcOperation.Stacker;
+using static Dm.net.buffer.ByteArrayBuffer;
+
+namespace WcsMain.Business.CirculationTask.Stacker;
+
+
+///
+/// 双货叉单深位执行堆垛机任务 ---- 卡特模式
+///
+[Circulation("双货叉单深位执行堆垛机任务")]
+public class ExeTaskDoubleFork(
+ StackerOperation stackerOperation, AppWcsTaskDao wcsTaskDao, WCSTaskExecuteEvent wcsTaskEvent,
+ ConveyOperation conveyOperation, DataBaseData dataBaseData)
+{
+ private readonly WCSTaskExecuteEvent _wcsTaskEvent = wcsTaskEvent;
+ private readonly AppWcsTaskDao _wcsTaskDao = wcsTaskDao;
+ private readonly StackerOperation _stackerOperation = stackerOperation;
+ private readonly ConveyOperation _conveyOperation = conveyOperation;
+ private readonly DataBaseData _dataBaseData = dataBaseData;
+
+ ///
+ /// 执行堆垛机任务
+ ///
+ ///
+ [Circulation("执行堆垛机任务")]
+ public bool ExecuteStackerTask()
+ {
+ List tasks = [];
+ foreach (var stacker in CommonData.AppStackers.Open())
+ {
+ tasks.Add(Task.Factory.StartNew(() =>
+ {
+ var stackerUseStatus = _stackerOperation.StackerCanUse(stacker.StackerId, out int plcId, out int spare1);
+ if (stackerUseStatus == StackerUseStatusEnum.Free)
+ {
+ /* 空闲时正常执行任务 */
+ // 移库
+ bool exeMoveTask = ExecuteMoveTask(stacker.StackerId);
+ if (exeMoveTask) return;
+ // 出库
+ bool exeOutTask = ExecuteOutTask(stacker.StackerId);
+ if (exeOutTask) return;
+ // 入库
+ bool exeInTask = ExecuteInTask(stacker.StackerId);
+ if (exeInTask) return;
+ // 拣选
+ //bool exePickTask = ExecutePickTask(stacker.StackerId);
+ //if (exePickTask) return;
+ }
+ if (stackerUseStatus == StackerUseStatusEnum.waitTask)
+ {
+ /* 重复入库时执行任务 */
+ bool exeDoubleInTask = ExecuteDoubleInTask(stacker.StackerId, plcId, 1);
+ if (exeDoubleInTask) return;
+ exeDoubleInTask = ExecuteDoubleInTask(stacker.StackerId, spare1, 2);
+ if (exeDoubleInTask) return;
+ }
+ }));
+ }
+ Task.WaitAll([.. tasks]);
+ return true;
+ }
+
+
+ ///
+ /// 执行堆垛机入库任务,若执行了任务则返回 true
+ ///
+ ///
+ ///
+ private bool ExecuteInTask(int? stackerId)
+ {
+ if (stackerId == default) return false;
+ /* 检查入库站台是否允许取货 */
+ bool allowGetGoods = _conveyOperation.AllGetVehicle(stackerId.ToString());
+ if(!allowGetGoods) return false; // 入库站台不允许取货
+ /* 读取入库站台的条码 */
+ var codes = _conveyOperation.ReadConveyCode(stackerId.ToString());
+ if(codes == default || codes.Count != 2) return false;
+ /* 构造任务数据 */
+ bool isWriteTask = false; // 指示是否写入任务
+ for (int i = 0; i < 2; i++)
+ {
+ /* 校验货叉开启 */
+ string forkStatus = CommonData.AppStackers.First(f => f.StackerId == stackerId).ForkStatus ?? "";
+ if (forkStatus.Length <= i || forkStatus[i] != '1') continue; // 获取数据失败或者货叉未开启
+ var code = codes[i];
+ if (string.IsNullOrEmpty(code)) continue; // 检查条码是否为空
+ ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 返回:{code}");
+ if (code == "NoRead") // 检查条码是否为 NoRead
+ {
+ /* 检查卸货站台是否允许卸货 */
+ bool allowSetGoods = _conveyOperation.AllSetVehicle(stackerId.ToString());
+ if (!allowSetGoods) continue; // 出库站台不允许取货
+ /* 生成一个直接卸货出去的任务 */
+ int? plcId = _dataBaseData.GetNewPlcTaskId();
+ if(plcId == default || plcId == 0) continue;
+ StackerPlcTask errTask = StackerPlcTask.DefaultErrTask((int)plcId!, (int)stackerId!, i + 1);
+ string WriteTaskErrText = _stackerOperation.WriteTask(errTask, i + 1);
+ if(string.IsNullOrEmpty(WriteTaskErrText)) // 写入成功
+ {
+ ConsoleLog.Success($"{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务成功,{errTask}");
+ isWriteTask = true;
+ }
+ else
+ {
+ ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务失败,{errTask},异常信息:{WriteTaskErrText},");
+ }
+ continue;
+ }
+ var wcsTasks = _wcsTaskDao.Select(new AppWcsTask { VehicleNo = code, TaskStatus = (int)WcsTaskStatusEnum.create });
+ if(wcsTasks == default) // 查询任务失败
+ {
+ ConsoleLog.Exception($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code} 查找任务失败,和数据库服务器连接中断");
+ continue;
+ }
+ if(wcsTasks.Count < 1) // 没有任务
+ {
+ /* 检查卸货站台是否允许卸货 */
+ bool allowSetGoods = _conveyOperation.AllSetVehicle(stackerId.ToString());
+ if (!allowSetGoods) continue; // 出库站台不允许取货
+ /* 生成一个直接卸货出去的任务 */
+ ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code} 没有找到对应任务");
+ int? plcId = _dataBaseData.GetNewPlcTaskId();
+ if (plcId == default || plcId == 0) continue;
+ StackerPlcTask errTask = StackerPlcTask.DefaultErrTask((int)plcId!, (int)stackerId!, i + 1, code.ToPlcVehicleNo());
+ string WriteTaskErrText = _stackerOperation.WriteTask(errTask, i + 1);
+ if (string.IsNullOrEmpty(WriteTaskErrText)) // 写入成功
+ {
+ ConsoleLog.Success($"{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务成功,{errTask}");
+ isWriteTask = true;
+ }
+ else
+ {
+ ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务失败,{errTask},异常信息:{WriteTaskErrText},");
+ }
+ continue;
+ }
+ var wcsTask = wcsTasks[0]; // 找出第一个任务
+ /* 校验终点是否正确 */
+ var destinationLocationInfo = CommonData.AppLocations.DetailWithWcsLocation(wcsTask.Destination);
+ if(destinationLocationInfo == default) // 任务终点错误,理论上此处不应该出现异常
+ {
+ /* 检查卸货站台是否允许卸货 */
+ bool allowSetGoods = _conveyOperation.AllSetVehicle(stackerId.ToString());
+ if (!allowSetGoods) continue; // 出库站台不允许取货
+ /* 生成一个直接卸货出去的任务 */
+ ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code} 无法识别的入库库位");
+ int? plcId = _dataBaseData.GetNewPlcTaskId();
+ if (plcId == default || plcId == 0) continue;
+ StackerPlcTask errTask = StackerPlcTask.DefaultErrTask((int)plcId!, (int)stackerId!, i + 1, code.ToPlcVehicleNo());
+ string WriteTaskErrText = _stackerOperation.WriteTask(errTask, i + 1);
+ if (string.IsNullOrEmpty(WriteTaskErrText)) // 写入成功
+ {
+ ConsoleLog.Success($"{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务成功,{errTask}");
+ _wcsTaskEvent.ErrTaskEvent(wcsTask, "入库库位不正确");
+ isWriteTask = true;
+ }
+ else
+ {
+ ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务失败,{errTask},异常信息:{WriteTaskErrText},");
+ }
+ continue;
+ }
+ /* 判断冲突货位是否有任务 */
+ var runningWcsTasks = _wcsTaskDao.QueryTaskWithWcsLocation(destinationLocationInfo.InterveneLocation);
+ if (runningWcsTasks == default) continue; // 查询失败
+ if(runningWcsTasks.Count > 0) continue; // 存在冲突点位,等待
+ /* 下发任务 */
+ StackerPlcTask stackerTask = wcsTask.ToStackerInTask((int)stackerId!, i + 1, destinationLocationInfo);
+ string WriteStackerTaskErrText = _stackerOperation.WriteTask(stackerTask, i + 1);
+ if (string.IsNullOrEmpty(WriteStackerTaskErrText)) // 写入成功
+ {
+ ConsoleLog.Success($"{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务成功,{stackerTask}");
+ _wcsTaskEvent.StartTaskEvent(wcsTask); // 任务开始
+ isWriteTask = true;
+ }
+ else
+ {
+ ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务失败,{stackerTask},异常信息:{WriteStackerTaskErrText},");
+ }
+ }
+ if (isWriteTask)
+ {
+ string confirmResult = _stackerOperation.WriteTaskConfirm(stackerId); // 写入任务确认
+ ConsoleLog.Info($"堆垛机入库任务写任务确认;信息:{(string.IsNullOrEmpty(confirmResult) ? "成功" : confirmResult)}");
+ Thread.Sleep(1000);
+ }
+ return isWriteTask;
+ }
+
+ ///
+ /// 执行堆垛机出库任务,若执行了任务则返回 true
+ ///
+ ///
+ ///
+ public bool ExecuteOutTask(int? stackerId)
+ {
+ if (stackerId == default) return false;
+ /* 检查出库站台是否可以卸货 */
+ bool allowSetGoods = _conveyOperation.AllSetVehicle(stackerId.ToString());
+ if (!allowSetGoods) return false; // 出库站台不允许取货
+ var wcsTasks = _wcsTaskDao.SelectOutTaskWithStacker((int)stackerId!);
+ if (wcsTasks == default)
+ {
+ ConsoleLog.Exception(string.Format("【异常】{0} 号堆垛机出库任务查询失败,与数据库连接异常", stackerId));
+ Thread.Sleep(5000);
+ return false;
+ }
+ if (wcsTasks.Count == 0) return false;
+ bool isWriteTask = false; // 指示是否写入任务
+ int writeTaskCount = 0; // 表示执行了多少条任务
+ for (int i = 0; i < wcsTasks.Count; i++)
+ {
+ if (writeTaskCount >= 2) break; // 最多执行两条
+ /* 校验货叉开启 */
+ string forkStatus = CommonData.AppStackers.First(f => f.StackerId == stackerId).ForkStatus ?? "";
+ if (forkStatus.Length <= i || forkStatus[i] != '1')
+ {
+ writeTaskCount ++;
+ continue; // 获取数据失败或者货叉未开启
+ }
+ var wcsTask = wcsTasks[i];
+ /* 校验起点是否正确 */
+ var originLocationInfo = CommonData.AppLocations.DetailWithWcsLocation(wcsTask.Origin);
+ if (originLocationInfo == default) // 任务起点错误,理论上此处不应该出现异常
+ {
+ ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,出库库位:{wcsTask.Origin} 条码:{wcsTask.VehicleNo} 无法识别的出库库位");
+ _wcsTaskEvent.ErrTaskEvent(wcsTask, "出库的库位不正确");
+ continue;
+ }
+ /* 判断冲突货位是否有任务 */
+ var runningWcsTasks = _wcsTaskDao.QueryTaskWithWcsLocation(originLocationInfo.InterveneLocation);
+ if (runningWcsTasks == default) continue; // 查询失败
+ if (runningWcsTasks.Count > 0) continue; // 存在冲突点位,等待
+ /* 下发任务 */
+ StackerPlcTask stackerTask = wcsTask.ToStackerOutTask((int)stackerId!, i + 1, originLocationInfo);
+ string WriteStackerTaskErrText = _stackerOperation.WriteTask(stackerTask, i + 1);
+ if (string.IsNullOrEmpty(WriteStackerTaskErrText)) // 写入成功
+ {
+ ConsoleLog.Success($"{stackerId} 号堆垛机,出库位置:{i + 1} 条码:{wcsTask.VehicleNo},写入任务成功,{stackerTask}");
+ _wcsTaskEvent.StartTaskEvent(wcsTask); // 任务开始
+ writeTaskCount++;
+ isWriteTask = true;
+ }
+ else
+ {
+ ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,出库位置:{i + 1} 条码:{wcsTask.VehicleNo},写入任务失败,{stackerTask},异常信息:{WriteStackerTaskErrText},");
+ }
+ }
+ if (isWriteTask)
+ {
+ string confirmResult = _stackerOperation.WriteTaskConfirm(stackerId); // 写入任务确认
+ ConsoleLog.Info($"堆垛机出库任务写任务确认;信息:{(string.IsNullOrEmpty(confirmResult) ? "成功" : confirmResult)}");
+ Thread.Sleep(1000);
+ }
+ return isWriteTask;
+ }
+
+ ///
+ /// 执行堆垛机拣选任务,若执行了任务则返回 true
+ ///
+ ///
+ ///
+ public bool ExecutePickTask(int? stackerId)
+ {
+ if (stackerId == default) return false;
+ var wcsTasks = _wcsTaskDao.SelectPickOutTaskWithStacker((int)stackerId!);
+ if (wcsTasks == default)
+ {
+ ConsoleLog.Error($"【异常】{stackerId} 号堆垛机拣选任务查询失败,与数据库连接异常");
+ Thread.Sleep(5000);
+ return false;
+ }
+ if (wcsTasks.Count == 0) return false;
+ var wcsTask = wcsTasks[0]; // 取第一条任务
+ /* 校验出库站台是否可以卸货 */
+ // TODO
+ /* 检验并返回起点终点信息 */
+ var originLocationInfo = CommonData.AppLocations.DetailWithWcsLocation(wcsTask.Origin);
+ var destinationLocationInfo = CommonData.AppLocations.DetailWithWcsLocation(wcsTask.Destination);
+ if (destinationLocationInfo == default || originLocationInfo == default) // 起点终点错误,直接标记错误
+ {
+ // 已经在接口内做了检查,按道理此处不会出错。直接返回异常,任务直接取消
+ ConsoleLog.Warning($"【警告】任务号:{wcsTask.TaskId},Plc任务号:{wcsTask.PlcId} 无法执行,起点或者终点存在异常");
+ _wcsTaskEvent.ErrTaskEvent(wcsTask, $"起点或者终点存在异常");
+ return false;
+ }
+ StackerPlcTask stackerTask = new()
+ {
+ StackerId = stackerId,
+ PlcId = wcsTask.PlcId,
+ TaskType = Convert.ToInt16(wcsTask.TaskType),
+ GetStand = 0,
+ InTunnelId = Convert.ToInt16(stackerId),
+ OutTunnelId = Convert.ToInt16(stackerId),
+ SetStand = 0,
+ GetQueue = Convert.ToInt16(originLocationInfo.Queue),
+ GetLine = Convert.ToInt16(originLocationInfo.Line),
+ GetLayer = Convert.ToInt16(originLocationInfo.Layer),
+ GetDeep = Convert.ToInt16(originLocationInfo.Depth),
+ SetQueue = Convert.ToInt16(destinationLocationInfo.Queue),
+ SetLine = Convert.ToInt16(destinationLocationInfo.Line),
+ SetLayer = Convert.ToInt16(destinationLocationInfo.Layer),
+ SetDeep = Convert.ToInt16(destinationLocationInfo.Depth),
+ Size = Convert.ToInt16(wcsTask.VehicleSize),
+ Weight = Convert.ToInt16(wcsTask.Weight),
+ Code = wcsTask.PlcVehicleNo ?? 0,
+ };
+ var writeStackerTaskErrText = _stackerOperation.WriteTask(stackerTask);
+ if (string.IsNullOrEmpty(writeStackerTaskErrText))
+ {
+ ConsoleLog.Success($"堆垛机:{stackerId} 写入拣选任务成功,箱号:{wcsTask.VehicleNo},PlcId:{wcsTask.PlcId};{wcsTask.Origin} => {wcsTask.Destination}");
+ _wcsTaskEvent.StartTaskEvent(wcsTask);
+ return true;
+ }
+ else
+ {
+ ConsoleLog.Warning($"【警告】堆垛机:{stackerId} 写入拣选任务失败,箱号:{wcsTask.VehicleNo},PlcId:{wcsTask.PlcId};{wcsTask.Origin} => {wcsTask.Destination},异常信息:{writeStackerTaskErrText}");
+ _wcsTaskEvent.ErrTaskEvent(wcsTask, $"写入任务失败,异常信息:{writeStackerTaskErrText}");
+ }
+ return false;
+
+ }
+
+ ///
+ /// 执行堆垛机移库任务,若执行了任务则返回 true
+ ///
+ ///
+ ///
+ public bool ExecuteMoveTask(int? stackerId)
+ {
+ if (stackerId == default) return false;
+ var wcsTasks = _wcsTaskDao.SelectMoveTaskWithStacker((int)stackerId!);
+ if (wcsTasks == default)
+ {
+ ConsoleLog.Error($"【异常】{stackerId} 号堆垛机移库任务查询失败,与数据库连接异常");
+ Thread.Sleep(5000);
+ return false;
+ }
+ if (wcsTasks.Count == 0) return false;
+ bool isWriteTask = false; // 指示是否写入任务
+ int writeTaskCount = 0; // 表示执行了多少条任务
+ for (int i = 0; i < wcsTasks.Count; i++)
+ {
+ if (writeTaskCount >= 2) break; // 最多执行两条
+ /* 校验货叉开启 */
+ string forkStatus = CommonData.AppStackers.First(f => f.StackerId == stackerId).ForkStatus ?? "";
+ if (forkStatus.Length <= i || forkStatus[i] != '1')
+ {
+ writeTaskCount++;
+ continue; // 获取数据失败或者货叉未开启
+ }
+ var wcsTask = wcsTasks[i];
+ /* 校验起点是否正确 */
+ var originLocationInfo = CommonData.AppLocations.DetailWithWcsLocation(wcsTask.Origin);
+ var destinationLocationInfo = CommonData.AppLocations.DetailWithWcsLocation(wcsTask.Origin);
+ if (originLocationInfo == default || destinationLocationInfo == default) // 任务起点终点错误,理论上此处不应该出现异常
+ {
+ ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,移库库位:{wcsTask.Origin} 条码:{wcsTask.VehicleNo} 无法识别的库位");
+ _wcsTaskEvent.ErrTaskEvent(wcsTask, "移库的库位不正确");
+ continue;
+ }
+ /* 判断冲突货位是否有任务,起点终点都要判断 */
+ var runningWcsTasks = _wcsTaskDao.QueryTaskWithWcsLocation(destinationLocationInfo.InterveneLocation, originLocationInfo.InterveneLocation);
+ if (runningWcsTasks == default) continue; // 查询失败
+ if (runningWcsTasks.Count > 0) continue; // 存在冲突点位,等待
+ /* 下发任务 */
+ StackerPlcTask stackerTask = wcsTask.ToStackerMoveTask((int)stackerId!, originLocationInfo, destinationLocationInfo);
+ string WriteStackerTaskErrText = _stackerOperation.WriteTask(stackerTask, i + 1);
+ if (string.IsNullOrEmpty(WriteStackerTaskErrText)) // 写入成功
+ {
+ ConsoleLog.Success($"{stackerId} 号堆垛机,移库位置:{i + 1} 条码:{wcsTask.VehicleNo},写入任务成功,{stackerTask}");
+ _wcsTaskEvent.StartTaskEvent(wcsTask); // 任务开始
+ writeTaskCount++;
+ isWriteTask = true;
+ }
+ else
+ {
+ ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,移库位置:{i + 1} 条码:{wcsTask.VehicleNo},写入任务失败,{stackerTask},异常信息:{WriteStackerTaskErrText},");
+ }
+ }
+ if (isWriteTask)
+ {
+ string confirmResult = _stackerOperation.WriteTaskConfirm(stackerId); // 写入任务确认
+ ConsoleLog.Info($"堆垛机移库任务写任务确认;信息:{(string.IsNullOrEmpty(confirmResult) ? "成功" : confirmResult)}");
+ Thread.Sleep(1000);
+ }
+ return isWriteTask;
+
+ }
+
+ ///
+ /// 执行重复入库新任务,若执行了返回true
+ ///
+ ///
+ ///
+ /// 货叉编号
+ ///
+ public bool ExecuteDoubleInTask(int? stackerId, int plcId, int forkId)
+ {
+ if (stackerId == default || plcId == 0) return false;
+ /* 查找这个PlcId对应的wms任务 */
+ List? doubleInTasks = _wcsTaskDao.Select(new AppWcsTask { PlcId = plcId });
+ if (doubleInTasks == default)
+ {
+ ConsoleLog.Error($"【异常】{stackerId} 号堆垛机重复入库任务检验失败,与数据库连接异常");
+ Thread.Sleep(5000);
+ return false;
+ }
+ if (doubleInTasks.Count == 0) return false; // 找不到对应的PlcId的任务
+ var doubleTask = doubleInTasks[0];
+ /* 判断这个任务是否出现卸货位置有货 */
+ if(doubleTask.TaskStatus != (int)WcsTaskStatusEnum.doubleIn) { return false; } // 没有重复入库不执行下面方法
+ /* 查找这个任务的新任务 */
+ List? newTasks = _wcsTaskDao.Select(new AppWcsTask { TaskId = doubleTask.TaskId, TaskType = (int)WcsTaskTypeEnum.newTaskForDoubleIn, TaskStatus = (int)WmsTaskStatusEnum.create });
+ if (newTasks == default)
+ {
+ ConsoleLog.Error($"【异常】{stackerId} 号堆垛机重复入库任务新任务查询失败,与数据库连接异常");
+ Thread.Sleep(5000);
+ return false;
+ }
+ if (newTasks.Count == 0) return false;
+ var newTask = newTasks[0];
+ var destinationLocationInfo = CommonData.AppLocations.DetailWithWcsLocation(newTask.Destination);
+ if (destinationLocationInfo == default) // 终点错误,直接标记错误
+ {
+ // 已经在接口内做了检查,按道理此处不会出错。直接返回异常,任务直接取消
+ ConsoleLog.Warning($"【警告】任务号:{newTask.TaskId},Plc任务号:{newTask.PlcId} 无法执行,新终点存在异常");
+ _wcsTaskEvent.ErrTaskEvent(newTask, $"新终点存在异常");
+ return false;
+ }
+ /* 判断冲突货位是否有任务 */
+ var runningWcsTasks = _wcsTaskDao.QueryTaskWithWcsLocation(destinationLocationInfo.InterveneLocation);
+ if (runningWcsTasks == default) return false; // 查询失败
+ if (runningWcsTasks.Count > 0) return false; // 存在冲突点位,等待
+ /* 下发任务 */
+ StackerPlcTask stackerTask = newTask.ToStackerInTask((int)stackerId!, forkId, destinationLocationInfo);
+ var writeStackerTaskErrText = _stackerOperation.WriteTask(stackerTask);
+ if (string.IsNullOrEmpty(writeStackerTaskErrText))
+ {
+ ConsoleLog.Success($"堆垛机:{stackerId} 写入重复入库新任务成功,箱号:{newTask.VehicleNo},PlcId:{newTask.PlcId};新目的地:{newTask.Destination}");
+ _wcsTaskEvent.StartTaskEvent(newTask);
+ return true;
+ }
+ else
+ {
+ ConsoleLog.Warning($"【警告】堆垛机:{stackerId} 写入重复入库新任务失败,箱号:{newTask.VehicleNo},PlcId:{newTask.PlcId};新目的地:{newTask.Destination},异常信息:{writeStackerTaskErrText}");
+ _wcsTaskEvent.ErrTaskEvent(newTask, $"写入任务失败,异常信息:{writeStackerTaskErrText}");
+ }
+ return false;
+ }
+
+
+
+
+
+}
diff --git a/WcsMain/Business/CirculationTask/Stacker/ExecuteWcsTask.cs b/WcsMain/Business/CirculationTask/Stacker/ExecuteWcsTask.cs
index 3883954..16398f9 100644
--- a/WcsMain/Business/CirculationTask/Stacker/ExecuteWcsTask.cs
+++ b/WcsMain/Business/CirculationTask/Stacker/ExecuteWcsTask.cs
@@ -14,7 +14,7 @@ namespace WcsMain.Business.CirculationTask.Stacker;
///
/// 执行堆垛机任务类
///
-[Circulation(tags: ["stacker"])]
+//[Circulation(tags: ["stacker"])]
public class ExecuteWcsTask(StackerOperation stackerOperation, AppWcsTaskDao wcsTaskDao, WCSTaskExecuteEvent wcsTaskEvent)
{
private readonly WCSTaskExecuteEvent _wcsTaskEvent = wcsTaskEvent;
@@ -30,7 +30,7 @@ public class ExecuteWcsTask(StackerOperation stackerOperation, AppWcsTaskDao wcs
{
foreach (var stacker in CommonData.AppStackers.Open())
{
- var stackerUseStatus = _stackerOperation.StackerCanUse(stacker.StackerId, out int plcId);
+ var stackerUseStatus = _stackerOperation.StackerCanUse(stacker.StackerId, out int plcId, out int _);
if (stackerUseStatus == StackerUseStatusEnum.Free)
{
/* 空闲时正常执行任务 */
diff --git a/WcsMain/DataBase/Dao/AppLocationDao.cs b/WcsMain/DataBase/Dao/AppLocationDao.cs
index 6c115f5..dacba30 100644
--- a/WcsMain/DataBase/Dao/AppLocationDao.cs
+++ b/WcsMain/DataBase/Dao/AppLocationDao.cs
@@ -98,6 +98,8 @@ public class AppLocationDao
.WhereIF(appLocation.Line != null, w => w.Line == appLocation.Line)
.WhereIF(appLocation.Layer != null, w => w.Layer == appLocation.Layer)
.WhereIF(appLocation.Depth != null, w => w.Depth == appLocation.Depth)
+ .WhereIF(appLocation.InterveneLocation != default, w => w.InterveneLocation == appLocation.InterveneLocation)
+ .WhereIF(appLocation.VehicleType == default, w => w.VehicleType == appLocation.VehicleType)
.WhereIF(!string.IsNullOrEmpty(appLocation.VehicleNo), w => w.VehicleNo == appLocation.VehicleNo)
.OrderBy(o => new { o.Queue, o.Line, o.Layer, o.Depth })
.ToList();
@@ -133,19 +135,18 @@ public class AppLocationDao
|| w.WmsLocation!.Contains(request.SearchStr!)
|| w.VehicleNo!.Contains(request.SearchStr!)
|| w.Remark!.Contains(request.SearchStr!));
- if (request.LocationStatus != default) // 查询任务类型
+ if (request.LocationStatus != default) // 查询点位状态
{
List locationStatus = [];
- foreach (var ls in request.LocationStatus)
- {
- if (ls == "空闲") { locationStatus.Add((int)LocationStatusEnum.empty); }
- if (ls == "锁定") { locationStatus.Add((int)LocationStatusEnum.locked); }
- if (ls == "占用") { locationStatus.Add((int)LocationStatusEnum.used); }
- if (ls == "禁用") { locationStatus.Add((int)LocationStatusEnum.forbidden); }
- if (ls == "特殊点位") { locationStatus.Add((int)LocationStatusEnum.special); }
- }
+ request.LocationStatus.ForEach(item => locationStatus.Add(item));
sqlFuc.Where(w => locationStatus.Contains(w.LocationStatus));
}
+ if (request.LocationType != default) // 查询点位类型
+ {
+ List locationTypes = [];
+ request.LocationType.ForEach(item => locationTypes.Add(item));
+ sqlFuc.Where(w => locationTypes.Contains(w.LocationType));
+ }
sqlFuc.OrderBy(o => new { o.EquipmentId, o.Queue, o.Line, o.Layer, o.Depth });
var queryResult = sqlFuc.ToPageList(request.Page!.PageIndex, request.Page!.PageSize, ref totalRows);
return (queryResult, totalRows);
diff --git a/WcsMain/DataBase/Dao/AppWcsTaskDao.cs b/WcsMain/DataBase/Dao/AppWcsTaskDao.cs
index c37f0e4..9495f13 100644
--- a/WcsMain/DataBase/Dao/AppWcsTaskDao.cs
+++ b/WcsMain/DataBase/Dao/AppWcsTaskDao.cs
@@ -378,7 +378,7 @@ public class AppWcsTaskDao
{
sql.AppendLine($"and vehicle_no = '{vehicleNo}' ");
}
- sql.AppendLine("order by priority desc, create_time asc ");
+ sql.AppendLine("order by priority desc, wms_time asc ");
var sqlFuc = CommonTool.DbServe.Ado.SqlQuery(sql.ToString());
return sqlFuc;
}
@@ -448,4 +448,35 @@ public class AppWcsTaskDao
return default;
}
}
+
+
+ ///
+ /// 根据起点或者终点查找当前正在运行的任务
+ ///
+ ///
+ ///
+ public List? QueryTaskWithWcsLocation(params string?[] destinations)
+ {
+ List? result = [];
+ if (destinations.Length < 1) return result;
+ try
+ {
+ foreach (var destination in destinations)
+ {
+ var sqlFuc = CommonTool.DbServe.Queryable()
+ .Where(x => x.Destination == destination || x.Origin == destination)
+ .Where(x => DataService.EnumData.GetWcsTaskStatusEnumRunningStatus().Contains((int)WcsTaskStatusEnum.running));
+ result.AddRange(sqlFuc.ToList());
+ }
+ return result;
+ }
+ catch (Exception ex)
+ {
+ _ = ex;
+ return default;
+ }
+
+
+
+ }
}
\ No newline at end of file
diff --git a/WcsMain/DataBase/TableEntity/AppLocation.cs b/WcsMain/DataBase/TableEntity/AppLocation.cs
index fd1c75b..4ed94ac 100644
--- a/WcsMain/DataBase/TableEntity/AppLocation.cs
+++ b/WcsMain/DataBase/TableEntity/AppLocation.cs
@@ -46,6 +46,13 @@ public class AppLocation
[JsonPropertyName("locationStatus")]
public int? LocationStatus { get; set; }
+ ///
+ /// 点位类型
+ ///
+ [SugarColumn(ColumnName = "location_type")]
+ [JsonPropertyName("locationType")]
+ public int? LocationType { get; set; }
+
///
/// 排
///
@@ -75,11 +82,18 @@ public class AppLocation
public int? Depth { get; set; }
///
- /// 点位类型
+ /// 干涉的点位
///
- [SugarColumn(ColumnName = "location_type")]
- [JsonPropertyName("locationType")]
- public int? LocationType { get; set; }
+ [SugarColumn(ColumnName = "intervene_location")]
+ [JsonPropertyName("interveneLocation")]
+ public string? InterveneLocation { get; set; }
+
+ ///
+ /// 兼容的载具类型
+ ///
+ [SugarColumn(ColumnName = "vehicle_type")]
+ [JsonPropertyName("vehicleType")]
+ public string? VehicleType { get; set; }
///
/// 载具编号
diff --git a/WcsMain/DataBase/TableEntity/AppStacker.cs b/WcsMain/DataBase/TableEntity/AppStacker.cs
index 4527e96..4ce2ae8 100644
--- a/WcsMain/DataBase/TableEntity/AppStacker.cs
+++ b/WcsMain/DataBase/TableEntity/AppStacker.cs
@@ -34,6 +34,13 @@ public class AppStacker
[JsonPropertyName("stackerStatus")]
public int? StackerStatus { get; set; }
+ ///
+ /// 货叉状态
+ ///
+ [SugarColumn(ColumnName = "fork_status")]
+ [JsonPropertyName("forkStatus")]
+ public string? ForkStatus { get; set; }
+
///
/// 控制该堆垛机的PLC
///
diff --git a/WcsMain/DataService/EnumData.cs b/WcsMain/DataService/EnumData.cs
new file mode 100644
index 0000000..e25f580
--- /dev/null
+++ b/WcsMain/DataService/EnumData.cs
@@ -0,0 +1,20 @@
+using WcsMain.Enum.TaskEnum;
+
+namespace WcsMain.DataService;
+
+///
+/// 枚举的数据操作
+///
+public static class EnumData
+{
+ ///
+ /// 返回可以视作正在运行的任务的Wcs任务状态的枚举
+ ///
+ ///
+ public static int[] GetWcsTaskStatusEnumRunningStatus()
+ {
+ return [(int)WcsTaskStatusEnum.leaveOrigin, (int)WcsTaskStatusEnum.running];
+ }
+
+
+}
diff --git a/WcsMain/Enum/TaskEnum/WcsTaskStatusEnum.cs b/WcsMain/Enum/TaskEnum/WcsTaskStatusEnum.cs
index f5d8a0e..3349768 100644
--- a/WcsMain/Enum/TaskEnum/WcsTaskStatusEnum.cs
+++ b/WcsMain/Enum/TaskEnum/WcsTaskStatusEnum.cs
@@ -10,5 +10,7 @@ public enum WcsTaskStatusEnum
running = 2,
arriveDestination = 3,
complete = 4,
+ doubleIn = 7,
+ emptyOut = 8,
err = 9,
}
\ No newline at end of file
diff --git a/WcsMain/Enum/TaskEnum/WcsTaskTypeEnum.cs b/WcsMain/Enum/TaskEnum/WcsTaskTypeEnum.cs
index 9dad01e..efcb48d 100644
--- a/WcsMain/Enum/TaskEnum/WcsTaskTypeEnum.cs
+++ b/WcsMain/Enum/TaskEnum/WcsTaskTypeEnum.cs
@@ -7,4 +7,7 @@ public enum WcsTaskTypeEnum
pick = 4, // 拣选任务
check = 10, // 盘点任务
moveTask = 9, // 移库任务
+
+
+ newTaskForDoubleIn = 21, // 卸货位置有货的新任务
}
diff --git a/WcsMain/ExtendMethod/AppWcsTaskExtendMethod.cs b/WcsMain/ExtendMethod/AppWcsTaskExtendMethod.cs
index 267699b..d8cf231 100644
--- a/WcsMain/ExtendMethod/AppWcsTaskExtendMethod.cs
+++ b/WcsMain/ExtendMethod/AppWcsTaskExtendMethod.cs
@@ -1,4 +1,6 @@
using WcsMain.DataBase.TableEntity;
+using WcsMain.Enum.TaskEnum;
+using WcsMain.PlcOperation.Entity.Stacker;
namespace WcsMain.ExtendMethod;
@@ -34,4 +36,110 @@ public static class AppWcsTaskExtendMethod
if (wcsTask == default) return false;
return wcsTask.NextPlcId == default;
}
+
+ ///
+ /// 生成一个入库任务
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static StackerPlcTask ToStackerInTask(this AppWcsTask wcsTask, int stackerId, int forkId, AppLocation destinationDetail)
+ {
+ StackerPlcTask stackerTask = new()
+ {
+ StackerId = stackerId,
+ PlcId = wcsTask.PlcId,
+ TaskType = (int)WcsTaskTypeEnum.inTask,
+ GetStand = 0,
+ InTunnelId = Convert.ToInt16(stackerId),
+ OutTunnelId = Convert.ToInt16(stackerId),
+ SetStand = 0,
+ GetQueue = 2,
+ GetLine = Convert.ToInt16(forkId),
+ GetLayer = 1,
+ GetDeep = 1,
+ SetQueue = Convert.ToInt16(destinationDetail.Queue),
+ SetLine = Convert.ToInt16(destinationDetail.Line),
+ SetLayer = Convert.ToInt16(destinationDetail.Layer),
+ SetDeep = Convert.ToInt16(destinationDetail.Depth),
+ Size = Convert.ToInt16(wcsTask.VehicleSize),
+ Weight = Convert.ToInt16(wcsTask.Weight),
+ Code = wcsTask.PlcVehicleNo ?? 0,
+ };
+ return stackerTask;
+ }
+
+
+ ///
+ /// 生成一个入库任务
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static StackerPlcTask ToStackerOutTask(this AppWcsTask wcsTask, int stackerId, int forkId, AppLocation originDetail)
+ {
+ StackerPlcTask stackerTask = new()
+ {
+ StackerId = stackerId,
+ PlcId = wcsTask.PlcId,
+ TaskType = (int)WcsTaskTypeEnum.outTask,
+ GetStand = 0,
+ InTunnelId = Convert.ToInt16(stackerId),
+ OutTunnelId = Convert.ToInt16(stackerId),
+ SetStand = 0,
+ GetQueue = Convert.ToInt16(originDetail.Queue),
+ GetLine = Convert.ToInt16(originDetail.Queue),
+ GetLayer = Convert.ToInt16(originDetail.Queue),
+ GetDeep = Convert.ToInt16(originDetail.Queue),
+ SetQueue = 2,
+ SetLine = Convert.ToInt16(forkId),
+ SetLayer = 2,
+ SetDeep = 1,
+ Size = Convert.ToInt16(wcsTask.VehicleSize),
+ Weight = Convert.ToInt16(wcsTask.Weight),
+ Code = wcsTask.PlcVehicleNo ?? 0,
+ };
+ return stackerTask;
+ }
+
+ ///
+ /// 生成一个移库任务
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static StackerPlcTask ToStackerMoveTask(this AppWcsTask wcsTask, int stackerId, AppLocation originDetail, AppLocation destinationDetail)
+ {
+ StackerPlcTask stackerTask = new()
+ {
+ StackerId = stackerId,
+ PlcId = wcsTask.PlcId,
+ TaskType = (int)WcsTaskTypeEnum.moveTask,
+ GetStand = 0,
+ InTunnelId = Convert.ToInt16(stackerId),
+ OutTunnelId = Convert.ToInt16(stackerId),
+ SetStand = 0,
+ GetQueue = Convert.ToInt16(originDetail.Queue),
+ GetLine = Convert.ToInt16(originDetail.Queue),
+ GetLayer = Convert.ToInt16(originDetail.Queue),
+ GetDeep = Convert.ToInt16(originDetail.Queue),
+ SetQueue = Convert.ToInt16(destinationDetail.Queue),
+ SetLine = Convert.ToInt16(destinationDetail.Line),
+ SetLayer = Convert.ToInt16(destinationDetail.Layer),
+ SetDeep = Convert.ToInt16(destinationDetail.Depth),
+ Size = Convert.ToInt16(wcsTask.VehicleSize),
+ Weight = Convert.ToInt16(wcsTask.Weight),
+ Code = wcsTask.PlcVehicleNo ?? 0,
+ };
+ return stackerTask;
+ }
+
+
+
}
diff --git a/WcsMain/Language/Readme.txt b/WcsMain/Language/Readme.txt
new file mode 100644
index 0000000..74d9903
--- /dev/null
+++ b/WcsMain/Language/Readme.txt
@@ -0,0 +1 @@
+多语言版本尚未添加
\ No newline at end of file
diff --git a/WcsMain/PlcOperation/ConveyOperation.cs b/WcsMain/PlcOperation/ConveyOperation.cs
index f536aa2..4f40281 100644
--- a/WcsMain/PlcOperation/ConveyOperation.cs
+++ b/WcsMain/PlcOperation/ConveyOperation.cs
@@ -2,21 +2,71 @@
using System.Text.RegularExpressions;
using WcsMain.Common;
using WcsMain.PlcOperation.Entity;
+using WcsMain.WcsAttribute.AutoFacAttribute;
namespace WcsMain.PlcOperation;
///
/// 输送机操作 ---- 箱式线,不包含于立库库前设备,库前请参考堆垛机操作
///
+[Component]
public class ConveyOperation
{
- private static ConveyOperation? _instance;
-
- public static ConveyOperation Instance()
+ ///
+ /// 写入输送机心跳
+ ///
+ ///
+ public string WriteHeartBeat()
{
- return _instance ??= new ConveyOperation();
+ if (!CommonData.IsConnectPlc || CommonTool.Siemens == default) return "PLC尚未连接。";
+ var (writeResult, _) = CommonTool.Siemens.WritePlcWhithName($"箱式线写心跳", (short)0);
+ return writeResult.Success ? string.Empty : writeResult.Message ?? "写入失败,未知原因";
}
+ ///
+ /// 箱式线允许取货
+ ///
+ /// 要取货的点位
+ ///
+ public bool AllGetVehicle(string? point)
+ {
+ if (!CommonData.IsConnectPlc || CommonTool.Siemens == default) return false;
+ var readResult = CommonTool.Siemens.ReadInt16WithName($"箱式线允许取货{point}");
+ return readResult.Success && readResult.Value == 1;
+ }
+
+ ///
+ /// 箱式线允许卸货
+ ///
+ /// 要取货的点位
+ ///
+ public bool AllSetVehicle(string? point)
+ {
+ if (!CommonData.IsConnectPlc || CommonTool.Siemens == default) return false;
+ var readResult = CommonTool.Siemens.ReadInt16WithName($"箱式线允许卸货{point}");
+ return readResult.Success && readResult.Value == 1;
+ }
+
+ ///
+ /// 读取箱式线入库站台反馈的载具号
+ ///
+ ///
+ ///
+ public List? ReadConveyCode(string? point)
+ {
+ if (!CommonData.IsConnectPlc || CommonTool.Siemens == default) return default;
+ var readResult1 = CommonTool.Siemens.ReadStringWithName($"箱式线入库载具号{point}-1", 20, Encoding.ASCII);
+ var readResult2 = CommonTool.Siemens.ReadStringWithName($"箱式线入库载具号{point}-2", 20, Encoding.ASCII);
+ if (!readResult1.Success! || !readResult2.Success!) return default;
+ // 返回读取到的任务号
+ return [Regex.Replace(readResult1.Value ?? "", "\\W", ""), Regex.Replace(readResult2.Value ?? "", "\\W", "")];
+ }
+
+
+
+
+
+
///
/// 写入箱式线任务
///
@@ -40,25 +90,9 @@ public class ConveyOperation
return writeResult.Message ?? "写入失败,未知原因";
}
- ///
- /// 写入输送机心跳
- ///
- ///
- public string WriteHeartBeat()
- {
- if (!CommonData.IsConnectPlc || CommonTool.Siemens == default)
- {
- // 未连接PLC
- return "PLC尚未连接。";
- }
- var (writeResult, _) = CommonTool.Siemens.WritePlcWhithName($"箱式线写心跳", (short)0);
- if (writeResult.Success)
- {
- return string.Empty;
- }
- return writeResult.Message ?? "写入失败,未知原因";
- }
+
+
///
/// 获取箱式线出库站台状态
///
diff --git a/WcsMain/PlcOperation/Entity/Stacker/StackerPlcTask.cs b/WcsMain/PlcOperation/Entity/Stacker/StackerPlcTask.cs
index 12cd2ca..ea05c98 100644
--- a/WcsMain/PlcOperation/Entity/Stacker/StackerPlcTask.cs
+++ b/WcsMain/PlcOperation/Entity/Stacker/StackerPlcTask.cs
@@ -1,4 +1,5 @@
-using WcsMain.Enum.TaskEnum;
+using System.Collections;
+using WcsMain.Enum.TaskEnum;
namespace WcsMain.PlcOperation.Entity.Stacker;
@@ -100,36 +101,45 @@ public class StackerPlcTask
///
public int Code { get; set; }
+
+ public override string ToString()
+ {
+ return $"PlcId:{PlcId},{GetQueue}排{GetLine}列{GetLayer}层{GetDeep}深 --> {SetQueue}排{SetLine}列{SetLayer}层{SetDeep}深";
+ }
+
+
///
/// 默认的直接从入口搬出去的任务
///
///
///
+ ///
///
///
- public static StackerPlcTask DefaultOutTask(int plcId, int stackerId, int vehicleNo = 999999999)
+ public static StackerPlcTask DefaultErrTask(int plcId, int stackerId, int forkId, int vehicleNo = 999999999)
{
- StackerPlcTask noTaskStackerTask = new()
+ StackerPlcTask stackerTask = new()
{
+ StackerId = stackerId,
PlcId = plcId,
- TaskType = Convert.ToInt16(TaskTypeEnum.inTask),
+ TaskType = Convert.ToInt16(WcsTaskTypeEnum.moveTask),
GetStand = 0,
InTunnelId = Convert.ToInt16(stackerId),
OutTunnelId = Convert.ToInt16(stackerId),
SetStand = 0,
- GetQueue = 1,
- GetLine = 46,
+ GetQueue = 2,
+ GetLine = Convert.ToInt16(forkId),
GetLayer = 1,
GetDeep = 1,
SetQueue = 2,
- SetLine = 46,
- SetLayer = 1,
+ SetLine = Convert.ToInt16(forkId),
+ SetLayer = 2,
SetDeep = 1,
Size = 0,
Weight = 0,
- Code = vehicleNo
+ Code = vehicleNo,
};
- return noTaskStackerTask;
+ return stackerTask;
}
}
\ No newline at end of file
diff --git a/WcsMain/PlcOperation/Stacker/StackerOperation.cs b/WcsMain/PlcOperation/Stacker/StackerOperation.cs
index 0cdef34..98aadb0 100644
--- a/WcsMain/PlcOperation/Stacker/StackerOperation.cs
+++ b/WcsMain/PlcOperation/Stacker/StackerOperation.cs
@@ -21,11 +21,13 @@ public class StackerOperation
/// 判断堆垛机状态,若是等待(二次申请)状态则带出当前的PlcId
///
///
- ///
+ ///
+ ///
///
- public StackerUseStatusEnum StackerCanUse(int? stackerId, out int plcId)
+ public StackerUseStatusEnum StackerCanUse(int? stackerId, out int plcId1, out int spare1)
{
- plcId = 0;
+ plcId1 = 0;
+ spare1 = 0;
if (stackerId == default) return StackerUseStatusEnum.BusyOrErr;
/* 获取堆垛机状态 */
var (errMsg, stackerInfo) = GetStackerInfo((int)stackerId!);
@@ -39,7 +41,8 @@ public class StackerOperation
&& stackerInfo.ErrCode == 0;
if(waitTask)
{
- plcId = stackerInfo.PlcId;
+ plcId1 = stackerInfo.PlcId;
+ spare1 = stackerInfo.Spare1;
return StackerUseStatusEnum.waitTask;
}
return StackerUseStatusEnum.BusyOrErr;
@@ -72,7 +75,7 @@ public class StackerOperation
{
return ("设备尚未连接", default); // 未连接PLC
}
- var readResult = CommonTool.Siemens.ReadByteWithName($"堆垛机状态反馈{stackerId}", 24);
+ var readResult = CommonTool.Siemens.ReadByteWithName($"堆垛机状态反馈{stackerId}", 50);
if (!readResult.Success || readResult.Value == default)
{
return (readResult.Message, default); // 读取失败
@@ -95,7 +98,7 @@ public class StackerOperation
// ForkCount = Convert.ToInt32(CommonTool.Siemens.Trans(data, 32)), // 货叉动作次数
// SubmitPlcId = Convert.ToInt32(CommonTool.Siemens.Trans(data, 36)), // 提交的任务
// DeletePlcId = Convert.ToInt32(CommonTool.Siemens.Trans(data, 40)), // 删除的任务
- // Spare1 = Convert.ToInt32(CommonTool.Siemens.Trans(data, 44)), // 备用1
+ Spare1 = Convert.ToInt32(CommonTool.Siemens.Trans(data, 44)), // 备用1
// Spare2 = Convert.ToInt16(CommonTool.Siemens.Trans(data, 48)), // 备用2
};
return (string.Empty, stackerInfo);
@@ -182,31 +185,26 @@ public class StackerOperation
///
///
///
- public string WriteTaskConfirm(int stackerId)
+ public string WriteTaskConfirm(int? stackerId)
{
- if (!CommonData.IsConnectPlc || CommonTool.Siemens == default)
- {
- // 未连接PLC
- return "PLC尚未连接。";
- }
+ if (!CommonData.IsConnectPlc || CommonTool.Siemens == default) return "PLC尚未连接。";
var (writeResult, _) = CommonTool.Siemens.WritePlcWhithName($"堆垛机写任务确认{stackerId}", (short)1);
- if (writeResult.Success)
- {
- return string.Empty;
- }
- return writeResult.Message ?? "写入失败";
+ return writeResult.Success ? string.Empty : writeResult.Message ?? "写入失败";
}
///
/// 写入堆垛机任务,返回错误信息
///
- ///
+ /// 任务数据
+ /// 货叉编号
///
- public string WriteTask(StackerPlcTask task)
+ public string WriteTask(StackerPlcTask task, int forkId = 0)
{
if (!CommonData.IsConnectPlc || CommonTool.Siemens == default) return "PLC尚未连接。"; // 未连接PLC
- var (writeResult, _) = CommonTool.Siemens.WritePlcWhithName($"堆垛机写任务{task.StackerId}",
+ var dbAddressName = $"堆垛机写任务{task.StackerId}";
+ if(forkId != 0) { dbAddressName += $"-{forkId}"; }
+ var (writeResult, _) = CommonTool.Siemens.WritePlcWhithName(dbAddressName,
task.PlcId!,
task.TaskType!,
task.GetStand!,
@@ -225,7 +223,7 @@ public class StackerOperation
task.Weight!,
task.Code
);
- return writeResult.Success ? string.Empty : writeResult.Message ?? "写入失败";
+ return writeResult.Success ? string.Empty : writeResult.Message ?? "写入失败,未知原因";
}
diff --git a/WcsMain/StartAction/HostService.cs b/WcsMain/StartAction/HostService.cs
index 87b174d..e4b5e09 100644
--- a/WcsMain/StartAction/HostService.cs
+++ b/WcsMain/StartAction/HostService.cs
@@ -23,6 +23,7 @@ public class HostService(ServiceStart serverStart) : IHostedLifecycleService
{
return Task.Run(() =>
{
+ _serverStart.LoadingData(); // 加载必要参数
string? loadingResult = LoadingRunningData.GetResult();
if (!string.IsNullOrEmpty(loadingResult))
{
diff --git a/WcsMain/StartAction/ServiceStart.cs b/WcsMain/StartAction/ServiceStart.cs
index d1928a9..669a394 100644
--- a/WcsMain/StartAction/ServiceStart.cs
+++ b/WcsMain/StartAction/ServiceStart.cs
@@ -28,6 +28,23 @@ public class ServiceStart(WcsCirculation wcsCirculation, ConnectPLCs connectPLCs
private readonly ConnectPlcServe _connectPlcServe = connectPlcServe;
private static string _errMsg = string.Empty;
+
+ ///
+ /// 加载必要参数
+ ///
+ public void LoadingData()
+ {
+ LoadingConfig(); // 加载数据库中的配置项 (config 表)
+ LoadingStackerData(); // 加载数据库中的堆垛机信息
+ LoadingLocationData(); // 加载数据库中的库位信息
+
+ if (!string.IsNullOrEmpty(_errMsg))
+ {
+ ConsoleLog.Error($"【异常】启动加载运行文件出错,WCS功能受到限制,您可以检查网络连接后重新启动或者联系我们,参考信息:{_errMsg}");
+ return;
+ }
+ }
+
///
/// 启动 ——-- 主方法
///
@@ -35,15 +52,7 @@ public class ServiceStart(WcsCirculation wcsCirculation, ConnectPLCs connectPLCs
{
/* 指定线程池规格 */
ThreadPool.SetMinThreads(30, 10);
- LoadingConfig(); // 加载数据库中的配置项 (config 表)
- LoadingStackerData(); // 加载数据库中的堆垛机信息
- LoadingLocationData(); // 加载数据库中的库位信息
-
- if(!string.IsNullOrEmpty(_errMsg))
- {
- ConsoleLog.Error($"【异常】启动加载运行文件出错,WCS功能受到限制,您可以检查网络连接后重新启动或者联系我们,参考信息:{_errMsg}");
- return;
- }
+
CreatePlcClient(); // 连接 PLC 客户端
CreateSocketClient(); // Socket客户端
diff --git a/WcsMain/WcsMain.csproj b/WcsMain/WcsMain.csproj
index b6c2598..9c233f6 100644
--- a/WcsMain/WcsMain.csproj
+++ b/WcsMain/WcsMain.csproj
@@ -45,7 +45,9 @@
-
+
+
+
diff --git a/WcsMain/WcsMain.csproj.user b/WcsMain/WcsMain.csproj.user
new file mode 100644
index 0000000..0ab25a4
--- /dev/null
+++ b/WcsMain/WcsMain.csproj.user
@@ -0,0 +1,6 @@
+
+
+
+ FolderProfile
+
+
\ No newline at end of file
diff --git a/WcsMain/appsettings.json b/WcsMain/appsettings.json
index 9fb58e0..33113d0 100644
--- a/WcsMain/appsettings.json
+++ b/WcsMain/appsettings.json
@@ -8,13 +8,14 @@
"AllowedHosts": "*",
"Settings": {
"DBMysql": "server=192.168.103.200;port=3306;user=developer;password=developer;database=wcs_main;",
- "DBMysqlLocal": "server=192.168.234.128;port=3306;user=developer;password=developer;database=wcs_main;",
+ "DBMysqlLocal": "server=192.168.234.128;port=3306;user=developer;password=developer;database=wcs_suzhoukt;",
"DBMssql": "Data Source=192.168.142.131;Initial Catalog=wcs;User Id=sa;Password=Sa123;",
"DBMssqlLocal": "Data Source=192.168.142.131;Initial Catalog=wcs_stacker;User Id=sa;Password=Sa123;",
"ApplicationConfig": {
- "ApiOnly": true
+ "ApiOnly": true,
+ "Language": "zh-CN"
},
"UseUrls": [ "http://*:890" ]