This commit is contained in:
2025-03-28 09:33:30 +08:00
parent 9b41d2e99e
commit 8f17b0435e
9 changed files with 709 additions and 79 deletions

View File

@@ -0,0 +1,102 @@
using Microsoft.AspNetCore.Mvc;
using DOAN.Model.PBL.Dto;
using DOAN.Model.PBL;
using DOAN.Service.PBL.IPBLService;
using DOAN.Admin.WebApi.Filters;
//创建时间2025-02-22
namespace DOAN.Admin.WebApi.Controllers.PBL
{
/// <summary>
/// 库存报警日志
/// </summary>
[Verify]
[Route("PBL/AlarmLog")]
public class AlarmLogController : BaseController
{
/// <summary>
/// 库存报警日志接口
/// </summary>
private readonly IAlarmLogService _AlarmLogService;
public AlarmLogController(IAlarmLogService AlarmLogService)
{
_AlarmLogService = AlarmLogService;
}
/// <summary>
/// 查询库存报警日志列表
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
[HttpGet("list")]
[ActionPermissionFilter(Permission = "alarmlog:list")]
public IActionResult QueryAlarmLog([FromQuery] AlarmLogQueryDto parm)
{
var response = _AlarmLogService.GetList(parm);
return SUCCESS(response);
}
/// <summary>
/// 查询库存报警日志详情
/// </summary>
/// <param name="Id"></param>
/// <returns></returns>
[HttpGet("{Id}")]
[ActionPermissionFilter(Permission = "alarmlog:query")]
public IActionResult GetAlarmLog(string Id)
{
var response = _AlarmLogService.GetInfo(Id);
var info = response.Adapt<AlarmLogDto>();
return SUCCESS(info);
}
/// <summary>
/// 添加库存报警日志
/// </summary>
/// <returns></returns>
[HttpPost]
[ActionPermissionFilter(Permission = "alarmlog:add")]
[Log(Title = "库存报警日志", BusinessType = BusinessType.INSERT)]
public IActionResult AddAlarmLog([FromBody] AlarmLogDto parm)
{
var modal = parm.Adapt<AlarmLog>().ToCreate(HttpContext);
var response = _AlarmLogService.AddAlarmLog(modal);
return SUCCESS(response);
}
/// <summary>
/// 更新库存报警日志
/// </summary>
/// <returns></returns>
[HttpPut]
[ActionPermissionFilter(Permission = "alarmlog:edit")]
[Log(Title = "库存报警日志", BusinessType = BusinessType.UPDATE)]
public IActionResult UpdateAlarmLog([FromBody] AlarmLogDto parm)
{
var modal = parm.Adapt<AlarmLog>().ToUpdate(HttpContext);
var response = _AlarmLogService.UpdateAlarmLog(modal);
return ToResponse(response);
}
/// <summary>
/// 删除库存报警日志
/// </summary>
/// <returns></returns>
[HttpPost("delete/{ids}")]
[ActionPermissionFilter(Permission = "alarmlog:delete")]
[Log(Title = "库存报警日志", BusinessType = BusinessType.DELETE)]
public IActionResult DeleteAlarmLog([FromRoute]string ids)
{
var idArr = Tools.SplitAndConvert<string>(ids);
return ToResponse(_AlarmLogService.Delete(idArr));
}
}
}

View File

@@ -0,0 +1,60 @@
namespace DOAN.Model.PBL
{
/// <summary>
/// 库存报警日志
/// </summary>
[SugarTable("alarm_log")]
public class AlarmLog
{
/// <summary>
/// 主键
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
public string Id { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 料架id
/// </summary>
[SugarColumn(ColumnName = "storagelocation_id")]
public int? StoragelocationId { get; set; }
/// <summary>
/// 系统类别
/// </summary>
public int? Type { get; set; }
/// <summary>
/// 系统状态
/// </summary>
public int? Status { get; set; }
/// <summary>
/// 系统备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 发生时间
/// </summary>
[SugarColumn(ColumnName = "action_time")]
public DateTime? ActionTime { get; set; }
/// <summary>
/// 完成报警时间
/// </summary>
[SugarColumn(ColumnName = "end_time")]
public DateTime? EndTime { get; set; }
}
}

View File

@@ -0,0 +1,48 @@
namespace DOAN.Model.PBL.Dto
{
/// <summary>
/// 库存报警日志查询对象
/// </summary>
public class AlarmLogQueryDto : PagerInfo
{
public string Name { get; set; }
public string Code { get; set; }
public int? StoragelocationId { get; set; }
public int? Type { get; set; }
public int? Status { get; set; }
public DateTime? StartTime { get; set; }
public DateTime? EndTime { get; set; }
}
/// <summary>
/// 库存报警日志输入输出对象
/// </summary>
public class AlarmLogDto
{
[Required(ErrorMessage = "主键不能为空")]
public string Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public int? StoragelocationId { get; set; }
public int? Type { get; set; }
public int? Status { get; set; }
public string Remark { get; set; }
public DateTime? ActionTime { get; set; }
public DateTime? EndTime { get; set; }
[ExcelColumn(Name = "系统类别")]
public string TypeLabel { get; set; }
}
}

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DOAN.Model.PBL
{
/// <summary>
/// PLC地址
/// </summary>
[SugarTable("plc_button_table")]
public class PlcButton
{
/// <summary>
/// 主键
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
public int Id { get; set; }
/// <summary>
/// 按钮名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 按钮型号
/// </summary>
public string Code { get; set; }
/// <summary>
/// 料架id
/// </summary>
[SugarColumn(ColumnName = "storagelocation_id")]
public int StoragelocationId { get; set; }
/// <summary>
/// PLC地址
/// </summary>
public int Address { get; set; }
/// <summary>
/// PLC地址下标
/// </summary>
public int Index { get; set; }
}
}

View File

@@ -0,0 +1,87 @@
using Infrastructure.Attribute;
using Infrastructure.Extensions;
using DOAN.Model.PBL.Dto;
using DOAN.Model.PBL;
using DOAN.Repository;
using DOAN.Service.PBL.IPBLService;
namespace DOAN.Service.PBL
{
/// <summary>
/// 库存报警日志Service业务层处理
/// </summary>
[AppService(ServiceType = typeof(IAlarmLogService), ServiceLifetime = LifeTime.Transient)]
public class AlarmLogService : BaseService<AlarmLog>, IAlarmLogService
{
/// <summary>
/// 查询库存报警日志列表
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
public PagedInfo<AlarmLogDto> GetList(AlarmLogQueryDto parm)
{
var predicate = QueryExp(parm);
var response = Queryable()
.Where(predicate.ToExpression())
.ToPage<AlarmLog, AlarmLogDto>(parm);
return response;
}
/// <summary>
/// 获取详情
/// </summary>
/// <param name="Id"></param>
/// <returns></returns>
public AlarmLog GetInfo(string Id)
{
var response = Queryable()
.Where(x => x.Id == Id)
.First();
return response;
}
/// <summary>
/// 添加库存报警日志
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public AlarmLog AddAlarmLog(AlarmLog model)
{
return Insertable(model).ExecuteReturnEntity();
}
/// <summary>
/// 修改库存报警日志
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public int UpdateAlarmLog(AlarmLog model)
{
return Update(model, true);
}
/// <summary>
/// 查询导出表达式
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
private static Expressionable<AlarmLog> QueryExp(AlarmLogQueryDto parm)
{
var predicate = Expressionable.Create<AlarmLog>()
.AndIF(!string.IsNullOrEmpty(parm.Name),it =>it.Name.Contains(parm.Name))
.AndIF(!string.IsNullOrEmpty(parm.Code), it => it.Code.Contains(parm.Code))
.AndIF(parm.Type > -1, it => it.Type == parm.Type)
.AndIF(parm.Status > -1, it => it.Status == parm.Status)
.AndIF(parm.StoragelocationId > -1, it => it.StoragelocationId == parm.StoragelocationId)
.AndIF(parm.StartTime.HasValue, it => it.ActionTime >= parm.StartTime)
.AndIF(parm.EndTime.HasValue, it => it.ActionTime <= parm.EndTime)
;
return predicate;
}
}
}

View File

@@ -142,7 +142,8 @@ public class BigScreenService : BaseService<Storagelocation>, IBigScreenService
AlarmNum = layer.AlarmNum ?? 2, // 确认默认值
PackageNum = layer.PackageNum ?? 0,
IsLight = layer.IsLight == 1,
IsFeedingMaterial = (layer.PackageNum ?? 0) <= (layer.AlarmNum ?? 2) && layer.IsLackAlarm == 1
// IsFeedingMaterial = (layer.PackageNum ?? 0) < (layer.AlarmNum ?? 2) && layer.IsLackAlarm == 1
IsFeedingMaterial = CalculateIsOneLayerNumFeedingMaterial(layer)
}).ToArray();
var rackDto = new BigScreenDto
{
@@ -150,7 +151,8 @@ public class BigScreenService : BaseService<Storagelocation>, IBigScreenService
RackCode = group.Key,
IsLight = layers.Any(l => l.IsLight == 1),
IsInUse = layers.Any(l => l.IsLackAlarm == 1),
IsFeedingMaterial = layers.Any(l => (l.PackageNum ?? 0) <= (l.AlarmNum ?? 2) && l.IsLackAlarm == 1),
// IsFeedingMaterial = layers.Any(l => (l.PackageNum ?? 0) < (l.AlarmNum ?? 2) && l.IsLackAlarm == 1),
IsFeedingMaterial = CalculateIsAllFeedingMaterial(layers),
LayerObjectArray = layerObjects
};
result.Add(rackDto);
@@ -158,4 +160,40 @@ public class BigScreenService : BaseService<Storagelocation>, IBigScreenService
return result;
}
// 将复杂逻辑封装到方法中
private bool CalculateIsAllFeedingMaterial(List<Storagelocation> layers)
{
int OneTotalPackageNum = layers.Where(it => it.LayerNum == 1).Sum(it => it.PackageNum ?? 0);
int SecondTotalPackageNum = layers.Where(it => it.LayerNum == 2).Sum(it => it.PackageNum ?? 0);
int alarmNum = 2;
if (layers.Any(ls => ls.Remark == "合并料架"))
{
alarmNum = 3;
}
else
{
alarmNum = layers[0].AlarmNum ?? 0;
}
return OneTotalPackageNum < alarmNum || SecondTotalPackageNum < alarmNum;
}
private bool CalculateIsOneLayerNumFeedingMaterial(Storagelocation layer)
{
if (layer.Remark == "合并料架")
{
int totalPackageNum = Context.Queryable<Storagelocation>()
.Where(it => it.LayerNum == layer.LayerNum)
.Where(it => it.RackCode == layer.RackCode)
.Sum(it => it.PackageNum ?? 0);
return totalPackageNum < 3;
}
else
{
return (layer.PackageNum ?? 0) < (layer.AlarmNum ?? 2) && layer.IsLackAlarm == 1;
}
}
}

View File

@@ -0,0 +1,21 @@
using DOAN.Model.PBL.Dto;
using DOAN.Model.PBL;
namespace DOAN.Service.PBL.IPBLService
{
/// <summary>
/// 库存报警日志service接口
/// </summary>
public interface IAlarmLogService : IBaseService<AlarmLog>
{
PagedInfo<AlarmLogDto> GetList(AlarmLogQueryDto parm);
AlarmLog GetInfo(string Id);
AlarmLog AddAlarmLog(AlarmLog parm);
int UpdateAlarmLog(AlarmLog parm);
}
}

View File

@@ -8,7 +8,9 @@ using Mapster;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.SignalR;
using Newtonsoft.Json.Linq;
using System;
using System.Security.Cryptography.X509Certificates;
using static System.Formats.Asn1.AsnWriter;
namespace DOAN.Service.PBL
{
@@ -39,77 +41,154 @@ namespace DOAN.Service.PBL
/// <returns></returns>
public bool MESLightUp(LightUpDto light, PLCTool pLCTool)
{
int result = 0;
// 1.记录MES交互记录
MES_Interation_Log item = light.Adapt<MES_Interation_Log>();
item.Id = XUEHUA;
item.CreatedTime = DateTime.Now;
Context.Insertable(item).ExecuteCommand();
// 2.根据总成零件号 ,版本 查询对应零件号,使得对应料架亮灯
List<Storagelocation> MirrorshellShelfList = Context
.Queryable<Storagelocation>()
.Where(it =>
it.Partnumber
== SqlFunc
.Subqueryable<Billofmaterials>()
.Where(It => It.Productcode == light.AssemblyPartNumber)
.Select(it => it.MirrorshellCode)
)
.ToList();
if (MirrorshellShelfList != null && MirrorshellShelfList.Count() > 0)
try
{
Storagelocation storagelocation = new();
// 是否合并料架
bool isMergeRack = MirrorshellShelfList.Count > 1;
if (isMergeRack)
Context.Ado.BeginTran();
int result = 0;
// 1.记录MES交互记录
MES_Interation_Log item = light.Adapt<MES_Interation_Log>();
item.Id = XUEHUA;
item.CreatedTime = DateTime.Now;
Context.Insertable(item).ExecuteCommand();
// 2.根据总成零件号 ,版本 查询对应零件号,使得对应料架亮灯
List<Storagelocation> MirrorshellShelfList = Context
.Queryable<Storagelocation>()
.Where(it =>
it.Partnumber
== SqlFunc
.Subqueryable<Billofmaterials>()
.Where(It => It.Productcode == light.AssemblyPartNumber)
.Select(it => it.MirrorshellCode)
)
.ToList();
if (MirrorshellShelfList != null && MirrorshellShelfList.Count() > 0)
{
// 合并料架 判断先进先出
foreach(var shelf in MirrorshellShelfList)
Storagelocation storagelocation = new();
// 是否合并料架
bool isMergeRack = MirrorshellShelfList.Count > 1;
if (isMergeRack)
{
// 第一个有箱子的
if(shelf.PackageNum > 0)
Storagelocation leftShelf = MirrorshellShelfList[0];
Storagelocation rightShelf = MirrorshellShelfList[1];
// 料架今天是否有补料信息 (补料完成信号判定)
var today = DateTime.Today;
bool hasAlarm = Context.Queryable<AlarmLog>()
.Where(it => it.ActionTime != null &&
it.ActionTime >= today &&
it.ActionTime < today.AddDays(1))
.Where(it => it.StoragelocationId == leftShelf.Id || it.StoragelocationId == rightShelf.Id)
.OrderByDescending(it => it.ActionTime)
.Any();
int packageTotal = leftShelf.PackageNum.Value + rightShelf.PackageNum.Value;
//1. 在今日有补料信号的前提下 料架>6箱已补料,未消耗最新箱,先消耗旧箱,哪边存在报警补哪边)
if (packageTotal == 8 && hasAlarm)
{
storagelocation = shelf;
continue;
if (leftShelf.IsLackAlarm == 1)
{
storagelocation = leftShelf;
}
else if (rightShelf.IsLackAlarm == 1)
{
storagelocation = rightShelf;
}
else
{
storagelocation = rightShelf;
}
}
else if (packageTotal == 7 && hasAlarm)
{
if (leftShelf.IsLackAlarm == 1)
{
storagelocation = leftShelf;
}
else if (rightShelf.IsLackAlarm == 1)
{
storagelocation = rightShelf;
}
else
{
storagelocation = rightShelf;
}
// 切换报警
DoChangeAlarmStatus(leftShelf, rightShelf);
}
else if (packageTotal <= 6 && packageTotal > 4 && hasAlarm)
{
if (leftShelf.IsLackAlarm == 1)
{
storagelocation = rightShelf;
}
else if (rightShelf.IsLackAlarm == 1)
{
storagelocation = leftShelf;
}
else
{
storagelocation = rightShelf;
}
}
else
{
// 默认情况
// 合并料架 判断 20250224 左先出原则
foreach (var shelf in MirrorshellShelfList)
{
// 第一个有箱子的料架
if (shelf.PackageNum > 0)
{
storagelocation = shelf;
break;
}
}
if (storagelocation.RackCode == null)
{
storagelocation = MirrorshellShelfList[^1];
}
}
}
if (storagelocation.RackCode == null)
else
{
storagelocation = MirrorshellShelfList[^1];
// 单独料架
storagelocation = MirrorshellShelfList[0];
}
// 3.对应料架亮灯
bool isSucesss = pLCTool.WriteBit(storagelocation.PlcAddress, true);
if (isSucesss)
{
storagelocation.IsLight = 1;
result += Context.Updateable(storagelocation).ExecuteCommand();
}
//亮灯日志
Light_Log light_Log = new Light_Log();
light_Log.Id = XUEHUA;
light_Log.LightOperation = 1;
light_Log.Operationer = "PBL";
light_Log.CreatedTime = DateTime.Now;
light_Log.ShelfCode = storagelocation.RackCode;
light_Log.LayerNum = storagelocation.LayerNum;
light_Log.IsSuccess = isSucesss;
result += Context.Insertable(light_Log).ExecuteCommand();
}
else
{
// 单独料架
storagelocation = MirrorshellShelfList[0];
// 发送socket 通知
string message =
$"MES产品编号{light.AssemblyPartNumber}或者版本{light.Version},在PBL中找不到。请维护PBL料架信息--{DateTime.Now}";
notificationHubContext.Clients.All.SendAsync("PBL_bom_except", message);
Context.Ado.RollbackTran();
return false;
}
// 3.对应料架亮灯
bool isSucesss = pLCTool.WriteBit(storagelocation.PlcAddress, true);
if (isSucesss) {
storagelocation.IsLight = 1;
result += Context.Updateable(storagelocation).ExecuteCommand();
}
//亮灯日志
Light_Log light_Log = new Light_Log();
light_Log.Id = XUEHUA;
light_Log.LightOperation = 1;
light_Log.Operationer = "PBL";
light_Log.CreatedTime = DateTime.Now;
light_Log.ShelfCode = storagelocation.RackCode;
light_Log.LayerNum = storagelocation.LayerNum;
light_Log.IsSuccess = isSucesss;
result += Context.Insertable(light_Log).ExecuteCommand();
notificationHubContext.Clients.All.SendAsync("PBL_storagelocation_change");
Context.Ado.CommitTran();
return result > 0;
}
else
catch (Exception)
{
// 发送socket 通知
string message =
$"MES产品编号{light.AssemblyPartNumber}或者版本{light.Version},在PBL中找不到。请维护PBL料架信息--{DateTime.Now}";
notificationHubContext.Clients.All.SendAsync("PBL_bom_except", message);
Context.Ado.RollbackTran();
return false;
}
return result > 0;
}
/// <summary>
@@ -159,7 +238,27 @@ namespace DOAN.Service.PBL
CreatedTime = DateTime.Now
};
result += Context.Insertable(light_Log).ExecuteCommand();
notificationHubContext.Clients.All.SendAsync("PBL_storagelocation_change");
return result > 0;
}
/// <summary>
/// 交换合并料架报警配置
/// </summary>
/// <param name="leftShelf"></param>
/// <param name="rightShelf"></param>
/// <returns></returns>
public int DoChangeAlarmStatus(Storagelocation leftShelf, Storagelocation rightShelf)
{
int result = 0;
// 都判断完后切换报警
leftShelf.IsLackAlarm = leftShelf.IsLackAlarm == 1 ? 0 : 1;
leftShelf.AlarmNum = leftShelf.IsLackAlarm == 1 ? rightShelf.AlarmNum : 0;
result += Context.Updateable(leftShelf).ExecuteCommand();
rightShelf.IsLackAlarm = rightShelf.IsLackAlarm == 1 ? 0 : 1;
rightShelf.AlarmNum = rightShelf.IsLackAlarm == 1 ? leftShelf.AlarmNum : 0;
result += Context.Updateable(rightShelf).ExecuteCommand();
return result;
}
}
}

View File

@@ -1,15 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using DOAN.Infrastructure.PLC;
using DOAN.Model.PBL;
using DOAN.ServiceCore.Signalr;
using JinianNet.JNTemplate;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Hosting;
using SqlSugar.IOC;
using static System.Formats.Asn1.AsnWriter;
namespace DOAN.ServiceCore
{
@@ -25,6 +29,7 @@ namespace DOAN.ServiceCore
private PLCTool pLCTool;
private List<Storagelocation> storagelocationList = new List<Storagelocation>();
private List<PlcAddressTable> pointPositionList = new List<PlcAddressTable>();
private List<PlcButton> buttonPositionList = new List<PlcButton>();
private Timer refreshTimer;
public DoanBackgroundService(IHubContext<PBLhub> hubContext)
@@ -34,17 +39,18 @@ namespace DOAN.ServiceCore
public Task StartAsync(CancellationToken cancellationToken)
{
Console.WriteLine($"PCL定时任务开启");
pLCTool = new PLCTool();
pLCTool.ConnectPLC();
// 初始化料架层和点位表数据
RefreshData(null);
// 启动后台任务
_executingTask = ExecuteAsync(_cancellationTokenSource.Token);
// 设置定时器每分钟刷新一次料架层和点位表
refreshTimer = new Timer(RefreshData, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
// 设置定时器每10分钟刷新一次料架层和点位表 .FromMinutes(1)
refreshTimer = new Timer(RefreshData, null, TimeSpan.Zero, TimeSpan.FromMinutes(10));
return _executingTask.IsCompleted ? _executingTask : Task.CompletedTask;
}
@@ -66,7 +72,7 @@ namespace DOAN.ServiceCore
{
if (position < 0 || position > 7)
{
throw new ArgumentOutOfRangeException(nameof(position), "Position must be between 0 and 7.");
throw new ArgumentOutOfRangeException(nameof(position), "Position must be between 0 and 7" + position);
}
byte mask = (byte)(1 << position);
@@ -81,6 +87,7 @@ namespace DOAN.ServiceCore
/// <returns></returns>
private async Task ExecuteAsync(CancellationToken stoppingToken)
{
Console.WriteLine($"PCL定时任务ExecuteAsync");
try
{
while (!stoppingToken.IsCancellationRequested)
@@ -89,13 +96,97 @@ namespace DOAN.ServiceCore
byte[] plcSensorValues;
try
{
plcSensorValues = pLCTool.ReadAllValue("VB100", 12);
// 读取1开头100,101。。。等全部地址数据
plcSensorValues = pLCTool.ReadAllValue("VB100", 13);
}
catch (Exception ex)
{
Console.WriteLine($"读取PLC数据异常: {ex.Message}\n堆栈跟踪: {ex.StackTrace}");
continue;
}
// XX 按钮处理
// 读取按钮PLC I/O状态
foreach (PlcButton button in buttonPositionList)
{
int row = button.Address - 100;
int col = button.Index;
if (plcSensorValues != null && row >= 0 && row < plcSensorValues.Length && !GetInvertedBit(plcSensorValues[row], col))
{
// 按钮按下灭灯
if (button.Code == "灭灯按钮")
{
Storagelocation offLightstoragelocation = storagelocationList.Where(it => it.Id == button.StoragelocationId).First();
bool isSuccess = pLCTool.WriteBit(offLightstoragelocation.PlcAddress, false);
if (isSuccess)
{
offLightstoragelocation.IsLight = 0;
using (var scope = DbScoped.SugarScope.CopyNew())
{
await scope.Updateable(offLightstoragelocation).ExecuteCommandAsync();
//灭灯日志
Light_Log light_Log = new Light_Log
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
LightOperation = 2,
LayerNum = offLightstoragelocation.LayerNum,
ShelfCode = offLightstoragelocation.RackCode,
IsSuccess = isSuccess,
Operationer = "按钮手动灭灯",
CreatedTime = DateTime.Now
};
await scope.Insertable(light_Log).ExecuteCommandAsync();
}
}
await notificationHubContext.Clients.All.SendAsync("PBL_storagelocation_change", "手动灭灯");
}
// 镜体补料按钮
if (button.Code == "镜体补料按钮")
{
bool lightStatus = pLCTool.ReadBit("V208.4");
// 原本灭灯,亮灯补料
if (!lightStatus)
{
using (var scope = DbScoped.SugarScope.CopyNew())
{
AlarmLog alarmLog = new AlarmLog
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
Name = "镜体需要补料",
Code = "镜体补料",
StoragelocationId = 0,
Type = 2,
Status = 1,
ActionTime = DateTime.Now,
EndTime = DateTime.Now
};
scope.Insertable(alarmLog).ExecuteCommand();
var alarmData = new
{
RackCode = "镜体需要补料",
LayerNum = 1,
CurrentPackageCount = 0,
AlarmThreshold = 1,
ActionTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss").ToString(),
};
string alarmMessage = System.Text.Json.JsonSerializer.Serialize(alarmData);
await notificationHubContext.Clients.All.SendAsync("PBL_lack_alarm", alarmMessage);
}
}
else
{
// 原本亮灯,按一下灭灯
pLCTool.WriteBit("V208.4", false);
}
}
}
}
var updateStoragelocationList = new List<Storagelocation>();
var inventoryLogs = new List<Inventorylog>();
@@ -134,17 +225,46 @@ namespace DOAN.ServiceCore
}
// 补料报警触发
if (layerItem.IsLackAlarm == 1 && currentPackageCount <= layerItem.AlarmNum.GetValueOrDefault())
if (layerItem.IsLackAlarm == 1 && currentPackageCount < layerItem.AlarmNum)
{
var alarmData = new
using (var scope = DbScoped.SugarScope.CopyNew())
{
RackCode = layerItem.RackCode,
LayerNum = layerItem.LayerNum,
CurrentPackageCount = currentPackageCount,
AlarmThreshold = layerItem.AlarmNum
};
string alarmMessage = System.Text.Json.JsonSerializer.Serialize(alarmData);
await notificationHubContext.Clients.All.SendAsync("PBL_lack_alarm", alarmMessage);
// 是否已经报警过,并且
bool hasLastAlarm = await scope.Queryable<AlarmLog>()
.Where(it => it.StoragelocationId == layerItem.Id)
.Where(it => it.Type == 1)
.Where(it => it.Status == 1)
.Where(it => DateTime.Now <= it.EndTime)
.OrderBy(it => it.ActionTime, OrderByType.Desc)
.AnyAsync();
if (!hasLastAlarm)
{
string layerName = layerItem.LayerNum == 1 ? "上层" : "中层";
AlarmLog alarmLog = new AlarmLog
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
Name = $"镜壳需补料:{layerItem.RackCode} {layerName} 阈值{layerItem.AlarmNum}",
Code = "镜壳补料",
StoragelocationId = layerItem.Id,
Type = 1,
Status = 1,
ActionTime = DateTime.Now,
// 过X分钟超时jishi
EndTime = DateTime.Now.AddMinutes(2)
};
await scope.Insertable(alarmLog).ExecuteCommandAsync();
var alarmData = new
{
RackCode = layerItem.RackCode,
LayerNum = layerItem.LayerNum,
CurrentPackageCount = currentPackageCount,
AlarmThreshold = layerItem.AlarmNum,
ActionTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss").ToString(),
};
string alarmMessage = System.Text.Json.JsonSerializer.Serialize(alarmData);
await notificationHubContext.Clients.All.SendAsync("PBL_lack_alarm", alarmMessage);
}
}
}
}
}
@@ -152,7 +272,12 @@ namespace DOAN.ServiceCore
// 更新库存
if (updateStoragelocationList.Any())
{
await DbScoped.SugarScope.CopyNew().Updateable(updateStoragelocationList).ExecuteCommandAsync();
using (var scope = DbScoped.SugarScope.CopyNew())
{
await scope.Updateable(updateStoragelocationList)
.IgnoreColumns(it => new { it.IsLight, it.IsLackAlarm, it.AlarmNum, it.MaxCapacity })
.ExecuteCommandAsync();
}
// 发送库存变更Socket通知
string changeMessage = "库存变动";
await notificationHubContext.Clients.All.SendAsync("PBL_storagelocation_change", changeMessage);
@@ -163,8 +288,8 @@ namespace DOAN.ServiceCore
{
await DbScoped.SugarScope.CopyNew().Insertable(inventoryLogs).ExecuteCommandAsync();
}
// 添加延迟以避免频繁查询
await Task.Delay(200, stoppingToken);
// 添加延迟以避免频繁查询(暂定3秒防误触)
await Task.Delay(2000, stoppingToken);
}
}
catch (OperationCanceledException)
@@ -181,14 +306,16 @@ namespace DOAN.ServiceCore
/// 刷新料架层和点位表数据
/// </summary>
/// <param name="state"></param>
private void RefreshData(object state)
private async void RefreshData(object state)
{
try
{
Console.WriteLine($"刷新料架点位和按钮");
using (var scope = DbScoped.SugarScope.CopyNew())
{
storagelocationList = scope.Queryable<Storagelocation>().ToListAsync().Result;
pointPositionList = scope.Queryable<PlcAddressTable>().ToListAsync().Result;
storagelocationList = await scope.Queryable<Storagelocation>().ToListAsync();
pointPositionList = await scope.Queryable<PlcAddressTable>().ToListAsync();
buttonPositionList = await scope.Queryable<PlcButton>().ToListAsync();
}
}
catch (Exception ex)
@@ -235,12 +362,12 @@ namespace DOAN.ServiceCore
{
try
{
pLCTool.ConnectClose();
_cancellationTokenSource.Cancel();
_executingTask?.Wait();
_executingTask?.GetAwaiter().GetResult(); // 确保任务完成
_cancellationTokenSource.Dispose();
refreshTimer?.Change(Timeout.Infinite, Timeout.Infinite);
refreshTimer?.Dispose();
pLCTool.ConnectClose();
}
catch (Exception ex)
{