hwh
2024-08-28 34044b791a62914aec56576f40d9de958c4f2bd4
Admin.NET/WCS.Application/PLC/PLCService.cs
@@ -1,14 +1,19 @@
using Flurl.Util;
using Furion.DatabaseAccessor;

using Furion.Logging;
using IoTClient;
using StackExchange.Redis;
using Microsoft.AspNetCore.SignalR;
using System.Data;
namespace WCS.Application;
public static class PLCService
{
    private static readonly ISqlSugarClient _db = SqlSugarSetup.ITenant.GetConnectionScope(SqlSugarConst.MainConfigId);
    private static readonly IHubContext<TaskLogHub, ITaskLogHub> _taskLogHubContext;
    static PLCService()
    {
        _taskLogHubContext = App.GetService<IHubContext<TaskLogHub, ITaskLogHub>>();
    }
    public static void OnChangeEvent(object sender, EventArgs e)
    {
@@ -49,137 +54,527 @@
        switch (modDevice.ToString())
        {
            case "820":
                var modTask = _db.Queryable<WcsTask>().First(s => s.Status == TaskStatusEnum.Wait && s.TaskType == TaskTypeEnum.Out && s.StartRoadway == modDevice.StationNum);
                if (modTask == null)
                {
                    break;
                }
                var modTaskMonitor = new WcsTaskMonitor()
                {
                    TaskNo = modTask.TaskNo,
                    StartLocat = modTask.StartLocate,
                    EndLocat = modTask.EndLocate,
                    PalletNo = modTask.PalletNo,
                };
                // 根据跺机号确认放货工位
                string outStationNum = "0";
                string endRow = "", endColumn = "", endStorey = "";
                switch (modDevice.StationNum)
                {
                    case "R01":
                        outStationNum = "11";
                        endRow = "1";
                        endColumn = "100";
                        endStorey = "1";
                        break;
                    case "R02":
                        outStationNum = "7";
                        endRow = "1";
                        endColumn = "100";
                        endStorey = "1";
                        break;
                    default: break;
                }
                var modD = modDevice.listDevice.FirstOrDefault();
                if (modD == null)
                {
                    Log.Error($"IP{modDevice.PlcId}.设备id:{modDevice.Id}缺少工位级别设备信息");
                    break;
                }
                var (result, value) = plcConn.GetPlcDBValue(modD.PosType.Value, modD.DbNumber, modD.PlcPos);
                if (result.IsSucceed)
                {
                    if (value == 120)// 放货工位空闲 可放货
                    var modTask = _db.Queryable<WcsTask>().First(s => s.Status == TaskStatusEnum.Wait && s.TaskType == TaskTypeEnum.Out && s.StartRoadway == modDevice.StationNum);
                    if (modTask == null)
                    {
                        if (int.Parse(outStationNum) > 0)
                        break;
                    }
                    var modTaskMonitor = new WcsTaskMonitor()
                    {
                        TaskNo = modTask.TaskNo,
                        StartLocat = modTask.StartLocate,
                        EndLocat = modTask.EndLocate,
                        PalletNo = modTask.PalletNo,
                    };
                    // 根据跺机号确认放货工位
                    string outStationNum = "0";
                    string endRow = "", endColumn = "", endStorey = "";
                    switch (modDevice.StationNum)
                    {
                        case "R01":
                            outStationNum = "11";
                            endRow = "1";
                            endColumn = "100";
                            endStorey = "1";
                            break;
                        case "R02":
                            outStationNum = "7";
                            endRow = "1";
                            endColumn = "100";
                            endStorey = "1";
                            break;
                        default: break;
                    }
                    var modD = modDevice.listDevice.FirstOrDefault();
                    if (modD == null)
                    {
                        Log.Error($"IP{modDevice.PlcId}.设备id:{modDevice.Id}缺少工位级别设备信息");
                        break;
                    }
                    var (result, value) = plcConn.GetPlcDBValue(modD.PosType, modD.DbNumber, modD.PlcPos);
                    if (result.IsSucceed)
                    {
                        if (value == 120)// 放货工位空闲 可放货
                        {
                            var row = int.Parse(modTaskMonitor.StartLocat.Substring(0, 2)).ToString();
                            var column = int.Parse(modTaskMonitor.StartLocat.Substring(2, 2)).ToString();
                            var layer = int.Parse(modTaskMonitor.StartLocat.Substring(4, 2)).ToString();
                            var deep = int.Parse(modTaskMonitor.StartLocat.Substring(6, 2)).ToString();
                            if (int.Parse(row) > 2) //大于4
                            if (int.Parse(outStationNum) > 0)
                            {
                                row = (int.Parse(row) - 2).ToString();
                            }
                            else
                            {
                                // 起始储位地址为空,跳过 写入任务明细表
                                modTaskMonitor.StartLocat = "";
                                modTaskMonitor.InteractiveMsg = "起始储位为空!";
                                _db.Insertable(modTaskMonitor).ExecuteCommand();
                                // 通知任务界面任务已存在更新 请更新界面
                                //if (TaskAction.refresh)
                                //{
                                //    wSChat.AlarmInformation("1");
                                //}
                                break;
                            }
                            //给PLC写入任务数据
                            var listResult = new List<Result>();
                            //任务号
                            var modPosTask = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo");
                            listResult.Add(plcConn.SetPlcDBValue(modPosTask.PosType.Value, modDevice.DbNumber, modPosTask.PlcPos, modTaskMonitor.TaskNo));
                            //托盘号
                            var modPosPalletNo = modDevice.listStation.FirstOrDefault(s => s.Text == "PalletNo");
                            listResult.Add(plcConn.SetPlcDBValue(modPosPalletNo.PosType.Value, modDevice.DbNumber, modPosPalletNo.PlcPos, modTaskMonitor.PalletNo));
                            //起始排
                            var modPosRow = modDevice.listStation.FirstOrDefault(s => s.Text == "StartRow");
                            listResult.Add(plcConn.SetPlcDBValue(modPosRow.PosType.Value, modDevice.DbNumber, modPosRow.PlcPos, row));
                            // 起始列
                            var modPosColumn = modDevice.listStation.FirstOrDefault(s => s.Text == "StartColumn");
                            listResult.Add(plcConn.SetPlcDBValue(modPosColumn.PosType.Value, modDevice.DbNumber, modPosColumn.PlcPos, column));
                            // 起始层
                            var modPosStorey = modDevice.listStation.FirstOrDefault(s => s.Text == "StartLayer");
                            listResult.Add(plcConn.SetPlcDBValue(modPosStorey.PosType.Value, modDevice.DbNumber, modPosStorey.PlcPos, layer));
                            // 目标放货工位
                            var modPosEndRow = modDevice.listStation.FirstOrDefault(s => s.Text == "EndRow");
                            listResult.Add(plcConn.SetPlcDBValue(modPosEndRow.PosType.Value, modDevice.DbNumber, modPosEndRow.PlcPos, endRow));
                            var modPosEndColumn = modDevice.listStation.FirstOrDefault(s => s.Text == "EndColumn");
                            listResult.Add(plcConn.SetPlcDBValue(modPosEndColumn.PosType.Value, modDevice.DbNumber, modPosEndColumn.PlcPos, endColumn));
                            var modPosEndStorey = modDevice.listStation.FirstOrDefault(s => s.Text == "EndLayer");
                            listResult.Add(plcConn.SetPlcDBValue(modPosEndStorey.PosType.Value, modDevice.DbNumber, modPosEndStorey.PlcPos, endColumn));
                            //全部写入成功
                            if (listResult.All(s => s.IsSucceed))
                            {
                                // 写入跺机任务下发完成
                                plcConn.SetPlcDBValue(modDevice.PosType.Value, modDevice.DbNumber, modDevice.WcsPos, "10");
                                // 将出库任务待执行改为正在执行
                                _db.Updateable<WcsTask>()
                                    .SetColumns(s => s.FinishDate == DateTime.Now)
                                    .SetColumns(s => s.Status == TaskStatusEnum.Doing)
                                    .SetColumns(s => s.Levels == 2)
                                    .Where(s => s.Id == modTask.Id)
                                    .ExecuteCommand();
                                var modInsertTaskMonitor = new WcsTaskMonitor()
                                var row = int.Parse(modTaskMonitor.StartLocat.Substring(0, 2)).ToString();
                                var column = int.Parse(modTaskMonitor.StartLocat.Substring(2, 2)).ToString();
                                var layer = int.Parse(modTaskMonitor.StartLocat.Substring(4, 2)).ToString();
                                var deep = int.Parse(modTaskMonitor.StartLocat.Substring(6, 2)).ToString();
                                if (int.Parse(row) > 2) //大于4
                                {
                                    TaskNo = modTask.TaskNo,
                                    PlcId = modDevice.Id,
                                    PlcName = modDevice.Text,
                                    InteractiveMsg = $"写入指令:{modTask.StartLocate}储位====》{outStationNum}工位",
                                    PalletNo = modTask.PalletNo,
                                    Status = TaskStatusEnum.Complete,
                                    StartLocat = modTask.StartLocate,
                                    EndLocat = outStationNum,
                                };
                                _db.Insertable(modInsertTaskMonitor).ExecuteCommand();
                                // 通知任务界面任务已存在更新 请更新界面
                                //if (TaskAction.refresh)
                                //{
                                //    wSChat.AlarmInformation("1");
                                //}
                                //修改led屏信息
                                //LedDisplay(modDevice.LedIP, "工位:" + modTask.EndLocate, "出库中 " + $"储位地址:{modTask.StartLocate}", "托盘号:" + modTask.PalletNo);
                                    row = (int.Parse(row) - 2).ToString();
                                }
                                else
                                {
                                    // 起始储位地址为空,跳过 写入任务明细表
                                    modTaskMonitor.StartLocat = "";
                                    modTaskMonitor.InteractiveMsg = "起始储位为空!";
                                    _db.Insertable(modTaskMonitor).ExecuteCommand();
                                    //下发任务日志
                                    _taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt<WcsTaskMonitorOutput>());
                                    break;
                                }
                                //给PLC写入任务数据
                                var listResult = new List<Result>();
                                //任务号
                                var modPosTask = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo");
                                listResult.Add(plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, modTaskMonitor.TaskNo));
                                //托盘号
                                var modPosPalletNo = modDevice.listStation.FirstOrDefault(s => s.Text == "PalletNo");
                                listResult.Add(plcConn.SetPlcDBValue(modPosPalletNo.PosType, modDevice.DbNumber, modPosPalletNo.PlcPos, modTaskMonitor.PalletNo));
                                //起始排
                                var modPosRow = modDevice.listStation.FirstOrDefault(s => s.Text == "StartRow");
                                listResult.Add(plcConn.SetPlcDBValue(modPosRow.PosType, modDevice.DbNumber, modPosRow.PlcPos, row));
                                // 起始列
                                var modPosColumn = modDevice.listStation.FirstOrDefault(s => s.Text == "StartColumn");
                                listResult.Add(plcConn.SetPlcDBValue(modPosColumn.PosType, modDevice.DbNumber, modPosColumn.PlcPos, column));
                                // 起始层
                                var modPosStorey = modDevice.listStation.FirstOrDefault(s => s.Text == "StartLayer");
                                listResult.Add(plcConn.SetPlcDBValue(modPosStorey.PosType, modDevice.DbNumber, modPosStorey.PlcPos, layer));
                                // 目标放货工位
                                var modPosEndRow = modDevice.listStation.FirstOrDefault(s => s.Text == "EndRow");
                                listResult.Add(plcConn.SetPlcDBValue(modPosEndRow.PosType, modDevice.DbNumber, modPosEndRow.PlcPos, endRow));
                                var modPosEndColumn = modDevice.listStation.FirstOrDefault(s => s.Text == "EndColumn");
                                listResult.Add(plcConn.SetPlcDBValue(modPosEndColumn.PosType, modDevice.DbNumber, modPosEndColumn.PlcPos, endColumn));
                                var modPosEndStorey = modDevice.listStation.FirstOrDefault(s => s.Text == "EndLayer");
                                listResult.Add(plcConn.SetPlcDBValue(modPosEndStorey.PosType, modDevice.DbNumber, modPosEndStorey.PlcPos, endColumn));
                                //全部写入成功
                                if (listResult.All(s => s.IsSucceed))
                                {
                                    // 写入跺机任务下发完成
                                    plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "10");
                                    // 将出库任务待执行改为正在执行
                                    _db.Updateable<WcsTask>()
                                        .SetColumns(s => s.FinishDate == DateTime.Now)
                                        .SetColumns(s => s.Status == TaskStatusEnum.Doing)
                                        .SetColumns(s => s.Levels == 2)
                                        .Where(s => s.Id == modTask.Id)
                                        .ExecuteCommand();
                                    var modInsertTaskMonitor = new WcsTaskMonitor()
                                    {
                                        TaskNo = modTask.TaskNo,
                                        PlcId = modDevice.Id,
                                        PlcName = modDevice.Text,
                                        InteractiveMsg = $"写入指令:{modTask.StartLocate}储位====》{outStationNum}工位",
                                        PalletNo = modTask.PalletNo,
                                        Status = TaskStatusEnum.Complete,
                                        StartLocat = modTask.StartLocate,
                                        EndLocat = outStationNum,
                                    };
                                    _db.Insertable(modInsertTaskMonitor).ExecuteCommand();
                                    //下发任务日志
                                    _taskLogHubContext.Clients.All.PublicTaskMonitor(modInsertTaskMonitor.Adapt<WcsTaskMonitorOutput>());
                                    //修改led屏信息
                                    //LedDisplay(modDevice.LedIP, "工位:" + modTask.EndLocate, "出库中 " + $"储位地址:{modTask.StartLocate}", "托盘号:" + modTask.PalletNo);
                                }
                            }
                        }
                    }
                    else
                    {
                        Log.Error(string.Join(',', result.ErrList));
                    }
                }
                else
                break;
            case "20":
                {
                    Log.Error(string.Join(',', result.ErrList));
                    var modPosPlcTask = modDevice.listStation.FirstOrDefault(s => s.Text == "PlcTaskNo");
                    var modPosTask = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo");
                    var (result, TaskNo) = plcConn.GetPlcDBValue(modPosPlcTask.PosType, modDevice.DbNumber, modPosPlcTask.PlcPos);
                    if (!result.IsSucceed)
                        break;
                    string taskNo = Convert.ToString(TaskNo);
                    var modTask = _db.Queryable<WcsTask>().First(s => s.TaskNo == taskNo && s.Status == TaskStatusEnum.Doing);
                    if (modTask == null)
                    {
                        Log.Error("【跺机】当前托盘号不存在对应的任务");
                        break;
                    }
                    if (modTask.TaskType.Value == TaskTypeEnum.In)
                    {
                        //入库任务
                        var res = plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, taskNo);
                        if (!res.IsSucceed)
                            break;
                        // 根据跺机号确认取货工位
                        string outStationNum = "0";
                        switch (modDevice.StationNum)
                        {
                            case "R01":
                                outStationNum = "10";
                                break;
                            case "R02":
                                outStationNum = "6";
                                break;
                            default: break;
                        }
                        var modDevice2 = modDevice.listDevice.Where(s => s.StationNum == outStationNum).FirstOrDefault();
                        var modStation = _db.Queryable<WcsPosition>().First(s => s.DeviceId == modDevice2.Id && s.Text == "TaskNo");
                        // 向取货工位写入任务号
                        res = plcConn.SetPlcDBValue(modStation.PosType, modDevice2.DbNumber, modStation.PlcPos, taskNo);
                        if (!res.IsSucceed)
                            break;
                        // 向取货工位写入流程控制字
                        res = plcConn.SetPlcDBValue(modDevice2.PosType, modDevice2.DbNumber, modDevice2.WcsPos, "100");
                        if (!res.IsSucceed)
                            break;
                        var modTaskMonitor = new WcsTaskMonitor()
                        {
                            TaskNo = modTask.TaskNo,
                            PlcId = modDevice2.PlcId,
                            PlcName = modDevice2.Text,
                            InteractiveMsg = "跺机取货完成",
                            StartLocat = outStationNum,
                            EndLocat = modTask.EndLocate,
                            PalletNo = modTask.PalletNo,
                            Status = TaskStatusEnum.Complete
                        };
                        _db.Insertable(modTaskMonitor).ExecuteCommand();
                        //下发任务日志
                        _taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt<WcsTaskMonitorOutput>());
                    }
                    else if (modTask.TaskType.Value == TaskTypeEnum.Out)
                    {
                        //入库任务
                        var res = plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, taskNo);
                        if (!res.IsSucceed)
                            break;
                        res = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "20");
                        if (!res.IsSucceed)
                            break;
                        // 根据跺机号确认取货工位
                        string outStationNum = "0";
                        switch (modDevice.StationNum)
                        {
                            case "R01":
                                outStationNum = "11";
                                break;
                            case "R02":
                                outStationNum = "7";
                                break;
                            default: break;
                        }
                        var modStation = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo");
                        var modTaskMonitor = new WcsTaskMonitor()
                        {
                            TaskNo = modTask.TaskNo,
                            PlcId = modDevice.PlcId,
                            PlcName = modDevice.Text,
                            InteractiveMsg = "跺机取货完成",
                            StartLocat = outStationNum,
                            EndLocat = modTask.EndLocate,
                            PalletNo = modTask.PalletNo,
                            Status = TaskStatusEnum.Complete
                        };
                        _db.Insertable(modTaskMonitor).ExecuteCommand();
                        //下发任务日志
                        _taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt<WcsTaskMonitorOutput>());
                    }
                }
                break;
            case "30":
                {
                    //操作完成(放货完成)
                    var modPosPlcTask = modDevice.listStation.FirstOrDefault(s => s.Text == "PlcTaskNo");
                    var (result, TaskNo) = plcConn.GetPlcDBValue(modPosPlcTask.PosType, modDevice.DbNumber, modPosPlcTask.PlcPos);
                    if (!result.IsSucceed)
                        break;
                    string taskNo = Convert.ToString(TaskNo);
                    var modTask = _db.Queryable<WcsTask>().First(s => s.TaskNo == taskNo && s.Status == TaskStatusEnum.Doing);
                    if (modTask == null)
                    {
                        Log.Error("【跺机】当前托盘号不存在对应的任务");
                        break;
                    }
                    switch (modTask.TaskType)
                    {
                        case TaskTypeEnum.In:
                        case TaskTypeEnum.PLC:
                            {
                                //入库任务
                                var modStation = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo");
                                // 写入plc任务号
                                var res = plcConn.SetPlcDBValue(modStation.PosType, modDevice.DbNumber, modStation.PlcPos, taskNo);
                                if (!res.IsSucceed)
                                    break;
                                res = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "30");
                                if (!res.IsSucceed)
                                    break;
                                //修改任务状态
                                modTask.Status = TaskStatusEnum.Complete;
                                _db.Updateable<WcsTask>()
                                        .SetColumns(s => s.Status == TaskStatusEnum.Complete)
                                        .Where(s => s.Id == modTask.Id)
                                        .ExecuteCommand();
                                //反馈给WMS
                                var modTaskRequest = modTask.Adapt<TaskRequest>();
                                HttpService httpService = new HttpService();
                                var modResponseTask = httpService.RequestTask(modTaskRequest).Result;
                                if (modResponseTask.StatusCode == "0")
                                {
                                    //请求成功
                                    modTask.IsSuccess = TaskSuccessEnum.Success;
                                    _db.Updateable(modTask).UpdateColumns(s => s.IsSuccess).ExecuteCommand();
                                    //todo:修改储位信息 任务类型 执行状态 起始位置 目标位置
                                    //
                                    //记录任务明细
                                    var modTaskMonitor = new WcsTaskMonitor()
                                    {
                                        TaskNo = modTask.TaskNo,
                                        PlcId = modDevice.PlcId,
                                        PlcName = modDevice.Text,
                                        InteractiveMsg = "任务完成,返回给WMS任务完成",
                                        StartLocat = modTask.StartLocate,
                                        EndLocat = modTask.EndLocate,
                                        PalletNo = modTask.PalletNo,
                                        Status = TaskStatusEnum.Complete
                                    };
                                    _db.Insertable(modTaskMonitor).ExecuteCommand();
                                    //下发任务日志
                                    _taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt<WcsTaskMonitorOutput>());
                                }
                                else
                                {
                                    //请求失败
                                    modTask.IsSuccess = TaskSuccessEnum.Fail;
                                    modTask.Information = modResponseTask.Message;
                                    _db.Updateable(modTask).UpdateColumns(s => new { s.IsSuccess, s.Information }).ExecuteCommand();
                                }
                                //todo:垛机入库不空跑
                                //todo:LED
                            }
                            break;
                        case TaskTypeEnum.Out://出库
                            {
                                // 从出库任务获取巷道号
                                string num = ""; // 放货工位号
                                if (modTask.StartRoadway == "R01")
                                {
                                    num = "11"; //交互工位
                                }
                                else if (modTask.StartRoadway == "R02")
                                {
                                    num = "7"; //交互工位
                                }
                                var modDevice2 = modDevice.listDevice.FirstOrDefault(s => s.StationNum == num);
                                if (modDevice2 == null)
                                {
                                    Log.Error($"【跺机】找不到工位{num}设备信息");
                                    break;
                                }
                                // 根据目标口获取目标工位
                                string outCode = modTask.EndLocate.IsNullOrEmpty() ? "-1" : modTask.EndLocate;
                                var listStation = _db.Queryable<WcsPosition>().Where(s => s.DeviceId == modDevice2.Id).ToList();
                                //给PLC写入任务数据
                                var listResult = new List<Result>();
                                //任务号
                                var modPosTask = listStation.FirstOrDefault(s => s.Text == "TaskNo");
                                listResult.Add(plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, modTask.TaskNo));
                                //托盘号
                                var modPosPalletNo = listStation.FirstOrDefault(s => s.Text == "PalletNo");
                                listResult.Add(plcConn.SetPlcDBValue(modPosPalletNo.PosType, modDevice.DbNumber, modPosPalletNo.PlcPos, modTask.PalletNo));
                                //起始工位
                                var modPosLocatNo = listStation.FirstOrDefault(s => s.Text == "StartLocatNo");
                                listResult.Add(plcConn.SetPlcDBValue(modPosLocatNo.PosType, modDevice.DbNumber, modPosLocatNo.PlcPos, num));
                                // 目标工位
                                var modPosEndLocatNo = listStation.FirstOrDefault(s => s.Text == "EndLocatNo");
                                listResult.Add(plcConn.SetPlcDBValue(modPosEndLocatNo.PosType, modDevice.DbNumber, modPosEndLocatNo.PlcPos, outCode));
                                //全部写入成功
                                if (listResult.All(s => s.IsSucceed))
                                {
                                    // 写入工位wcs控制字
                                    var res = plcConn.SetPlcDBValue(modDevice2.PosType, modDevice2.DbNumber, modDevice2.WcsPos, "120");
                                    if (!res.IsSucceed)
                                        break;
                                    //写入plc任务号
                                    var modStation = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo");
                                    res = plcConn.SetPlcDBValue(modStation.PosType, modDevice.DbNumber, modStation.PlcPos, modTask.TaskNo);
                                    if (!res.IsSucceed)
                                        break;
                                    //写入跺机wcs控制字流程30 返回垛机执行完成
                                    res = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "30");
                                    if (!res.IsSucceed)
                                        break;
                                    //记录任务明细
                                    var modTaskMonitor = new WcsTaskMonitor()
                                    {
                                        TaskNo = modTask.TaskNo,
                                        PlcId = modDevice2.PlcId,
                                        PlcName = modDevice2.Text,
                                        InteractiveMsg = $"写入指令:收到跺机放货完成;放货{num}工位===》{outCode}出库口",
                                        PalletNo = modTask.PalletNo,
                                        Status = TaskStatusEnum.Complete,
                                        StartLocat = num, //起始位置
                                        EndLocat = outCode, //目标工位
                                    };
                                    _db.Insertable(modTaskMonitor).ExecuteCommand();
                                    //下发任务日志
                                    _taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt<WcsTaskMonitorOutput>());
                                    //todo:垛机出库不空跑
                                }
                            }
                            break;
                        case TaskTypeEnum.Move:
                            {
                                //移库任务
                                var modStation = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo");
                                // 写入plc任务号
                                var res = plcConn.SetPlcDBValue(modStation.PosType, modDevice.DbNumber, modStation.PlcPos, taskNo);
                                if (!res.IsSucceed)
                                    break;
                                //写入plc控制字
                                res = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "30");
                                if (!res.IsSucceed)
                                    break;
                                modTask.Status = TaskStatusEnum.Complete;
                                _db.Updateable(modTask).UpdateColumns(s => s.Status).ExecuteCommand();
                                var modTaskRequest = modTask.Adapt<TaskRequest>();
                                HttpService httpService = new HttpService();
                                var modResponseTask = httpService.RequestTask(modTaskRequest).Result;
                                if (modResponseTask.StatusCode == "0")
                                {
                                    //请求成功
                                    modTask.IsSuccess = TaskSuccessEnum.Success;
                                    _db.Updateable(modTask).UpdateColumns(s => s.IsSuccess).ExecuteCommand();
                                    //todo:修改储位信息 任务类型 执行状态 起始位置 目标位置
                                    //
                                    //记录任务明细
                                    var modTaskMonitor = new WcsTaskMonitor()
                                    {
                                        TaskNo = modTask.TaskNo,
                                        PlcId = modDevice.PlcId,
                                        PlcName = modDevice.Text,
                                        InteractiveMsg = "任务完成,返回给WMS任务完成",
                                        StartLocat = modTask.StartLocate,
                                        EndLocat = modTask.EndLocate,
                                        PalletNo = modTask.PalletNo,
                                        Status = TaskStatusEnum.Complete
                                    };
                                    _db.Insertable(modTaskMonitor).ExecuteCommand();
                                    //下发任务日志
                                    _taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt<WcsTaskMonitorOutput>());
                                }
                                else
                                {
                                    //请求失败
                                    modTask.IsSuccess = TaskSuccessEnum.Fail;
                                    modTask.Information = modResponseTask.Message;
                                    _db.Updateable(modTask).UpdateColumns(s => new { s.IsSuccess, s.Information }).ExecuteCommand();
                                }
                                //todo:LED屏
                            }
                            break;
                        default:
                            break;
                    }
                }
                break;
            case "100":
                {
                    //空取货异常
                    var modPosPlcTask = modDevice.listStation.FirstOrDefault(s => s.Text == "PlcTaskNo");
                    var modPosTask = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo");
                    var (result, TaskNo) = plcConn.GetPlcDBValue(modPosPlcTask.PosType, modDevice.DbNumber, modPosPlcTask.PlcPos);
                    if (!result.IsSucceed)
                        break;
                    string taskNo = Convert.ToString(TaskNo);
                    var modTask = _db.Queryable<WcsTask>().First(s => s.TaskNo == taskNo && s.Status == TaskStatusEnum.Doing);
                    if (modTask == null)
                    {
                        Log.Error($"【跺机】当前任务号不存在对应的任务,任务号:{modTask.TaskNo}");
                        break;
                    }
                    var res = plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, taskNo);
                    if (!res.IsSucceed)
                        break;
                    res = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "100");
                    if (!res.IsSucceed)
                        break;
                    modTask.Status = TaskStatusEnum.Exception;
                    _db.Updateable(modTask).UpdateColumns(s => s.Status).ExecuteCommand();
                    Log.Information($"【跺机】wcs任务变更空取异常,任务号:{modTask.TaskNo}");
                    var modTaskRequest = modTask.Adapt<TaskRequest>();
                    HttpService httpService = new HttpService();
                    var modResponseTask = httpService.RequestEmptyException(modTaskRequest).Result;
                    if (modResponseTask.StatusCode == "0")
                    {
                        //请求成功
                        modTask.IsSuccess = TaskSuccessEnum.Success;
                        _db.Updateable(modTask).UpdateColumns(s => s.IsSuccess).ExecuteCommand();
                        //下发任务日志
                        _taskLogHubContext.Clients.All.PublicTask(modTask.Adapt<WcsTaskOutput>());
                    }
                    else
                    {
                        //请求失败
                        modTask.IsSuccess = TaskSuccessEnum.Fail;
                        modTask.Information = modResponseTask.Message;
                        _db.Updateable(modTask).UpdateColumns(s => new { s.IsSuccess, s.Information }).ExecuteCommand();
                    }
                    //todo:LED屏
                }
                break;
            case "101":
                {
                    //满放货异常
                    var modPosPlcTask = modDevice.listStation.FirstOrDefault(s => s.Text == "PlcTaskNo");
                    var modPosTask = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo");
                    var modPosPalletNo = modDevice.listStation.FirstOrDefault(s => s.Text == "PalletNo");
                    var (result, TaskNo) = plcConn.GetPlcDBValue(modPosPlcTask.PosType, modDevice.DbNumber, modPosPlcTask.PlcPos);
                    if (!result.IsSucceed)
                        break;
                    string taskNo = Convert.ToString(TaskNo);
                    var modTask = _db.Queryable<WcsTask>().First(s => s.TaskNo == taskNo && s.Status == TaskStatusEnum.Doing);
                    if (modTask == null)
                    {
                        Log.Error($"【跺机】当前任务号不存在对应的任务,任务号:{modTask.TaskNo}");
                        break;
                    }
                    modTask.Status = TaskStatusEnum.Exception;
                    _db.Updateable(modTask).UpdateColumns(s => s.Status).ExecuteCommand();
                    Log.Information($"【跺机】wcs任务变更满取异常,任务号:{modTask.TaskNo}");
                    var modTaskRequest = modTask.Adapt<TaskRequest>();
                    HttpService httpService = new HttpService();
                    var modResponseTask = httpService.RequestEmptyException(modTaskRequest).Result;
                    if (modResponseTask.StatusCode == "0")
                    {
                        //请求成功
                        modTask.IsSuccess = TaskSuccessEnum.Success;
                        _db.Updateable(modTask).UpdateColumns(s => s.IsSuccess).ExecuteCommand();
                        var modInsertTask = modResponseTask.TaskList;
                        modInsertTask.TaskType = TaskTypeEnum.In;
                        modInsertTask.Origin = "WMS";
                        modInsertTask.StartLocate = modTask.StartLocate;
                        modInsertTask.Levels = 1;
                        _db.Insertable(modInsertTask);
                        //下发任务日志
                        _taskLogHubContext.Clients.All.PublicTask(modInsertTask.Adapt<WcsTaskOutput>());
                    }
                    else
                    {
                        //请求失败
                        modTask.IsSuccess = TaskSuccessEnum.Fail;
                        modTask.Information = modResponseTask.Message;
                        _db.Updateable(modTask).UpdateColumns(s => new { s.IsSuccess, s.Information }).ExecuteCommand();
                    }
                    //todo:LED屏
                }
                break;
            default:
@@ -220,7 +615,7 @@
        Dictionary<string, PLCDataTypeEnum> listaddress = new Dictionary<string, PLCDataTypeEnum>();
        foreach (var modStation in modDevice.listStation)
        {
            listaddress.Add(modStation.PlcPos, modStation.PosType.Value);
            listaddress.Add(modStation.PlcPos, modStation.PosType);
        }
        var result = modDevice.PLCUtil.GetPlcBatchDBValue(listaddress);
        if (result.Value.Count > 0)