New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace WCS.Application; |
| | | public interface IPlcDeviceHub |
| | | { |
| | | /// <summary> |
| | | /// 下发设备信息 |
| | | /// </summary> |
| | | /// <param name="context"></param> |
| | | /// <returns></returns> |
| | | Task PublicPlcDevice(WcsDeviceOutput context); |
| | | } |
New file |
| | |
| | | using Admin.NET.Core.Service; |
| | | using DocumentFormat.OpenXml.Office2010.ExcelAc; |
| | | using Furion.InstantMessaging; |
| | | using Microsoft.AspNetCore.SignalR; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace WCS.Application; |
| | | |
| | | /// <summary> |
| | | /// 任务日志集线器 |
| | | /// </summary> |
| | | [MapHub("/hubs/PlcDevice")] |
| | | public class PlcDeviceHub : Hub<IPlcDeviceHub> |
| | | { |
| | | private static readonly IHubContext<PlcDeviceHub, IPlcDeviceHub> _plcDeviceHubContext = App.GetService<IHubContext<PlcDeviceHub, IPlcDeviceHub>>(); |
| | | private static readonly SysCacheService _sysCacheService = App.GetRequiredService<SysCacheService>(); |
| | | private static bool boRunningState = false; |
| | | private static CancellationTokenSource cts;//取消线程标识 |
| | | private static readonly ISqlSugarClient _db = SqlSugarSetup.ITenant.GetConnectionScope(SqlSugarConst.MainConfigId); |
| | | public PlcDeviceHub() |
| | | { |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 连接 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public override async Task OnConnectedAsync() |
| | | { |
| | | var httpContext = Context.GetHttpContext(); |
| | | var userId = (httpContext.User.FindFirst(ClaimConst.UserId)?.Value).ToLong(); |
| | | _sysCacheService.Set("PlcDeviceHub:" + Context.ConnectionId, userId); |
| | | if (!boRunningState) |
| | | { |
| | | //开启读取服务线程 |
| | | boRunningState = true; |
| | | cts = new CancellationTokenSource();//取消线程标识 |
| | | StartRead(); |
| | | } |
| | | await base.OnConnectedAsync(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 断开 |
| | | /// </summary> |
| | | /// <param name="exception"></param> |
| | | /// <returns></returns> |
| | | public override async Task OnDisconnectedAsync(Exception exception) |
| | | { |
| | | _sysCacheService.Remove("PlcDeviceHub:" + Context.ConnectionId); |
| | | //如果没有连接了 就关闭线程不读了 |
| | | if (_sysCacheService.GetKeysByPrefixKey("PlcDeviceHub").Count == 0) |
| | | { |
| | | cts.Cancel(); |
| | | boRunningState = false; |
| | | } |
| | | await base.OnDisconnectedAsync(exception); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 开启读取plc线程 |
| | | /// </summary> |
| | | public static void StartRead() |
| | | { |
| | | Task.Run(() => |
| | | { |
| | | // 用于保存每个设备的初始状态 |
| | | var initialStates = new Dictionary<long, WcsDeviceOutput>(); |
| | | |
| | | var listPlc = _db.Queryable<WcsPlc>().Where(s => s.Type == PLCTypeEnum.StackingMachine || s.Type == PLCTypeEnum.ConveyorLine).ToList(); |
| | | var listPlcId = listPlc.Select(s => s.Id).ToList(); |
| | | var listPlcDevice = _db.Queryable<WcsDevice>().Where(s => s.DeviceType == DeviceTypeEnum.Business && listPlcId.Contains(s.PlcId)).Select<WcsDeviceOutput>().ToList(); |
| | | var listPlcDeviceId = listPlcDevice.Select(s => s.Id).ToList(); |
| | | var listPlcStation = _db.Queryable<WcsPosition>().Where(s => listPlcDeviceId.Contains(s.DeviceId)).ToList(); |
| | | while (true) |
| | | { |
| | | try |
| | | { |
| | | //获取跺机的状态 |
| | | foreach (var modDevice in listPlcDevice) |
| | | { |
| | | //取消线程 |
| | | if (cts.Token.IsCancellationRequested) |
| | | { |
| | | throw new OperationCanceledException(); |
| | | } |
| | | var modPlc = listPlc.Where(s => s.Id == modDevice.Id).FirstOrDefault(); |
| | | //读取plc的值 |
| | | var modConn = PLCTaskAction.listPlcConn.FirstOrDefault(s => s != null && s.PlcId == modDevice.PlcId); |
| | | if (modConn == null) |
| | | { |
| | | modDevice.Status = false; |
| | | continue; |
| | | } |
| | | else |
| | | { |
| | | modDevice.Status = modConn.Connected; |
| | | } |
| | | if (modConn.Connected) |
| | | { |
| | | var listPosition = listPlcStation.Where(s => s.DeviceId == modDevice.Id).ToList(); |
| | | (var result, var plc) = modConn.GetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.PlcPos); |
| | | modDevice.Plc = Convert.ToString(plc); |
| | | (result, var wcs) = modConn.GetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos); |
| | | modDevice.Wcs = Convert.ToString(wcs); |
| | | //任务号 |
| | | var modPositionTask = listPosition.FirstOrDefault(s => s.Text == "任务号"); |
| | | (result, var taskNo) = modConn.GetPlcDBValue(modPositionTask.PosType, modDevice.DbNumber, modPositionTask.PlcPos, modPositionTask.StringLength); |
| | | modDevice.TaskNo = Convert.ToString(taskNo); |
| | | //任务类型 |
| | | var modPositionTaskType = listPosition.FirstOrDefault(s => s.Text == "任务类型"); |
| | | (result, var taskType) = modConn.GetPlcDBValue(modPositionTaskType.PosType, modDevice.DbNumber, modPositionTaskType.PlcPos); |
| | | modDevice.TaskType = (TaskTypeEnum)Convert.ToInt32(taskType); |
| | | //起始工位 |
| | | var modPositionStartLocatNo = listPosition.FirstOrDefault(s => s.Text == "起始工位"); |
| | | (result, var startLocatNo) = modConn.GetPlcDBValue(modPositionStartLocatNo.PosType, modDevice.DbNumber, modPositionStartLocatNo.PlcPos); |
| | | modDevice.StartLocatNo = Convert.ToString(startLocatNo); |
| | | //目的工位 |
| | | var modPositionEndLocatNo = listPosition.FirstOrDefault(s => s.Text == "目的工位"); |
| | | (result, var endLocatNo) = modConn.GetPlcDBValue(modPositionEndLocatNo.PosType, modDevice.DbNumber, modPositionEndLocatNo.PlcPos); |
| | | modDevice.EndLocatNo = Convert.ToString(endLocatNo); |
| | | //托盘码 |
| | | var modPositionPalletNo = listPosition.FirstOrDefault(s => s.Text == "托盘码"); |
| | | (result, var palletNo) = modConn.GetPlcDBValue(modPositionPalletNo.PosType, modDevice.DbNumber, modPositionPalletNo.PlcPos, modPositionPalletNo.StringLength); |
| | | modDevice.PalletNo = Convert.ToString(palletNo); |
| | | if (modPlc.Type == PLCTypeEnum.ConveyorLine) |
| | | { |
| | | //放货排 |
| | | var modPositionReleaseRow = listPosition.FirstOrDefault(s => s.Text == "放货排"); |
| | | (result, var releaseRow) = modConn.GetPlcDBValue(modPositionReleaseRow.PosType, modDevice.DbNumber, modPositionReleaseRow.PlcPos); |
| | | modDevice.ReleaseRow = Convert.ToInt32(releaseRow); |
| | | //放货列 |
| | | var modPositionReleaseCol = listPosition.FirstOrDefault(s => s.Text == "放货列"); |
| | | (result, var releaseCol) = modConn.GetPlcDBValue(modPositionReleaseCol.PosType, modDevice.DbNumber, modPositionReleaseCol.PlcPos); |
| | | modDevice.ReleaseCol = Convert.ToInt32(releaseCol); |
| | | //放货层 |
| | | var modPositionReleaseStorey = listPosition.FirstOrDefault(s => s.Text == "放货层"); |
| | | (result, var releaseStorey) = modConn.GetPlcDBValue(modPositionReleaseStorey.PosType, modDevice.DbNumber, modPositionReleaseStorey.PlcPos); |
| | | modDevice.ReleaseStorey = Convert.ToInt32(releaseStorey); |
| | | //取货排 |
| | | var modPositionPickRow = listPosition.FirstOrDefault(s => s.Text == "取货排"); |
| | | (result, var pickRow) = modConn.GetPlcDBValue(modPositionPickRow.PosType, modDevice.DbNumber, modPositionPickRow.PlcPos); |
| | | modDevice.PickRow = Convert.ToInt32(pickRow); |
| | | //取货列 |
| | | var modPositionPickCol = listPosition.FirstOrDefault(s => s.Text == "取货列"); |
| | | (result, var pickCol) = modConn.GetPlcDBValue(modPositionPickCol.PosType, modDevice.DbNumber, modPositionPickCol.PlcPos); |
| | | modDevice.PickCol = Convert.ToInt32(pickCol); |
| | | //取货层 |
| | | var modPositionPickStorey = listPosition.FirstOrDefault(s => s.Text == "取货层"); |
| | | (result, var pickStorey) = modConn.GetPlcDBValue(modPositionPickStorey.PosType, modDevice.DbNumber, modPositionPickStorey.PlcPos); |
| | | modDevice.PickStorey = Convert.ToInt32(pickStorey); |
| | | } |
| | | } |
| | | // 比较之前的状态 |
| | | if (initialStates.TryGetValue(modDevice.Id, out var initialState)) |
| | | { |
| | | if (modDevice.Status != initialState.Status || |
| | | modDevice.Plc != initialState.Plc || |
| | | modDevice.Wcs != initialState.Wcs || |
| | | modDevice.TaskNo != initialState.TaskNo || |
| | | modDevice.TaskType != initialState.TaskType || |
| | | modDevice.StartLocatNo != initialState.StartLocatNo || |
| | | modDevice.EndLocatNo != initialState.EndLocatNo || |
| | | modDevice.PalletNo != initialState.PalletNo || |
| | | (modPlc.Type == PLCTypeEnum.ConveyorLine && |
| | | (modDevice.ReleaseRow != initialState.ReleaseRow || |
| | | modDevice.ReleaseCol != initialState.ReleaseCol || |
| | | modDevice.ReleaseStorey != initialState.ReleaseStorey || |
| | | modDevice.PickRow != initialState.PickRow || |
| | | modDevice.PickCol != initialState.PickCol || |
| | | modDevice.PickStorey != initialState.PickStorey))) |
| | | { |
| | | // 通知用户变更 |
| | | _plcDeviceHubContext.Clients.All.PublicPlcDevice(modDevice); |
| | | } |
| | | } |
| | | |
| | | initialStates[modDevice.Id] = modDevice.Adapt<WcsDeviceOutput>(); |
| | | |
| | | |
| | | } |
| | | Thread.Sleep(2000); |
| | | } |
| | | catch (Exception) |
| | | { |
| | | |
| | | throw; |
| | | } |
| | | } |
| | | }, cts.Token); |
| | | } |
| | | } |
| | |
| | | /// </summary> |
| | | [Required(ErrorMessage = "起始点位不能为空")] |
| | | public int Pos { get; set; } |
| | | } |
| | | /// <summary> |
| | | /// 写入参数 |
| | | /// </summary> |
| | | public class WriteWcsDeviceInput : WcsDeviceBaseInput |
| | | { |
| | | /// <summary> |
| | | /// 主键Id |
| | | /// </summary> |
| | | [Required(ErrorMessage = "主键Id不能为空")] |
| | | public long Id { get; set; } |
| | | /// <summary> |
| | | /// 任务号 |
| | | /// </summary> |
| | | public string TaskNo { get; set; } |
| | | /// <summary> |
| | | /// 任务类型 |
| | | /// </summary> |
| | | public TaskTypeEnum? TaskType { get; set; } |
| | | /// <summary> |
| | | /// 起始工位 |
| | | /// </summary> |
| | | public string StartLocatNo { get; set; } |
| | | /// <summary> |
| | | /// 结束工位 |
| | | /// </summary> |
| | | public string EndLocatNo { get; set; } |
| | | /// <summary> |
| | | /// 托盘码 |
| | | /// </summary> |
| | | public string PalletNo { get; set; } |
| | | public string Plc { get; set; } |
| | | public string Wcs { get; set; } |
| | | /// <summary> |
| | | /// 连接状态 |
| | | /// </summary> |
| | | public bool Status { get; set; } = false; |
| | | /// <summary> |
| | | /// 放货排 |
| | | /// </summary> |
| | | public int ReleaseRow { get; set; } |
| | | /// <summary> |
| | | /// 放货列 |
| | | /// </summary> |
| | | public int ReleaseCol { get; set; } |
| | | /// <summary> |
| | | /// 放货层 |
| | | /// </summary> |
| | | public int ReleaseStorey { get; set; } |
| | | /// <summary> |
| | | /// 取货排 |
| | | /// </summary> |
| | | public int PickRow { get; set; } |
| | | /// <summary> |
| | | /// 取货列 |
| | | /// </summary> |
| | | public int PickCol { get; set; } |
| | | /// <summary> |
| | | /// 取货层 |
| | | /// </summary> |
| | | public int PickStorey { get; set; } |
| | | } |
| | |
| | | /// 连接状态 |
| | | /// </summary> |
| | | public bool Status { get; set; } = false; |
| | | |
| | | |
| | | /// <summary> |
| | | /// 放货排 |
| | | /// </summary> |
| | | public int ReleaseRow { get; set; } |
| | | /// <summary> |
| | | /// 放货列 |
| | | /// </summary> |
| | | public int ReleaseCol { get; set; } |
| | | /// <summary> |
| | | /// 放货层 |
| | | /// </summary> |
| | | public int ReleaseStorey { get; set; } |
| | | /// <summary> |
| | | /// 取货排 |
| | | /// </summary> |
| | | public int PickRow { get; set; } |
| | | /// <summary> |
| | | /// 取货列 |
| | | /// </summary> |
| | | public int PickCol { get; set; } |
| | | /// <summary> |
| | | /// 取货层 |
| | | /// </summary> |
| | | public int PickStorey { get; set; } |
| | | } |
| | | |
| | | |
| | |
| | | var modPositionPalletNo = listPosition.FirstOrDefault(s => s.Text == "托盘码"); |
| | | (result, var palletNo) = modConn.GetPlcDBValue(modPositionPalletNo.PosType, modDevice.DbNumber, modPositionPalletNo.PlcPos, modPositionPalletNo.StringLength); |
| | | modDevice.PalletNo = Convert.ToString(palletNo); |
| | | if (cachePlc.Type == PLCTypeEnum.ConveyorLine) |
| | | { |
| | | //放货排 |
| | | var modPositionReleaseRow = listPosition.FirstOrDefault(s => s.Text == "放货排"); |
| | | (result, var releaseRow) = modConn.GetPlcDBValue(modPositionReleaseRow.PosType, modDevice.DbNumber, modPositionReleaseRow.PlcPos); |
| | | modDevice.ReleaseRow = Convert.ToInt32(releaseRow); |
| | | //放货列 |
| | | var modPositionReleaseCol = listPosition.FirstOrDefault(s => s.Text == "放货列"); |
| | | (result, var releaseCol) = modConn.GetPlcDBValue(modPositionReleaseCol.PosType, modDevice.DbNumber, modPositionReleaseCol.PlcPos); |
| | | modDevice.ReleaseCol = Convert.ToInt32(releaseCol); |
| | | //放货层 |
| | | var modPositionReleaseStorey = listPosition.FirstOrDefault(s => s.Text == "放货层"); |
| | | (result, var releaseStorey) = modConn.GetPlcDBValue(modPositionReleaseStorey.PosType, modDevice.DbNumber, modPositionReleaseStorey.PlcPos); |
| | | modDevice.ReleaseStorey = Convert.ToInt32(releaseStorey); |
| | | //取货排 |
| | | var modPositionPickRow = listPosition.FirstOrDefault(s => s.Text == "取货排"); |
| | | (result, var pickRow) = modConn.GetPlcDBValue(modPositionPickRow.PosType, modDevice.DbNumber, modPositionPickRow.PlcPos); |
| | | modDevice.PickRow = Convert.ToInt32(pickRow); |
| | | //取货列 |
| | | var modPositionPickCol = listPosition.FirstOrDefault(s => s.Text == "取货列"); |
| | | (result, var pickCol) = modConn.GetPlcDBValue(modPositionPickCol.PosType, modDevice.DbNumber, modPositionPickCol.PlcPos); |
| | | modDevice.PickCol = Convert.ToInt32(pickCol); |
| | | //取货层 |
| | | var modPositionPickStorey = listPosition.FirstOrDefault(s => s.Text == "取货层"); |
| | | (result, var pickStorey) = modConn.GetPlcDBValue(modPositionPickStorey.PosType, modDevice.DbNumber, modPositionPickStorey.PlcPos); |
| | | modDevice.PickStorey = Convert.ToInt32(pickStorey); |
| | | |
| | | } |
| | | } |
| | | catch (Exception) |
| | | { |
| | |
| | | } |
| | | |
| | | return list; |
| | | } |
| | | |
| | | [HttpPost] |
| | | [ApiDescriptionSettings(Name = "WriteValue")] |
| | | [DisplayName("写入值")] |
| | | public async Task WriteValue(WriteWcsDeviceInput modDevice) |
| | | { |
| | | var modPlc = await _wcsDeviceRep.Context.Queryable<WcsPlc>().FirstAsync(s => s.Id == modDevice.PlcId); |
| | | if (modPlc == null) |
| | | throw Oops.Bah("找不到PLC信息"); |
| | | PLCUtil modUtil = new PLCUtil(modPlc); |
| | | var listPosition = await _wcsDeviceRep.Context.Queryable<WcsPosition>().Where(s => s.DeviceId == modDevice.Id).ToListAsync(); |
| | | //(var result, var plc) = modConn.GetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.PlcPos); |
| | | //modDevice.Plc = Convert.ToString(plc); |
| | | //任务号 |
| | | var modPositionTask = listPosition.FirstOrDefault(s => s.Text == "任务号"); |
| | | if (modPositionTask != null) |
| | | modUtil.SetPlcDBValue(modPositionTask.PosType, modPositionTask.PlcPos, modDevice.TaskNo); |
| | | //任务类型 |
| | | var modPositionTaskType = listPosition.FirstOrDefault(s => s.Text == "任务类型"); |
| | | if (modPositionTaskType != null) |
| | | modUtil.SetPlcDBValue(modPositionTaskType.PosType, modPositionTaskType.PlcPos, modDevice.TaskType.ToString()); |
| | | //起始工位 |
| | | var modPositionStartLocatNo = listPosition.FirstOrDefault(s => s.Text == "起始工位"); |
| | | if (modPositionStartLocatNo != null) |
| | | modUtil.SetPlcDBValue(modPositionStartLocatNo.PosType, modPositionStartLocatNo.PlcPos, modDevice.StartLocatNo.ToString()); |
| | | //目的工位 |
| | | var modPositionEndLocatNo = listPosition.FirstOrDefault(s => s.Text == "目的工位"); |
| | | if (modPositionEndLocatNo != null) |
| | | modUtil.SetPlcDBValue(modPositionEndLocatNo.PosType, modPositionEndLocatNo.PlcPos, modDevice.EndLocatNo.ToString()); |
| | | //托盘码 |
| | | var modPositionPalletNo = listPosition.FirstOrDefault(s => s.Text == "托盘码"); |
| | | if (modPositionPalletNo != null) |
| | | modUtil.SetPlcDBValue(modPositionPalletNo.PosType, modPositionPalletNo.PlcPos, modDevice.PalletNo.ToString()); |
| | | if (modPlc.Type == PLCTypeEnum.ConveyorLine) |
| | | { |
| | | //放货排 |
| | | var modPositionReleaseRow = listPosition.FirstOrDefault(s => s.Text == "放货排"); |
| | | if (modPositionReleaseRow != null) |
| | | modUtil.SetPlcDBValue(modPositionReleaseRow.PosType, modPositionReleaseRow.PlcPos, modDevice.ReleaseRow.ToString()); |
| | | //放货列 |
| | | var modPositionReleaseCol = listPosition.FirstOrDefault(s => s.Text == "放货列"); |
| | | if (modPositionReleaseRow != null) |
| | | modUtil.SetPlcDBValue(modPositionReleaseCol.PosType, modPositionReleaseCol.PlcPos, modDevice.ReleaseCol.ToString()); |
| | | //放货层 |
| | | var modPositionReleaseStorey = listPosition.FirstOrDefault(s => s.Text == "放货层"); |
| | | if (modPositionReleaseStorey != null) |
| | | modUtil.SetPlcDBValue(modPositionReleaseStorey.PosType, modPositionReleaseStorey.PlcPos, modDevice.ReleaseStorey.ToString()); |
| | | //取货排 |
| | | var modPositionPickRow = listPosition.FirstOrDefault(s => s.Text == "取货排"); |
| | | if (modPositionPickRow != null) |
| | | modUtil.SetPlcDBValue(modPositionPickRow.PosType, modPositionPickRow.PlcPos, modDevice.PickRow.ToString()); |
| | | //取货列 |
| | | var modPositionPickCol = listPosition.FirstOrDefault(s => s.Text == "取货列"); |
| | | if (modPositionPickCol != null) |
| | | modUtil.SetPlcDBValue(modPositionPickCol.PosType, modPositionPickCol.PlcPos, modDevice.PickCol.ToString()); |
| | | //取货层 |
| | | var modPositionPickStorey = listPosition.FirstOrDefault(s => s.Text == "取货层"); |
| | | if (modPositionPickStorey != null) |
| | | modUtil.SetPlcDBValue(modPositionPickStorey.PosType, modPositionPickStorey.PlcPos, modDevice.PickStorey.ToString()); |
| | | |
| | | } |
| | | modUtil.Close(); |
| | | } |
| | | |
| | | #region 分拣码垛 |
| | |
| | | [HttpGet] |
| | | [ApiDescriptionSettings(Name = "WcsPackStationPlcList")] |
| | | [DisplayName("获取设备对应工位列表")] |
| | | public async Task<List<WcsDeviceTaskOrderDto>> WcsPackStationPlcList([FromQuery]WcsDeviceBaseInput entry) |
| | | { |
| | | public async Task<List<WcsDeviceTaskOrderDto>> WcsPackStationPlcList([FromQuery] WcsDeviceBaseInput entry) |
| | | { |
| | | return await _wcsDeviceRep.Context.Queryable<WcsDevice>() |
| | | .LeftJoin<WcsCheckTask>((device, task) => device.StationNum == task.Port) |
| | | .Where((device, task) => device.PlcId == entry.PlcId) |
| | | .OrderBy((device, task) => device.CreateTime) |
| | | .Select((device, task) => new WcsDeviceTaskOrderDto() |
| | | { |
| | | Id=device.Id, |
| | | Text=device.Text, |
| | | OrderNo=task.OrderNo, |
| | | LotNo=task.LotNo, |
| | | SkuNo=task.SkuNo, |
| | | SkuName=task.SkuName, |
| | | Status=task.Status, |
| | | Qty=task.Qty |
| | | Id = device.Id, |
| | | Text = device.Text, |
| | | OrderNo = task.OrderNo, |
| | | LotNo = task.LotNo, |
| | | SkuNo = task.SkuNo, |
| | | SkuName = task.SkuName, |
| | | Status = task.Status, |
| | | Qty = task.Qty |
| | | }) |
| | | .ToListAsync(); |
| | | } |
| | |
| | | GetWcsPlcPlcIdDropdown = '/api/wcsDevice/WcsPlcPlcIdDropdown', |
| | | GeneratePos = '/api/wcsDevice/GeneratePos', |
| | | ListWcsDevice = '/api/wcsDevice/list', |
| | | WriteValue = '/api/wcsdevice/writeValue', |
| | | |
| | | GetWcsPackPlcList='/api/wcsDevice/WcsPackPlcList', |
| | | GetWcsPackStationPlcList='/api/wcsDevice/WcsPackStationPlcList', |
| | |
| | | url: Api.CloseTaskForPLC, |
| | | method: 'post', |
| | | data: params, |
| | | }); |
| | | //写入值 |
| | | export const writeValue = (params?: any) => |
| | | request({ |
| | | url: Api.WriteValue, |
| | | method: 'post', |
| | | data: params, |
| | | }); |
| | |
| | | <el-card class="box-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | |
| | | |
| | | <div> |
| | | <span>工位号:</span> |
| | | <el-select v-model="stationValue" placeholder="请选择" filterable value-key="stationNum" |
| | |
| | | <el-button style="margin-left: 10px;">自动</el-button> |
| | | </div> |
| | | <div> |
| | | <div :class="['lineStatus', stationValue.status ? 'device-status-0' : 'device-status-1']"></div> |
| | | <div :class="['lineStatus', stationValue.status ? 'device-status-0' : 'device-status-1']"> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | |
| | | <el-input v-model="stationValue.wcs"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="取货排"> |
| | | <el-input ></el-input> |
| | | <el-input></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="放货排"> |
| | | <el-input ></el-input> |
| | | <el-input></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="取货列"> |
| | | <el-input ></el-input> |
| | | <el-input></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="放货列"> |
| | | <el-input ></el-input> |
| | | <el-input></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="取货层"> |
| | | <el-input ></el-input> |
| | | <el-input></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="放货层"> |
| | | <el-input ></el-input> |
| | | <el-input></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <div style="text-align: center;margin: 10px;"> |
| | | <el-button class="button" size="large">写入数据</el-button> |
| | | <el-button class="button" size="large" @click="write(stationValue)">写入数据</el-button> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | |
| | | |
| | | <script lang="ts" setup> |
| | | import { ref, defineModel } from 'vue'; |
| | | import { writeValue } from '/@/api/wcs/wcsDevice'; |
| | | import { ElMessageBox,ElMessage } from 'element-plus'; |
| | | const listStationsData = defineModel<any>("listStationsData") |
| | | const stationValue = defineModel<any>("stationValue") |
| | | |
| | |
| | | // emit('update:listStationsData', listStationsData.value); |
| | | // emit('update:stationValue', stationValue); |
| | | // }; |
| | | |
| | | const write = async (row: any) => { |
| | | await writeValue(row); |
| | | ElMessage.success('写入成功!'); |
| | | } |
| | | const isShowDialog = ref(false); |
| | | |
| | | const openDialog = async (row: any) => { |
| | |
| | | } |
| | | |
| | | .lineStatus { |
| | | right: 0; |
| | | height: 20px; |
| | | width: 20px; |
| | | border-radius: 50%; |
| | | background-color: #67C23A; |
| | | right: 0; |
| | | height: 20px; |
| | | width: 20px; |
| | | border-radius: 50%; |
| | | background-color: #67C23A; |
| | | } |
| | | |
| | | .device-status-0 { |
| | | background-color: #67C23A; |
| | | background-color: #67C23A; |
| | | } |
| | | |
| | | .device-status-1 { |
| | | background-color: red; |
| | | background-color: red; |
| | | } |
| | | </style> |
| | |
| | | <div class="lineButtonfix"> |
| | | <el-form label-position="left" label-width="80px"> |
| | | <el-form-item> |
| | | <el-button>写入</el-button> |
| | | <el-button @click="openDialog">设置</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | |
| | | <el-form-item label="目的工位"> |
| | | <el-input v-model="deviceInfo.endLocatNo"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="托盘码"> |
| | | <el-input v-model="deviceInfo.palletNo"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="PLC"> |
| | | <el-input v-model="deviceInfo.plc"></el-input> |
| | | </el-form-item> |
| | |
| | | <div class="otherButtonfix"> |
| | | <el-form label-position="left"> |
| | | <el-form-item> |
| | | <el-button>写入</el-button> |
| | | <el-button @click="write(deviceInfo)">写入</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </el-card> |
| | | </div> |
| | | </el-main> |
| | | <setting ref="settingDialogRef" :title="title" v-model:listStationsData="listStationsData" v-model:stationValue="stationValue" /> |
| | | <setting ref="settingDialogRef" :title="title" v-model:listStationsData="listStationsData" |
| | | v-model:stationValue="stationValue" /> |
| | | </el-container> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { ref, reactive } from 'vue'; |
| | | import { listWcsDevice } from '/@/api/wcs/wcsDevice'; |
| | | import { ref, onMounted } from 'vue'; |
| | | import { listWcsDevice, writeValue } from '/@/api/wcs/wcsDevice'; |
| | | import { getDictDataItem as di, getDictDataList as dl } from '/@/utils/dict-utils'; |
| | | import { listWcsPlc } from '/@/api/wcs/wcsPlc'; |
| | | |
| | | import { ElMessageBox, ElMessage } from 'element-plus'; |
| | | import setting from '/@/views/device/deviceMonitor/component/setting.vue' |
| | | import { signalR } from './signalR'; |
| | | //连接signalR 监听变更 |
| | | onMounted(async () => { |
| | | signalR.off('PublicPlcDevice'); |
| | | signalR.on('PublicPlcDevice', (data: any) => { |
| | | //todo 需要测试 |
| | | if (data.type == 0) { |
| | | var index = listStackingMachineData.value.findIndex(s => s.id == data.id); |
| | | if (index !== -1) { |
| | | listStackingMachineData.value.splice(index, 1, data); |
| | | } |
| | | } |
| | | else if (data.type == 1) { |
| | | stations.value.forEach(list => { |
| | | var index = list.findIndex(s => s.id == data.id); |
| | | if (index !== -1) { |
| | | list.splice(index, 1, data); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | }); |
| | | |
| | | const stations = ref<any>([]); |
| | | const listStationsData = ref<any>([]); |
| | |
| | | const openDialog = async () => { |
| | | settingDialogRef.value.openDialog(stationValue); |
| | | } |
| | | const write = async (row: any) => { |
| | | await writeValue(row); |
| | | ElMessage.success('写入成功!'); |
| | | } |
| | | // 查询操作 |
| | | const handleQuery = async () => { |
| | | var listplc = await listWcsPlc({ type: 1 }); |
| | |
| | | listStationsData.value = stations.value[lineValue.value]; |
| | | stationValue.value = listStationsData.value[0]; |
| | | } |
| | | else { |
| | | listStationsData.value = []; |
| | | stationValue.value = { |
| | | stationNum: '', |
| | | taskNo: '', |
| | | taskType: '', |
| | | startLocatNo: '', |
| | | endLocatNo: '', |
| | | plc: '', |
| | | wcs: '', |
| | | status: false |
| | | }; |
| | | } |
| | | title.value = listStationsData.value[0].text; |
| | | }; |
| | | |
New file |
| | |
| | | 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/PlcDevice?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('启动连接plc'); |
| | | }); |
| | | // 断开连接 |
| | | connection.onclose(async () => { |
| | | console.log('断开连接plc'); |
| | | }); |
| | | // 重连中 |
| | | connection.onreconnecting(() => { |
| | | console.log('服务器已断线plc'); |
| | | }); |
| | | // 重连成功 |
| | | connection.onreconnected(() => { |
| | | console.log('重连成功plc'); |
| | | }); |
| | | |
| | | // connection.on('PublicPlcConn', () => {}); |
| | | |
| | | export { connection as signalR }; |