using Rhea.Common; using Tiger.IBusiness; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading; using System.Threading.Tasks; using Tiger.Model; using static Tiger.Business.Biz; using Tiger.Model.Entitys.MES.Position; using System.Globalization; using Tiger.Business.MES.WorkAction; using System.Collections; using Tiger.IBusiness.MES.WorkAction; using Dm.parser; namespace Tiger.Business.MES.Transaction { /// /// MES岗位事务 /// public class Position : MESTransactionBase, IPosition { public IPosition Init(string id, string apiHost, string userCode, string postCode) { TransID = id; UserCode = userCode; ApiHost = apiHost; PostCode = postCode; _MainDB = Biz.Db; CurPosition = MainDB.Queryable().Where(q => q.POST_CODE == postCode).First(); //if (CurPosition.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.PositionNotExistsException", new Exception($"{postCode}|")); if (CurPosition.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]不存在,请提交正确的岗位代码", new Exception($"{postCode}|")); CurLine = MainDB.Queryable().Where(q => q.LINE_CODE == CurPosition.LINE_CODE).First(); //if (CurLine.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.LineNotExistsException", new Exception($"{postCode}|{CurPosition.LINE_CODE}")); if (CurLine.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]所属的产线[{CurPosition.LINE_CODE}]不存在,请先设置所属产线", new Exception($"{postCode}|{CurPosition.LINE_CODE}")); CurWorkshop = MainDB.Queryable().Where(q => q.WS_CODE == CurLine.WS_CODE).First(); //if (CurWorkshop.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.WorkshopNotExistsException", new Exception($"{postCode}|{CurLine.WS_CODE}")); if (CurWorkshop.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]所属的车间[{CurLine.WS_CODE}]不存在,请先设置所属车间", new Exception($"{postCode}|{CurLine.WS_CODE}")); CurFactory = MainDB.Queryable().Where(q => q.FTY_CODE == CurWorkshop.FTY_CODE).First(); //if (CurFactory.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.FactoryNotExistsException", new Exception($"{postCode}|{CurWorkshop.FTY_CODE}")); if (CurFactory.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]所属的工厂[{CurWorkshop.FTY_CODE}]不存在,请先设置所属工厂", new Exception($"{postCode}|{CurWorkshop.FTY_CODE}")); //加载当前产线的班制 CurShiftSys = MainDB.Queryable().Where(q => q.SFTS_CODE == CurLine.SFTS_CODE).IncludesAllFirstLayer().IncludesAllSecondLayer(q => q.Shifts).First(); return this; } #region Propertys & Variables public string UserCode { get; set; } public string PostCode { get; set; } protected DateTime BeginAt; protected DateTime EndAt; public TimeSpan ElapsedTime => EndAt - BeginAt; public MES_FACTORY CurFactory { get; set; } public MES_WORKSHOP CurWorkshop { get; set; } public MES_LINE CurLine { get; set; } public MES_POSITION CurPosition { get; set; } public MES_SHIFT_SYS CurShiftSys { get; set; } public WorkBatch CurBatch { get; set; } public IWorkBatch WorkBatch => CurBatch; public List CurWipSNs { get; set; } = new(); public List LastWipSNs { get; set; } = new(); public string CurSN => (CurWipSNs.Any() ? (CurWipSNs.First().TRAY_SN.IsNullOrEmpty() ? CurWipSNs.First().SN : CurWipSNs.First().TRAY_SN) : ""); public List CurWipSNHiss { get; set; } = new(); public List CurDefects { get; set; } = new(); public Dictionary Context { get; set; } = new(); public List Steps { get; set; } = new(); public WorkStep CurStep { get; set; } public List NextSteps { get; set; } = new(); public bool IsFinishNodeSteps => !Steps.Any(q => q.NodeType == IWorkStep.NodeTypes.Node && !q.IsFinished); public bool IsFinishAllSteps => Steps.Any() && !Steps.Any(q => !q.IsFinished); //public int CurStep => Steps.Where(q => !q.IsFinished).OrderBy(q => q.Sequence).FirstOrDefault()?.Sequence ?? 0; private DbClient _MainDB; public DbClient MainDB => _MainDB; private DbClient CommitDB; /// /// 是否需要临时存储数据库提交操作,待需要的时候再提交 /// public bool NeedTemporaryStoreDBCommitAction { get; set; } = false; protected Dictionary> DBCommitList { get; set; } = new(); protected List NodeCommitList { get; set; } = new(); private Dictionary OperInfoDic = new(); #endregion Propertys & Variables #region Functions /// /// 获取提交数据的DbClient对象 /// /// public DbClient GetCommitDB() { return CommitDB ??= Biz.Db; } /// /// 选择工单 /// /// /// public async Task SelectOrder(WoInput input, string batchNo = "") { var action = new ApiAction(); try { if (!WoContext.ExistsBatch(input.OrderNo, CurLine.LINE_CODE, batchNo, true)) { var wo = await MainDB.Queryable().ByAuth(input.AuthOption).Where(q => q.ORDER_NO == input.OrderNo).FirstAsync(); //验证明细是否正确 if (wo.IsNullOrEmpty()) { action.IsSuccessed = false; //action.LocaleMsg = new($"工单[{input.OrderNo}]不存在", input.OrderNo); action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.EmptyException", input.OrderNo); return action; } if (wo.STATUS != BIZ_MES_WO.STATUSs.Release.GetValue() && wo.STATUS != BIZ_MES_WO.STATUSs.Working.GetValue()) { action.IsSuccessed = false; //action.LocaleMsg = new($"工单[{0}]状态[{1}]不能生产"); action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.StatusException", input.OrderNo, wo.STATUS.GetEnumDesc()); return action; } var batch = await MainDB.Queryable().ByAuth(input.AuthOption) .Where(q => q.ORDER_NO == input.OrderNo && q.ACT_LINE == CurLine.LINE_CODE) .WhereIF(!batchNo.IsNullOrEmpty(), q => q.BATCH_NO == batchNo) .OrderBy(q => q.STATUS).FirstAsync(); if (batch.IsNullOrEmpty()) { action.IsSuccessed = false; //action.LocaleMsg = new($"工单[{input.OrderNo}]没有下发到产线状态[{CurLine.LINE_CODE}]"); action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.LineException", input.OrderNo, CurLine.LINE_CODE); return action; } if (batch.STATUS != BIZ_MES_WO_BATCH.STATUSs.Release.GetValue() && batch.STATUS != BIZ_MES_WO_BATCH.STATUSs.Working.GetValue()) { action.IsSuccessed = false; //action.LocaleMsg = new($"工单[{0}]批次[1]状态[{2}]不能生产"); action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.BatchStatusException", input.OrderNo, batch.BATCH_NO, batch.STATUS.GetEnumDesc()); return action; } var wb = WoContext.Add(input.OrderNo, CurLine.LINE_CODE); batchNo = wb.Batch.BATCH_NO; } CurBatch = WoContext.GetBatch(input.OrderNo, CurLine.LINE_CODE, batchNo); if (!OperInfoDic.ContainsKey(CurBatch.Batch.BATCH_NO)) { OperInfoDic.Add(CurBatch.Batch.BATCH_NO, new()); } action.Data = new { WorkOrder = CurBatch.WO, Bacth = CurBatch.Batch }; } catch (Exception ex) { action.CatchExceptionWithLog(ex, $"采集工序:选择工单异常"); } return action; } /// /// 获取当前时间所属的班制班次时段 /// public ShiftPeriod GetShiftPeriodForNow() { var time = DateTime.Now.ToString("HHmm").ToInt32(); foreach (var shift in CurShiftSys.Shifts) { var period = shift.Periods.Where(q => q.PRD_BEGIN <= time && time <= q.PRD_END).FirstOrDefault(); if (!period.IsNullOrEmpty()) { var result = new ShiftPeriod(); result.ShiftSys = CurShiftSys; result.Shift = shift; result.Period = period; return result; } } return null; } /// /// 重置工序操作 /// /// public ApiAction Reset() { var action = new ApiAction(); ResetNode(); action.IsSuccessed = true; action.LocaleMsg = new($"工序操作已重置,请重新扫描进站产品条码"); action.LocaleMsg = new("MES.Transaction.Position.ResetNode"); return action; } /// /// 重置当前工序,有需要则重写此方法 /// public virtual void ResetNode() { Steps.Clear(); CurWipSNs.Clear(); CurWipSNHiss.Clear(); CurStep = null; CurDefects.Clear(); } //获取当前的工序信息 protected OperInfo CurOperInfo(string locale) { OperInfo info = new(); if (CurBatch?.Batch?.BATCH_NO != null) { info = OperInfoDic[CurBatch.Batch.BATCH_NO]; info.StepsInfo = Steps.Select(q => q.GetInfo(locale)).ToList(); } return info; } /// /// 设置当前条码的工序信息 /// public OperInfo SetOperNodeInfo(OperInfo info) { if (CurWipSNs.Any()) { info.CurNode = CurWipSNs.First().NODE_NAME; var nextNodes = CurBatch.GetNextNodes(CurWipSNs.First()); info.NextNode = string.Join(",", nextNodes.Select(q => q.NODE_NAME)); if (nextNodes.Count == 1 && nextNodes.Single().OPER_CODE == "EndNode") { info.IsReachedEndNode = true; } } else { info.CurNode = " — "; info.NextNode = " — "; } return info; } /// /// 设置当前条码的工序信息 /// public ApiAction SetOutPutMqttMsg(ApiAction action, string locale = null) { MQTT.Message msg = new() { IsSuccessed = action.IsSuccessed, Content = Biz.T(action.LocaleMsg, locale), }; switch (action.Status) { case ApiAction.StatusCodes.Success: msg.Voice = MQTT.Voice.Success; msg.Color = "#FF1E90FF"; break; case ApiAction.StatusCodes.Warning: msg.Voice = MQTT.Voice.Warning; msg.Color = "#FFB8860B"; break; case ApiAction.StatusCodes.Error: case ApiAction.StatusCodes.Failed: msg.Voice = MQTT.Voice.Fail; msg.Color = "#FFFF0000"; break; case ApiAction.StatusCodes.Exception: msg.Voice = MQTT.Voice.Fail; msg.Color = "#FF8B0000"; break; case ApiAction.StatusCodes.Normal: case ApiAction.StatusCodes.NeedConfrim: case ApiAction.StatusCodes.Confrimed: default: msg.Voice = MQTT.Voice.Silent; msg.Color = "#FF000000"; break; } if (action.Data.IsFinished && action.IsSuccessed) { msg.Voice = MQTT.Voice.Pass; msg.Color = "#FF228B22"; } else if (!action.IsSuccessed) { msg.Voice = MQTT.Voice.Fail; msg.Color = "#FFFF0000"; } else { msg.Voice = MQTT.Voice.Silent; msg.Color = "#FF000000"; } action.Data.MqttMsg = msg; return action; } /// /// 生成传入工步后续的行为到工步列表 /// /// public void GenerateSteps(WorkStep parent) { //递归添加所有工步 AddNextActToSteps(parent); //调整工步的序号 //while (CurBatch.Edges.Any(q => Steps.First(s => s.NodeID == q.SRC_NODE).Sequence <= Steps.First(s => s.NodeID == q.TGT_NODE).Sequence)) //{ // var edges = CurBatch.Edges.Where(q => Steps.First(s => s.NodeID == q.SRC_NODE).Sequence >= Steps.First(s => s.NodeID == q.TGT_NODE).Sequence).ToList(); // foreach (var edge in edges) // { // var source = Steps.First(s => s.NodeID == edge.SRC_NODE); // var target = Steps.First(s => s.NodeID == edge.TGT_NODE); // target.Sequence = source.Sequence + 1; // } //} } /// /// 添加节点的下一个行为到工步列表 /// /// private void AddNextActToSteps(WorkStep parent) { var edges = CurBatch.Edges.Where(q => q.SRC_NODE == parent.NodeID && CurBatch.NodeActs.Any(a => a.NODE_ID == parent.Node.ID && a.ID == q.TGT_NODE)).ToList(); foreach (var edge in edges) { var act = CurBatch.NodeActs.First(q => q.ID == edge.TGT_NODE); if (Steps.Any(q => q.NodeID == act.ID)) { var next = Steps.First(q => q.NodeID == act.ID); next.Sequence = next.Sequence > parent.Sequence ? next.Sequence : (parent.Sequence + 1); next.PrepNodeIDs.Add(parent.NodeID); next.PrepNodeIDs.AddRange(parent.PrepNodeIDs); next.PrepNodeIDs = next.PrepNodeIDs.Distinct().ToList(); AddNextActToSteps(next); } else { var next = new WorkStep(IWorkStep.NodeTypes.Action, this) { Name = act.ACT_NAME, Sequence = parent.Sequence + 1, Node = parent.Node, OperSetting = CurBatch.NodeSets.FirstOrDefault(q => q.NODE_ID == parent.Node.ID), NodeAct = act, ActSetting = CurBatch.ActionSets.FirstOrDefault(q => q.ACT_ID == act.ID), }; next.Init(); next.PrepNodeIDs.Add(parent.NodeID); next.PrepNodeIDs.AddRange(parent.PrepNodeIDs); next.PrepNodeIDs = next.PrepNodeIDs.Distinct().ToList(); Steps.Add(next); AddNextActToSteps(next); } } } /// /// 根据传入的工步,返回下一步可执行的工步列表 /// /// public List GetNextSteps(WorkStep curStep) { var result = new List(); var nextSteps = Steps.Where(q => !q.IsFinished && CurBatch.Edges.Any(e => e.SRC_NODE == curStep.NodeID && e.TGT_NODE == q.NodeID) ).ToList(); //尝试将当前工步的后续工步添加到可以执行的工步列表 foreach (var step in nextSteps) { //查找有没有前置工步未完成,若有则不允许继续执行 if (!Steps.Any(q => step.PrepNodeIDs.Any(id => id == q.NodeID && !q.IsFinished))) { result.Add(step); } } //如果当前工步没有可执行的后续工步,则在前置工步查找还有没有后续工步没完成的工步,有则执行 if (!result.Any() && Steps.Any()) { //查找有没有前置工步未完成,若有则先完成未完成的前置工步 var prepIDs = curStep.PrepNodeIDs.Where(id => CurBatch.Edges.Any(e => e.SRC_NODE == id && Steps.Any(q => !q.IsFinished && e.TGT_NODE == q.NodeID))).ToList(); var prepSteps = Steps.Where(q => prepIDs.Contains(q.NodeID)).OrderByDescending(q => q.Sequence).ToList(); while (prepSteps.Any() && !result.Any()) { var prep = prepSteps.First(); var prepNext = GetNextSteps(prep); if (prepNext.Any()) { result = prepNext; } else { prepSteps.Remove(prep); } } } return result.OrderBy(q => q.NodeAct.ACT_NAME).ToList(); } /// /// 开始执行下一行为工步 /// /// public ApiAction BeginNextActionStep(SubmitInput input) { var result = new ApiAction(new SubmitOutput()); //设置后续可执行的工步列表 NextSteps = GetNextSteps(CurStep); //尝试有没有可以直接开始的后续工步 foreach (var step in NextSteps) { //尝试执行后续工步 var canBegin = step.TryBegin(input); //如果后续工步可以直接开始则直接执行 if (canBegin.IsSuccessed) { //更新当前执行工步为已开始工步 CurStep = step; //更新后续可执行的工步列表 NextSteps = GetNextSteps(CurStep); //如果当前执行工步尝试执行后就已经完成,不需要后续交互,且,则继续开始下一工步 if (CurStep.IsFinished && NextSteps.Any()) { result = BeginNextActionStep(input); } else { //返回结果到客户端 result = canBegin; result.Data.SetValue(CurBatch, CurStep, CurStep?.ID, IsFinishAllSteps); } return result; } //工序被重置 else if (Steps.IsNullOrEmpty()) { return canBegin; } } //没有可以直接开始的后续工步,根据后续工步返回ApiAction result.Data.SetValue(CurBatch, CurStep, "", IsFinishAllSteps); //没有可以直接开始的后续工步,根据后续可执行工步列表返回相应的操作提示 if (NextSteps.Count == 1) { result.LocaleMsg = NextSteps.First().GetBeginMsg(); } else { result.LocaleMsg = new(T(L("MES.Transaction.Position.PleaseSelectNextStep"), input.Locale) + "\r\n" + string.Join("\r\n", NextSteps.Select(q => " >> " + T(q.GetBeginMsg(), input.Locale)))); } return result; } /// /// 保存工步的数据库提交操作到数据库 /// /// 提交完工步数据后,提交附加的保存内容 public void SaveStepsCommitActionToDB(Action appendToSave = null) { //保存工步的数据库提交操作到提交操作列表 if (!Steps.IsNullOrEmpty()) { var commitList = new List(); foreach (var step in Steps.OrderBy(q => q.Sequence)) { commitList.Add(step.DBSubmitAction); } //记录工序耗时 var ids = CurWipSNHiss.Select(q => q.ID).ToList().Clone(); commitList.Add(() => { EndAt = DateTime.Now; GetCommitDB().Updateable().SetColumns(q => q.ELAPSED_TIME == ElapsedTime.TotalMilliseconds.ToInt64()).Where(q => ids.Contains(q.ID)).ExecuteCommand(); }); //增加附加的保存内容 if (!appendToSave.IsNullOrEmpty()) { commitList.Add(appendToSave); } DBCommitList.Add(CurSN, commitList); } else { //增加附加的保存内容 if (!appendToSave.IsNullOrEmpty()) { if (!DBCommitList.ContainsKey("AppendSaveAction")) { DBCommitList.Add("AppendSaveAction", new List()); } var commitList = DBCommitList["AppendSaveAction"]; commitList.Add(appendToSave); } } //如果不需要临时存储数据库提交操作,则把提交操作列表提交到数据库 if (!NeedTemporaryStoreDBCommitAction) { //恢复临时存储标记为false NeedTemporaryStoreDBCommitAction = false; var dbTran = GetCommitDB().UseTran(() => { //在同一个事务中保存所有工步的数据 foreach (var wipSn in DBCommitList.Keys.Where(q => q != "AppendSaveAction")) { foreach (var action in DBCommitList[wipSn]) { action.Invoke(); } } //附加的保存内容 if (DBCommitList.ContainsKey("AppendSaveAction")) { foreach (var action in DBCommitList["AppendSaveAction"]) { action.Invoke(); } } }); if (dbTran.IsSuccess) { //保存成功则清空提交操作列表 DBCommitList.Clear(); } else { //抛出异常 throw dbTran.ErrorException; } } //记录最后成功过站的条码 LastWipSNs.Clear(); LastWipSNs.AddRange(CurWipSNs); } protected void DoSaveToDB() { var dbTran = GetCommitDB().UseTran(() => { //在同一个事务中保存所有工步的数据 foreach (var step in Steps.OrderBy(q => q.Sequence)) { step.DBSubmitAction.Invoke(); } }); if (!dbTran.IsSuccess) { //抛出异常 throw dbTran.ErrorException; } } #region 打印专用方法 /// /// 获取打印标签模板过程变量值 /// /// 过程变量列表 /// 标签模板 /// public BAS_LABEL_TEMP SetLabelVariables(List labelPVs, BAS_LABEL_TEMP label, IWorkAction action) { return SetLabelVariables(labelPVs, label, action, null); } public BAS_LABEL_TEMP SetLabelVariables(List labelPVs, BAS_LABEL_TEMP label, IWorkAction action, WipPkg? CurPkg) { foreach (var item in label.Variables.OrderBy(q => q.VAR_TYPE == BAS_LABEL_VAR.VAR_TYPEs.BarcodeGenerate.GetValue() ? 0 : 1)) { switch (item.VAR_TYPE.GetEnum()) { case BAS_LABEL_VAR.VAR_TYPEs.Constant: item.Value = item.VAR_VALUE; break; case BAS_LABEL_VAR.VAR_TYPEs.ProcessVariable: item.Value = GetPrintProcessValue(labelPVs, item, label.Variables, action, CurPkg); break; case BAS_LABEL_VAR.VAR_TYPEs.DateVariable: item.Value = DateTime.Now.ToString(item.VAR_VALUE); break; case BAS_LABEL_VAR.VAR_TYPEs.BarcodeGenerate: item.Value = GetGeneratePValue(labelPVs, item); break; case BAS_LABEL_VAR.VAR_TYPEs.CustomVariable: default: item.Value = ""; break; } } return label; } /// /// 获取打印标签模板过程变量值 /// /// 过程变量列表 /// 标签模板变量 /// public string GetPrintProcessValue(List labelPVs, BAS_LABEL_VAR lv, List lvars, IWorkAction curAction, WipPkg? CurPkg) { var pv = labelPVs.FirstOrDefault(q => q.VAR_CODE == lv.VAR_VALUE); if (!pv.IsNullOrEmpty()) { switch (pv.VAR_TYPE.GetEnum()) { case BAS_PROCESS_VAR.VAR_TYPEs.ServerMethod: { switch (pv.VAR_METHOD) { case "GetSN": return CurSN; case "GetItemCode": return GetLabelVarWo(lv, WorkBatch.Product.ITEM_CODE); case "GetBAS_ITEM": return GetLabelVarWo(lv, WorkBatch.Product.CUST_PROD_CODE); case "GetItemName": return GetLabelVarWo(lv, WorkBatch.Product.ITEM_NAME); case "GetCustomer": return GetLabelVarWo(lv, WorkBatch.Batch.Customer.ToJson()); case "GetSalesOrder": return GetLabelVarWo(lv, WorkBatch.WO.SALES_ORDER); case "GetPackNumber": return GetLabelVarWo(lv, WorkBatch.WO.ORDER_NO); case "GetBoxQR": return GetCardOrBoxQR(GetBoxCode(), curAction, CurPkg); case "GetCardQR": return GetCardOrBoxQR("", curAction, CurPkg); case "GetCardSN": List minPkgList = new List(); if (!CurPkg.IsNullOrEmpty()) { minPkgList = CurPkg.Item.GetWipSnList().Select(q => q.Value).ToList(); } else { var _pkaction = curAction is PackingAction ? curAction as PackingAction : null; if (!_pkaction.IsNullOrEmpty()) { minPkgList = GetMinPkgList(_pkaction); } if (curAction is PrintInStoreLabel) { minPkgList = (curAction as PrintInStoreLabel).CurPkg.Item.GetWipSnList().Select(q => q.Value).ToList(); } } return string.Join("\r\n", minPkgList); case "GetDescription": return GetLabelVarWo(lv, WorkBatch.Product.ITEM_DESC); case "GetFengZ": return GetLabelVarWo(lv, WorkBatch.Product.ExtInfo.Packaging); case "GetPAndO": return GetLabelVarWo(lv, WorkBatch.WO.SALES_CONTRACT); case "GetLTD": return GetLabelVarWo(lv, WorkBatch.WO.Customer?.CUST_NAME_CN); case "GetHWDate": List list = new List(); if (!CurPkg.IsNullOrEmpty()) { list = CurPkg.Item.GetWipSnList().Select(q => q.Value).ToList(); } else { var _action = curAction is PackingAction ? curAction as PackingAction : null; if (_action != null) { list = _action.CurPkg.Item.GetWipSnList().Select(q => q.Value).ToList(); } if (curAction is PrintInStoreLabel) { list = (curAction as PrintInStoreLabel).CurPkg.Item.GetWipSnList().Select(q => q.Value).ToList(); } } return GetHuaWeiWeek(WorkBatch.Batch.ORDER_NO, list); case "GetQty": List qtylist = new List(); if (!CurPkg.IsNullOrEmpty()) { qtylist = CurPkg.Item.GetWipSnList().Select(q => q.Value).ToList(); } else { if (curAction is PackingAction) { qtylist = (curAction as PackingAction).CurPkg.Item.GetWipSnList().Select(q => q.Value).ToList(); } if (curAction is PrintInStoreLabel) { qtylist = (curAction as PrintInStoreLabel).CurPkg.Item.GetWipSnList().Select(q => q.Value).ToList(); } } return $"{qtylist.Count}"; case "GetModel": return GetLabelVarWo(lv, WorkBatch.Product.ExtInfo?.Model); case "GetInput": return GetLabelVarWo(lv, WorkBatch.Product.ExtInfo?.Input); case "GetOutput": return GetLabelVarWo(lv, WorkBatch.Product.ExtInfo?.OutPut); case "GetPower": return GetLabelVarWo(lv, WorkBatch.Product.ExtInfo?.Power); case "GetAccuracy": return GetLabelVarWo(lv, WorkBatch.Product.ExtInfo?.Accuracy); case "GetVarByWo": return GetLabelVarWo(lv, ""); case "GetLOTNO": List snList = new List(); string _lotnos = ""; var _orderAction = curAction is PackingAction ? curAction as PackingAction : null; if (!CurPkg.IsNullOrEmpty()) { snList = CurPkg.Item.GetWipSnList().Select(q => q.Value).ToList(); } else { if (_orderAction != null) { snList = _orderAction.CurPkg.Item.GetWipSnList().Select(q => q.Value).ToList(); snList.Add(_orderAction.CurPkg.CustSN?.FLOW_SN); } if (curAction is PrintInStoreLabel) { snList = (curAction as PrintInStoreLabel).CurPkg.Item.GetWipSnList().Select(q => q.Value).ToList(); snList.Add((curAction as PrintInStoreLabel).CurPkg.CustSN?.FLOW_SN); } } _lotnos = string.Join(",", MainDB.Queryable() .Where((q) => snList.Contains(q.FLOW_SN)) .Select((q) => q.WORK_ORDER).Distinct().ToList()); return _lotnos; case "GetNOTES": return GetLabelVarWo(lv, WorkBatch.Product.ExtInfo?.Remark); case "GetXH": return ""; case "GetCardNo": return $"{Context.GetOrDefault("CurWaitShipmentCarton").ToInt32() + 1}"; case "GetCardTotal": var total = ""; var _curaction = curAction is PackingAction ? curAction as PackingAction : null; if (!_curaction.IsNullOrEmpty()) { total = $"{Math.Ceiling(Context.GetOrDefault("CurShipQty").ToDecimal()/_curaction.PkgRule.GetTotalQty().ToDecimal())}"; } return total; case "GetModelSpec": //Model+空格+SPEC, return GetLabelVarWo(lv, $"{WorkBatch.Product.ExtInfo?.Model} {WorkBatch.Product.SPEC}"); case "GetDATE": return GetLabelVarWo(lv, $"{DateTime.Now.ToString("yyyy/MM/dd")}"); default: return ""; } } case BAS_PROCESS_VAR.VAR_TYPEs.WebApi: break; case BAS_PROCESS_VAR.VAR_TYPEs.StoredProcedure: break; default: break; } } return ""; } /// /// 获取根据条码规则生成标签模板的过程变量值 /// /// /// /// public string GetGeneratePValue(List labelPVs, BAS_LABEL_VAR lv) { var pv = labelPVs.FirstOrDefault(q => q.VAR_CODE == lv.VAR_VALUE); if (!pv.IsNullOrEmpty()) { switch (pv.VAR_TYPE.GetEnum()) { case BAS_PROCESS_VAR.VAR_TYPEs.BarcodeGenerate: { switch (pv.VAR_METHOD) { case "GetCartonGenerate": return Cache.CodeRule[lv.BARCODE_RULE ?? ""]?.Generate("B", $"{WorkBatch.Batch.BATCH_NO}-{WorkBatch.Batch.PLAN_QTY}-").Data.ToString() ?? ""; case "GetHW21SNGenerate": return Cache.CodeRule[lv.BARCODE_RULE ?? ""]?.Generate("SN:", "05").Data.ToString() ?? ""; default: return ""; } } default: break; } } return ""; } /// /// 获取工单维护的模板变量 /// /// /// private string GetLabelVarWo(BAS_LABEL_VAR lv, string value) { string result = ""; var labelVarwos = MainDB.Queryable().Where(x => x.LABEL_ID == lv.LABEL_ID && x.VAR_NAME == lv.VAR_NAME).ToList(); if (labelVarwos.Any(q => q.WORK_ORDER == WorkBatch.Batch.ORDER_NO)) { result = labelVarwos.First(q => q.WORK_ORDER == WorkBatch.Batch.ORDER_NO).VAR_VALUE; } else { result = value.IsNullOrEmpty() ? (labelVarwos.Count > 0 ? labelVarwos.First(q => q.WORK_ORDER.IsNullOrEmpty()).DEFAULT_VALUE : "") : value; } return result; } /// /// 获取最小包装条码列表 /// /// /// private List GetMinPkgList(PackingAction action) { List list = new List(); if (action.CurPkg.IsNullOrEmpty()) { list.Add(CurSN); } else { list = action.CurPkg.Item.GetMinPackageList().Select(q => q.SN).ToList(); } return list; } /// /// 获取白盒条码 /// /// private string GetBoxCode() { return Cache.CodeRule["WhiteBoxNo"]?.Generate("W", $"{WorkBatch.Batch.BATCH_NO}-{WorkBatch.Batch.PLAN_QTY}-").Data.ToString() ?? ""; } /// /// 获取箱条码 /// /// private string GetCardCode() { return Cache.CodeRule["CartonNo"]?.Generate("B", $"{WorkBatch.Batch.BATCH_NO}-{WorkBatch.Batch.PLAN_QTY}-").Data.ToString() ?? ""; } /// /// 获取白盒或者箱二维码 /// /// /// /// /// private string GetCardOrBoxQR(string code, IWorkAction action, WipPkg? CurPkg) { List minPkgList = new List(); var itemCode = ""; double weight = 0; var unit = ""; if (!CurPkg.IsNullOrEmpty()) { minPkgList = CurPkg.Item.GetWipSnList().Select(q => q.Value).ToList(); itemCode = CurPkg.CustSN?.ITEM_CODE; weight = CurPkg.WeightInfo.Weight; unit = CurPkg.WeightInfo.Unit?.ToUpper() ?? "kg"; } else { if (action is PackingAction) { var pkg = action as PackingAction; //minPkgList = pkg.CurPkg.Item.GetMinPackageList().Select(q => q.SN).ToList(); minPkgList = pkg.CurPkg.Item.GetWipSnList().Select(q => q.Value).ToList(); itemCode = pkg.CurPkg.CustSN?.ITEM_CODE; weight = pkg.CurPkg.WeightInfo.Weight; unit = pkg.CurPkg.WeightInfo.Unit?.ToUpper() ?? "kg"; } if (action is PrintInStoreLabel) { var print = action as PrintInStoreLabel; //minPkgList = print.CurPkg.Item.GetMinPackageList().Select(q => q.SN).ToList(); minPkgList = print.CurPkg.Item.GetWipSnList().Select(q => q.Value).ToList(); itemCode = print.CurPkg.CustSN?.ITEM_CODE; weight = print.CurPkg.WeightInfo.Weight; unit = print.CurPkg.WeightInfo.Unit?.ToUpper() ?? "kg"; } } var wo = WorkBatch.Batch.ORDER_NO; var snList = string.Join("\r\n", minPkgList); if (snList.IsNullOrEmpty()) { snList = $"{CurSN}"; } var model = WorkBatch.Product.ExtInfo?.Model; var Input = WorkBatch.Product.ExtInfo?.Input; var OutPut = WorkBatch.Product.ExtInfo?.OutPut; var Power = WorkBatch.Product.ExtInfo?.Power; var Accuracy = WorkBatch.Product.ExtInfo?.Accuracy; var Display = WorkBatch.Product.ExtInfo?.Display; var Remark = WorkBatch.Product.ExtInfo?.Remark; return $"{code}|{itemCode}|{wo}|\r\n{snList}|{weight}{unit}|型号:{model},输入:{Input},显示:{Display},输出:{OutPut},电源:{Power},精度:{Accuracy},备注:{Remark}"; } /// /// 根据包装工单和条码获取华为要求的生产周期 /// /// /// private string GetHuaWeiWeek(string pkgOrder, List snList) { Dictionary dic = new(); var snOrder = MainDB.Queryable((q, w) => new JoinQueryInfos(JoinType.Left, q.WORK_ORDER == w.ORDER_NO)) .Where((q, w) => q.PKG_ORDER == pkgOrder && (snList.Contains(q.FLOW_SN) || snList.Contains(q.CUST_SN))) .Select((q, w) => new { q.PKG_ORDER, q.WORK_ORDER, w.ACT_START_TIME, w.PLAN_START_TIME, q.FLOW_SN, q.CUST_SN }).ToList(); foreach (var sn in snList) { var item = snOrder.FirstOrDefault(q => q.FLOW_SN == sn || q.CUST_SN == sn); if (!item.IsNullOrEmpty()) { var date = item.ACT_START_TIME < new DateTime(2000, 1, 1) ? item.PLAN_START_TIME : item.ACT_START_TIME; var firstDay = new DateTime(date.Year, 1, 1); int daysOffset = firstDay.DayOfWeek.GetValue() > 3 ? (firstDay.DayOfWeek.GetValue() - 7) : 0; int year = date.Year + ((date - firstDay).TotalDays + daysOffset < 0 ? -1 : 0); int week = CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Sunday); dic.Add(sn, $"{year.ToString("0000").Substring(2, 2)}{week:00}"); } else { dic.Add(sn, ""); } } var weeks = dic.Select(q => q.Value).Where(q => !q.IsNullOrEmpty()).Distinct().OrderBy(q => q).ToList(); switch (weeks.Count) { case 0: return ""; case 1: return weeks.First(); case 2: return string.Join("、", weeks.Select(q => q + $"({dic.Count(d => d.Value == q)}PCS)")); default: return string.Join("、", weeks.Take(2)) + " (+)"; } } #endregion #region 条码规则方法 /// /// 获取根据条码规则生成条码 /// /// /// /// public string GenerateSN(string ruleCode, IWorkAction curAction) { var rule = Cache.CodeRule[ruleCode ?? ""]; if (!rule.IsNullOrEmpty()) { switch (rule.RULE_CODE) { case "WhiteBoxNo": return rule.Generate("W", $"{WorkBatch.Batch.BATCH_NO}-{WorkBatch.Batch.PLAN_QTY}-").Data.ToString() ?? ""; case "CartonNo": return rule.Generate("B", $"{WorkBatch.Batch.BATCH_NO}-{WorkBatch.Batch.PLAN_QTY}-").Data.ToString() ?? ""; default: return rule.Generate().Data.ToString() ?? ""; } } return ""; } #endregion #region 包装专用方法 /// /// 根据传入的包装对象返回所有的包装实体列表 /// /// /// public List GetPackageList(WipPkgItem parent) { List list = new(); if (!parent.Package.IsNullOrEmpty()) { list.Add(parent.Package); } foreach (var item in parent.Items) { item.Package.PARENT_SN = parent.Package?.SN; list.AddRange(GetPackageList(item)); } return list; } #endregion #endregion Functions public override bool Close(bool needSaveHistoryLog = false) { //needSaveHistoryLog = true; //保存操作日志 this.IsFinished = true; return IsFinished ? base.Close(needSaveHistoryLog) : IsFinished; } }//endClass }