服务端的TigerApi 框架,基于.NET6 2024 版本
Rodney Chen
2024-08-02 8bfaf7141c88f41d3dbd1995cfb9cb015ca0d1d6
Tiger.Business.MES/Transaction/PackingNode.cs
@@ -10,6 +10,7 @@
using System.Threading.Tasks;
using Tiger.Model;
using Tiger.Model.Entitys.MES.Position;
using Tiger.Business.MES.WorkAction;
namespace Tiger.Business.MES.Transaction
{
@@ -26,7 +27,14 @@
        }
        #region Propertys & Variables
        /// <summary>
        /// 工序当前执行的指令代码,包括:<br/>
        /// {null or ""}:工序空闲,指令为空则认为工序没有执行任何指令<br/>
        /// NodeSubmit:产品过站,正常产品过站逻辑<br/>
        /// PkgSubmit:手动结束包装,手动保存暂存的包装数据<br/>
        /// </summary>
        public string NodeCmd { get; set; }
        public PackingAction TempPkgAction { get; set; }
        #endregion Propertys & Variables
        #region Functions
@@ -37,116 +45,128 @@
        /// <returns></returns>
        public async Task<ApiAction<SubmitOutput>> Submit(SubmitInput input)
        {
            var action = new ApiAction<SubmitOutput>();
            var action = new ApiAction<SubmitOutput>(new SubmitOutput());
            try
            {
                //工步列表为空或者工序节点工步有未完成时,优先完成工序节点工步
                if (Steps.IsNullOrEmpty() || !IsFinishNodeSteps)
                //PkgSubmit:手动结束包装,手动保存暂存的包装数据
                if (NodeCmd == "PkgSubmit")
                {
                   //先判断当前工单不为空且当前岗位在当前工单是不是首站,如果是则不允许变更当前工单,尝试把条码绑定到当前工单
                   if (!CurBatch.IsNullOrEmpty() && CurBatch.IsFirstNode(PostCode))
                   {
                       action = NodeSubmit(action, input);
                       return action;
                   }
                   //当前岗位在当前工单不是首站,则查找条码已绑定的工单当作当前工单
                   else
                   {
                       var wosn = Biz.Db.Queryable<BIZ_MES_WO_BATCH, BIZ_MES_WO_SN>((b, s) => new JoinQueryInfos(JoinType.Inner, b.ORDER_NO == s.WORK_ORDER)).ByAuth(input.AuthOption)
                                                   .Where((b, s) => s.SN == input.SN && b.ACT_LINE == CurLine.LINE_CODE && (b.STATUS == BIZ_MES_WO_BATCH.STATUSs.Release.GetValue() || b.STATUS == BIZ_MES_WO_BATCH.STATUSs.Working.GetValue()))
                                                   .Select((b, s) => new { Batch = b, SN = s }).First();
                       //查找到条码已绑定的工单
                       if (!wosn.IsNullOrEmpty())
                       {
                           if (CurBatch?.Batch?.ORDER_NO != wosn.Batch.ORDER_NO)
                           {
                               //条码已绑定的工单不等于当前工单则重新选择工单
                               var result = await SelectOrder(new() { AuthOption = input.AuthOption, OrderNo = wosn.Batch.ORDER_NO });
                               if (!result.IsSuccessed)
                               {
                                   action.IsSuccessed = result.IsSuccessed;
                                    action.LocaleMsg = result.LocaleMsg;
                                    return action;
                               }
                           }
                           //条码过站
                           action = NodeSubmit(action, input);
                           return action;
                       }
                       //查找不到条码已绑定的工单
                       else
                       {
                           //没有当前工单,则先选择工单后再扫描条码
                           if (CurBatch.IsNullOrEmpty())
                           {
                               action.IsSuccessed = false;
                               //action.LocaleMsg = new($"未选择工单,请先选择要生产的工单");
                               action.LocaleMsg = new("MES.Transaction.PackingNode.Submit.NotSelectOrderException");
                               return action;
                           }
                           //有当前工单且不是投入,则提示条码未投入生产,请先去首站扫描
                           else
                           {
                               action.IsSuccessed = false;
                               //action.LocaleMsg = new($"条码[{input.SN}]尚未投入生产,请先去首站扫描", input.SN);
                               action.LocaleMsg = new("MES.Transaction.PackingNode.Submit.NotInputException", input.SN);
                               return action;
                           }
                       }
                   }
                }
                //完成工序节点工步后,后开始执行当前工序的行为工步
                else if(IsFinishNodeSteps && !IsFinishAllSteps)
                {
                    var submitStep = Steps.Where(q => q.ID == input.CurStepID && !q.IsFinished).FirstOrDefault();
                    if (submitStep.IsNullOrEmpty())
                    action = TempPkgAction.Submit(input);
                    //如果行为被标记成已完成,则重置工序
                    if (TempPkgAction.IsFinished)
                    {
                        action = BeginNextActionStep(input);
                        return action;
                        ResetNode();
                    }
                    else
                    return action;
                }
                //NodeSubmit:产品过站,正常产品过站逻辑
                else
                {
                    NodeCmd = "NodeSubmit";
                    //工步列表为空或者工序节点工步有未完成时,优先完成工序节点工步
                    if (Steps.IsNullOrEmpty() || !IsFinishNodeSteps)
                    {
                        var result = submitStep.Submit(input);
                        //如果当前工步已完成,开始执行下一工步
                        if (result.IsSuccessed && submitStep.IsFinished)
                        //先判断当前工单不为空且当前岗位在当前工单是不是首站,如果是则不允许变更当前工单,尝试把条码绑定到当前工单
                        if (!CurBatch.IsNullOrEmpty() && CurBatch.IsFirstNode(PostCode))
                        {
                            result = BeginNextActionStep(input);
                            action = NodeSubmit(action, input);
                            return action;
                        }
                        //如果当前工步未完成
                        //当前岗位在当前工单不是首站,则查找条码已绑定的工单当作当前工单
                        else
                        {
                            //行为执行出错,工步被重置
                            if (Steps.IsNullOrEmpty())
                            var wosn = Biz.Db.Queryable<BIZ_MES_WO_BATCH, BIZ_MES_WO_SN>((q, s) => new JoinQueryInfos(JoinType.Inner, q.ORDER_NO == s.WORK_ORDER))
                                                        .ByAuth(input.AuthOption)
                                                        .Where((q, s) => s.SN == input.SN && q.ACT_LINE == CurLine.LINE_CODE && (q.STATUS == BIZ_MES_WO_BATCH.STATUSs.Release.GetValue() || q.STATUS == BIZ_MES_WO_BATCH.STATUSs.Working.GetValue()))
                                                        .Select((q, s) => new { Batch = q, SN = s }).First();
                            //查找到条码已绑定的工单
                            if (!wosn.IsNullOrEmpty())
                            {
                                result.LocaleMsg = new(Biz.T(result.LocaleMsg, input.Locale) + Biz.T(Biz.L("MES.Transaction.Position.RescanSN"), input.Locale));
                                if (CurBatch?.Batch?.ORDER_NO != wosn.Batch.ORDER_NO)
                                {
                                    //条码已绑定的工单不等于当前工单则重新选择工单
                                    var result = await SelectOrder(new() { AuthOption = input.AuthOption, OrderNo = wosn.Batch.ORDER_NO });
                                    if (!result.IsSuccessed)
                                    {
                                        action.IsSuccessed = result.IsSuccessed;
                                        action.LocaleMsg = result.LocaleMsg;
                                        return action;
                                    }
                                }
                                //条码过站
                                action = NodeSubmit(action, input);
                                return action;
                            }
                            //查找不到条码已绑定的工单
                            else
                            {
                                result.Data.IsFinished = IsFinishAllSteps;
                                result.Data.CurWO = CurBatch.WO.ORDER_NO;
                                result.Data.CurBatch = CurBatch.Batch.BATCH_NO;
                                result.Data.CurNode = CurStep.NodeAct.ACT_NAME;
                                result.Data.StepActCode = CurStep.NodeAct.ACT_CODE;
                                result.Data.NextStepID = CurStep.ID;
                                //没有当前工单,则先选择工单后再扫描条码
                                if (CurBatch.IsNullOrEmpty())
                                {
                                    action.IsSuccessed = false;
                                    //action.LocaleMsg = new($"未选择工单,请先选择要生产的工单");
                                    action.LocaleMsg = new("MES.Transaction.PackingNode.Submit.NotSelectOrderException");
                                    return action;
                                }
                                //有当前工单且不是投入,则提示条码未投入生产,请先去首站扫描
                                else
                                {
                                    action.IsSuccessed = false;
                                    //action.LocaleMsg = new($"条码[{input.SN}]尚未投入生产,请先去首站扫描", input.SN);
                                    action.LocaleMsg = new("MES.Transaction.PackingNode.Submit.NotInputException", input.SN);
                                    return action;
                                }
                            }
                        }
                        //如果所有工步都完成
                        if (IsFinishAllSteps)
                        {
                            return DoIfFinishAllSteps(result);
                        }
                        return result;
                    }
                    //完成工序节点工步后,后开始执行当前工序的行为工步
                    else if (IsFinishNodeSteps && !IsFinishAllSteps)
                    {
                        var submitStep = Steps.Where(q => q.ID == input.CurStepID && !q.IsFinished).FirstOrDefault();
                        if (submitStep.IsNullOrEmpty())
                        {
                            action = BeginNextActionStep(input);
                            return action;
                        }
                        else
                        {
                            var result = submitStep.Submit(input);
                            //如果当前工步已完成,开始执行下一工步
                            if (result.IsSuccessed && submitStep.IsFinished)
                            {
                                result = BeginNextActionStep(input);
                            }
                            //如果当前工步未完成
                            else
                            {
                                //行为执行出错,工步被重置
                                if (Steps.IsNullOrEmpty())
                                {
                                    result.LocaleMsg = new(Biz.T(result.LocaleMsg, input.Locale) + Biz.T(Biz.L("MES.Transaction.Position.RescanSN"), input.Locale));
                                }
                                else
                                {
                                    result.Data.SetValue(CurBatch, CurStep, CurStep?.ID, IsFinishAllSteps);
                                }
                            }
                            //如果所有工步都完成
                            if (IsFinishAllSteps)
                            {
                                return DoIfFinishAllSteps(result);
                            }
                            return result;
                        }
                    }
                    //没有可执行的工步
                    ResetNode();
                    action.IsSuccessed = false;
                    //action.LocaleMsg = new($"岗位[{CurPosition.POST_CODE}]工步执行异常,请重新扫描产品条码", CurPosition.POST_CODE);
                    action.LocaleMsg = new("MES.Transaction.PackingNode.Submit.WorkStepException", CurPosition.POST_CODE);
                }
                //没有可执行的工步
                ResetSteps();
                action.IsSuccessed = false;
                //action.LocaleMsg = new($"岗位[{CurPosition.POST_CODE}]工步执行异常,请重新扫描产品条码", CurPosition.POST_CODE);
                action.LocaleMsg = new("MES.Transaction.PackingNode.Submit.WorkStepException", CurPosition.POST_CODE);
            }
            catch (Exception ex)
            {
                action.CatchExceptionWithLog(ex, $"包装工序:扫描产品条码异常");
                action.CatchExceptionWithLog(ex, $"包装工序:提交操作数据异常");
            }
            return action;
        }
@@ -169,7 +189,7 @@
                    return woStatus;
                }
                //非法过站防呆:进入工序时要增加判断条码是否按流程过站
                var wipSN = Biz.Db.Queryable<MES_WIP_DATA>().Where(q => q.SN == input.SN && q.WORK_ORDER == CurBatch.WO.ORDER_NO).IncludesAllFirstLayer().First() ?? new MES_WIP_DATA()
                var wipSN = Biz.Db.Queryable<MES_WIP_DATA>().IncludesAllFirstLayer().First(q => q.SN == input.SN && q.WORK_ORDER == CurBatch.WO.ORDER_NO) ?? new MES_WIP_DATA()
                {
                    SN = input.SN,
                    STATUS = MES_WIP_DATA.STATUSs.Init.GetValue(),
@@ -188,15 +208,6 @@
                {
                    return canGotoNext;
                }
                //if (nextNodes.Any(q => q.ID == curNode.ID))
                //{
                //    action.IsSuccessed = false;
                //    action.Data.CurWO = CurBatch.WO.ORDER_NO;
                //    action.Data.CurBatch = CurBatch.Batch.BATCH_NO;
                //    action.LocaleMsg = new($"条码[{wipSN.SN}]过站扫描错误,请先通过以下工序:{string.Join(", ", nextNodes.Select(q => q.NODE_NAME))}");
                //    action.LocaleMsg = new("MES.Transaction.PackingNode.NotNextNodeException", wipSN.SN, string.Join(", ", nextNodes.Select(q => q.NODE_NAME)));
                //    return action;
                //}
                //当工步列表为空,则执行当前工序的必要逻辑当作第一个工序节点,完成后按需求创建后续的工步列表
                if (Steps.IsNullOrEmpty())
@@ -268,7 +279,6 @@
                   Steps.Clear();
                   var curStep = new Biz.WorkStep(IWorkStep.Types.Node, this) 
                    {
                       NodeID = curNode.ID,
                       Sequence = Steps.Count + 1,
                       Node = curNode,
                       DBSubmitAction = () =>
@@ -281,7 +291,7 @@
                   };
                   Steps.Add(curStep);
   
                   //有需要则添加工序节点的其他工步
                   //有需要用户提交信息则添加工序节点的其他工步
   
                   //最后添加当前工序的行为工步
                   GenerateSteps(curStep);
@@ -302,7 +312,7 @@
                //未完成所有工步
                if (!IsFinishAllSteps)
                {
                    var result = new ApiAction<SubmitOutput>();
                    var result = new ApiAction<SubmitOutput>(new SubmitOutput());
                    //未完成所有工序节点工步
                    if (!IsFinishNodeSteps)
                    {
@@ -311,18 +321,14 @@
                        NextSteps.Clear();
                        NextSteps.Add(next);
                        //根据后续工步返回ApiAction
                        result.Data.IsFinished = IsFinishAllSteps;
                        result.Data.CurWO = CurBatch.WO.ORDER_NO;
                        result.Data.CurBatch = CurBatch.Batch.BATCH_NO;
                        result.Data.CurNode = CurStep.Node.NODE_NAME;
                        result.Data.NextStepID = next.ID;
                        result.Data.SetValue(CurBatch, CurStep, next.ID, IsFinishAllSteps);
                        //根据工序节点工步的序号返回相应的操作提示
                        switch (next.Sequence)
                        {
                            case 2:
                                //action.LocaleMsg = new($"请执行第二步");
                                result.LocaleMsg = new("MES.Transaction.PackingNode.第二步操作提示");
                                result.LocaleMsg = new("MES.Transaction.CollectNode.第二步操作提示");
                                break;
                            default:
                                break;
@@ -338,18 +344,14 @@
                //已完成所有工步
                else
                {
                    action.Data.IsFinished = IsFinishAllSteps;
                    action.Data.CurWO = CurBatch.WO.ORDER_NO;
                    action.Data.CurBatch = CurBatch.Batch.BATCH_NO;
                    action.Data.CurNode = CurStep.Node.NODE_NAME;
                    action.Data.NextStepID = "";
                    action.Data.SetValue(CurBatch, CurStep, "", IsFinishAllSteps);
                    action = DoIfFinishAllSteps(action);
                }
            }
            catch (Exception ex)
            {
                ResetSteps();
                action.CatchExceptionWithLog(ex, $"包装工序:扫描产品条码异常");
                ResetNode();
                action.CatchExceptionWithLog(ex, $"包装工序:工序节点工步提交数据异常");
            }
            return action;
        }
@@ -377,11 +379,71 @@
            //保存成功,返回过站消息
            //action.LocaleMsg = new($"工单[{CurWipSN.WORK_ORDER}]的条码[{CurWipSN.SN}]在岗位[{CurWipSN.POST_CODE}]工序[{CurWipSN.NODE_NAME}]过站成功,状态[{CurWipSN.STATUS.GetEnumDesc<MES_WIP_DATA.STATUSs>()}]", CurWipSN.WORK_ORDER, CurWipSN.SN, CurWipSN.POST_CODE, CurWipSN.NODE_NAME, CurWipSN.STATUS.GetEnumDesc<MES_WIP_DATA.STATUSs>());
            action.LocaleMsg = new("MES.Transaction.PackingNode.ScanSn.PassSuccess", CurWipSN.WORK_ORDER, CurWipSN.SN, CurWipSN.POST_CODE, CurWipSN.NODE_NAME, CurWipSN.STATUS.GetEnumDesc<MES_WIP_DATA.STATUSs>());
            //重置工序
            ResetNode();
            return action;
        }
        /// <summary>
        /// 包装工序:手动结束包装
        /// </summary>
        /// <returns></returns>
        public async Task<ApiAction<SubmitOutput>> CompletePkg()
        {
            var action = new ApiAction<SubmitOutput>(new SubmitOutput());
            try
            {
                //PkgSubmit:手动结束包装,保存暂存的包装数据
                if (NodeCmd.IsNullOrEmpty("PkgSubmit") == "PkgSubmit")
                {
                    if (Context.ContainsKey("CurPackage"))
                    {
                        NodeCmd = "PkgSubmit";
                        TempPkgAction = new PackingAction();
                        TempPkgAction.Init(null, this, null, null);
                        action = TempPkgAction.Submit(null);
                    }
                    else
                    {
                        action.IsSuccessed = false;
                        //action.LocaleMsg = new($"找不到暂存的包装数据,无需手动结束包装");
                        action.LocaleMsg = new("MES.Transaction.PackingNode.NoCurPackage");
                    }
                }
                //工序处于其他命令模式,不允许手动结束包装
                else
                {
                    switch (NodeCmd)
                    {
                        case "NodeSubmit":
                            action.IsSuccessed = false;
                            //action.LocaleMsg = new($"正在进行条码[{CurWipSN.SN}]的过站业务,不允许手动结束包装");
                            action.LocaleMsg = new("MES.Transaction.PackingNode.WorkingOnNodeSubmit", CurWipSN.SN);
                            break;
                        default:
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                action.CatchExceptionWithLog(ex, $"包装工序:手动结束包装异常");
            }
            return action;
        }
        #endregion Functions
        /// <summary>
        /// 重置当前工步,有需要则重写此方法
        /// </summary>
        public override void ResetNode()
        {
            base.ResetNode();
            NodeCmd = null;
        }
        public override bool Close(bool needSaveHistoryLog = false)
        {
            //needSaveHistoryLog = true;