服务端的TigerApi 框架,基于.NET6 2024 版本
Rodney Chen
2024-08-16 eec9f268552af1d0ce8c95312930770669f1cc18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
using Rhea.Common;
using Tiger.IBusiness;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tiger.Model;
using static Tiger.Business.Biz;
using Tiger.Model.Entitys.MES.Position;
 
namespace Tiger.Business.MES.Transaction
{
    /// <summary>
    /// MES岗位事务
    /// </summary>
    public class Position : MESTransactionBase, IPosition
    {
        public IPosition Init(string id, string apiHost, string userCode, string postCode)
        {
            TransID = id;
            UserCode = userCode;
            ApiHost = apiHost;
            PostCode = postCode;
 
            CurPosition = Biz.Db.Queryable<MES_POSITION>().Where(q => q.POST_CODE == postCode).First();
            //if (CurPosition.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.PositionNotExistsException", new Exception($"{postCode}|"));
            if (CurPosition.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]不存在,请提交正确的岗位代码", new Exception($"{postCode}|"));
            CurLine = Biz.Db.Queryable<MES_LINE>().Where(q => q.LINE_CODE == CurPosition.LINE_CODE).First();
            //if (CurLine.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.LineNotExistsException", new Exception($"{postCode}|{CurPosition.LINE_CODE}"));
            if (CurLine.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]所属的产线[{CurPosition.LINE_CODE}]不存在,请先设置所属产线", new Exception($"{postCode}|{CurPosition.LINE_CODE}"));
            CurWorkshop = Biz.Db.Queryable<MES_WORKSHOP>().Where(q => q.WS_CODE == CurLine.WS_CODE).First();
            //if (CurWorkshop.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.WorkshopNotExistsException", new Exception($"{postCode}|{CurLine.WS_CODE}"));
            if (CurWorkshop.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]所属的车间[{CurLine.WS_CODE}]不存在,请先设置所属车间", new Exception($"{postCode}|{CurLine.WS_CODE}"));
            CurFactory = Biz.Db.Queryable<MES_FACTORY>().Where(q => q.FTY_CODE == CurWorkshop.FTY_CODE).First();
            //if (CurFactory.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.FactoryNotExistsException", new Exception($"{postCode}|{CurWorkshop.FTY_CODE}"));
            if (CurFactory.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]所属的工厂[{CurWorkshop.FTY_CODE}]不存在,请先设置所属工厂", new Exception($"{postCode}|{CurWorkshop.FTY_CODE}"));
 
            //加载当前产线的班制
            CurShiftSys = Biz.Db.Queryable<MES_SHIFT_SYS>().Where(q => q.SFTS_CODE == CurLine.SFTS_CODE).IncludesAllFirstLayer().IncludesAllSecondLayer(q => q.Shifts).First();
 
            return this;
        }
 
        #region Propertys & Variables
        public string UserCode { get; set; }
        public string PostCode { get; set; }
        public MES_FACTORY CurFactory { get; set; }
        public MES_WORKSHOP CurWorkshop { get; set; }
        public MES_LINE CurLine { get; set; }
        public MES_POSITION CurPosition { get; set; }
        public MES_SHIFT_SYS CurShiftSys { get; set; }
        public WorkBatch CurBatch { get; set; }
        public IWorkBatch WorkBatch => CurBatch;
        public List<MES_WIP_DATA> CurWipSNs { get; set; } = new();
        public string CurSN => (CurWipSNs.Any() ? (CurWipSNs.First().TRAY_SN.IsNullOrEmpty() ? CurWipSNs.First().SN : CurWipSNs.First().TRAY_SN) : "");
        public List<MES_WIP_HIS> CurWipSNHiss { get; set; } = new();
        public List<MES_WIP_DFT> CurDefects { get; set; } = new();
        public Dictionary<string, object> Context { get; set; } = new();
        public List<WorkStep> Steps { get; set; } = new();
        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;
        /// <summary>
        /// 是否需要临时存储数据库提交操作,待需要的时候再提交
        /// </summary>
        public bool NeedTemporaryStoreDBCommitAction { get; set; } = false;
        protected List<Action> DBCommitList { get; set; } = new();
        protected List<Position> NodeCommitList { get; set; } = new();
        protected Dictionary<string, OperInfo> OperInfoDic { get; set; } = new();
        protected OperInfo CurOperInfo { get; set; }
        #endregion Propertys & Variables
 
        #region Functions
        /// <summary>
        /// 获取提交数据的DbClient对象
        /// </summary>
        /// <returns></returns>
        public DbClient GetCommitDB()
        {
            return CommitDB ??= Biz.Db;
        }
        /// <summary>
        /// 选择工单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<ApiAction> SelectOrder(WoInput input)
        {
            var action = new ApiAction();
            try
            {
                if (!WoContext.ExistsBatch(input.OrderNo, CurLine.LINE_CODE))
                {
                    var wo = await Biz.Db.Queryable<BIZ_MES_WO>().ByAuth(input.AuthOption).Where(q => q.ORDER_NO == input.OrderNo).FirstAsync();
                    //验证明细是否正确
                    if (wo.IsNullOrEmpty())
                    {
                        action.IsSuccessed = false;
                        //action.LocaleMsg = new($"工单[{input.OrderNo}]不存在", input.OrderNo);
                        action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.EmptyException", input.OrderNo);
                        return action;
                    }
                    if (wo.STATUS != BIZ_MES_WO.STATUSs.Release.GetValue() && wo.STATUS != BIZ_MES_WO.STATUSs.Working.GetValue())
                    {
                        action.IsSuccessed = false;
                        //action.LocaleMsg = new($"工单[{input.OrderNo}]状态[{wo.STATUS.GetEnum<BIZ_MES_WO.STATUSs>().GetName()}]不能生产");
                        action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.StatusException", input.OrderNo, wo.STATUS.GetEnum<BIZ_MES_WO.STATUSs>().GetName());
                        return action;
                    }
                    var batch = await Biz.Db.Queryable<BIZ_MES_WO_BATCH>().ByAuth(input.AuthOption).Where(q => q.ORDER_NO == input.OrderNo && q.ACT_LINE == CurLine.LINE_CODE).FirstAsync();
                    if (batch.IsNullOrEmpty())
                    {
                        action.IsSuccessed = false;
                        //action.LocaleMsg = new($"工单[{input.OrderNo}]没有下发到产线状态[{CurLine.LINE_CODE}]");
                        action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.LineException", input.OrderNo, CurLine.LINE_CODE);
                        return action;
                    }
                    var wb = new WorkBatch(input.OrderNo).Init(CurLine.LINE_CODE);
                    WoContext.WoBatchDic.Add(wb.Batch.BATCH_NO, wb);
                }
                CurBatch = WoContext.GetBatch(input.OrderNo, CurLine.LINE_CODE);
                OperInfoDic.Add(CurBatch.Batch.BATCH_NO, new());
                action.Data = new { WorkOrder = CurBatch.WO, Bacth = CurBatch.Batch };
            }
            catch (Exception ex)
            {
                action.CatchExceptionWithLog(ex, $"采集工序:选择工单异常");
            }
            return action;
        }
 
        /// <summary>
        /// 获取当前时间所属的班制班次时段
        /// </summary>
        public ShiftPeriod GetShiftPeriodForNow()
        {
            var time = DateTime.Now.ToString("HHmm").ToInt32();
            foreach (var shift in CurShiftSys.Shifts)
            {
                var period = shift.Periods.Where(q => q.PRD_BEGIN <= time && time <= q.PRD_END).FirstOrDefault();
                if (!period.IsNullOrEmpty())
                {
                    var result = new ShiftPeriod();
                    result.ShiftSys = CurShiftSys;
                    result.Shift = shift;
                    result.Period = period;
                    return result;
                }
            }
            return null;
        }
 
        /// <summary>
        /// 重置工序操作
        /// </summary>
        /// <returns></returns>
        public ApiAction Reset()
        {
            var action = new ApiAction();
 
            ResetNode();
            action.IsSuccessed = true;
            action.LocaleMsg = new($"工序操作已重置,请重新扫描进站产品条码");
            action.LocaleMsg = new("MES.Transaction.Position.ResetNode");
 
            return action;
        }
 
        /// <summary>
        /// 重置当前工序,有需要则重写此方法
        /// </summary>
        public virtual void ResetNode()
        {
            Steps.Clear();
            CurWipSNs.Clear();
            CurWipSNHiss.Clear();
            CurStep = null;
            CurDefects.Clear();
        }
 
        /// <summary>
        /// 设置当前条码的工序信息
        /// </summary>
        public OperInfo SetOperNodeInfo(OperInfo info)
        {
            if (CurWipSNs.Any())
            {
                info.CurNode = CurWipSNs.First().NODE_NAME;
                info.NextNode = string.Join(",", CurBatch.GetNextNodes(CurWipSNs.First()).Select(q => q.NODE_NAME));
            }
            else
            {
                info.CurNode = "   —   ";
                info.NextNode = "   —   ";
            }
            return info;
        }
 
        /// <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="parent"></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.Add(parent.NodeID);
                    next.PrepNodeIDs.AddRange(parent.PrepNodeIDs);
                    next.PrepNodeIDs = next.PrepNodeIDs.Distinct().ToList();
                    AddNextActToSteps(next);
                }
                else
                {
                    var next = new WorkStep(IWorkStep.Types.Action, this)
                    {
                        Sequence = parent.Sequence + 1,
                        Node = parent.Node,
                        NodeAct = act,
                        Setting = CurBatch.ActionSets.FirstOrDefault(q => q.ACT_ID == act.ID),
                    };
                    next.Init();
                    next.PrepNodeIDs.Add(parent.NodeID);
                    next.PrepNodeIDs.AddRange(parent.PrepNodeIDs);
                    next.PrepNodeIDs = next.PrepNodeIDs.Distinct().ToList();
                    Steps.Add(next);
                    AddNextActToSteps(next);
                }
            }
        }
 
        /// <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() && Steps.Any())
            {
                //查找有没有前置工步未完成,若有则先完成未完成的前置工步
                var prepIDs = curStep.PrepNodeIDs.Where(id => CurBatch.Edges.Any(e => e.SRC_NODE == id && Steps.Any(q => !q.IsFinished && e.TGT_NODE == q.NodeID))).ToList();
                var prepSteps = Steps.Where(q => prepIDs.Contains(q.NodeID)).OrderByDescending(q => q.Sequence).ToList();
                while (prepSteps.Any() && !result.Any())
                {
                    var prep = prepSteps.First();
                    var prepNext = GetNextSteps(prep);
                    if (prepNext.Any())
                    {
                        result = prepNext;
                    }
                    else
                    {
                        prepSteps.Remove(prep);
                    }
                }
 
            }
            return result.OrderBy(q => q.NodeAct.ACT_NAME).ToList();
        }
 
        /// <summary>
        /// 开始执行下一行为工步
        /// </summary>
        /// <param name="input"></param>
        public ApiAction<SubmitOutput> BeginNextActionStep(SubmitInput input)
        {
            var result = new ApiAction<SubmitOutput>(new 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.SetValue(CurBatch, CurStep, CurStep?.ID, IsFinishAllSteps);
 
                    return result;
                }
            }
 
            //没有可以直接开始的后续工步,根据后续工步返回ApiAction
            result.Data.SetValue(CurBatch, CurStep, "", IsFinishAllSteps);
 
            //没有可以直接开始的后续工步,根据后续可执行工步列表返回相应的操作提示
            if (NextSteps.Count == 1)
            {
                result.LocaleMsg = NextSteps.First().GetBeginMsg();
            }
            else
            {
                result.LocaleMsg = new(T(L("MES.Transaction.Position.PleaseSelectNextStep"), input.Locale) + "\r\n" +
                                              string.Join("\r\n", NextSteps.Select(q => "    >> " + T(q.GetBeginMsg(), input.Locale))));
            }
            return result;
        }
 
        /// <summary>
        /// 保存工步的数据库提交操作到数据库
        /// </summary>
        protected void SaveStepsCommitActionToDB()
        {
            //保存工步的数据库提交操作到提交操作列表
            foreach (var step in Steps.OrderBy(q => q.Sequence))
            {
                DBCommitList.Add(step.DBSubmitAction);
            }
            //如果不需要临时存储数据库提交操作,则把提交操作列表提交到数据库
            if (!NeedTemporaryStoreDBCommitAction)
            {
                //恢复临时存储标记为false
                NeedTemporaryStoreDBCommitAction = false;
 
                var dbTran = GetCommitDB().UseTran(() =>
                {
                    //在同一个事务中保存所有工步的数据
                    foreach (var action in DBCommitList)
                    {
                        action.Invoke();
                    }
                });
                if (dbTran.IsSuccess)
                {
                    //保存成功则清空提交操作列表
                    DBCommitList.Clear();
                }
                else
                {
                    //抛出异常
                    throw dbTran.ErrorException;
                }
            }
        }
 
        protected void DoSaveToDB()
        {
            var dbTran = GetCommitDB().UseTran(() =>
            {
                //在同一个事务中保存所有工步的数据
                foreach (var step in Steps.OrderBy(q => q.Sequence))
                {
                    step.DBSubmitAction.Invoke();
                }
            });
            if (!dbTran.IsSuccess)
            {
                //抛出异常
                throw dbTran.ErrorException;
            }
        }
 
        /// <summary>
        /// 获取打印标签模板过程变量值
        /// </summary>
        /// <param name="labelPVs">过程变量列表</param>
        /// <param name="label">标签模板</param>
        /// <returns></returns>
        public BAS_LABEL_TEMP SetLabelVariables(List<BAS_LABEL_PV> labelPVs, BAS_LABEL_TEMP label)
        {
            foreach (var item in label.Variables)
            {
                switch (item.VAR_TYPE.GetEnum<BAS_LABEL_VAR.VAR_TYPEs>())
                {
                    case BAS_LABEL_VAR.VAR_TYPEs.Constant:
                        item.Value = item.VAR_VALUE;
                        break;
                    case BAS_LABEL_VAR.VAR_TYPEs.ProcessVariable:
                        item.Value = GetPrintProcessValue(labelPVs, item);
                        break;
                    case BAS_LABEL_VAR.VAR_TYPEs.DateVariable:
                        item.Value = DateTime.Now.ToString(item.VAR_VALUE);
                        break;
                    case BAS_LABEL_VAR.VAR_TYPEs.BarcodeGenerate:
                        item.Value = GetGeneratePValue(labelPVs, item);
                        break;
                    case BAS_LABEL_VAR.VAR_TYPEs.CustomVariable:
                    default:
                        item.Value = "";
                        break;
                }
            }
            return label;
        }
 
        /// <summary>
        /// 获取打印标签模板过程变量值
        /// </summary>
        /// <param name="labelPVs">过程变量列表</param>
        /// <param name="lv">标签模板变量</param>
        /// <returns></returns>
        public string GetPrintProcessValue(List<BAS_LABEL_PV> labelPVs, BAS_LABEL_VAR lv)
        {
            var pv = labelPVs.FirstOrDefault(q => q.VAR_CODE == lv.VAR_VALUE);
            if (!pv.IsNullOrEmpty())
            {
                switch (pv.VAR_TYPE.GetEnum<BAS_LABEL_PV.VAR_TYPEs>())
                {
                    case BAS_LABEL_PV.VAR_TYPEs.ServerMethod:
                        {
                            switch (pv.VAR_METHOD)
                            {
                                case "GetSN":
                                    return CurSN;
                                case "GetBAS_ITEM":
                                    return WorkBatch.Product.ToJson();
                                case "GetCustomer":
                                    return WorkBatch.Batch.ToJson();
                                case "GetVarByWo":
                                    return GetLabelVarWo(lv);
                                default:
                                    return "";
                            }
                        }
                    case BAS_LABEL_PV.VAR_TYPEs.WebApi:
                        break;
                    case BAS_LABEL_PV.VAR_TYPEs.StoredProcedure:
                        break;
                    default:
                        break;
                }
            }
            return "";
        }
 
        /// <summary>
        /// 获取根据条码规则生成标签模板的过程变量值
        /// </summary>
        /// <param name="labelPVs"></param>
        /// <param name="lv"></param>
        /// <returns></returns>
        public string GetGeneratePValue(List<BAS_LABEL_PV> labelPVs, BAS_LABEL_VAR lv)
        {
            var pv = labelPVs.FirstOrDefault(q => q.VAR_CODE == lv.VAR_VALUE);
            if (!pv.IsNullOrEmpty())
            {
                switch (pv.VAR_TYPE.GetEnum<BAS_LABEL_PV.VAR_TYPEs>())
                {
                    case BAS_LABEL_PV.VAR_TYPEs.BarcodeGenerate:
                        {
                            switch (pv.VAR_METHOD)
                            {
                                case "GetCartonGenerate":
                                    return Biz.CodeRule[lv.BARCODE_RULE ?? ""]?.Generate($"{WorkBatch.Batch.BATCH_NO}-{WorkBatch.Batch.PLAN_QTY}-").Data.ToString() ?? "";
                                default:
                                    return "";
                            }
                        }
                    default:
                        break;
                }
            }
            return "";
        }
 
        /// <summary>
        /// 获取工单维护的模板变量
        /// </summary>
        /// <param name="labelId"></param>
        /// <returns></returns>
        private string GetLabelVarWo(BAS_LABEL_VAR lv)
        {
            string result = "";
            var labelVarwos = Biz.Db.Queryable<BAS_LABEL_VAR_WO>().Where(x => x.LABEL_ID == lv.LABEL_ID && x.VAR_NAME == lv.VAR_NAME).ToList();
            if (labelVarwos.Any(q => q.WORK_ORDER == WorkBatch.Batch.ORDER_NO))
            {
                result = labelVarwos.First(q => q.WORK_ORDER == WorkBatch.Batch.ORDER_NO).VAR_VALUE;
            }
            else
            {
                result = labelVarwos.Count > 0 ? labelVarwos[0].DEFAULT_VALUE : "";
            }
            return result;
        }
 
        #endregion Functions
 
        public override bool Close(bool needSaveHistoryLog = false)
        {
            //needSaveHistoryLog = true;
            //保存操作日志
 
            this.IsFinished = true;
            return IsFinished ? base.Close(needSaveHistoryLog) : IsFinished;
        }
    }//endClass
}