using System; using System.Diagnostics; using System.Dynamic; using System.Linq; using System.Linq.Expressions; using System.Net; using System.Security.Policy; using System.Text; using System.Threading.Tasks; using Aop.Api.Domain; using Aspose.Cells; using JNPF; using JNPF.Common.Contracts; using JNPF.Common.Core.Manager; using JNPF.Common.Enums; using JNPF.Common.Extension; using JNPF.Common.Manager; using JNPF.Common.Security; using JNPF.FriendlyException; using JNPF.Systems.Interfaces.System; using Mapster; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.CodeAnalysis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using NetTaste; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NPOI.OpenXmlFormats.Dml; using NPOI.SS.Formula.Functions; using Org.BouncyCastle.Crypto; using SqlSugar; using Tnb.BasicData.Entities; using Tnb.Common.Extension; using Tnb.Common.Redis; using Tnb.Common.Utils; using Tnb.ProductionMgr.Entities; using Tnb.QcMgr.Entities; using Tnb.WarehouseMgr.Entities; using Tnb.WarehouseMgr.Entities.Configs; using Tnb.WarehouseMgr.Entities.Consts; using Tnb.WarehouseMgr.Entities.Dto; using Tnb.WarehouseMgr.Entities.Dto.Inputs; using Tnb.WarehouseMgr.Entities.Dto.Outputs; using Tnb.WarehouseMgr.Entities.Dto.Queries; using Tnb.WarehouseMgr.Entities.Entity; using Tnb.WarehouseMgr.Entities.Enums; using Tnb.WarehouseMgr.Interfaces; namespace Tnb.WarehouseMgr { /// /// 库房业务类(出入库) /// public class WareHouseService : DevServBase, IWareHouseService { private readonly ISqlSugarClient _db; private readonly IDictionaryDataService _dictionaryDataService; private readonly IBillRullService _billRullService; private readonly IUserManager _userManager; private readonly ICacheManager _cacheManager; private readonly IElevatorControlService _elevatorControlService; private readonly IWmsCarryBindService _wmsCarryBindService; private static readonly Dictionary _elevatorAgvCtlStatusMap = new(StringComparer.OrdinalIgnoreCase); private readonly ElevatorControlConfiguration _eleCtlCfg = App.Configuration.Build(); private static Dictionary locMap = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly IConfiguration _configuration; private readonly RedisData _redisData; public static SemaphoreSlim s_floor2CreatePretask = new(1); public Func AddUnExecuteTask { get; set; } public WareHouseService(ISqlSugarRepository repository, IDictionaryDataService dictionaryDataService, RedisData redisData, IBillRullService billRullService, IUserManager userManager, ICacheManager cacheManager, IElevatorControlService elevatorControlService, IWmsCarryBindService wmsCarryBindService //IConfiguration configuration ) : base(repository.AsSugarClient()) { _db = repository.AsSugarClient(); _dictionaryDataService = dictionaryDataService; _billRullService = billRullService; _userManager = userManager; _cacheManager = cacheManager; _elevatorControlService = elevatorControlService; _redisData = redisData; _wmsCarryBindService = wmsCarryBindService; //_configuration = configuration; } /// /// 根据载具Id带出库位、仓库信息 /// /// 载具id /// /// returns: ///
{ ///
carry_id:载具Id ///
carry_name:载具名称 ///
location_id:库位Id ///
location_name:库位名称 ///
warehouse_id:库房Id ///
warehouse_name:库房名称 ///
} ///
[HttpGet] public async Task GetLocationAndWorkHouseByCarryId([FromRoute] string carryId) { var items = await _db.Queryable().LeftJoin((a, b) => a.location_id == b.id) .LeftJoin((a, b, c) => b.wh_id == c.id) .Where(a => a.id == carryId) .Select((a, b, c) => new { carry_id = a.id, a.carry_name, location_id = b.id, b.location_name, warehouse_id = c.id, warehouse_name = c.whname, }) .ToListAsync(); return items ?? Enumerable.Empty(); } /// /// 库房业务,入库、出库申请新增修改功能 /// /// /// [HttpPost] public async Task ApplyFor(InOutStockApplyforUpInput input) { if (input == null) { throw new ArgumentNullException(nameof(input)); } async Task _updateLocalFunc(InOutStockApplyforUpInput input) where TStockD : BaseEntity, new() where TStockCode : BaseEntity, IInOutStockCode, new() { TStockD instockD = input.Adapt(); global::System.Collections.Generic.List? stockCodes = input.InstockCodes?.Adapt>(); if (stockCodes?.Count > 0) { stockCodes.ForEach(x => { if (x.id.IsNullOrWhiteSpace()) { x.id = SnowflakeIdHelper.NextId(); } x.bill_d_id = instockD.id; }); } return await Update(instockD, stockCodes!); } bool isOk = input.inoutStockType switch { EnumInOutStockType.In => await _updateLocalFunc(input), EnumInOutStockType.Out => await _updateLocalFunc(input), _ => throw new ArgumentOutOfRangeException(nameof(input.inoutStockType), $"Not expected EnumInOutStockType value: {input.inoutStockType}"), }; if (!isOk) { throw Oops.Oh(ErrorCode.COM1001); } } /// /// 根据明细Id获取出入库明细信息 /// /// [HttpGet] public async Task GetInOutStockCodesById([FromQuery] InOutStockDetailQuery input) { dynamic? result = input.inoutStockType switch { EnumInOutStockType.In => await FetchInOutStockCodesById(input.bill_d_id), EnumInOutStockType.Out => await FetchInOutStockCodesById(input.bill_d_id), _ => throw new NotImplementedException(), }; return result ?? Enumerable.Empty(); } /// /// 入库策略 /// /// [HttpGet] public async Task> InStockStrategy([FromQuery] InStockStrategyQuery input) { List items = new(); try { WmsInstockPolicies policy = await _db.CopyNew().Queryable().Where(it => it.status == 1).FirstAsync(); if (policy == null) { throw new AppFriendlyException("没有可用的策略", 500); } Expression> whereExp = Expressionable.Create() .And(it => it.wh_id == input.warehouse_id) .And(it => it.is_lock == 0) .And(it => it.is_type == ((int)EnumLocationType.存储库位).ToString()) .And(it => it.is_use == ((int)EnumCarryStatus.空闲).ToString()) .ToExpression(); items = await _db.CopyNew().Queryable().Where(whereExp).OrderBy(policy.policy).ToListAsync(); } catch (Exception) { throw; } return items.Take(input.Size).ToList(); } /// /// 是否为一楼出库工位 /// /// /// public string[] GetFloor1OutstockLocation() { return new string[3] { WmsWareHouseConst.FinishproductOutstockStation1 , WmsWareHouseConst.FinishproductOutstockStation2 , WmsWareHouseConst.FinishproductOutstockStation3 }; } /// /// 出库策略-销售出库下发 /// /// [HttpGet] public async Task>> OutStockStrategy_saleRelease([FromQuery] OutStockStrategyQuery input) { Expressionable whereExprable = Expressionable.Create() .And((a, b, c) => a.is_lock == 0 && c.is_lock == 0) .And((a, b, c) => !string.IsNullOrEmpty(a.location_id)) .And((a, b, c) => c.is_type == ((int)EnumLocationType.存储库位).ToString()) .And((a, b, c) => a.out_status == "0") .And((a, b, c) => c.wh_id == input.warehouse_id) .AndIF(!string.IsNullOrEmpty(input.material_id), (a, b, c) => b.material_id == input.material_id) .AndIF(!string.IsNullOrEmpty(input.code_batch), (a, b, c) => b.code_batch == input.code_batch) .AndIF(!string.IsNullOrEmpty(input.material_specification), (a, b, c) => b.material_specification == input.material_specification) .AndIF(!string.IsNullOrEmpty(input.container_no), (a, b, c) => b.container_no == input.container_no) .AndIF(!string.IsNullOrEmpty(input.carrystd_id), (a, b, c) => a.carrystd_id == input.carrystd_id); Expression> carryStatusFilterExp = !input.material_id.IsNullOrWhiteSpace() ? (a, b, c) => a.carry_status == ((int)EnumCarryStatus.占用).ToString() : (a, b, c) => a.carry_status == ((int)EnumCarryStatus.空闲).ToString(); _ = whereExprable.And(carryStatusFilterExp); Expression> whereExpr = whereExprable.ToExpression(); SqlSugarClient cyDb = _db.CopyNew(); List> items = cyDb.Queryable().LeftJoin((a, b) => a.id == b.carry_id) .LeftJoin((a, b, c) => a.location_id == c.id) .Where(whereExpr) //.OrderByIF((a,b,c)=>SqlFunc.IsNullOrEmpty()) .OrderBy("a.location_code,layers,loc_line,loc_column") .Select((a, b, c) => new { WmsCarryH = a, WmsCarryCode = b, BasLocation = c, codeqty = b.codeqty }).ToList().Select(r => { input.qty = input.qty - r.codeqty; // 出库数量与托盘上的数量不一致需要进行分拣 if (input.qty < 0) { r.WmsCarryCode.codeqty = input.qty + r.codeqty; return new Tuple("分拣任务", r.WmsCarryH, r.WmsCarryCode, r.BasLocation); } else { // 正常预任务出库 return new Tuple("预任务", r.WmsCarryH, r.WmsCarryCode, r.BasLocation); } }).ToList(); return items; } public async Task> OutStockStrategy([FromQuery] OutStockStrategyQuery input) { Expressionable whereExprable = Expressionable.Create() .And((a, b, c) => a.is_lock == 0) .And((a, b, c) => !string.IsNullOrEmpty(a.location_id)) .And((a, b, c) => c.is_type == ((int)EnumLocationType.存储库位).ToString()) .And((a, b, c) => a.out_status == "0") .And((a, b, c) => c.wh_id == input.warehouse_id) .AndIF(!string.IsNullOrEmpty(input.material_id), (a, b, c) => b.material_id == input.material_id) .AndIF(!string.IsNullOrEmpty(input.code_batch), (a, b, c) => b.code_batch == input.code_batch) .AndIF(!string.IsNullOrEmpty(input.material_specification), (a, b, c) => b.material_specification == input.material_specification) .AndIF(!string.IsNullOrEmpty(input.container_no), (a, b, c) => b.container_no == input.container_no) .AndIF(!string.IsNullOrEmpty(input.carrystd_id), (a, b, c) => a.carrystd_id == input.carrystd_id); Expression> carryStatusFilterExp = !input.material_id.IsNullOrWhiteSpace() ? (a, b, c) => a.carry_status == ((int)EnumCarryStatus.占用).ToString() : (a, b, c) => a.carry_status == ((int)EnumCarryStatus.空闲).ToString(); _ = whereExprable.And(carryStatusFilterExp); Expression> whereExpr = whereExprable.ToExpression(); SqlSugarClient cyDb = _db.CopyNew(); WmsInstockPolicies policy = await cyDb.Queryable().Where(it => it.status == 1).FirstAsync(); if (policy == null) { throw new AppFriendlyException("没有可用策略", 500); } List items = await cyDb.Queryable().LeftJoin((a, b) => a.id == b.carry_id) .LeftJoin((a, b, c) => a.location_id == c.id) .Where(whereExpr) //.OrderByIF((a,b,c)=>SqlFunc.IsNullOrEmpty()) .OrderBy(policy.policy) .Select() .ToListAsync(); return input.Size > 0 ? items.Take(input.Size).ToList() : items; } /// /// 判断CTU是否可以放货 /// /// [HttpPost] [AllowAnonymous] public async Task CheckPut(CheckPutInput input) { Logger.Information("联核请求CheckPut接口传入参数为:" + JsonConvert.SerializeObject(input)); Dictionary putdic = new Dictionary(); putdic.Add("SSX-011-006", new string[] { "YTCS", "AllowEmptyIn_CS06" }); putdic.Add("SSX-021-007", new string[] { "东面提升机输送线", "出库输送线7允许入箱" }); putdic.Add("SSX-121-009", new string[] { "东面提升机输送线", "上升降机9允许入箱" }); putdic.Add("SSX-121-010", new string[] { "东面提升机输送线", "上升降机10允许入箱" }); putdic.Add("SSX-021-003", new string[] { "YTCS", "AllowCtuEmptyIn_CS03" }); putdic.Add("SSX-021-001", new string[] { "YTCS", "AllowCtuEmptyIn_CS01" }); putdic.Add("ZSSSXCTU02", new string[] { "YTCS", "AllowCtuFullOut_CS04", }); putdic.Add("ZSSSXCTU01", new string[] { "YTCS", "AllowCtuFullOut_CS02", }); var strs = new string[] { }; if (!putdic.ContainsKey(input.targetName)) throw new AppFriendlyException("点位" + input.targetName + "不存在", 500); strs = putdic.Where(p => p.Key == input.targetName).First().Value; bool flag = await _redisData.HashExist(strs[0], strs[1]); if (!flag) { throw new AppFriendlyException("点位" + input.targetName + "不存在", 500); } string data = await _redisData.GetHash(strs[0], strs[1]); Logger.Information("联核请求CheckPut接口查询X2Server数据:" + data); JObject? res = JsonConvert.DeserializeObject(data); bool result = res != null && res["Value"] != null ? res.Value("Value") : false; if (!result) throw new AppFriendlyException("点位" + input.targetName + "不可放", 500); Logger.Information("联核请求CheckPut接口结果:CTU可放货" + data); } /// /// 判断CTU是否可以取货 /// /// public async Task Check(string code, string action) { Logger.Information($"【Check】 判断CTU是否可以取货 {code} {action}"); Dictionary putdic = new Dictionary(); Dictionary getdic = new Dictionary(); putdic.Add("ZSSSXCTU02", new string[] { "YTCS", "AllowCtuFullOut_CS04", }); putdic.Add("ZSSSXCTU01", new string[] { "YTCS", "AllowCtuFullOut_CS02", }); getdic.Add("ZSSSXCTU01", new string[] { "YTCS", "AllowAgvEmptyOut_CS01" }); getdic.Add("ZSSSXCTU02", new string[] { "YTCS", "AllowAgvEmptyOut_CS03" }); putdic.Add("ZS-C01-1", new string[] { "hxjC", "A2允许入空箱", }); getdic.Add("ZS-C01-2", new string[] { "hxjC", "A2允许取满箱" }); putdic.Add("ZS-C02-1", new string[] { "hxjC", "A3允许入空箱", }); getdic.Add("ZS-C02-2", new string[] { "hxjC", "A3允许取满箱" }); putdic.Add("ZS-C03-1", new string[] { "hxjC", "A4允许入空箱", }); getdic.Add("ZS-C03-2", new string[] { "hxjC", "A4允许取满箱" }); putdic.Add("ZS-C04-1", new string[] { "hxjC", "A5允许入空箱", }); getdic.Add("ZS-C04-2", new string[] { "hxjC", "A5允许取满箱" }); putdic.Add("ZS-C05-1", new string[] { "hxjC", "A6允许入空箱", }); getdic.Add("ZS-C05-2", new string[] { "hxjC", "A6允许取满箱" }); putdic.Add("ZS-C06-1", new string[] { "hxjC", "A7允许入空箱", }); getdic.Add("ZS-C06-2", new string[] { "hxjC", "A7允许取满箱" }); var strs = new string[] { }; if (action == "LOAD")//取货 { if (!getdic.ContainsKey(code)) { return false; } strs = getdic.Where(p => p.Key == code).First().Value; bool flag = _redisData.HashExist(strs[0], strs[1]).Result; if (!flag) { Logger.Information($"【Check】 判断CTU是否可以取货 {code} {action} flag:{flag} "); return false; } 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) return false; return true; } else if (action == "UNLOAD")//放货 { if (!putdic.ContainsKey(code)) return false; strs = putdic.Where(p => p.Key == code).First().Value; bool flag = _redisData.HashExist(strs[0], strs[1]).Result; if (!flag) { Logger.Information($"【Check】 判断CTU是否可以取货 {code} {action} flag:{flag} "); return false; } 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) return false; return true; } return false; } public async Task SsxControl(WmsDistaskH disTask, string action) { Logger.Information($"输送线控制SsxControl传入参数: {JsonConvert.SerializeObject(disTask)} {action}"); Dictionary putdic = new Dictionary(); Dictionary getdic = new Dictionary(); getdic.Add("SSX-021-005", new string[] { "YTCS", "FullOut_CS05Done", "true" }); getdic.Add("SSX-111-011", new string[] { "东面提升机输送线", "下升降机11出箱完毕", "true" }); getdic.Add("SSX-111-012", new string[] { "东面提升机输送线", "下升降机12出箱完毕", "true" }); getdic.Add("ZSSSXCTU02", new string[] { "YTCS", "右输送线上层允许出箱3", "true" }); getdic.Add("ZSSSXCTU01", new string[] { "YTCS", "左输送线上层允许出箱1", "true" }); getdic.Add("SSX-011-008", new string[] { "东面提升机输送线", "入库输送线8出箱完毕", "true" }); getdic.Add("ZS-C01-2", new string[] { "hxjC", "A2AGV允许入满箱", "true" }); getdic.Add("ZS-C02-2", new string[] { "hxjC", "A3AGV允许入满箱", "true" }); getdic.Add("ZS-C03-2", new string[] { "hxjC", "A4AGV允许入满箱", "true" }); getdic.Add("ZS-C04-2", new string[] { "hxjC", "A5AGV允许入满箱", "true" }); getdic.Add("ZS-C05-2", new string[] { "hxjC", "A6AGV允许入满箱", "true" }); getdic.Add("ZS-C06-2", new string[] { "hxjC", "A7AGV允许入满箱", "true" }); putdic.Add("SSX-021-007", new string[] { "东面提升机输送线", "出库输送线7入箱完毕", "true" }); putdic.Add("SSX-011-006", new string[] { "YTCS", "EmptyIn_CS06Done", "true" }); putdic.Add("SSX-021-003", new string[] { "YTCS", "AgvFullIn_CS03Done", "true" }); putdic.Add("SSX-021-001", new string[] { "YTCS", "CtuEmptyIn_CS01Done", "true" }); putdic.Add("ZSSSXCTU02", new string[] { "YTCS", "右输送线下层允许入箱4", "true" }); putdic.Add("ZSSSXCTU01", new string[] { "YTCS", "左输送线下层允许入箱2", "true" }); putdic.Add("SSX-121-009", new string[] { "东面提升机输送线", "上升降机9入箱完毕", "true" }); putdic.Add("SSX-121-010", new string[] { "东面提升机输送线", "上升降机10入箱完毕", "true" }); putdic.Add("YCLCKBGW", new string[] { "CP8", "PutDoneEmptyBox", "true" }); putdic.Add("ZS-C01-1", new string[] { "hxjC", "A2AGV允许出空箱", "true" }); putdic.Add("ZS-C02-1", new string[] { "hxjC", "A3AGV允许出空箱", "true" }); putdic.Add("ZS-C03-1", new string[] { "hxjC", "A4AGV允许出空箱", "true" }); putdic.Add("ZS-C04-1", new string[] { "hxjC", "A5AGV允许出空箱", "true" }); putdic.Add("ZS-C05-1", new string[] { "hxjC", "A6AGV允许出空箱", "true" }); putdic.Add("ZS-C06-1", new string[] { "hxjC", "A7AGV允许出空箱", "true" }); if (action == "LOAD")//取货 { if (getdic.Keys.Contains(disTask.startlocation_code)) { var strarr = getdic.Where(p => p.Key == disTask.startlocation_code).First().Value; Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = strarr[0], ["token"] = _eleCtlCfg.token, ["TagName"] = strarr[1], ["Value"] = strarr[2], }; Logger.Information($"SsxControlLOAD:{JsonConvert.SerializeObject(dicCommand)}"); var str = await HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand); Logger.Information($"SsxControlLOAD:{str}"); } } else if (action == "UNLOAD")//放货 { if (putdic.Keys.Contains(disTask.endlocation_code)) { var strarr = putdic.Where(p => p.Key == disTask.endlocation_code).First().Value; Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = strarr[0], ["token"] = _eleCtlCfg.token, ["TagName"] = strarr[1], ["Value"] = strarr[2], }; Logger.Information($"SsxControlUNLOAD:{dicCommand}"); var str = await HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand); Logger.Information($"SsxControlUNLOAD:{str}"); } } } /// /// // 二楼机械臂 /// /// public async Task Floor2MechanicalComplete(WmsDistaskH disTask, string action) { List rackAreaPoints = new List(); // 二楼料架区点位 rackAreaPoints.Add("AS01"); rackAreaPoints.Add("AS02"); rackAreaPoints.Add("AX01"); rackAreaPoints.Add("AX02"); if (disTask.area_code == "E") { Logger.Information($"【二楼机械臂Floor2MechanicalComplete】收到到货完成信号 传入参数: {disTask.bill_code} {action}"); SqlSugarClient db = _db.CopyNew(); if (action == "UNLOAD") { // 去料架区放货 if (rackAreaPoints.Contains(disTask.endlocation_code)) { ISugarQueryable WmsMechanicalArmHs = db.Queryable().Where(r => r.point_code == disTask.endpoint_code); if (WmsMechanicalArmHs.Count() == 0) { Logger.Information($"【二楼机械臂Floor2MechanicalComplete】 任务执行终点{disTask.endpoint_code} 与料架区的点位不匹配"); return false; } WmsMechanicalArmH target = WmsMechanicalArmHs.First(); // 回写料架和AGV确认 await db.Updateable().SetColumns(r => new WmsMechanicalArmH { agvconfirm = 1, rackid = disTask.carry_id, rackcode = disTask.carry_code }).Where(r => r.id == target.id).ExecuteCommandAsync(); Logger.Information($"【二楼机械臂Floor2MechanicalComplete】{disTask.bill_code} AGV已到货"); } else // 去暂存仓放货 { // 回写料架料箱绑定表的库位 ISugarQueryable WmsCarryCodes = db.Queryable() .InnerJoin((a, b) => b.membercarry_id == a.carry_id) .Where((a, b) => b.carry_id == disTask.carry_id); var WmsCarryCodeList = WmsCarryCodes.ToList(); WmsCarryCodeList.ForEach(r => { r.location_id = disTask.endlocation_id; r.location_code = disTask.endlocation_code; }); await db.Updateable(WmsCarryCodeList).ExecuteCommandAsync(); } } else { // 去暂存仓取货 if (rackAreaPoints.Contains(disTask.endlocation_code)) { Logger.Information($"【二楼机械臂Floor2MechanicalComplete】{disTask.bill_code} AGV在暂存仓取货完成"); } else // 去料架区取货 { ISugarQueryable WmsMechanicalArmHs = db.Queryable().Where(r => r.point_code == disTask.startpoint_code); if (WmsMechanicalArmHs.Count() == 0) { Logger.Information($"【二楼机械臂Floor2MechanicalComplete】 任务执行起点{disTask.endpoint_code} 与料架区的点位不匹配"); return false; } WmsMechanicalArmH target = WmsMechanicalArmHs.First(); if (target.note == "上升降机") { bool result = await Floor2UpDownMachinecode_SetTag($"上升降机满托{target.stackingposition}移走", "true"); Logger.LogInformation($@"【上升降机】设定升上升降机满托{target.stackingposition}移走 结果为 {result}"); if (!result) { throw new Exception($@"【上升降机】设定升上升降机满托{target.stackingposition}移走 结果为 {result}"); } } else if (target.note == "下升降机") { bool result = await Floor2UpDownMachinecode_SetTag($"下升降机空托{target.stackingposition}移走", "true"); Logger.LogInformation($@"【上升降机】设定升下升降机空托{target.stackingposition}移走 结果为 {result}"); if (!result) { throw new Exception($@"【上升降机】设定升下升降机空托{target.stackingposition}移走 结果为 {result}"); } } //回写出库单状态 await db.Updateable().SetColumns(r => new WmsEmptyOutstockH { bindrackcomplete = WmsWareHouseConst.BILLSTATUS_COMPLETE_ID }).Where(r => r.bill_code == target.outbill).ExecuteCommandAsync(); // 重置料架区 await db.Updateable().SetColumns(r => new WmsMechanicalArmH { stackingcount = 0, barcodes = "", outbill = "", maxnum = 0, iscreatepretask = 0, rackcode = "", rackid = "", agvconfirm = 0, mechanicalconfirm = 0 }).Where(r => r.id == target.id).ExecuteCommandAsync(); Logger.Information($"【二楼机械臂Floor2MechanicalComplete】{disTask.bill_code} AGV在料架区取货完成"); } } } return true; } private async Task Floor2UpDownMachinecode_SetTag(string tag, string value) { string DevName = "东面提升机输送线"; Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = DevName, ["token"] = _eleCtlCfg.token, ["TagName"] = tag, ["Value"] = value, }; string result = await HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand); // 测试 //JObject valueJson = new JObject(); //valueJson["Value"] = value; //bool res = await _redisData.HSet(DevName, tag, valueJson.ToString()); //return true; return result.Contains("Ok"); } /// /// 生成任务执行 /// /// [HttpPost] public async Task GenTaskExecute() { CTUTaskExecute(); await s_taskExecuteSemaphore.WaitAsync(); Stopwatch sw = Stopwatch.StartNew(); CancellationTokenSource agvCts = new(); SqlSugarClient db = _db.CopyNew(); try { //获取所有未下发的预任务申请 Logger.Information("【GenTaskExecute】 开始获取未下发的预任务..."); ISugarQueryable sugarQueryable = db.Queryable().InnerJoin((a, b) => a.startlocation_id == b.location_id && a.carry_id == b.id) .InnerJoin((a, b, c) => a.area_id == c.id) .InnerJoin((a, b, c, d) => a.endlocation_id == d.id && d.is_use == "0") .Where(a => a.status == WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID && !string.IsNullOrWhiteSpace(a.startlocation_id)) .OrderBy(a => new { priority = SqlFunc.Desc(a.priority), a.bill_code }) .Select((a, b, c, d) => new WmsPretaskH { move_num = c.move_num, third_eqp_type = c.third_eqp_type, }, true); Logger.Information("【GenTaskExecute】 执行SQL: " + sugarQueryable.ToSqlString()); List preTasks = await sugarQueryable.ToListAsync(); //List executedPreTasks = await db.Queryable().Where(it => it.status != WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID && it.status != WmsWareHouseConst.PRETASK_BILL_STATUS_COMPLE_ID).ToListAsync(); List agvElevatorTasks = preTasks .Where(it => it.endlocation_code.StartsWith("DT", StringComparison.OrdinalIgnoreCase) && !it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase)) .ToList(); var elePreTasks = preTasks.Where(it => it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase)).ToList(); var normalPreTasks = preTasks.Where(it => it.area_code != "B" && !agvElevatorTasks.Concat(elePreTasks).Select(x => x.endlocation_code).Contains(it.endlocation_code)).ToList(); //Logger.Information("【GenTaskExecute】 电梯预任务elePreTasks:" + JsonConvert.SerializeObject(elePreTasks)); //Logger.Information("【GenTaskExecute】 AGV/CTU/KIVA预任务normalPreTasks:" + JsonConvert.SerializeObject(normalPreTasks)); //Logger.Information("【GenTaskExecute】 AGV电梯预任务agvElevatorTasks:" + JsonConvert.SerializeObject(agvElevatorTasks)); /* IEnumerable firstEleGrp = agvElevatorTasks.GroupBy(g => g.endlocation_code).Select(t => t.OrderBy(o => o.bill_code).FirstOrDefault()); agvElevatorTasks = firstEleGrp?.ToList() ?? Enumerable.Empty().ToList()!; */ //如果电梯任务,预Agv任务存在相同目标库位,删除Agv任务保证电梯任务先行 var equalEndLocPreTasks = elePreTasks.Select(x => x.endlocation_code).Intersect(agvElevatorTasks.Select(x => x.endlocation_code)); if (equalEndLocPreTasks.Any()) { Logger.Information("【GenTaskExecute】 执行:如果电梯任务,预Agv任务存在相同目标库位,删除Agv任务保证电梯任务先行 "); agvElevatorTasks = agvElevatorTasks.Where(x => !equalEndLocPreTasks.Contains(x.endlocation_code)).ToList(); } preTasks = normalPreTasks.Concat(agvElevatorTasks).Concat(elePreTasks).ToList(); //一楼中储仓CTU List ids = preTasks.Select(x => x.id).Distinct().ToList(); List? preTaskCodes = await db.Queryable().Where(it => ids.Contains(it.bill_id)).ToListAsync(); if (preTasks.Count > 0) { //根据预任务管理区分组,获取到所有分组后的预任务,遍历每个预任务 是否为任务链,通过管理区ID List> preTaskGroups = preTasks.GroupBy(g => g.area_code).ToList(); List disTasks = new(); List distaskCodes = new(); foreach (IGrouping? itGroup in preTaskGroups) { List items = itGroup.Adapt>(); for (int i = 0, cnt = items.Count; i < cnt; i++) { items[i].id = SnowflakeIdHelper.NextId(); items[i].status = WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID; } int moveNum = itGroup.First().move_num; int itemsCount = items.Count; int mod = itemsCount % moveNum > 0 ? (itemsCount / moveNum) + 1 : itemsCount / moveNum; WmsDistaskH[] arrary = items.ToArray(); //for (int i = 1; i <= mod; i++) { if (moveNum >= 1) { List areaPreTasks = itGroup.ToList(); if (areaPreTasks.Any(x => x.third_eqp_type.ToEnum() != EnumTaskChainType.CTU)) { Logger.Information("非CTU任务链生成"); for (int i = 0; i < items.Count; i++) { var num = (i + 1); var x = items[i]; string groupCode = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_TASK_EXECUTE_ENCODE).Result; x.is_chain = 0; x.groups = groupCode; x.bill_code = $"{groupCode}-1"; } } else if ((moveNum >= areaPreTasks.Count && areaPreTasks.Count > 1) || moveNum <= areaPreTasks.Count) { Logger.Information("CTU任务链生成"); string groupCode = await _billRullService.GetBillNumber(WmsWareHouseConst.WMS_TASK_EXECUTE_ENCODE); items.ForEach(x => x.is_chain = 1); int start = 0; int end = Math.Min(itemsCount, moveNum); List arrList = new(mod); while (start < itemsCount) { WmsDistaskH[] subArray = arrary[start..end]; arrList.Add(subArray); start = end; end = Math.Min(end + moveNum, arrary.Length); } foreach (WmsDistaskH[] arr in arrList) { for (int j = 1, len = arr.Length; j <= len; j++) { arr[j - 1].groups = groupCode; arr[j - 1].bill_code = $"{groupCode}-{j}"; } } } } } if (preTaskCodes?.Count > 0) { foreach (WmsDistaskH disTask in items) { List curPreTaskCodes = preTaskCodes.FindAll(x => x.bill_id == disTask.pretask_id); List curDisTaskCodes = curPreTaskCodes.Adapt>(); curDisTaskCodes.ForEach(x => { x.id = SnowflakeIdHelper.NextId(); x.bill_id = disTask.id; x.create_time = DateTime.Now; }); distaskCodes.AddRange(curDisTaskCodes); } } disTasks.AddRange(items); } await db.Ado.BeginTranAsync(); int row = await db.Insertable(disTasks).ExecuteCommandAsync(); Logger.Information("【GenTaskExecute】 插入任务执行表数据: " + JsonConvert.SerializeObject(disTasks)); if (preTaskCodes?.Count > 0) { row = await db.Insertable(distaskCodes).ExecuteCommandAsync(); Logger.Information("【GenTaskExecute】 插入任务执行条码表数据: " + JsonConvert.SerializeObject(disTasks)); } if (row > 0) { List preTaskIds = preTasks.Select(x => x.id).ToList(); List preTaskBill_codes = preTasks.Select(x => x.bill_code).ToList(); row = await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_YXF_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync(); Logger.Information("【GenTaskExecute】 更改这些预任务执行状态为 已下发: " + JsonConvert.SerializeObject(preTaskBill_codes)); } await db.Ado.CommitTranAsync(); Logger.Information("【GenTaskExecute】 预任务执行完成"); Logger.Information($"【GenTaskExecute】_eleCtlCfg.Environment={_eleCtlCfg.Environment}"); if (string.Equals(_eleCtlCfg.Environment, ElevatorConsts.EnvironmentName, StringComparison.OrdinalIgnoreCase)) { //呼梯操作 //获取目标库位为电梯库位的任务 Logger.Information("【GenTaskExecute】操作设备"); var agvDTTasks = disTasks.Where(it => it.endlocation_code.StartsWith("DT", StringComparison.OrdinalIgnoreCase) && !it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase)).ToList(); foreach (var task in agvDTTasks) { ElevagorInfoQuery q = new() { endlocation_id = task.endlocation_id }; Logger.Information($"【GenTaskExecute】呼梯时 根据任务单号获取电梯参数 {JsonConvert.SerializeObject(q)}"); var e = await FindElevatorFromPars(q); Logger.Information($"【GenTaskExecute】呼梯时 根据任务单号获取电梯结果 {JsonConvert.SerializeObject(e)}"); if (e != null) { task.device_id = e.device_id; } } List<(string endlocation_code, string device_id, string id, int start_floor)> endLocCodes = agvDTTasks .Select(it => (it.endlocation_code, it.device_id, it.id, it.start_floor)).ToList(); var callLiftCnt = endLocCodes?.Count ?? 0; Logger.Information($"【GenTaskExecute】呼梯任务数:{callLiftCnt}"); if (endLocCodes?.Count > 0) { if (endLocCodes.Select(x => x.device_id).All(x => !x.IsNullOrWhiteSpace())) { Logger.Information("【GenTaskExecute】呼梯操作"); _ = CallingLanding(endLocCodes); } else { Logger.Error("【GenTaskExecute】呼梯失败,没有设备ID"); return; } } //执行电梯任务 List? elevatorTasks = disTasks.Where(it => it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase)).ToList(); Logger.Information($"【GenTaskExecute】当前电梯任务数:{elevatorTasks?.Count ?? 0}"); if (elevatorTasks?.Count > 0) { foreach (WmsDistaskH? elevatorTask in elevatorTasks) { ElevagorInfoQuery q = new() { endlocation_id = elevatorTask.endlocation_id }; Logger.Information($"【GenTaskExecute】执行电梯任务时 根据任务单号获取电梯参数 {JsonConvert.SerializeObject(q)}"); var e = await FindElevatorFromPars(q); Logger.Information($"【GenTaskExecute】执行电梯任务时 根据任务单号获取电梯结果 {JsonConvert.SerializeObject(e)}"); if (e != null) { elevatorTask.device_id = e.device_id; } _ = ExecuteTargetFloorTask(elevatorTask); } } List agvTasks = disTasks.Where(it => !it.area_code.Contains("ELE", StringComparison.OrdinalIgnoreCase)).ToList(); if (agvTasks?.Count > 0) { Logger.Information($"【GenTaskExecute】Agv任务数量:{agvTasks.Count},taskCodes:{string.Join(",", agvTasks.Select(x => x.bill_code).Distinct())}"); _ = AgvDispatch(agvTasks, agvCts.Token); } } } } catch (Exception ex) when (ex is HttpRequestException hReqEx) { agvCts.Cancel(); } catch (Exception ex) { Logger.Error("生成预任务执行时出现错误", ex); Logger.Error(ex.StackTrace!); await db.Ado.RollbackTranAsync(); throw; } finally { _ = s_taskExecuteSemaphore.Release(); agvCts.Dispose(); } } /// /// 获取电梯根据任务单号 /// /// /// taskCode:子任务编号 /// endlocation_id:目标库位ID /// /// protected async Task FindElevatorFromPars(ElevagorInfoQuery input) { var whereExpable = Expressionable.Create() .And((a, b, c) => a.enabled == 1); Logger.Information($"【FindElevatorFromPars】 {JsonConvert.SerializeObject(input)}"); if (!input.taskCode.IsNullOrEmpty()) { whereExpable.AndIF(!SqlFunc.IsNullOrEmpty(input.taskCode), (a, b, c) => c.bill_code == input.taskCode); } if (!input.endlocation_id.IsNullOrEmpty()) { whereExpable.AndIF(!SqlFunc.IsNullOrEmpty(input.endlocation_id), (a, b, c) => b.location_id == input.endlocation_id); } if (!input.startlocation_id.IsNullOrEmpty()) { whereExpable.AndIF(!SqlFunc.IsNullOrEmpty(input.startlocation_id), (a, b, c) => b.location_id == input.startlocation_id); } ISugarQueryable queryable = _db.CopyNew().Queryable().InnerJoin((a, b) => a.id == b.bill_id) .InnerJoin((a, b, c) => b.location_code == c.endlocation_code || b.location_code == c.startlocation_code) .Where(whereExpable.ToExpression()) .WhereIF(!SqlFunc.IsNullOrEmpty(input.sourceName) && SqlFunc.StartsWith("DT-R", input.sourceName), (a, b, c) => c.startpoint_code == input.sourceName) .WhereIF(!SqlFunc.IsNullOrEmpty(input.sourceName) && SqlFunc.StartsWith("DT-C", input.sourceName), (a, b, c) => c.endpoint_code == input.sourceName) .Select((a, b, c) => new WmsElevatorH { bill_code = c.bill_code, device_id = a.elevator_id, end_floor = c.end_floor }, true); var ele = await queryable.FirstAsync(); Logger.Information($"【FindElevatorFromPars】 " + queryable.ToSqlString()); return ele; } #region CTU /// /// 生成CTU任务执行 /// /// [HttpPost] public async Task CTUTaskExecute() { try { Dictionary indic = new Dictionary(); indic.Add("SSX-021-005", new string[] { "YTCS", "CallCtuFullIn_CS05" }); indic.Add("SSX-111-011", new string[] { "东面提升机输送线", "下升降机11呼叫CTU" }); indic.Add("SSX-111-012", new string[] { "东面提升机输送线", "下升降机12呼叫CTU" }); var db = _db.CopyNew(); List CTUTasks = await db.Queryable() .InnerJoin((a, b) => a.area_id == b.id) .Where(a => a.status == WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID) .Where((a, b) => b.code == "B")//一楼中储仓 .OrderBy(a => a.create_id) .Select((a, b) => new WmsPretaskH { move_num = b.move_num, third_eqp_type = b.third_eqp_type, }, true).ToListAsync(); List TaskCodes = await db.Queryable().Where(it => CTUTasks.Select(p => p.id).ToList().Contains(it.bill_id)).ToListAsync(); Logger.Information($@"【CTUTaskExecute】 获取任务TaskCodes: {JsonConvert.SerializeObject(TaskCodes)}"); var InTasks = CTUTasks.Where(a => a.task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID).ToList(); var OutTasks = CTUTasks.Where(a => a.task_type == WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID).ToList(); //Logger.Information($@"【CTUTaskExecute】 获取任务InTasks: {JsonConvert.SerializeObject(InTasks)}"); //Logger.Information($@"【CTUTaskExecute】 获取任务OutTasks: {JsonConvert.SerializeObject(OutTasks)}"); var OriginDistaskHs = await db.Queryable() .InnerJoin((a, b) => a.area_id == b.id) .Where((a, b) => b.code == "B" && a.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID) .OrderBy(a => a.bill_code) .ToListAsync(); //Logger.Information($@"【CTUTaskExecute】 OriginDistaskHs: {JsonConvert.SerializeObject(OriginDistaskHs)}"); List DistaskHs = new List(); List UpDistaskHs = new List(); List DistaskCodes = new List(); var inCtuExec = new List(); var outCtuExec = new List(); foreach (var item in InTasks) { /* if (indic.Keys.Contains(item.startlocation_code)) { var strs = indic.Where(p => p.Key == item.startlocation_code).First().Value; bool flag = _redisData.HashExist(strs[0], strs[1]).Result; if (!flag) continue; 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) continue; }*/ WmsDistaskH distaskH = item.Adapt(); distaskH.id = SnowflakeIdHelper.NextId(); distaskH.status = WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID; distaskH.is_chain = 1; distaskH.create_time = DateTime.Now; var billcode = GetBillCode(OriginDistaskHs, DistaskHs, distaskH); distaskH.groups = billcode.Substring(0, billcode.Length - 2); distaskH.bill_code = billcode; var num = int.Parse(distaskH.bill_code.Substring(billcode.Length - 1, 1)); Logger.Information($@"【CTUTaskExecute】 比对billcode:{num}和单次搬运数量move_num:{item.move_num},如果一致 会添加到inCtuExec"); if (num == item.move_num) { distaskH.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID; inCtuExec.Add(distaskH); if (OriginDistaskHs.Where(p => p.groups == distaskH.groups).Any()) { OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList().ForEach(p => p.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID); UpDistaskHs.AddRange(OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList()); inCtuExec.AddRange(OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList()); } if (DistaskHs.Where(p => p.groups == distaskH.groups).Any()) { DistaskHs.Where(p => p.groups == distaskH.groups).ToList().ForEach(p => p.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID); inCtuExec.AddRange(DistaskHs.Where(p => p.groups == distaskH.groups).ToList()); } } List preTaskCodes = TaskCodes.FindAll(x => x.bill_id == distaskH.pretask_id); List disTaskCodes = preTaskCodes.Adapt>(); disTaskCodes.ForEach(x => { x.id = SnowflakeIdHelper.NextId(); x.bill_id = distaskH.id; x.create_time = DateTime.Now; }); DistaskHs.Add(distaskH); DistaskCodes.AddRange(disTaskCodes); } foreach (var item in OutTasks) { WmsDistaskH distaskH = item.Adapt(); distaskH.id = SnowflakeIdHelper.NextId(); distaskH.status = WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID; distaskH.is_chain = 1; distaskH.create_time = DateTime.Now; var billcode = GetBillCode(OriginDistaskHs, DistaskHs, distaskH); distaskH.groups = billcode.Substring(0, billcode.Length - 2); distaskH.bill_code = billcode; var num = int.Parse(distaskH.bill_code.Substring(billcode.Length - 1, 1)); Logger.Information($@"【CTUTaskExecute】 比对billcode:{num}和单次搬运数量move_num:{item.move_num},如果一致 会添加到outCtuExec"); if (num == item.move_num) { distaskH.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID; outCtuExec.Add(distaskH); if (OriginDistaskHs.Where(p => p.groups == distaskH.groups).Any()) { OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList().ForEach(p => p.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID); UpDistaskHs.AddRange(OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList()); outCtuExec.AddRange(OriginDistaskHs.Where(p => p.groups == distaskH.groups).ToList()); } if (DistaskHs.Where(p => p.groups == distaskH.groups).Any()) { DistaskHs.Where(p => p.groups == distaskH.groups).ToList().ForEach(p => p.status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID); outCtuExec.AddRange(DistaskHs.Where(p => p.groups == distaskH.groups).ToList()); } } List preTaskCodes = TaskCodes.FindAll(x => x.bill_id == distaskH.pretask_id); List disTaskCodes = preTaskCodes.Adapt>(); disTaskCodes.ForEach(x => { x.id = SnowflakeIdHelper.NextId(); x.bill_id = distaskH.id; x.create_time = DateTime.Now; }); DistaskHs.Add(distaskH); DistaskCodes.AddRange(disTaskCodes); } await db.Ado.BeginTranAsync(); int row = 0; if (UpDistaskHs.Count > 0) { await db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID }).Where(it => UpDistaskHs.Select(p => p.id).ToList().Contains(it.id)).ExecuteCommandAsync(); } if (DistaskHs.Count > 0) { row = await db.Insertable(DistaskHs).ExecuteCommandAsync(); } if (DistaskCodes.Count > 0) { await db.Insertable(DistaskCodes).ExecuteCommandAsync(); } if (row > 0) { List preTaskIds = DistaskHs.Select(x => x.pretask_id).ToList(); await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_YXF_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync(); } await db.Ado.CommitTranAsync(); //判断 Logger.Information($"【CTUTaskExecute】 判断单据状态(status)是否为26126851525157 {JsonConvert.SerializeObject(DistaskHs)}"); if (DistaskHs.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID).Any()) { var time = int.Parse(db.Queryable().Where(P => P.key == "getinterval").First().value); timer = new Timer(TimerExec, null, TimeSpan.FromMinutes(time), TimeSpan.FromMinutes(time)); } //Logger.Information($@"【CTUTaskExecute】 可执行的CTU任务inCtuExec: {JsonConvert.SerializeObject(inCtuExec)}"); if (inCtuExec.Count > 0) { Logger.Information($"开始执行CTU入库任务: {JsonConvert.SerializeObject(inCtuExec)}"); //呼叫ctu入库 // await db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_RUNING_ID }).Where(it => inCtuExec.Select(p => p.id).ToList().Contains(it.id)).ExecuteCommandAsync(); // await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_START_ID }).Where(it => inCtuExec.Select(x => x.pretask_id).ToList().Contains(it.id)).ExecuteCommandAsync(); CancellationTokenSource Ctu = new(); await CallingCTU(inCtuExec, Ctu.Token, 1); Ctu.Dispose(); } //Logger.Information($@"【CTUTaskExecute】 可执行的CTU任务outCtuExec: {JsonConvert.SerializeObject(outCtuExec)}"); if (outCtuExec.Count > 0) { Logger.Information($"开始执行CTU出库任务: {JsonConvert.SerializeObject(outCtuExec)}"); //呼叫ctu出库 // await db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_RUNING_ID }).Where(it => outCtuExec.Select(p => p.id).ToList().Contains(it.id)).ExecuteCommandAsync(); // await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_START_ID }).Where(it => outCtuExec.Select(x => x.pretask_id).ToList().Contains(it.id)).ExecuteCommandAsync(); CancellationTokenSource Ctu = new(); await CallingCTU(outCtuExec, Ctu.Token, 0); Ctu.Dispose(); } } catch (Exception ex) { } } //判断生成bill_code private string GetBillCode(List OriginDistaskH, List NewdistaskHs, WmsDistaskH distaskH) { string BillCode = string.Empty; //入库 if (distaskH.task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID) { var orgdistaskHs = OriginDistaskH.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID && p.task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID && p.startpoint_id == distaskH.startpoint_id).ToList(); var newdistaskHs = NewdistaskHs.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID && p.task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID && p.startpoint_id == distaskH.startpoint_id).ToList(); if ((orgdistaskHs.Count + newdistaskHs.Count) == 0) { var groups = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_TASK_EXECUTE_ENCODE).Result; BillCode = $"{groups}-1"; } else { var groups = orgdistaskHs.Count > 0 ? orgdistaskHs.First().groups : newdistaskHs.First().groups; BillCode = $"{groups}-" + (orgdistaskHs.Count + newdistaskHs.Count + 1); } } else if (distaskH.task_type == WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID) { var orgdistaskHs = OriginDistaskH.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID && p.task_type == WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID && p.endpoint_id == distaskH.endpoint_id).ToList(); var newdistaskHs = NewdistaskHs = OriginDistaskH.Where(p => p.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID && p.task_type == WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID && p.endpoint_id == distaskH.endpoint_id).ToList(); if ((orgdistaskHs.Count + newdistaskHs.Count) == 0) { var groups = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_TASK_EXECUTE_ENCODE).Result; BillCode = $"{groups}-1"; } else { var groups = orgdistaskHs.Count > 0 ? orgdistaskHs.First().groups : newdistaskHs.First().groups; BillCode = $"{groups}-" + (orgdistaskHs.Count + newdistaskHs.Count + 1); } } return BillCode; } private Timer? timer; private async void TimerExec(object e) { try { SqlSugarClient db = _db.CopyNew(); var list = db.Queryable().InnerJoin((a, b) => a.area_id == b.id) .Where((a, b) => b.code == "B" && a.status == WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID) .OrderBy(a => a.bill_code) .ToList(); var data = list.GroupBy(p => p.groups).Select(p => new { groups = p.Key, time = p.Max(a => a.create_time) }).ToList(); var date = DateTime.Now; var time = int.Parse(db.Queryable().Where(P => P.key == "getinterval").First().value); foreach (var item in data) { if (date.Subtract(item.time).Minutes >= time) { var execlist = list.Where(p => p.groups == item.groups).ToList(); await db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID }).Where(it => execlist.Select(p => p.id).ToList().Contains(it.id)).ExecuteCommandAsync(); // await db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_START_ID }).Where(it => execlist.Select(x => x.pretask_id).ToList().Contains(it.id)).ExecuteCommandAsync(); CancellationTokenSource Ctu = new(); int type = execlist.First().task_type == WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID ? 1 : 0; await CallingCTU(execlist, Ctu.Token, type); Ctu.Dispose(); } } } catch (Exception ex) { } finally { timer?.Dispose(); } } private async Task CallingCTU(List distaskHs, CancellationToken token, int type) { try { AgvRequestConfig requestCfg = App.Configuration.Build(); string url = requestCfg.AgvRequestUrls.CreateTaskChainUrl; var taskChainCodeDic = distaskHs.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, })); foreach ((string k, object v) in taskChainCodeDic) { dynamic reqBody = new ExpandoObject(); reqBody.taskChainCode = k; reqBody.type = (int)EnumTaskChainType.CTU; reqBody.sequential = false; reqBody.taskChainPriority = 0; reqBody.taskList = v; reqBody.inOut = type; Logger.Information($"【CallingCTU】 CTU任务下发 开始请求联核/task-chain/create接口 请求地址:{url} 请求参数:{JsonConvert.SerializeObject(reqBody)} type:{(type == 0 ? "CTU出库" : "CTU入库")}"); dynamic respBody = await HttpClientHelper.PostStreamAsync(url, reqBody, token); Logger.Information($"【CallingCTU】 CTU任务下发 接收到联核/task-chain/create接口信息:{respBody}"); } } catch (Exception ex) { Logger.Information($"【CallingCTU】 CTU任务下发 请求联核/task-chain/create接口失败 异常信息:{ex}"); } } #endregion /// /// 呼梯操作 /// /// /// private async Task CallingLanding(List<(string endlocation_code, string device_id, string id, int floorNO)> endLocCodes) { Logger.Information($"【CallingLanding】 开始呼梯操作............."); try { foreach ((_, string devId, string disTaskId, int floorNO) in endLocCodes) { Logger.Information($"【CallingLanding】 devId:{devId}"); if (!s_elevatorMap.TryGetValue(devId, out object? elevatorCode)) { continue; } string? devName = elevatorCode.ToString(); Logger.Information($"【CallingLanding】 电梯编号:{devName}"); Logger.Information($"【CallingLanding】 当前:{devName.Match(@"\d+")}#梯"); await _elevatorControlService.WriteTagAsync(devName, ElevatorConsts.AGVControl, 1); (int sysStatus, int runStatus, int curFloorNo, int doorStatus, int agvStatus) eleStatusMulti = (-1, -1, -1, -1, -1); Logger.Information("【CallingLanding】 获取电梯AGV运行状态"); if (!_elevatorAgvCtlStatusMap.TryGetValue(devId, out int agvCtlStatus) || agvCtlStatus != (int)EnumAgvStatus.AGV运行状态) { var tags = new[] { "SysStatus", "RunStatus", "FloorNo", "DoorStatus", "AGVStatus" }; do { eleStatusMulti = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None); await Task.Delay(1000); } while (eleStatusMulti.agvStatus != (int)EnumAgvStatus.AGV运行状态); Logger.Information($"{devName.Match(@"\d+")}#, 当前Agv状态:{eleStatusMulti.agvStatus.ToEnum()}"); _elevatorAgvCtlStatusMap[devId] = eleStatusMulti.agvStatus; } else { Logger.Information("【CallingLanding】 AGV运行状态:" + agvCtlStatus); } Logger.Information($"【CallingLanding】 任务开始目标楼层为:{floorNO}"); int floorN = await GetRealFloor(floorNO); //如果电梯在当前楼层则不呼梯 if (floorN == eleStatusMulti.curFloorNo) { Logger.Information($"【CallingLanding】 {devName.Match(@"\d+")}#,在当前楼层,无需呼梯"); continue; } Logger.Information($"【CallingLanding】 实际目标楼层为:{floorN}"); WmsElevatorUnexecute elevatorQueueItem = new() { distask_id = disTaskId, elevator_id = devId, elevator_code = devName, floor = floorN, //5代表4楼 task_status = "待执行", create_id = _userManager.UserId, create_time = DateTime.Now }; List elevatorQueue = await _db.Queryable().Where(it => it.distask_id == disTaskId && it.task_status == "执行中").ToListAsync(); if ((elevatorQueue.IsNull() || elevatorQueue.Count < 1) && floorN != eleStatusMulti.curFloorNo) { Logger.Information($"【CallingLanding】 判断当前电梯{devName.Match(@"\d+")}#梯 无任务在做执行呼梯"); elevatorQueueItem.task_status = "执行中"; bool callLiftRes = await _elevatorControlService.CallLift(devName, floorN, CancellationToken.None); string successful = "成功", fail = "失败"; string callLiftResult = callLiftRes ? successful : fail; Logger.Information($"{devName.Match(@"\d+")}#, 呼梯结果:{callLiftResult}"); } else { Logger.Information("【CallingLanding】 当前有任务在做,不会呼梯"); } //如果当前电梯有任务在做,将当前呼梯任务放入待执行队列 _ = await _db.Insertable(elevatorQueueItem).ExecuteCommandAsync(); Logger.Information("【CallingLanding】 呼梯任务执行完成"); } } catch (Exception ex) { Logger.Error("【CallingLanding】 呼梯操作错误", ex); Logger.Error($"【CallingLanding】 呼梯操作错误堆栈跟踪:{Environment.NewLine}{ex.StackTrace}"); throw; } } /// /// 执行到目标楼层电梯任务 /// /// /// private async Task ExecuteTargetFloorTask(WmsDistaskH disTask) { //收到放货确认通知,向电梯发送到3楼的指令 Logger.Information($"开始执行电梯任务,任务ID:{disTask.id}"); try { if (!s_elevatorMap.TryGetValue(disTask.device_id, out object? elevatorCode)) { Logger.Information($"开始执行电梯任务,没有取到设备{disTask.device_id}的 elevatorCode! s_elevatorMap: {JsonConvert.SerializeObject(s_elevatorMap)}"); return; } string devName = s_elevatorMap[disTask.device_id]?.ToString() ?? _eleCtlCfg.DevName3; Logger.Information($"当前:{devName.Match(@"\d+")}#梯"); var tags = new[] { "SysStatus", "RunStatus", "FloorNo", "DoorStatus", "AGVStatus" }; (int sysStatus, int runStatus, int curFloorNo, int doorStatus, int agvStatus) eleStatusMulti = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None); if (eleStatusMulti.agvStatus != (int)EnumAgvStatus.AGV运行状态) { _ = await _elevatorControlService.WriteTagAsync(devName, ElevatorConsts.AGVControl, 1); } if (!_elevatorAgvCtlStatusMap.TryGetValue(disTask.id, out int agvCtlStatus) || agvCtlStatus != (int)EnumAgvStatus.AGV运行状态) { do { eleStatusMulti = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None); await Task.Delay(1000); } while (eleStatusMulti.agvStatus != (int)EnumAgvStatus.AGV运行状态); Logger.Information($"{devName.Match(@"\d+")}#, 当前Agv状态:{eleStatusMulti.agvStatus.ToEnum()}"); _elevatorAgvCtlStatusMap[disTask.id] = eleStatusMulti.agvStatus; } int doorStatus = -1; bool closeDoorRes = await _elevatorControlService.SendOpenCloseCmd(devName, 4); //向电梯发送前门关门指令 Logger.Information($"关门结果:{closeDoorRes}"); do { doorStatus = await _elevatorControlService.GetTagAsync(devName, ElevatorConsts.DoorStatus); await Task.Delay(1000); } while (doorStatus != 4); Logger.Information($"当前门状态:{doorStatus}"); int floor = await GetRealFloor(disTask.end_floor); Logger.Information($"目标楼层:{floor}"); //发送到目标楼的指令 dynamic reuslt = await _elevatorControlService.WriteTagAsync(devName, ElevatorConsts.FloorExecute, floor); //电梯任务手动执行任务状态上报 (int sysStatus, int runStatus, int floorNo, int doorStatus, int agvStatus) tuple = (-1, -1, -1, -1, -1); do { tuple = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None); await Task.Delay(1000); } while (tuple.sysStatus != 3 || tuple.runStatus != 0); Logger.Information($"sysStatus:{tuple.sysStatus},runStatus:{tuple.runStatus},floorNo:{tuple.floorNo},disTask.end_floor={disTask.end_floor}"); if (tuple.sysStatus.ToEnum() == EnumSysStatus.正常状态 && tuple.runStatus.ToEnum() == EnumRunStatus.停梯) { Logger.Information($"disTask.require_id={disTask.require_id}"); List disTaskIds = new() { disTask.id }; var upInput = new { disTaskIds = disTask.id }; TaskExecuteAfterUpInput teaUpInput = new() { disTaskIds = disTaskIds, }; await TaskExecuteAfter(teaUpInput); TaskCompleUpInput tcUpInput = new() { disTaskIds = disTaskIds, }; await TaskComplate(tcUpInput); Logger.Information("电梯任务执行完成"); } } catch (Exception ex) { Logger.Error("执行到目标楼层电梯任务失败", ex); throw; } } /// /// Agv调度 /// /// /// /// private async Task AgvDispatch(List disTasks, CancellationToken token) { Logger.Information("【AgvDispatch】 Agv任务执行...."); List kiva = new List(); // 一楼中储仓 kiva.Add("ZSSSXCTU02"); kiva.Add("ZSSSXCTU01"); List floor2 = new List(); // 二楼暂存仓 floor2.Add("AS01"); floor2.Add("AS02"); floor2.Add("AX01"); floor2.Add("AX02"); //调用AGV创建任务链接口 try { AgvRequestConfig requestCfg = App.Configuration.Build(); string url = requestCfg.AgvRequestUrls.CreateTaskChainUrl; Logger.Information($"【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, shelfNumber = floor2.Contains(it.startlocation_code) || floor2.Contains(it.endlocation_code) ? it.carry_code : "" // 二楼暂存仓传料架 })); Logger.Information($"【AgvDispatch】 Agv任务执行的taskChainCodeDic:{JsonConvert.SerializeObject(taskChainCodeDic)}"); foreach ((string k, object v) in taskChainCodeDic) { var typeflag = false; var dis = disTasks.Where(p => p.groups == k).First(); if (kiva.Contains(dis.startlocation_code) || kiva.Contains(dis.endlocation_code) || floor2.Contains(dis.startlocation_code) || floor2.Contains(dis.endlocation_code)) { typeflag = true; } dynamic reqBody = new ExpandoObject(); reqBody.taskChainCode = k; reqBody.type = typeflag ? (int)EnumTaskChainType.KIVA : (int)EnumTaskChainType.AGV; reqBody.sequential = false; reqBody.taskChainPriority = 0; reqBody.taskList = v; reqBody.floor = dis.end_floor; Logger.Information($"【AgvDispatch】 Agv任务执行 开始请求联核/task-chain/create接口 请求地址:{url} 请求参数:{JsonConvert.SerializeObject(reqBody)} "); dynamic respBody = await HttpClientHelper.PostStreamAsync(url, reqBody, token); Logger.Information($"【AgvDispatch】 Agv任务执行 接收到联核/task-chain/create接口信息:{respBody}"); } } catch (Exception ex) { Logger.Information($"【AgvDispatch】 agv任务执行 请求联核/task-chain/create接口失败 异常信息:{ex}"); throw; } } /// /// 任务执行 /// /// /// [HttpPost] public async Task TaskExecute(TaskExecuteUpInput input) { try { await _db.Ado.BeginTranAsync(); //更任务执行 for (int i = 0, cnt = input.disTaskIds.Count; i < cnt; i++) { _ = input.EqpIds?.Count > 0 ? await _db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID, device_id = input.EqpIds[i] }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync() : await _db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync(); //await _db.Updateable().SetColumns(it => setColVal).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync(); } List preTaskIds = await _db.Queryable().Where(it => input.disTaskIds.Contains(it.id)).Select(it => it.pretask_id).ToListAsync(); if (preTaskIds.Count > 0) { //更预任务申请表状态 _ = await _db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_START_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync(); } await _db.Ado.CommitTranAsync(); } catch (Exception ex) { Logger.Error("任务执行失败", ex); await _db.Ado.RollbackTranAsync(); throw; } } /// /// 任务执行取操作返回(后续操作) /// /// [HttpPost] public async Task TaskExecuteAfter(TaskExecuteAfterUpInput input) { //更新任务执行表单据状态 try { await _db.Ado.BeginTranAsync(); _ = await _db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_RUNING_ID, act_start_date = DateTime.Now }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync(); //清空载具库位数据 var carryAndLocIds = await _db.Queryable().Where(it => input.disTaskIds.Contains(it.id)).Select(it => new { it.carry_id, it.startlocation_id }).ToListAsync(); if (carryAndLocIds?.Count > 0) { List carryIds = carryAndLocIds.Select(x => x.carry_id).ToList(); _ = await _db.Updateable().SetColumns(it => new WmsCarryH { location_id = null, location_code = null }).Where(it => carryIds.Contains(it.id)).ExecuteCommandAsync(); } //更新起始库位,状态改为空闲、锁定状态,未锁定 if (carryAndLocIds?.Count > 0) { List startLocationIds = carryAndLocIds.Select(x => x.startlocation_id).ToList(); _ = await _db.Updateable().SetColumns(it => new BasLocation { is_use = ((int)EnumCarryStatus.空闲).ToString(), is_lock = 0 }).Where(it => startLocationIds.Contains(it.id)).ExecuteCommandAsync(); } await _db.Ado.CommitTranAsync(); } catch (Exception ex) { Logger.Error("设备取返回操作失败", ex); await _db.Ado.RollbackTranAsync(); } } /// /// 任务完成 /// /// [HttpPost] public async Task TaskComplate(TaskCompleUpInput input) { try { await _db.Ado.BeginTranAsync(); //更新任务执行表,单据状态为 完成 _ = await _db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_COMPLE_ID, act_end_date = DateTime.Now }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync(); List disTasks = await _db.Queryable().InnerJoin((a, b) => a.carry_id == b.id).Where(a => input.disTaskIds.Contains(a.id)).Select((a, b) => new WmsDistaskH { carry_status = b.carry_status }, true).ToListAsync(); if (disTasks?.Count > 0) { // 更新预任务申请表,单据状态为 已完成 List preTaskIds = disTasks.Select(x => x.pretask_id).ToList(); _ = await _db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_COMPLE_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync(); //更新电梯任务数量 _ = await _db.Updateable().SetColumns(it => new WmsElevatorH { task_nums = it.task_nums - 1}).Where(it => disTasks.Select(x => x.area_code).Contains(it.area_code)).ExecuteCommandAsync(); // 更新中储仓任务数量 _ = await _db.Updateable().SetColumns(it => new BasLocation { task_nums = it.task_nums - 1 }).Where(it => disTasks.Where(r => r.startlocation_code.Contains("SSX-111-011") || r.startlocation_code.Contains("SSX-111-012")).Select(x => x.startlocation_code).Contains(it.location_code)).ExecuteCommandAsync(); //更新载具,锁定状态为未锁定,更新载具的库位当前任务的目标库位 List<(string carry_id, string carry_status, string endlocation_id, string endlocation_code)> multiList = disTasks.Select(it => (it.carry_id, it.carry_status, it.endlocation_id, it.endlocation_code)).ToList(); Dictionary locWhIdMap = await _db.Queryable().Where(it => multiList.Select(x => x.endlocation_id).Contains(it.id)).ToDictionaryAsync(it => it.id, it => it.wh_id); List carryIts = new(); List carryCodeIts = new(); List locIts = new(); for (int i = 0, cnt = multiList.Count; i < cnt; i++) { WmsCarryH carry = new() { id = multiList[i].carry_id, is_lock = 0, location_id = multiList[i].endlocation_id, location_code = multiList[i].endlocation_code }; string endLocId = multiList[i].endlocation_id; WmsCarryCode carryCode = new() { warehouse_id = locWhIdMap.ContainsKey(endLocId) ? locWhIdMap[endLocId].ToString() : "", location_id = multiList[i].endlocation_id, location_code = multiList[i].endlocation_code }; carryIts.Add(carry); carryCodeIts.Add(carryCode); BasLocation loc = new() { id = multiList[i].endlocation_id, is_lock = 0, is_use = multiList[i].carry_status }; if (multiList[i].carry_status.ToEnum() == EnumCarryStatus.空闲) { loc.is_use = ((int)EnumCarryStatus.占用).ToString(); } locIts.Add(loc); } Logger.Information($@"TaskComplate 更新carryIts: {JsonConvert.SerializeObject(carryIts)}"); Logger.Information($@"TaskComplate 更新carryCodeIts: {JsonConvert.SerializeObject(carryCodeIts)}"); _ = await _db.Updateable(carryIts).UpdateColumns(it => new { it.is_lock, it.location_id, it.location_code }).ExecuteCommandAsync(); //更新条码的库位和仓库信息 _ = await _db.Updateable(carryCodeIts).UpdateColumns(it => new { it.warehouse_id, it.location_id, it.location_code }).Where(it => multiList.Select(x => x.carry_id).Contains(it.carry_id)).ExecuteCommandAsync(); //更新库位信息,使用状态为 使用,锁定状态为未锁定 _ = await _db.Updateable(locIts).UpdateColumns(it => new { it.is_use, it.is_lock }).ExecuteCommandAsync(); /* var loginType= _userManager?.LoginType ?? "web"; Log.Information($"_userManager.LoginType={loginType}"); */ //更新业务主表的单据状态 foreach (WmsDistaskH? dt in disTasks) { // 销售出库 if (dt.biz_type == WmsWareHouseConst.BIZTYPE_WMSSALERELEASE_ID) { // TODO 一楼工位放货完成后更新出库明细的实际出库数量 if (dt.start_floor == 1 && dt.end_floor == 1) { WmsCarryCode wmsCarryCode = await _db.Queryable().Where(r => r.carry_id == dt.carry_id).FirstAsync(); await _db.Updateable().SetColumns(r => r.purchase_prqty == r.purchase_prqty + wmsCarryCode.codeqty).Where(r => r.id == dt.require_id).ExecuteCommandAsync(); CarryCodeUnbindInput carryCodeUnbindInput = new CarryCodeUnbindInput(); carryCodeUnbindInput.carry_id = dt.carry_id; await _wmsCarryBindService.CarryCodeUnbind(carryCodeUnbindInput); } } // 成品调拨入库 else if (dt.biz_type == WmsWareHouseConst.BIZTYPE_WMSTRANSFERINSTOCK_ID) { if (dt.start_floor == 3 && dt.end_floor == 3) { WmsCarryCode wmsCarryCode = await _db.Queryable().Where(r => r.carry_id == dt.carry_id).FirstAsync(); await _db.Updateable().SetColumns(r => r.qty == r.qty + wmsCarryCode.codeqty).Where(r => r.id == dt.require_id).ExecuteCommandAsync(); } } List disTaskCodes = await _db.Queryable().Where(it => it.bill_id == dt.id).ToListAsync(); WareHouseUpInput upInput = new() { bizTypeId = dt.biz_type, requireId = dt.require_id!, distaskCodes = disTaskCodes, carryIds = disTasks.Select(x => x.carry_id).ToList() }; /*if (!_userManager?.LoginType.IsNullOrEmpty() ?? false) { upInput.loginType = "app"; } else { upInput.loginType = "web"; }*/ upInput.loginType = "web";//(!string.IsNullOrEmpty(_userManager?.LoginType) ? "app" : "web") ?? "web"; if (dt.is_sign == 1 && dt.chain_type == "3") { await DoUpdate(upInput); } } } await _db.Ado.CommitTranAsync(); Logger.Information("任务操作完成"); } catch (Exception ex) { Logger.Error($"任务结束失败", ex); Logger.Error($"任务结束失败堆栈异常", ex); await _db.Ado.RollbackTranAsync(); throw; } finally { _ = GenTaskExecute(); } } /// /// 出入库策略启用、禁用状态修改 /// /// /// [HttpPost] public async Task ModifyPoliciesStatus(ModifyEnabledInput input) { async Task _updateStatus(ModifyEnabledInput input) where T : BaseEntity, IUpdatePoliciesStatus, new() { T obj = new() { status = input.status }; _ = await _db.Updateable(obj).UpdateColumns(it => it.status).Where(it => input.ids.Contains(it.id)).ExecuteCommandAsync(); } switch (input.strategyType) { case EnumInOutStockType.In: await _updateStatus(input); break; case EnumInOutStockType.Out: await _updateStatus(input); break; } } /// /// 生成预任务 /// /// 预任务集合 /// 预任务编码集合 /// public async Task GenPreTask(List preTasks, List preTaskCodes) { //如果预任务出现起终库位相同,则删除对应预任务 //modifiy by ly on 20230922 将当前预任务操作者设为四场管理员 preTasks.ForEach(pt => { pt.org_id = WmsWareHouseConst.AdministratorOrgId; pt.create_id = WmsWareHouseConst.AdministratorUserId; }); if (preTasks.FindAll(it => it.startlocation_id == it.endlocation_id)?.Count > 0) { _ = preTasks.RemoveAll(it => it.startlocation_id == it.endlocation_id); } List> grpList = preTasks.OrderBy(o => o.bill_code).GroupBy(g => g.carry_id).ToList(); if (grpList?.Count > 0) { foreach (IGrouping? grp in grpList) { WmsPretaskH[] arr = grp.ToArray(); if (arr.Length > 1) { WmsPretaskH[] subArr = arr[..^1]; System.Array.ForEach(subArr, a => a.chain_type = "1"); } } } int row = await _db.Insertable(preTasks).ExecuteCommandAsync(); if (preTaskCodes?.Count > 0) { row = await _db.Insertable(preTaskCodes).ExecuteCommandAsync(); } var eleP = preTasks.Find(x => x.area_code.Contains("ELE")); if (eleP != null) { row = await _db.Updateable().SetColumns(it => it.task_nums == it.task_nums + 1).Where(it => it.area_code == eleP.area_code).ExecuteCommandAsync(); } // 累加终点库位任务数 row = await _db.Updateable().SetColumns(it => it.task_nums == it.task_nums + 1) .Where(it => preTasks.Select(r => r.endlocation_id).Contains(it.id)).ExecuteCommandAsync(); return row > 0; } /// /// 生成预任务后续处理 /// /// [NonAction] public async Task GenInStockTaskHandleAfter(GenPreTaskUpInput input, Expression> setCarryColumnsExp, Expression> setLocaionColumbExp) { try { await _db.Ado.BeginTranAsync(); //根据生成的预任务,插入预任务操作记录 if (input.PreTaskRecord != null) { _ = await _db.Insertable(input.PreTaskRecord).ExecuteCommandAsync(); } if (input.PreTaskHandleCodes.Count > 0) { _ = await _db.Insertable(input.PreTaskHandleCodes).ExecuteCommandAsync(); } //根据载具ID,更新是否锁定和赋值起始库位 if (setCarryColumnsExp != null) { Expression> whereExp = input.CarryIds?.Count > 0 ? it => input.CarryIds.Contains(it.id) : it => it.id == input.CarryId; _ = await _db.Updateable().SetColumns(setCarryColumnsExp).Where(whereExp).ExecuteCommandAsync(); } if (input.CarryStartLocationId.IsNullOrWhiteSpace() == false) { _ = await _db.Updateable().SetColumns(setLocaionColumbExp).Where(it => input.LocationIds.Contains(it.id)).ExecuteCommandAsync(); } //根据所有库位更新库位的锁定状态为“锁定” if (setLocaionColumbExp != null && input.LocationIds?.Count > 0) { _ = await _db.Updateable().SetColumns(setLocaionColumbExp).Where(it => input.LocationIds.Contains(it.id)).ExecuteCommandAsync(); } await _db.Ado.CommitTranAsync(); } catch (Exception) { await _db.Ado.RollbackTranAsync(); throw; } } /// /// 路径算法 /// /// /// /// [NonAction] public async Task> PathAlgorithms(string pStartId, string pEndId) { /* var sp= await _db.Queryable().Where(it => it.id == pStartId).FirstAsync(); var ep = await _db.Queryable().Where(it => it.id == pEndId).FirstAsync(); if (sp.area_code == "B" || ep.area_code == "B") { List Points = new List(); var zp = await _db.Queryable().Where(it => it.point_code == "ZSCJZJD").FirstAsync(); Points.Add(sp); Points.Add(ep); Points.Add(zp); Points.ForEach(p => { p.area_code = zp.area_code; p.area_id = zp.area_id; }); return Points; }*/ List roads = await _db.Queryable().Where(it => it.status == 1).ToListAsync(); List points = await LocPathCalcAlgorithms(pStartId, pEndId, roads); try { if (points?.FindAll(x => x.location_code != null && x.location_code.Contains("dt", StringComparison.OrdinalIgnoreCase))?.Count > 0) { //查询当前电梯点 List curEleDs = await _db.Queryable().InnerJoin((a, b) => a.bill_id == b.id).Where((a, b) => points.Select(x => x.id).Contains(a.point_id)).ToListAsync(); Logger.Information($"curEleDs==null :{curEleDs == null},curEleDs:{string.Join(",", curEleDs.Select(x => x.bill_id))}"); //如果有电梯点,则会进行电梯的均匀分配 if (curEleDs?.Count > 0) { //当前电梯 WmsElevatorH curEle = await _db.Queryable().SingleAsync(it => it.id == curEleDs.First().bill_id); //同电梯组电梯 List sGpEle = await _db.Queryable().Where(it => it.elevator_group == curEle.elevator_group && it.id != curEle.id && it.enabled == 1).ToListAsync(); if (curEle.enabled == 0 && (sGpEle == null || sGpEle.Count < 1)) { throw new AppFriendlyException("电梯被禁用或未配置", 500); } if ((sGpEle == null || sGpEle.Count < 1) && curEle.enabled == 1) { return points; } if (sGpEle?.Count > 0 && curEle.enabled == 0) { return points; } //判断电梯组中各电梯任务数 if (sGpEle.FindAll(x => Math.Abs(x.task_nums - curEle.task_nums) % 2 == 1)?.Count > 0) { List sGpDs = await _db.Queryable().Where(it => it.bill_id == sGpEle.First().id).ToListAsync(); if (sGpDs?.Count > 0) { List sGpPoints = await _db.Queryable().Where(it => sGpDs.Select(x => x.point_id).Contains(it.id)).ToListAsync(); string sFEndId = sGpDs.Single(x => x.floor == curEleDs.First().floor).point_id; string eFStartId = sGpDs.Single(x => x.floor == curEleDs.Last().floor).point_id; List sFPoints = await LocPathCalcAlgorithms(pStartId, sFEndId, roads); List elePoints = new(); foreach (WmsElevatorD pt in curEleDs) { WmsPointH? elePoint = sGpPoints.Find(x => x.floor == pt.floor); if (elePoint != null) { elePoints.Add(elePoint); } } List eFPoints = await LocPathCalcAlgorithms(eFStartId, pEndId, roads); _ = elePoints.Remove(elePoints.First()); _ = elePoints.Remove(elePoints.Last()); points.Clear(); points.AddRange(sFPoints); points.AddRange(elePoints); points.AddRange(eFPoints); } } } } } catch (Exception ex) { Logger.Error("路径算法异常", ex); throw; } return points; } /// /// 路径算法 当出现多个载具同时出库,可能需要进入电梯时 /// /// /// /// /// [NonAction] public async Task> PathAlgorithmsEle(string pStartId, string pEndId, int ele) { List roads = await _db.Queryable().Where(it => it.status == 1).ToListAsync(); List points = await LocPathCalcAlgorithms(pStartId, pEndId, roads); try { if (points.FindAll(x => x.location_code != null && x.location_code.Contains("dt", StringComparison.OrdinalIgnoreCase))?.Count > 0) { //查询当前电梯点 List curEleDs = await _db.Queryable().Where(it => points.Select(x => x.id).Contains(it.point_id)).ToListAsync(); //如果有电梯点,则会进行电梯的均匀分配 if (curEleDs?.Count > 0) { //当前电梯 WmsElevatorH curEle = await _db.Queryable().SingleAsync(it => it.id == curEleDs.First().bill_id && it.enabled == 1); //同电梯组电梯 List sGpEle = await _db.Queryable().Where(it => it.elevator_group == curEle.elevator_group && it.id != curEle.id && it.enabled == 1).ToListAsync(); if (curEle == null && sGpEle?.Count > 0) { throw new AppFriendlyException("电梯被禁用或未配置", 500); } if (ele % 2 == 1) { //判断电梯组中各电梯任务数 if (curEle == null || sGpEle.FindAll(x => Math.Abs(x.task_nums - curEle.task_nums) % 2 == 1)?.Count > 0) { List sGpDs = await _db.Queryable().Where(it => it.bill_id == sGpEle.First().id).ToListAsync(); if (sGpDs?.Count > 0) { List sGpPoints = await _db.Queryable().Where(it => sGpDs.Select(x => x.point_id).Contains(it.id)).ToListAsync(); string sFEndId = sGpDs.Single(x => x.floor == curEleDs.First().floor).point_id; string eFStartId = sGpDs.Single(x => x.floor == curEleDs.Last().floor).point_id; List sFPoints = await LocPathCalcAlgorithms(pStartId, sFEndId, roads); List elePoints = new(); foreach (WmsElevatorD pt in curEleDs) { WmsPointH? elePoint = sGpPoints.Find(x => x.floor == pt.floor); if (elePoint != null) { elePoints.Add(elePoint); } } List eFPoints = await LocPathCalcAlgorithms(eFStartId, pEndId, roads); _ = elePoints.Remove(elePoints.First()); _ = elePoints.Remove(elePoints.Last()); points.Clear(); points.AddRange(sFPoints); points.AddRange(elePoints); points.AddRange(eFPoints); } } } } } } catch (Exception ex) { Logger.Error("路径算法异常", ex); throw; } return points; } #region PrivateMethods private async Task> LocPathCalcAlgorithms(string pStartId, string pEndId, List roads) { #region dp //List results = new(); //var points = await _db.Queryable().ToListAsync(); //Dictionary isVisited = roads.Select(x => x.startpoint_id).Distinct().ToDictionary(x => x, x => false); //List pointIds = new(); //List codes = new(); //Dp dp = new(); //dynamic obj = new ExpandoObject(); //obj.isArrivedEpoint = false; //dp.DpFunc(roads, pointIds, isVisited, pStartId, pEndId, obj); //foreach (var pid in pointIds) //{ // var point = points.Find(x => x.id == pid); // if (point != null) // { // results.Add(point); // } //} //return results; #endregion #region dijkstra List results = new(); try { List? points = await _db.Queryable().ToListAsync(); WmsPointH? startObj = points.Find(x => x.id == pStartId); WmsPointH? endObj = points.Find(x => x.id == pEndId); int sIndex = points.IndexOf(startObj); int eIndex = points.IndexOf(endObj); if (eIndex < sIndex) { (eIndex, sIndex) = (sIndex, eIndex); (points[eIndex], points[sIndex]) = (points[sIndex], points[eIndex]); } string[] vexs = points.Select(p => p.id).ToArray(); EData[] edges = new EData[roads.Count]; for (int i = 0; i < edges.Length; i++) { string start = roads[i].startpoint_id; string end = roads[i].endpoint_id; int weight = roads[i].distance; edges[i] = new EData(start, end, weight); } Dijkstra pG = new(vexs, edges); int[] prev = new int[pG.mVexs.Length]; int[] dist = new int[pG.mVexs.Length]; List vertexs = new() { startObj }; pG.CalcDijkstra(sIndex, prev, dist); List pointIds = points.Select(p => p.id).ToList(); Stack result = new(); GetPoints(pointIds, prev, result, eIndex); results = new() { startObj }; if (points?.Count > 0) { //points.Where(it => result.Contains(it.id)); foreach (string i in result) { WmsPointH? point = points?.Find(x => x.id == i); if (point != null) { results.Add(point); } } } } catch (Exception ex) { Logger.Error("路径算法错误", ex); throw; } return results; #endregion } /// /// 获取匹配的最短路径节点 /// /// /// /// /// /// /// private void MatchPoint(List results, List roads, List shortestPathPoints, Dictionary isVisited, string pStartId, string pEndId) { List sRoads = roads.Where(x => x.startpoint_id == pStartId).ToList(); for (int j = 0; j < sRoads.Count; j++) { WmsPointH? sPoint = shortestPathPoints.Find(x => x.id == sRoads[j].endpoint_id); if (sPoint != null && isVisited.ContainsKey(sPoint.id) && !isVisited[sPoint.id] && sPoint.id != pEndId) { string code = sPoint.point_code; results.Add(sPoint); isVisited[sPoint.id] = true; MatchPoint(results, roads, shortestPathPoints, isVisited, sPoint.id, pEndId); } } } /// /// 根据终止节点获取最短路径顶点 /// /// /// /// /// private static void GetPoints(List pointIds, int[] prev, Stack result, int eIdx) { int index = eIdx; while (index != 0) { result.Push(pointIds[index]); index = prev[index]; } } private async Task Update(T1 entity, List entities) where T1 : BaseEntity, new() where T2 : BaseEntity, new() { bool isOk = false; try { await _db.Ado.BeginTranAsync(); isOk = await _db.Updateable(entity).ExecuteCommandHasChangeAsync(); if (entities?.Count > 0) { int row = await _db.Storageable(entities).ExecuteCommandAsync(); isOk = row > 0; } await _db.Ado.CommitTranAsync(); } catch (Exception) { await _db.Ado.RollbackTranAsync(); } return isOk; } /// /// 根据明细Id获取出入库明细信息 /// /// 出入库明细 /// 明细输出类 /// 出入库条码 /// 明细Id /// private async Task FetchInOutStockCodesById(string billDId) where TStockD : BaseEntity, new() where TOutput : IInOutStockDetail, new() where TStockCode : BaseEntity, IInOutStockCode, new() { Dictionary dic = await _dictionaryDataService.GetDictionaryByTypeId(WmsWareHouseConst.WMS_INSTOCK_D_BILL_STATUS_TYPEID); List data = await _db.Queryable() .Where(a => a.id == billDId) .Select(a => new TOutput { CodeDetails = SqlFunc.Subqueryable().Where(it => it.bill_d_id == a.id).ToList(), }, true) .Mapper(it => { it.line_status = it.line_status != null && dic.ContainsKey(key: it.line_status) ? dic[it.line_status]?.ToString() : ""; it.warehouse_id = _db.Queryable().Single(y => y.id == it.warehouse_id)?.whname ?? ""; }) .ToListAsync(); return data; } /// /// 二楼kiva把料架送到下升降机后生成中储仓入库任务 /// /// 料架id /// public async Task Floor2EmptyCarryCreateZZCPretask(string rackid) { try { List wmsCarryCodes = _db.Queryable().Where(r => r.carry_id == rackid).ToList(); foreach (WmsCarryD wmsCarryD in wmsCarryCodes) { await s_floor2CreatePretask.WaitAsync(); //入库取终点 //出库起点 InStockStrategyQuery inStockStrategyInput = new() { warehouse_id = WmsWareHouseConst.WAREHOUSE_ZC_ID, Size = 1 }; List endLocations = await InStockStrategy(inStockStrategyInput); if (endLocations.Count == 0) { Logger.LogWarning("没有可用的入库库位"); continue; } WmsPointH sPoint = null!; WmsPointH ePoint = null!; BasLocation basLocation011 = _db.Queryable().Where(r => r.id == WmsWareHouseConst.ZZCSSX111011).First(); BasLocation basLocation012 = _db.Queryable().Where(r => r.id == WmsWareHouseConst.ZZCSSX111012).First(); BasLocation startLocation = basLocation011.task_nums >= basLocation012.task_nums ? basLocation012 : basLocation011; sPoint = await _db.Queryable().FirstAsync(it => it.location_id == startLocation.id); if (endLocations?.Count > 0) { WmsCarryH carry = await _db.Queryable().SingleAsync(it => it.carry_code == wmsCarryD.membercarry_code); await _db.Updateable().SetColumns(r => new WmsCarryH { location_id = startLocation.id, location_code = startLocation.location_code, }).Where(r => r.id == carry.id).ExecuteCommandAsync(); //if (carry.carry_status == "1") //{ // throw new AppFriendlyException("载具已占用!", 500); //} //if (carry.is_lock == 1) //{ // throw new AppFriendlyException("载具已锁定!", 500); //} BasLocation loc = await _db.Queryable().SingleAsync(it => it.id == endLocations[0].id); bool isMatch = await IsCarryAndLocationMatchByCarryStd(carry, loc); if (!isMatch) { Logger.LogWarning("库位与载具规格不匹配"); continue; } ePoint = await _db.Queryable().FirstAsync(it => it.location_id == endLocations[0].id); } else { Logger.LogWarning($"库位{endLocations[0].location_code}未在点位表中维护对应点位"); continue; } Logger.LogInformation($"【送满托到下升降区】 开始生成一楼CTU'预任务 起点{sPoint.point_code} 终点{ePoint.point_code} 料箱 {wmsCarryD.membercarry_code}"); List points = new List(); points.Add(sPoint); points.Add(ePoint); //根据获取的路径点生成预任务,生成顺序必须预路径算法返回的起终点的顺序一致(预任务顺序) WmsPretaskH preTask = null; string bill_code = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_PRETASK_H_ENCODE).GetAwaiter().GetResult(); List preTasks = points.Where(it => !it.location_id.IsNullOrEmpty()).GroupBy(g => g.area_code).Select(it => { WmsPointH? sPoint = it.FirstOrDefault(); WmsPointH? ePoint = it.LastOrDefault(); preTask = new() { org_id = "", startlocation_id = sPoint?.location_id!, startlocation_code = sPoint?.location_code!, endlocation_id = ePoint?.location_id!, endlocation_code = ePoint?.location_code!, start_floor = sPoint?.floor.ToString(), end_floor = ePoint?.floor.ToString(), startpoint_id = sPoint?.id!, startpoint_code = sPoint?.point_code!, endpoint_id = ePoint?.id!, endpoint_code = ePoint?.point_code!, bill_code = bill_code, status = WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID, biz_type = WmsWareHouseConst.BIZTYPE_WMSEMPTYINSTOCK_ID, task_type = "", carry_id = wmsCarryD.membercarry_id, carry_code = wmsCarryD.membercarry_code, area_id = sPoint?.area_id!, area_code = it.Key, require_id = "", require_code = "", create_id = "", create_time = DateTime.Now }; return preTask; }).ToList(); //更新页面 //赋值签收状态 Logger.LogInformation($"开始执行 GenPreTask {JsonConvert.SerializeObject(preTasks)}"); bool result = await GenPreTask(preTasks, null!); Logger.LogInformation($"GenPreTask 结果 {result}"); if (result) { _ = await _db.Updateable().SetColumns(it => new BasLocation { is_lock = 1 }).Where(r => r.id == endLocations[0].id).ExecuteCommandAsync(); _ = await _db.Updateable().SetColumns(it => new BasLocation { task_nums = it.task_nums + 1 }).Where(r => r.id == startLocation.id).ExecuteCommandAsync(); Logger.LogInformation($"成功生成预任务:{preTasks.First().bill_code}"); } else { Logger.LogInformation($"【二楼kiva把料架送到下升降机后生成中储仓入库任务】 未成功生成预任务 起点{sPoint.point_code} 终点{ePoint.point_code} 料箱 {wmsCarryD.membercarry_code}"); } s_floor2CreatePretask.Release(); } return true; } catch(Exception ex) { Logger.LogInformation($"【二楼kiva把料架送到下升降机后生成中储仓入库任务】:{ex}"); s_floor2CreatePretask.Release(); return false; } finally { s_floor2CreatePretask.Release(); } } #endregion #region 通用接口 /// /// 生成预任务接口 CTU需要传task_type /// /// /// [HttpPost, NonUnify, AllowAnonymous] public async Task CommonCreatePretask(CommonCreatePretaskInput input) { Logger.LogInformation($"【createPretask】 接收到请求 参数:{JsonConvert.SerializeObject(input)}"); try { WmsPointH? sPoint = null; WmsPointH? ePoint = null; if (!string.IsNullOrEmpty(input.startlocation_id)) { sPoint = await _db.Queryable().FirstAsync(it => it.location_id == input.startlocation_id); } if (!string.IsNullOrEmpty(input.endlocation_id)) { ePoint = await _db.Queryable().FirstAsync(it => it.location_id == input.endlocation_id); } List points = new List(); if (sPoint.area_code != ePoint.area_code) { points = await PathAlgorithms(sPoint.id, ePoint.id); if (points.Count <= 2) { throw new AppFriendlyException("该路径不存在", 500); } } else { points.Add(sPoint); points.Add(ePoint); } //根据获取的路径点生成预任务,生成顺序必须预路径算法返回的起终点的顺序一致(预任务顺序) WmsPretaskH preTask = null; string bill_code = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_PRETASK_H_ENCODE).GetAwaiter().GetResult(); List preTasks = points.Where(it => !it.location_id.IsNullOrEmpty()).GroupBy(g => g.area_code).Select(it => { WmsPointH? sPoint = it.FirstOrDefault(); WmsPointH? ePoint = it.LastOrDefault(); string carry_id = ""; string carry_code = ""; WmsCarryH wmsCarryH = null; if (!string.IsNullOrEmpty(input.carry_id) && !string.IsNullOrEmpty(input.carry_code)) { carry_id = input.carry_id; carry_code = input.carry_code; } // 如果指定了carry_id else if (!string.IsNullOrEmpty(input.carry_id)) { wmsCarryH = _db.Queryable().Where(r => r.id == input.carry_id).First(); } // carry_code else if (!string.IsNullOrEmpty(input.carry_code)) { wmsCarryH = _db.Queryable().Where(r => r.carry_code == input.carry_code).First(); } // 如果carry_id和carry_code都没有指定,随机取库位上载具记录的一条 else { wmsCarryH = _db.Queryable().InnerJoin((a, b) => a.id == b.location_id) .Where((a, b) => a.id == sPoint.location_id).Select((a, b) => b).First(); } if (wmsCarryH != null) { carry_id = wmsCarryH.id; carry_code = wmsCarryH.carry_code; } if (string.IsNullOrEmpty(carry_id)) { throw new AppFriendlyException("起点库位上没有载具", 500); } preTask = new() { org_id = _userManager.User.OrganizeId, startlocation_id = sPoint?.location_id!, startlocation_code = sPoint?.location_code!, endlocation_id = ePoint?.location_id!, endlocation_code = ePoint?.location_code!, start_floor = sPoint?.floor.ToString(), end_floor = ePoint?.floor.ToString(), startpoint_id = sPoint?.id!, startpoint_code = sPoint?.point_code!, endpoint_id = ePoint?.id!, endpoint_code = ePoint?.point_code!, bill_code = bill_code, status = WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID, biz_type = !string.IsNullOrEmpty(input.biz_type) ? input.biz_type : "", task_type = !string.IsNullOrEmpty(input.task_type) ? input.task_type : "", carry_id = carry_id, carry_code = carry_code, area_id = sPoint?.area_id!, area_code = it.Key, require_id = "", require_code = "", create_id = _userManager.UserId, create_time = DateTime.Now }; return preTask; }).ToList(); //更新页面 //赋值签收状态 Logger.LogInformation($"【createPretask】 开始执行 GenPreTask {JsonConvert.SerializeObject(preTasks)}"); bool result = await GenPreTask(preTasks, null!); Logger.LogInformation($"【createPretask】 GenPreTask 结果 {result}"); if (result) { Logger.LogInformation($"【createPretask】 成功生成预任务:{preTasks.First().bill_code}"); return await ToApiResult(JNPF.Common.Enums.HttpStatusCode.OK, "成功"); } return await ToApiResult(JNPF.Common.Enums.HttpStatusCode.InternalServerError, "生成预任务失败"); } catch (Exception ex) { return await ToApiResult(JNPF.Common.Enums.HttpStatusCode.InternalServerError, ex.Message); } finally { await GenTaskExecute(); } } #endregion } }