diff --git a/DOAN.Admin.WebApi/Controllers/PBL/Logging/AlarmLogController.cs b/DOAN.Admin.WebApi/Controllers/PBL/Logging/AlarmLogController.cs
new file mode 100644
index 0000000..011ba73
--- /dev/null
+++ b/DOAN.Admin.WebApi/Controllers/PBL/Logging/AlarmLogController.cs
@@ -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
+{
+ ///
+ /// 库存报警日志
+ ///
+ [Verify]
+ [Route("PBL/AlarmLog")]
+ public class AlarmLogController : BaseController
+ {
+ ///
+ /// 库存报警日志接口
+ ///
+ private readonly IAlarmLogService _AlarmLogService;
+
+ public AlarmLogController(IAlarmLogService AlarmLogService)
+ {
+ _AlarmLogService = AlarmLogService;
+ }
+
+ ///
+ /// 查询库存报警日志列表
+ ///
+ ///
+ ///
+ [HttpGet("list")]
+ [ActionPermissionFilter(Permission = "alarmlog:list")]
+ public IActionResult QueryAlarmLog([FromQuery] AlarmLogQueryDto parm)
+ {
+ var response = _AlarmLogService.GetList(parm);
+ return SUCCESS(response);
+ }
+
+
+ ///
+ /// 查询库存报警日志详情
+ ///
+ ///
+ ///
+ [HttpGet("{Id}")]
+ [ActionPermissionFilter(Permission = "alarmlog:query")]
+ public IActionResult GetAlarmLog(string Id)
+ {
+ var response = _AlarmLogService.GetInfo(Id);
+
+ var info = response.Adapt();
+ return SUCCESS(info);
+ }
+
+ ///
+ /// 添加库存报警日志
+ ///
+ ///
+ [HttpPost]
+ [ActionPermissionFilter(Permission = "alarmlog:add")]
+ [Log(Title = "库存报警日志", BusinessType = BusinessType.INSERT)]
+ public IActionResult AddAlarmLog([FromBody] AlarmLogDto parm)
+ {
+ var modal = parm.Adapt().ToCreate(HttpContext);
+
+ var response = _AlarmLogService.AddAlarmLog(modal);
+
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 更新库存报警日志
+ ///
+ ///
+ [HttpPut]
+ [ActionPermissionFilter(Permission = "alarmlog:edit")]
+ [Log(Title = "库存报警日志", BusinessType = BusinessType.UPDATE)]
+ public IActionResult UpdateAlarmLog([FromBody] AlarmLogDto parm)
+ {
+ var modal = parm.Adapt().ToUpdate(HttpContext);
+ var response = _AlarmLogService.UpdateAlarmLog(modal);
+
+ return ToResponse(response);
+ }
+
+ ///
+ /// 删除库存报警日志
+ ///
+ ///
+ [HttpPost("delete/{ids}")]
+ [ActionPermissionFilter(Permission = "alarmlog:delete")]
+ [Log(Title = "库存报警日志", BusinessType = BusinessType.DELETE)]
+ public IActionResult DeleteAlarmLog([FromRoute]string ids)
+ {
+ var idArr = Tools.SplitAndConvert(ids);
+
+ return ToResponse(_AlarmLogService.Delete(idArr));
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/DOAN.Model/PBL/AlarmLog.cs b/DOAN.Model/PBL/AlarmLog.cs
new file mode 100644
index 0000000..bc73a0e
--- /dev/null
+++ b/DOAN.Model/PBL/AlarmLog.cs
@@ -0,0 +1,60 @@
+
+namespace DOAN.Model.PBL
+{
+ ///
+ /// 库存报警日志
+ ///
+ [SugarTable("alarm_log")]
+ public class AlarmLog
+ {
+ ///
+ /// 主键
+ ///
+ [SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
+ public string Id { get; set; }
+
+ ///
+ /// 名称
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// 编码
+ ///
+ public string Code { get; set; }
+
+ ///
+ /// 料架id
+ ///
+ [SugarColumn(ColumnName = "storagelocation_id")]
+ public int? StoragelocationId { get; set; }
+
+ ///
+ /// 系统类别
+ ///
+ public int? Type { get; set; }
+
+ ///
+ /// 系统状态
+ ///
+ public int? Status { get; set; }
+
+ ///
+ /// 系统备注
+ ///
+ public string Remark { get; set; }
+
+ ///
+ /// 发生时间
+ ///
+ [SugarColumn(ColumnName = "action_time")]
+ public DateTime? ActionTime { get; set; }
+
+ ///
+ /// 完成报警时间
+ ///
+ [SugarColumn(ColumnName = "end_time")]
+ public DateTime? EndTime { get; set; }
+
+ }
+}
\ No newline at end of file
diff --git a/DOAN.Model/PBL/Dto/AlarmLogDto.cs b/DOAN.Model/PBL/Dto/AlarmLogDto.cs
new file mode 100644
index 0000000..0863d94
--- /dev/null
+++ b/DOAN.Model/PBL/Dto/AlarmLogDto.cs
@@ -0,0 +1,48 @@
+
+namespace DOAN.Model.PBL.Dto
+{
+ ///
+ /// 库存报警日志查询对象
+ ///
+ 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; }
+ }
+
+ ///
+ /// 库存报警日志输入输出对象
+ ///
+ 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; }
+ }
+}
\ No newline at end of file
diff --git a/DOAN.Model/PBL/PlcButton.cs b/DOAN.Model/PBL/PlcButton.cs
new file mode 100644
index 0000000..bdc605b
--- /dev/null
+++ b/DOAN.Model/PBL/PlcButton.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DOAN.Model.PBL
+{
+ ///
+ /// PLC地址
+ ///
+ [SugarTable("plc_button_table")]
+ public class PlcButton
+ {
+ ///
+ /// 主键
+ ///
+ [SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
+ public int Id { get; set; }
+
+ ///
+ /// 按钮名称
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// 按钮型号
+ ///
+ public string Code { get; set; }
+
+ ///
+ /// 料架id
+ ///
+ [SugarColumn(ColumnName = "storagelocation_id")]
+ public int StoragelocationId { get; set; }
+
+ ///
+ /// PLC地址
+ ///
+ public int Address { get; set; }
+
+ ///
+ /// PLC地址下标
+ ///
+ public int Index { get; set; }
+
+ }
+}
diff --git a/DOAN.Service/PBL/AlarmLogService.cs b/DOAN.Service/PBL/AlarmLogService.cs
new file mode 100644
index 0000000..2b06b78
--- /dev/null
+++ b/DOAN.Service/PBL/AlarmLogService.cs
@@ -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
+{
+ ///
+ /// 库存报警日志Service业务层处理
+ ///
+ [AppService(ServiceType = typeof(IAlarmLogService), ServiceLifetime = LifeTime.Transient)]
+ public class AlarmLogService : BaseService, IAlarmLogService
+ {
+ ///
+ /// 查询库存报警日志列表
+ ///
+ ///
+ ///
+ public PagedInfo GetList(AlarmLogQueryDto parm)
+ {
+ var predicate = QueryExp(parm);
+
+ var response = Queryable()
+ .Where(predicate.ToExpression())
+ .ToPage(parm);
+
+ return response;
+ }
+
+
+ ///
+ /// 获取详情
+ ///
+ ///
+ ///
+ public AlarmLog GetInfo(string Id)
+ {
+ var response = Queryable()
+ .Where(x => x.Id == Id)
+ .First();
+
+ return response;
+ }
+
+ ///
+ /// 添加库存报警日志
+ ///
+ ///
+ ///
+ public AlarmLog AddAlarmLog(AlarmLog model)
+ {
+ return Insertable(model).ExecuteReturnEntity();
+ }
+
+ ///
+ /// 修改库存报警日志
+ ///
+ ///
+ ///
+ public int UpdateAlarmLog(AlarmLog model)
+ {
+ return Update(model, true);
+ }
+
+ ///
+ /// 查询导出表达式
+ ///
+ ///
+ ///
+ private static Expressionable QueryExp(AlarmLogQueryDto parm)
+ {
+ var predicate = Expressionable.Create()
+ .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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DOAN.Service/PBL/BigScreenService.cs b/DOAN.Service/PBL/BigScreenService.cs
index adbb806..2d44410 100644
--- a/DOAN.Service/PBL/BigScreenService.cs
+++ b/DOAN.Service/PBL/BigScreenService.cs
@@ -142,7 +142,8 @@ public class BigScreenService : BaseService, 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, 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, IBigScreenService
return result;
}
+ // 将复杂逻辑封装到方法中
+ private bool CalculateIsAllFeedingMaterial(List 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()
+ .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;
+ }
+
+
+ }
+
}
diff --git a/DOAN.Service/PBL/IService/IAlarmLogService.cs b/DOAN.Service/PBL/IService/IAlarmLogService.cs
new file mode 100644
index 0000000..3fc032b
--- /dev/null
+++ b/DOAN.Service/PBL/IService/IAlarmLogService.cs
@@ -0,0 +1,21 @@
+using DOAN.Model.PBL.Dto;
+using DOAN.Model.PBL;
+
+namespace DOAN.Service.PBL.IPBLService
+{
+ ///
+ /// 库存报警日志service接口
+ ///
+ public interface IAlarmLogService : IBaseService
+ {
+ PagedInfo GetList(AlarmLogQueryDto parm);
+
+ AlarmLog GetInfo(string Id);
+
+
+ AlarmLog AddAlarmLog(AlarmLog parm);
+ int UpdateAlarmLog(AlarmLog parm);
+
+
+ }
+}
diff --git a/DOAN.Service/PBL/MESInteractionServcie.cs b/DOAN.Service/PBL/MESInteractionServcie.cs
index fc96806..68d4495 100644
--- a/DOAN.Service/PBL/MESInteractionServcie.cs
+++ b/DOAN.Service/PBL/MESInteractionServcie.cs
@@ -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
///
public bool MESLightUp(LightUpDto light, PLCTool pLCTool)
{
- int result = 0;
- // 1.记录MES交互记录
- MES_Interation_Log item = light.Adapt();
- item.Id = XUEHUA;
- item.CreatedTime = DateTime.Now;
- Context.Insertable(item).ExecuteCommand();
- // 2.根据总成零件号 ,版本 查询对应零件号,使得对应料架亮灯
- List MirrorshellShelfList = Context
- .Queryable()
- .Where(it =>
- it.Partnumber
- == SqlFunc
- .Subqueryable()
- .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();
+ item.Id = XUEHUA;
+ item.CreatedTime = DateTime.Now;
+ Context.Insertable(item).ExecuteCommand();
+ // 2.根据总成零件号 ,版本 查询对应零件号,使得对应料架亮灯
+ List MirrorshellShelfList = Context
+ .Queryable()
+ .Where(it =>
+ it.Partnumber
+ == SqlFunc
+ .Subqueryable()
+ .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()
+ .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;
+
}
///
@@ -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;
}
+
+ ///
+ /// 交换合并料架报警配置
+ ///
+ ///
+ ///
+ ///
+ 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;
+ }
}
}
diff --git a/DOAN.ServiceCore/DoanBackgroundService.cs b/DOAN.ServiceCore/DoanBackgroundService.cs
index 4d69059..3d91b76 100644
--- a/DOAN.ServiceCore/DoanBackgroundService.cs
+++ b/DOAN.ServiceCore/DoanBackgroundService.cs
@@ -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 storagelocationList = new List();
private List pointPositionList = new List();
+ private List buttonPositionList = new List();
private Timer refreshTimer;
public DoanBackgroundService(IHubContext 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
///
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();
var inventoryLogs = new List();
@@ -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()
+ .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
/// 刷新料架层和点位表数据
///
///
- private void RefreshData(object state)
+ private async void RefreshData(object state)
{
try
{
+ Console.WriteLine($"刷新料架点位和按钮");
using (var scope = DbScoped.SugarScope.CopyNew())
{
- storagelocationList = scope.Queryable().ToListAsync().Result;
- pointPositionList = scope.Queryable().ToListAsync().Result;
+ storagelocationList = await scope.Queryable().ToListAsync();
+ pointPositionList = await scope.Queryable().ToListAsync();
+ buttonPositionList = await scope.Queryable().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)
{