Files
sy_hx_pbl_backend/DOAN.ServiceCore/DoanBackgroundService.cs
2025-01-20 16:15:40 +08:00

194 lines
7.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using DOAN.Infrastructure.PLC;
using DOAN.Model.PBL;
using DOAN.Model.System;
using Microsoft.Extensions.Hosting;
using SqlSugar;
using SqlSugar.IOC;
namespace DOAN.ServiceCore
{
/// <summary>
/// 永驻线程
/// 功能:检测传感器信号,判断箱子数
/// </summary>
public class DoanBackgroundService : IHostedService, IDisposable
{
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private Task _executingTask;
private PLCTool pLCTool;
public Task StartAsync(CancellationToken cancellationToken)
{
pLCTool = new PLCTool();
pLCTool.ConnectPLC();
// 当服务开始时,启动后台任务
_executingTask = ExecuteAsync(_cancellationTokenSource.Token);
return _executingTask.IsCompleted ? _executingTask : Task.CompletedTask;
}
public async Task StopAsync(CancellationToken cancellationToken)
{
// 请求取消后台任务
_cancellationTokenSource.Cancel();
// 等待后台任务完成
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
}
private static bool GetInvertedBit(byte b, int position)
{
if (position < 0 || position > 7)
{
throw new ArgumentOutOfRangeException(nameof(position), "Position must be between 0 and 7.");
}
// 创建一个掩码其中只有要检查的那一位是1
byte mask = (byte)(1 << position);
// 使用按位与运算符(&)来检查该位是否为1
bool isSet = (b & mask) != 0;
// 返回取反后的值
return !isSet;
}
/// <summary>
/// 功能:检测传感器信号,判断箱子数并更新库存及日志
/// </summary>
/// <param name="stoppingToken">取消令牌</param>
/// <returns></returns>
private async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!stoppingToken.IsCancellationRequested)
{
// 读取PLC I/O状态 12个数组
byte[] plcSensorValues = pLCTool.ReadAllValue("VB100", 12);
// 获取所有料架层
List<Storagelocation> storagelocationList = await DbScoped.SugarScope.CopyNew().Queryable<Storagelocation>().ToListAsync();
// 获取点位表
List<PlcAddressTable> pointPositionList = await DbScoped.SugarScope.CopyNew().Queryable<PlcAddressTable>().ToListAsync();
List<Storagelocation> updateStoragelocationList = [];
List<Inventorylog> inventoryLogs = [];
foreach (Storagelocation layerItem in storagelocationList)
{
// 获取这个料架层的点位表
List<PlcAddressTable> layerPoints = pointPositionList.Where(it => it.FkStorageId == layerItem.Id).ToList();
if (layerPoints != null && layerPoints.Count > 0)
{
int currentPackageCount = 0; // 默认最小值为0
foreach (PlcAddressTable point in layerPoints)
{
int row = point.ByteNum - 100;
int col = point.BitNum - 1;
if (plcSensorValues != null)
{
currentPackageCount += GetInvertedBit(plcSensorValues[row], col) ? 1 : 0;
}
}
// 检查箱子数量变化并记录日志
if (currentPackageCount > layerItem.PackageNum)
{
UpdateAndLog(layerItem, currentPackageCount, 2, "补料", inventoryLogs);
updateStoragelocationList.Add(layerItem);
}
else if (currentPackageCount < layerItem.PackageNum)
{
UpdateAndLog(layerItem, currentPackageCount, 1, "出料", inventoryLogs);
updateStoragelocationList.Add(layerItem);
}
}
}
// 更新库存
if (updateStoragelocationList.Count > 0)
{
await DbScoped.SugarScope.CopyNew().Updateable(updateStoragelocationList).ExecuteCommandAsync();
}
// 插入库存变更日志
if (inventoryLogs.Count > 0)
{
await DbScoped.SugarScope.CopyNew().Insertable(inventoryLogs).ExecuteCommandAsync();
}
// 添加延迟以避免频繁查询
await Task.Delay(200, stoppingToken);
}
}
catch (OperationCanceledException)
{
Console.WriteLine("任务已取消");
}
catch (Exception ex)
{
Console.WriteLine($"DoanBackGround线程ExecuteAsync异常: {ex.Message}\n堆栈跟踪: {ex.StackTrace}");
}
}
/// <summary>
/// 更新料架位置的箱子数量并记录库存日志
/// </summary>
/// <param name="storageLocation">料架位置对象</param>
/// <param name="newPackageCount">新的箱子数量</param>
/// <param name="operation">操作类型 (1-出库, 2-入库)</param>
/// <param name="operatorName">操作员名称</param>
/// <param name="inventoryLogs">库存日志列表</param>
private void UpdateAndLog(Storagelocation storageLocation, int newPackageCount, int operation, string operatorName, List<Inventorylog> inventoryLogs)
{
storageLocation.PackageNum = newPackageCount;
storageLocation.UpdatedBy = operatorName;
storageLocation.UpdatedTime = DateTime.Now;
Inventorylog inventoryLog = new Inventorylog
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
RackCode = storageLocation.RackCode,
Partnumber = storageLocation.Partnumber,
Operation = operation,
PackageNum = Math.Abs((int)(newPackageCount - storageLocation.PackageNum)),
CreatedBy = operatorName,
CreatedTime = DateTime.Now.ToLocalTime()
};
inventoryLogs.Add(inventoryLog);
}
public void Dispose()
{
try
{
pLCTool.ConnectClose();
_cancellationTokenSource.Cancel();
_executingTask.Wait();
_cancellationTokenSource.Dispose();
}
catch (Exception ex)
{
Console.WriteLine("DoanBackGround线程Dispose异常:" + ex.Message);
}
}
}
}