You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

579 lines
21 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Admin.Core.IService;
using Admin.Core.Model;
using Admin.Core.Service;
using Aucma.Scada.UI.Common;
using log4net;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Aucma.Scada.UI
{
/// <summary>
/// 入库业务逻辑
/// </summary>
public class InStoreBusiness
{
#region 单例实现
//private static readonly InStoreBusiness lazy = new InStoreBusiness();
//public static InStoreBusiness Instance
//{
// get
// {
// return lazy;
// }
//}
#endregion
#region 对象引用
private static readonly log4net.ILog logHelper = LogManager.GetLogger(typeof(ExecutePlanInfoServices));
private AppConfig appConfig = new AppConfig();//AppConfig.Instance;
//??????????????????????????????
//private InStoreTaskHandle taskHandle = InStoreTaskHandle.Instance;
//private GrabImage grabImage = GrabImage.Instance;
#endregion
#region 接口引用
/// <summary>
/// 货道信息
/// </summary>
private IBaseSpaceInfoServices _spaceInfoService;
/// <summary>
/// 实时任务
/// </summary>
private IRealTaskInfoServices _taskInfoService;
private IBaseSpaceDetailServices _baseSpaceDetailService;
private IBaseBomInfoServices _baseBomInfoService;
private IRecordInStoreServices _recordInStore;
#endregion
#region 委托事件
/// <summary>
/// 初始化入库任务
/// </summary>
/// <param name="message"></param>
public delegate void RefreshInStoreTask(RealTaskInfo taskInfos, bool isFinsih = false);
public event RefreshInStoreTask RefreshInStoreTaskEvent;
/// <summary>
/// 扫码信息刷新
/// </summary>
/// <param name="materialCode"></param>
/// <param name="materialName"></param>
/// <param name="spaceName"></param>
/// <param name="materialType"></param>
public delegate void RefreshScanMateriaCode(string materialCode, string materialName, string spaceName, string materialType);
public event RefreshScanMateriaCode RefreshScanMateriaCodeEvent;
/// <summary>
/// 日志信息刷新
/// </summary>
/// <param name="message"></param>
public delegate void RefreshLogMessage(string message);
public event RefreshLogMessage RefreshLogMessageEvent;
#endregion
public InStoreBusiness()
{
_spaceInfoService = App.ServiceProvider.GetService<IBaseSpaceInfoServices>();
_taskInfoService = App.ServiceProvider.GetService<IRealTaskInfoServices>();
_baseSpaceDetailService = App.ServiceProvider.GetService<IBaseSpaceDetailServices>();
_baseBomInfoService = App.ServiceProvider.GetService<IBaseBomInfoServices>();
_recordInStore = App.ServiceProvider.GetService<IRecordInStoreServices>();
//taskHandle.InStoreFinsihEvent += InStoreFinish;
//taskHandle.InStoreAnswerEvent += InStoreAnswer;
//grabImage.RefreshMaterialCodeStrEvent += InStore;
//grabImage.RefreshLogMessageEvent += PrintLogInfoMessage;
StartPassDown();
//Task.Run(() =>
//{
// Thread.Sleep(6000);
// for (int i = 1; i < 12; i++)
// {
// InStore(appConfig.shellStoreCode, "B23600000781110900" + i.ToString().PadLeft(2, '0'));
// Thread.Sleep(1000 * 30);
// InStore(appConfig.linerStoreCode, "L23600000788110900" + i.ToString().PadLeft(2, '0'));
// Thread.Sleep(1000 * 30);
// }
//});
}
/// <summary>
/// 入库
/// </summary>
/// <param name="storeCode"></param>
/// <param name="materialType"></param>
private async void InStore(string storeCode, string materialCode)
{
try
{
PrintLogInfoMessage($"扫码成功,物料码:{materialCode}");
string materialType = SubStringMaterialCode(materialCode);
#region Delete By wenjy 2023-10-30 11:41:00 取消通过数据库获取货道数量、在途量改为通过PLC获取货道信息
//var spaceInfo = _spaceInfoService.InStoreGetSpaceInfoByMaterialType(storeCode, materialType);
#endregion
var spaceInfo =await GetSpaceInfoByMaterialType(storeCode, materialType);
if (spaceInfo != null)
{
PrintLogInfoMessage($"匹配货道:{spaceInfo.SpaceName}");
spaceInfo.MaterialType = materialType;
RefreshScanMateriaCodeEvent?.Invoke(materialCode,await GetMaterialName(materialType), spaceInfo.SpaceName, storeCode); //刷新界面扫码信息
var result =await CreateInStoreTask(spaceInfo, materialCode); //创建入库任务
if (result)
{
//spaceInfo.onRouteAmount += 1; //通过PLC获取货道信息在库、在途数量时不需要修改在途数量
_spaceInfoService.UpdateSpaceInfo(spaceInfo);
}
}
else
{
//报警停线
PrintLogInfoMessage($"物料码:{materialCode};未匹配到可用货道");
}
}
catch (Exception ex)
{
PrintLogErrorMessage("入库业务异常", ex);
}
}
/// <summary>
/// 创建入库任务
/// </summary>
/// <param name="spaceInfo"></param>
private async Task<bool> CreateInStoreTask(BaseSpaceInfo spaceInfo, string materialCode)
{
bool result = false;
#region 任务赋值
RealTaskInfo realTaskInfo = new RealTaskInfo();
realTaskInfo.TaskType = 1;
realTaskInfo.TaskCode = System.Guid.NewGuid().ToString("N").Substring(0, 6);
realTaskInfo.StoreCode = spaceInfo.StoreCode;
realTaskInfo.SpaceCode = spaceInfo.SpaceCode;
realTaskInfo.MaterialType = spaceInfo.MaterialType;
realTaskInfo.MaterialCode = materialCode;
realTaskInfo.PlanAmount = 1;
realTaskInfo.TaskStatus = 1;
realTaskInfo.CreateTime = DateTime.Now;
#endregion
int r =await _taskInfoService.AddAsync(realTaskInfo);
if (r>0)
{
PrintLogInfoMessage("入库任务创建成功");
RefreshInStoreTaskEvent?.Invoke(realTaskInfo);
result = true;
}
else
{
PrintLogInfoMessage("入库任务创建失败");
}
return result;
}
#region 轮询获取入库任务下发至PLC等待PLC执行反馈完成后再次下发
private SemaphoreSlim shellSemaphore = new SemaphoreSlim(0);
private SemaphoreSlim linerSemaphore = new SemaphoreSlim(0);
/// <summary>
/// 任务下发 ——迁移到任务调度中去
/// </summary>
[Obsolete("迁移到任务调度中去,废弃")]
private void StartPassDown()
{
Thread.Sleep(5000);
Task.Run(() =>
{
while (true)
{
PassDownShellTask();
Thread.Sleep(5000);
}
});
Task.Run(async () =>
{
while (true)
{
await PassDownLinerTaskAsync();
Thread.Sleep(5000);
}
});
}
/// <summary>
/// 依次获取箱壳任务队列进行下发
/// </summary>
/// <param name="source"></param>
/// <param name="e"></param>
private async void PassDownShellTask()
{
try
{
RealTaskInfo taskInfo =await _taskInfoService.GetTaskInfoByStoreCode(appConfig.shellStoreCode, appConfig.instoreTaskType);
if (taskInfo != null)
{
PrintLogInfoMessage($"下发箱壳入库任务:{taskInfo.TaskCode};仓库{taskInfo.StoreCode};货道:{taskInfo.SpaceCode}");
//if (taskHandle.SendShellTask_InStore(taskInfo))
{
PrintLogInfoMessage($"箱壳入库任务:{taskInfo.TaskCode}下发成功等待PLC执行反馈");
shellSemaphore.Wait(); //一直堵塞直到信号量释放
PrintLogInfoMessage($"箱壳入库任务:{taskInfo.TaskCode};开始执行");
taskInfo.TaskStatus = 2;
_taskInfoService.UpdateAsync(taskInfo);
RefreshInStoreTaskEvent?.Invoke(taskInfo);
}
//else
//{
// PrintLogInfoMessage($"箱壳入库任务:{taskInfo.TaskCode}下发失败请排查PLC连接");
//}
}
else
{
PrintLogInfoMessage("未获取到需要下发的箱壳入库任务");
}
}
catch (Exception ex)
{
PrintLogErrorMessage("依次获取箱壳任务队列进行下发逻辑异常", ex);
}
}
/// <summary>
/// 依次获取内胆任务队列进行下发
/// </summary>
private async Task PassDownLinerTaskAsync()
{
try
{
RealTaskInfo taskInfo = await _taskInfoService.GetTaskInfoByStoreCode(appConfig.linerStoreCode, appConfig.instoreTaskType);
if (taskInfo != null)
{
PrintLogInfoMessage($"下发内胆入库任务:{taskInfo.TaskCode};仓库{taskInfo.StoreCode};货道:{taskInfo.SpaceCode}");
//if (taskHandle.SendLinerTask_InStore(taskInfo))
{
PrintLogInfoMessage($"内胆入库任务:{taskInfo.TaskCode}下发成功等待PLC执行反馈");
linerSemaphore.Wait(); //一直堵塞直到信号量释放
PrintLogInfoMessage($"内胆入库任务:{taskInfo.TaskCode};开始执行");
taskInfo.TaskStatus = 2;
_taskInfoService.UpdateAsync(taskInfo);
RefreshInStoreTaskEvent?.Invoke(taskInfo);
}
//else
//{
// PrintLogInfoMessage($"内胆入库任务:{taskInfo.TaskCode}下发失败请排除PLC连接");
//}
}
else
{
PrintLogInfoMessage("未获取到需要下发的内胆入库任务");
}
}
catch (Exception ex)
{
PrintLogErrorMessage("依次获取内胆任务队列进行下发逻辑异常", ex);
}
}
#endregion
/// <summary>
/// 入库应答PLC收到入库任务后进行应答
/// </summary>
/// <param name="storeCode"></param>
/// <param name="taskCode"></param>
private void InStoreAnswer(string storeCode, string taskCode)
{
if (storeCode == appConfig.shellStoreCode)
{
PrintLogInfoMessage("箱壳应答成功,自动释放信号量,进行下发新任务");
shellSemaphore.Release();
}
else
{
PrintLogInfoMessage("内胆应答成功,自动释放信号量,进行下发新任务");
linerSemaphore.Release();
}
}
/// <summary>
/// 入库完成
/// </summary>
/// <param name="storeCode"></param>
/// <param name="taskCode"></param>
private void InStoreFinish(string storeCode, string taskCode)
{
if (storeCode == appConfig.shellStoreCode)
{
PrintLogInfoMessage($"箱壳任务:{taskCode};执行完成");
InStoreFinishHandle(taskCode, appConfig.shellStoreCode);
}
else
{
PrintLogInfoMessage($"内胆任务:{taskCode};执行完成");
InStoreFinishHandle(taskCode, appConfig.linerStoreCode);
}
}
/// <summary>
/// 入库完成逻辑处理
/// </summary>
/// <param name="storeCode"></param>
/// <param name="spaceCode"></param>
/// <param name="materialType"></param>
private async void InStoreFinishHandle(string taskCode, string storeCode)
{
try
{
var taskInfo =await _taskInfoService.GetTaskInfoByTaskCode(taskCode, storeCode);
if (taskInfo != null)
{
var spaceInfo =await _spaceInfoService.GetSpaceInfoBySpaceCode(taskInfo.StoreCode, taskInfo.SpaceCode);
if (spaceInfo != null)
{
//taskHandle.WritePlc(spaceInfo.StoreCode, spaceInfo.SpaceCode, true);
//spaceInfo.materialType = taskInfo.materialType;
spaceInfo.SpaceStock = spaceInfo.SpaceStock + 1;
spaceInfo.OnRouteAmount -= 1;
//读取PLC获取货道信息存放数量、在途数量,
#region Add By wenjy 2023-10-30 13:44:00 通过PLC获取货道信息
//var item = taskHandle.ReadSpaceInfoByPlc(spaceInfo);
//spaceInfo.SpaceStock = item.spaceStock;
//spaceInfo.OnRouteAmount = item.onRouteAmount;
//spaceInfo.SpaceStatus = item.spaceStatus;
#endregion
_spaceInfoService.UpdateSpaceInfo(spaceInfo);
#region 添加货道明细
BaseSpaceDetail spaceDetail = new BaseSpaceDetail();
spaceDetail.MaterialType = taskInfo.MaterialType;
spaceDetail.MaterialCode = taskInfo.MaterialCode;
spaceDetail.MaterialName = await GetMaterialName(taskInfo.MaterialType);
spaceDetail.StoreCode = spaceInfo.StoreCode;
spaceDetail.SpaceCode = spaceInfo.SpaceCode;
spaceDetail.MaterialAmount = 1;
await _baseSpaceDetailService.InsertSpaceDetail(spaceDetail);
#endregion
#region 添加入库记录
RecordInStore recordInstore = new RecordInStore();
recordInstore.StoreCode = taskInfo.StoreCode;
recordInstore.SpaceCode = taskInfo.SpaceCode;
recordInstore.MaterialCode = taskInfo.MaterialCode;
recordInstore.MaterialType = taskInfo.MaterialType;
recordInstore.MaterialName = await GetMaterialName(taskInfo.MaterialType);
recordInstore.InStoreAmount = 1;
recordInstore.InStoreTime = DateTime.Now;
recordInstore.BarCodeCode = taskInfo.MaterialCode;
await _recordInStore.AddAsync(recordInstore);
#endregion
}
//清除任务信息
_taskInfoService.DeleteTaskInfo(taskCode, storeCode);
}
RefreshInStoreTaskEvent?.Invoke(taskInfo, true);
}
catch (Exception ex)
{
PrintLogErrorMessage("入库完成逻辑处理异常", ex);
}
}
/// <summary>
/// 截取条码
/// </summary>
/// <param name="materialCode"></param>
/// <returns></returns>
private string SubStringMaterialCode(string materialCode)
{
string result = string.Empty;
if (!string.IsNullOrEmpty(materialCode))
{
result = materialCode.Substring(2, 10);
}
return result;
}
/// <summary>
/// 获取已创建的所有入库任务
/// </summary>
/// <returns></returns>
public async Task<List<RealTaskInfo>> GetInStoreTask()
{
return await _taskInfoService.GetTaskInfosByStoreCode(new string[] { appConfig.shellStoreCode, appConfig.linerStoreCode }, appConfig.instoreTaskType);
}
/// <summary>
/// 通过BOM获取物料名称
/// </summary>
/// <param name="materialType"></param>
/// <returns></returns>
public async Task<string> GetMaterialName(string materialType)
{
string materialName = string.Empty;
var info =await _baseBomInfoService.GetBomInfoByMaterialCode(materialType);
if (info != null)
{
materialName = info.MaterialName;
}
return materialName;
}
/// <summary>
/// 获取仓库物料库存
/// </summary>
/// <returns></returns>
public async Task<List<dynamic>> GetMaterialStock()
{
return await _spaceInfoService.GetMaterialStock(appConfig.shellStoreCode, appConfig.linerStoreCode);
}
#region 通过PLC读取货道信息在库、在途、货道状态
/// <summary>
/// 通过PLC读取货道信息在途数量、在库数量、货道状态)
/// </summary>
/// <param name="storeCode"></param>
/// <param name="materialType"></param>
/// <returns></returns>
private async Task<BaseSpaceInfo> GetSpaceInfoByMaterialType(string storeCode, string materialType)
{
BaseSpaceInfo result = null;
try
{
List<BaseSpaceInfo> info = await _spaceInfoService.GetBaseSpaceInfosByMaterialType(storeCode, materialType);
if (info != null)
{
if (info.Count > 0)
{
result = GetSpaceInfosByPlc(info);
if (result == null)
{
var list =await _spaceInfoService.GetEmptySpaceInfo(storeCode);
result = GetSpaceInfosByPlc(list);
}
}
}
}
catch (Exception ex)
{
PrintLogErrorMessage("货道信息读取异常", ex);
}
return result;
}
/// <summary>
/// 读取PLC货道信息
/// </summary>
/// <param name="info"></param>
/// <returns></returns>
private BaseSpaceInfo GetSpaceInfosByPlc(List<BaseSpaceInfo> info)
{
BaseSpaceInfo result = null;
if (info != null)
{
if (info.Count > 0)
{
//foreach (BaseSpaceInfo item in info)
//{
// var spaceInfo = taskHandle.ReadSpaceInfoByPlc(item);
// item.SpaceStock = spaceInfo.spaceStock;
// item.OnRouteAmount = spaceInfo.onRouteAmount;
// item.SpaceStatus = spaceInfo.spaceStatus;
// PrintLogInfoMessage($"通过PLC读取货道信息货道{spaceInfo.spaceName};在库数量:{item.SpaceStock};在途数量:{item.OnRouteAmount};货道状态:{item.SpaceStatus}");
//}
var list = info.Where(x => x.SpaceStock > 0 ? x.SpaceCapacity > (x.SpaceStock + x.OnRouteAmount) : 1 == 1 && x.SpaceStatus == 1).ToList();
if (list.Count > 0)
{
result = list.OrderByDescending(x => x.SpaceStock).OrderBy(x => x.SpaceCode).First();
}
}
}
return result;
}
#endregion
#region 日志输出
/// <summary>
/// 日志输出,界面刷新同时记录文件
/// </summary>
/// <param name="message"></param>
private void PrintLogInfoMessage(string message)
{
RefreshLogMessageEvent?.Invoke(message);
logHelper.Info(message);
}
/// <summary>
/// 异常日志输出
/// </summary>
/// <param name="message"></param>
/// <param name="ex"></param>
private void PrintLogErrorMessage(string message, Exception ex = null)
{
RefreshLogMessageEvent?.Invoke(message);
logHelper.Error(message, ex);
}
#endregion
}
}