wanshenmean
2026-03-26 8e42d0c1b7ae36cff2e7c69999117911a4b6f300
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs
@@ -1,27 +1,13 @@
#region << 版 本 注 释 >>
/*----------------------------------------------------------------
 * 命名空间:WIDESEAWCS_Tasks.ConveyorLineJob
 * 创建者:胡童庆
 * 创建时间:2024/8/2 16:13:36
 * 版本:V1.0.0
 * 描述:
 *
 * ----------------------------------------------------------------
 * 修改人:
 * 修改时间:
 * 版本:V1.0.1
 * 修改说明:
 *
 *----------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
using AutoMapper;
using MapsterMapper;
using Microsoft.Extensions.Configuration;
using Quartz;
using SqlSugar;
using System.Text.Json;
using WIDESEA_Core;
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;
@@ -29,78 +15,200 @@
namespace WIDESEAWCS_Tasks
{
    /// <summary>
    /// 输送线任务作业(Quartz Job)- 核心执行逻辑
    /// </summary>
    /// <remarks>
    /// Quartz 定时任务,负责处理输送线的任务调度。
    /// 使用 [DisallowConcurrentExecution] 禁止并发执行,确保同一设备的任务串行处理。
    ///
    /// 核心职责:
    /// 1. 获取输送线的所有子设备位置
    /// 2. 并行处理每个子设备的消息
    /// 3. 根据任务状态调用相应的调度方法
    /// 4. 处理入库和出库两大类任务
    ///
    /// 该 Job 通过 Parallel.For 并行处理多个子设备,提高处理效率。
    /// </remarks>
    [DisallowConcurrentExecution]
    public class CommonConveyorLineNewJob : IJob
    {
        /// <summary>
        /// 任务服务
        /// </summary>
        private readonly ITaskService _taskService;
        private readonly ITaskExecuteDetailService _taskExecuteDetailService;
        private readonly IRouterService _routerService;
        private readonly IMapper _mapper;
        ConveyorLineDispatchHandler _conveyorLineDispatch;
        public CommonConveyorLineNewJob(ITaskService taskService, ITaskExecuteDetailService taskExecuteDetailService, IRouterService routerService, IMapper mapper)
        /// <summary>
        /// 任务执行明细服务
        /// </summary>
        private readonly ITaskExecuteDetailService _taskExecuteDetailService;
        /// <summary>
        /// 路由服务
        /// </summary>
        private readonly IRouterService _routerService;
        /// <summary>
        /// 对象映射器
        /// </summary>
        private readonly IMapper _mapper;
        /// <summary>
        /// 输送线调度处理器
        /// </summary>
        /// <remarks>
        /// 封装了输送线业务逻辑的处理方法。
        /// </remarks>
        private ConveyorLineDispatchHandler _conveyorLineDispatch;
        /// <summary>
        /// HTTP 客户端帮助类
        /// </summary>
        /// <remarks>
        /// 用于调用 WMS 系统的 HTTP 接口。
        /// </remarks>
        private readonly HttpClientHelper _httpClientHelper;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="taskService">任务服务</param>
        /// <param name="taskExecuteDetailService">任务执行明细服务</param>
        /// <param name="routerService">路由服务</param>
        /// <param name="mapper">对象映射器</param>
        /// <param name="httpClientHelper">HTTP 客户端帮助类</param>
        public CommonConveyorLineNewJob(ITaskService taskService, ITaskExecuteDetailService taskExecuteDetailService, IRouterService routerService, IMapper mapper, HttpClientHelper httpClientHelper)
        {
            _taskService = taskService;
            _taskExecuteDetailService = taskExecuteDetailService;
            _routerService = routerService;
            _mapper = mapper;
            _httpClientHelper = httpClientHelper;
            // 初始化调度处理器
            _conveyorLineDispatch = new ConveyorLineDispatchHandler(_taskService, _taskExecuteDetailService, _routerService, _mapper);
        }
        /// <summary>
        /// Quartz Job 的执行入口
        /// </summary>
        /// <remarks>
        /// 执行流程:
        /// 1. 从 JobDataMap 获取输送线设备信息
        /// 2. 获取该输送线的所有子设备位置列表
        /// 3. 并行处理每个子设备的消息
        /// 4. 检查托盘位置(特定配置的位置)
        /// 5. 根据任务状态分发到相应的处理方法
        ///
        /// 并行处理提高了对多站台输送线的处理效率。
        /// </remarks>
        /// <param name="context">Quartz 作业执行上下文</param>
        public Task Execute(IJobExecutionContext context)
        {
            try
            {
                // 从 JobDataMap 获取输送线设备参数
                CommonConveyorLine conveyorLine = (CommonConveyorLine)context.JobDetail.JobDataMap.Get("JobParams");
                if (conveyorLine != null)
                {
                    // 获取该输送线下的所有子设备位置编码
                    List<string> childDeviceCodes = _routerService.QueryAllPositions(conveyorLine.DeviceCode);
                    if (childDeviceCodes == null || childDeviceCodes.Count == 0)
                    {
                        // 没有子设备,直接返回
                        Console.WriteLine($"输送线 {conveyorLine.DeviceCode} 没有子设备");
                        return Task.CompletedTask;
                    }
                    // 创建并行选项
                    // 创建并行选项,限制最大并发数
                    var parallelOptions = new ParallelOptions
                    {
                        MaxDegreeOfParallelism = Math.Min(childDeviceCodes.Count, Environment.ProcessorCount * 2), // 合理限制并发数
                        // 限制并发数:子设备数量和 CPU 核心数*2 的较小值
                        MaxDegreeOfParallelism = Math.Min(childDeviceCodes.Count, Environment.ProcessorCount * 2),
                    };
                    // 并行处理每个子设备
                    Parallel.For(0, childDeviceCodes.Count, parallelOptions, i =>
                    {
                        string childDeviceCode = childDeviceCodes[i];
                        var correlationId = Guid.NewGuid().ToString("N");
                        try
                        {
                            // 读取该位置的 PLC 命令数据
                            ConveyorLineTaskCommandNew command = conveyorLine.ReadCustomer<ConveyorLineTaskCommandNew>(childDeviceCode);
                            if (command == null || command.PLC_STB != 1)
                            // 如果命令为空,跳过
                            if (command == null)
                            {
                                return;
                            }
                            if (command.Barcode.IsNullOrEmpty())
                            // 如果 WCS_ACK 为 1,先清除(表示处理过上一次请求)
                            if (command.WCS_ACK == 1)
                                conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 0, childDeviceCode);
                            // ========== 检查特定位置是否有托盘 ==========
                            // 从配置中读取需要检查托盘的位置列表
                            var checkPalletPositions = App.Configuration.GetSection("CheckPalletPositions")
                                .Get<List<CheckPalletPosition>>() ?? new List<CheckPalletPosition>();
                            // 如果当前设备在检查列表中
                            if (checkPalletPositions.Any(x => x.Code == childDeviceCode))
                            {
                                //无托盘号时
                                // 检查输送线状态(是否有托盘)
                                if (command.CV_State.ObjToBool())
                                {
                                    // 检查该位置是否已有任务
                                    var existingTask = _taskService.Repository.QueryFirst(x => x.TargetAddress == childDeviceCode);
                                    if (existingTask.IsNullOrEmpty())
                                    {
                                        // 没有任务,向 WMS 请求出库托盘任务
                                        var position = checkPalletPositions.FirstOrDefault(x => x.Code == childDeviceCode);
                                        var responseResult = _httpClientHelper.Post<WebResponseContent>("GetOutBoundTrayTaskAsync", new CreateTaskDto()
                                        {
                                            WarehouseId = position.WarehouseId,
                                            TargetAddress = childDeviceCode
                                        }.Serialize());
                                        // 如果请求成功,接收 WMS 返回的任务
                                        if (responseResult.IsSuccess && responseResult.Data.Status)
                                        {
                                            var wmsTask = JsonSerializer.Deserialize<List<WMSTaskDTO>>(responseResult.Data.Data.Serialize());
                                            if (wmsTask != null)
                                                _taskService.ReceiveWMSTask(wmsTask);
                                        }
                                    }
                                }
                            }
                            // ========== 检查 PLC_STB 标志 ==========
                            // 只有当 PLC_STB 为 1 时才处理任务
                            if (command.PLC_STB != 1) return;
                            // ========== 处理无托盘条码的情况 ==========
                            // 无托盘条码时,请求出库任务
                            if (command.Barcode.IsNullOrEmpty() || command.Barcode.Replace("\0", "") == "")
                            {
                                _conveyorLineDispatch.RequestOutbound(conveyorLine, command, childDeviceCode);
                                return;
                            }
                            // ========== 处理已有任务号的情况 ==========
                            if (command.TaskNo > 0)
                            {
                                // 查询正在执行的任务
                                Dt_Task task = _taskService.QueryExecutingConveyorLineTask(command.TaskNo, childDeviceCode);
                                if (task.IsNullOrEmpty())
                                if (!task.IsNullOrEmpty())
                                {
                                    _conveyorLineDispatch.RequestInbound(conveyorLine, command, childDeviceCode);
                                    // 处理任务状态(根据状态分发到不同方法)
                                    ProcessTaskState(conveyorLine, command, task, childDeviceCode);
                                    return;
                                }
                                // 处理任务状态
                                ProcessTaskState(conveyorLine, command, task, childDeviceCode);
                            }
                        }
                        catch (Exception innerEx)
                        {
                            // 记录异常,但不影响其他子设备的处理
                            Console.Error.WriteLine($"{DateTime.UtcNow:O} [{childDeviceCode}] CorrelationId={correlationId} {innerEx}");
                        }
                    });
@@ -108,57 +216,68 @@
            }
            catch (Exception ex)
            {
                // 记录整体异常
                Console.Error.WriteLine(ex);
            }
            return Task.CompletedTask;
        }
        /// <summary>
        /// 处理任务状态
        /// </summary>
        /// <param name="conveyorLine">输送线实例对象</param>
        /// <param name="command">读取的请求信息</param>
        /// <param name="task">子设备编号</param>
        /// <param name="childDeviceCode"></param>
        /// <remarks>
        /// 根据任务的当前状态,调用相应的调度方法:
        /// - InExecuting: 入库执行中 -> 调用 RequestInNextAddress
        /// - OutExecuting: 出库执行中 -> 根据是否到达目标地址调用对应方法
        /// - InFinish: 入库完成 -> 调用 ConveyorLineInFinish
        /// - OutFinish: 出库完成 -> 调用 ConveyorLineOutFinish
        /// </remarks>
        /// <param name="conveyorLine">输送线设备对象</param>
        /// <param name="command">PLC 命令数据</param>
        /// <param name="task">任务对象</param>
        /// <param name="childDeviceCode">子设备编码</param>
        private void ProcessTaskState(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, Dt_Task task, string childDeviceCode)
        {
            // 定义状态常量(如果类中已定义则可移除)
            const int InExecuting = (int)TaskInStatusEnum.Line_InExecuting;
            const int OutExecuting = (int)TaskOutStatusEnum.Line_OutExecuting;
            const int InFinish = (int)TaskInStatusEnum.InFinish;
            const int OutFinish = (int)TaskOutStatusEnum.OutFinish;
            // 定义任务状态常量
            const int InExecuting = (int)TaskInStatusEnum.Line_InExecuting;     // 入库执行中
            const int OutExecuting = (int)TaskOutStatusEnum.Line_OutExecuting; // 出库执行中
            const int InFinish = (int)TaskInStatusEnum.InFinish;                 // 入库完成
            const int OutFinish = (int)TaskOutStatusEnum.OutFinish;             // 出库完成
            int state = task.TaskState;
            // 获取当前任务状态
            int state = task.TaskStatus;
            // 判断当前子设备是否为目标地址
            bool isTargetAddress = task.TargetAddress == childDeviceCode;
            // 处理状态逻辑
            // 根据状态分发处理
            switch (state)
            {
                case InExecuting:
                    //if (isTargetAddress)
                    //    _conveyorLineDispatch.ConveyorLineInFinish(conveyorLine, command, childDeviceCode);
                    //else
                    // 入库执行中,调用下一地址处理
                    _conveyorLineDispatch.RequestInNextAddress(conveyorLine, command, childDeviceCode);
                    break;
                case OutExecuting:
                    // 出库执行中
                    if (isTargetAddress)
                        // 到达目标地址,调用出库完成
                        _conveyorLineDispatch.ConveyorLineOutFinish(conveyorLine, command, childDeviceCode);
                    else
                        // 未到达目标地址,调用出库下一地址处理
                        _conveyorLineDispatch.RequestOutNextAddress(conveyorLine, command, childDeviceCode);
                    break;
                case InFinish:
                    // 入库完成
                    _conveyorLineDispatch.ConveyorLineInFinish(conveyorLine, command, childDeviceCode);
                    break;
                case OutFinish:
                    // 出库完成
                    _conveyorLineDispatch.ConveyorLineOutFinish(conveyorLine, command, childDeviceCode);
                    break;
            }
        }
    }
}
}