fix: 修复多个功能模块中的问题和优化逻辑
修复WMS基础URL配置错误
修复SiemensDBDataType中DataType_ByteArray的类型转换问题
修复RedisConnectionManager中无可用终结点时的异常处理
修复RobotTaskService中GetRobotTaskTotalNum方法的WMS接口调用
优化ConveyorLineTargetAddressSelector中的目标地址选择逻辑
优化Quartz任务调度中IntervalSecond为0或负值的处理
优化RobotWorkflowOrchestrator中的换盘任务处理逻辑
优化TaskService_Inbound中的库存状态更新
优化ConveyorLineDispatchHandler中的任务下发逻辑
优化RobotSimpleCommandHandler中的批量拆盘和组盘确认逻辑
优化StackerCraneTaskSelector中的出库任务选择逻辑
优化CommonConveyorLineNewJob中的手动入库任务处理
| | |
| | | /// <summary> |
| | | /// WMS接口基础URL |
| | | /// </summary> |
| | | public const string WMSBaseUrl = "http://localhost:9291/api/"; |
| | | public const string WMSBaseUrl = "http://192.168.60.30:9291/api/"; |
| | | |
| | | /// <summary> |
| | | /// WCS接口基础URL |
| | |
| | | DataType_Char => TypeCode.Char, |
| | | DataType_UInt => TypeCode.UInt16, |
| | | DataType_UDInt => TypeCode.UInt32, |
| | | DataType_ByteArray => TypeCode.SByte, |
| | | _ => throw new CommunicationException($"数据类型错误:【{dataType}】", CommunicationErrorType.TypeError), |
| | | }; |
| | | } |
| | |
| | | return Encoding.Default.GetString((byte[])GetContent(plc.Read(address, length), address)).ToArray(); |
| | | return (char)GetContent(plc.ReadByte(address), address); |
| | | |
| | | case TypeCode.SByte: |
| | | return Encoding.Default.GetString((byte[])GetContent(plc.Read(address, 20), address)).ToArray(); |
| | | |
| | | default: |
| | | throw new CommunicationException(string.Format(CommunicationExceptionMessage.DataTypeErrorException, typeCode.ToString(), address), CommunicationErrorType.TypeError); |
| | | } |
| | |
| | | WebResponseContent GetWMSRobotTask(Dt_Task task); |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | /// <param name="taskType"></param> |
| | | /// <param name="palletCode"></param> |
| | | /// <returns></returns> |
| | | int GetRobotTaskTotalNum(int taskType, string? palletCode); |
| | | |
| | | /// <summary> |
| | | /// 在本地直接创建机械手任务,不调用WMS接口 |
| | | /// </summary> |
| | | /// <param name="task">出库任务</param> |
| | |
| | | /// <returns></returns> |
| | | private ITrigger CreateSimpleTrigger(DispatchInfoDTO sysSchedule) |
| | | { |
| | | // Quartz要求间隔至少1秒,防止数据库中IntervalSecond为0或负值导致ArgumentOutOfRangeException |
| | | var intervalSeconds = sysSchedule.IntervalSecond <= 0 ? 1 : sysSchedule.IntervalSecond; |
| | | |
| | | ITrigger trigger = TriggerBuilder.Create() |
| | | .WithIdentity(sysSchedule.Id.ToString(), sysSchedule.JobGroup) |
| | | .StartAt(sysSchedule.BeginTime.GetValueOrDefault()) |
| | | .WithSimpleSchedule(x => x |
| | | .WithIntervalInSeconds(sysSchedule.IntervalSecond) |
| | | .WithIntervalInSeconds(intervalSeconds) |
| | | .RepeatForever() |
| | | ) |
| | | .EndAt(sysSchedule.EndTime.GetValueOrDefault()) |
| | |
| | | public IServer GetServer() |
| | | { |
| | | var endpoints = _connection.Value.GetEndPoints(); |
| | | if (endpoints == null || endpoints.Length == 0) |
| | | throw new InvalidOperationException("Redis没有可用的终结点,请检查连接配置"); |
| | | return _connection.Value.GetServer(endpoints[0]); |
| | | } |
| | | |
| | |
| | | using Microsoft.AspNetCore.Authorization; |
| | | using Microsoft.AspNetCore.Mvc; |
| | | using System.Threading.Tasks; |
| | | using WIDESEAWCS_Core; |
| | | using WIDESEAWCS_Core.BaseController; |
| | | using WIDESEAWCS_Core.Enums; |
| | | using WIDESEAWCS_DTO.TaskInfo; |
| | | using WIDESEAWCS_ISystemServices; |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_Model.Models; |
| | | |
| | |
| | | { |
| | | public RobotTaskController(IRobotTaskService service) : base(service) |
| | | { |
| | | |
| | | }
|
| | |
|
| | | [HttpGet, HttpPost, Route("DeleteRobotTask"), AllowAnonymous] |
| | | public WebResponseContent DeleteRobotTask(int id) |
| | | { |
| | | if (Service.DeleteRobotTask(id)){
|
| | | if (Service.DeleteRobotTask(id))
|
| | | {
|
| | | return WebResponseContent.Instance.OK();
|
| | | } |
| | | return WebResponseContent.Instance.Error(); |
| | | } |
| | | |
| | |
|
| | | [HttpGet, HttpPost, Route("GetRobotTaskTotalNum"), AllowAnonymous]
|
| | | public int GetRobotTaskTotalNum( int taskType, string? palletCode)
|
| | | {
|
| | | return Service.GetRobotTaskTotalNum(taskType, palletCode);
|
| | | }
|
| | | } |
| | | } |
| | |
| | | //5.PostgreSQL |
| | | "DBType": "SqlServer", |
| | | //连接字符串 |
| | | "ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWCS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |
| | | "ConnectionString": "Data Source=192.168.60.30;Initial Catalog=WIDESEAWCS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |
| | | //"ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWCS_ShanMei;User ID=sa;Password=123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |
| | | |
| | | //跨域 |
| | |
| | | using MapsterMapper;
|
| | | using Microsoft.Extensions.Configuration;
|
| | | using Newtonsoft.Json;
|
| | | using Newtonsoft.Json.Linq;
|
| | | using Serilog;
|
| | | using SqlSugar;
|
| | | using System.Diagnostics;
|
| | | using System.Diagnostics.CodeAnalysis;
|
| | | using System.Text;
|
| | | using WIDESEA_Core;
|
| | | using WIDESEAWCS_Common;
|
| | | using WIDESEAWCS_Common.HttpEnum;
|
| | |
| | | _taskExecuteDetailService = taskExecuteDetailService;
|
| | | _logger = logger;
|
| | | }
|
| | |
|
| | | public override WebResponseContent DeleteData(object[] keys)
|
| | | {
|
| | | List<int> taskKeys = new List<int>();
|
| | |
| | | List<Dt_RobotTask> tasks = BaseDal.QueryData(x => taskKeys.Contains(x.RobotTaskId));
|
| | | BaseDal.DeleteAndMoveIntoHty(tasks, OperateTypeEnum.人工删除);
|
| | | return WebResponseContent.Instance.OK($"成功删除{tasks.Count}条数据");
|
| | |
|
| | | }
|
| | |
|
| | | public bool DeleteRobotTask(int id)
|
| | | {
|
| | | Dt_RobotTask task = BaseDal.QueryFirst(x => x.RobotTaskId == id);
|
| | |
| | |
|
| | | public Dt_RobotTask? QueryRobotCraneTask(string deviceCode)
|
| | | {
|
| | | return BaseDal.QueryFirst(x => x.RobotRoadway == deviceCode && x.RobotTaskState != (int)TaskRobotStatusEnum.RobotExecuting, TaskOrderBy);
|
| | | return BaseDal.QueryFirst(x => x.RobotRoadway == deviceCode, TaskOrderBy);
|
| | | }
|
| | |
|
| | | public Dt_RobotTask? QueryRobotCraneExecutingTask(string deviceCode)
|
| | |
| | | /// 获取机械手任务总数量。
|
| | | /// 组盘任务固定48,换盘和拆盘任务通过托盘号查询WMS库存明细数量。
|
| | | /// </summary>
|
| | | private int GetRobotTaskTotalNum(int taskType, string? palletCode)
|
| | | public int GetRobotTaskTotalNum(int taskType, string? palletCode)
|
| | | {
|
| | | if (taskType == (int)RobotTaskTypeEnum.GroupPallet)
|
| | | return 48;
|
| | |
| | |
|
| | | try
|
| | | {
|
| | | QuartzLogHelper.LogInfo(_logger, $"开始调用WMS接口获取库存明细数量,托盘号:【{palletCode}】", "RobotTaskService");
|
| | | string url = $"{BaseAPI.WMSBaseUrl}Stock/GetStockDetailCount?palletCode={Uri.EscapeDataString(palletCode)}";
|
| | | var result = _httpClientHelper.Get(url);
|
| | | QuartzLogHelper.LogInfo(_logger, $"调用WMS获取库存明细数量接口,请求URL:【{url}】,响应数据:【{result.Content}】,耗时:{result.Duration}ms", "RobotTaskService");
|
| | | if (!result.IsSuccess || string.IsNullOrEmpty(result.Content))
|
| | | return 1;
|
| | |
|
| | |
| | | if (response == null || !response.Status)
|
| | | return 1;
|
| | |
|
| | | var detailCount = response.Data?.GetType().GetProperty("DetailCount")?.GetValue(response.Data);
|
| | | return detailCount is int count and > 0 ? count : 1;
|
| | | var detailCount = (response.Data as JObject)?["detailCount"]?.Value<int>();
|
| | | return detailCount.HasValue && detailCount.Value > 0 ? detailCount.Value : 1;
|
| | | }
|
| | | catch
|
| | | {
|
| | |
| | | CommonConveyorLine conveyorLine = (CommonConveyorLine)device;
|
| | |
|
| | | DeviceProDTO? devicePro = conveyorLine.DeviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(ConveyorLineDBNameNew.Barcode) && x.DeviceChildCode == sourceLineNo);
|
| | | //conveyorLine.Communicator.Read(devicePro.DeviceProAddress, 20);
|
| | | //ConveyorLineTaskCommandNew command = conveyorLine.ReadCustomer<ConveyorLineTaskCommandNew>(sourceLineNo); // 测试用
|
| | | var barcode = conveyorLine.GetValue<ConveyorLineDBNameNew, string>(ConveyorLineDBNameNew.Barcode, sourceLineNo);
|
| | | var bytes = conveyorLine.Communicator.Read(devicePro.DeviceProAddress, 20);
|
| | | var barcode = Encoding.Default.GetString(bytes).Trim();
|
| | | stock.SourcePalletNo = string.IsNullOrEmpty(barcode) ? string.Empty : barcode;
|
| | | }
|
| | | }
|
| | |
| | | using MapsterMapper; |
| | | using Masuit.Tools; |
| | | using Microsoft.Extensions.Configuration; |
| | | using Newtonsoft.Json; |
| | | using Quartz; |
| | | using Serilog; |
| | | using SqlSugar; |
| | | using WIDESEA_Core; |
| | | using WIDESEAWCS_Common.HttpEnum; |
| | | using WIDESEAWCS_Common.TaskEnum; |
| | | using WIDESEAWCS_Core; |
| | | using WIDESEAWCS_Core.Helper; |
| | | using WIDESEAWCS_DTO.TaskInfo; |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_Model.Models; |
| | | using WIDESEAWCS_QuartzJob; |
| | |
| | | { |
| | | // 如果 WCS_ACK 为 1,先清除(表示处理过上一次请求) |
| | | if (command.WCS_ACK == 1) |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)0, childDeviceCode); |
| | | { |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (byte)0, childDeviceCode); |
| | | //Thread.Sleep(300); |
| | | //conveyorLine.SetValue(ConveyorLineDBNameNew.Target, (short)0, childDeviceCode); |
| | | } |
| | | |
| | | // 处理手动入库任务(起点为线体点位的任务) |
| | | try |
| | |
| | | } |
| | | continue; |
| | | } |
| | | else |
| | | { |
| | | if (childDeviceCode == "2103" || childDeviceCode == "2101") |
| | | { |
| | | try |
| | | { |
| | | var task = _taskService.QueryManualInboundTask(childDeviceCode); |
| | | if (task != null) |
| | | { |
| | | QuartzLogHelper.LogInfo(_logger, $"获取到输送线开始任务,任务号:{task.TaskNum},状态: {task.TaskStatus},当前地址:{conveyorLine.DeviceCode}", conveyorLine.DeviceCode); |
| | | var handler = new ManualInboundTaskHandler(_taskService, _logger); |
| | | handler.WriteTaskToPlc(conveyorLine, childDeviceCode, task); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | QuartzLogHelper.LogError(_logger, ex, "处理手动入库任务异常", $"处理手动入库任务异常: {ex.Message}", "CommonConveyorLineNewJob"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // ========== 处理无托盘条码的情况 ========== |
| | | // 无托盘条码时,请求出库任务 |
| | | if (command.Barcode.IsNullOrEmpty() || command.Barcode.Replace("\0", "") == "") |
| | | // 如果 PLC_STB 为 1,但没有任务号,可能是新任务的开始,先请求出库任务(适用于无条码的情况) |
| | | if (command.TaskNo == 1000) |
| | | { |
| | | _conveyorLineDispatch.RequestOutbound(conveyorLine, command, childDeviceCode); |
| | | continue; |
| | | } |
| | | |
| | | // ========== 处理已有任务号的情况 ========== |
| | | if (command.TaskNo > 0 && !command.Barcode.IsNullOrEmpty()) |
| | | if (command.TaskNo > 0) |
| | | { |
| | | // 查询正在执行的任务 |
| | | Dt_Task task = _taskService.QueryExecutingConveyorLineTask(command.TaskNo, childDeviceCode); |
| | |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, childDeviceCode); |
| | | } |
| | | } |
| | | //else if (!command.Barcode.IsNullOrEmpty() && (childDeviceCode == "11001" || childDeviceCode == "11010")) |
| | | //{ |
| | | // var isWcsTask = _taskService.Db.Queryable<Dt_Task>().Any(x => x.PalletCode == command.Barcode && (x.TaskStatus == (int)TaskOutStatusEnum.OutNew || x.TaskStatus == (int)TaskInStatusEnum.InNew)); |
| | | // var isRobotTask = _robotTaskService.Db.Queryable<Dt_RobotTask>().Any(x => x.RobotTargetAddressPalletCode == command.Barcode); |
| | | // if (isWcsTask || isRobotTask) |
| | | // { |
| | | // continue; |
| | | // } |
| | | |
| | | // // 调用 WMS 创建空托盘入库任务 |
| | | // string configKey = nameof(ConfigKey.CreateTaskInboundAsync); |
| | | // string requestParam = new CreateTaskDto() |
| | | // { |
| | | // PalletCode = command.Barcode, |
| | | // SourceAddress = childDeviceCode, |
| | | // TargetAddress = "GWSC1", // 目标地址 |
| | | // Roadway = "GWSC1", // 巷道 |
| | | // WarehouseId = 1, // 仓库 ID |
| | | // PalletType = 1, // 托盘类型(默认为1) |
| | | // TaskType = TaskTypeEnum.InEmpty.GetHashCode() // 任务类型(入库/空托盘入库) |
| | | // }.Serialize(); |
| | | // DateTime startTime = DateTime.Now; |
| | | |
| | | // var responseResult = _httpClientHelper.Post<WebResponseContent>(configKey, requestParam); |
| | | |
| | | // if (responseResult.IsSuccess && responseResult.Data.Status) |
| | | // { |
| | | // QuartzLogHelper.LogInfo(_logger, $"调用WMS接口成功,接口:【{configKey}】,请求参数:【{requestParam}】,响应数据:【{responseResult.Data?.Data}】,耗时:{(DateTime.Now - startTime).TotalMilliseconds}ms", conveyorLine.DeviceCode); |
| | | // var wmsTask = JsonConvert.DeserializeObject<WMSTaskDTO>(responseResult?.Data?.Data?.ToString()); |
| | | // List<WMSTaskDTO> taskDTOs = new List<WMSTaskDTO> { wmsTask }; |
| | | // if (wmsTask == null) continue; |
| | | |
| | | // if (_taskService.ReceiveWMSTask(taskDTOs).Status) |
| | | // { |
| | | // conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, childDeviceCode); |
| | | // } |
| | | // } |
| | | // else |
| | | // { |
| | | // QuartzLogHelper.LogError(_logger, $"调用WMS接口失败,接口:【{configKey}】,请求参数:【{requestParam}】,错误信息:【{responseResult.Data?.Message}】", conveyorLine.DeviceCode); |
| | | // } |
| | | //} |
| | | } |
| | | } |
| | | catch (Exception innerEx) |
| | |
| | | |
| | | // 确定目标地址:空托盘任务使用 "2201",其他任务使用 NextAddress |
| | | var isEmptyTask = task.TaskType == (int)TaskOutboundTypeEnum.OutEmpty; |
| | | var targetAddress = task.CurrentAddress == "2217" ? (isEmptyTask ? "2201" : task.NextAddress) : task.NextAddress; |
| | | var targetAddress = task.CurrentAddress == "2217" ? (isEmptyTask ? task.TargetAddress : task.NextAddress) : task.NextAddress; |
| | | |
| | | // 处理特殊地址 2217,需要调用目标地址选择器 |
| | | if (task.CurrentAddress == "2217" && !_targetAddressSelector.HandleOutboundNextAddress(conveyorLine, targetAddress, childDeviceCode)) |
| | | { |
| | | return Task.CompletedTask; ; |
| | | } |
| | | //if (task.CurrentAddress == "2217" && !_targetAddressSelector.HandleOutboundNextAddress(conveyorLine, targetAddress, childDeviceCode)) |
| | | //{ |
| | | // return Task.CompletedTask; ; |
| | | //} |
| | | |
| | | // 设置任务号、托盘条码、目标地址、WCS_ACK |
| | | var isTaskNoSet = conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, task.TaskNum, childDeviceCode); |
| | | |
| | | Thread.Sleep(100); // 确保 PLC 能正确读取任务号后再写入条码 |
| | | Thread.Sleep(300); // 确保 PLC 能正确读取任务号后再写入条码 |
| | | var isPalletSet = conveyorLine.SetValue(ConveyorLineDBNameNew.Barcode, task.PalletCode, childDeviceCode); |
| | | |
| | | Thread.Sleep(100); // 确保 PLC 能正确读取任务号后再写入条码 |
| | | Thread.Sleep(300); // 确保 PLC 能正确读取任务号后再写入条码 |
| | | bool isTargetSet = conveyorLine.SetValue(ConveyorLineDBNameNew.Target, targetAddress, childDeviceCode); |
| | | //if (targetAddress == "2217" && !isEmptyTask) |
| | | //{ |
| | |
| | | |
| | | bool isWmsResult = false; |
| | | // 更新任务状态或位置 |
| | | if (isEmptyTask && task.NextAddress == "2217") |
| | | if (isEmptyTask && (task.TargetAddress == "2103" || task.TargetAddress == "2101")) |
| | | { |
| | | task.TaskStatus = task.TaskStatus.GetNextNotCompletedStatus<TaskOutStatusEnum>(); |
| | | task.NextAddress = "2201"; |
| | | task.NextAddress = "2103"; |
| | | isWmsResult = _taskService.Repository.UpdateData(task); |
| | | } |
| | | else |
| | |
| | | |
| | | var cvState = conveyorLine.GetValue<ConveyorLineDBNameNew, byte>(ConveyorLineDBNameNew.CV_State, nextAddress); |
| | | bool isAvailable = cvState == 2; |
| | | WriteDebug(conveyorLine, "出库下一地址状态", childDeviceCode, $"CV_State={cvState},可用={isAvailable}"); |
| | | if (isAvailable) |
| | | { |
| | | WriteDebug(conveyorLine, "出库下一地址可用,写入目标地址", childDeviceCode, nextAddress); |
| | | Thread.Sleep(300); // 短暂等待,确保设备状态稳定后再写入目标地址 |
| | | return conveyorLine.SetValue(ConveyorLineDBNameNew.Target, Convert.ToInt16(nextAddress), childDeviceCode); |
| | | } |
| | | return false; |
| | |
| | | // 解析 WMS 返回的任务信息
|
| | | WMSTaskDTO taskDTO = JsonConvert.DeserializeObject<WMSTaskDTO>(result.Data.Data.ToJson() ?? string.Empty) ?? new WMSTaskDTO();
|
| | |
|
| | | var task = await _taskService.Repository.QueryFirstAsync(x => x.PalletCode == taskDTO.PalletCode);
|
| | | if(task != null)
|
| | | {
|
| | | await _taskService.Repository.DeleteDataAsync(task);
|
| | | }
|
| | |
|
| | | // 调用任务服务接收 WMS 任务
|
| | | var content = _taskService.ReceiveWMSTask(new List<WMSTaskDTO> { taskDTO });
|
| | | if (!content.Status)
|
| | |
| | | // 调用批量拆盘确认接口 |
| | | var sourcePallet = state.CurrentTask.RobotSourceAddressPalletCode; |
| | | var confirmResult = _taskProcessor.PostSplitPalletConfirmAsync(sourcePallet, state.RobotCrane?.DeviceName); |
| | | if (!confirmResult.IsSuccess) |
| | | if (!confirmResult.IsSuccess && !confirmResult.Data.Status) |
| | | { |
| | | QuartzLogHelper.LogError(_logger, $"批量拆盘确认失败: {confirmResult.ErrorMessage}", state.RobotCrane?.DeviceName ?? "Unknown"); |
| | | return false; |
| | |
| | | // 调用批量组盘确认接口 |
| | | var targetPallet = state.CurrentTask.RobotTargetAddressPalletCode; |
| | | var confirmResult = _taskProcessor.PostGroupPalletConfirmAsync(targetPallet, state.RobotCrane?.DeviceName); |
| | | if (!confirmResult.IsSuccess) |
| | | if (!confirmResult.IsSuccess && !confirmResult.Data.Status) |
| | | { |
| | | QuartzLogHelper.LogError(_logger, $"批量组盘确认失败: {confirmResult.ErrorMessage}", state.RobotCrane?.DeviceName ?? "Unknown"); |
| | | return false; |
| | |
| | | // 目标数量为48:直接走原有逻辑,不进入批次模式 |
| | | if (targetNormalCount + currentCompletedCount == targetTotal) |
| | | { |
| | | QuartzLogHelper.LogInfo(_logger, $"HandlePutFinishedStateAsync:目标数量已达48,直接下发取货指令,任务号: {task.RobotTaskNum}", stateForUpdate?.RobotCrane?.DeviceName ?? ipAddress); |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate); |
| | | return; |
| | | } |
| | | |
| | | QuartzLogHelper.LogDebug(_logger,$"HandlePutFinishedStateAsync:换盘任务目标数量: {targetNormalCount},当前已完成数量: {currentCompletedCount},流向: {(isFlowA ? "A" : "B")},任务号: {task.RobotTaskNum}", stateForUpdate?.RobotCrane?.DeviceName ?? ipAddress); |
| | | |
| | | // 初始化批次模式 |
| | | if (stateForUpdate.ChangePalletPhase == 0) |
| | | { |
| | |
| | | using System.Text.Json; |
| | | using System.IO; |
| | | using WIDESEAWCS_Model.Models; |
| | | using Serilog.Core; |
| | | |
| | | namespace WIDESEAWCS_Tasks.SocketServer |
| | | { |
| | |
| | | //{ |
| | | // if (_clientLastMessage.TryGetValue(clientId, out var prev) && message == prev) |
| | | // { |
| | | // QuartzLogHelper.LogInfo(Logger.None, $"来自客户端 {clientId} 的重复消息,内容: {message}", clientId); |
| | | // continue; |
| | | // } |
| | | // _clientLastMessage[clientId] = message; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 加载配置文件(优先级:配置文件 > 默认配置) |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 从应用程序目录下的 StackerCraneJob/stackercrane-command-config.json 读取配置。 |
| | | /// 如果文件不存在或解析失败,使用默认配置。 |
| | | /// </remarks> |
| | | /// <returns>堆垛机命令配置</returns> |
| | | private static StackerCraneCommandConfig LoadConfig() |
| | | { |
| | | try |
| | | { |
| | | // 构造配置文件路径 |
| | | string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "StackerCraneJob", "stackercrane-command-config.json"); |
| | | if (File.Exists(configPath)) |
| | | { |
| | | // 读取并解析 JSON 配置 |
| | | string json = File.ReadAllText(configPath); |
| | | return System.Text.Json.JsonSerializer.Deserialize<StackerCraneCommandConfig>(json) ?? new StackerCraneCommandConfig(); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | // 配置加载失败,使用默认配置 |
| | | Console.WriteLine($"配置加载失败: {ex.Message},使用默认配置"); |
| | | } |
| | | |
| | | return new StackerCraneCommandConfig(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Quartz Job 的执行入口 |
| | | /// </summary> |
| | | /// <remarks> |
| | |
| | | using Newtonsoft.Json; |
| | | using Serilog; |
| | | using System.Diagnostics.CodeAnalysis; |
| | | using System.Threading.Tasks; |
| | | using WIDESEA_Core; |
| | | using WIDESEAWCS_Common.Constants; |
| | | using WIDESEAWCS_Common.HttpEnum; |
| | |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_Model.Models; |
| | | using WIDESEAWCS_QuartzJob; |
| | | using WIDESEAWCS_QuartzJob.ConveyorLine.Enum; |
| | | using WIDESEAWCS_QuartzJob.Models; |
| | | using WIDESEAWCS_QuartzJob.Service; |
| | | |
| | |
| | | { |
| | | // 先进行本地站台检查(PLC 读取,快速),避免不必要的 WMS HTTP 调用 |
| | | |
| | | if (outboundTask.TaskType != (int)TaskOutboundTypeEnum.OutEmpty && outboundTask.Roadway != "GWSC1" && outboundTask.TargetAddress != "CWSC1") |
| | | if (outboundTask.TaskType != (int)TaskOutboundTypeEnum.OutEmpty && outboundTask.TargetAddress != "CWSC1") |
| | | { |
| | | // 判断 TargetAddress 输送线站台是否空闲 |
| | | if (!IsTargetAddressConveyorStationAvailable(outboundTask)) |
| | |
| | | return null; |
| | | } |
| | | |
| | | if (outboundTask.TargetAddress != "CWSC1") |
| | | { |
| | | //if (outboundTask.TargetAddress != "CWSC1") |
| | | //{ |
| | | // 检查是否有正在执行的输送线任务去往同一 TargetAddress |
| | | if (_taskService.HasExecutingTaskToTarget(outboundTask.Roadway, outboundTask.TargetAddress)) |
| | | { |
| | |
| | | $"TrySelectOutboundTask:TargetAddress: {outboundTask.TargetAddress} 已有正在执行的输送线任务", outboundTask.Roadway, outboundTask.TargetAddress, outboundTask.TaskNum); |
| | | return null; |
| | | } |
| | | } |
| | | //} |
| | | |
| | | if(outboundTask.Roadway != "GWSC1") |
| | | { |
| | |
| | | && x.LocationType == locationType) |
| | | .CountAsync(); |
| | | |
| | | if(roadwayNo != "CWSC1") |
| | | { |
| | | // 空闲货位不足最低保留数量时返回null,避免将巷道分配耗尽 |
| | | const int minFreeLocationThreshold = 5; |
| | | const int minFreeLocationThreshold = 1; |
| | | if (freeCount < minFreeLocationThreshold) return null; |
| | | } |
| | | |
| | | // 数据库端排序取第一条(只传输单行数据) |
| | | return await BaseDal.Db.Queryable<Dt_LocationInfo>() |
| | |
| | | /// <summary> |
| | | /// GW_1首放入库时效(24小时) |
| | | /// </summary> |
| | | public const int OUTBOUND_HOURS_GW1_FIRST = 24; |
| | | public const double OUTBOUND_HOURS_GW1_FIRST = 24; |
| | | |
| | | /// <summary> |
| | | /// GW_1二放入库时效(24小时) |
| | | /// GW_1二放入库时效(5分钟) |
| | | /// </summary> |
| | | public const int OUTBOUND_HOURS_GW1_SECOND = 24; |
| | | public const double OUTBOUND_HOURS_GW1_SECOND = 0.05; |
| | | |
| | | /// <summary> |
| | | /// CW_1出库时效(12小时) |
| | | /// CW_1出库时效(3小时) |
| | | /// </summary> |
| | | public const int OUTBOUND_HOURS_CW1 = 12; |
| | | public const double OUTBOUND_HOURS_CW1 = 3; |
| | | } |
| | | } |
| | |
| | | /// <summary> |
| | | /// 高温1号出库地址列表(轮询) |
| | | /// </summary> |
| | | public static readonly string[] GW1_ADDRESSES = { "11001" }; |
| | | public static readonly string[] GW1_ADDRESSES = { "11010" }; |
| | | |
| | | /// <summary> |
| | | /// 高温2号出库地址 |
| | |
| | | /// <summary> |
| | | /// 分容库出库地址 |
| | | /// </summary> |
| | | public const string GRADING_OUTBOUND_ADDRESS = "2103"; |
| | | public const string GRADING_OUTBOUND_ADDRESS = "2101"; |
| | | |
| | | /// <summary> |
| | | /// 分容库出库地址 |
| | |
| | | Creater = StockConstants.SYSTEM_USER, |
| | | Details = null, |
| | | LocationCode = location.LocationCode, |
| | | LocationId = location.Id |
| | | LocationId = location.Id, |
| | | OutboundDate = DateTime.Now |
| | | }; |
| | | location.LocationStatus = LocationStatusEnum.InStock.GetHashCode(); |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location); |
| | | var updateStockResult = await _stockInfoService.Repository.AddDataAsync(stockInfo); |
| | | return await CompleteTaskAsync(task, "入库完成"); |
| | |
| | | |
| | | stockInfo.StockStatus = StockStatusEmun.入库完成.GetHashCode(); |
| | | |
| | | stockInfo.CreateDate = DateTime.Now; |
| | | |
| | | location.LocationStatus = LocationStatusEnum.InStock.GetHashCode(); |
| | | |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location); |
| | |
| | | "MainDB": "DB_WIDESEA", //当前项目的主库,所对应的连接字符串的Enabled必须为true |
| | | //连接字符串 |
| | | //"ConnectionString": "HTI6FB1H05Krd07mNm9yBCNhofW6edA5zLs9TY~MNthRYW3kn0qKbMIsGp~3yyPDF1YZUCPBQx8U0Jfk4PH~ajNFXVIwlH85M3F~v_qKYQ3CeAz3q1mLVDn8O5uWt1~3Ut2V3KRkEwYHvW2oMDN~QIDXPxDgXN0R2oTIhc9dNu7QNaLEknblqmHhjaNSSpERdDVZIgHnMKejU_SL49tralBkZmDNi0hmkbL~837j1NWe37u9fJKmv91QPb~16JsuI9uu0EvNZ06g6PuZfOSAeFH9GMMIZiketdcJG3tHelo=", |
| | | "ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |
| | | "ConnectionString": "Data Source=192.168.60.30;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |
| | | //"ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |
| | | //"ConnectionString": "Data Source=10.30.4.92;Initial Catalog=WMS_TC;User ID=sa;Password=duo123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |
| | | //旧WMS数据库连接 |