服务端的TigerApi 框架,基于.NET6 2024 版本
Rodney Chen
2024-07-30 0c2a5ba3e7e2334f1cd69a66cc60cc0be0e4129c
包装工序功能以及一些一直问题的优化
已修改15个文件
已添加2个文件
1207 ■■■■ 文件已修改
Tiger.Api/Controllers/Test/TestController.R.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Api/Language.db 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Business.MES/Transaction/CollectNode.cs 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Business.MES/Transaction/PackingNode.cs 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Business.MES/Transaction/TestNode.cs 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Business.MES/WorkAction/PackingAction.cs 536 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.IBusiness/MES/WorkAction/IPackingAction.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Model.Net/Entitys/BAS/BAS_PKG_DTL.cs 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Model.Net/Entitys/BAS/BAS_PKG_RULE.cs 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Model.Net/Entitys/MES/MES_PROD_ACTION.cs 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Model.Net/Entitys/MES/MES_PROD_OPER.cs 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Model.Net/Entitys/MES/MES_WIP_DATA.cs 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Model.Net/Entitys/MES/MES_WIP_HIS.cs 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Model.Net/Entitys/MES/MES_WIP_PKG.cs 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Model.Net/Entitys/MES/MES_WO_ACTION.cs 184 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Model.Net/Entitys/MES/MES_WO_OPER.cs 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Model.Net/Entitys/MES/ParameterEntity/PositionParameter.cs 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Tiger.Api/Controllers/Test/TestController.R.cs
@@ -319,6 +319,17 @@
            Logger.Default.Info($"{begin:mmssfff} completed");
            return Ok($"{begin:mmssfff} completed");
        }
        [HttpPost]
        public async Task<IActionResult> MESSubmitAsync([FromBody] ApiAction<SubmitInput> action)
        {
            var data = action.Data.Data;
            data?.ToString().JsonToObject<PackingActionInput>();
            var result = JsonConvert.DeserializeObject<PackingActionInput>(data?.ToString() ?? "");
            return Ok(result?.ToJson());
        }
    }
    /// <summary>
Tiger.Api/Language.db
Binary files differ
Tiger.Business.MES/Transaction/CollectNode.cs
@@ -126,9 +126,9 @@
                                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;
                                result.Data.CurNode = CurStep?.NodeAct.ACT_NAME;
                                result.Data.StepActCode = CurStep?.NodeAct.ACT_CODE;
                                result.Data.NextStepID = CurStep?.ID;
                            }
                        }
                        //如果所有工步都完成
@@ -273,7 +273,7 @@
                    };
                    Steps.Add(curStep);
                    //有需要则添加工序节点的其他工步
                    //有需要用户提交信息则添加工序节点的其他工步
                    //最后添加当前工序的行为工步
                    GenerateSteps(curStep);
@@ -306,7 +306,7 @@
                        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.CurNode = CurStep?.Node.NODE_NAME;
                        result.Data.NextStepID = next.ID;
                        //根据工序节点工步的序号返回相应的操作提示
@@ -333,7 +333,7 @@
                    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.CurNode = CurStep?.Node.NODE_NAME;
                    action.Data.NextStepID = "";
                    action = DoIfFinishAllSteps(action);
                }
Tiger.Business.MES/Transaction/PackingNode.cs
@@ -126,9 +126,9 @@
                                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;
                                result.Data.CurNode = CurStep?.NodeAct.ACT_NAME;
                                result.Data.StepActCode = CurStep?.NodeAct.ACT_CODE;
                                result.Data.NextStepID = CurStep?.ID;
                            }
                        }
                        //如果所有工步都完成
@@ -273,7 +273,7 @@
                    };
                    Steps.Add(curStep);
    
                    //有需要则添加工序节点的其他工步
                    //有需要用户提交信息则添加工序节点的其他工步
    
                    //最后添加当前工序的行为工步
                    GenerateSteps(curStep);
@@ -306,15 +306,15 @@
                        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.CurNode = CurStep?.Node.NODE_NAME;
                        result.Data.NextStepID = next.ID;
                        //根据工序节点工步的序号返回相应的操作提示
                        switch (next.Sequence)
                        {
                            case 2:
                                //action.LocaleMsg = new($"请执行第二步");
                                result.LocaleMsg = new("MES.Transaction.PackingNode.第二步操作提示");
                                result.LocaleMsg = new("MES.Transaction.CollectNode.第二步操作提示");
                                break;
                            default:
                                break;
@@ -333,7 +333,7 @@
                    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.CurNode = CurStep?.Node.NODE_NAME;
                    action.Data.NextStepID = "";
                    action = DoIfFinishAllSteps(action);
                }
Tiger.Business.MES/Transaction/TestNode.cs
@@ -127,9 +127,9 @@
                                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;
                                result.Data.CurNode = CurStep?.NodeAct.ACT_NAME;
                                result.Data.StepActCode = CurStep?.NodeAct.ACT_CODE;
                                result.Data.NextStepID = CurStep?.ID;
                            }
                        }
                        //如果所有工步都完成
@@ -274,7 +274,7 @@
                    };
                    Steps.Add(curStep);
                    //有需要则添加工序节点的其他工步
                    //有需要用户提交信息则添加工序节点的其他工步
                    //最后添加当前工序的行为工步
                    GenerateSteps(curStep);
@@ -307,7 +307,7 @@
                        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.CurNode = CurStep?.Node.NODE_NAME;
                        result.Data.NextStepID = next.ID;
                        //根据工序节点工步的序号返回相应的操作提示
@@ -334,7 +334,7 @@
                    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.CurNode = CurStep?.Node.NODE_NAME;
                    action.Data.NextStepID = "";
                    action = DoIfFinishAllSteps(action);
                }
Tiger.Business.MES/WorkAction/PackingAction.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,536 @@
using Rhea.Common;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tiger.IBusiness;
using Tiger.Model;
using Tiger.Model.Entitys.MES.Position;
namespace Tiger.Business.MES.WorkAction
{
    public class PackingAction : IPackingAction
    {
        #region Propertys & Variables
        #region å›ºå®šå†™æ³•,工序中的必要信息
        public bool IsFinished { get; set; } = false;
        public IWorkStep CurStep { get; set; }
        public IPosition CurPosition { get; set; }
        public MES_WO_NODE_ACT NodeAct { get; set; }
        public MES_WO_ACTION Setting { get; set; }
        #endregion
        public BAS_PKG_RULE PkgRule { get; set; }
        public WipPkg CurPkg { get; set; }
        public WipPkgItem CurPkgItem { get; set; }
        public PackingActionOutput CurPrint { get; set; }
        public int PrintTimes = 0;
        public Dictionary<int, BAS_LABEL_TEMP> LabelDic { get; set; }
        public List<BAS_LABEL_PV> LabelPV { get; set; }
        public int FinishLevel = 0;
        #endregion Propertys & Variables
        #region Functions
        /// <summary>
        /// åˆå§‹åŒ–工序行为
        /// </summary>
        /// <returns></returns>
        public void Init(IWorkStep curStep, IPosition position, MES_WO_NODE_ACT nodeAct, MES_WO_ACTION setting)
        {
            #region å›ºå®šå†™æ³•,给默认变量赋值
            CurStep = curStep;
            CurPosition = position;
            NodeAct = nodeAct;
            Setting = setting;
            #endregion
            PkgRule = Biz.Db.Queryable<BAS_PKG_RULE>().Where(q => q.RULE_CODE == setting.PKG_CODE).IncludesAllFirstLayer().IncludesAllSecondLayer(q => q.Details).First();
            //根据行为设置获取多层包装的标签打印模板字典
            for (int i = 1; i < 10; i++)
            {
                var code = Setting.GetType().GetProperty($"OPTION_{i}")?.GetValue(Setting).ToString() ?? "";
                var label = code.IsNullOrEmpty() ? null : Biz.Db.Queryable<BAS_LABEL_TEMP>().Where(q => q.LABEL_CODE == code).IncludesAllFirstLayer().First();
                LabelDic.Add(i, label);
            }
            //如果工序上下文中没有包装记录则新建一个,有则获取当前的包装记录
            if (CurPosition.Context.ContainsKey("CurPackage") && !CurPosition.Context["CurPackage"].IsNullOrEmpty())
            {
                CurPkg = (CurPosition.Context["CurPackage"] as WipPkg).Clone();
            }
            else
            {
                var max = PkgRule.Details.OrderByDescending(q => q.PKG_LEVEL).First();
                CurPkg = new WipPkg()
                {
                    RULE_CODE = PkgRule.RULE_CODE,
                    RULE_NAME = PkgRule.RULE_NAME,
                    Item = new WipPkgItem()
                    {
                        PKG_CODE = max.PKG_CODE,
                        PKG_NAME = max.PkgType.PKG_NAME,
                        IS_MIN_PKG = max.PkgType.IS_MIN_PKG,
                        PKG_LEVEL = max.PKG_LEVEL,
                        PKG_QTY = max.PKG_QTY,
                        LABEL_CODE = LabelDic[max.PKG_LEVEL].LABEL_CODE,
                    }
                };
                WipPkgItem child = null;
                foreach (var dtl in PkgRule.Details.OrderBy(q => q.PKG_LEVEL))
                {
                    if (1 < dtl.PKG_LEVEL && dtl.PKG_LEVEL < max.PKG_LEVEL)
                    {
                        var item = new WipPkgItem()
                        {
                            PKG_CODE = dtl.PKG_CODE,
                            PKG_NAME = dtl.PkgType.PKG_NAME,
                            IS_MIN_PKG = dtl.PkgType.IS_MIN_PKG,
                            PKG_LEVEL = dtl.PKG_LEVEL,
                            PKG_QTY = dtl.PKG_QTY,
                            LABEL_CODE = LabelDic[dtl.PKG_LEVEL].LABEL_CODE,
                        };
                        if (!child.IsNullOrEmpty())
                        {
                            item.Items.Add(child);
                        }
                        child = item;
                    }
                }
                CurPkg.Item.Items.Add(child);
            }
        }
        /// <summary>
        /// èŽ·å–è¡Œä¸ºå¼€å§‹çš„æç¤ºä¿¡æ¯
        /// </summary>
        /// <returns></returns>
        public Locale GetBeginMsg()
        {
            var min = PkgRule.Details.OrderBy(q => q.PKG_LEVEL).First();
            //行为设定的OPTION_1是第一层包装的标签模板代码,如果为空则不需要打印
            if (LabelDic[min.PKG_LEVEL].IsNullOrEmpty())
            {
                var msg = new Locale("MES.WorkAction.PackingAction.BeginMsg", min.PKG_LEVEL, min.PkgType.PKG_NAME, CurPosition.CurWipSN.SN);
                //var msg = new Locale($"已扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码[{CurPosition.CurWipSN.SN}]");
                return msg;
            }
            else
            {
                var msg = new Locale("MES.WorkAction.PackingAction.BeginPrint", min.PKG_LEVEL, min.PkgType.PKG_NAME, LabelDic[min.PKG_LEVEL].LABEL_CODE, LabelDic[min.PKG_LEVEL].LABEL_NAME);
                //var msg = new Locale($"开始打印第{min.PKG_LEVEL}层包装[{min.PkgType.PKG_NAME}]的标签[{LabelDic[min.PKG_LEVEL].LABEL_CODE}: {LabelDic[min.PKG_LEVEL].LABEL_NAME}]");
                return msg;
            }
        }
        /// <summary>
        /// å°è¯•开始执行工序行为
        /// </summary>
        /// <returns></returns>
        public ApiAction<SubmitOutput> TryBegin(SubmitInput input)
        {
            var action = new ApiAction<SubmitOutput>(new SubmitOutput());
            action.LocaleMsg = GetBeginMsg();
            var min = PkgRule.Details.OrderBy(q => q.PKG_LEVEL).First();
            //行为设定的OPTION_1-9是包装不同层级的标签模板代码,如果为空则不需要打印
            if (LabelDic[min.PKG_LEVEL].IsNullOrEmpty())
            {
                input.Data = new PackingActionInput()
                {
                    ExecCode = "Scan",
                    IsFinish = true,
                    PkgLevel = min.PKG_LEVEL,
                    PkgSN = CurPosition.CurWipSN.SN,
                }.ToJson();
                action = Submit(input);
            }
            else
            {
                //设置打印变量值
                LabelDic[min.PKG_LEVEL] = CurPosition.SetLabelVariables(LabelPV, LabelDic[min.PKG_LEVEL]);
                var data = new PackingActionOutput() { PkgInfo = CurPkg };
                data.ExecCode = "Print";
                data.PkgLevel = min.PKG_LEVEL;
                data.PrintLable = LabelDic[min.PKG_LEVEL];
                CurPrint = data;
                PrintTimes++;
                action.Data.Data = data;
                //action.LocaleMsg = new Locale($"开始第{PrintTimes}次打印第{min.PKG_LEVEL}层包装[{min.PkgType.PKG_NAME}]的标签[{LabelDic[min.PKG_LEVEL].LABEL_CODE}: {LabelDic[min.PKG_LEVEL].LABEL_NAME}]");
                action.LocaleMsg = new Locale("MES.WorkAction.PackingAction.BeginPrint", PrintTimes, min.PKG_LEVEL, min.PkgType.PKG_NAME, LabelDic[min.PKG_LEVEL].LABEL_CODE, LabelDic[min.PKG_LEVEL].LABEL_NAME);
            }
            //如果返回成功则认为当前行为可以开始执行,否则返回失败
            action.IsSuccessed = true;
            return action;
        }
        /// <summary>
        /// å·¥åºè¡Œä¸ºæäº¤æ•°æ®
        /// </summary>
        /// <returns></returns>
        public ApiAction<SubmitOutput> Submit(SubmitInput input)
        {
            var action = new ApiAction<SubmitOutput>(new SubmitOutput());
            var pInput = input.Data?.JsonToObject<PackingActionInput>();
            switch (pInput.ExecCode)
            {
                //Scan:扫码,扫描当前包装层级的条码
                case "Scan":
                    {
                        //客户端扫描成功
                        if (pInput.IsFinish)
                        {
                            action = SavePkgData(input, action);
                        }
                        //客户端扫描失败
                        else
                        {
                            var dtl = PkgRule.Details.First(q => q.PKG_LEVEL == pInput.PkgLevel);
                            action.IsSuccessed = false;
                            //action.LocaleMsg = new($"条码扫描失败,请重新扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码");
                            action.LocaleMsg = new("MES.WorkAction.PackingAction.ScanFail", dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME);
                            return action;
                        }
                    }
                    break;
                //Print:打印,打印当前包装层级的标签
                case "Print":
                    {
                        var dtl = PkgRule.Details.First(q => q.PKG_LEVEL == pInput.PkgLevel);
                        //客户端完成打印
                        if (pInput.IsFinish)
                        {
                            CurPrint = null;
                            PrintTimes = 0;
                            var data = new PackingActionOutput() { PkgInfo = CurPkg };
                            data.ExecCode = "Scan";
                            data.PkgLevel = dtl.PKG_LEVEL;
                            action.Data.Data = data;
                            //action.LocaleMsg = new($"请扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码");
                            action.LocaleMsg = new("MES.WorkAction.PackingAction.PleaseScanLabel", dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME);
                        }
                        //客户端打印失败
                        else
                        {
                            //如果打印失败则尝试三次重新打印,如果都失败则重置工序
                            if (PrintTimes < 3 && !CurPrint.IsNullOrEmpty())
                            {
                                PrintTimes++;
                                action.Data.Data = CurPrint;
                                //action.LocaleMsg = new Locale($"开始{PrintTimes}次打印第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签[{LabelDic[dtl.PKG_LEVEL].LABEL_CODE}: {LabelDic[dtl.PKG_LEVEL].LABEL_NAME}]");
                                action.LocaleMsg = new Locale("MES.WorkAction.PackingAction.BeginPrint", PrintTimes, dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME, LabelDic[dtl.PKG_LEVEL].LABEL_CODE, LabelDic[dtl.PKG_LEVEL].LABEL_NAME);
                            }
                            else
                            {
                                CurPrint = null;
                                PrintTimes = 0;
                                action.IsSuccessed = false;
                                //action.LocaleMsg = new($"尝试第{PrintTimes}次打印第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签[{LabelDic[dtl.PKG_LEVEL].LABEL_CODE}: {LabelDic[dtl.PKG_LEVEL].LABEL_NAME}]失败,工序已重置,请重新扫描进站产品条码");
                                action.LocaleMsg = new("MES.WorkAction.PackingAction.PrintFail3Times", PrintTimes, dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME, LabelDic[dtl.PKG_LEVEL].LABEL_CODE, LabelDic[dtl.PKG_LEVEL].LABEL_NAME);
                                CurPosition.ResetSteps();
                            }
                        }
                    }
                    break;
                // Complete:完成,完成全部包装后结束行为
                case "Complete":
                    {
                        action = End();
                    }
                    break;
                default:
                    break;
            }
            //如果行为设置为出错需要重置工序操作
            if (!action.IsSuccessed && NodeAct.NEED_RESET == "Y")
            {
                CurPosition.ResetSteps();
            }
            return action;
        }
        //保存包装信息
        public ApiAction<SubmitOutput> SavePkgData(SubmitInput input, ApiAction<SubmitOutput> action)
        {
            var pInput = input.Data?.JsonToObject<PackingActionInput>();
            try
            {
                //正在处理的包装层级明细
                var dtl = PkgRule.Details.First(q => q.PKG_LEVEL == FinishLevel + 1);
                //没有保存过任何包装层级的数据,则先处理最小包装数据
                if (FinishLevel == 0)
                {
                    CurPkgItem = new WipPkgItem()
                    {
                        PKG_CODE = dtl.PKG_CODE,
                        PKG_NAME = dtl.PkgType.PKG_NAME,
                        IS_MIN_PKG = dtl.PkgType.IS_MIN_PKG,
                        PKG_LEVEL = dtl.PKG_LEVEL,
                        PKG_QTY = dtl.PKG_QTY,
                        LABEL_CODE = LabelDic[dtl.PKG_LEVEL].LABEL_CODE,
                        IsFinished = true,
                        Package = new()
                        {
                            AUTH_ORG = CurPosition.WorkBatch.WO.AUTH_ORG,
                            AUTH_PROD = CurPosition.CurLine.LINE_CODE,
                            SN = pInput.PkgSN,
                            PKG_TYPE = dtl.PkgType.PKG_NAME,
                            ITEM_CODE = CurPosition.CurWipSN.ITEM_CODE,
                            QTY = CurPosition.CurWipSN.QTY,
                            UNIT = dtl.PkgType.PKG_NAME,
                            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,
                            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,
                        }
                    };
                    FinishLevel++;
                    action = SavePkgData(input, action);
                }
                //处理其他包装层级数据
                else
                {
                    //客户端提交的包装层级等于当前处理的包装层级
                    if (pInput.PkgLevel == dtl.PKG_LEVEL)
                    {
                        CurPkgItem.IsFinished = true;
                        CurPkgItem.Package = new()
                        {
                            AUTH_ORG = CurPosition.WorkBatch.WO.AUTH_ORG,
                            AUTH_PROD = CurPosition.CurLine.LINE_CODE,
                            SN = pInput.PkgSN,
                            PKG_TYPE = dtl.PkgType.PKG_NAME,
                            ITEM_CODE = CurPosition.CurWipSN.ITEM_CODE,
                            QTY = CurPkgItem.Items.Sum(q => q.Package.QTY),
                            UNIT = dtl.PkgType.PKG_NAME,
                            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,
                            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,
                        };
                        FinishLevel++;
                        //完成包装的层级小于最外层包装层级
                        if (FinishLevel < PkgRule.Details.Max(q => q.PKG_LEVEL))
                        {
                            //当前处理的包装层级已经处理完,继续往上保存
                            action = SavePkgData(input, action);
                        }
                        //最外层包装已经完成包装,保存包装数据到数据库
                        else
                        {
                            action = SaveToDB();
                        }
                    }
                    //当前处理的包装层级已经处理完,继续往上保存
                    else if (pInput.PkgLevel == FinishLevel)
                    {
                        //获取当前的包装明细的上一层包装对象
                        WipPkgItem curItem = CurPkg.Item;
                        while (curItem.PKG_LEVEL > dtl.PKG_LEVEL)
                        {
                            var next = curItem.Items.FirstOrDefault(q => !q.IsFinished);
                            if (next.IsNullOrEmpty())
                            {
                                var nextDtl = PkgRule.Details.First(q => q.PKG_LEVEL == curItem.PKG_LEVEL - 1);
                                next = new WipPkgItem()
                                {
                                    PKG_CODE = nextDtl.PKG_CODE,
                                    PKG_NAME = nextDtl.PkgType.PKG_NAME,
                                    IS_MIN_PKG = nextDtl.PkgType.IS_MIN_PKG,
                                    PKG_LEVEL = nextDtl.PKG_LEVEL,
                                    PKG_QTY = nextDtl.PKG_QTY,
                                    LABEL_CODE = LabelDic[nextDtl.PKG_LEVEL].LABEL_CODE,
                                };
                                curItem.Items.Add(next);
                            }
                            curItem = next;
                        }
                        //添加当前的包装明细到上一层包装的明细列表
                        curItem.Items.Add(CurPkgItem);
                        CurPkgItem = curItem;
                        //添加明细后判断当前包装层级的明细数量是否等于包装数量,若相等则标记当前包装层级为完成并尝试打印标签
                        if (CurPkgItem.Items.Count == CurPkgItem.PKG_QTY)
                        {
                            //行为设定的OPTION_1-9是包装不同层级的标签模板代码,如果为空则不需要打印
                            if (LabelDic[dtl.PKG_LEVEL].IsNullOrEmpty())
                            {
                                var data = new PackingActionOutput() { PkgInfo = CurPkg };
                                data.ExecCode = "Scan";
                                data.PkgLevel = dtl.PKG_LEVEL;
                                action.Data.Data = data;
                                //action.LocaleMsg = new($"请扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码");
                                action.LocaleMsg = new("MES.WorkAction.PackingAction.PleaseScanLabel", dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME);
                            }
                            else
                            {
                                //设置打印变量值
                                LabelDic[dtl.PKG_LEVEL] = CurPosition.SetLabelVariables(LabelPV, LabelDic[dtl.PKG_LEVEL]);
                                var data = new PackingActionOutput() { PkgInfo = CurPkg };
                                data.ExecCode = "Print";
                                data.PkgLevel = dtl.PKG_LEVEL;
                                data.PrintLable = LabelDic[dtl.PKG_LEVEL];
                                CurPrint = data;
                                PrintTimes++;
                                action.Data.Data = data;
                                //action.LocaleMsg = new Locale($"开始第{PrintTimes}次打印第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签[{LabelDic[dtl.PKG_LEVEL].LABEL_CODE}: {LabelDic[dtl.PKG_LEVEL].LABEL_NAME}]");
                                action.LocaleMsg = new Locale("MES.WorkAction.PackingAction.BeginPrint", PrintTimes, dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME, LabelDic[dtl.PKG_LEVEL].LABEL_CODE, LabelDic[dtl.PKG_LEVEL].LABEL_NAME);
                            }
                        }
                        //当前包装层级的明细数量未达到包装数量,则完成本次扫描,等待下个产品进站
                        else
                        {
                            action = End();
                        }
                    }
                    //数据异常
                    else
                    {
                        var pdtl = PkgRule.Details.First(q => q.PKG_LEVEL == pInput.PkgLevel);
                        action.IsSuccessed = false;
                        //action.LocaleMsg = new($"客户端提交的包装层级[{pdtl.PKG_LEVEL}]({pdtl.PkgType.PKG_NAME})数据不是正在处理的包装层级[{dtl.PKG_LEVEL}]({dtl.PkgType.PKG_NAME}),工序已重置,请重新扫描进站产品条码");
                        action.LocaleMsg = new("MES.WorkAction.PackingAction.SaveLevelNotMatchException", pdtl.PKG_LEVEL, pdtl.PkgType.PKG_NAME, dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME);
                        CurPosition.ResetSteps();
                    }
                }
            }
            catch (System.Exception ex)
            {
                var dtl = PkgRule.Details.First(q => q.PKG_LEVEL == pInput.PkgLevel);
                action.CatchExceptionWithLog(ex, $"包装行为:扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码[{input.SN}]后保存数据失败");
                action.IsSuccessed = false;
                //action.LocaleMsg = new($"扫描第{dtl.PKG_LEVEL}层包装[{dtl.PkgType.PKG_NAME}]的标签条码[{input.SN}]后保存数据失败,工序已重置,请重新扫描进站产品条码");
                action.LocaleMsg = new("MES.WorkAction.PackingAction.SavePkgDataException", dtl.PKG_LEVEL, dtl.PkgType.PKG_NAME, input.SN);
                CurPosition.ResetSteps();
            }
            return action;
        }
        private List<MES_WIP_PKG> GetPackageList(WipPkgItem parent)
        {
            List<MES_WIP_PKG> list = new() { parent.Package };
            foreach (var item in parent.Items)
            {
                item.Package.PARENT_SN = parent.Package.SN;
                list.AddRange(GetPackageList(item));
            }
            return list;
        }
        public ApiAction<SubmitOutput> SaveToDB()
        {
            var action = new ApiAction<SubmitOutput>(new SubmitOutput());
            var pkgList = GetPackageList(CurPkg.Item);
            //保存数据库
            var db = Biz.Db;
            var dbTran = db.UseTran(() =>
            {
                db.Insertable(pkgList, CurPosition.UserCode).ExecuteCommand();
            });
            if (!dbTran.IsSuccess)
            {
                throw dbTran.ErrorException;
            }
            //删除工序上下文中的包装记录
            CurPosition.Context.Remove("CurPackage");
            var data = new PackingActionOutput() { PkgInfo = CurPkg };
            data.ExecCode = "Complete";
            data.PkgLevel = CurPkg.Item.PKG_LEVEL;
            action.Data.Data = data;
            //action.LocaleMsg = new($"第{CurPkg.Item.PKG_LEVEL}层包装[{CurPkg.Item.PKG_NAME}]已经全部完成,保存包装数据");
            action.LocaleMsg = new("MES.WorkAction.PackingAction.PackageComplete", CurPkg.Item.PKG_LEVEL, CurPkg.Item.PKG_NAME);
            return action;
        }
        /// <summary>
        /// ç»“束执行工序行为
        /// </summary>
        /// <returns></returns>
        public ApiAction<SubmitOutput> End()
        {
            var action = new ApiAction<SubmitOutput>(new SubmitOutput());
            //记录行为操作记录
            var wipAct = new MES_WIP_ACT()
            {
                AUTH_ORG = CurPosition.WorkBatch.WO.AUTH_ORG,
                AUTH_PROD = CurPosition.CurLine.LINE_CODE,
                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_RESULT = "Y",
                TRACE_INFO = $"产品条码[{CurPosition.CurWipSN.SN}]包装完成",
            };
            //保存数据
            CurStep.DBSubmitAction = () =>
            {
                var db = CurPosition.GetCommitDB();
                db.Storageable(wipAct, CurPosition.UserCode).ExecuteCommand();
            };
            //如果工序上下文中没有包装记录则新建一个
            if (CurPosition.Context.ContainsKey("CurPackage"))
            {
                CurPosition.Context["CurPackage"] = CurPkg;
            }
            else
            {
                CurPosition.Context.Add("CurPackage", CurPkg);
            }
            IsFinished = true;
            action.LocaleMsg = new($"产品条码[{CurPosition.CurWipSN.SN}]包装完成");
            action.LocaleMsg = new("MES.WorkAction.PackingAction.PackingSuccess", CurPosition.CurWipSN.SN);
            return action;
        }
        #endregion Functions
    }
}
Tiger.IBusiness/MES/WorkAction/IPackingAction.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
using Newtonsoft.Json;
using Rhea.Common;
using System;
using Tiger.Model;
namespace Tiger.IBusiness
{
    public interface IPackingAction : IWorkAction
    {
    }
}
Tiger.Model.Net/Entitys/BAS/BAS_PKG_DTL.cs
@@ -46,17 +46,17 @@
        /// å¤‡æ³¨
        /// </summary>
        public string REMARK { get; set; }
        #endregion
        #endregion
        #region è™šæ‹Ÿå±žæ€§
        /*例子
        #region è™šæ‹Ÿå±žæ€§
        /*例子
        [SugarColumn(IsIgnore = true)]
        public string FieldName { get; set; }
        */
        #endregion
        #endregion
        #region å¤–键属性
        /*例子
        #region å¤–键属性
        /*例子
        //一对一外键导航
        [Navigate(NavigateType.OneToOne, nameof(ClassAId))]//一对一 ClassAId是BAS_PKG_DTL类里面的外键ID字段
        public ClassA ClassA { get; set; } //注意禁止手动赋值,只能是null
@@ -67,10 +67,12 @@
        [Navigate(typeof(MappingClass), nameof(MappingClass.BAS_PKG_DTLId), nameof(MappingClass.ClassAId))]//注意顺序
        public List<ClassA> ClassAList { get; set; } //注意禁止手动赋值,只能是null
        */
        #endregion
        [Navigate(NavigateType.OneToOne, nameof(PKG_CODE), nameof(BAS_PKG_TYPE.PKG_CODE), "GHOST_ROW = 0")]//一对一 ClassAId是BIZ_MES_WO类里面的外键ID字段
        public BAS_PKG_TYPE PkgType { get; set; } //注意禁止手动赋值,只能是null
        #endregion
        #region æžšä¸¾å˜é‡
        /*例子
        #region æžšä¸¾å˜é‡
        /*例子
        public enum FieldNames
        {
            [Description("枚举描述0")]
@@ -79,11 +81,11 @@
            Enum1,
        }
        */
        #endregion
        #endregion
        #region å…¬å…±æ–¹æ³•
        #region å…¬å…±æ–¹æ³•
        #endregion
        #endregion
    }//endClass
    }//endClass
}
Tiger.Model.Net/Entitys/BAS/BAS_PKG_RULE.cs
@@ -7,75 +7,77 @@
namespace Tiger.Model
{
    /// <summary>
    /// å®žä½“:包装规则定义
    /// å®žä½“:包装规则定义
    /// </summary>
    [Description("Primary:ID")]
    [Serializable]
    [SugarTable("BAS_PKG_RULE")]
    public class BAS_PKG_RULE : DbEntityWithAuth
    {
        #region æž„造函数
        #region æž„造函数
        /// <summary>
        /// å®žä½“:包装规则定义
        /// å®žä½“:包装规则定义
        /// </summary>
        public BAS_PKG_RULE() {}
        #endregion
        #region å…¬å…±å±žæ€§
        #region å…¬å…±å±žæ€§
        /// <summary>
        /// åŒ…装规则编码
        /// åŒ…装规则编码
        /// </summary>
        public string RULE_CODE { get; set; }
        /// <summary>
        /// åŒ…装规则名称
        /// åŒ…装规则名称
        /// </summary>
        public string RULE_NAME { get; set; }
        /// <summary>
        /// æ˜¯å¦å¯ç”¨(Y/N)
        /// æ˜¯å¦å¯ç”¨(Y/N)
        /// </summary>
        public string IS_ACTIVE { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// å¤‡æ³¨
        /// </summary>
        public string REMARK { get; set; }
        #endregion
        #endregion
        #region è™šæ‹Ÿå±žæ€§
        /*例子
        #region è™šæ‹Ÿå±žæ€§
        /*例子
        [SugarColumn(IsIgnore = true)]
        public string FieldName { get; set; }
        */
        #endregion
        #endregion
        #region å¤–键属性
        /*例子
        //一对一外键导航
        [Navigate(NavigateType.OneToOne, nameof(ClassAId))]//一对一 ClassAId是BAS_PKG_RULE类里面的外键ID字段
        public ClassA ClassA { get; set; } //注意禁止手动赋值,只能是null
        //一对多外键导航
        [Navigate(NavigateType.OneToMany, nameof(ClassA.BAS_PKG_RULEId))]//ClassA表中的BAS_PKG_RULEId
        public List<ClassA> ClassAList { get; set; }//注意禁止手动赋值,只能是null
        //多对多外键导航
        [Navigate(typeof(MappingClass), nameof(MappingClass.BAS_PKG_RULEId), nameof(MappingClass.ClassAId))]//注意顺序
        public List<ClassA> ClassAList { get; set; } //注意禁止手动赋值,只能是null
        #region å¤–键属性
        /*例子
        //一对一外键导航
        [Navigate(NavigateType.OneToOne, nameof(ClassAId))]//一对一 ClassAId是BAS_PKG_RULE类里面的外键ID字段
        public ClassA ClassA { get; set; } //注意禁止手动赋值,只能是null
        //一对多外键导航
        [Navigate(NavigateType.OneToMany, nameof(ClassA.BAS_PKG_RULEId))]//ClassA表中的BAS_PKG_RULEId
        public List<ClassA> ClassAList { get; set; }//注意禁止手动赋值,只能是null
        //多对多外键导航
        [Navigate(typeof(MappingClass), nameof(MappingClass.BAS_PKG_RULEId), nameof(MappingClass.ClassAId))]//注意顺序
        public List<ClassA> ClassAList { get; set; } //注意禁止手动赋值,只能是null
        */
        #endregion
        [Navigate(NavigateType.OneToMany, nameof(BAS_PKG_DTL.PKG_RULE_ID), nameof(ID), "GHOST_ROW = 0")]//ClassA表中的BAS_LABEL_TEMPId
        public List<BAS_PKG_DTL> Details { get; set; }//注意禁止手动赋值,只能是null
        #endregion
        #region æžšä¸¾å˜é‡
        /*例子
        #region æžšä¸¾å˜é‡
        /*例子
        public enum FieldNames
        {
            [Description("枚举描述0")]
            [Description("枚举描述0")]
            Enum0,
            [Description("枚举描述1")]
            [Description("枚举描述1")]
            Enum1,
        }
        */
        #endregion
        #endregion
        #region å…¬å…±æ–¹æ³•
        #region å…¬å…±æ–¹æ³•
        #endregion
        #endregion
    }//endClass
    }//endClass
}
Tiger.Model.Net/Entitys/MES/MES_PROD_ACTION.cs
@@ -93,10 +93,15 @@
        /// </summary>
        [DisplayName("是否启用(Y/N)")]
        public string IS_ACTIVE { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼1
        /// </summary>
        [DisplayName("设置值1")]
        /// <summary>
        /// æ˜¯å¦è®¾ç½®å®Œæˆ(Y/N)
        /// </summary>
        [DisplayName("是否设置完成(Y/N)")]
        public string SETUP_FINISH { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼1
        /// </summary>
        [DisplayName("设置值1")]
        public string OPTION_1 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼2
@@ -118,15 +123,30 @@
        /// </summary>
        [DisplayName("设置值5")]
        public string OPTION_5 { get; set; }
        /// <summary>
        /// æ˜¯å¦è®¾ç½®å®Œæˆ(Y/N)
        /// </summary>
        [DisplayName("是否设置完成(Y/N)")]
        public string SETUP_FINISH { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [DisplayName("备注")]
        /// <summary>
        /// è®¾ç½®å€¼6
        /// </summary>
        [DisplayName("设置值6")]
        public string OPTION_6 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼7
        /// </summary>
        [DisplayName("设置值7")]
        public string OPTION_7 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼8
        /// </summary>
        [DisplayName("设置值8")]
        public string OPTION_8 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼9
        /// </summary>
        [DisplayName("设置值9")]
        public string OPTION_9 { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [DisplayName("备注")]
        public string REMARK { get; set; }
        #endregion
Tiger.Model.Net/Entitys/MES/MES_PROD_OPER.cs
@@ -108,10 +108,30 @@
        /// </summary>
        [DisplayName("设置值5")]
        public string OPTION_5 { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [DisplayName("备注")]
        /// <summary>
        /// è®¾ç½®å€¼6
        /// </summary>
        [DisplayName("设置值6")]
        public string OPTION_6 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼7
        /// </summary>
        [DisplayName("设置值7")]
        public string OPTION_7 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼8
        /// </summary>
        [DisplayName("设置值8")]
        public string OPTION_8 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼9
        /// </summary>
        [DisplayName("设置值9")]
        public string OPTION_9 { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [DisplayName("备注")]
        public string REMARK { get; set; }
        #endregion
Tiger.Model.Net/Entitys/MES/MES_WIP_DATA.cs
@@ -38,10 +38,15 @@
        /// </summary>
        [DisplayName("物料编码")]
        public string ITEM_CODE { get; set; }
        /// <summary>
        /// å·¥å•号
        /// </summary>
        [DisplayName("工单号")]
        /// <summary>
        /// æ•°é‡
        /// </summary>
        [DisplayName("数量")]
        public double QTY { get; set; } = 1;
        /// <summary>
        /// å·¥å•号
        /// </summary>
        [DisplayName("工单号")]
        public string WORK_ORDER { get; set; }
        /// <summary>
        /// å·¥å•批次号
Tiger.Model.Net/Entitys/MES/MES_WIP_HIS.cs
@@ -37,6 +37,7 @@
            SN = data.SN;
            STATUS = data.STATUS;
            ITEM_CODE = data.ITEM_CODE;
            QTY = data.QTY;
            WORK_ORDER = data.WORK_ORDER;
            BATCH_NO = data.BATCH_NO;
            ROT_CODE = data.ROT_CODE;
@@ -93,10 +94,15 @@
        /// </summary>
        [DisplayName("物料编码")]
        public string ITEM_CODE { get; set; }
        /// <summary>
        /// å·¥å•号
        /// </summary>
        [DisplayName("工单号")]
        /// <summary>
        /// æ•°é‡
        /// </summary>
        [DisplayName("数量")]
        public double QTY { get; set; } = 1;
        /// <summary>
        /// å·¥å•号
        /// </summary>
        [DisplayName("工单号")]
        public string WORK_ORDER { get; set; }
        /// <summary>
        /// å·¥å•批次号
Tiger.Model.Net/Entitys/MES/MES_WIP_PKG.cs
@@ -7,168 +7,154 @@
namespace Tiger.Model
{
    /// <summary>
    /// å®žä½“:生产包装记录
    /// å®žä½“:生产包装记录
    /// </summary>
    [Description("Primary:ID")]
    [DisplayName("生产包装记录")]
    [DisplayName("生产包装记录")]
    [Serializable]
    [SugarTable("MES_WIP_PKG")]
    public class MES_WIP_PKG : DbEntityWithAuth
    {
        #region æž„造函数
        #region æž„造函数
        /// <summary>
        /// å®žä½“:生产包装记录
        /// å®žä½“:生产包装记录
        /// </summary>
        public MES_WIP_PKG() {}
        #endregion
        #region å…¬å…±å±žæ€§
        #region å…¬å…±å±žæ€§
        /// <summary>
        /// æ¡ç 
        /// æ¡ç 
        /// </summary>
        [DisplayName("条码")]
        [DisplayName("条码")]
        public string SN { get; set; }
        /// <summary>
        /// çˆ¶åŒ…装条码
        /// çˆ¶åŒ…装条码
        /// </summary>
        [DisplayName("父包装条码")]
        [DisplayName("父包装条码")]
        public string PARENT_SN { get; set; }
        /// <summary>
        /// åŒ…装类型(0OnePiece单件|1Container载具|2Cartonç®±|3Pallet栈板)
        /// åŒ…装类型
        /// </summary>
        [DisplayName("包装类型(0OnePiece单件|1Container载具|2Cartonç®±|3Pallet栈板)")]
        public int PKG_TYPE { get; set; }
        [DisplayName("包装类型")]
        public string PKG_TYPE { get; set; }
        /// <summary>
        /// ç‰©æ–™ç¼–码
        /// ç‰©æ–™ç¼–码
        /// </summary>
        [DisplayName("物料编码")]
        [DisplayName("物料编码")]
        public string ITEM_CODE { get; set; }
        /// <summary>
        /// æ•°é‡
        /// æ•°é‡
        /// </summary>
        [DisplayName("数量")]
        [DisplayName("数量")]
        public double QTY { get; set; }
        /// <summary>
        /// å•位
        /// å•位
        /// </summary>
        [DisplayName("单位")]
        [DisplayName("单位")]
        public string UNIT { get; set; }
        /// <summary>
        /// å·¥å•号
        /// å·¥å•号
        /// </summary>
        [DisplayName("工单号")]
        [DisplayName("工单号")]
        public string WORK_ORDER { get; set; }
        /// <summary>
        /// å·¥å•批次号
        /// å·¥å•批次号
        /// </summary>
        [DisplayName("工单批次号")]
        [DisplayName("工单批次号")]
        public string BATCH_NO { get; set; }
        /// <summary>
        /// å·¥è‰ºè·¯çº¿ç¼–码
        /// å·¥è‰ºè·¯çº¿ç¼–码
        /// </summary>
        [DisplayName("工艺路线编码")]
        [DisplayName("工艺路线编码")]
        public string ROT_CODE { get; set; }
        /// <summary>
        /// å·¥è‰ºè·¯çº¿èŠ‚ç‚¹ID
        /// å·¥è‰ºè·¯çº¿èŠ‚ç‚¹ID
        /// </summary>
        [DisplayName("工艺路线节点ID")]
        [DisplayName("工艺路线节点ID")]
        public string NODE_ID { get; set; }
        /// <summary>
        /// å·¥è‰ºè·¯çº¿èŠ‚ç‚¹åç§°
        /// å·¥è‰ºè·¯çº¿èŠ‚ç‚¹åç§°
        /// </summary>
        [DisplayName("工艺路线节点名称")]
        [DisplayName("工艺路线节点名称")]
        public string NODE_NAME { get; set; }
        /// <summary>
        /// å·¥åŽ‚ç¼–ç 
        /// å·¥åŽ‚ç¼–ç 
        /// </summary>
        [DisplayName("工厂编码")]
        [DisplayName("工厂编码")]
        public string FTY_CODE { get; set; }
        /// <summary>
        /// è½¦é—´ç¼–码
        /// è½¦é—´ç¼–码
        /// </summary>
        [DisplayName("车间编码")]
        [DisplayName("车间编码")]
        public string WS_CODE { get; set; }
        /// <summary>
        /// äº§çº¿ç¼–码
        /// äº§çº¿ç¼–码
        /// </summary>
        [DisplayName("产线编码")]
        [DisplayName("产线编码")]
        public string LINE_CODE { get; set; }
        /// <summary>
        /// å²—位编码
        /// å²—位编码
        /// </summary>
        [DisplayName("岗位编码")]
        [DisplayName("岗位编码")]
        public string POST_CODE { get; set; }
        /// <summary>
        /// å·¥åºç¼–码
        /// å·¥åºç¼–码
        /// </summary>
        [DisplayName("工序编码")]
        [DisplayName("工序编码")]
        public string OPER_CODE { get; set; }
        /// <summary>
        /// åŠ å·¥æ®µ
        /// åŠ å·¥æ®µ
        /// </summary>
        [DisplayName("加工段")]
        [DisplayName("加工段")]
        public string SEGMENT { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// å¤‡æ³¨
        /// </summary>
        [DisplayName("备注")]
        [DisplayName("备注")]
        public string REMARK { get; set; }
        /// <summary>
        /// è¿½æº¯ä¿¡æ¯
        /// è¿½æº¯ä¿¡æ¯
        /// </summary>
        [DisplayName("追溯信息")]
        [DisplayName("追溯信息")]
        public string TRACE_INFO { get; set; }
        #endregion
        #region è™šæ‹Ÿå±žæ€§
        /*例子
        #region è™šæ‹Ÿå±žæ€§
        /*例子
        [SugarColumn(IsIgnore = true)]
        public string FieldName { get; set; }
        */
        #endregion
        #region å¤–键属性
        /*例子
        //一对一外键导航
        [Navigate(NavigateType.OneToOne, nameof(ClassAId))]//一对一 ClassAId是MES_WIP_PKG类里面的外键ID字段
        public ClassA ClassA { get; set; } //注意禁止手动赋值,只能是null
        //一对多外键导航
        [Navigate(NavigateType.OneToMany, nameof(ClassA.MES_WIP_PKGId))]//ClassA表中的MES_WIP_PKGId
        public List<ClassA> ClassAList { get; set; }//注意禁止手动赋值,只能是null
        //多对多外键导航
        [Navigate(typeof(MappingClass), nameof(MappingClass.MES_WIP_PKGId), nameof(MappingClass.ClassAId))]//注意顺序
        public List<ClassA> ClassAList { get; set; } //注意禁止手动赋值,只能是null
        #region å¤–键属性
        /*例子
        //一对一外键导航
        [Navigate(NavigateType.OneToOne, nameof(ClassAId))]//一对一 ClassAId是MES_WIP_PKG类里面的外键ID字段
        public ClassA ClassA { get; set; } //注意禁止手动赋值,只能是null
        //一对多外键导航
        [Navigate(NavigateType.OneToMany, nameof(ClassA.MES_WIP_PKGId))]//ClassA表中的MES_WIP_PKGId
        public List<ClassA> ClassAList { get; set; }//注意禁止手动赋值,只能是null
        //多对多外键导航
        [Navigate(typeof(MappingClass), nameof(MappingClass.MES_WIP_PKGId), nameof(MappingClass.ClassAId))]//注意顺序
        public List<ClassA> ClassAList { get; set; } //注意禁止手动赋值,只能是null
        */
        #endregion
        #region æžšä¸¾å˜é‡
        /*例子
        #region æžšä¸¾å˜é‡
        /*例子
        public enum FieldNames
        {
            [Description("枚举描述0")]
            [Description("枚举描述0")]
            Enum0,
            [Description("枚举描述1")]
            [Description("枚举描述1")]
            Enum1,
        }
        */
        /// <summary>
        /// æžšä¸¾ï¼šåŒ…装类型(0OnePiece单件|1Container载具|2Cartonç®±|3Pallet栈板)
        /// </summary>
        public enum PKG_TYPEs
        {
            [Description("单件")]
            OnePiece = 0,
            [Description("载具")]
            Container = 1,
            [Description("ç®±")]
            Carton = 2,
            [Description("栈板")]
            Pallet = 3,
        }
        #endregion
        #region å…¬å…±æ–¹æ³•
        #region å…¬å…±æ–¹æ³•
        #endregion
Tiger.Model.Net/Entitys/MES/MES_WO_ACTION.cs
@@ -7,189 +7,209 @@
namespace Tiger.Model
{
    /// <summary>
    /// å®žä½“:工单工序行为
    /// å®žä½“:工单工序行为
    /// </summary>
    [Description("Primary:ID")]
    [DisplayName("工单工序行为")]
    [DisplayName("工单工序行为")]
    [Serializable]
    [SugarTable("MES_WO_ACTION")]
    public class MES_WO_ACTION : DbEntityWithAuth
    {
        #region æž„造函数
        #region æž„造函数
        /// <summary>
        /// å®žä½“:工单工序行为
        /// å®žä½“:工单工序行为
        /// </summary>
        public MES_WO_ACTION() {}
        #endregion
        #region å…¬å…±å±žæ€§
        #region å…¬å…±å±žæ€§
        /// <summary>
        /// å…³è”工单号
        /// å…³è”工单号
        /// </summary>
        [DisplayName("关联工单号")]
        [DisplayName("关联工单号")]
        public string WORK_ORDER { get; set; }
        /// <summary>
        /// äº§å“ç¼–码
        /// äº§å“ç¼–码
        /// </summary>
        [DisplayName("产品编码")]
        [DisplayName("产品编码")]
        public string PROD_CODE { get; set; }
        /// <summary>
        /// å®¢æˆ·ç¼–码(留空则不区分客户)
        /// å®¢æˆ·ç¼–码(留空则不区分客户)
        /// </summary>
        [DisplayName("客户编码(留空则不区分客户)")]
        [DisplayName("客户编码(留空则不区分客户)")]
        public string CUST_CODE { get; set; }
        /// <summary>
        /// å·¥è‰ºè·¯çº¿ID
        /// å·¥è‰ºè·¯çº¿ID
        /// </summary>
        [DisplayName("工艺路线ID")]
        [DisplayName("工艺路线ID")]
        public string ROT_ID { get; set; }
        /// <summary>
        /// å·¥å•路线节点ID
        /// å·¥å•路线节点ID
        /// </summary>
        [DisplayName("工单路线节点ID")]
        [DisplayName("工单路线节点ID")]
        public string NODE_ID { get; set; }
        /// <summary>
        /// å·¥å•行为节点ID
        /// å·¥å•行为节点ID
        /// </summary>
        [DisplayName("工单行为节点ID")]
        [DisplayName("工单行为节点ID")]
        public string ACT_ID { get; set; }
        /// <summary>
        /// è¡Œä¸ºç±»åž‹(0Normal默认行为|1Scan扫码验证|2Assy组装上料|3Test产品测试|4Audit产品抽检|5Print标签打印|6Package包装规则)
        /// è¡Œä¸ºç±»åž‹(0Normal默认行为|1Scan扫码验证|2Assy组装上料|3Test产品测试|4Audit产品抽检|5Print标签打印|6Package包装规则)
        /// </summary>
        [DisplayName("行为类型(0Normal默认行为|1Scan扫码验证|2Assy组装上料|3Test产品测试|4Audit产品抽检|5Print标签打印|6Package包装规则)")]
        [DisplayName("行为类型(0Normal默认行为|1Scan扫码验证|2Assy组装上料|3Test产品测试|4Audit产品抽检|5Print标签打印|6Package包装规则)")]
        public int ACT_TYPE { get; set; }
        /// <summary>
        /// è¡Œä¸ºå®šä¹‰ç¼–码
        /// è¡Œä¸ºå®šä¹‰ç¼–码
        /// </summary>
        [DisplayName("行为定义编码")]
        [DisplayName("行为定义编码")]
        public string ACT_CODE { get; set; }
        /// <summary>
        /// æ‰«ç éªŒè¯ï¼šæ¡ç è§„则
        /// æ‰«ç éªŒè¯ï¼šæ¡ç è§„则
        /// </summary>
        [DisplayName("扫码验证:条码规则")]
        [DisplayName("扫码验证:条码规则")]
        public string RULE_CODE { get; set; }
        /// <summary>
        /// ç»„装上料:物料料号
        /// ç»„装上料:物料料号
        /// </summary>
        [DisplayName("组装上料:物料料号")]
        [DisplayName("组装上料:物料料号")]
        public string ITEM_CODE { get; set; }
        /// <summary>
        /// äº§å“æµ‹è¯•:检验项目编码
        /// äº§å“æµ‹è¯•:检验项目编码
        /// </summary>
        [DisplayName("产品测试:检验项目编码")]
        [DisplayName("产品测试:检验项目编码")]
        public string TEST_CODE { get; set; }
        /// <summary>
        /// äº§å“æŠ½æ£€ï¼šæŠ½æ ·è§„则编码
        /// äº§å“æŠ½æ£€ï¼šæŠ½æ ·è§„则编码
        /// </summary>
        [DisplayName("产品抽检:抽样规则编码")]
        [DisplayName("产品抽检:抽样规则编码")]
        public string SAPL_CODE { get; set; }
        /// <summary>
        /// æ ‡ç­¾æ‰“印:标签模板编码
        /// æ ‡ç­¾æ‰“印:标签模板编码
        /// </summary>
        [DisplayName("标签打印:标签模板编码")]
        [DisplayName("标签打印:标签模板编码")]
        public string LABEL_CODE { get; set; }
        /// <summary>
        /// åŒ…装规则:包装规则编码
        /// åŒ…装规则:包装规则编码
        /// </summary>
        [DisplayName("包装规则:包装规则编码")]
        [DisplayName("包装规则:包装规则编码")]
        public string PKG_CODE { get; set; }
        /// <summary>
        /// æ˜¯å¦å¯ç”¨(Y/N)
        /// æ˜¯å¦å¯ç”¨(Y/N)
        /// </summary>
        [DisplayName("是否启用(Y/N)")]
        [DisplayName("是否启用(Y/N)")]
        public string IS_ACTIVE { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼1
        /// </summary>
        [DisplayName("设置值1")]
        /// <summary>
        /// æ˜¯å¦è®¾ç½®å®Œæˆ(Y/N)
        /// </summary>
        [DisplayName("是否设置完成(Y/N)")]
        public string SETUP_FINISH { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼1
        /// </summary>
        [DisplayName("设置值1")]
        public string OPTION_1 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼2
        /// è®¾ç½®å€¼2
        /// </summary>
        [DisplayName("设置值2")]
        [DisplayName("设置值2")]
        public string OPTION_2 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼3
        /// è®¾ç½®å€¼3
        /// </summary>
        [DisplayName("设置值3")]
        [DisplayName("设置值3")]
        public string OPTION_3 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼4
        /// è®¾ç½®å€¼4
        /// </summary>
        [DisplayName("设置值4")]
        [DisplayName("设置值4")]
        public string OPTION_4 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼5
        /// è®¾ç½®å€¼5
        /// </summary>
        [DisplayName("设置值5")]
        [DisplayName("设置值5")]
        public string OPTION_5 { get; set; }
        /// <summary>
        /// æ˜¯å¦è®¾ç½®å®Œæˆ(Y/N)
        /// </summary>
        [DisplayName("是否设置完成(Y/N)")]
        public string SETUP_FINISH { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [DisplayName("备注")]
        /// <summary>
        /// è®¾ç½®å€¼6
        /// </summary>
        [DisplayName("设置值6")]
        public string OPTION_6 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼7
        /// </summary>
        [DisplayName("设置值7")]
        public string OPTION_7 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼8
        /// </summary>
        [DisplayName("设置值8")]
        public string OPTION_8 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼9
        /// </summary>
        [DisplayName("设置值9")]
        public string OPTION_9 { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [DisplayName("备注")]
        public string REMARK { get; set; }
        #endregion
        #region è™šæ‹Ÿå±žæ€§
        /*例子
        #region è™šæ‹Ÿå±žæ€§
        /*例子
        [SugarColumn(IsIgnore = true)]
        public string FieldName { get; set; }
        */
        #endregion
        #region å¤–键属性
        /*例子
        //一对一外键导航
        [Navigate(NavigateType.OneToOne, nameof(ClassAId))]//一对一 ClassAId是MES_WO_ACTION类里面的外键ID字段
        public ClassA ClassA { get; set; } //注意禁止手动赋值,只能是null
        //一对多外键导航
        [Navigate(NavigateType.OneToMany, nameof(ClassA.MES_WO_ACTIONId))]//ClassA表中的MES_WO_ACTIONId
        public List<ClassA> ClassAList { get; set; }//注意禁止手动赋值,只能是null
        //多对多外键导航
        [Navigate(typeof(MappingClass), nameof(MappingClass.MES_WO_ACTIONId), nameof(MappingClass.ClassAId))]//注意顺序
        public List<ClassA> ClassAList { get; set; } //注意禁止手动赋值,只能是null
        #region å¤–键属性
        /*例子
        //一对一外键导航
        [Navigate(NavigateType.OneToOne, nameof(ClassAId))]//一对一 ClassAId是MES_WO_ACTION类里面的外键ID字段
        public ClassA ClassA { get; set; } //注意禁止手动赋值,只能是null
        //一对多外键导航
        [Navigate(NavigateType.OneToMany, nameof(ClassA.MES_WO_ACTIONId))]//ClassA表中的MES_WO_ACTIONId
        public List<ClassA> ClassAList { get; set; }//注意禁止手动赋值,只能是null
        //多对多外键导航
        [Navigate(typeof(MappingClass), nameof(MappingClass.MES_WO_ACTIONId), nameof(MappingClass.ClassAId))]//注意顺序
        public List<ClassA> ClassAList { get; set; } //注意禁止手动赋值,只能是null
        */
        #endregion
        #region æžšä¸¾å˜é‡
        /*例子
        #region æžšä¸¾å˜é‡
        /*例子
        public enum FieldNames
        {
            [Description("枚举描述0")]
            [Description("枚举描述0")]
            Enum0,
            [Description("枚举描述1")]
            [Description("枚举描述1")]
            Enum1,
        }
        */
        /// <summary>
        /// æžšä¸¾ï¼šè¡Œä¸ºç±»åž‹(0Normal默认行为|1Scan扫码验证|2Assy组装上料|3Test产品测试|4Audit产品抽检|5Print标签打印|6Package包装规则)
        /// æžšä¸¾ï¼šè¡Œä¸ºç±»åž‹(0Normal默认行为|1Scan扫码验证|2Assy组装上料|3Test产品测试|4Audit产品抽检|5Print标签打印|6Package包装规则)
        /// </summary>
        public enum ACT_TYPEs
        {
            [Description("默认行为")]
            [Description("默认行为")]
            Normal = 0,
            [Description("扫码验证")]
            [Description("扫码验证")]
            Scan = 1,
            [Description("组装上料")]
            [Description("组装上料")]
            Assy = 2,
            [Description("产品测试")]
            [Description("产品测试")]
            Test = 3,
            [Description("产品抽检")]
            [Description("产品抽检")]
            Audit = 4,
            [Description("标签打印")]
            [Description("标签打印")]
            Print = 5,
            [Description("包装规则")]
            [Description("包装规则")]
            Package = 6,
        }
        #endregion
        #region å…¬å…±æ–¹æ³•
        #region å…¬å…±æ–¹æ³•
        #endregion
Tiger.Model.Net/Entitys/MES/MES_WO_OPER.cs
@@ -114,6 +114,26 @@
        [DisplayName("设置值5")]
        public string OPTION_5 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼6
        /// </summary>
        [DisplayName("设置值6")]
        public string OPTION_6 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼7
        /// </summary>
        [DisplayName("设置值7")]
        public string OPTION_7 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼8
        /// </summary>
        [DisplayName("设置值8")]
        public string OPTION_8 { get; set; }
        /// <summary>
        /// è®¾ç½®å€¼9
        /// </summary>
        [DisplayName("设置值9")]
        public string OPTION_9 { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [DisplayName("备注")]
Tiger.Model.Net/Entitys/MES/ParameterEntity/PositionParameter.cs
@@ -87,4 +87,75 @@
        public string DFT_NAME { get; set; }
        public int DFT_LEVEL { get; set; }
    }
    public class PackingActionInput
    {
        /// <summary>
        /// åŒ…装行为当前执行的操作代码,包括:<br/>
        /// Scan:扫码,扫描当前包装层级的条码<br/>
        /// Print:打印,打印当前包装层级的标签<br/>
        /// Complete:完成,完成全部包装后结束行为<br/>
        /// </summary>
        public string ExecCode { get; set; }
        /// <summary>
        /// å®¢æˆ·ç«¯æ˜¯å¦å®Œæˆå½“前操作
        /// </summary>
        public bool IsFinish { get; set; }
        /// <summary>
        /// å½“前操作的包装层级
        /// </summary>
        public int PkgLevel { get; set; }
        /// <summary>
        /// å½“前操作的包装层级的标签条码
        /// </summary>
        public string PkgSN { get; set; }
    }
    public class PackingActionOutput
    {
        public WipPkg PkgInfo { get; set; }
        /// <summary>
        /// åŒ…装行为当前执行的操作代码,包括:<br/>
        /// Scan:扫码,扫描当前包装层级的条码<br/>
        /// Print:打印,打印当前包装层级的标签<br/>
        /// Complete:完成,已保存包装数据<br/>
        /// </summary>
        public string ExecCode { get; set; }
        /// <summary>
        /// å½“前操作的包装层级
        /// </summary>
        public int PkgLevel { get; set; }
        /// <summary>
        /// å½“前需要打印的包装层级的标签信息
        /// </summary>
        public BAS_LABEL_TEMP PrintLable { get; set; }
    }
    /// <summary>
    /// åœ¨çº¿åŒ…装
    /// </summary>
    public class WipPkg
    {
        public string RULE_CODE { get; set; }
        public string RULE_NAME { get; set; }
        public WipPkgItem Item { get; set; }
        public bool IsFinished { get; set; } = false;
    }
    /// <summary>
    /// åœ¨çº¿åŒ…装明细
    /// </summary>
    public class WipPkgItem
    {
        public string PKG_CODE { get; set; }
        public string PKG_NAME { get; set; }
        public string IS_MIN_PKG { get; set; }
        public int PKG_LEVEL { get; set; }
        public int PKG_QTY { get; set; }
        public string LABEL_CODE { get; set; }
        public MES_WIP_PKG Package { get; set; }
        public bool IsFinished { get; set; } = false;
        public List<WipPkgItem> Items { get; set; } = new List<WipPkgItem>();
    }
}