IPC-610
2025-01-15 b4083a6b047fc9e0964133c87227213c5154e37a
11111111
9个文件已修改
4个文件已添加
1150 ■■■■ 已修改文件
Admin.NET/WCS.Application/OpenApi/DemoOpenApi.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/PLC/PLCService.cs 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/PLC/PLCTaskAction.cs 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Service/WcsAlarmInfo/WcsAlarmInfoService.cs 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Service/WcsCheckTask/WcsCheckTaskService.cs 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Service/WcsDevice/Dto/WcsDeviceTaskOrderDto.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/Service/WcsDevice/WcsDeviceService.cs 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Web/src/api/wcs/wcsDevice.ts 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Web/src/views/device/alarmManage/index.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Web/src/views/device/inboundSorting/index.vue 308 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Web/src/views/device/inboundSorting/signalR.ts 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Web/src/views/device/outboundSorting/index.vue 275 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Web/src/views/device/outboundSorting/signalR.ts 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Admin.NET/WCS.Application/OpenApi/DemoOpenApi.cs
@@ -158,12 +158,17 @@
        {
            foreach (var item in models)
            {
                string str = JsonConvert.SerializeObject(models);
                Log.Information("接收WMS推送的箱码信息:" + str);
                // 验证任务是否已存在
                //var taskInfo = _db.Queryable<WcsOderTask>().First(w => w.OrderNo == item.OrderNo && w.SkuNo == item.SkuNo && w.LotNo == item.LotNo);
                //if (taskInfo == null)
                //{
                    var orderAdd = new WcsOderTask()
                //var taskid = _db.Queryable<WcsOderTask>().OrderByDescending(w=>w.CreateTime).First();
                //int newid = (int)taskid.Id + 1;
                var orderAdd = new WcsOderTask()
                    {
                        OrderNo = item.OrderNo,
                        TaskNo = "",
                        LotNo = item.LotNo,
@@ -172,6 +177,7 @@
                        BoxType = item.BoxType,
                        Qty = item.Qty,
                        TaskType = (TaskTypeEnum)item.TaskType,
                        CreateTime = DateTime.Now,
                    };
                    _db.Insertable(orderAdd).ExecuteCommand();
               //}
Admin.NET/WCS.Application/PLC/PLCService.cs
@@ -2,6 +2,7 @@
using Dm.filter;
using DocumentFormat.OpenXml.Bibliography;
using DocumentFormat.OpenXml.Drawing.Charts;
using Elastic.Clients.Elasticsearch.Snapshot;
using Elastic.Clients.Elasticsearch.Tasks;
using Flurl.Util;
using Furion.Logging;
@@ -1800,7 +1801,7 @@
    {
        var plcConn = modDevice.PLCUtil;
        if (modDevice.DbNumber == "DB101" && modDevice.DbNumber == "DB102")
        if (modDevice.DbNumber == "DB101")//&& modDevice.DbNumber == "DB102"&& (modDevice.DbNumber == "DB102"||modDevice.PlcIdIP == "10.18.51.110")
        {
            // 主扫交互流程
            switch (modDevice.Value.ToString())
@@ -2023,8 +2024,8 @@
                                //是否结批箱 
                                if (boxInfo[0].EndLotFlag == "1" && retVal.IsSucceed) 
                                {
                                    // 触发结批 解绑分道
                                    AutoEndLot(boxInfo[0].LotNo, plcConn, "0");
                                    // 触发结批 分道变为结批中
                                    AutoEndLot(boxInfo[0].LotNo, plcConn, "2");
                                }
                            }
                            else 
@@ -2167,6 +2168,7 @@
                                    string sqlStr2 = $"delete from WCSBoxInfoLog where  IsDelete=0 and PalletNo='{palletNo}'";
                                    _db.Ado.ExecuteCommand(sqlStr2);
                                }
                                // 向WMS申请巷道
                                var http = new HttpService();
                                string TaskNo = "", EndLocate = "";
@@ -2179,6 +2181,29 @@
                                }
                                else
                                {
                                    //判断是否结批中
                                    var (res, jiepi) = plcConn.GetPlcDBValue(checkTaskMedel.PosType, modDevice.DbNumber, checkTaskMedel.PosLot);
                                    if (jiepi == 2)//结批中
                                    {
                                        // 分道解绑,抓箱品种写入0
                                        var ret1 = plcConn.SetPlcDBValue(checkTaskMedel.PosTypeLot, modDevice.DbNumber, checkTaskMedel.PlcPos, "0");
                                        if (ret1.IsSucceed)
                                        {
                                            //写入流程字成功后更新分拣任务    liudl 最后一托盘申请完入库才可清空
                                            checkTaskMedel.OrderNo = "";
                                            checkTaskMedel.TaskNo = "";
                                            checkTaskMedel.LotNo = "";
                                            checkTaskMedel.SkuNo = "";
                                            checkTaskMedel.SkuName = "";
                                            checkTaskMedel.BoxType = "";
                                            checkTaskMedel.Qty = 0;
                                            checkTaskMedel.PZNo = "";
                                            checkTaskMedel.Status = "0";      // 绑定分道 0:解绑  1:绑定
                                            //更新分拣任务
                                            _db.Updateable(checkTaskMedel).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
                                        }
                                    }
                                    // 获取入库任务信息
                                    var taskModel = _db.Queryable<WcsTask>().First(m => m.TaskNo == TaskNo && m.IsDelete == false && m.Status == TaskStatusEnum.Wait);
                                    if (taskModel != null)
@@ -2376,7 +2401,7 @@
                // 写入结批信号
                var ret = plcConn.SetPlcDBValue(item.PosTypeLot, item.DbNumber, item.PosLot, "1");
                // 分道解绑,抓箱品种写入0
                var ret1 = plcConn.SetPlcDBValue(item.PosTypeLot, item.DbNumber, item.PlcPos, "0");
                //var ret1 = plcConn.SetPlcDBValue(item.PosTypeLot, item.DbNumber, item.PlcPos, "0");
                if (ret.IsSucceed)
                {
                    //写入流程字成功后更新分拣任务    liudl 最后一托盘申请完入库才可清空
@@ -2388,7 +2413,7 @@
                    //item.BoxType = "";
                    //item.Qty = 0;
                    item.PZNo = "";
                    item.Status = status;      // 绑定分道 0:解绑  1:绑定
                    item.Status = status;      // 绑定分道 0:解绑  1:绑定  2:结批中
                    //更新分拣任务
                    _db.Updateable(item).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
Admin.NET/WCS.Application/PLC/PLCTaskAction.cs
@@ -69,7 +69,7 @@
    /// </summary>
    public static void Init()
    {
       // var strMsg = new HttpService().RequestPackWcs("LN000001");
        // var strMsg = new HttpService().RequestPackWcs("LN000001");
        cts.Cancel();
        listPlc = _db.Queryable<WcsPlc>()
            .Where(s => s.Type == PLCTypeEnum.StackingMachine || s.Type == PLCTypeEnum.ConveyorLine || s.Type == PLCTypeEnum.BoxConveyorLine)
@@ -162,7 +162,7 @@
                            {
                                //Console.WriteLine($"{modPlc.IP}读取{modDevice.DbNumber}.{modDevice.PlcPos}的值为:{value}");
                                //无流程跳出
                                if (value == 0 )// && modPlc.Type!= PLCTypeEnum.BoxConveyorLine
                                if (value == 0)// && modPlc.Type!= PLCTypeEnum.BoxConveyorLine
                                    continue;
                                var dto = modDevice.Adapt<WcsDeviceDto>();
                                dto.Value = value;
@@ -316,7 +316,7 @@
                                listPulish.Add(modAlarm);
                            }
                            //取消报警
                            else if (value && modAlarm.Status == YesNoEnum.Y)
                            else if (!value && modAlarm.Status == YesNoEnum.Y)
                            {
                                modAlarm.AlarmTime = null;
                                modAlarm.Status = YesNoEnum.N;
@@ -333,7 +333,8 @@
                                modLog.Id = 0;
                                listLog.Add(modLog);
                            }
                            _db.Insertable(listLog).ExecuteCommand();
                            if (listLog.Count >= 0)
                                _db.Insertable(listLog).ExecuteCommand();
                            HubUtil.PublicAlarm(listPulish);
                        }
                    }
@@ -375,8 +376,8 @@
                        if (modPlcUtil == null)
                            continue;
                        var plcIp = modPlcUtil.PlcIP;
                        var listDevice = listPlcDevice.Where(s => s.PlcId == modPlcUtil.PlcId && s.DeviceType == DeviceTypeEnum.Show).ToList();
                        var modPlc = listPlc.FirstOrDefault(s => s.Id == modPlcUtil.PlcId);
                        var listDevice = listPlcDevice.Where(s => s.PlcId == modPlcUtil.PlcId && s.DeviceType == DeviceTypeEnum.Show).ToList();
                        var modPlc = listPlc.FirstOrDefault(s => s.Id == modPlcUtil.PlcId);
                        var listaddress = new Dictionary<string, PLCDataTypeEnum>();
                        foreach (var modDevice in listDevice)
                        {
@@ -435,7 +436,7 @@
                                        {
                                            bl = false;
                                        }
                                        else
                                        else
                                        {
                                            bl = true;
                                        }
Admin.NET/WCS.Application/Service/WcsAlarmInfo/WcsAlarmInfoService.cs
@@ -137,20 +137,24 @@
        if (value == null)
            throw Oops.Bah("未找到复位地址,请在字典管理中设置");
        PLCUtil modUtil = new PLCUtil(modPlc);
        switch (input.layer)
        {
            case 1:
                break;
            case 2:
                {
                    modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, value.Value, "1");
                }
                break;
            case 3:
                break;
            default:
                break;
        }
        //switch (input.layer)
        //{
        //    case 1:
        //        modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, value.Value, "1");
        //        break;
        //    case 2:
        //        {
        //            modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, value.Value, "1");
        //        }
        //        break;
        //    case 3:
        //        modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, value.Value, "1");
        //        break;
        //    default:
        //        break;
        //}
        modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, value.Value, "1");
        modUtil.Close();
    }
Admin.NET/WCS.Application/Service/WcsCheckTask/WcsCheckTaskService.cs
@@ -41,7 +41,7 @@
    [DisplayName("分页查询分拣任务表")]
    public async Task<SqlSugarPagedList<WcsCheckTaskOutput>> Page(PageWcsCheckTaskInput input)
    {
        input.SearchKey = input.SearchKey?.Trim();
        input.SearchKey = input.SearchKey?.Trim();
        var query = _wcsCheckTaskRep.AsQueryable()
            .WhereIF(!string.IsNullOrEmpty(input.SearchKey), u =>
                u.OrderNo.Contains(input.SearchKey)
@@ -67,14 +67,14 @@
            .WhereIF(!string.IsNullOrWhiteSpace(input.Status), u => u.Status.Contains(input.Status.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.PZNo), u => u.PZNo.Contains(input.PZNo.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.PalletNo), u => u.PalletNo.Contains(input.PalletNo.Trim()))
            .WhereIF(input.BoxInsert>0, u => u.BoxInsert == input.BoxInsert)
            .WhereIF(input.BoxCount>0, u => u.BoxCount == input.BoxCount)
            .WhereIF(input.Qty>0, u => u.Qty == input.Qty)
            .WhereIF(input.FinishQty>0, u => u.FinishQty == input.FinishQty)
            .WhereIF(input.BoxInsert > 0, u => u.BoxInsert == input.BoxInsert)
            .WhereIF(input.BoxCount > 0, u => u.BoxCount == input.BoxCount)
            .WhereIF(input.Qty > 0, u => u.Qty == input.Qty)
            .WhereIF(input.FinishQty > 0, u => u.FinishQty == input.FinishQty)
            .WhereIF(input.BindTimeRange != null && input.BindTimeRange.Length == 2, u => u.BindTime >= input.BindTimeRange[0] && u.BindTime <= input.BindTimeRange[1])
            .WhereIF(input.BindUserId>0, u => u.BindUserId == input.BindUserId)
            .WhereIF(input.BindUserId > 0, u => u.BindUserId == input.BindUserId)
            .Select<WcsCheckTaskOutput>();
        return await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
        return await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
    }
    /// <summary>
@@ -191,34 +191,41 @@
        checkTaskInfo.LotNo = taskInfo.LotNo;
        checkTaskInfo.SkuNo = taskInfo.SkuNo;
        checkTaskInfo.SkuName = taskInfo.SkuName;
        checkTaskInfo.BoxType = taskInfo.BoxType;
        //checkTaskInfo.BoxType = taskInfo.BoxType;
        checkTaskInfo.Qty = taskInfo.Qty;
        checkTaskInfo.Status = "1";//已绑定
        checkTaskInfo.PZNo = skuInfo.PZNo;
        checkTaskInfo.PZNo = skuInfo.PZNo;
        #region#给PLC写入抓箱品种号
        var modPlc = await _wcsDeviceRep.Context.Queryable<WcsPlc>().FirstAsync(s => s.Id == deviceInfo.PlcId);
        if (modPlc == null)
        if (checkTaskInfo.Id >= 6)
        {
            throw Oops.Bah("找不到PLC信息");
        }
        PLCUtil modUtil = new PLCUtil(modPlc);
        if (modUtil.Connected)
        {
            var ret = modUtil.SetPlcDBValue(checkTaskInfo.PosType, checkTaskInfo.DbNumber, checkTaskInfo.PlcPos, checkTaskInfo.PZNo);
            if (ret.IsSucceed)
            var modPlc = await _wcsDeviceRep.Context.Queryable<WcsPlc>().FirstAsync(s => s.Id == deviceInfo.PlcId);
            if (modPlc == null)
            {
                //写入流程字成功后更新分拣任务
                await _wcsCheckTaskRep.AsUpdateable(checkTaskInfo).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
                throw Oops.Bah("找不到PLC信息");
            }
            PLCUtil modUtil = new PLCUtil(modPlc);
            if (modUtil.Connected)
            {
                var ret = modUtil.SetPlcDBValue(checkTaskInfo.PosType, checkTaskInfo.DbNumber, checkTaskInfo.PlcPos, checkTaskInfo.PZNo);
                if (ret.IsSucceed)
                {
                    //写入流程字成功后更新分拣任务
                    await _wcsCheckTaskRep.AsUpdateable(checkTaskInfo).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
                }
                else
                {
                    throw Oops.Bah("与PCL交互失败,绑定失败!");
                }
            }
            else
            {
                throw Oops.Bah("与PCL交互失败,绑定失败!");
                throw Oops.Bah("PCL未连接,绑定失败!");
            }
        }
        else
        {
            throw Oops.Bah("PCL未连接,绑定失败!");
            await _wcsCheckTaskRep.AsUpdateable(checkTaskInfo).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
        }
        #endregion
    }
@@ -250,7 +257,7 @@
        //        throw Oops.Bah($"找不到工位号:208的设备信息");
        //    }
        //    PLCUtil modUtil = new PLCUtil(modPlc);
        //    var ret = modUtil.SetPlcDBValue(checkTaskList2.PosTypeLot, checkTaskList2.DbNumber, checkTaskList2.PosLot, "1");
        //    return;
        //}
@@ -281,27 +288,29 @@
            PLCUtil modUtil = new PLCUtil(modPlc);
            if (modUtil.Connected)
            {
                var ret = modUtil.SetPlcDBValue(item.PosTypeLot, item.DbNumber, item.PosLot, "0");    // 解绑分道
                if (ret.IsSucceed)
                {
                    //写入流程字成功后更新分拣任务
                    item.OrderNo = "";
                    item.TaskNo = "";
                    item.LotNo = "";
                    item.SkuNo = "";
                    item.SkuName = "";
                    item.BoxType = "";
                    item.Qty = 0;
                    item.PZNo = "";
                    item.Status = "0";//未绑定
                // 写入结批信号
                var ret = modUtil.SetPlcDBValue(item.PosTypeLot, item.DbNumber, item.PosLot, "1");
                //var ret1 = modUtil.SetPlcDBValue(item.PosTypeLot, item.DbNumber, item.PosLot, "0");    // 解绑分道
                //if (ret1.IsSucceed)
                //{
                //    //写入流程字成功后更新分拣任务
                //    item.OrderNo = "";
                //    item.TaskNo = "";
                //    item.LotNo = "";
                //    item.SkuNo = "";
                //    item.SkuName = "";
                //    item.BoxType = "";
                //    item.Qty = 0;
                //    item.PZNo = "";
                //    item.Status = "0";//未绑定
                    //更新分拣任务
                    await _wcsCheckTaskRep.AsUpdateable(item).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
                }
                else
                {
                    throw Oops.Bah("与PCL交互失败,结批失败!");
                }
                //    //更新分拣任务
                //    await _wcsCheckTaskRep.AsUpdateable(item).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
                //}
                //else
                //{
                //    throw Oops.Bah("与PCL交互失败,结批失败!");
                //}
            }
            else
            {
@@ -310,4 +319,33 @@
            #endregion
        }
    }
    /// <summary>
    /// 任务解绑
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "UnBindTaskForPLC")]
    [DisplayName("任务解绑")]
    public async Task UnBindTaskForPLC(BaseIdInput input)
    {
        var modCheckTask = await _wcsCheckTaskRep.AsQueryable().FirstAsync(s => s.Id == input.Id);
        if (modCheckTask == null)
            throw Oops.Bah("找不到该信息");
        if (modCheckTask.Status != "1")
            throw Oops.Bah("该任务已解绑");
        modCheckTask.Status = "0";
        modCheckTask.OrderNo = "";
        modCheckTask.TaskNo = "";
        modCheckTask.SkuNo = "";
        modCheckTask.SkuName = "";
        modCheckTask.LotNo = "";
        modCheckTask.PZNo = "";
        modCheckTask.BoxType = "";
        modCheckTask.Qty = 0;
        await _wcsCheckTaskRep.AsUpdateable(modCheckTask).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
    }
}
Admin.NET/WCS.Application/Service/WcsDevice/Dto/WcsDeviceTaskOrderDto.cs
@@ -8,6 +8,7 @@
public class WcsDeviceTaskOrderDto
{
    public long Id { get; set; }
    public long TaskId { get; set; }
    public string Text { get; set; }
    public string? TaskNo { get; set; }
    public string? OrderNo { get; set; }
Admin.NET/WCS.Application/Service/WcsDevice/WcsDeviceService.cs
@@ -18,7 +18,7 @@
    private readonly SqlSugarRepository<WcsPlc> _wcsPlcRep;
    private readonly SqlSugarRepository<WcsDevice> _wcsDeviceRep;
    private readonly SysCacheService _sysCacheService;
    public WcsDeviceService(SqlSugarRepository<WcsPlc> wcsPlcRep,SqlSugarRepository<WcsDevice> wcsDeviceRep, SysCacheService sysCacheService)
    public WcsDeviceService(SqlSugarRepository<WcsPlc> wcsPlcRep, SqlSugarRepository<WcsDevice> wcsDeviceRep, SysCacheService sysCacheService)
    {
        _wcsPlcRep = wcsPlcRep;
        _wcsDeviceRep = wcsDeviceRep;
@@ -82,7 +82,7 @@
            case "suoding":     // 锁定
                modUtil.SetPlcDBValue(PLCDataTypeEnum.Short, DbNum, "48.0", input.LocatNo);
                break;
            default:
                break;
        }
@@ -182,50 +182,46 @@
    public async Task WriteInfo(WcsDeviceUpInfo input)
    {
        WcsPlc modPlc;
        string DbNum = "";// DB块
        string DbNum = "DB91";// DB块
        if (string.IsNullOrWhiteSpace(input.LocatNo))//如果工位为空
        {
            throw Oops.Bah("工位不能为空");
        }
        var plcList = await _wcsPlcRep.Context.Queryable<WcsPlc>().Where(s => s.Type == PLCTypeEnum.ConveyorLine && s.IsDelete == false).ToListAsync();
        var plcList = await _wcsPlcRep.Context.Queryable<WcsPlc>().Where(s => s.Type == PLCTypeEnum.ConveyorLine).ToListAsync();
        switch (input.Layer)
        {
            case "1":
                modPlc = plcList.FirstOrDefault(m=>m.Text == "1层托盘输送线");
                if (modPlc == null)
                    throw Oops.Bah($"未查询到{input.Layer}楼层PLC信息");
                DbNum = "";
                modPlc = plcList.FirstOrDefault(m => m.Text == "1层托盘输送线");
                //DbNum = "";
                break;
            case "2":
                modPlc = plcList.FirstOrDefault(m => m.Text == "2层托盘输送线");
                if (modPlc == null)
                    throw Oops.Bah($"未查询到{input.Layer}楼层PLC信息");
                DbNum = "DB91";
                //DbNum = "DB91";
                break;
            case "3":
                modPlc = plcList.FirstOrDefault(m => m.Text == "3层托盘输送线");
                if (modPlc == null)
                    throw Oops.Bah($"未查询到{input.Layer}楼层PLC信息");
                DbNum = "";
                //DbNum = "";
                break;
            default:
                throw Oops.Bah("楼层信息错误");
        }
        var device = await _wcsDeviceRep.Context.Queryable<WcsDevice>().FirstAsync(s => s.PlcId == modPlc.Id && s.StationNum == input.LocatNo && s.IsDelete == false && s.DeviceType == DeviceTypeEnum.Show);
        if (device == null)
        if (modPlc == null)
            throw Oops.Bah($"未查询到{input.Layer}楼层PLC信息");
        var device = await _wcsDeviceRep.Context.Queryable<WcsDevice>().FirstAsync(s => s.PlcId == modPlc.Id && s.StationNum == input.LocatNo && s.DeviceType == DeviceTypeEnum.Show);
        if (device == null)
        {
            throw Oops.Bah("当前楼层未查询到该工位信息");
        }
        PLCUtil modUtil = new PLCUtil(modPlc);
        // true : 手动模式    false:自动模式
        var (result, value) = modUtil.GetPlcDBValue(PLCDataTypeEnum.Bit, DbNum, "50.4");
        if (result.IsSucceed)
        {
            if (input.TypeName != "shoudong" && value.ToString().ToLower() == "false"  && input.TypeName != "huifu" && input.TypeName != "UpTask" )
            if (input.TypeName != "shoudong" && value.ToString().ToLower() == "false" && input.TypeName != "huifu" && input.TypeName != "UpTask")
            {
                throw Oops.Bah("当前为自动模式,请先切换为手动模式");
            }
@@ -234,7 +230,7 @@
        {
            throw Oops.Bah("读取PLC手自动值失败");
        }
        switch (input.TypeName)
        {
            case "zidong":     // 自动
@@ -258,10 +254,10 @@
                {
                    throw Oops.Bah("事件结果错误");
                }
                break;
            case "1diandong":   // 1点动
                if(input.FuncName == "true")
                if (input.FuncName == "true")
                {
                    modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, DbNum, "50.7", "true");
                }
@@ -403,11 +399,11 @@
            case "fanzhuansheng":
                if (input.FuncName == "true")
                {
                    modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, DbNum, "51.7", "true");
                    modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, DbNum, "59.0", "true");
                }
                else if (input.FuncName == "false")
                {
                    modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, DbNum, "51.7", "false");
                    modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, DbNum, "59.0", "false");
                }
                else
                {
@@ -417,11 +413,11 @@
            case "fanzhuanjiang":
                if (input.FuncName == "true")
                {
                    modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, DbNum, "52.0", "true");
                    modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, DbNum, "59.1", "true");
                }
                else if (input.FuncName == "false")
                {
                    modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, DbNum, "52.0", "false");
                    modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, DbNum, "59.1", "false");
                }
                else
                {
@@ -445,8 +441,8 @@
                {
                    throw Oops.Bah("读取PLC值失败");
                }
                break;
            default:
                break;
@@ -547,7 +543,7 @@
                Thread.Sleep(1000);
                modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, DbNum, "50.2", "false");
                break;
            default:
                break;
        }
@@ -570,7 +566,7 @@
        WcsPlc modPlc;
        string DbNum = "";// DB块 
        var plcList = await _wcsPlcRep.Context.Queryable<WcsPlc>().Where(s => s.Type == PLCTypeEnum.ConveyorLine && s.IsDelete == false).ToListAsync();
        if (input.Layer == "1")
        {
@@ -685,7 +681,7 @@
                    {
                        throw Oops.Bah("事件结果错误");
                    }
                    break;
                    break;
                case "TwoBoxStop":
                    if (input.FuncName == "true")
@@ -717,7 +713,7 @@
        {
            throw Oops.Bah("操作类型信息错误");
        }
    }
    #endregion
@@ -970,7 +966,7 @@
                            (result, var palletNo) = modConn.GetPlcDBValue(modPositionPalletNo.PosType, modDevice.DbNumber, modPositionPalletNo.PlcPos, modPositionPalletNo.StringLength);
                            modDevice.PalletNo = Convert.ToString(palletNo);
                            Console.WriteLine(modDevice.DbNumber + "." + modPositionPalletNo.PlcPos + "----------");
                        }
                        }
                        if (cachePlc.Type == PLCTypeEnum.ConveyorLine || cachePlc.Type == PLCTypeEnum.StackingMachine)
                        {
                            //放货排
@@ -1015,11 +1011,11 @@
                                (result, var pickStorey) = modConn.GetPlcDBValue(modPositionPickStorey.PosType, modDevice.DbNumber, modPositionPickStorey.PlcPos);
                                modDevice.PickStorey = Convert.ToInt32(pickStorey);
                            }
                            if (cachePlc.Type == PLCTypeEnum.StackingMachine)
                            {
                                //跺机的起始工位用取货排列层
                                modDevice.StartLocatNo = $"{modDevice.PickRow.ToString().PadLeft(2,'0')}{modDevice.PickCol.ToString().PadLeft(2, '0')}{modDevice.PickStorey.ToString().PadLeft(2, '0')}";
                                modDevice.StartLocatNo = $"{modDevice.PickRow.ToString().PadLeft(2, '0')}{modDevice.PickCol.ToString().PadLeft(2, '0')}{modDevice.PickStorey.ToString().PadLeft(2, '0')}";
                                //跺机的目的工位用放货排列层
                                modDevice.EndLocatNo = $"{modDevice.ReleaseRow.ToString().PadLeft(2, '0')}{modDevice.ReleaseCol.ToString().PadLeft(2, '0')}{modDevice.ReleaseStorey.ToString().PadLeft(2, '0')}";
                            }
@@ -1157,7 +1153,7 @@
                var modPositionEndLocatNo = listPosition.FirstOrDefault(s => s.Text == "目的工位");
                if (modPositionEndLocatNo != null)
                    result = modUtil.SetPlcDBValue(modPositionEndLocatNo.PosType, modDbDevice.DbNumber, modPositionEndLocatNo.PlcPos, modDevice.EndLocatNo.ToString());
            }
            }
        }
        //托盘码
        if (modDevice.PalletNo != null)
@@ -1237,7 +1233,7 @@
    public async Task<dynamic> WcsPackPlcList()
    {
        return await _wcsDeviceRep.Context.Queryable<WcsPlc>()
                .Where(w => w.Type == PLCTypeEnum.RobotPalletizer || w.Type == PLCTypeEnum.StackingRobot)
                .Where(w => w.Type == PLCTypeEnum.RobotPalletizer /*|| w.Type == PLCTypeEnum.StackingRobot*/)
                .OrderByDescending(o => o.Type)
                .Select(u => new
                {
@@ -1282,7 +1278,7 @@
                    PZNo = task.PZNo,
                    Qty = task.Qty,
                    PlcId=device.PlcId,
                    PlcId = device.PlcId,
                    Type = plc.Type
                })
                .ToListAsync();
@@ -1294,7 +1290,62 @@
        if (modUtil.Connected)
        {
            connStatus = true;
        }
        }
        foreach (var item in list)
        {
            item.PlcStatus = connStatus;
        }
        return list;
    }
    /// <summary>
    /// 获取设备对应工位列表
    /// </summary>
    /// <param name="entry"></param>
    /// <returns></returns>
    [HttpGet]
    [ApiDescriptionSettings(Name = "WcsStackingRobotList")]
    [DisplayName("获取设备对应工位列表")]
    public async Task<List<WcsDeviceTaskOrderDto>> WcsStackingRobotList()
    {
        //var list = await _wcsDeviceRep.AsQueryable()
        //                            .LeftJoin<WcsPlc>((a, b) => a.PlcId == b.Id)
        //                            .Where((a, b) => a.DeviceType == DeviceTypeEnum.Business)
        //                            .Select<WcsDeviceOutput>((a, b) => new WcsDeviceOutput() { Type = b.Type }, true)
        //                            .ToListAsync();
        var list = await _wcsDeviceRep.Context.Queryable<WcsCheckTask>()
                .LeftJoin<WcsDevice>((task, device) => device.StationNum == task.Port)
                .InnerJoin<WcsPlc>((task, device, plc) => device.PlcId == plc.Id)
                .Where((task, device, plc) => task.Id <= 3)
                .OrderBy((task, device, plc) => device.CreateTime)
                .Select((task, device, plc) => new WcsDeviceTaskOrderDto()
                {
                    Id = device.Id,
                    TaskId = task.Id,
                    Text = task.Id.ToString() + "号出库分拣线",
                    TaskNo = task.TaskNo,
                    OrderNo = task.OrderNo,
                    LotNo = task.LotNo,
                    SkuNo = task.SkuNo,
                    SkuName = task.SkuName,
                    LineNo = task.LineNo,
                    Status = task.Status,
                    PZNo = task.PZNo,
                    Qty = task.Qty,
                    PlcId = device.PlcId,
                    Type = plc.Type
                })
                .ToListAsync();
        bool connStatus = false;
        //获取设备的状态
        var modPlc = await _wcsDeviceRep.Context.Queryable<WcsPlc>().FirstAsync(s => s.Id == list[0].PlcId);
        PLCUtil modUtil = new PLCUtil(modPlc);
        if (modUtil.Connected)
        {
            connStatus = true;
        }
        foreach (var item in list)
        {
            item.PlcStatus = connStatus;
Web/src/api/wcs/wcsDevice.ts
@@ -1,26 +1,27 @@
import request from '/@/utils/request';
enum Api {
  AddWcsDevice = '/api/wcsDevice/add',
  DeleteWcsDevice = '/api/wcsDevice/delete',
  UpdateWcsDevice = '/api/wcsDevice/update',
  PageWcsDevice = '/api/wcsDevice/page',
  DetailWcsDevice = '/api/wcsDevice/detail',
  GetWcsPlcPlcIdDropdown = '/api/wcsDevice/WcsPlcPlcIdDropdown',
  GeneratePos = '/api/wcsDevice/GeneratePos',
  ListWcsDevice = '/api/wcsDevice/list',
  WriteValue = '/api/wcsdevice/writeValue',
    AddWcsDevice = '/api/wcsDevice/add',
    DeleteWcsDevice = '/api/wcsDevice/delete',
    UpdateWcsDevice = '/api/wcsDevice/update',
    PageWcsDevice = '/api/wcsDevice/page',
    DetailWcsDevice = '/api/wcsDevice/detail',
    GetWcsPlcPlcIdDropdown = '/api/wcsDevice/WcsPlcPlcIdDropdown',
    GeneratePos = '/api/wcsDevice/GeneratePos',
    ListWcsDevice = '/api/wcsDevice/list',
    WriteValue = '/api/wcsdevice/writeValue',
  GetWcsPackPlcList='/api/wcsDevice/WcsPackPlcList',
  GetWcsPackStationPlcList='/api/wcsDevice/WcsPackStationPlcList',
  BindTaskForPLC='/api/WcsCheckTask/BindTaskForPLC',
  CloseTaskForPLC='/api/WcsCheckTask/CloseTaskForPLC',
    GetWcsPackPlcList = '/api/wcsDevice/WcsPackPlcList',
    GetWcsPackStationPlcList = '/api/wcsDevice/WcsPackStationPlcList',
    GetWcsStackingRobotList = '/api/wcsDevice/WcsStackingRobotList',
    BindTaskForPLC = '/api/WcsCheckTask/BindTaskForPLC',
    CloseTaskForPLC = '/api/WcsCheckTask/CloseTaskForPLC',
    UnBindTaskForPLC = '/api/WcsCheckTask/UnBindTaskForPLC',
  GetLocationInfo = '/api/wcsDevice/GetLocationInfo',
  WriteLocationInfo = '/api/wcsDevice/WriteLocationInfo',
  WriteInfo = '/api/wcsDevice/WriteInfo',
  WriteTaskInfo = '/api/wcsDevice/WriteTaskInfo',
  WriteStartStop = '/api/wcsDevice/WriteStartStop',
    GetLocationInfo = '/api/wcsDevice/GetLocationInfo',
    WriteLocationInfo = '/api/wcsDevice/WriteLocationInfo',
    WriteInfo = '/api/wcsDevice/WriteInfo',
    WriteTaskInfo = '/api/wcsDevice/WriteTaskInfo',
    WriteStartStop = '/api/wcsDevice/WriteStartStop',
}
// 增加设备信息
export const WriteLocationInfo = (params?: any) =>
@@ -67,54 +68,54 @@
    });
// 删除设备信息
export const deleteWcsDevice = (params?: any) =>
export const deleteWcsDevice = (params?: any) =>
    request({
            url: Api.DeleteWcsDevice,
            method: 'post',
            data: params,
        });
        url: Api.DeleteWcsDevice,
        method: 'post',
        data: params,
    });
// 编辑设备信息
export const updateWcsDevice = (params?: any) =>
export const updateWcsDevice = (params?: any) =>
    request({
            url: Api.UpdateWcsDevice,
            method: 'post',
            data: params,
        });
        url: Api.UpdateWcsDevice,
        method: 'post',
        data: params,
    });
// 分页查询设备信息
export const pageWcsDevice = (params?: any) =>
export const pageWcsDevice = (params?: any) =>
    request({
            url: Api.PageWcsDevice,
            method: 'post',
            data: params,
        });
        url: Api.PageWcsDevice,
        method: 'post',
        data: params,
    });
// 详情设备信息
export const detailWcsDevice = (id: any) =>
export const detailWcsDevice = (id: any) =>
    request({
            url: Api.DetailWcsDevice,
            method: 'get',
            data: { id },
        });
        url: Api.DetailWcsDevice,
        method: 'get',
        data: { id },
    });
export const getWcsPlcPlcIdDropdown = () =>
        request({
    request({
        url: Api.GetWcsPlcPlcIdDropdown,
        method: 'get'
        });
    });
export const generatePos = (params?: any) =>
    request({
    url: Api.GeneratePos,
    method: 'post',
    data: params
        url: Api.GeneratePos,
        method: 'post',
        data: params
    });
export const listWcsDevice = () =>
    request({
    url: Api.ListWcsDevice,
    method: 'get'
        url: Api.ListWcsDevice,
        method: 'get'
    });
@@ -122,33 +123,45 @@
    request({
        url: Api.GetWcsPackPlcList,
        method: 'get'
});
    });
export const GetWcsPackStationPlcList = (params?: any) =>
    request({
        url: Api.GetWcsPackStationPlcList,
        method: 'get',
        data: params
});
    });
export const GetWcsStackingRobotList = (params?: any) =>
    request({
        url: Api.GetWcsStackingRobotList,
        method: 'get',
        data: params
    });
// 手动绑定任务到PLC
export const BindTaskForPLC = (params?: any) =>
export const BindTaskForPLC = (params?: any) =>
    request({
        url: Api.BindTaskForPLC,
        method: 'post',
        data: params,
});
    });
//任务结批
export const CloseTaskForPLC = (params?: any) =>
export const CloseTaskForPLC = (params?: any) =>
    request({
        url: Api.CloseTaskForPLC,
        method: 'post',
        data: params,
});
    });
//任务解绑
export const UnBindTaskForPLC = (params?: any) =>
    request({
        url: Api.UnBindTaskForPLC,
        method: 'post',
        data: params,
    });
//写入值
export const writeValue = (params?: any) =>
export const writeValue = (params?: any) =>
    request({
        url: Api.WriteValue,
        method: 'post',
        data: params,
});
    });
Web/src/views/device/alarmManage/index.vue
@@ -11,12 +11,12 @@
                    <el-table-column prop="alarmName" label="描述" align="center"></el-table-column>
                    <el-table-column prop="stationNum" label="位置" align="center"></el-table-column>
                    <el-table-column prop="alarmTime" label="时间" align="center"></el-table-column>
                    <el-table-column label="操作" width="80" align="center" fixed="right" show-overflow-tooltip="">
                    <!-- <el-table-column label="操作" width="80" align="center" fixed="right" show-overflow-tooltip="">
                        <template #default="scope">
                            <el-button icon="ele-Check" size="small" text="" type="primary"
                                @click="topUpAlarm(scope.row)">恢复</el-button>
                        </template>
                    </el-table-column>
                    </el-table-column> -->
                </el-table>
                <el-pagination v-model:currentPage="tableParams.page" v-model:page-size="tableParams.pageSize"
                    :total="tableParams.total" :page-sizes="[10, 20, 50, 100, 200, 500]" size="small" background=""
@@ -73,10 +73,8 @@
    signalR.off('PublicAlarm');
    signalR.on('PublicAlarm', (dataArray: any) => {
        dataArray.forEach(data => {
            console.log("1111111:"+data);
            // 更新 tableData
            const index = tableData.value.findIndex(t => t.id == data.id);
            console.log("2222222:"+index.value);
            
            if (index === -1 && data.status == 1) {
                // 如果不存在,添加新数据
Web/src/views/device/inboundSorting/index.vue
New file
@@ -0,0 +1,308 @@
<template>
    <el-container>
        <el-col>
            <el-row :span="1">
                <div class="card-page">
                    <el-button
                        v-for="device in deviceList"
                        :key="device.id"
                        type="primary"
                        :plain="selectedDeviceId !== device.id"
                        @click="chooseDevice(device.id)"
                        >
                        {{ device.name }}
                    </el-button>
                </div>
            </el-row>
            <el-row :span="1">
                <div class="card-container">
                    <el-card class="other-box-card" v-for="deviceInfo in devicePointData" :key="deviceInfo.id">
                        <div slot="header" class="linefix">
                            <span>{{ deviceInfo.text }}</span>
                            <div :class="['lineStatus', { 'device-status-0': deviceInfo.plcStatus === true  }, { 'device-status-1': deviceInfo.plcStatus === false }]"></div>
                        </div>
                        <div class="otherValuefix" >
                            <el-form label-position="left" label-width="90px">
                                <el-form-item label="WMS明细单号" v-if="deviceInfo.type==5">
                                    <el-input v-model="deviceInfo.orderNo" readonly></el-input>
                                </el-form-item>
                                <el-form-item label="任务号">
                                    <el-input v-model="deviceInfo.taskNo"></el-input>
                                </el-form-item>
                                <el-form-item label="批次号">
                                    <el-input v-model="deviceInfo.lotNo" readonly></el-input>
                                </el-form-item>
                                <el-form-item label="物料编码">
                                    <el-input v-model="deviceInfo.skuNo" readonly></el-input>
                                </el-form-item>
                                <el-form-item label="物料名称">
                                    <el-input v-model="deviceInfo.skuName" readonly></el-input>
                                </el-form-item>
                                <el-form-item label="分拣线编号" v-if="deviceInfo.type==5">
                                    <el-input v-model="deviceInfo.lineNo" readonly></el-input>
                                </el-form-item>
                                <el-form-item label="绑定状态">
                                    <el-input :value="deviceInfo.status === '0' ? '未绑定' : '已绑定'" readonly></el-input>
                                </el-form-item>
                                <el-form-item label="抓箱品种">
                                    <el-input v-model="deviceInfo.pzNo" readonly></el-input>
                                </el-form-item>
                                <el-form-item label="托盘号">
                                    <el-input readonly></el-input>
                                </el-form-item>
                                <el-form-item label="插码箱数" v-if="deviceInfo.type==5">
                                    <el-input readonly></el-input>
                                </el-form-item>
                                <el-form-item label="拆垛箱数" v-if="deviceInfo.type==6">
                                    <el-input readonly></el-input>
                                </el-form-item>
                                <el-form-item label="整跺箱数">
                                    <el-input readonly></el-input>
                                </el-form-item>
                                <el-form-item label="完成箱数">
                                    <el-input readonly></el-input>
                                </el-form-item>
                                <!-- <el-form-item label="WMS下发数量">
                                    <el-input v-model="deviceInfo.qty" readonly></el-input>
                                </el-form-item> -->
                                <el-form-item label="状态">
                                <el-input :value="deviceInfo.plcStatus ? '在线' : '离线'" readonly></el-input>
                            </el-form-item>
                            </el-form>
                        </div>
                        <!-- 设备类型为码垛机器人 -->
                        <div v-if="deviceInfo.type==5" class="otherButtonfix">
                            <el-form label-position="left">
                                <el-form-item>
                                    <el-button type="primary" @click="openBindDialog(deviceInfo.id)">绑定</el-button>
                                    <el-button @click="closeBindDialog(deviceInfo.lotNo)">结批</el-button>
                                </el-form-item>
                            </el-form>
                        </div>
                    </el-card>
                </div>
            </el-row>
        </el-col>
         <!-- 绑定任务弹框 -->
         <el-dialog v-model="bindDialogVisible" title="选择数据">
            <el-table
                :data="bindData"
                highlight-current-row
                @row-click="handleRowClick"
                >
                <el-table-column prop="orderNo" label="WMS下发单号"  show-overflow-tooltip="" />
                <el-table-column prop="taskNo" label="任务号"  show-overflow-tooltip="" />
                <el-table-column prop="lotNo" label="批次号"  show-overflow-tooltip="" />
                <el-table-column prop="skuNo" label="物料编码"  show-overflow-tooltip="" />
                <el-table-column prop="skuName" label="物料名称"  show-overflow-tooltip="" />
                <el-table-column prop="boxType" label="规格"  show-overflow-tooltip="" />
                <el-table-column prop="qty" label="总箱数/计划箱数/预估箱数"  show-overflow-tooltip="" />
            </el-table>
            <div slot="footer" class="dialog-footer">
                <el-button @click="bindDialogVisible = false">取消</el-button>
                <el-button type="primary" @click="confirmBinding">确认</el-button>
            </div>
        </el-dialog>
    </el-container>
</template>
<script lang="ts" setup>
import { ref, onMounted  } from 'vue';
import { GetWcsPackPlcList,GetWcsPackStationPlcList,BindTaskForPLC,CloseTaskForPLC } from '/@/api/wcs/wcsDevice';
import { pageWcsOderTask } from '/@/api/device/wcsOderTask';
import { ElMessageBox,ElMessage } from 'element-plus';
import { signalR,stopConnection } from './signalR';
//连接signalR 监听变更
onMounted(async () => {
    signalR.off('PublicCheckTask');
    signalR.on('PublicCheckTask', (data: any) => {
        //todo 需要测试
        // if (data.type == 0) {
        // }
        var index = devicePointData.value.findIndex(s => s.id == data.id);
        if (index !== -1) {
            devicePointData.value.splice(index, 1, data);
        }
    });
});
//设备数据
const deviceList=ref<any>([]);
//设备对应工位数据
const devicePointData = ref<any>([]);
//选中设备ID
const selectedDeviceId=ref<any>();
//选中工位ID
const selectedStationId=ref<any>();
const bindDialogVisible = ref(false);
const bindData = ref<any>([]);
const selectedRow = ref<any>(null);
const queryParams = ref<any>({});
const tableParams = ref({
    page: 1,
    pageSize: 20,
    total: 0,
});
//获取设备对应的工位数据
const fetchStationData = async (plcId: any) => {
    const res2 = await GetWcsPackStationPlcList({ plcId });
    devicePointData.value = res2.data.result;
};
// 获取设备数据
const fetchPLCDeviceData = async () => {
    var res = await GetWcsPackPlcList();
    deviceList.value = res.data.result;
    if (deviceList.value.length > 0) {
      selectedDeviceId.value = deviceList.value[0].id;
      await fetchStationData(selectedDeviceId.value);
    }
};
fetchPLCDeviceData();
//切换设备
function chooseDevice(id) {
    selectedDeviceId.value = id;
    fetchStationData(selectedDeviceId.value);
}
const handleQuery = async () => {
    var res = await pageWcsOderTask(Object.assign(queryParams.value, tableParams.value));
    bindData.value = res.data.result?.items ?? [];
    tableParams.value.total = res.data.result?.total;
  };
//打开绑定弹框
function openBindDialog(id) {
    selectedStationId.value=null;
    selectedRow.value=null;
    selectedStationId.value=id;
    bindDialogVisible.value = true;
    handleQuery();
}
//点击行时设置选中行
function handleRowClick(row) {
    selectedRow.value = row;
}
//确认绑定操作
function confirmBinding() {
    if (selectedRow.value) {
        //手动绑定任务到PLC
        bindTaskForPLC(selectedStationId.value,selectedRow.value.id);
        bindDialogVisible.value = false;
    } else {
        ElMessage.error('请选择要绑定的任务!');
    }
}
const bindTaskForPLC = async (deviceId: any,oderTaskId:any) => {
    const res = await BindTaskForPLC({ deviceId,oderTaskId });
    if(res.status==200){
        ElMessage.success('绑定成功!');
        // 刷新
        fetchStationData(selectedDeviceId.value);
    }
}
//结批操作
function closeBindDialog(lotNo){
    // if(lotNo==''){
    //     ElMessage.error('该工位未绑定任务!');
    //     return;
    // }
    ElMessageBox.confirm(`确定对该批次任务结批吗?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
    })
    .then(async () => {
        closeTaskForPLC(lotNo);
    })
    .catch(() => {});
}
const closeTaskForPLC = async (lotNo: string) => {
    const res = await CloseTaskForPLC({ lotNo });
    if(res.status==200){
        ElMessage.success('结批成功!');
        // 刷新
        fetchStationData(selectedDeviceId.value);
    }
}
</script>
<style scoped>
    .card-page {
        width: 100%;
        height: 50px;
        display: flex;
        text-align: center;
        justify-content: center;
        align-items: center;
        text-align: center;
    }
    .card-page>button {
        width: 150px;
        height: 30px;
    }
    .card-container {
            display: grid;
            grid-template-columns: repeat(6, 1fr);
            gap: 10px;
    }
    .other-box-card {
            box-sizing: border-box;
            background: linear-gradient(135deg, #66ccff, #3399ff);
    }
    .lineStatus{
        position: absolute;
        right: 0;
        float: right;
        height: 20px;
        width: 20px;
        border-radius: 20px;
        background-color: #67C23A;
    }
    .linefix{
        border-bottom: 1px solid rgb(197, 195, 195);
        display: flex;
        align-items: center;
        height: 40px;
        position: relative;
        color: #fff;
    }
    .otherValuefix{
        width: 100%;
        height: 540px;
        padding: 10px;
        border-bottom: 1px solid rgb(197, 195, 195);
    }
    .otherButtonfix{
        width: 100%;
        height: 60px;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0;
    }
    .device-status-0{
        background-color: #58f709;
    }
    .device-status-1{
        background-color: red;
    }
    .dialog-footer {
        display: flex;
        justify-content: flex-end;
        margin-top: 20px;
    }
    .divDisplay{
        display:none
    }
</style>
Web/src/views/device/inboundSorting/signalR.ts
New file
@@ -0,0 +1,45 @@
import * as SignalR from '@microsoft/signalr';
import { getToken } from '/@/utils/axios-utils';
// 初始化SignalR对象
const connection = new SignalR.HubConnectionBuilder()
    .configureLogging(SignalR.LogLevel.Information)
    .withUrl(`${window.__env__.VITE_API_URL}/hubs/CheckTask?token=${getToken()}`, { transport: SignalR.HttpTransportType.WebSockets, skipNegotiation: true })
    .withAutomaticReconnect({
        nextRetryDelayInMilliseconds: () => {
            return 5000; // 每5秒重连一次
        },
    })
    .build();
connection.keepAliveIntervalInMilliseconds = 15 * 1000; // 心跳检测15s
connection.serverTimeoutInMilliseconds = 30 * 60 * 1000; // 超时时间30m
// 启动连接
connection.start().then(() => {
    console.log('启动连接checkTask');
});
// 断开连接
connection.onclose(async () => {
    console.log('断开连接checkTask');
});
// 重连中
connection.onreconnecting(() => {
    console.log('服务器已断线checkTask');
});
// 重连成功
connection.onreconnected(() => {
    console.log('重连成功checkTask');
});
// 关闭连接的方法
async function stopConnection() {
    try {
      await connection.stop();
      console.log('连接已关闭');
    } catch (error) {
      console.error('关闭连接时发生错误:', error);
    }
  }
// connection.on('PublicPlcConn', () => {});
export { connection as signalR,stopConnection };
Web/src/views/device/outboundSorting/index.vue
New file
@@ -0,0 +1,275 @@
<template>
    <el-container>
        <el-col>
            <el-row :span="1">
                <div class="card-container">
                    <el-card class="other-box-card" v-for="deviceInfo in devicePointData" :key="deviceInfo.id">
                        <div slot="header" class="linefix">
                            <span>{{ deviceInfo.text }}</span>
                            <!-- <div
                                :class="['lineStatus', { 'device-status-0': deviceInfo.plcStatus === true }, { 'device-status-1': deviceInfo.plcStatus === false }]">
                            </div> -->
                        </div>
                        <div class="otherValuefix">
                            <el-form label-position="left" label-width="90px">
                                <el-form-item label="WMS明细单号">
                                    <el-input v-model="deviceInfo.orderNo" readonly></el-input>
                                </el-form-item>
                                <el-form-item label="任务号">
                                    <el-input v-model="deviceInfo.taskNo"></el-input>
                                </el-form-item>
                                <el-form-item label="批次号">
                                    <el-input v-model="deviceInfo.lotNo" readonly></el-input>
                                </el-form-item>
                                <el-form-item label="物料编码">
                                    <el-input v-model="deviceInfo.skuNo" readonly></el-input>
                                </el-form-item>
                                <el-form-item label="物料名称">
                                    <el-input v-model="deviceInfo.skuName" readonly></el-input>
                                </el-form-item>
                                <el-form-item label="分拣线编号" v-if="deviceInfo.type == 5">
                                    <el-input v-model="deviceInfo.lineNo" readonly></el-input>
                                </el-form-item>
                                <el-form-item label="绑定状态">
                                    <el-input :value="deviceInfo.status === '0' ? '未绑定' : '已绑定'" readonly></el-input>
                                </el-form-item>
                                <el-form-item label="抓箱品种">
                                    <el-input v-model="deviceInfo.pzNo" readonly></el-input>
                                </el-form-item>
                                <!-- <el-form-item label="托盘号">
                                    <el-input readonly></el-input>
                                </el-form-item>
                                <el-form-item label="插码箱数" v-if="deviceInfo.type==5">
                                    <el-input readonly></el-input>
                                </el-form-item>
                                <el-form-item label="拆垛箱数" v-if="deviceInfo.type==6">
                                    <el-input readonly></el-input>
                                </el-form-item>
                                <el-form-item label="整跺箱数">
                                    <el-input readonly></el-input>
                                </el-form-item>
                                <el-form-item label="完成箱数">
                                    <el-input readonly></el-input>
                                </el-form-item> -->
                                <!-- <el-form-item label="WMS下发数量">
                                    <el-input v-model="deviceInfo.qty" readonly></el-input>
                                </el-form-item> -->
                                <el-form-item label="状态">
                                    <el-input :value="deviceInfo.plcStatus ? '在线' : '离线'" readonly></el-input>
                                </el-form-item>
                            </el-form>
                        </div>
                        <div class="otherButtonfix">
                            <el-form label-position="left">
                                <el-form-item>
                                    <el-button type="primary" @click="openBindDialog(deviceInfo.id)">绑定</el-button>
                                    <el-button @click="closeBindDialog(deviceInfo.taskId)">解绑</el-button>
                                </el-form-item>
                            </el-form>
                        </div>
                    </el-card>
                </div>
            </el-row>
        </el-col>
        <!-- 绑定任务弹框 -->
        <el-dialog v-model="bindDialogVisible" title="选择数据">
            <el-table :data="bindData" highlight-current-row @row-click="handleRowClick">
                <el-table-column prop="orderNo" label="WMS下发单号" show-overflow-tooltip="" />
                <el-table-column prop="taskNo" label="任务号" show-overflow-tooltip="" />
                <el-table-column prop="lotNo" label="批次号" show-overflow-tooltip="" />
                <el-table-column prop="skuNo" label="物料编码" show-overflow-tooltip="" />
                <el-table-column prop="skuName" label="物料名称" show-overflow-tooltip="" />
                <el-table-column prop="boxType" label="规格" show-overflow-tooltip="" />
                <el-table-column prop="qty" label="总箱数/计划箱数/预估箱数" show-overflow-tooltip="" />
            </el-table>
            <div slot="footer" class="dialog-footer">
                <el-button @click="bindDialogVisible = false">取消</el-button>
                <el-button type="primary" @click="confirmBinding">确认</el-button>
            </div>
        </el-dialog>
    </el-container>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
import { GetWcsPackPlcList, GetWcsStackingRobotList, BindTaskForPLC, UnBindTaskForPLC } from '/@/api/wcs/wcsDevice';
import { pageWcsOderTask } from '/@/api/device/wcsOderTask';
import { ElMessageBox, ElMessage } from 'element-plus';
import { signalR, stopConnection } from './signalR';
//连接signalR 监听变更
onMounted(async () => {
    signalR.off('PublicCheckTask');
    signalR.on('PublicCheckTask', (data: any) => {
        var index = devicePointData.value.findIndex(s => s.id == data.id);
        if (index !== -1) {
            devicePointData.value.splice(index, 1, data);
        }
    });
});
//设备对应工位数据
const devicePointData = ref<any>([]);
//选中设备ID
const selectedDeviceId = ref<any>();
//选中工位ID
const selectedStationId = ref<any>();
const bindDialogVisible = ref(false);
const bindData = ref<any>([]);
const selectedRow = ref<any>(null);
const queryParams = ref<any>({});
const tableParams = ref({
    page: 1,
    pageSize: 20,
    total: 0,
});
//获取设备对应的工位数据
const fetchStationData = async () => {
    const res2 = await GetWcsStackingRobotList();
    debugger;
    devicePointData.value = res2.data.result;
};
fetchStationData();
const handleQuery = async () => {
    var res = await pageWcsOderTask(Object.assign(queryParams.value, tableParams.value));
    bindData.value = res.data.result?.items ?? [];
    tableParams.value.total = res.data.result?.total;
};
//打开绑定弹框
function openBindDialog(id) {
    selectedStationId.value = null;
    selectedRow.value = null;
    selectedStationId.value = id;
    bindDialogVisible.value = true;
    handleQuery();
}
//点击行时设置选中行
function handleRowClick(row) {
    selectedRow.value = row;
}
//确认绑定操作
function confirmBinding() {
    if (selectedRow.value) {
        //手动绑定任务到PLC
        bindTaskForPLC(selectedStationId.value, selectedRow.value.id);
        bindDialogVisible.value = false;
    } else {
        ElMessage.error('请选择要绑定的任务!');
    }
}
const bindTaskForPLC = async (deviceId: any, oderTaskId: any) => {
    const res = await BindTaskForPLC({ deviceId, oderTaskId });
    if (res.status == 200) {
        ElMessage.success('绑定成功!');
        fetchStationData();
    }
}
//解绑操作
function closeBindDialog(id) {
    debugger;
    ElMessageBox.confirm(`确定对该批次任务解绑吗?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
    })
        .then(async () => {
            await closeTaskForPLC(id);
        })
        .catch(() => { });
}
const closeTaskForPLC = async (id: number) => {
    const res = await UnBindTaskForPLC({ id });
    if (res.status == 200) {
        ElMessage.success('解绑成功!');
        fetchStationData();
    }
}
</script>
<style scoped>
.card-page {
    width: 100%;
    height: 50px;
    display: flex;
    text-align: center;
    justify-content: center;
    align-items: center;
    text-align: center;
}
.card-page>button {
    width: 150px;
    height: 30px;
}
.card-container {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 10px;
}
.other-box-card {
    box-sizing: border-box;
    background: linear-gradient(135deg, #66ccff, #3399ff);
}
.lineStatus {
    position: absolute;
    right: 0;
    float: right;
    height: 20px;
    width: 20px;
    border-radius: 20px;
    background-color: #67C23A;
}
.linefix {
    border-bottom: 1px solid rgb(197, 195, 195);
    display: flex;
    align-items: center;
    height: 40px;
    position: relative;
    color: #fff;
}
.otherValuefix {
    width: 100%;
    height: 540px;
    padding: 10px;
    border-bottom: 1px solid rgb(197, 195, 195);
}
.otherButtonfix {
    width: 100%;
    height: 60px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}
.device-status-0 {
    background-color: #58f709;
}
.device-status-1 {
    background-color: red;
}
.dialog-footer {
    display: flex;
    justify-content: flex-end;
    margin-top: 20px;
}
.divDisplay {
    display: none
}
</style>
Web/src/views/device/outboundSorting/signalR.ts
New file
@@ -0,0 +1,45 @@
import * as SignalR from '@microsoft/signalr';
import { getToken } from '/@/utils/axios-utils';
// 初始化SignalR对象
const connection = new SignalR.HubConnectionBuilder()
    .configureLogging(SignalR.LogLevel.Information)
    .withUrl(`${window.__env__.VITE_API_URL}/hubs/CheckTask?token=${getToken()}`, { transport: SignalR.HttpTransportType.WebSockets, skipNegotiation: true })
    .withAutomaticReconnect({
        nextRetryDelayInMilliseconds: () => {
            return 5000; // 每5秒重连一次
        },
    })
    .build();
connection.keepAliveIntervalInMilliseconds = 15 * 1000; // 心跳检测15s
connection.serverTimeoutInMilliseconds = 30 * 60 * 1000; // 超时时间30m
// 启动连接
connection.start().then(() => {
    console.log('启动连接checkTask');
});
// 断开连接
connection.onclose(async () => {
    console.log('断开连接checkTask');
});
// 重连中
connection.onreconnecting(() => {
    console.log('服务器已断线checkTask');
});
// 重连成功
connection.onreconnected(() => {
    console.log('重连成功checkTask');
});
// 关闭连接的方法
async function stopConnection() {
    try {
      await connection.stop();
      console.log('连接已关闭');
    } catch (error) {
      console.error('关闭连接时发生错误:', error);
    }
  }
// connection.on('PublicPlcConn', () => {});
export { connection as signalR,stopConnection };