using System; using System.Data; using System.Dynamic; using System.Security.Policy; using System.Text; using Aop.Api.Domain; using JNPF; using JNPF.Common.Cache; using JNPF.Common.Dtos.VisualDev; using JNPF.Common.Extension; using JNPF.FriendlyException; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using NetTaste; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NPOI.OpenXmlFormats; using Qiniu.Util; using SqlSugar; using Tnb.Common.Extension; using Tnb.Common.Redis; using Tnb.Common.Utils; using Tnb.ProductionMgr.Entities; using Tnb.ProductionMgr.Entities.Dto; using Tnb.ProductionMgr.Entities.Enums; using Tnb.ProductionMgr.Interfaces; using Tnb.WarehouseMgr.Entities; using Tnb.WarehouseMgr.Entities.Configs; using Tnb.WarehouseMgr.Entities.Consts; using Tnb.WarehouseMgr.Entities.Enums; using Tnb.WarehouseMgr.Interfaces; namespace Tnb.ProductionMgr { //redis定时获取数采数据 public class RedisBackGround : IHostedService, IDisposable { private Timer? Readtimer; private Timer? CheckGettimer; private Timer? Scantimer; private Timer? SSXcodetimer; // 二楼上升降机 private Timer? Floor2UpMachinecodetimer; // 二楼下升降机 private Timer? Floor2DownMachinecodetimer; private readonly RedisData _redisData; private readonly IPrdInstockService _prdInstockService; private readonly ISqlSugarRepository _repository; private readonly IWmsPDAScanInStockService _wmsPDAScanInStock; private readonly ElevatorControlConfiguration _eleCtlCfg = App.Configuration.Build(); public RedisBackGround(RedisData redisData, IPrdInstockService prdInstockService, ISqlSugarRepository repository, IWmsPDAScanInStockService wmsPDAScanInStock) { _redisData = redisData; _prdInstockService = prdInstockService; _repository = repository; _wmsPDAScanInStock = wmsPDAScanInStock; } //获取redis数据 private void GetRedisData(object state) { var _redisReadConfigs = _repository.AsQueryable().Where(p => p.enabled == 1).ToList(); foreach (var config in _redisReadConfigs) { try { var json = _redisData.GetHash(config.dev_name!, config.tag_name!).Result; JObject? res = JsonConvert.DeserializeObject(json); if (config.data_type == (int)DataType.INT) { if (config.check_type == (int)CheckType.相等) { if (res.Value("Value") == int.Parse(config.data!)) { InstockInput instockInput = new() { equip_code = res["DevName"]!.ToString(), label_code = res["TagName"]!.ToString() }; TriggerEvent((EventType)config.event_type, instockInput); } } else if (config.check_type == (int)CheckType.包含) { int[] ints = Array.ConvertAll(config.data!.Replace("[", "").Replace("]", "").Split(",", StringSplitOptions.RemoveEmptyEntries), int.Parse); if (ints.Contains(res.Value("Value"))) { InstockInput instockInput = new() { equip_code = res["DevName"]!.ToString(), label_code = res["TagName"]!.ToString() }; TriggerEvent((EventType)config.event_type, instockInput); } } } else if (config.data_type == (int)DataType.BOOL) { if (config.check_type == (int)CheckType.相等) { if (res.Value("Value") == bool.Parse(config.data!)) { InstockInput instockInput = new() { equip_code = res["DevName"]!.ToString(), label_code = res["TagName"]!.ToString() }; TriggerEvent((EventType)config.event_type, instockInput); } } } } catch (Exception) { } } } private void TriggerEvent(EventType eventType, InstockInput instockInput) { switch (eventType) { case EventType.注塑空满箱请求: _prdInstockService.InstockTypeOne(instockInput); break; case EventType.挤出空满箱请求: _prdInstockService.InstockTubeOne(instockInput); break; case EventType.限位请求: _prdInstockService.InstockOutPack(instockInput); break; default: break; } } //ctu取货 private void CheckGet(object state) { Dictionary getdic = new Dictionary(); getdic.Add("SSX-021-005", new string[] { "YTCS", "AllowFullOut_CS05", "LiftCode" }); getdic.Add("SSX-011-002", new string[] { "YTCS", "AllowAgvFullIn_CS02", "Code_CS02" }); getdic.Add("SSX-011-004", new string[] { "YTCS", "AllowCtuFullOut_CS04", "Code_CS04" }); getdic.Add("SSX-011-008", new string[] { "东面提升机输送线", "入库输送线8允许出箱", "入库输送线7条码" }); getdic.Add("SSX-111-011", new string[] { "东面提升机输送线", "下升降机11允许出箱", "下升降机11条码" }); getdic.Add("SSX-111-012", new string[] { "东面提升机输送线", "下升降机12允许出箱", "下升降机12条码" }); getdic.Add("ZSSSXCTU02", new string[] { "YTCS", "AllowAgvEmptyOut_CS03", "" }); getdic.Add("ZSSSXCTU01", new string[] { "YTCS", "AllowAgvEmptyOut_CS01", "" }); foreach (var key in getdic.Keys) { try { var strs = getdic.Where(p => p.Key == key).First().Value; bool flag = _redisData.HashExist(strs[0], strs[1]).Result; string data = _redisData.GetHash(strs[0], strs[1]).Result; JObject? res = JsonConvert.DeserializeObject(data); bool result = res != null && res["Value"] != null ? res.Value("Value") : false; if (result) { if (!string.IsNullOrEmpty(strs[2])) { string codedata = _redisData.GetHash(strs[0], strs[2]).Result; JObject? coderes = JsonConvert.DeserializeObject(codedata); string coderesult = coderes != null && coderes["Value"] != null ? coderes.Value("Value")! : ""; coderesult = coderesult.Replace("\r", ""); var DistaskH = _repository.AsSugarClient().Queryable().Where(p => p.carry_code == coderesult && p.status == WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID && string.IsNullOrEmpty(p.extras)).First(); if (DistaskH != null) { Logger.LogInformation($@"【定时任务CheckGet】 {JsonConvert.SerializeObject(DistaskH)}"); dynamic reqBody = new ExpandoObject(); reqBody.taskCode = DistaskH.bill_code; reqBody.slotCode = key; reqBody.containerCode = coderesult; CancellationTokenSource Ctu = new(); if (strs[0] == "东面提升机输送线") { Logger.LogInformation($"【定时任务CheckGet】 开始发送请求到 http://192.168.11.104:1880/wcs/notify/cargo "); } dynamic respBody = HttpClientHelper.PostStreamAsync("http://192.168.11.104:1880/wcs/notify/cargo", reqBody, Ctu.Token).Result; if (strs[0] == "东面提升机输送线") { Logger.LogInformation($"【定时任务CheckGet】 接收请求 http://192.168.11.104:1880/wcs/notify/cargo 结果 {respBody} "); } DistaskH.extras = respBody; _repository.AsSugarClient().Updateable(DistaskH).ExecuteCommand(); Ctu.Dispose(); } else { LoggerSSX.LogInformation($@"【定时任务CheckGet】 {key}->{strs[0]} {strs[2]} 采集结果:{ $@"任务执行(wms_distask_h)中找不到匹配的记录 任务执行需要存在载具编号(carry_code)为{coderesult} 且单据状态(status)为已下达(26126853976101) 且扩展字段(extras)为空的记录 select extras,* from wms_distask_h where carry_code = '{coderesult}' and status = '{WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID}' " }"); } } else { var DistaskH = _repository.AsSugarClient().Queryable().Where(p => p.startlocation_code == key && p.status == WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID && string.IsNullOrEmpty(p.extras)).First(); if (DistaskH != null) { dynamic reqBody = new ExpandoObject(); reqBody.taskCode = DistaskH.bill_code; reqBody.slotCode = key; reqBody.containerCode = DistaskH.carry_code; CancellationTokenSource Ctu = new(); dynamic respBody = HttpClientHelper.PostStreamAsync("http://192.168.11.104:1880/wcs/notify/cargo", reqBody, Ctu.Token).Result; DistaskH.extras = respBody; _repository.AsSugarClient().Updateable(DistaskH).ExecuteCommand(); Ctu.Dispose(); } } } } catch (Exception ex) { LoggerSSX.LogError(ex.ToString()); } } } private static readonly Dictionary s_logLevelMap = new() { [LogLevel.Debug] = "DBG", [LogLevel.Information] = "INF", [LogLevel.Warning] = "WRN", [LogLevel.Error] = "ERR", }; #region 日志 protected ILogger Logger => LoggerFactory.Create(builder => builder.AddFile($"{AppContext.BaseDirectory}/logs/custom{DateTime.Now:yyyyMMdd}.log", cfgOpts => { //cfgOpts.DateFormat = "yyyy-MM-dd HH:mm:ss.fff"; cfgOpts.MessageFormat = (logMsg) => { var logLevel = s_logLevelMap[logMsg.LogLevel]; var sb = new StringBuilder(); _ = sb.Append($"[{logLevel}] "); _ = sb.Append($"{logMsg.LogName} "); _ = sb.Append($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} "); _ = sb.Append($"#{logMsg.EventId.Id} "); _ = sb.Append(logMsg.Message + " "); _ = sb.Append(logMsg.Exception?.ToString()); return sb.ToString(); }; })).CreateLogger(this.GetType()); protected ILogger LoggerBGW => LoggerFactory.Create(builder => builder.AddFile($"{AppContext.BaseDirectory}/logs/customBGW{DateTime.Now:yyyyMMdd}.log", cfgOpts => { //cfgOpts.DateFormat = "yyyy-MM-dd HH:mm:ss.fff"; cfgOpts.MessageFormat = (logMsg) => { var logLevel = s_logLevelMap[logMsg.LogLevel]; var sb = new StringBuilder(); _ = sb.Append($"[{logLevel}] "); _ = sb.Append($"{logMsg.LogName} "); _ = sb.Append($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} "); _ = sb.Append($"#{logMsg.EventId.Id} "); _ = sb.Append(logMsg.Message + " "); _ = sb.Append(logMsg.Exception?.ToString()); return sb.ToString(); }; })).CreateLogger(this.GetType()); protected ILogger LoggerSSX => LoggerFactory.Create(builder => builder.AddFile($"{AppContext.BaseDirectory}/logs/customSSX{DateTime.Now:yyyyMMdd}.log", cfgOpts => { //cfgOpts.DateFormat = "yyyy-MM-dd HH:mm:ss.fff"; cfgOpts.MessageFormat = (logMsg) => { var logLevel = s_logLevelMap[logMsg.LogLevel]; var sb = new StringBuilder(); _ = sb.Append($"[{logLevel}] "); _ = sb.Append($"{logMsg.LogName} "); _ = sb.Append($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} "); _ = sb.Append($"#{logMsg.EventId.Id} "); _ = sb.Append(logMsg.Message + " "); _ = sb.Append(logMsg.Exception?.ToString()); return sb.ToString(); }; })).CreateLogger(this.GetType()); // 二楼上下升降机日志 protected ILogger LoggerFloor2UpDownMachine => LoggerFactory.Create(builder => builder.AddFile($"{AppContext.BaseDirectory}/logs/customFloor2UpDownMachine{DateTime.Now:yyyyMMdd}.log", cfgOpts => { //cfgOpts.DateFormat = "yyyy-MM-dd HH:mm:ss.fff"; cfgOpts.MessageFormat = (logMsg) => { var logLevel = s_logLevelMap[logMsg.LogLevel]; var sb = new StringBuilder(); _ = sb.Append($"[{logLevel}] "); _ = sb.Append($"{logMsg.LogName} "); _ = sb.Append($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} "); _ = sb.Append($"#{logMsg.EventId.Id} "); _ = sb.Append(logMsg.Message + " "); _ = sb.Append(logMsg.Exception?.ToString()); return sb.ToString(); }; })).CreateLogger(this.GetType()); // 二楼料架补充 protected ILogger LoggerFloor2RackSupplement => LoggerFactory.Create(builder => builder.AddFile($"{AppContext.BaseDirectory}/logs/customFloor2RackSupplement{DateTime.Now:yyyyMMdd}.log", cfgOpts => { //cfgOpts.DateFormat = "yyyy-MM-dd HH:mm:ss.fff"; cfgOpts.MessageFormat = (logMsg) => { var logLevel = s_logLevelMap[logMsg.LogLevel]; var sb = new StringBuilder(); _ = sb.Append($"[{logLevel}] "); _ = sb.Append($"{logMsg.LogName} "); _ = sb.Append($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} "); _ = sb.Append($"#{logMsg.EventId.Id} "); _ = sb.Append(logMsg.Message + " "); _ = sb.Append(logMsg.Exception?.ToString()); return sb.ToString(); }; })).CreateLogger(this.GetType()); #endregion //扫码入库 private void ScanInStock(object state) { Dictionary getdic = new Dictionary(); getdic.Add("BGWRKYCL02", new string[] { "CP8", "AllowGetFullBox1", "code1", "PutDoneEmptyBox", "false" }); getdic.Add("BGWRKYCL01", new string[] { "CP8", "AllowGetFullBox2", "code2", "PutDoneEmptyBox", "false" }); foreach (var key in getdic.Keys) { try { var strs = getdic.Where(p => p.Key == key).First().Value; bool flag = _redisData.HashExist(strs[0], strs[1]).Result; string data = _redisData.GetHash(strs[0], strs[1]).Result; JObject? res = JsonConvert.DeserializeObject(data); bool result = res != null && res["Value"] != null ? res.Value("Value") : false; if (result) { Logger.LogInformation($"【ScanInStock】 八工位 {key} AllowGetFullBox1采集到 {res["Value"]}"); Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = strs[0], ["token"] = _eleCtlCfg.token, ["TagName"] = strs[3], ["Value"] = strs[4], }; Logger.LogInformation($"【ScanInStock】 八工位 {key} 发送PutDoneEmptyBox指令 {_eleCtlCfg.WriteTagUrl} {JsonConvert.SerializeObject(dicCommand)}"); HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand).Wait(); string codedata = _redisData.GetHash(strs[0], strs[2]).Result; Logger.LogInformation($"【ScanInStock】 八工位 {key} 获取到扫码信息: {codedata}"); JObject? coderes = JsonConvert.DeserializeObject(codedata); string coderesult = coderes != null && coderes["Value"] != null ? coderes.Value("Value")! : ""; WmsCarryH? carry = _repository.AsSugarClient().Queryable().Single(it => it.carry_code == coderesult); Logger.LogInformation($"【ScanInStock】 八工位 {key} 查找{coderesult}绑定的托盘: {JsonConvert.SerializeObject(carry)}"); if (carry != null) { if (_repository.AsSugarClient().Queryable().Where(p => p.carry_id == carry.id && p.status != WmsWareHouseConst.TASK_BILL_STATUS_COMPLE_ID ).Any()) { Logger.LogInformation($"【ScanInStock】 八工位 {key} 托盘 {carry.id} 对应的执行任务状态(status)不是26126860808229(已完成),此时不能执行入库"); continue; } var WmsCarryCode = _repository.AsSugarClient().Queryable().Where(it => it.carry_id == carry.id).OrderByDescending(it => it.id).First(); // 用适当的字段替换 YourTimestampField if (WmsCarryCode != null) { Logger.LogInformation($"【ScanInStock】 八工位 {key} 查找到托盘{carry.id}在WmsCarryCode中存在"); VisualDevModelDataCrInput input = new VisualDevModelDataCrInput(); input.data = new Dictionary(); input.data.Add("barcode", coderesult); input.data.Add("codeqty", WmsCarryCode.codeqty);//条码数量 input.data.Add("material_code", WmsCarryCode.material_code); input.data.Add("extras", key);//location_code input.data.Add("warehouse_id", "1");//TEST input.data.Add("bill_code", "");//采购收货单号 input.data.Add("code_batch", WmsCarryCode.code_batch!);//批次 input.data.Add("material_specification", WmsCarryCode.material_specification!);//规格型号 input.data.Add("container_no", WmsCarryCode.container_no!);//箱号 input.data.Add("material_id", WmsCarryCode.material_id); input.data.Add("id", null); _wmsPDAScanInStock.ScanInStockByRedis(input).Wait(); } } } } catch (Exception ex) { Logger.LogInformation($"【ScanInStock】 八工位扫到码发送入库请求发生异常:{ex}"); } } } private void SSXcode(object state) { Dictionary dic = new Dictionary(); //有问题 dic.Add("东面提升机输送线", new string[] { "下升降机判断请求", "下升降机判断条码", "下升降机判断完毕", "下升降机判断结果" }); Dictionary putdic = new Dictionary(); putdic.Add("SSX-111-011", 11); putdic.Add("SSX-111-012", 12); foreach (var key in dic.Keys) { try { var strs = dic.Where(p => p.Key == key).First().Value; string dataflag = _redisData.GetHash(key, strs[0]).Result; JObject? resflag = JsonConvert.DeserializeObject(dataflag); //Logger.LogInformation($"【定时任务SSXcode】 {key}->{strs[0]} 采集结果:{resflag}"); bool re = resflag != null && resflag["Value"] != null ? resflag.Value("Value") : false; if (!re) continue; string data = _redisData.GetHash(key, strs[1]).Result; JObject? res = JsonConvert.DeserializeObject(data); //Logger.LogInformation($"【定时任务SSXcode】 {key}->{strs[1]} 采集结果:{res}"); string? result = res != null && res["Value"] != null ? res.Value("Value") : ""; if (!string.IsNullOrEmpty(result)) { if (result.Length < 5) { result = "LX" + result.Replace("\r", ""); } var DistaskH = _repository.AsSugarClient().Queryable().Where(p => p.carry_code == result && p.status != WmsWareHouseConst.TASK_BILL_STATUS_COMPLE_ID).OrderByDescending(p => p.create_time).First(); if (DistaskH != null) { Dictionary dicCommand2 = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = key, ["token"] = _eleCtlCfg.token, ["TagName"] = strs[3], ["Value"] = putdic.Keys.Contains(DistaskH.startlocation_code) ? putdic.Where(p => p.Key == DistaskH.startlocation_code).First().Value.ToString() : "13", }; HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand2).Wait(); Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = key, ["token"] = _eleCtlCfg.token, ["TagName"] = strs[2], ["Value"] = "true", }; HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand).Wait(); } else { Dictionary dicCommand2 = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = key, ["token"] = _eleCtlCfg.token, ["TagName"] = strs[3], ["Value"] = "13", }; HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand2).Wait(); Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = key, ["token"] = _eleCtlCfg.token, ["TagName"] = strs[2], ["Value"] = "true", }; HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand).Wait(); } } } catch (Exception ex) { Logger.LogInformation($"【定时任务SSXcode】发生异常 {ex}"); } } } public void Dispose() { Readtimer?.Dispose(); CheckGettimer?.Dispose(); Scantimer?.Dispose(); SSXcodetimer?.Dispose(); } #region 二楼升降机 // 上升降机 private void Floor2UpMachinecode(object args) { // 补充料架 //var DistaskH = _repository.AsSugarClient().Queryable().Where(p => p.carry_code == && p.status != WmsWareHouseConst.TASK_BILL_STATUS_COMPLE_ID).OrderByDescending(p => p.create_time).First(); // MechanicalArmConsts.上升降机满托2数量 // 扫码分配码垛位 } // 下升降机 private void Floor2DownMachinecode(object args) { // 补充料架 // 扫码分配拆垛位 } // 上下升降机生成预任务(补充料架、上升降机取货到料架、上升降机满托运走,下升降机拿货到输送线、下升降机空托运走) private void Floor2UpDownMachinecode_createPretask() { } // 上下升降机生成任务执行 private void Floor2UpDownMachinecode_createDistask() { } private Tuple Floor2UpDownMachinecode_GetTag(MechanicalArmConsts tag) { //string key = "东面提升机输送线"; //string data = _redisData.GetHash(key, tag.ToString()).Result; //JObject? res = JsonConvert.DeserializeObject(data); //T result = res != null && res["Value"] != null ? res.Value("Value") : false; //return new Tuple(result, res.Value("Value")); return new Tuple(false, default(T)); } /// /// Agv调度 /// /// /// /// private async Task Floor2UpDownMachinecode_AgvDispatch(List disTasks, CancellationToken token) { LoggerFloor2UpDownMachine.LogInformation("【AgvDispatch】 Agv任务执行...."); //调用AGV创建任务链接口 try { AgvRequestConfig requestCfg = App.Configuration.Build(); string url = requestCfg.AgvRequestUrls.CreateTaskChainUrl; LoggerFloor2UpDownMachine.LogInformation($"【AgvDispatch】 Agv任务执行的disTasks:{JsonConvert.SerializeObject(disTasks)}"); var taskChainCodeDic = disTasks.Where(t => !t.groups.IsNullOrWhiteSpace()).GroupBy(g => g.groups!) .ToDictionary(x => x.Key, x => x.Select(it => new { taskCode = it.bill_code, sourceName = it.startpoint_code, targetName = it.endpoint_code, containerCode = it.carry_code, })); LoggerFloor2UpDownMachine.LogInformation($"【AgvDispatch】 Agv任务执行的taskChainCodeDic:{JsonConvert.SerializeObject(taskChainCodeDic)}"); foreach ((string k, object v) in taskChainCodeDic) { var dis = disTasks.Where(p => p.groups == k).First(); dynamic reqBody = new ExpandoObject(); reqBody.taskChainCode = k; reqBody.type = (int)EnumTaskChainType.AGV; reqBody.sequential = false; reqBody.taskChainPriority = 0; reqBody.taskList = v; reqBody.floor = dis.end_floor; LoggerFloor2UpDownMachine.LogInformation($"【AgvDispatch】 Agv任务执行 开始请求联核/task-chain/create接口 请求地址:{url} 请求参数:{reqBody} "); dynamic respBody = await HttpClientHelper.PostStreamAsync(url, reqBody, token); LoggerFloor2UpDownMachine.LogInformation($"【AgvDispatch】 Agv任务执行 接收到联核/task-chain/create接口信息:{respBody}"); } } catch (Exception ex) { LoggerFloor2UpDownMachine.LogInformation($"【AgvDispatch】 agv任务执行 请求联核/task-chain/create接口失败 异常信息:{ex}"); throw; } } private void Floor2UpDownMachinecode_SetTag() { string key = "东面提升机输送线"; } #endregion public Task StartAsync(CancellationToken cancellationToken) { Readtimer = new Timer(GetRedisData, null, TimeSpan.Zero, TimeSpan.FromSeconds(300)); CheckGettimer = new Timer(CheckGet, null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); Scantimer = new Timer(ScanInStock, null, TimeSpan.Zero, TimeSpan.FromSeconds(60)); SSXcodetimer= new Timer(SSXcode, null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); // 二楼上升降机 Floor2UpMachinecodetimer = new Timer(Floor2UpMachinecode, null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); // 二楼下升降机 Floor2DownMachinecodetimer = new Timer(Floor2DownMachinecode, null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); return Task.CompletedTask; } public Task StopAsync(CancellationToken cancellationToken) { return Task.CompletedTask; } } }