hwh
2024-08-27 41ca2b65f055b9c7b8f3ce68418423bac15c8e46
plc基础信息优化;堆垛机出库逻辑
7个文件已修改
3个文件已删除
5 文件已重命名
5个文件已添加
1759 ■■■■■ 已修改文件
Admin.NET/WCS.Application/Entity/WcsDevice.cs 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Entity/WcsPosition.cs 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Model/TaskRequest.cs 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/PLC/PLCService.cs 500 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/PLC/PLCTaskAction.cs 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Service/WcsDevice/Dto/WcsDeviceDto.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Service/WcsDevice/Dto/WcsDeviceInput.cs 330 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Service/WcsDevice/Dto/WcsDeviceOutput.cs 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Service/WcsDevice/WcsDeviceService.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Service/WcsPosition/Dto/WcsPositionDto.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Service/WcsPosition/Dto/WcsPositionInput.cs 171 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Service/WcsPosition/Dto/WcsPositionOutput.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Service/WcsPosition/WcsPositionService.cs 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Service/WcsStation/Dto/WcsStationInput.cs 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Service/WcsStation/WcsStationService.cs 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Util/HttpService.cs 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Web/src/api/wcs/wcsPosition.ts 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Web/src/api/wcs/wcsStation.ts 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Web/src/views/wcs/wcsPosition/component/editDialog.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Web/src/views/wcs/wcsPosition/index.vue 63 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Entity/WcsDevice.cs
@@ -13,42 +13,48 @@
    [Required]
    [SugarColumn(ColumnName = "PlcId", ColumnDescription = "PlcId")]
    public long PlcId { get; set; }
    /// <summary>
    /// 设备级别
    /// </summary>
    [Required]
    [SugarColumn(ColumnName = "Level", ColumnDescription = "设备级别")]
    public DeviceLevelEnum? Level { get; set; }
    public DeviceLevelEnum Level { get; set; }
    /// <summary>
    /// DB区域
    /// </summary>
    [Required]
    [SugarColumn(ColumnName = "DbNumber", ColumnDescription = "DB区域", Length = 10)]
    public string? DbNumber { get; set; }
    public string DbNumber { get; set; }
    /// <summary>
    /// 工位号
    /// </summary>
    [Required]
    [SugarColumn(ColumnName = "StationNum", ColumnDescription = "工位号", Length = 4)]
    public string? StationNum { get; set; }
    public string StationNum { get; set; }
    /// <summary>
    /// PLC偏移量
    /// </summary>
    [Required]
    [SugarColumn(ColumnName = "PlcPos", ColumnDescription = "PLC偏移量", Length = 10)]
    public string? PlcPos { get; set; }
    public string PlcPos { get; set; }
    /// <summary>
    /// WCS偏移量
    /// </summary>
    [Required]
    [SugarColumn(ColumnName = "WcsPos", ColumnDescription = "WCS偏移量", Length = 10)]
    public string? WcsPos { get; set; }
    public string WcsPos { get; set; }
    /// <summary>
    /// 流程字类型
    /// </summary>
    [Required]
    [SugarColumn(ColumnName = "PosType", ColumnDescription = "流程字类型")]
    public PLCDataTypeEnum? PosType { get; set; }
    public PLCDataTypeEnum PosType { get; set; }
    
    /// <summary>
    /// 显示屏ip地址
Admin.NET/WCS.Application/Entity/WcsPosition.cs
File was renamed from Admin.NET/WCS.Application/Entity/WcsStation.cs
@@ -4,8 +4,8 @@
/// <summary>
/// 工位对应的流程字表
/// </summary>
[SugarTable("WCSPLCStation","工位对应的流程字表")]
public class WcsStation  : EntityBaseData
[SugarTable("WCSPLCPosition", "工位对应的流程字表")]
public class WcsPosition : EntityBaseData
{
    /// <summary>
    /// 设备ID
@@ -13,24 +13,27 @@
    [Required]
    [SugarColumn(ColumnName = "DeviceId", ColumnDescription = "设备ID")]
    public long DeviceId { get; set; }
    /// <summary>
    /// 工位号
    /// </summary>
    [Required]
    [SugarColumn(ColumnName = "StationNum", ColumnDescription = "工位号", Length = 4)]
    public string? StationNum { get; set; }
    public string StationNum { get; set; }
    /// <summary>
    /// 偏移量
    /// </summary>
    [Required]
    [SugarColumn(ColumnName = "PlcPos", ColumnDescription = "偏移量", Length = 32)]
    public string? PlcPos { get; set; }
    public string PlcPos { get; set; }
    /// <summary>
    /// 流程字类型
    /// </summary>
    [Required]
    [SugarColumn(ColumnName = "PosType", ColumnDescription = "流程字类型")]
    public PLCDataTypeEnum? PosType { get; set; }
    public PLCDataTypeEnum PosType { get; set; }
    
    /// <summary>
    /// 显示屏ip地址
Admin.NET/WCS.Application/Model/TaskRequest.cs
New file
@@ -0,0 +1,18 @@

namespace WCS.Application;
public class TaskRequest
{
    public string TaskNo { get; set; }                          // 任务号
    public string PalletNo { get; set; }                        // 托盘号
    public string TaskType { get; set; }                        // 任务类型
    public TaskStatusEnum TaskStatus { get; set; }                      // 任务状态 0 等待执行 1 正在执行 2 执行完成 3 异常结束   4 任务取消
}
public class ResponseTasks
{
    public string StatusCode { get; set; }
    public string Success { get; set; }
    public string Message { get; set; }
    public WcsTask TaskList { get; set; }
}
Admin.NET/WCS.Application/PLC/PLCService.cs
@@ -1,8 +1,6 @@
using Flurl.Util;
using Furion.DatabaseAccessor;

using Furion.Logging;
using IoTClient;
using StackExchange.Redis;
using System.Data;
namespace WCS.Application;
@@ -49,64 +47,384 @@
        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 = "起始储位为空!";
                                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
                                {
                                    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, 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.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()
                                    {
                                        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);
                                }
                            }
                        }
                    }
                    else
                    {
                        Log.Error(string.Join(',', result.ErrList));
                    }
                }
                break;
            case "20":
                {
                    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();
                        //通知任务界面任务已存在更新 请更新界面
                        //if (TaskAction.refresh)
                        //{
                        //    wSChat.AlarmInformation("1");
                        //}
                    }
                    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.Value, 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();
                        //通知任务界面任务已存在更新 请更新界面
                        //if (TaskAction.refresh)
                        //{
                        //    wSChat.AlarmInformation("1");
                        //}
                    }
                }
                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.Value, 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();
                                    // 通知任务界面任务已存在更新 请更新界面
                                    //if (TaskAction.refresh)
                                    //{
                                    //    wSChat.AlarmInformation("1");
                                    //}
                                }
                                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.Value, 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();
                                // 通知任务界面任务已存在更新 请更新界面
@@ -114,72 +432,16 @@
                                //{
                                //    wSChat.AlarmInformation("1");
                                //}
                                break;
                                //todo:垛机出库不空跑
                            }
                            //给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");
                            break;
                        case TaskTypeEnum.Move:
                                // 将出库任务待执行改为正在执行
                                _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();
                                // 通知任务界面任务已存在更新 请更新界面
                                //if (TaskAction.refresh)
                                //{
                                //    wSChat.AlarmInformation("1");
                                //}
                                //修改led屏信息
                                //LedDisplay(modDevice.LedIP, "工位:" + modTask.EndLocate, "出库中 " + $"储位地址:{modTask.StartLocate}", "托盘号:" + modTask.PalletNo);
                            }
                        }
                            break;
                        default:
                            break;
                    }
                }
                else
                {
                    Log.Error(string.Join(',', result.ErrList));
                }
                break;
            default:
@@ -220,7 +482,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)
Admin.NET/WCS.Application/PLC/PLCTaskAction.cs
@@ -1,4 +1,5 @@
using Admin.NET.Core.Service;
using Furion.Logging;
namespace WCS.Application;
public static class PLCTaskAction
@@ -7,7 +8,7 @@
    private static List<WcsPlc> listPlc;
    private static List<WcsDevice> listPlcDevice;
    private static List<WcsStation> listPlcStation;
    private static List<WcsPosition> listPlcStation;
    private static List<PLCUtil> listPlcUtil = new List<PLCUtil>();
    private static CancellationTokenSource cts;//取消线程标识
@@ -20,7 +21,7 @@
        listPlc = _db.Queryable<WcsPlc>().ToList();
        listPlcDevice = _db.Queryable<WcsDevice>().ToList();
        listPlcStation = _db.Queryable<WcsStation>().ToList();
        listPlcStation = _db.Queryable<WcsPosition>().ToList();
    }
    /// <summary>
    /// 初始化PLC连接
@@ -32,7 +33,7 @@
            cts.Cancel();
            listPlc = _db.Queryable<WcsPlc>().ToList();
            listPlcDevice = _db.Queryable<WcsDevice>().ToList();
            listPlcStation = _db.Queryable<WcsStation>().ToList();
            listPlcStation = _db.Queryable<WcsPosition>().ToList();
            //等待几秒钟,把已有线程取消掉再连接
            Thread.Sleep(5000);
            foreach (var modPlcUtil in listPlcUtil)
@@ -82,7 +83,7 @@
                        //循环读设备
                        foreach (var modDevice in listDevice.Where(s => s.Level == DeviceLevelEnum.DB))
                        {
                            var (result, value) = modPlcUtil.GetPlcDBValue(modDevice.PosType.Value, modDevice.DbNumber, modDevice.PlcPos);
                            var (result, value) = modPlcUtil.GetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.PlcPos);
                            if (result.IsSucceed)
                            {
                                //无流程跳出
@@ -108,9 +109,13 @@
                        Thread.Sleep(3000);
                    }
                    catch (OperationCanceledException)
                    {
                        Console.WriteLine("中止线程");
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex.Message, ex);
                    }
                }
            }, cts.Token);
Admin.NET/WCS.Application/Service/WcsDevice/Dto/WcsDeviceDto.cs
@@ -116,5 +116,5 @@
    public PLCUtil PLCUtil { get; set; }
    public List<WcsDevice> listDevice { get; set; }
    public List<WcsStation> listStation { get; set; }
    public List<WcsPosition> listStation { get; set; }
}
Admin.NET/WCS.Application/Service/WcsDevice/Dto/WcsDeviceInput.cs
@@ -9,168 +9,204 @@
namespace WCS.Application;
/// <summary>
/// 设备信息基础输入参数
/// </summary>
public class WcsDeviceBaseInput
{
    /// <summary>
    /// 设备信息基础输入参数
    /// PlcId
    /// </summary>
    public class WcsDeviceBaseInput
    {
        /// <summary>
        /// PlcId
        /// </summary>
        public virtual long PlcId { get; set; }
        /// <summary>
        /// 设备级别
        /// </summary>
        public virtual DeviceLevelEnum Level { get; set; }
        /// <summary>
        /// DB区域
        /// </summary>
        public virtual string? DbNumber { get; set; }
        /// <summary>
        /// 工位号
        /// </summary>
        public virtual string? StationNum { get; set; }
        /// <summary>
        /// PLC偏移量
        /// </summary>
        public virtual string? PlcPos { get; set; }
        /// <summary>
        /// WCS偏移量
        /// </summary>
        public virtual string? WcsPos { get; set; }
        /// <summary>
        /// 流程字类型
        /// </summary>
        public virtual PLCDataTypeEnum? PosType { get; set; }
        /// <summary>
        /// 显示屏ip地址
        /// </summary>
        public virtual string? LedIP { get; set; }
        /// <summary>
        /// 描述
        /// </summary>
        public virtual string? Text { get; set; }
        /// <summary>
        /// 创建时间
        /// </summary>
        public virtual DateTime? CreateTime { get; set; }
        /// <summary>
        /// 更新时间
        /// </summary>
        public virtual DateTime? UpdateTime { get; set; }
        /// <summary>
        /// 创建者Id
        /// </summary>
        public virtual long? CreateUserId { get; set; }
        /// <summary>
        /// 创建者姓名
        /// </summary>
        public virtual string? CreateUserName { get; set; }
        /// <summary>
        /// 修改者Id
        /// </summary>
        public virtual long? UpdateUserId { get; set; }
        /// <summary>
        /// 修改者姓名
        /// </summary>
        public virtual string? UpdateUserName { get; set; }
        /// <summary>
        /// 创建者部门Id
        /// </summary>
        public virtual long? CreateOrgId { get; set; }
        /// <summary>
        /// 创建者部门名称
        /// </summary>
        public virtual string? CreateOrgName { get; set; }
        /// <summary>
        /// 软删除
        /// </summary>
        public virtual bool IsDelete { get; set; }
    }
    public virtual long PlcId { get; set; }
    /// <summary>
    /// 设备信息分页查询输入参数
    /// 设备级别
    /// </summary>
    public class PageWcsDeviceInput : BasePageInput
    {
        /// <summary>
        /// 关键字查询
        /// </summary>
        public string? SearchKey { get; set; }
        /// <summary>
        /// PlcId
        /// </summary>
        public long? PlcId { get; set; }
        /// <summary>
        /// 描述
        /// </summary>
        public string? Text { get; set; }
    }
    public virtual DeviceLevelEnum Level { get; set; }
    /// <summary>
    /// 设备信息增加输入参数
    /// DB区域
    /// </summary>
    public class AddWcsDeviceInput : WcsDeviceBaseInput
    {
        /// <summary>
        /// PlcId
        /// </summary>
        [Required(ErrorMessage = "PlcId不能为空")]
        public override long PlcId { get; set; }
        /// <summary>
        /// 软删除
        /// </summary>
        [Required(ErrorMessage = "软删除不能为空")]
        public override bool IsDelete { get; set; }
    }
    public virtual string DbNumber { get; set; }
    /// <summary>
    /// 设备信息删除输入参数
    /// 工位号
    /// </summary>
    public class DeleteWcsDeviceInput : BaseIdInput
    {
    }
    public virtual string StationNum { get; set; }
    /// <summary>
    /// 设备信息更新输入参数
    /// PLC偏移量
    /// </summary>
    public class UpdateWcsDeviceInput : WcsDeviceBaseInput
    {
        /// <summary>
        /// 主键Id
        /// </summary>
        [Required(ErrorMessage = "主键Id不能为空")]
        public long Id { get; set; }
    }
    public virtual string PlcPos { get; set; }
    /// <summary>
    /// 设备信息主键查询输入参数
    /// WCS偏移量
    /// </summary>
    public class QueryByIdWcsDeviceInput : DeleteWcsDeviceInput
    {
    public virtual string WcsPos { get; set; }
    }
    /// <summary>
    /// 流程字类型
    /// </summary>
    public virtual PLCDataTypeEnum PosType { get; set; }
    /// <summary>
    /// 显示屏ip地址
    /// </summary>
    public virtual string? LedIP { get; set; }
    /// <summary>
    /// 描述
    /// </summary>
    public virtual string? Text { get; set; }
    /// <summary>
    /// 创建时间
    /// </summary>
    public virtual DateTime? CreateTime { get; set; }
    /// <summary>
    /// 更新时间
    /// </summary>
    public virtual DateTime? UpdateTime { get; set; }
    /// <summary>
    /// 创建者Id
    /// </summary>
    public virtual long? CreateUserId { get; set; }
    /// <summary>
    /// 创建者姓名
    /// </summary>
    public virtual string? CreateUserName { get; set; }
    /// <summary>
    /// 修改者Id
    /// </summary>
    public virtual long? UpdateUserId { get; set; }
    /// <summary>
    /// 修改者姓名
    /// </summary>
    public virtual string? UpdateUserName { get; set; }
    /// <summary>
    /// 创建者部门Id
    /// </summary>
    public virtual long? CreateOrgId { get; set; }
    /// <summary>
    /// 创建者部门名称
    /// </summary>
    public virtual string? CreateOrgName { get; set; }
    /// <summary>
    /// 软删除
    /// </summary>
    public virtual bool IsDelete { get; set; }
}
/// <summary>
/// 设备信息分页查询输入参数
/// </summary>
public class PageWcsDeviceInput : BasePageInput
{
    /// <summary>
    /// 关键字查询
    /// </summary>
    public string? SearchKey { get; set; }
    /// <summary>
    /// PlcId
    /// </summary>
    public long? PlcId { get; set; }
    /// <summary>
    /// 描述
    /// </summary>
    public string? Text { get; set; }
}
/// <summary>
/// 设备信息增加输入参数
/// </summary>
public class AddWcsDeviceInput : WcsDeviceBaseInput
{
    /// <summary>
    /// PlcId
    /// </summary>
    [Required(ErrorMessage = "PlcId不能为空")]
    public override long PlcId { get; set; }
    /// <summary>
    /// 设备级别
    /// </summary>
    [Required(ErrorMessage = "设备级别不能为空")]
    public override DeviceLevelEnum Level { get; set; }
    /// <summary>
    /// DB区域
    /// </summary>
    [Required(ErrorMessage = "DB区域不能为空")]
    public override string? DbNumber { get; set; }
    /// <summary>
    /// 工位号
    /// </summary>
    [Required(ErrorMessage = "工位号不能为空")]
    public override string? StationNum { get; set; }
    /// <summary>
    /// PLC偏移量
    /// </summary>
    [Required(ErrorMessage = "PLC偏移量不能为空")]
    public override string? PlcPos { get; set; }
    /// <summary>
    /// WCS偏移量
    /// </summary>
    [Required(ErrorMessage = "WCS偏移量不能为空")]
    public override string? WcsPos { get; set; }
    /// <summary>
    /// 流程字类型
    /// </summary>
    [Required(ErrorMessage = "流程字类型不能为空")]
    public override PLCDataTypeEnum PosType { get; set; }
    /// <summary>
    /// 软删除
    /// </summary>
    [Required(ErrorMessage = "软删除不能为空")]
    public override bool IsDelete { get; set; }
}
/// <summary>
/// 设备信息删除输入参数
/// </summary>
public class DeleteWcsDeviceInput : BaseIdInput
{
}
/// <summary>
/// 设备信息更新输入参数
/// </summary>
public class UpdateWcsDeviceInput : WcsDeviceBaseInput
{
    /// <summary>
    /// 主键Id
    /// </summary>
    [Required(ErrorMessage = "主键Id不能为空")]
    public long Id { get; set; }
}
/// <summary>
/// 设备信息主键查询输入参数
/// </summary>
public class QueryByIdWcsDeviceInput : DeleteWcsDeviceInput
{
}
Admin.NET/WCS.Application/Service/WcsDevice/Dto/WcsDeviceOutput.cs
@@ -10,102 +10,102 @@
    /// 主键Id
    /// </summary>
    public long Id { get; set; }
    /// <summary>
    /// PlcId
    /// </summary>
    public long PlcId { get; set; }
    public long PlcId { get; set; }
    /// <summary>
    /// PlcId 描述
    /// </summary>
    public string PlcIdIP { get; set; }
    public string PlcIdIP { get; set; }
    /// <summary>
    /// 设备级别
    /// </summary>
    public DeviceLevelEnum Level { get; set; }
    /// <summary>
    /// DB区域
    /// </summary>
    public string? DbNumber { get; set; }
    /// <summary>
    /// 工位号
    /// </summary>
    public string? StationNum { get; set; }
    /// <summary>
    /// PLC偏移量
    /// </summary>
    public string? PlcPos { get; set; }
    /// <summary>
    /// WCS偏移量
    /// </summary>
    public string? WcsPos { get; set; }
    /// <summary>
    /// 流程字类型
    /// </summary>
    public PLCDataTypeEnum? PosType { get; set; }
    public PLCDataTypeEnum PosType { get; set; }
    /// <summary>
    /// 显示屏ip地址
    /// </summary>
    public string? LedIP { get; set; }
    /// <summary>
    /// 描述
    /// </summary>
    public string? Text { get; set; }
    /// <summary>
    /// 创建时间
    /// </summary>
    public DateTime? CreateTime { get; set; }
    /// <summary>
    /// 更新时间
    /// </summary>
    public DateTime? UpdateTime { get; set; }
    /// <summary>
    /// 创建者Id
    /// </summary>
    public long? CreateUserId { get; set; }
    /// <summary>
    /// 创建者姓名
    /// </summary>
    public string? CreateUserName { get; set; }
    /// <summary>
    /// 修改者Id
    /// </summary>
    public long? UpdateUserId { get; set; }
    /// <summary>
    /// 修改者姓名
    /// </summary>
    public string? UpdateUserName { get; set; }
    /// <summary>
    /// 创建者部门Id
    /// </summary>
    public long? CreateOrgId { get; set; }
    /// <summary>
    /// 创建者部门名称
    /// </summary>
    public string? CreateOrgName { get; set; }
    /// <summary>
    /// 软删除
    /// </summary>
    public bool IsDelete { get; set; }
    }
}
Admin.NET/WCS.Application/Service/WcsDevice/WcsDeviceService.cs
@@ -144,7 +144,7 @@
        return await _wcsDeviceRep.Context.Queryable<WcsPlc>()
                .Select(u => new
                {
                    Label = u.IP,
                    Label = u.Text,
                    Value = u.Id
                }
                ).ToListAsync();
Admin.NET/WCS.Application/Service/WcsPosition/Dto/WcsPositionDto.cs
File was renamed from Admin.NET/WCS.Application/Service/WcsStation/Dto/WcsStationDto.cs
@@ -4,7 +4,7 @@
    /// <summary>
    /// 设备工位输出参数
    /// </summary>
    public class WcsStationDto
    public class WcsPositionDto
    {
        /// <summary>
        /// 设备ID
Admin.NET/WCS.Application/Service/WcsPosition/Dto/WcsPositionInput.cs
New file
@@ -0,0 +1,171 @@

namespace WCS.Application;
/// <summary>
/// 设备点位管理基础输入参数
/// </summary>
public class WcsPositionBaseInput
{
    /// <summary>
    /// 设备ID
    /// </summary>
    public virtual long DeviceId { get; set; }
    /// <summary>
    /// 工位号
    /// </summary>
    public virtual string StationNum { get; set; }
    /// <summary>
    /// 偏移量
    /// </summary>
    public virtual string PlcPos { get; set; }
    /// <summary>
    /// 流程字类型
    /// </summary>
    public virtual PLCDataTypeEnum PosType { get; set; }
    /// <summary>
    /// 显示屏ip地址
    /// </summary>
    public virtual string? LedIP { get; set; }
    /// <summary>
    /// 描述
    /// </summary>
    public virtual string? Text { get; set; }
    /// <summary>
    /// 创建时间
    /// </summary>
    public virtual DateTime? CreateTime { get; set; }
    /// <summary>
    /// 更新时间
    /// </summary>
    public virtual DateTime? UpdateTime { get; set; }
    /// <summary>
    /// 创建者Id
    /// </summary>
    public virtual long? CreateUserId { get; set; }
    /// <summary>
    /// 创建者姓名
    /// </summary>
    public virtual string? CreateUserName { get; set; }
    /// <summary>
    /// 修改者Id
    /// </summary>
    public virtual long? UpdateUserId { get; set; }
    /// <summary>
    /// 修改者姓名
    /// </summary>
    public virtual string? UpdateUserName { get; set; }
    /// <summary>
    /// 创建者部门Id
    /// </summary>
    public virtual long? CreateOrgId { get; set; }
    /// <summary>
    /// 创建者部门名称
    /// </summary>
    public virtual string? CreateOrgName { get; set; }
    /// <summary>
    /// 软删除
    /// </summary>
    public virtual bool IsDelete { get; set; }
}
/// <summary>
/// 设备点位管理分页查询输入参数
/// </summary>
public class PageWcsPositionInput : BasePageInput
{
    /// <summary>
    /// 关键字查询
    /// </summary>
    public string? SearchKey { get; set; }
    /// <summary>
    /// 设备ID
    /// </summary>
    public long? DeviceId { get; set; }
    /// <summary>
    /// 描述
    /// </summary>
    public string? Text { get; set; }
}
/// <summary>
/// 设备点位管理增加输入参数
/// </summary>
public class AddWcsPositionInput : WcsPositionBaseInput
{
    /// <summary>
    /// 设备ID
    /// </summary>
    [Required(ErrorMessage = "设备ID不能为空")]
    public override long DeviceId { get; set; }
    /// <summary>
    /// 工位号
    /// </summary>
    [Required(ErrorMessage = "工位号不能为空")]
    public override string StationNum { get; set; }
    /// <summary>
    /// 偏移量
    /// </summary>
    [Required(ErrorMessage = "偏移量不能为空")]
    public override string PlcPos { get; set; }
    /// <summary>
    /// 流程字类型
    /// </summary>
    [Required(ErrorMessage = "流程字类型不能为空")]
    public override PLCDataTypeEnum PosType { get; set; }
    /// <summary>
    /// 软删除
    /// </summary>
    [Required(ErrorMessage = "软删除不能为空")]
    public override bool IsDelete { get; set; }
}
/// <summary>
/// 设备点位管理删除输入参数
/// </summary>
public class DeleteWcsPositionInput : BaseIdInput
{
}
/// <summary>
/// 设备点位管理更新输入参数
/// </summary>
public class UpdateWcsPositionInput : WcsPositionBaseInput
{
    /// <summary>
    /// 主键Id
    /// </summary>
    [Required(ErrorMessage = "主键Id不能为空")]
    public long Id { get; set; }
}
/// <summary>
/// 设备点位管理主键查询输入参数
/// </summary>
public class QueryByIdWcsPositionInput : DeleteWcsPositionInput
{
}
Admin.NET/WCS.Application/Service/WcsPosition/Dto/WcsPositionOutput.cs
File was renamed from Admin.NET/WCS.Application/Service/WcsStation/Dto/WcsStationOutput.cs
@@ -4,7 +4,7 @@
/// <summary>
/// 设备工位输出参数
/// </summary>
public class WcsStationOutput
public class WcsPositionOutput
{
    /// <summary>
    /// 主键Id
Admin.NET/WCS.Application/Service/WcsPosition/WcsPositionService.cs
New file
@@ -0,0 +1,150 @@

namespace WCS.Application;
/// <summary>
/// 设备工位服务
/// </summary>
[ApiDescriptionSettings(ApplicationConst.GroupName, Order = 100)]
public class WcsPositionService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<WcsPosition> _WcsPositionRep;
    public WcsPositionService(SqlSugarRepository<WcsPosition> WcsPositionRep)
    {
        _WcsPositionRep = WcsPositionRep;
    }
    /// <summary>
    /// 分页查询设备工位
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Page")]
    [DisplayName("分页查询设备工位")]
    public async Task<SqlSugarPagedList<WcsPositionOutput>> Page(PageWcsPositionInput input)
    {
        if (input.Field.IsNullOrEmpty())
        {
            input.Field = "u.Id";
            input.Order = "desc";
        }
        input.SearchKey = input.SearchKey?.Trim();
        var query = _WcsPositionRep.AsQueryable()
            .WhereIF(!string.IsNullOrEmpty(input.SearchKey), u =>
                u.Text.Contains(input.SearchKey)
            )
            .WhereIF(input.DeviceId > 0, u => u.DeviceId == input.DeviceId)
            .WhereIF(!string.IsNullOrWhiteSpace(input.Text), u => u.Text.Contains(input.Text.Trim()))
            //处理外键和TreeSelector相关字段的连接
            .LeftJoin<WcsDevice>((u, deviceid) => u.DeviceId == deviceid.Id)
            .Select((u, deviceid) => new WcsPositionOutput
            {
                Id = u.Id,
                DeviceId = u.DeviceId,
                DeviceIdText = deviceid.Text,
                StationNum = u.StationNum,
                PlcPos = u.PlcPos,
                PosType = u.PosType,
                LedIP = u.LedIP,
                Text = u.Text,
                CreateUserId = u.CreateUserId,
                CreateUserName = u.CreateUserName,
                CreateTime = u.CreateTime,
                UpdateUserId = u.UpdateUserId,
                UpdateUserName = u.UpdateUserName,
                UpdateTime = u.UpdateTime,
            });
        return await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
    }
    /// <summary>
    /// 增加设备工位
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Add")]
    [DisplayName("增加设备工位")]
    public async Task<long> Add(AddWcsPositionInput input)
    {
        var entity = input.Adapt<WcsPosition>();
        await _WcsPositionRep.InsertAsync(entity);
        return entity.Id;
    }
    /// <summary>
    /// 删除设备工位
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Delete")]
    [DisplayName("删除设备工位")]
    public async Task Delete(DeleteWcsPositionInput input)
    {
        var entity = await _WcsPositionRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
        await _WcsPositionRep.FakeDeleteAsync(entity);   //假删除
        //await _WcsPositionRep.DeleteAsync(entity);   //真删除
    }
    /// <summary>
    /// 更新设备工位
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Update")]
    [DisplayName("更新设备工位")]
    public async Task Update(UpdateWcsPositionInput input)
    {
        var entity = input.Adapt<WcsPosition>();
        await _WcsPositionRep.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
    }
    /// <summary>
    /// 获取设备工位
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpGet]
    [ApiDescriptionSettings(Name = "Detail")]
    [DisplayName("获取设备工位")]
    public async Task<WcsPosition> Detail([FromQuery] QueryByIdWcsPositionInput input)
    {
        return await _WcsPositionRep.GetFirstAsync(u => u.Id == input.Id);
    }
    /// <summary>
    /// 获取设备工位列表
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpGet]
    [ApiDescriptionSettings(Name = "List")]
    [DisplayName("获取设备工位列表")]
    public async Task<List<WcsPositionOutput>> List([FromQuery] PageWcsPositionInput input)
    {
        return await _WcsPositionRep.AsQueryable().Select<WcsPositionOutput>().ToListAsync();
    }
    /// <summary>
    /// 获取设备ID列表
    /// </summary>
    /// <returns></returns>
    [ApiDescriptionSettings(Name = "WcsDeviceDeviceIdDropdown"), HttpGet]
    [DisplayName("获取设备ID列表")]
    public async Task<dynamic> WcsDeviceDeviceIdDropdown()
    {
        return await _WcsPositionRep.Context.Queryable<WcsDevice>()
                .Select(u => new
                {
                    Label = u.Text,
                    Value = u.Id
                }
                ).ToListAsync();
    }
}
Admin.NET/WCS.Application/Service/WcsStation/Dto/WcsStationInput.cs
File was deleted
Admin.NET/WCS.Application/Service/WcsStation/WcsStationService.cs
File was deleted
Admin.NET/WCS.Application/Util/HttpService.cs
New file
@@ -0,0 +1,26 @@
using Furion.Logging;
using Furion.RemoteRequest.Extensions;
using System.Text;
namespace WCS.Application;
public class HttpService
{
    private dynamic Urls;
    public HttpService()
    {
        var _sysConfigService = App.GetService<SysConfigService>();//todo 这里需要测试下生命周期问题
        Urls = _sysConfigService.GetSystemInfo().Result;
    }
    /// <summary>
    /// 调用WMS接口反馈任务接口
    /// </summary>
    /// <param name="model">任务完成状态</param>
    /// <returns></returns>
    public async Task<ResponseTasks> RequestTask(TaskRequest model)
    {
        string url = Urls.WMSAddress + ":" + Urls.WMSPort;
        var result = await (url + "/api/DownAPi/ReceiveWcsSignal").SetBody(model, "application/json", Encoding.UTF8).PostAsAsync<ResponseTasks>();
        Log.Debug("调用WMS接口反馈任务接口" + result.ToJson());
        return result;
    }
}
Web/src/api/wcs/wcsPosition.ts
New file
@@ -0,0 +1,56 @@
import request from '/@/utils/request';
enum Api {
  AddWcsPosition = '/api/wcsPosition/add',
  DeleteWcsPosition = '/api/wcsPosition/delete',
  UpdateWcsPosition = '/api/wcsPosition/update',
  PageWcsPosition = '/api/wcsPosition/page',
  DetailWcsPosition = '/api/wcsPosition/detail',
  GetWcsDeviceDeviceIdDropdown = '/api/wcsPosition/WcsDeviceDeviceIdDropdown',
}
// 增加设备工位
export const addWcsPosition = (params?: any) =>
    request({
        url: Api.AddWcsPosition,
        method: 'post',
        data: params,
    });
// 删除设备工位
export const deleteWcsPosition = (params?: any) =>
    request({
            url: Api.DeleteWcsPosition,
            method: 'post',
            data: params,
        });
// 编辑设备工位
export const updateWcsPosition = (params?: any) =>
    request({
            url: Api.UpdateWcsPosition,
            method: 'post',
            data: params,
        });
// 分页查询设备工位
export const pageWcsPosition = (params?: any) =>
    request({
            url: Api.PageWcsPosition,
            method: 'post',
            data: params,
        });
// 详情设备工位
export const detailWcsPosition = (id: any) =>
    request({
            url: Api.DetailWcsPosition,
            method: 'get',
            data: { id },
        });
export const getWcsDeviceDeviceIdDropdown = () =>
        request({
        url: Api.GetWcsDeviceDeviceIdDropdown,
        method: 'get'
        });
Web/src/api/wcs/wcsStation.ts
File was deleted
Web/src/views/wcs/wcsPosition/component/editDialog.vue
File was renamed from Web/src/views/wcs/wcsStation/component/editDialog.vue
@@ -1,5 +1,5 @@
<template>
    <div class="wcsStation-container">
    <div class="wcsPosition-container">
        <el-dialog v-model="isShowDialog" :width="800" draggable="" :close-on-click-modal="false">
            <template #header>
                <div style="color: #fff">
@@ -81,9 +81,14 @@
    import { ref,onMounted } from "vue";
    import { ElMessage } from "element-plus";
    import type { FormRules } from "element-plus";
    import { addWcsStation, updateWcsStation, detailWcsStation } from "/@/api/wcs/wcsStation";
    import { getWcsDeviceDeviceIdDropdown } from '/@/api/wcs/wcsStation';
    import { getDictDataItem as di, getDictDataList as dl } from '/@/utils/dict-utils';
    import { getDictLabelByVal as dv } from '/@/utils/dict-utils';
      import { formatDate } from '/@/utils/formatTime';
    import { addWcsPosition, updateWcsPosition, detailWcsPosition } from "/@/api/wcs/wcsPosition";
    import { getWcsDeviceDeviceIdDropdown } from '/@/api/wcs/wcsPosition';
    import { getAPI } from '/@/utils/axios-utils';
    import { SysEnumApi } from '/@/api-services/api';
    //父级传递来的参数
    var props = defineProps({
        title: {
@@ -98,6 +103,8 @@
    const ruleForm = ref<any>({});
    //自行添加其他规则
    const rules = ref<FormRules>({
        stationNum: [{required: true, message: '请输入工位号!', trigger: 'blur',},],
        plcPos: [{required: true, message: '请输入偏移量!', trigger: 'blur',},],
    });
    // 页面加载时
@@ -111,7 +118,7 @@
        // 改用detail获取最新数据来编辑
        let rowData = JSON.parse(JSON.stringify(row));
        if (rowData.id)
            ruleForm.value = (await detailWcsStation(rowData.id)).data.result;
            ruleForm.value = (await detailWcsPosition(rowData.id)).data.result;
        else
            ruleForm.value = rowData;
        isShowDialog.value = true;
@@ -134,9 +141,9 @@
            if (isValid) {
                let values = ruleForm.value;
                if (ruleForm.value.id == undefined || ruleForm.value.id == null || ruleForm.value.id == "" || ruleForm.value.id == 0) {
                    await addWcsStation(values);
                    await addWcsPosition(values);
                } else {
                    await updateWcsStation(values);
                    await updateWcsPosition(values);
                }
                closeDialog();
            } else {
Web/src/views/wcs/wcsPosition/index.vue
File was renamed from Web/src/views/wcs/wcsStation/index.vue
@@ -1,5 +1,5 @@
<template>
  <div class="wcsStation-container">
  <div class="wcsPosition-container">
    <el-card shadow="hover" :body-style="{ paddingBottom: '0' }">
      <el-form :model="queryParams" ref="queryForm" labelWidth="90">
        <el-row>
@@ -28,15 +28,15 @@
          <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10">
            <el-form-item>
              <el-button-group style="display: flex; align-items: center;">
                <el-button type="primary" icon="ele-Search" @click="handleQuery" v-auth="'wcsStation:page'"> 查询
                <el-button type="primary" icon="ele-Search" @click="handleQuery" v-auth="'wcsPosition:page'"> 查询
                </el-button>
                <el-button icon="ele-Refresh" @click="() => queryParams = {}"> 重置 </el-button>
                <el-button icon="ele-ZoomIn" @click="changeAdvanceQueryUI" v-if="!showAdvanceQueryUI"
                  style="margin-left:5px;"> 高级查询 </el-button>
                <el-button icon="ele-ZoomOut" @click="changeAdvanceQueryUI" v-if="showAdvanceQueryUI"
                  style="margin-left:5px;"> 隐藏 </el-button>
                <el-button type="primary" style="margin-left:5px;" icon="ele-Plus" @click="openAddWcsStation"
                  v-auth="'wcsStation:add'"> 新增 </el-button>
                <el-button type="primary" style="margin-left:5px;" icon="ele-Plus" @click="openAddWcsPosition"
                  v-auth="'wcsPosition:add'"> 新增 </el-button>
              </el-button-group>
            </el-form-item>
@@ -57,8 +57,8 @@
        </el-table-column>
        <el-table-column prop="stationNum" label="工位号" show-overflow-tooltip="" />
        <el-table-column prop="plcPos" label="偏移量" show-overflow-tooltip="" /> <el-table-column prop="posType"
          label="流程字类型" show-overflow-tooltip="">
        <el-table-column prop="plcPos" label="偏移量" show-overflow-tooltip="" />
        <el-table-column prop="posType" label="流程字类型" show-overflow-tooltip="">
          <template #default="scope">
            <el-tag :type="dv('PLCDataTypeEnum', scope.row.posType)?.tagType"> {{ dv('PLCDataTypeEnum',
              scope.row.posType)?.name}}</el-tag>
@@ -72,12 +72,12 @@
          </template>
        </el-table-column>
        <el-table-column label="操作" width="140" align="center" fixed="right" show-overflow-tooltip=""
          v-if="auth('wcsStation:update') || auth('wcsStation:delete')">
          v-if="auth('wcsPosition:update') || auth('wcsPosition:delete')">
          <template #default="scope">
            <el-button icon="ele-Edit" size="small" text="" type="primary" @click="openEditWcsStation(scope.row)"
              v-auth="'wcsStation:update'"> 编辑 </el-button>
            <el-button icon="ele-Delete" size="small" text="" type="primary" @click="delWcsStation(scope.row)"
              v-auth="'wcsStation:delete'"> 删除 </el-button>
            <el-button icon="ele-Edit" size="small" text="" type="primary" @click="openEditWcsPosition(scope.row)"
              v-auth="'wcsPosition:update'"> 编辑 </el-button>
            <el-button icon="ele-Delete" size="small" text="" type="primary" @click="delWcsPosition(scope.row)"
              v-auth="'wcsPosition:delete'"> 删除 </el-button>
          </template>
        </el-table-column>
      </el-table>
@@ -85,23 +85,26 @@
        :total="tableParams.total" :page-sizes="[10, 20, 50, 100, 200, 500]" size="small" background=""
        @size-change="handleSizeChange" @current-change="handleCurrentChange"
        layout="total, sizes, prev, pager, next, jumper" />
      <printDialog ref="printDialogRef" :title="printWcsStationTitle" @reloadTable="handleQuery" />
      <editDialog ref="editDialogRef" :title="editWcsStationTitle" @reloadTable="handleQuery" />
      <printDialog ref="printDialogRef" :title="printWcsPositionTitle" @reloadTable="handleQuery" />
      <editDialog ref="editDialogRef" :title="editWcsPositionTitle" @reloadTable="handleQuery" />
    </el-card>
  </div>
</template>
<script lang="ts" setup="" name="wcsStation">
<script lang="ts" setup="" name="wcsPosition">
import { ref } from "vue";
import { ElMessageBox, ElMessage } from "element-plus";
import { auth } from '/@/utils/authFunction';
import { getDictLabelByVal as dv } from '/@/utils/dict-utils';
import ModifyRecord from '/@/components/table/modifyRecord.vue';
import { getDictDataItem as di, getDictDataList as dl } from '/@/utils/dict-utils';
import { getDictLabelByVal as dv } from '/@/utils/dict-utils';
import { formatDate } from '/@/utils/formatTime';
import ModifyRecord from '/@/components/table/modifyRecord.vue';
import printDialog from '/@/views/system/print/component/hiprint/preview.vue'
import editDialog from '/@/views/wcs/wcsStation/component/editDialog.vue'
import { pageWcsStation, deleteWcsStation } from '/@/api/wcs/wcsStation';
import { getWcsDeviceDeviceIdDropdown } from '/@/api/wcs/wcsStation';
import editDialog from '/@/views/wcs/wcsPosition/component/editDialog.vue'
import { pageWcsPosition, deleteWcsPosition } from '/@/api/wcs/wcsPosition';
import { getWcsDeviceDeviceIdDropdown } from '/@/api/wcs/wcsPosition';
const showAdvanceQueryUI = ref(false);
const printDialogRef = ref();
@@ -115,8 +118,8 @@
  total: 0,
});
const printWcsStationTitle = ref("");
const editWcsStationTitle = ref("");
const printWcsPositionTitle = ref("");
const editWcsPositionTitle = ref("");
// 改变高级查询的控件显示状态
const changeAdvanceQueryUI = () => {
@@ -126,7 +129,7 @@
// 查询操作
const handleQuery = async () => {
  loading.value = true;
  var res = await pageWcsStation(Object.assign(queryParams.value, tableParams.value));
  var res = await pageWcsPosition(Object.assign(queryParams.value, tableParams.value));
  tableData.value = res.data.result?.items ?? [];
  tableParams.value.total = res.data.result?.total;
  loading.value = false;
@@ -140,31 +143,31 @@
};
// 打开新增页面
const openAddWcsStation = () => {
  editWcsStationTitle.value = '添加设备工位';
const openAddWcsPosition = () => {
  editWcsPositionTitle.value = '添加设备点位管理';
  editDialogRef.value.openDialog({});
};
// 打开打印页面
const openPrintWcsStation = async (row: any) => {
  printWcsStationTitle.value = '打印设备工位';
const openPrintWcsPosition = async (row: any) => {
  printWcsPositionTitle.value = '打印设备点位管理';
}
// 打开编辑页面
const openEditWcsStation = (row: any) => {
  editWcsStationTitle.value = '编辑设备工位';
const openEditWcsPosition = (row: any) => {
  editWcsPositionTitle.value = '编辑设备点位管理';
  editDialogRef.value.openDialog(row);
};
// 删除
const delWcsStation = (row: any) => {
const delWcsPosition = (row: any) => {
  ElMessageBox.confirm(`确定要删除吗?`, "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(async () => {
      await deleteWcsStation(row);
      await deleteWcsPosition(row);
      handleQuery();
      ElMessage.success("删除成功");
    })