服务端的TigerApi 框架,基于.NET6 2024 版本
Rodney Chen
2024-07-19 01a5cb6f77739630a88fc2f95be694b53ade0d41
工步修改为支持并行执行行为,优化工步执行逻辑
已修改18个文件
1570 ■■■■■ 文件已修改
Tiger.Api/Language.db 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Business.MES/Transaction/CollectNode.cs 304 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Business.MES/Transaction/PackingNode.cs 314 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Business.MES/Transaction/Position.cs 160 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Business.MES/Transaction/TestNode.cs 302 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Business.MES/WorkAction/IPQC.cs 108 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Business.MES/WorkAction/PrintLabel.cs 43 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Business/Language/Biz.Language.cs 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Business/MES/Biz.WorkStep.cs 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.IBusiness/MES/IWorkAction.cs 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.IBusiness/MES/IWorkStep.cs 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.IBusiness/MES/Transaction/ICollectNode.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.IBusiness/MES/Transaction/IPackingNode.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.IBusiness/MES/Transaction/IPosition.cs 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.IBusiness/MES/Transaction/ITestNode.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Model.Net/Entitys/MES/MES_ROUTE_NODE_ACT.cs 194 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Model.Net/Entitys/MES/MES_WO_NODE_ACT.cs 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Model.Net/Entitys/MES/ParameterEntity/PositionParameter.cs 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Api/Language.db
Binary files differ
Tiger.Business.MES/Transaction/CollectNode.cs
@@ -35,18 +35,18 @@
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<ApiAction> Submit(SubmitInput input)
        public async Task<ApiAction<SubmitOutput>> Submit(SubmitInput input)
        {
            var action = new ApiAction();
            var action = new ApiAction<SubmitOutput>();
            try
            {
                //工步列表为空时,认为需要先扫描过站条码
                if (Steps.IsNullOrEmpty())
                //工步列表为空或者工序节点工步有未完成时,优先完成工序节点工步
                if (Steps.IsNullOrEmpty() || !IsFinishNodeSteps)
                {
                    //先判断当前工单不为空且当前岗位在当前工单是不是首站,如果是则不允许变更当前工单,尝试把条码绑定到当前工单
                    if (!CurBatch.IsNullOrEmpty() && CurBatch.IsFirstNode(PostCode))
                    {
                        action = ScanSn(action, input);
                        action = NodeSubmit(action, input);
                        return action;
                    }
                    //当前岗位在当前工单不是首站,则查找条码已绑定的工单当作当前工单
@@ -64,12 +64,13 @@
                                var result = await SelectOrder(new() { AuthOption = input.AuthOption, OrderNo = wosn.Batch.ORDER_NO });
                                if (!result.IsSuccessed)
                                {
                                    action = result;
                                    action.IsSuccessed = result.IsSuccessed;
                                    action.LocaleMsg = result.LocaleMsg;
                                    return action;
                                }
                            }
                            //条码过站
                            action = ScanSn(action, input);
                            action = NodeSubmit(action, input);
                            return action;
                        }
                        //查找不到条码已绑定的工单
@@ -94,22 +95,47 @@
                        }
                    }
                }
                //完成第一步,后开始执行当前工序的行为列表
                else if (Steps.First().IsFinished && !IsFinishAllSteps)
                //完成工序节点工步后,后开始执行当前工序的行为工步
                else if (IsFinishNodeSteps && !IsFinishAllSteps)
                {
                    //var curStep = Steps.Where(q => !q.IsFinished).OrderBy(q => q.Sequence).First();
                    var curStep = Steps.Where(q => q.ID == input.StepID).FirstOrDefault();
                    if (!curStep.IsNullOrEmpty())
                    var submitStep = Steps.Where(q => q.ID == input.CurStepID && !q.IsFinished).FirstOrDefault();
                    if (submitStep.IsNullOrEmpty())
                    {
                        var result = curStep.Submit(input);
                        result.Data.StepID = curStep.ID;
                        result.Data.IsFinished = IsFinishAllSteps;
                        result.Data.CurStep = CurStep;
                        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.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 (IsFinishAllSteps)
                        {
                            return DoIfFinishAllSteps(result.ToApiAction());
                            return DoIfFinishAllSteps(result);
                        }
                        return result.ToApiAction();
                        return result;
                    }
                }
                //没有可执行的工步
@@ -126,130 +152,168 @@
        }
        /// <summary>
        /// 扫描过站条码
        /// 工序节点工步提交数据
        /// </summary>
        /// <param name="action"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        public ApiAction ScanSn(ApiAction action, SubmitInput input)
        public ApiAction<SubmitOutput> NodeSubmit(ApiAction<SubmitOutput> action, SubmitInput input)
        {
            try
            {
                //绑定条码到工单
                if (!CurBatch.WoSNs.Any(q => q.SN == input.SN))
                //当工步列表为空,则执行当前工序的必要逻辑当作第一个工序节点,完成后按需求创建后续的工步列表
                if (Steps.IsNullOrEmpty())
                {
                    CurBatch.WoSNs.Add(new()
                    //绑定条码到工单
                    if (!CurBatch.WoSNs.Any(q => q.SN == input.SN))
                    {
                        WORK_ORDER = CurBatch.Batch.ORDER_NO,
                        SN = input.SN,
                        STATUS = BIZ_MES_WO_SN.STATUSs.NotInput.GetValue(),
                        BATCH_NO = CurBatch.Batch.BATCH_NO,
                    });
                }
                var woSN = CurBatch.WoSNs.FirstOrDefault(q => q.SN == input.SN);
                var curNode = CurBatch.GetNode(PostCode);
                //条码过站
                var wipSN = Biz.Db.Queryable<MES_WIP_DATA>().First(q => q.SN == input.SN && q.BATCH_NO == CurBatch.Batch.BATCH_NO) ?? new MES_WIP_DATA()
                {
                    SN = input.SN,
                    STATUS = MES_WIP_DATA.STATUSs.Init.GetValue(),
                    ITEM_CODE = CurBatch.WO.ITEM_CODE,
                    WORK_ORDER = CurBatch.Batch.ORDER_NO,
                    BATCH_NO = CurBatch.Batch.BATCH_NO,
                    HOLD_FLAG = "N",
                    REWORK_FLAG = CurBatch.WO.ORDER_TYPE == BIZ_MES_WO.ORDER_TYPEs.Rework.GetValue() ? "Y" : "N",
                    FINISHED_FLAG = "N",
                    INV_FLAG = "N",
                    DFT_FLAG = "N",
                    DFT_COUNT = 0,
                };
                wipSN.AUTH_PROD = CurLine.LINE_CODE;
                wipSN.STATUS = wipSN.STATUS > 0 ? MES_WIP_DATA.STATUSs.OK.GetValue() : wipSN.STATUS;
                wipSN.ROT_CODE = CurBatch.WO.ROUTE_CODE;
                wipSN.NODE_ID = curNode.ID;
                wipSN.NODE_NAME = curNode.NODE_NAME;
                wipSN.FTY_CODE = CurFactory.FTY_CODE;
                wipSN.WS_CODE = CurWorkshop.WS_CODE;
                wipSN.LINE_CODE = CurLine.LINE_CODE;
                wipSN.POST_CODE = CurPosition.POST_CODE;
                wipSN.OPER_CODE = curNode.OPER_CODE;
                wipSN.SEGMENT = curNode.SEGMENT;
                wipSN.OPERATION_TIME = DateTime.Now;
                wipSN.SFTS_CODE = CurLine.SFTS_CODE;
                //wipSN.SFT_CODE = CurBatch.WO.ROUTE_CODE;
                //wipSN.PRD_CODE = CurBatch.WO.ROUTE_CODE;
                CurBatch.StartWorking(UserCode);
                //如果是投入站
                if (curNode.IS_INPUT == "Y")
                {
                    woSN.STATUS = BIZ_MES_WO_SN.STATUSs.Inputed.GetValue();
                    wipSN.STATUS = MES_WIP_DATA.STATUSs.Input.GetValue();
                    wipSN.INLINE_DATE = DateTime.Now;
                }
                //如果是产出站
                if (curNode.IS_OUTPUT == "Y")
                {
                    woSN.STATUS = BIZ_MES_WO_SN.STATUSs.Finished.GetValue();
                    wipSN.STATUS = MES_WIP_DATA.STATUSs.Finished.GetValue();
                    wipSN.OUTLINE_DATE = DateTime.Now;
                }
                //如果有提交不良
                if (!input.DFT_CODE.IsNullOrEmpty())
                {
                    wipSN.STATUS = MES_WIP_DATA.STATUSs.NG.GetValue();
                    wipSN.DFT_FLAG = "Y";
                    wipSN.DFT_COUNT++;
                    wipSN.DFT_CODE = input.DFT_CODE;
                }
                CurWipSNHis = new MES_WIP_HIS(CurWipSN = wipSN, $"工单[{wipSN.WORK_ORDER}]条码[{wipSN.SN}]在岗位[{wipSN.POST_CODE}]过站工序[{wipSN.NODE_NAME}]成功");
                //初始化工步列表
                Steps.Clear();
                var curStep = new Biz.WorkStep(curNode.ID, IWorkStep.Types.Node)
                {
                    Sequence = Steps.Count + 1,
                    Node = curNode,
                    DBSubmitAction = () =>
                    {
                        var db = GetCommitDB();
                        db.Storageable(woSN, UserCode).ExecuteCommand();
                        db.Storageable(wipSN, UserCode).ExecuteCommand();
                        db.Storageable(CurWipSNHis, UserCode).ExecuteCommand();
                        CurBatch.WoSNs.Add(new()
                        {
                            WORK_ORDER = CurBatch.Batch.ORDER_NO,
                            SN = input.SN,
                            STATUS = BIZ_MES_WO_SN.STATUSs.NotInput.GetValue(),
                            BATCH_NO = CurBatch.Batch.BATCH_NO,
                        });
                    }
                };
                Steps.Add(curStep);
                    var woSN = CurBatch.WoSNs.FirstOrDefault(q => q.SN == input.SN);
                    var curNode = CurBatch.GetNode(PostCode);
                //如果当前工序节点有行为则添加到工步列表
                var acts = CurBatch.NodeActs.Where(q => q.NODE_ID == curNode.ID).ToList();
                foreach (var act in acts)
                {
                    Steps.Add(new Biz.WorkStep(act.ID, IWorkStep.Types.Action)
                    //条码过站
                    var wipSN = Biz.Db.Queryable<MES_WIP_DATA>().First(q => q.SN == input.SN && q.BATCH_NO == CurBatch.Batch.BATCH_NO) ?? new MES_WIP_DATA()
                    {
                        SN = input.SN,
                        STATUS = MES_WIP_DATA.STATUSs.Init.GetValue(),
                        ITEM_CODE = CurBatch.WO.ITEM_CODE,
                        WORK_ORDER = CurBatch.Batch.ORDER_NO,
                        BATCH_NO = CurBatch.Batch.BATCH_NO,
                        HOLD_FLAG = "N",
                        REWORK_FLAG = CurBatch.WO.ORDER_TYPE == BIZ_MES_WO.ORDER_TYPEs.Rework.GetValue() ? "Y" : "N",
                        FINISHED_FLAG = "N",
                        INV_FLAG = "N",
                        DFT_FLAG = "N",
                        DFT_COUNT = 0,
                    };
                    wipSN.AUTH_PROD = CurLine.LINE_CODE;
                    wipSN.STATUS = wipSN.STATUS > 0 ? MES_WIP_DATA.STATUSs.OK.GetValue() : wipSN.STATUS;
                    wipSN.ROT_CODE = CurBatch.WO.ROUTE_CODE;
                    wipSN.NODE_ID = curNode.ID;
                    wipSN.NODE_NAME = curNode.NODE_NAME;
                    wipSN.FTY_CODE = CurFactory.FTY_CODE;
                    wipSN.WS_CODE = CurWorkshop.WS_CODE;
                    wipSN.LINE_CODE = CurLine.LINE_CODE;
                    wipSN.POST_CODE = CurPosition.POST_CODE;
                    wipSN.OPER_CODE = curNode.OPER_CODE;
                    wipSN.SEGMENT = curNode.SEGMENT;
                    wipSN.OPERATION_TIME = DateTime.Now;
                    wipSN.SFTS_CODE = CurLine.SFTS_CODE;
                    //wipSN.SFT_CODE = CurBatch.WO.ROUTE_CODE;
                    //wipSN.PRD_CODE = CurBatch.WO.ROUTE_CODE;
                    CurBatch.StartWorking(UserCode);
                    //如果是投入站
                    if (curNode.IS_INPUT == "Y")
                    {
                        woSN.STATUS = BIZ_MES_WO_SN.STATUSs.Inputed.GetValue();
                        wipSN.STATUS = MES_WIP_DATA.STATUSs.Input.GetValue();
                        wipSN.INLINE_DATE = DateTime.Now;
                    }
                    //如果是产出站
                    if (curNode.IS_OUTPUT == "Y")
                    {
                        woSN.STATUS = BIZ_MES_WO_SN.STATUSs.Finished.GetValue();
                        wipSN.STATUS = MES_WIP_DATA.STATUSs.Finished.GetValue();
                        wipSN.OUTLINE_DATE = DateTime.Now;
                    }
                    //如果有提交不良
                    if (!input.DFT_CODE.IsNullOrEmpty())
                    {
                        wipSN.STATUS = MES_WIP_DATA.STATUSs.NG.GetValue();
                        wipSN.DFT_FLAG = "Y";
                        wipSN.DFT_COUNT++;
                        wipSN.DFT_CODE = input.DFT_CODE;
                    }
                    CurWipSNHis = new MES_WIP_HIS(CurWipSN = wipSN, $"工单[{wipSN.WORK_ORDER}]条码[{wipSN.SN}]在岗位[{wipSN.POST_CODE}]过站工序[{wipSN.NODE_NAME}]成功");
                    //初始化工步列表
                    Steps.Clear();
                    var curStep = new Biz.WorkStep(IWorkStep.Types.Node, this)
                    {
                        NodeID = curNode.ID,
                        Sequence = Steps.Count + 1,
                        Node = curNode,
                        NodeAct = act,
                        Setting = CurBatch.ActionSets.FirstOrDefault(q => q.ACT_ID == act.ID),
                    });
                        DBSubmitAction = () =>
                        {
                            var db = GetCommitDB();
                            db.Storageable(woSN, UserCode).ExecuteCommand();
                            db.Storageable(wipSN, UserCode).ExecuteCommand();
                            db.Storageable(CurWipSNHis, UserCode).ExecuteCommand();
                        }
                    };
                    Steps.Add(curStep);
                    //有需要则添加工序节点的其他工步
                    //最后添加当前工序的行为工步
                    GenerateSteps(curStep);
                    //完成第一个工序节点工步
                    curStep.IsFinished = true;
                    CurStep = curStep;
                }
                else if (!IsFinishNodeSteps)
                {
                    var curStep = Steps.Where(q => q.Type == IWorkStep.Types.Node && !q.IsFinished).OrderBy(q => q.Sequence).First();
                    //完成当前工序节点工步
                    curStep.IsFinished = true;
                    CurStep = curStep;
                }
                //完成当前工序节点
                curStep.IsFinished = true;
                //未完成所有工步
                if (!IsFinishAllSteps)
                {
                    var next = Steps.Where(q => !q.IsFinished).OrderBy(q => q.Sequence).First();
                    var result = next.Begin(this);
                    result.Data.StepID = next.ID;
                    result.Data.IsFinished = IsFinishAllSteps;
                    result.Data.CurStep = CurStep;
                    return result.ToApiAction();
                    var result = new ApiAction<SubmitOutput>();
                    //未完成所有工序节点工步
                    if (!IsFinishNodeSteps)
                    {
                        var next = Steps.Where(q => q.Type == IWorkStep.Types.Node && !q.IsFinished).OrderBy(q => q.Sequence).First();
                        //设置后续可执行的工步列表
                        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;
                        //根据工序节点工步的序号返回相应的操作提示
                        switch (next.Sequence)
                        {
                            case 2:
                                //action.LocaleMsg = new($"请执行第二步");
                                result.LocaleMsg = new("MES.Transaction.CollectNode.第二步操作提示");
                                break;
                            default:
                                break;
                        }
                    }
                    //已完成所有工序节点工步,开始执行行为工步
                    else
                    {
                        result = BeginNextActionStep(input);
                    }
                    return result;
                }
                //已完成所有工步
                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 = DoIfFinishAllSteps(action);
                }
            }
@@ -266,7 +330,7 @@
        /// </summary>
        /// <param name="action"></param>
        /// <returns></returns>
        public ApiAction DoIfFinishAllSteps(ApiAction action)
        public ApiAction<SubmitOutput> DoIfFinishAllSteps(ApiAction<SubmitOutput> action)
        {
            //保存数据库
            var dbTran = GetCommitDB().UseTran(() =>
Tiger.Business.MES/Transaction/PackingNode.cs
@@ -35,18 +35,18 @@
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<ApiAction> Submit(SubmitInput input)
        public async Task<ApiAction<SubmitOutput>> Submit(SubmitInput input)
        {
            var action = new ApiAction();
            var action = new ApiAction<SubmitOutput>();
            try
            {
                //工步列表为空时,认为需要先扫描过站条码
                if (Steps.IsNullOrEmpty())
                //工步列表为空或者工序节点工步有未完成时,优先完成工序节点工步
                if (Steps.IsNullOrEmpty() || !IsFinishNodeSteps)
                {
                    //先判断当前工单不为空且当前岗位在当前工单是不是首站,如果是则不允许变更当前工单,尝试把条码绑定到当前工单
                    if (!CurBatch.IsNullOrEmpty() && CurBatch.IsFirstNode(PostCode))
                    {
                        action = ScanSn(action, input);
                        action = NodeSubmit(action, input);
                        return action;
                    }
                    //当前岗位在当前工单不是首站,则查找条码已绑定的工单当作当前工单
@@ -64,12 +64,13 @@
                                var result = await SelectOrder(new() { AuthOption = input.AuthOption, OrderNo = wosn.Batch.ORDER_NO });
                                if (!result.IsSuccessed)
                                {
                                    action = result;
                                    return action;
                                    action.IsSuccessed = result.IsSuccessed;
                                    action.LocaleMsg = result.LocaleMsg;
                                    return action;
                                }
                            }
                            //条码过站
                            action = ScanSn(action, input);
                            action = NodeSubmit(action, input);
                            return action;
                        }
                        //查找不到条码已绑定的工单
@@ -94,22 +95,47 @@
                        }
                    }
                }
                //完成第一步,后开始执行当前工序的行为列表
                else if(Steps.First().IsFinished && !IsFinishAllSteps)
                //完成工序节点工步后,后开始执行当前工序的行为工步
                else if(IsFinishNodeSteps && !IsFinishAllSteps)
                {
                    //var curStep = Steps.Where(q => !q.IsFinished).OrderBy(q => q.Sequence).First();
                    var curStep = Steps.Where(q => q.ID == input.StepID).FirstOrDefault();
                    if (!curStep.IsNullOrEmpty())
                    var submitStep = Steps.Where(q => q.ID == input.CurStepID && !q.IsFinished).FirstOrDefault();
                    if (submitStep.IsNullOrEmpty())
                    {
                        var result = curStep.Submit(input);
                        result.Data.StepID = curStep.ID;
                        result.Data.IsFinished = IsFinishAllSteps;
                        result.Data.CurStep = CurStep;
                        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.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 (IsFinishAllSteps)
                        {
                            return DoIfFinishAllSteps(result.ToApiAction());
                            return DoIfFinishAllSteps(result);
                        }
                        return result.ToApiAction();
                        return result;
                    }
                }
                //没有可执行的工步
@@ -126,129 +152,168 @@
        }
        /// <summary>
        /// 扫描过站条码
        /// 工序节点工步提交数据
        /// </summary>
        /// <param name="action"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        public ApiAction ScanSn(ApiAction action, SubmitInput input)
        public ApiAction<SubmitOutput> NodeSubmit(ApiAction<SubmitOutput> action, SubmitInput input)
        {
            try
            {
                //绑定条码到工单
                if (!CurBatch.WoSNs.Any(q => q.SN == input.SN))
                //当工步列表为空,则执行当前工序的必要逻辑当作第一个工序节点,完成后按需求创建后续的工步列表
                if (Steps.IsNullOrEmpty())
                {
                    CurBatch.WoSNs.Add(new()
                    //绑定条码到工单
                    if (!CurBatch.WoSNs.Any(q => q.SN == input.SN))
                    {
                        CurBatch.WoSNs.Add(new()
                        {
                            WORK_ORDER = CurBatch.Batch.ORDER_NO,
                            SN = input.SN,
                            STATUS = BIZ_MES_WO_SN.STATUSs.NotInput.GetValue(),
                            BATCH_NO = CurBatch.Batch.BATCH_NO,
                        });
                    }
                    var woSN = CurBatch.WoSNs.FirstOrDefault(q => q.SN == input.SN);
                    var curNode = CurBatch.GetNode(PostCode);
                    //条码过站
                    var wipSN = Biz.Db.Queryable<MES_WIP_DATA>().First(q => q.SN == input.SN && q.BATCH_NO == CurBatch.Batch.BATCH_NO) ?? new MES_WIP_DATA()
                    {
                        SN = input.SN,
                        STATUS = MES_WIP_DATA.STATUSs.Init.GetValue(),
                        ITEM_CODE = CurBatch.WO.ITEM_CODE,
                        WORK_ORDER = CurBatch.Batch.ORDER_NO,
                        BATCH_NO = CurBatch.Batch.BATCH_NO,
                        HOLD_FLAG = "N",
                        REWORK_FLAG = CurBatch.WO.ORDER_TYPE == BIZ_MES_WO.ORDER_TYPEs.Rework.GetValue() ? "Y" : "N",
                        FINISHED_FLAG = "N",
                        INV_FLAG = "N",
                        DFT_FLAG = "N",
                        DFT_COUNT = 0,
                    };
                    wipSN.AUTH_PROD = CurLine.LINE_CODE;
                    wipSN.STATUS = wipSN.STATUS > 0 ? MES_WIP_DATA.STATUSs.OK.GetValue() : wipSN.STATUS;
                    wipSN.ROT_CODE = CurBatch.WO.ROUTE_CODE;
                    wipSN.NODE_ID = curNode.ID;
                    wipSN.NODE_NAME = curNode.NODE_NAME;
                    wipSN.FTY_CODE = CurFactory.FTY_CODE;
                    wipSN.WS_CODE = CurWorkshop.WS_CODE;
                    wipSN.LINE_CODE = CurLine.LINE_CODE;
                    wipSN.POST_CODE = CurPosition.POST_CODE;
                    wipSN.OPER_CODE = curNode.OPER_CODE;
                    wipSN.SEGMENT = curNode.SEGMENT;
                    wipSN.OPERATION_TIME = DateTime.Now;
                    wipSN.SFTS_CODE = CurLine.SFTS_CODE;
                    //wipSN.SFT_CODE = CurBatch.WO.ROUTE_CODE;
                    //wipSN.PRD_CODE = CurBatch.WO.ROUTE_CODE;
                    CurBatch.StartWorking(UserCode);
                    //如果是投入站
                    if (curNode.IS_INPUT == "Y")
                    {
                        woSN.STATUS = BIZ_MES_WO_SN.STATUSs.Inputed.GetValue();
                        wipSN.STATUS = MES_WIP_DATA.STATUSs.Input.GetValue();
                        wipSN.INLINE_DATE = DateTime.Now;
                    }
                    //如果是产出站
                    if (curNode.IS_OUTPUT == "Y")
                    {
                        woSN.STATUS = BIZ_MES_WO_SN.STATUSs.Finished.GetValue();
                        wipSN.STATUS = MES_WIP_DATA.STATUSs.Finished.GetValue();
                        wipSN.OUTLINE_DATE = DateTime.Now;
                    }
                    //如果有提交不良
                    if (!input.DFT_CODE.IsNullOrEmpty())
                    {
                        wipSN.STATUS = MES_WIP_DATA.STATUSs.NG.GetValue();
                        wipSN.DFT_FLAG = "Y";
                        wipSN.DFT_COUNT++;
                        wipSN.DFT_CODE = input.DFT_CODE;
                    }
                    CurWipSNHis = new MES_WIP_HIS(CurWipSN = wipSN, $"工单[{wipSN.WORK_ORDER}]的条码[{wipSN.SN}]在岗位[{wipSN.POST_CODE}]工序[{wipSN.NODE_NAME}]过站成功,状态[{wipSN.STATUS.GetEnumDesc<MES_WIP_DATA.STATUSs>()}]");
                    //初始化工步列表
                    Steps.Clear();
                    var curStep = new Biz.WorkStep(IWorkStep.Types.Node, this)
                    {
                        WORK_ORDER = CurBatch.Batch.ORDER_NO,
                        SN = input.SN,
                        STATUS = BIZ_MES_WO_SN.STATUSs.NotInput.GetValue(),
                        BATCH_NO = CurBatch.Batch.BATCH_NO,
                    });
                }
                var woSN = CurBatch.WoSNs.FirstOrDefault(q => q.SN == input.SN);
                var curNode = CurBatch.GetNode(PostCode);
                        NodeID = curNode.ID,
                        Sequence = Steps.Count + 1,
                        Node = curNode,
                        DBSubmitAction = () =>
                        {
                            var db = GetCommitDB();
                            db.Storageable(woSN, UserCode).ExecuteCommand();
                            db.Storageable(wipSN, UserCode).ExecuteCommand();
                            db.Storageable(CurWipSNHis, UserCode).ExecuteCommand();
                        }
                    };
                    Steps.Add(curStep);
                    //有需要则添加工序节点的其他工步
                    //最后添加当前工序的行为工步
                    GenerateSteps(curStep);
                    //完成第一个工序节点工步
                    curStep.IsFinished = true;
                    CurStep = curStep;
                }
                else if (!IsFinishNodeSteps)
                {
                    var curStep = Steps.Where(q => q.Type == IWorkStep.Types.Node && !q.IsFinished).OrderBy(q => q.Sequence).First();
                //条码过站
                var wipSN = Biz.Db.Queryable<MES_WIP_DATA>().First(q => q.SN == input.SN && q.BATCH_NO == CurBatch.Batch.BATCH_NO) ?? new MES_WIP_DATA()
                {
                    SN = input.SN,
                    STATUS = MES_WIP_DATA.STATUSs.Init.GetValue(),
                    ITEM_CODE = CurBatch.WO.ITEM_CODE,
                    WORK_ORDER = CurBatch.Batch.ORDER_NO,
                    BATCH_NO = CurBatch.Batch.BATCH_NO,
                    HOLD_FLAG = "N",
                    REWORK_FLAG = CurBatch.WO.ORDER_TYPE == BIZ_MES_WO.ORDER_TYPEs.Rework.GetValue() ? "Y" : "N",
                    FINISHED_FLAG = "N",
                    INV_FLAG = "N",
                    DFT_FLAG = "N",
                    DFT_COUNT = 0,
                };
                wipSN.AUTH_PROD = CurLine.LINE_CODE;
                wipSN.STATUS = wipSN.STATUS > 0 ? MES_WIP_DATA.STATUSs.OK.GetValue() : wipSN.STATUS;
                wipSN.ROT_CODE = CurBatch.WO.ROUTE_CODE;
                wipSN.NODE_ID = curNode.ID;
                wipSN.NODE_NAME = curNode.NODE_NAME;
                wipSN.FTY_CODE = CurFactory.FTY_CODE;
                wipSN.WS_CODE = CurWorkshop.WS_CODE;
                wipSN.LINE_CODE = CurLine.LINE_CODE;
                wipSN.POST_CODE = CurPosition.POST_CODE;
                wipSN.OPER_CODE = curNode.OPER_CODE;
                wipSN.SEGMENT = curNode.SEGMENT;
                wipSN.OPERATION_TIME = DateTime.Now;
                wipSN.SFTS_CODE = CurLine.SFTS_CODE;
                //wipSN.SFT_CODE = CurBatch.WO.ROUTE_CODE;
                //wipSN.PRD_CODE = CurBatch.WO.ROUTE_CODE;
                CurBatch.StartWorking(UserCode);
                //如果是投入站
                if (curNode.IS_INPUT == "Y")
                {
                    woSN.STATUS = BIZ_MES_WO_SN.STATUSs.Inputed.GetValue();
                    wipSN.STATUS = MES_WIP_DATA.STATUSs.Input.GetValue();
                    wipSN.INLINE_DATE = DateTime.Now;
                }
                //如果是产出站
                if (curNode.IS_OUTPUT == "Y")
                {
                    woSN.STATUS = BIZ_MES_WO_SN.STATUSs.Finished.GetValue();
                    wipSN.STATUS = MES_WIP_DATA.STATUSs.Finished.GetValue();
                    wipSN.OUTLINE_DATE = DateTime.Now;
                }
                //如果有提交不良
                if (!input.DFT_CODE.IsNullOrEmpty())
                {
                    wipSN.STATUS = MES_WIP_DATA.STATUSs.NG.GetValue();
                    wipSN.DFT_FLAG = "Y";
                    wipSN.DFT_COUNT++;
                    wipSN.DFT_CODE = input.DFT_CODE;
                    //完成当前工序节点工步
                    curStep.IsFinished = true;
                    CurStep = curStep;
                }
                CurWipSNHis = new MES_WIP_HIS(CurWipSN = wipSN, $"工单[{wipSN.WORK_ORDER}]的条码[{wipSN.SN}]在岗位[{wipSN.POST_CODE}]工序[{wipSN.NODE_NAME}]过站成功,状态[{wipSN.STATUS.GetEnumDesc<MES_WIP_DATA.STATUSs>()}]");
                //初始化工步列表
                Steps.Clear();
                var curStep = new Biz.WorkStep(curNode.ID, IWorkStep.Types.Node) {
                    Sequence = Steps.Count + 1,
                    Node = curNode,
                    DBSubmitAction = () =>
                    {
                        var db = GetCommitDB();
                        db.Storageable(woSN, UserCode).ExecuteCommand();
                        db.Storageable(wipSN, UserCode).ExecuteCommand();
                        db.Storageable(CurWipSNHis, UserCode).ExecuteCommand();
                    }
                };
                Steps.Add(curStep);
                //如果当前工序节点有行为则添加到工步列表
                var acts = CurBatch.NodeActs.Where(q => q.NODE_ID == curNode.ID).ToList();
                foreach (var act in acts)
                {
                    Steps.Add(new Biz.WorkStep(act.ID, IWorkStep.Types.Action)
                    {
                        Sequence = Steps.Count + 1,
                        Node = curNode,
                        NodeAct = act,
                        Setting = CurBatch.ActionSets.FirstOrDefault(q => q.ACT_ID == act.ID),
                    });
                }
                //完成当前工序节点
                curStep.IsFinished = true;
                //未完成所有工步
                if (!IsFinishAllSteps)
                {
                    var next = Steps.Where(q => !q.IsFinished).OrderBy(q => q.Sequence).First();
                    var result = next.Begin(this);
                    result.Data.StepID = next.ID;
                    result.Data.IsFinished = IsFinishAllSteps;
                    result.Data.CurStep = CurStep;
                    return result.ToApiAction();
                    var result = new ApiAction<SubmitOutput>();
                    //未完成所有工序节点工步
                    if (!IsFinishNodeSteps)
                    {
                        var next = Steps.Where(q => q.Type == IWorkStep.Types.Node && !q.IsFinished).OrderBy(q => q.Sequence).First();
                        //设置后续可执行的工步列表
                        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;
                        //根据工序节点工步的序号返回相应的操作提示
                        switch (next.Sequence)
                        {
                            case 2:
                                //action.LocaleMsg = new($"请执行第二步");
                                result.LocaleMsg = new("MES.Transaction.PackingNode.第二步操作提示");
                                break;
                            default:
                                break;
                        }
                    }
                    //已完成所有工序节点工步,开始执行行为工步
                    else
                    {
                        result = BeginNextActionStep(input);
                    }
                    return result;
                }
                //已完成所有工步
                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 = DoIfFinishAllSteps(action);
                }
            }
@@ -265,7 +330,7 @@
        /// </summary>
        /// <param name="action"></param>
        /// <returns></returns>
        public ApiAction DoIfFinishAllSteps(ApiAction action)
        public ApiAction<SubmitOutput> DoIfFinishAllSteps(ApiAction<SubmitOutput> action)
        {
            //保存数据库
            var dbTran = GetCommitDB().UseTran(() =>
@@ -283,6 +348,7 @@
            //保存成功,返回过站消息
            //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>());
            return action;
        }
        #endregion Functions
Tiger.Business.MES/Transaction/Position.cs
@@ -10,9 +10,7 @@
using System.Threading.Tasks;
using Tiger.Model;
using static Tiger.Business.Biz;
using Org.BouncyCastle.Ocsp;
using Tiger.Model.Entitys.MES.Position;
using MailKit.Search;
namespace Tiger.Business.MES.Transaction
{
@@ -56,8 +54,11 @@
        public MES_WIP_DATA CurWipSN { get; set; }
        public MES_WIP_HIS CurWipSNHis { get; set; }
        public List<WorkStep> Steps { get; set; } = new();
        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;
        public WorkStep CurStep { get; set; }
        public List<WorkStep> NextSteps { get; set; } = new();
        public bool IsFinishNodeSteps => !Steps.Any(q => q.Type == IWorkStep.Types.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 CommitDB;
        #endregion Propertys & Variables
@@ -128,6 +129,157 @@
            CurWipSN = null;
        }
        /// <summary>
        /// 生成传入工步后续的行为到工步列表
        /// </summary>
        /// <param name="parent"></param>
        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;
            //    }
            //}
        }
        /// <summary>
        /// 添加节点的下一个行为到工步列表
        /// </summary>
        /// <param name="curNode"></param>
        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.AddRange(parent.PrepNodeIDs);
                    next.PrepNodeIDs = next.PrepNodeIDs.Distinct().ToList();
                    AddNextActToSteps(next);
                }
                else
                {
                    var next = new WorkStep(IWorkStep.Types.Action, this)
                    {
                        NodeID = act.ID,
                        Sequence = parent.Sequence + 1,
                        Node = parent.Node,
                        NodeAct = act,
                        Setting = CurBatch.ActionSets.FirstOrDefault(q => q.ACT_ID == act.ID),
                    };
                    next.PrepNodeIDs.AddRange(parent.PrepNodeIDs);
                    next.PrepNodeIDs = next.PrepNodeIDs.Distinct().ToList();
                    Steps.Add(next);
                    AddNextActToSteps(next);
                }
            }
        }
        /// <summary>
        /// 根据传入的工步,返回下一步可执行的工步列表
        /// </summary>
        /// <param name="curStep"></param>
        public List<WorkStep> GetNextSteps(WorkStep curStep)
        {
            var result = new List<WorkStep>();
            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())
            {
                //查找有没有前置工步未完成,若有则先完成未完成的前置工步
                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();
        }
        /// <summary>
        /// 开始执行下一行为工步
        /// </summary>
        /// <param name="input"></param>
        public ApiAction<SubmitOutput> BeginNextActionStep(SubmitInput input)
        {
            var result = new ApiAction<SubmitOutput>();
            //设置后续可执行的工步列表
            NextSteps = GetNextSteps(CurStep);
            //尝试有没有可以直接开始的后续工步
            foreach (var step in NextSteps)
            {
                var canBegin = step.TryBegin(input);
                //如果后续工步可以直接开始则直接执行
                if (canBegin.IsSuccessed)
                {
                    CurStep = step;
                    NextSteps = GetNextSteps(CurStep);
                    result = canBegin;
                    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;
                    return result;
                }
            }
            //根据后续工步返回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.StepActCode = CurStep.NodeAct.ACT_CODE;
            result.Data.NextStepID = "";
            //根据后续可执行工步列表返回相应的操作提示
            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;
        }
        #endregion Functions
        public override bool Close(bool needSaveHistoryLog = false)
Tiger.Business.MES/Transaction/TestNode.cs
@@ -35,18 +35,18 @@
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<ApiAction> Submit(SubmitInput input)
        public async Task<ApiAction<SubmitOutput>> Submit(SubmitInput input)
        {
            var action = new ApiAction();
            var action = new ApiAction<SubmitOutput>();
            try
            {
                //工步列表为空时,认为需要先扫描过站条码
                if (Steps.IsNullOrEmpty())
                //工步列表为空或者工序节点工步有未完成时,优先完成工序节点工步
                if (Steps.IsNullOrEmpty() || !IsFinishNodeSteps)
                {
                    //先判断当前工单不为空且当前岗位在当前工单是不是首站,如果是则不允许变更当前工单,尝试把条码绑定到当前工单
                    if (!CurBatch.IsNullOrEmpty() && CurBatch.IsFirstNode(PostCode))
                    {
                        action = ScanSn(action, input);
                        action = NodeSubmit(action, input);
                        return action;
                    }
                    //当前岗位在当前工单不是首站,则查找条码已绑定的工单当作当前工单
@@ -64,12 +64,13 @@
                                var result = await SelectOrder(new() { AuthOption = input.AuthOption, OrderNo = wosn.Batch.ORDER_NO });
                                if (!result.IsSuccessed)
                                {
                                    action = result;
                                    action.IsSuccessed = result.IsSuccessed;
                                    action.LocaleMsg = result.LocaleMsg;
                                    return action;
                                }
                            }
                            //条码过站
                            action = ScanSn(action, input);
                            action = NodeSubmit(action, input);
                            return action;
                        }
                        //查找不到条码已绑定的工单
@@ -95,20 +96,47 @@
                    }
                }
                //完成第一步,后开始执行当前工序的行为列表
                else if (Steps.First().IsFinished && !IsFinishAllSteps)
                //完成工序节点工步后,后开始执行当前工序的行为工步
                else if (IsFinishNodeSteps && !IsFinishAllSteps)
                {
                    var curStep = Steps.Where(q => q.ID == input.StepID).FirstOrDefault();
                    if (!curStep.IsNullOrEmpty())
                    var submitStep = Steps.Where(q => q.ID == input.CurStepID && !q.IsFinished).FirstOrDefault();
                    if (submitStep.IsNullOrEmpty())
                    {
                        var result = curStep.Submit(input);
                        result.Data.StepID = curStep.ID;
                        result.Data.IsFinished = IsFinishAllSteps;
                        result.Data.CurStep = CurStep;
                        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.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 (IsFinishAllSteps)
                        {
                            return DoIfFinishAllSteps(result.ToApiAction());
                            return DoIfFinishAllSteps(result);
                        }
                        return result.ToApiAction();
                        return result;
                    }
                }
                //没有可执行的工步
@@ -125,130 +153,168 @@
        }
        /// <summary>
        /// 扫描过站条码
        /// 工序节点工步提交数据
        /// </summary>
        /// <param name="action"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        public ApiAction ScanSn(ApiAction action, SubmitInput input)
        public ApiAction<SubmitOutput> NodeSubmit(ApiAction<SubmitOutput> action, SubmitInput input)
        {
            try
            {
                //绑定条码到工单
                if (!CurBatch.WoSNs.Any(q => q.SN == input.SN))
                //当工步列表为空,则执行当前工序的必要逻辑当作第一个工序节点,完成后按需求创建后续的工步列表
                if (Steps.IsNullOrEmpty())
                {
                    CurBatch.WoSNs.Add(new()
                    //绑定条码到工单
                    if (!CurBatch.WoSNs.Any(q => q.SN == input.SN))
                    {
                        WORK_ORDER = CurBatch.Batch.ORDER_NO,
                        SN = input.SN,
                        STATUS = BIZ_MES_WO_SN.STATUSs.NotInput.GetValue(),
                        BATCH_NO = CurBatch.Batch.BATCH_NO,
                    });
                }
                var woSN = CurBatch.WoSNs.FirstOrDefault(q => q.SN == input.SN);
                var curNode = CurBatch.GetNode(PostCode);
                //条码过站
                var wipSN = Biz.Db.Queryable<MES_WIP_DATA>().First(q => q.SN == input.SN && q.BATCH_NO == CurBatch.Batch.BATCH_NO) ?? new MES_WIP_DATA()
                {
                    SN = input.SN,
                    STATUS = MES_WIP_DATA.STATUSs.Init.GetValue(),
                    ITEM_CODE = CurBatch.WO.ITEM_CODE,
                    WORK_ORDER = CurBatch.Batch.ORDER_NO,
                    BATCH_NO = CurBatch.Batch.BATCH_NO,
                    HOLD_FLAG = "N",
                    REWORK_FLAG = CurBatch.WO.ORDER_TYPE == BIZ_MES_WO.ORDER_TYPEs.Rework.GetValue() ? "Y" : "N",
                    FINISHED_FLAG = "N",
                    INV_FLAG = "N",
                    DFT_FLAG = "N",
                    DFT_COUNT = 0,
                };
                wipSN.AUTH_PROD = CurLine.LINE_CODE;
                wipSN.STATUS = wipSN.STATUS > 0 ? MES_WIP_DATA.STATUSs.OK.GetValue() : wipSN.STATUS;
                wipSN.ROT_CODE = CurBatch.WO.ROUTE_CODE;
                wipSN.NODE_ID = curNode.ID;
                wipSN.NODE_NAME = curNode.NODE_NAME;
                wipSN.FTY_CODE = CurFactory.FTY_CODE;
                wipSN.WS_CODE = CurWorkshop.WS_CODE;
                wipSN.LINE_CODE = CurLine.LINE_CODE;
                wipSN.POST_CODE = CurPosition.POST_CODE;
                wipSN.OPER_CODE = curNode.OPER_CODE;
                wipSN.SEGMENT = curNode.SEGMENT;
                wipSN.OPERATION_TIME = DateTime.Now;
                wipSN.SFTS_CODE = CurLine.SFTS_CODE;
                //wipSN.SFT_CODE = CurBatch.WO.ROUTE_CODE;
                //wipSN.PRD_CODE = CurBatch.WO.ROUTE_CODE;
                CurBatch.StartWorking(UserCode);
                //如果是投入站
                if (curNode.IS_INPUT == "Y")
                {
                    woSN.STATUS = BIZ_MES_WO_SN.STATUSs.Inputed.GetValue();
                    wipSN.STATUS = MES_WIP_DATA.STATUSs.Input.GetValue();
                    wipSN.INLINE_DATE = DateTime.Now;
                }
                //如果是产出站
                if (curNode.IS_OUTPUT == "Y")
                {
                    woSN.STATUS = BIZ_MES_WO_SN.STATUSs.Finished.GetValue();
                    wipSN.STATUS = MES_WIP_DATA.STATUSs.Finished.GetValue();
                    wipSN.OUTLINE_DATE = DateTime.Now;
                }
                //如果有提交不良
                if (!input.DFT_CODE.IsNullOrEmpty())
                {
                    wipSN.STATUS = MES_WIP_DATA.STATUSs.NG.GetValue();
                    wipSN.DFT_FLAG = "Y";
                    wipSN.DFT_COUNT++;
                    wipSN.DFT_CODE = input.DFT_CODE;
                }
                CurWipSNHis = new MES_WIP_HIS(CurWipSN = wipSN, $"工单[{wipSN.WORK_ORDER}]条码[{wipSN.SN}]在岗位[{wipSN.POST_CODE}]过站工序[{wipSN.NODE_NAME}]成功");
                //初始化工步列表
                Steps.Clear();
                var curStep = new Biz.WorkStep(curNode.ID, IWorkStep.Types.Node)
                {
                    Sequence = Steps.Count + 1,
                    Node = curNode,
                    DBSubmitAction = () =>
                    {
                        var db = GetCommitDB();
                        db.Storageable(woSN, UserCode).ExecuteCommand();
                        db.Storageable(wipSN, UserCode).ExecuteCommand();
                        db.Storageable(CurWipSNHis, UserCode).ExecuteCommand();
                        CurBatch.WoSNs.Add(new()
                        {
                            WORK_ORDER = CurBatch.Batch.ORDER_NO,
                            SN = input.SN,
                            STATUS = BIZ_MES_WO_SN.STATUSs.NotInput.GetValue(),
                            BATCH_NO = CurBatch.Batch.BATCH_NO,
                        });
                    }
                };
                Steps.Add(curStep);
                    var woSN = CurBatch.WoSNs.FirstOrDefault(q => q.SN == input.SN);
                    var curNode = CurBatch.GetNode(PostCode);
                //如果当前工序节点有行为则添加到工步列表
                var acts = CurBatch.NodeActs.Where(q => q.NODE_ID == curNode.ID).ToList();
                foreach (var act in acts)
                {
                    Steps.Add(new Biz.WorkStep(act.ID, IWorkStep.Types.Action)
                    //条码过站
                    var wipSN = Biz.Db.Queryable<MES_WIP_DATA>().First(q => q.SN == input.SN && q.BATCH_NO == CurBatch.Batch.BATCH_NO) ?? new MES_WIP_DATA()
                    {
                        SN = input.SN,
                        STATUS = MES_WIP_DATA.STATUSs.Init.GetValue(),
                        ITEM_CODE = CurBatch.WO.ITEM_CODE,
                        WORK_ORDER = CurBatch.Batch.ORDER_NO,
                        BATCH_NO = CurBatch.Batch.BATCH_NO,
                        HOLD_FLAG = "N",
                        REWORK_FLAG = CurBatch.WO.ORDER_TYPE == BIZ_MES_WO.ORDER_TYPEs.Rework.GetValue() ? "Y" : "N",
                        FINISHED_FLAG = "N",
                        INV_FLAG = "N",
                        DFT_FLAG = "N",
                        DFT_COUNT = 0,
                    };
                    wipSN.AUTH_PROD = CurLine.LINE_CODE;
                    wipSN.STATUS = wipSN.STATUS > 0 ? MES_WIP_DATA.STATUSs.OK.GetValue() : wipSN.STATUS;
                    wipSN.ROT_CODE = CurBatch.WO.ROUTE_CODE;
                    wipSN.NODE_ID = curNode.ID;
                    wipSN.NODE_NAME = curNode.NODE_NAME;
                    wipSN.FTY_CODE = CurFactory.FTY_CODE;
                    wipSN.WS_CODE = CurWorkshop.WS_CODE;
                    wipSN.LINE_CODE = CurLine.LINE_CODE;
                    wipSN.POST_CODE = CurPosition.POST_CODE;
                    wipSN.OPER_CODE = curNode.OPER_CODE;
                    wipSN.SEGMENT = curNode.SEGMENT;
                    wipSN.OPERATION_TIME = DateTime.Now;
                    wipSN.SFTS_CODE = CurLine.SFTS_CODE;
                    //wipSN.SFT_CODE = CurBatch.WO.ROUTE_CODE;
                    //wipSN.PRD_CODE = CurBatch.WO.ROUTE_CODE;
                    CurBatch.StartWorking(UserCode);
                    //如果是投入站
                    if (curNode.IS_INPUT == "Y")
                    {
                        woSN.STATUS = BIZ_MES_WO_SN.STATUSs.Inputed.GetValue();
                        wipSN.STATUS = MES_WIP_DATA.STATUSs.Input.GetValue();
                        wipSN.INLINE_DATE = DateTime.Now;
                    }
                    //如果是产出站
                    if (curNode.IS_OUTPUT == "Y")
                    {
                        woSN.STATUS = BIZ_MES_WO_SN.STATUSs.Finished.GetValue();
                        wipSN.STATUS = MES_WIP_DATA.STATUSs.Finished.GetValue();
                        wipSN.OUTLINE_DATE = DateTime.Now;
                    }
                    //如果有提交不良
                    if (!input.DFT_CODE.IsNullOrEmpty())
                    {
                        wipSN.STATUS = MES_WIP_DATA.STATUSs.NG.GetValue();
                        wipSN.DFT_FLAG = "Y";
                        wipSN.DFT_COUNT++;
                        wipSN.DFT_CODE = input.DFT_CODE;
                    }
                    CurWipSNHis = new MES_WIP_HIS(CurWipSN = wipSN, $"工单[{wipSN.WORK_ORDER}]条码[{wipSN.SN}]在岗位[{wipSN.POST_CODE}]过站工序[{wipSN.NODE_NAME}]成功");
                    //初始化工步列表
                    Steps.Clear();
                    var curStep = new Biz.WorkStep(IWorkStep.Types.Node, this)
                    {
                        NodeID = curNode.ID,
                        Sequence = Steps.Count + 1,
                        Node = curNode,
                        NodeAct = act,
                        Setting = CurBatch.ActionSets.FirstOrDefault(q => q.ACT_ID == act.ID),
                    });
                        DBSubmitAction = () =>
                        {
                            var db = GetCommitDB();
                            db.Storageable(woSN, UserCode).ExecuteCommand();
                            db.Storageable(wipSN, UserCode).ExecuteCommand();
                            db.Storageable(CurWipSNHis, UserCode).ExecuteCommand();
                        }
                    };
                    Steps.Add(curStep);
                    //有需要则添加工序节点的其他工步
                    //最后添加当前工序的行为工步
                    GenerateSteps(curStep);
                    //完成第一个工序节点工步
                    curStep.IsFinished = true;
                    CurStep = curStep;
                }
                else if (!IsFinishNodeSteps)
                {
                    var curStep = Steps.Where(q => q.Type == IWorkStep.Types.Node && !q.IsFinished).OrderBy(q => q.Sequence).First();
                    //完成当前工序节点工步
                    curStep.IsFinished = true;
                    CurStep = curStep;
                }
                //完成当前工序节点
                curStep.IsFinished = true;
                //未完成所有工步
                if (!IsFinishAllSteps)
                {
                    var next = Steps.Where(q => !q.IsFinished).OrderBy(q => q.Sequence).First();
                    var result = next.Begin(this);
                    result.Data.StepID = next.ID;
                    result.Data.IsFinished = IsFinishAllSteps;
                    result.Data.CurStep = CurStep;
                    return result.ToApiAction();
                    var result = new ApiAction<SubmitOutput>();
                    //未完成所有工序节点工步
                    if (!IsFinishNodeSteps)
                    {
                        var next = Steps.Where(q => q.Type == IWorkStep.Types.Node && !q.IsFinished).OrderBy(q => q.Sequence).First();
                        //设置后续可执行的工步列表
                        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;
                        //根据工序节点工步的序号返回相应的操作提示
                        switch (next.Sequence)
                        {
                            case 2:
                                //action.LocaleMsg = new($"请执行第二步");
                                result.LocaleMsg = new("MES.Transaction.TestNode.第二步操作提示");
                                break;
                            default:
                                break;
                        }
                    }
                    //已完成所有工序节点工步,开始执行行为工步
                    else
                    {
                        result = BeginNextActionStep(input);
                    }
                    return result;
                }
                //已完成所有工步
                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 = DoIfFinishAllSteps(action);
                }
            }
@@ -265,7 +331,7 @@
        /// </summary>
        /// <param name="action"></param>
        /// <returns></returns>
        public ApiAction DoIfFinishAllSteps(ApiAction action)
        public ApiAction<SubmitOutput> DoIfFinishAllSteps(ApiAction<SubmitOutput> action)
        {
            //保存数据库
            var dbTran = GetCommitDB().UseTran(() =>
Tiger.Business.MES/WorkAction/IPQC.cs
@@ -23,20 +23,42 @@
        #region Functions
        /// <summary>
        /// 开始执行工序行为
        /// 初始化工序行为
        /// </summary>
        /// <returns></returns>
        public ApiAction<SubmitOutput> Begin(IWorkStep curStep, IPosition position, MES_WO_NODE_ACT nodeAct, MES_WO_ACTION setting)
        public void Init(IWorkStep curStep, IPosition position, MES_WO_NODE_ACT nodeAct, MES_WO_ACTION setting)
        {
            CurStep = curStep;
            CurPosition = position;
            NodeAct = nodeAct;
            Setting = setting;
        }
        /// <summary>
        /// 获取行为开始的提示信息
        /// </summary>
        /// <returns></returns>
        public Locale GetBeginMsg()
        {
            //var msg = new Locale("MES.WorkAction.IPQC.BeginMsg");
            var msg = new Locale($"请提交测试结果");
            return msg;
        }
        /// <summary>
        /// 尝试开始执行工序行为
        /// </summary>
        /// <returns></returns>
        public ApiAction<SubmitOutput> TryBegin(SubmitInput input)
        {
            var action = new ApiAction<SubmitOutput>();
            //action.LocaleMsg = new($"请按测试项提交测试数据");
            action.LocaleMsg = new("MES.WorkAction.IPQC.PleaseTest");
            //如果根据输入可以开始执行当前行为则标记为成功,否则失败
            action.IsSuccessed = false;
            return action;
        }
        /// <summary>
@@ -46,6 +68,31 @@
        public ApiAction<SubmitOutput> Submit(SubmitInput input)
        {
            var action = new ApiAction<SubmitOutput>();
            //提交数据执行成功
            if (true)
            {
                action.IsSuccessed = true;
                action.LocaleMsg = new($"执行成功");
                //action.LocaleMsg = new("MES.WorkAction.IPQC.Success");
                //行为执行完成
                if (false)
                {
                    action = End();
                }
            }
            //提交数据执行失败
            else
            {
                action.IsSuccessed = false;
                //action.LocaleMsg = new($"执行失败");
                action.LocaleMsg = new("MES.WorkAction.IPQC.Fail");
                //如果行为设置为出错需要重置工序操作
                if (NodeAct.NEED_RESET == "Y")
                {
                    CurPosition.ResetSteps();
                }
            }
            return action;
        }
@@ -57,18 +104,55 @@
        {
            var action = new ApiAction<SubmitOutput>();
            //记录行为操作记录
            var wipAct = new MES_WIP_ACT()
            {
                HIS_ID = CurPosition.CurWipSNHis.ID,
                SN = CurPosition.CurWipSN.SN,
                STATUS = CurPosition.CurWipSN.STATUS,
                ITEM_CODE = CurPosition.CurWipSN.ITEM_CODE,
                WORK_ORDER = CurPosition.CurWipSN.WORK_ORDER,
                BATCH_NO = CurPosition.CurWipSN.BATCH_NO,
                ROT_CODE = CurPosition.CurWipSN.ROT_CODE,
                NODE_ID = CurPosition.CurWipSN.NODE_ID,
                NODE_NAME = CurPosition.CurWipSN.NODE_NAME,
                ACT_ID = NodeAct.ID,
                ACT_NAME = NodeAct.ACT_NAME,
                FTY_CODE = CurPosition.CurWipSN.FTY_CODE,
                WS_CODE = CurPosition.CurWipSN.WS_CODE,
                LINE_CODE = CurPosition.CurWipSN.LINE_CODE,
                POST_CODE = CurPosition.CurWipSN.POST_CODE,
                OPER_CODE = CurPosition.CurWipSN.OPER_CODE,
                SEGMENT = CurPosition.CurWipSN.SEGMENT,
                TRAY_SN = CurPosition.CurWipSN.TRAY_SN,
                OPERATION_TIME = DateTime.Now,
                SFTS_CODE = CurPosition.CurWipSN.SFTS_CODE,
                SFT_CODE = CurPosition.CurWipSN.SFT_CODE,
                PRD_CODE = CurPosition.CurWipSN.PRD_CODE,
                ACT_TYPE = NodeAct.ACT_TYPE,
                ACT_SN = CurPosition.CurWipSN.SN,
                ACT_VALUE_1 = "",
                ACT_VALUE_2 = "",
                ACT_VALUE_3 = "",
                ACT_VALUE_4 = "",
                ACT_VALUE_5 = "",
                ACT_RESULT = "Y",
                TRACE_INFO = $"执行成功",
            };
            //保存数据
            CurStep.DBSubmitAction = () =>
            {
                var db = CurPosition.GetCommitDB();
                db.Storageable(wipAct, CurPosition.UserCode).ExecuteCommand();
            };
            IsFinished = true;
            action.LocaleMsg = new($"行为结束");
            //action.LocaleMsg = new("MES.WorkAction.IPQC.Finish");
            return action;
        }
        /// <summary>
        /// 获取行为提示信息
        /// </summary>
        /// <returns></returns>
        public ApiAction GetPrompt()
        {
            var action = new ApiAction();
            action.LocaleMsg = new($"开始打印条码");
            return action;
        }
        #endregion Functions
    }
Tiger.Business.MES/WorkAction/PrintLabel.cs
@@ -26,19 +26,39 @@
        #region Functions
        /// <summary>
        /// 开始执行工序行为
        /// 初始化工序行为
        /// </summary>
        /// <returns></returns>
        public ApiAction<SubmitOutput> Begin(IWorkStep curStep, IPosition position, MES_WO_NODE_ACT nodeAct, MES_WO_ACTION setting)
        public void Init(IWorkStep curStep, IPosition position, MES_WO_NODE_ACT nodeAct, MES_WO_ACTION setting)
        {
            CurStep = curStep;
            CurPosition = position;
            NodeAct = nodeAct;
            Setting = setting;
            var action = new ApiAction<SubmitOutput>();
            Label = Biz.Db.Queryable<BAS_LABEL_TEMP>().Where(q => q.LABEL_CODE == setting.LABEL_CODE).IncludesAllFirstLayer().First();
            LabelPV = Biz.Db.Queryable<BAS_LABEL_PV>().ToList();
        }
        /// <summary>
        /// 获取行为开始的提示信息
        /// </summary>
        /// <returns></returns>
        public Locale GetBeginMsg()
        {
            var msg = new Locale("MES.WorkAction.PrintLabel.BeginMsg", CurPosition.CurWipSN.SN, Label.LABEL_CODE, Label.LABEL_NAME);
            //var msg = new Locale($"开始打印条码[{CurPosition.CurWipSN.SN}]的标签[{Label.LABEL_CODE}: {Label.LABEL_NAME}]");
            return msg;
        }
        /// <summary>
        /// 尝试开始执行工序行为
        /// </summary>
        /// <returns></returns>
        public ApiAction<SubmitOutput> TryBegin(SubmitInput input)
        {
            var action = new ApiAction<SubmitOutput>();
            foreach (var item in Label.Variables)
            {
                switch (item.VAR_TYPE.GetEnum<BAS_LABEL_VAR.VAR_TYPEs>())
@@ -58,10 +78,13 @@
                        break;
                }
            }
            action.Data.StepActCode = nodeAct.Definition.ACT_CODE;
            action.Data.Data = Label;
            //如果根据输入可以开始执行当前行为则标记为成功,否则失败
            action.IsSuccessed = true;
            return action;
        }
        /// <summary>
        /// 工序行为提交数据
        /// </summary>
@@ -69,17 +92,22 @@
        public ApiAction<SubmitOutput> Submit(SubmitInput input)
        {
            var action = new ApiAction<SubmitOutput>();
            //提交数据执行成功
            if (input.Data.ToBoolean())
            {
                action = End();
            }
            //提交数据执行失败
            else
            {
                //重置当前工序
                CurPosition.ResetSteps();
                action.IsSuccessed = false;
                //action.LocaleMsg = new($"标签{Label.LABEL_NAME}[{Label.LABEL_CODE}]打印失败,请重新扫描产品条码", Label.LABEL_NAME);
                //action.LocaleMsg = new($"标签{Label.LABEL_NAME}[{Label.LABEL_CODE}]打印失败", Label.LABEL_NAME);
                action.LocaleMsg = new("MES.WorkAction.PrintLabel.PrintFail", Label.LABEL_NAME, Label.LABEL_CODE);
                //如果行为设置为出错需要重置工序操作
                if (NodeAct.NEED_RESET == "Y")
                {
                    CurPosition.ResetSteps();
                }
            }
            return action;
        }
@@ -91,6 +119,7 @@
        {
            var action = new ApiAction<SubmitOutput>();
            //记录行为操作记录
            var wipAct = new MES_WIP_ACT()
            {
                HIS_ID = CurPosition.CurWipSNHis.ID,
Tiger.Business/Language/Biz.Language.cs
@@ -17,6 +17,7 @@
using System.Xml.Linq;
using Tiger.IBusiness;
using System.Data;
using Tiger.Model.Entitys.MES.Position;
namespace Tiger.Business
{
@@ -30,6 +31,13 @@
        /// <returns></returns>
        public static string T(string key, params object?[] args) => new Locale(key, args).Default();
        /// <summary>
        /// 多语言翻译,按传入的语言翻译,传入语言为空则按BizSettings设置的默认语言(DefaultLanguage)翻译
        /// </summary>
        /// <param name="locale"></param>
        /// <param name="language"></param>
        /// <returns></returns>
        public static string T(Locale locale, string language) => language.IsNullOrEmpty() ? locale.Default() : locale[language];
        /// <summary>
        /// 多语言对象(未翻译)
        /// </summary>
        /// <param name="key"></param>
Tiger.Business/MES/Biz.WorkStep.cs
@@ -22,14 +22,15 @@
        /// </summary>
        public partial class WorkStep : IWorkStep
        {
            public WorkStep(string id, IWorkStep.Types type)
            public WorkStep(IWorkStep.Types type, IPosition position)
            {
                ID = id;
                Type = type;
                CurPosition = position;
            }
            #region Propertys & Variables
            public string ID { get; set; } = Guid.NewGuid().ToString("N");
            public string NodeID { get; set; }
            public IWorkStep.Types Type { get; set; }
            public int Sequence { get; set; }
            public MES_WO_NODE Node { get; set; }
@@ -37,6 +38,7 @@
            public MES_WO_ACTION Setting { get; set; }
            public IPosition CurPosition { get; set; }
            public IWorkAction CurAction { get; set; }
            public List<string> PrepNodeIDs { get; set; } = new();
            private bool _IsFinished = false;
            public bool IsFinished
            {
@@ -48,16 +50,32 @@
            #region Functions
            /// <summary>
            /// 开始执行工步
            /// 初始化工步
            /// </summary>
            /// <param name="position"></param>
            /// <returns></returns>
            public ApiAction<SubmitOutput> Begin(IPosition position)
            public void Init()
            {
                CurPosition = position;
                CurAction = DI.Resolve(NodeAct.Definition.SERVICE_TYPE) as IWorkAction;
                //CurAction = DI.Resolve("Tiger.IBusiness.IPrintLabel,Tiger.IBusiness") as IWorkAction;
                return CurAction.Begin(this, position, NodeAct, Setting);
                CurAction.Init(this, CurPosition, NodeAct, Setting);
            }
            /// <summary>
            /// 尝试开始执行工步
            /// </summary>
            /// <returns></returns>
            public ApiAction<SubmitOutput> TryBegin(SubmitInput input)
            {
                return CurAction.TryBegin(input);
            }
            /// <summary>
            /// 获取行为开始的提示信息
            /// </summary>
            /// <returns></returns>
            public Locale GetBeginMsg()
            {
                return CurAction.GetBeginMsg();
            }
            /// <summary>
Tiger.IBusiness/MES/IWorkAction.cs
@@ -21,10 +21,20 @@
        #region Functions
        /// <summary>
        /// 开始执行工序行为
        /// 初始化工序行为
        /// </summary>
        /// <returns></returns>
        public ApiAction<SubmitOutput> Begin(IWorkStep curStep, IPosition position, MES_WO_NODE_ACT nodeAct, MES_WO_ACTION setting);
        public void Init(IWorkStep curStep, IPosition position, MES_WO_NODE_ACT nodeAct, MES_WO_ACTION setting);
        /// <summary>
        /// 获取行为开始的提示信息
        /// </summary>
        /// <returns></returns>
        public Locale GetBeginMsg();
        /// <summary>
        /// 尝试开始执行工序行为
        /// </summary>
        /// <returns></returns>
        public ApiAction<SubmitOutput> TryBegin(SubmitInput input);
        /// <summary>
        /// 工序行为提交数据
        /// </summary>
Tiger.IBusiness/MES/IWorkStep.cs
@@ -21,6 +21,7 @@
        public MES_WO_ACTION Setting { get; set; }
        public IPosition CurPosition { get; set; }
        public IWorkAction CurAction { get; set; }
        public List<string> PrepNodeIDs { get; set; }
        public bool IsFinished { get; set; }
        public Action DBSubmitAction { get; set; }
        #endregion Propertys & Variables
@@ -28,11 +29,15 @@
        #region Functions
        /// <summary>
        /// 开始执行工步
        /// 尝试开始执行工步
        /// </summary>
        /// <param name="position"></param>
        /// <returns></returns>
        public ApiAction<SubmitOutput> Begin(IPosition position);
        public ApiAction<SubmitOutput> TryBegin(SubmitInput input);
        /// <summary>
        /// 获取行为开始的提示信息
        /// </summary>
        /// <returns></returns>
        public Locale GetBeginMsg();
        /// <summary>
        /// 工步提交数据
        /// </summary>
Tiger.IBusiness/MES/Transaction/ICollectNode.cs
@@ -32,6 +32,6 @@
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public Task<ApiAction> Submit(SubmitInput input);
        public Task<ApiAction<SubmitOutput>> Submit(SubmitInput input);
    }
}
Tiger.IBusiness/MES/Transaction/IPackingNode.cs
@@ -32,6 +32,6 @@
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public Task<ApiAction> Submit(SubmitInput input);
        public Task<ApiAction<SubmitOutput>> Submit(SubmitInput input);
    }
}
Tiger.IBusiness/MES/Transaction/IPosition.cs
@@ -20,12 +20,23 @@
        public IWorkBatch WorkBatch { get; }
        public MES_WIP_DATA CurWipSN { get; set; }
        public MES_WIP_HIS CurWipSNHis { get; set; }
        public IPosition Init(string id, string apiHost, string userCode, string postCode);
        public void ResetSteps();
        #endregion Propertys & Variables
        #region Functions
        /// <summary>
        /// 初始化岗位
        /// </summary>
        /// <param name="id"></param>
        /// <param name="apiHost"></param>
        /// <param name="userCode"></param>
        /// <param name="postCode"></param>
        /// <returns></returns>
        public IPosition Init(string id, string apiHost, string userCode, string postCode);
        /// <summary>
        /// 重置工步列表
        /// </summary>
        public void ResetSteps();
        /// <summary>
        /// 获取提交数据的DbClient对象
        /// </summary>
        /// <returns></returns>
Tiger.IBusiness/MES/Transaction/ITestNode.cs
@@ -32,7 +32,7 @@
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public Task<ApiAction> Submit(SubmitInput input);
        public Task<ApiAction<SubmitOutput>> Submit(SubmitInput input);
        /// <summary>
        /// 测试工序:获取工序不良代码
        /// </summary>
Tiger.Model.Net/Entitys/MES/MES_ROUTE_NODE_ACT.cs
@@ -6,42 +6,43 @@
namespace Tiger.Model
{
    /// <summary>
    /// 实体:工序行为
    /// </summary>
    [Description("Primary:ID")]
    [Serializable]
    [SugarTable("MES_ROUTE_NODE_ACT")]
    public class MES_ROUTE_NODE_ACT : DbEntityWithAuth
    {
        #region 构造函数
        /// <summary>
        /// 实体:工序行为
        /// </summary>
        public MES_ROUTE_NODE_ACT() {}
        #endregion
    /// <summary>
    /// 实体:工艺行为节点
    /// </summary>
    [Description("Primary:ID")]
    [DisplayName("工艺行为节点")]
    [Serializable]
    [SugarTable("MES_ROUTE_NODE_ACT")]
    public class MES_ROUTE_NODE_ACT : DbEntityWithAuth
    {
        #region 构造函数
        /// <summary>
        /// 实体:工艺行为节点
        /// </summary>
        public MES_ROUTE_NODE_ACT() { }
        #endregion
        #region 公共属性
        /// <summary>
        /// 行为名称
        /// </summary>
        public string ACT_NAME { get; set; }
        /// <summary>
        /// 工艺路线ID
        /// </summary>
        public string ROT_ID { get; set; }
        /// <summary>
        /// 工艺路线节点ID
        /// </summary>
        public string NODE_ID { get; set; }
        /// <summary>
        /// 工序编码
        /// </summary>
        //public string OPER_CODE { get; set; }
        /// <summary>
        /// 行为类型(0Normal默认行为|1Scan扫码验证|2Assy组装上料|3Test产品测试|4Audit产品抽检|5Print标签打印|6Package包装规则)
        /// </summary>
        public int ACT_TYPE { get; set; }
        #region 公共属性
        /// <summary>
        /// 行为名称
        /// </summary>
        [DisplayName("行为名称")]
        public string ACT_NAME { get; set; }
        /// <summary>
        /// 工艺路线ID
        /// </summary>
        [DisplayName("工艺路线ID")]
        public string ROT_ID { get; set; }
        /// <summary>
        /// 工序节点ID
        /// </summary>
        [DisplayName("工序节点ID")]
        public string NODE_ID { get; set; }
        /// <summary>
        /// 行为类型(0Normal默认行为|1Scan扫码验证|2Assy组装上料|3Test产品测试|4Audit产品抽检|5Print标签打印|6Package包装规则)
        /// </summary>
        [DisplayName("行为类型(0Normal默认行为|1Scan扫码验证|2Assy组装上料|3Test产品测试|4Audit产品抽检|5Print标签打印|6Package包装规则)")]
        public int ACT_TYPE { get; set; }
        /// <summary>
        /// 行为编码
        /// </summary>
@@ -50,26 +51,32 @@
        /// <summary>
        /// 绘图属性:type
        /// </summary>
        [DisplayName("绘图属性:type")]
        public string GPH_TYPE { get; set; }
        /// <summary>
        /// 绘图属性:x
        /// </summary>
        public double GPH_X { get; set; }
        /// <summary>
        /// 绘图属性:y
        /// </summary>
        public double GPH_Y { get; set; }
        /// <summary>
        /// 绘图属性:properties
        /// </summary>
        public string GPH_PROP { get; set; }
        /// <summary>
        /// 绘图属性:text
        /// </summary>
        public string GPH_TEXT { get; set; }
        /// <summary>
        /// 绘图属性:x
        /// </summary>
        [DisplayName("绘图属性:x")]
        public double GPH_X { get; set; }
        /// <summary>
        /// 绘图属性:y
        /// </summary>
        [DisplayName("绘图属性:y")]
        public double GPH_Y { get; set; }
        /// <summary>
        /// 绘图属性:properties
        /// </summary>
        [DisplayName("绘图属性:properties")]
        public string GPH_PROP { get; set; }
        /// <summary>
        /// 绘图属性:text
        /// </summary>
        [DisplayName("绘图属性:text")]
        public string GPH_TEXT { get; set; }
        /// <summary>
        /// 是否启用(Y/N)
        /// </summary>
        [DisplayName("是否启用(Y/N)")]
        public string IS_ACTIVE { get; set; }
        /// <summary>
        /// 是否设置才能下发生产(Y/N)
@@ -77,45 +84,40 @@
        [DisplayName("是否设置才能下发生产(Y/N)")]
        public string NEED_SETUP { get; set; }
        /// <summary>
        /// 自定义方法类型(0ServerMethod服务端方法|1WebApiWebApi方法|2StoredProcedure存储过程)
        /// 执行出错时,是否重置整个工序的操作(Y/N)
        /// </summary>
  //      public int DO_TYPE { get; set; }
        ///// <summary>
        ///// 自定义方法(调用方法的全名)
        ///// </summary>
        //public string DO_METHOD { get; set; }
        ///// <summary>
        ///// 通过时执行(调用方法的全名)
        ///// </summary>
        //public string DO_IF_PASS { get; set; }
        ///// <summary>
        ///// 失败时执行(调用方法的全名)
        ///// </summary>
        //public string DO_IF_FAIL { get; set; }
        /// <summary>
        /// 设置值1
        /// </summary>
        public string OPTION_1 { get; set; }
        /// <summary>
        /// 设置值2
        /// </summary>
        public string OPTION_2 { get; set; }
        /// <summary>
        /// 设置值3
        /// </summary>
        public string OPTION_3 { get; set; }
        /// <summary>
        /// 设置值4
        /// </summary>
        public string OPTION_4 { get; set; }
        /// <summary>
        /// 设置值5
        /// </summary>
        public string OPTION_5 { get; set; }
        /// <summary>
        /// 备注
        /// </summary>
        public string REMARK { get; set; }
        [DisplayName("执行出错时,是否重置整个工序的操作(Y/N)")]
        public string NEED_RESET { get; set; }
        /// <summary>
        /// 设置值1
        /// </summary>
        [DisplayName("设置值1")]
        public string OPTION_1 { get; set; }
        /// <summary>
        /// 设置值2
        /// </summary>
        [DisplayName("设置值2")]
        public string OPTION_2 { get; set; }
        /// <summary>
        /// 设置值3
        /// </summary>
        [DisplayName("设置值3")]
        public string OPTION_3 { get; set; }
        /// <summary>
        /// 设置值4
        /// </summary>
        [DisplayName("设置值4")]
        public string OPTION_4 { get; set; }
        /// <summary>
        /// 设置值5
        /// </summary>
        [DisplayName("设置值5")]
        public string OPTION_5 { get; set; }
        /// <summary>
        /// 备注
        /// </summary>
        [DisplayName("备注")]
        public string REMARK { get; set; }
        #endregion
        #region 虚拟属性
@@ -154,6 +156,10 @@
            Enum1,
        }
        */
        /// <summary>
        /// 枚举:行为类型(0Normal默认行为|1Scan扫码验证|2Assy组装上料|3Test产品测试|4Audit产品抽检|5Print标签打印|6Package包装规则)
        /// </summary>
        public enum ACT_TYPEs
        {
            [Description("自定义行为")]
@@ -170,16 +176,6 @@
            Print = 5,
            [Description("包装规则")]
            Package = 6,
        }
        public enum DO_TYPEs
        {
            [Description("服务端方法")]
            ServerMethod,
            [Description("WebApi方法")]
            WebApi,
            [Description("存储过程")]
            StoredProcedure,
        }
        #endregion
Tiger.Model.Net/Entitys/MES/MES_WO_NODE_ACT.cs
@@ -98,10 +98,15 @@
        /// </summary>
        [DisplayName("是否设置才能下发生产(Y/N)")]
        public string NEED_SETUP { get; set; }
        /// <summary>
        /// 设置值1
        /// </summary>
        [DisplayName("设置值1")]
        /// <summary>
        /// 执行出错时,是否重置整个工序的操作(Y/N)
        /// </summary>
        [DisplayName("执行出错时,是否重置整个工序的操作(Y/N)")]
        public string NEED_RESET { get; set; }
        /// <summary>
        /// 设置值1
        /// </summary>
        [DisplayName("设置值1")]
        public string OPTION_1 { get; set; }
        /// <summary>
        /// 设置值2
Tiger.Model.Net/Entitys/MES/ParameterEntity/PositionParameter.cs
@@ -19,19 +19,57 @@
    public class SubmitInput : ApiInput
    {
        public int CurStep { get; set; }
        public string StepID { get; set; }
        /// <summary>
        /// 客户端显示的语言
        /// </summary>
        public string Locale {  get; set; }
        /// <summary>
        /// 当前操作的工步ID,如果未指定则留空
        /// </summary>
        public string CurStepID { get; set; }
        /// <summary>
        /// 当前扫描的内容,不限于条码
        /// </summary>
        public string SN { get; set; }
        /// <summary>
        /// 当前操作提交的不良代码,没有则留空
        /// </summary>
        public string DFT_CODE { get; set; }
        /// <summary>
        /// 当前操作需要提交的数据
        /// </summary>
        public string Data { get; set; }
    }
    public class SubmitOutput
    {
        /// <summary>
        /// 整个工序操作是否完成
        /// </summary>
        public bool IsFinished { get; set; }
        public int CurStep { get; set; }
        public string StepID { get; set; }
        /// <summary>
        /// 当前操作的工单
        /// </summary>
        public string CurWO { get; set; }
        /// <summary>
        /// 当前操作的工单批次
        /// </summary>
        public string CurBatch { get; set; }
        /// <summary>
        /// 当前操作的节点名称
        /// </summary>
        public string CurNode { get; set; }
        /// <summary>
        /// 如果当前节点为工序行为节点,则行为定义编码,否则留空
        /// </summary>
        public string StepActCode { get; set; }
        /// <summary>
        /// 下一个操作的工步ID
        /// </summary>
        public string NextStepID { get; set; }
        /// <summary>
        /// 当前操作返回的数据
        /// </summary>
        public object Data { get; set; }
    }