11
schangxiang@126.com
2024-12-03 e8734db76fbbb3149ba663beff3b4f7451012b03
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
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
using iWareCommon;
using iWareCommon.Utils;
using iWareSql;
using System;
using System.Collections.Generic;
using System.Threading;
 
using iWareCC.SrmService;
using System.Linq;
using iWareSql.Orm;
using System.Threading.Tasks;
using iWareSql.DataAccess;
using iWareSql.Entity.ParamModel;
using Newtonsoft.Json;
using iWareCC.BLL;
using iWareCC.Common;
 
using iWareModel;
using iWareSql.DBModel;
using iWareCommon.Common.Globle;
using XiGang.Core.Model;
using iWareCC.Common.Helper;
 
namespace iWareCC
{
    /// <summary>
    /// 堆垛机任务服务线程类
    /// </summary>
    public class SrmTaskThreadService : DeviceThreadServiceHandle
    {
        private static string _namespace = "iWareCC.SrmTaskThreadService";
 
        private SrmTaskThreadService() { }
        public SrmTaskThreadService(iWareCommon.Utils.LogType logType)
        {
            base.currentLogType = logType;
        }
        public override void StartService()
        {
            Task.Run(() =>
            {
                try
                {
                    //自动执行堆垛机任务线程
                    Log4NetHelper.WriteInfoLog(base.currentLogType, "自动执行堆垛机任务线程启动了");
                    //var srmList = new SrmService.SrmServiceClient().GetSrm_CacheEntity();
                    var srmList = FormCC.SrmDeviceList;
                    foreach (var x in srmList)
                    {
                        IssueTaskThread(x);
                        ConfirmFinishTaskThread(x);
                    }
                }
                catch (Exception ex)
                {
                    Log4NetHelper.WriteErrorLog(base.currentLogType, "SrmTaskThreadService线程启动出现异常", ex);
                }
            });
        }
 
 
        #region 线程处理
 
        #region 自动执行堆垛机任务线程
 
        /// <summary>
        /// 自动执行堆垛机任务
        /// </summary>
        /// <param name="srmName"></param>
        public override void IssueTask(object deviceId)
        {
            string errMsg1 = "", errMsg2 = "", errMsg3 = "", errMsg4 = "";
            int i_deviceId = (int)deviceId;
            while (true)
            {
                if ((int)deviceId == (int)EDevice.一号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_1 && SystemValue.isStartedModel)
                {
                    IssueTaskHandle(i_deviceId, out errMsg1);
                }
                else if ((int)deviceId == (int)EDevice.二号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_2 && SystemValue.isStartedModel)
                {
                    IssueTaskHandle(i_deviceId, out errMsg2);
                }
                else if ((int)deviceId == (int)EDevice.三号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_3 && SystemValue.isStartedModel)
                {
                    IssueTaskHandle(i_deviceId, out errMsg3);
                }
                else if ((int)deviceId == (int)EDevice.四号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_4 && SystemValue.isStartedModel)
                {
                    IssueTaskHandle(i_deviceId, out errMsg4);
                }
                SystemWarningMsg._lbl_Alert_DataProcess_BZ39_IssueInboundTask = errMsg1;
                SystemWarningMsg._lbl_Alert_Srm2Release = errMsg2;
                SystemWarningMsg._lbl_Alert_Srm3Release = errMsg3;
                SystemWarningMsg._lbl_Alert_Srm4Release = errMsg4;
                Thread.Sleep(2000);//2秒一次
            }
        }
 
        /// <summary>
        /// 自动执行堆垛机任务(线程)
        /// </summary>
        /// <param name="srmName"></param>
        public override void IssueTaskHandle(int deviceId, out string errMsg)
        {
            errMsg = "";
            string logHeader = "方法:DoSrmTaskByThead,参数deviceId:" + deviceId.ToString() + "===";
            #region 新增异常信息表  【EditBy shaocx,2020-01-20】
            IDictionary<string, object> logDict = new Dictionary<string, object>();
            logDict.Add("deviceId", deviceId);
            Base_SysExceptionInfo exception = SysExceptionInfoHandler.GetExceptionInfo<IDictionary<string, object>>(base.currentLogType, _namespace, "DoSrmTaskByThead", logDict);
            #endregion
            try
            {
                /*
                 * 执行发送给堆垛机的指令任务
                 * 1、验证根据设备号是否找到堆垛机
                 * 2、判断设备是否属于任务完成,如果属于任务完成,就继续走3
                 * 3、判断数据库中是否有可要下发的任务,如果有就下发+验证起始点和目标点是否正确
                 * 4、下发成功后,更新任务状态
                 */
 
                errMsg = "";
                int int_deviceId = (int)deviceId;
 
 
 
                //2、判断堆垛机是否可以下发新任务
                bool isOk = ValidateDeviceIsAllowSendTask(int_deviceId, out errMsg);
                if (!isOk)
                {
                    errMsg = "不允许下发新任务," + errMsg;
                    return;
                }
 
                using (DbModel dbModel = new DbModel())
                {
                    //var srmTask = ValidateIsExistTaskToDispose(dbModel, int_deviceId, out errMsg, TaskExcuteTypeEnum.执行任务);
                    //if (srmTask == null)
                    //{//表示DB中没有任务要发送给堆垛机
                    //    return;
                    //}
                    var srmTaskList = ValidateIsExistTaskToDisposeForIssued(dbModel, int_deviceId, out errMsg);
                    if (srmTaskList == null || srmTaskList.Count == 0)
                    {//表示DB中没有任务要发送给堆垛机
                        return;
                    }
                    foreach (var item in srmTaskList)
                    {
                        SingleIssueTaskHandle(item, exception, dbModel, int_deviceId, out errMsg);
                        if (!string.IsNullOrEmpty(errMsg))
                        {//说明报错了,继续走下一个循环
                            continue;
                        }
                        else
                        {//说明执行成功了,跳出循环
                            break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                errMsg = "异常,请联系管理员:" + ex.Message;
                SysExceptionInfoHandler.GetExceptionInfoForError("自动执行堆垛机任务(线程)出现异常,deviceId:" + deviceId + ",异常:" + ex.Message, ex, ref exception);
                SysExceptionInfoHandler.InsertExceptionInfo(exception, true);
            }
        }
 
        /// <summary>
        /// 单个堆垛机任务下发处理
        /// </summary>
        /// <param name="srmTask"></param>
        /// <param name="exception"></param>
        /// <param name="dbModel"></param>
        /// <param name="int_deviceId"></param>
        /// <param name="errMsg"></param>
        private void SingleIssueTaskHandle(Task_Part srmTask, Base_SysExceptionInfo exception, DbModel dbModel, int int_deviceId, out string errMsg)
        {
            #region //3、判断数据库中是否有可要下发的任务,如果有就下发
 
            DeviceTaskTypeEnum _DeviceTaskTypeEnum = (DeviceTaskTypeEnum)Enum.Parse(typeof(DeviceTaskTypeEnum), srmTask.TaskType.ToString());
 
            //验证起始点和目标点是否正确
            RealPlaceEntity realPlaceEntity = null;
            if (!ValdiatePalceIsRight(dbModel, (int)srmTask.SourcePlace, (int)srmTask.ToPlace, ref realPlaceEntity))
            {
                errMsg = "验证起始点和目标点是否正确失败";
                PartTaskHandler.WriteOperationRemarkForPartTask(srmTask.Id, errMsg);
                return;
            }
 
            //验证目标点是否已经有库存 【EditBy shaocx,2022-04-15】
            var isOk = ValidateIsHasStoreForToPlace(int_deviceId, srmTask.ToPlace, srmTask.RealToPlace, out errMsg);
            if (!isOk)
            {
                errMsg = "不允许下发新任务," + errMsg;
                PartTaskHandler.WriteOperationRemarkForPartTask(srmTask.Id, errMsg);
                return;
            }
 
            #region 增加校验 [EditBy shaocx,2022-05-15]
 
            //去掉这个验证 【EditBy shaocx,2022-05-19】
            /*
            Base_Station toPlaceObject = dbModel.Base_Station.Where(o => o.Id == (int)srmTask.ToPlace).FirstOrDefault();
            if (toPlaceObject == null)
            {
                throw new Exception(string.Format("根据目标库位ID {0},{1}没有找到库位信息!", srmTask.ToPlace, srmTask.RealToPlace));
            }
            //*/
 
            var sourcePlace = dbModel.Base_Station.Where(o => o.Id == srmTask.SourcePlace).FirstOrDefault();
            if (sourcePlace == null)
            {
                throw new Exception(string.Format("根据库位号{0},{1}没有找到堆垛机的来源库位信息!", srmTask.SourcePlace.ToString(), srmTask.RealSourcePlace));
            }
            //要判断起点是否有库存,如果起点没有库存,则报错
            var sourcePlaceStore = dbModel.V_AllStore.Where(x => x.StationId == sourcePlace.Id).FirstOrDefault();
            if (sourcePlaceStore == null)
            {
                throw new Exception(string.Format("起点{0},{1}没有找到库存信息,无法下发堆垛机任务!任务号{2}", srmTask.SourcePlace.ToString(), srmTask.RealSourcePlace, srmTask.Id));
            }
 
            #endregion
 
            //同一个关联任务的其他设备任务
            var queryTaskState1 = (int)DeviceTaskStatusEnum.未开始;
            //var queryTaskState2 = (int)DeviceTaskStatusEnum.已下发;
            var relevanceTask = dbModel.Task_Part.Where(x => x.MainTaskId == srmTask.MainTaskId && x.TaskSequence < srmTask.TaskSequence
                 && (x.TaskState == queryTaskState1)
                 ).FirstOrDefault();
            if (relevanceTask != null)
            {
                errMsg = string.Format("关联{0}任务未开始,所以堆垛机任务不允许下发!关联任务号:{1}", relevanceTask.DeviceName, relevanceTask.PlcTaskId);
                PartTaskHandler.WriteOperationRemarkForPartTask(srmTask.Id, errMsg);
                return;
            }
 
            //去掉验证 【EditBy shaocx,2022-05-19】
            /*
            var validateIsAllowNewTaskForRgvStattion = ValidateIsAllowNewTaskForRgvStattion(dbModel, _DeviceTaskTypeEnum, srmTask.RealToPlace, ref errMsg);
            if (!validateIsAllowNewTaskForRgvStattion)
            {
                PartTaskHandler.WriteOperationRemarkForPartTask(srmTask.Id, errMsg);
                return;
            }
            //*/
 
 
            var log = TaskRequestLogHandler.GetTask(srmTask.Id,
                int_deviceId, srmTask.PlcTaskId, srmTask.RealSourcePlace,
                srmTask.RealToPlace, "给堆垛机发送任务指令", "sys");
            SdaResEntity sdaResult = new SdaResEntity();
            try
            {
                if (MyExtendHelper.IsAllowSimulatorHandle(srmTask))
                {
                    sdaResult.result = true;
                }
                else
                {
                    if (Convert.ToInt32(srmTask.PlcTaskId) <= 0)
                    {
                        throw new Exception("任务号不能小于等于0,PlcTaskId:" + srmTask.PlcTaskId);
                    }
                    sdaResult = new SrmService.SrmServiceClient().SendSrmTask(int_deviceId, Convert.ToInt32(srmTask.PlcTaskId), srmTask.RealSourcePlace, srmTask.RealToPlace, (short)ESrmCmd.库内搬运);
                }
                if (sdaResult.result == false)
                {//给堆垛机下发指令失败
                    exception.exceptionMsg = string.Format("发送指令给堆垛机失败,设备号{0},任务ID{1},起始位{2},目标位{3},ContainerId{4}", int_deviceId,
                        Convert.ToInt32(srmTask.PlcTaskId), srmTask.RealSourcePlace, srmTask.RealToPlace, srmTask.SalverId);
                    SysExceptionInfoHandler.InsertExceptionInfo(exception, true);
                    TaskRequestLogHandler.InsertTask(base.currentLogType, RequestStatusEnum.请求失败, JsonConvert.SerializeObject(sdaResult).ToString(), log, null);
                    return;
                }
                else
                {
                    TaskRequestLogHandler.InsertTask(base.currentLogType, RequestStatusEnum.请求成功, JsonConvert.SerializeObject(sdaResult).ToString(), log, null);
                    SystemValueUtil.DelayExcuteForSrmTaskThreadService(int_deviceId, ThreadDirectionEnum.任务开始下发线程);
                }
            }
            catch (Exception ex)
            {
                TaskRequestLogHandler.InsertTask(base.currentLogType, RequestStatusEnum.请求失败, JsonConvert.SerializeObject(sdaResult).ToString(), log, ex);
                throw ex;
            }
 
            #endregion
 
 
            //只更新着三个字段!
            //任务完成后的库存转移工作
            isOk = DealWithCurrentTaskWhenFinished(srmTask, dbModel);
            if (isOk == false)
            {
                throw new Exception("DealWithCurrentTaskWhenFinished处理失败");
            }
        }
 
 
        /// <summary>
        /// 当前任务完成后进行状态修改
        /// </summary>
        /// <param name="currentTask">当前任务</param>
        /// <returns></returns>
        private bool DealWithCurrentTaskWhenFinished(Task_Part currentTask, DbModel dbModel)
        {
            #region 新增异常信息表  【EditBy shaocx,2020-01-20】
            IDictionary<string, object> logDict = new Dictionary<string, object>();
            logDict.Add("currentTask.tackId", currentTask.Id);
            logDict.Add("currentTask.plcTaskId", currentTask.PlcTaskId);
            Base_SysExceptionInfo exception = SysExceptionInfoHandler.GetExceptionInfo<IDictionary<string, object>>(base.currentLogType, _namespace, "DealWithCurrentTask", logDict);
            #endregion
            try
            {
                bool rtn = false;
                var taskType = (DeviceTaskTypeEnum)Enum.Parse(typeof(DeviceTaskTypeEnum), currentTask.TaskType.ToString());
                switch (taskType)
                {
                    case DeviceTaskTypeEnum.组盘入库:
                    case DeviceTaskTypeEnum.空托转运到立体库:
                        rtn = DealFor_Srm_Store_In(currentTask, dbModel, taskType);//入库执行后增加库存
                        break;
                    case DeviceTaskTypeEnum.出库:
                    case DeviceTaskTypeEnum.立库空托到拆盘机入口:
                        rtn = DealFor_Srm_Store_Out(currentTask, dbModel, taskType);//出库
                        break;
                    default:
                        break;
                }
 
 
 
                //库存发生变化时,发送库存给MES
                //switch (taskType)
                //{
                //    case DeviceTaskTypeEnum22.配板原料入库:
                //    case DeviceTaskTypeEnum22.线下配板原料入库:
                //    case DeviceTaskTypeEnum22.配板余料回库:
                //    case DeviceTaskTypeEnum22.配板原料出库:
                //    case DeviceTaskTypeEnum22.人工出库:
                //        //MesBLL.SendSysnStockToMes();
                //        break;
                //    default:
                //        break;
                //}
                return rtn;
            }
            catch (Exception ex)
            {
                SysExceptionInfoHandler.GetExceptionInfoForError("当前任务完成后进行状态修改出现异常:" + ex.Message, ex, ref exception);
                SysExceptionInfoHandler.InsertExceptionInfo(exception);
                throw ex;
            }
        }
 
        /// <summary>
        /// 入库任务处理
        /// </summary>
        /// <param name="currentTask"></param>
        /// <returns></returns>
        private bool DealFor_Srm_Store_In(Task_Part currentTask, DbModel dbModel, DeviceTaskTypeEnum taskType)
        {
            #region 新增异常信息表  【EditBy shaocx,2020-01-20】
            IDictionary<string, object> logDict = new Dictionary<string, object>();
            logDict.Add("currentTask.tackId", currentTask.Id);
            logDict.Add("currentTask.plcTaskId", currentTask.PlcTaskId);
            Base_SysExceptionInfo exception = SysExceptionInfoHandler.GetExceptionInfo<IDictionary<string, object>>(base.currentLogType, _namespace, "DealFor_Srm_Store_In", logDict);
            #endregion
            try
            {
                /**
                 * 1、当前任务状态修改为已完成
                 * 2、添加托盘和库位的绑定关系
                 * 3、变更库位状态
                 */
                #region 准备数据
 
                #region 增加校验 [EditBy shaocx,2022-05-15]
 
                Base_Station toPlaceObject = dbModel.Base_Station.Where(o => o.Id == (int)currentTask.ToPlace).FirstOrDefault();
                if (toPlaceObject == null)
                {
                    throw new Exception(string.Format("根据目标库位ID {0},{1}没有找到库位信息!", currentTask.ToPlace, currentTask.RealToPlace));
                }
 
                var sourcePlace = dbModel.Base_Station.Where(o => o.Id == currentTask.SourcePlace).FirstOrDefault();
                if (sourcePlace == null)
                {
                    throw new Exception(string.Format("根据库位号{0},{1}没有找到堆垛机的来源库位信息!", currentTask.SourcePlace.ToString(), currentTask.RealSourcePlace));
                }
                //要判断起点是否有库存,如果起点没有库存,则报错
                var sourcePlaceStore = dbModel.V_AllStore.Where(x => x.StationId == sourcePlace.Id).FirstOrDefault();
                if (sourcePlaceStore == null)
                {
                    throw new Exception(string.Format("起点{0},{1}没有找到库存信息,无法下发堆垛机任务!这里任务号{2}", currentTask.SourcePlace.ToString(), currentTask.RealSourcePlace, currentTask.Id));
                }
 
                #endregion
 
 
                toPlaceObject.IsHasTaskDoing = false;
                toPlaceObject.IsFull = true;
                StationHandler.SetPlaceLockStatus(false, SysGloble.WCSSystem, ref toPlaceObject, "堆垛机任务完成,入库任务处理,任务类型:" + taskType.ToString());
                StationHandler.SetPlaceLockStatus(false, SysGloble.WCSSystem, ref sourcePlace, "堆垛机任务完成,入库任务处理,任务类型:" + taskType.ToString());
 
 
 
                #endregion
 
                return CommonTransForThreadFinish(dbModel, currentTask, "入库任务完成处理成功,任务类型:" + taskType.ToString(), sourcePlace, toPlaceObject, taskType);
            }
            catch (Exception ex)
            {
                SysExceptionInfoHandler.GetExceptionInfoForError("入库任务处理出现异常:" + ex.Message, ex, ref exception);
                SysExceptionInfoHandler.InsertExceptionInfo(exception);
 
                throw ex;
            }
        }
 
 
 
        /// <summary>
        /// 出库任务处理
        /// </summary>
        /// <param name="currentTask"></param>
        /// <returns></returns>
        private bool DealFor_Srm_Store_Out(Task_Part currentTask, DbModel dbModel, DeviceTaskTypeEnum taskType)
        {
            #region 新增异常信息表  【EditBy shaocx,2020-01-20】
            IDictionary<string, object> logDict = new Dictionary<string, object>();
            logDict.Add("currentTask.tackId", currentTask.Id);
            logDict.Add("currentTask.plcTaskId", currentTask.PlcTaskId);
            Base_SysExceptionInfo exception = SysExceptionInfoHandler.GetExceptionInfo<IDictionary<string, object>>(base.currentLogType, _namespace, "DealFor_Srm_Store_Out", logDict);
            #endregion
            try
            {
                /**
                 * 1、当前任务状态修改为已完成
                 * 2、解除来源位置的托盘和库位的绑定关系
                 * 3、变更库位状态
                 */
                #region 准备数据
 
 
                Base_Station toPlaceObject = dbModel.Base_Station.Where(o => o.Id == (int)currentTask.ToPlace).FirstOrDefault();
                if (toPlaceObject == null)
                {
                    throw new Exception(string.Format("根据库位ID {0}没有找到库位信息!", currentTask.ToPlace));
                }
 
                #region 3、变更库位状态
 
                //目标的库位状态
 
                toPlaceObject.IsHasTaskDoing = false;
                toPlaceObject.IsFull = true;
                StationHandler.SetPlaceLockStatus(false, SysGloble.WCSSystem, ref toPlaceObject, "堆垛机任务完成,出库任务处理");
 
                //来源位置的库位状态
                var sourcePlace = dbModel.Base_Station.Where(o => o.Id == currentTask.SourcePlace).FirstOrDefault();
                if (sourcePlace == null)
                {
                    throw new Exception(string.Format("根据库位号{0}没有找到库位信息!", currentTask.SourcePlace.ToString()));
                }
                sourcePlace.IsHasTaskDoing = false;
                sourcePlace.IsFull = false;
                StationHandler.SetPlaceLockStatus(false, SysGloble.WCSSystem, ref sourcePlace, "堆垛机任务完成,出库任务处理");
 
                #endregion
 
                #endregion
 
                return CommonTransForThreadFinish(dbModel, currentTask, "出库任务处理成功", sourcePlace, toPlaceObject, taskType);
 
            }
            catch (Exception ex)
            {
                SysExceptionInfoHandler.GetExceptionInfoForError("出库任务处理出现异常:" + ex.Message, ex, ref exception);
                SysExceptionInfoHandler.InsertExceptionInfo(exception);
                return false;
            }
        }
 
 
        private bool CommonTransForThreadFinish(DbModel dbModel, Task_Part currentTask,
            string business, Base_Station sourcePlace, Base_Station toPlaceObject, DeviceTaskTypeEnum taskType)
        {
            #region 新增异常信息表  【EditBy shaocx,2020-01-20】
            IDictionary<string, object> logDict = new Dictionary<string, object>();
            logDict.Add("currentTask.tackId", currentTask.Id);
            logDict.Add("currentTask.plcTaskId", currentTask.PlcTaskId);
            Base_SysExceptionInfo exception = SysExceptionInfoHandler.GetExceptionInfo<IDictionary<string, object>>(base.currentLogType, _namespace, "CommonTransForThreadFinish", logDict);
            #endregion
            try
            {
                try
                {
                    #region 当设备任务完成后,转移库存(注意:一定要在最后面执行!!)
 
                    try
                    {
                        TransferStoreWhenFinished(currentTask, dbModel, currentTask.SalverId, toPlaceObject, business, taskType, EDeviceType.堆垛机);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("转移库存时抛出异常,方法(TransferStoreWhenFinished),message:" + ex.Message, ex);
                    }
 
                    #endregion
 
                    UpdateMainTaskStatus(dbModel, currentTask.MainTaskId, currentTask.TaskType, "堆垛机任务完成时");
 
                    //4、下发成功后,更新任务状态
                    currentTask.IsReleased = true;
                    currentTask.ModifyBy = SysGloble.WCSSystem;
                    currentTask.ModifyTime = DateTime.Now;
                    currentTask.TaskState = (int)DeviceTaskStatusEnum.已下发;
                    currentTask.TaskStateName = DeviceTaskStatusEnum.已下发.ToString();
                    currentTask.OperationRemark = "任务已下发给设备";
                    currentTask.IssueTime = DateTime.Now;//下发时间
 
 
 
                    //注意:一定是先要保存数据库,才再跟plc交互!!!!!
                    int i = dbModel.SaveChanges();
                    if (i <= 0)
                    {
                        throw new Exception("更新的条数为" + i);
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
 
                return true;
            }
            catch (Exception)
            {
 
                throw;
            }
 
        }
 
        #endregion
 
        #region 自动结束堆垛机任务线程
 
        /// <summary>
        /// 自动结束堆垛机任务线程
        /// </summary>
        /// <param name="srmName"></param>
        public override void ConfirmFinishTask(object deviceId)
        {
            string errMsg1 = "", errMsg2 = "", errMsg3 = "", errMsg4 = "";
            int i_deviceId = (int)deviceId;
            while (true)
            {
                if ((int)deviceId == (int)EDevice.一号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_1_Finish && SystemValue.isStartedModel)
                {
                    ConfirmFinishTaskHandle(i_deviceId, out errMsg1);
                }
                else if ((int)deviceId == (int)EDevice.二号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_2_Finish && SystemValue.isStartedModel)
                {
                    ConfirmFinishTaskHandle(i_deviceId, out errMsg2);
                }
                else if ((int)deviceId == (int)EDevice.三号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_3_Finish && SystemValue.isStartedModel)
                {
                    ConfirmFinishTaskHandle(i_deviceId, out errMsg3);
                }
                else if ((int)deviceId == (int)EDevice.四号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_4_Finish && SystemValue.isStartedModel)
                {
                    ConfirmFinishTaskHandle(i_deviceId, out errMsg4);
                }
                SystemWarningMsg._lbl_Alert_Srm1ReleaseFinish = errMsg1;
                SystemWarningMsg._lbl_Alert_Srm2ReleaseFinish = errMsg2;
                SystemWarningMsg._lbl_Alert_Srm3ReleaseFinish = errMsg3;
                SystemWarningMsg._lbl_Alert_Srm4ReleaseFinish = errMsg4;
                Thread.Sleep(2000);//设置2秒一次
            }
        }
 
        /// <summary>
        /// 自动结束堆垛机任务线程(线程)
        /// </summary>
        /// <param name="srmName"></param>
        public override void ConfirmFinishTaskHandle(int deviceId, out string errMsg)
        {
            errMsg = "";
            string logHeader = "自动结束堆垛机任务线程(线程),设备号:" + deviceId;
            #region 新增异常信息表  【EditBy shaocx,2020-01-20】
            IDictionary<string, object> logDict = new Dictionary<string, object>();
            logDict.Add("deviceId", deviceId);
            Base_SysExceptionInfo exception = SysExceptionInfoHandler.GetExceptionInfo<IDictionary<string, object>>(base.currentLogType, _namespace, "FinishSrmTaskByThead", logDict);
            #endregion
            try
            {
                /*
                 * 执行发送给堆垛机的指令任务
                 * 1、验证根据设备号是否找到堆垛机
                 * 2、判断设备是否属于任务完成,如果属于任务完成,就继续走3
                 * 3、判断数据库中是否有可要完成的任务,如果有判断是否跟堆垛机中的完成任务相符,如果相符就处理
                 * 4、更新任务状态
                 */
                int int_deviceId = (int)deviceId;
 
 
 
                //SystemValueUtil.DelayExcuteForSrmTaskThreadService((int)deviceId, ThreadDirectionEnum.任务完成线程);
 
                using (DbModel dbModel = new DbModel())
                {
                    #region //3、判断数据库中是否有可要完成的任务,如果有判断是否跟堆垛机中的完成任务相符,如果相符就处理
                    var currentTask = ValidateIsExistTaskToDispose(dbModel, int_deviceId, out errMsg, TaskExcuteTypeEnum.结束任务);
                    if (currentTask == null)
                    {//表示DB中没有任务要发送给堆垛机
                        //注释以下代码,手动发的任务,不要自动确认
                        ////可以完成 非系统发送的自动任务 [EditBy shaocx,2022-04-04]
                        //if (FormCC.IsSimulationPLC == false && FormCC.srmViewDict[int_deviceId].R_TaskFinish == 1 && FormCC.srmViewDict[int_deviceId].R_TaskNo > 0)
                        //{//只有当堆垛机是任务完成的时候
                        //    ConfirmTaskFinishToSda(deviceId, FormCC.srmViewDict[int_deviceId].R_TaskNo);
                        //}
                        errMsg = "没有堆垛机任务数据要处理";
                        return;
                    }
 
                    #endregion
 
                    //2、判断设备是否任务完成
                    var isFinished = ValidateDeviceTaskIsFinsished(int_deviceId, currentTask, Convert.ToInt32(currentTask.PlcTaskId), (DeviceTaskTypeEnum)Enum.Parse(typeof(DeviceTaskTypeEnum), currentTask.TaskType.ToString()), currentTask.IsAllowSimulateExecute, out errMsg);
                    if (!isFinished) return;
 
 
                    ////判断和堆垛机(或RGV)的连接任务是不是已经完成了
                    var queryTaskState1 = (int)DeviceTaskStatusEnum.未开始;
                    var queryTaskState2 = (int)DeviceTaskStatusEnum.已下发;
                    /*
                  //注释以下方法,因为出现了 某个任务MainTaskSequence 比他小,但是某个任务还未执行的问题 【EditBy shaocx,2022-04-28】
                  //同一个堆垛机的前面未结束的任务,且同种类型
                  var otherSrmTask = dbModel.Task_Part.Where(x => x.DeviceId == int_deviceId
                       && x.Id != currentTask.Id
                       && (x.TaskState == queryTaskState1 || x.TaskState == queryTaskState2)
                       && x.CreateTime < currentTask.CreateTime
                       ).FirstOrDefault();
                  if (otherSrmTask != null)
                  {
                      errMsg = "上一个堆垛机任务未完成,所以堆垛机任务不允许完成!上一个堆垛机任务号:" + otherSrmTask.PlcTaskId + ",本次堆垛机任务号:" + currentTask.PlcTaskId;
                      return;
                  }
                  //*/
 
                    //同一个关联任务的其他设备任务
                    var relevanceTask = dbModel.Task_Part.Where(x => x.MainTaskId == currentTask.MainTaskId && x.TaskSequence < currentTask.TaskSequence
                         && (x.TaskState == queryTaskState1 || x.TaskState == queryTaskState2)).FirstOrDefault();
                    if (relevanceTask != null)
                    {
                        errMsg = string.Format("关联{0}任务未完成,所以堆垛机任务不允许完成!关联任务号:{1}", relevanceTask.DeviceName, relevanceTask.PlcTaskId);
                        return;
                    }
 
 
                    //4、处理任务完成状态 
                    var isOk = ConfirmTaskFinishToSrm(currentTask, "堆垛机任务完成", exception);
                    if (isOk)
                    {
                        //堆垛机完成了当前任务后进行任务状态的修改
                        ChangeTaskStateWhenTaskFinish(currentTask);
                        dbModel.SaveChanges();
                    }
 
                }
            }
            catch (Exception ex)
            {
                errMsg = "出现异常:" + ex.Message;
                SysExceptionInfoHandler.GetExceptionInfoForError("自动结束堆垛机任务线程(线程)出现异常,deviceId:" + deviceId + ",异常:" + ex.Message, ex, ref exception);
                SysExceptionInfoHandler.InsertExceptionInfo(exception, true);
            }
        }
 
 
 
        /// <summary>
        /// 判断是人工发送给任务,单独给堆垛机发送任务完成信号
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="taskId"></param>
        /// <returns></returns>
        private bool ConfirmTaskFinishToSda(int deviceId, int taskId)
        {
            //任务完成处理成功,需要再给堆垛机发送任务完成确认信号
            SdaResEntity sdaResult = new SdaResEntity();
            try
            {
                sdaResult = new SrmService.SrmServiceClient().ConfirmTaskFinish(deviceId, taskId);
 
                if (!sdaResult.result)
                {
                    Log4NetHelper.WriteInfoLog(iWareCommon.Utils.LogType.DataProcess_BZ39_IssueInboundTask, "判断是人工发送的任务,单独给堆垛机发送任务完成信号,【失败】,设备号:" + deviceId + ",任务号:" + taskId);
                    return false;
                }
                else
                {
                    Log4NetHelper.WriteInfoLog(iWareCommon.Utils.LogType.DataProcess_BZ39_IssueInboundTask, "判断是人工发送的任务,单独给堆垛机发送任务完成信号,【成功】,设备号:" + deviceId + ",任务号:" + taskId);
                    return true;
                }
            }
            catch (Exception ex)
            {
                Log4NetHelper.WriteErrorLog(iWareCommon.Utils.LogType.DataProcess_BZ39_IssueInboundTask, "判断是人工发送的任务,单独给堆垛机发送任务完成信号,【异常】,设备号:" + deviceId + ",任务号:" + taskId + ",ex:" + ex.Message, ex);
                throw ex;
            }
        }
 
        #region 向堆垛机发送任务完成确认信号
 
 
        /// <summary>
        /// 向堆垛机发送任务完成确认信号
        /// </summary>
        /// <param name="currentTask"></param>
        /// <param name="business"></param>
        /// <param name="exception"></param>
        /// <returns></returns>
        private bool ConfirmTaskFinishToSrm(Task_Part currentTask, string business, Base_SysExceptionInfo exception)
        {
            //任务完成处理成功,需要再给堆垛机发送任务完成确认信号
            SdaResEntity sdaResult = new SdaResEntity();
            var log = TaskRequestLogHandler.GetTask(currentTask.Id,
              (int)currentTask.DeviceId, currentTask.PlcTaskId, currentTask.RealSourcePlace.ToString(),
              currentTask.RealToPlace.ToString(), "给堆垛机发送任务完成确信指令", "sys");
 
            try
            {
                if (MyExtendHelper.IsAllowSimulatorHandle(currentTask))
                {
                    sdaResult.result = true;
                }
                else
                {
                    sdaResult = new SrmService.SrmServiceClient().ConfirmTaskFinish((int)currentTask.DeviceId, Convert.ToInt32(currentTask.PlcTaskId));
                }
                if (!sdaResult.result)
                {
                    TaskRequestLogHandler.InsertTask(base.currentLogType, RequestStatusEnum.请求失败, JsonConvert.SerializeObject(sdaResult), log, null);
                    exception.exceptionMsg = string.Format(business + ",需要再给堆垛机发送任务完成确认信号失败,设备号{0} 任务号{1}", (int)currentTask.DeviceId, currentTask.PlcTaskId);
                    SysExceptionInfoHandler.InsertExceptionInfo(exception, true);
                    return false;
                }
                else
                {
                    TaskRequestLogHandler.InsertTask(base.currentLogType, RequestStatusEnum.请求成功, JsonConvert.SerializeObject(sdaResult), log, null);
                    Log4NetHelper.WriteInfoLog(base.currentLogType, string.Format(business + ",再给堆垛机发送任务完成确认信号成功,设备号{0} 任务号{1}", (int)currentTask.DeviceId, currentTask.PlcTaskId));
                    return true;
                }
            }
            catch (Exception ex)
            {
                TaskRequestLogHandler.InsertTask(base.currentLogType, RequestStatusEnum.请求失败, JsonConvert.SerializeObject(sdaResult), log, ex);
                throw ex;
            }
        }
 
        #endregion
 
        #endregion
 
        #endregion
 
        #region 公共处理
 
 
        /// <summary>
        /// 验证RGV站点上是否允许下发堆垛机新任务
        /// </summary>
        /// <param name="model"></param>
        /// <param name="_DeviceTaskTypeEnum"></param>
        /// <param name="realToPlace"></param>
        /// <param name="errMsg"></param>
        /// <returns>true:允许,false:不允许</returns>
        private bool ValidateIsAllowNewTaskForRgvStattion(DbModel model, DeviceTaskTypeEnum _DeviceTaskTypeEnum, string realToPlace, ref string errMsg)
        {
            MainInOutFlagEnum _MainInOutFlagEnum = GetMainInOutFlagForSrm(_DeviceTaskTypeEnum);
            if (_MainInOutFlagEnum == MainInOutFlagEnum.出库)
            {
                //判断目标点是否有光电占用
                var rgv_stationCode = model.Base_Station.Where(x => x.SrmStationCode == realToPlace).First();
                var isGD_HasCatogryForRgvStattion = MyExtendHelper.IsGD_HasCatogryForRgvStattion(rgv_stationCode.RgvStationCode);
                if (isGD_HasCatogryForRgvStattion)
                {
                    errMsg = "RGV出库口站点" + rgv_stationCode.RgvStationCode + "上面光电显示有货,不允许下发堆垛机的出库任务";
                    return false;
                }
            }
            return true;
        }
 
        /// <summary>
        /// 根据堆垛机任务类型判断出是出库还是入库
        /// </summary>
        /// <param name="_DeviceTaskTypeEnum"></param>
        /// <returns></returns>
        private MainInOutFlagEnum GetMainInOutFlagForSrm(DeviceTaskTypeEnum _DeviceTaskTypeEnum)
        {
            switch (_DeviceTaskTypeEnum)
            {
                case DeviceTaskTypeEnum.组盘入库:
                case DeviceTaskTypeEnum.空托转运到立体库:
                    return MainInOutFlagEnum.入库;
                case DeviceTaskTypeEnum.立库空托到拆盘机入口:
                case DeviceTaskTypeEnum.出库:
                    return MainInOutFlagEnum.出库;
            }
            throw new Exception("堆垛机不支持的任务类型" + _DeviceTaskTypeEnum.ToString());
        }
 
        /// <summary>
        /// 更新主任务的状态
        /// </summary>
        /// <param name="edm"></param>
        /// <param name="mainTaskId"></param>
        /// <param name="srmTaskTypeValue"></param>
        /// <param name="remark"></param>
        private void UpdateMainTaskStatus(DbModel edm, int mainTaskId, int srmTaskTypeValue, string remark)
        {
            DeviceTaskTypeEnum srmTaskTypeEnum = (DeviceTaskTypeEnum)Enum.Parse(typeof(DeviceTaskTypeEnum), srmTaskTypeValue.ToString());
            MainTaskStatusEnum changeTaskStatus = default(MainTaskStatusEnum);
            switch (srmTaskTypeEnum)
            {
                case DeviceTaskTypeEnum.组盘入库:
                case DeviceTaskTypeEnum.空托转运到立体库:
                    changeTaskStatus = MainTaskStatusEnum.已完成;
                    MainTaskHandler.UpdateTaskStatus(edm, mainTaskId, changeTaskStatus, remark);
                    break;
            }
        }
 
        /// <summary>
        /// 堆垛机任务完成后修改任务状态
        /// </summary>
        /// <param name="currentTask"></param>
        private void ChangeTaskStateWhenTaskFinish(Task_Part currentTask)
        {
            //堆垛机完成了当前任务后进行任务状态的修改
            currentTask.FinishTime = DateTime.Now;//完成时间
            currentTask.IsFinished = true;
            currentTask.TaskState = (int)DeviceTaskStatusEnum.已完成;
            currentTask.TaskStateName = DeviceTaskStatusEnum.已完成.ToString();
            currentTask.OperationRemark = "已完成";
            currentTask.ModifyTime = DateTime.Now;
            currentTask.ModifyBy = SysGloble.WCSSystem;
            //currentTask.IsLastTask = (int)EYesOrNo.否;//设置不是最新的任务
        }
 
        /// <summary>
        /// 堆垛机任务完成后,根据堆垛机的任务类型去判断Base_Salver_V_Station 的State
        /// </summary>
        /// <param name="_DeviceTaskTypeEnum">堆垛机任务类型</param>
        /// <param name="old_int_C_V_P_StateEnum">原先的Base_Salver_V_Station 的State</param>
        /// <returns></returns>
        private Salver_V_Station_StateEnum DeviceTaskTypeEnumToC_V_P_StateEnumWhenTaskFinish(DeviceTaskTypeEnum _DeviceTaskTypeEnum, int old_int_C_V_P_StateEnum)
        {
            Salver_V_Station_StateEnum old_C_V_P_StateEnum = (Salver_V_Station_StateEnum)Enum.Parse(typeof(Salver_V_Station_StateEnum), old_int_C_V_P_StateEnum.ToString());
            Salver_V_Station_StateEnum _C_V_P_StateEnum = old_C_V_P_StateEnum;
            switch (_DeviceTaskTypeEnum)
            {
                case DeviceTaskTypeEnum.组盘入库:
                    _C_V_P_StateEnum = Salver_V_Station_StateEnum.在库物料;
                    break;
                //case DeviceTaskTypeEnum22.线下其他垛入库:
                //    _C_V_P_StateEnum = C_V_P_StateEnum.在库其他料;
                //    break;
                //case DeviceTaskTypeEnum22.线下垫板垛入库:
                //    _C_V_P_StateEnum = C_V_P_StateEnum.在库垫板;
                //    break;
                //case DeviceTaskTypeEnum22.成品料配板完成回库:
                //    _C_V_P_StateEnum = C_V_P_StateEnum.在库成品料;
                //    break;
                //case DeviceTaskTypeEnum22.待拆垛回库:
                //    _C_V_P_StateEnum = C_V_P_StateEnum.在库待拆垛;
                //    break;
                //case DeviceTaskTypeEnum22.桁架垫板垛入立库垫板库位:
                //case DeviceTaskTypeEnum22.锯切垫板垛入立体库:
                //    _C_V_P_StateEnum = C_V_P_StateEnum.在库垫板;
                //    break;
                //case DeviceTaskTypeEnum22.移库://移库,状态不变
                //case DeviceTaskTypeEnum22.成品料上锯切线出库://成品料出库,状态不变
                //case DeviceTaskTypeEnum22.垫板上料出库://垫板出库,状态不变
                //    _C_V_P_StateEnum = old_C_V_P_StateEnum;
                //    break;
                //case DeviceTaskTypeEnum22.配板原料出库:
                //    _C_V_P_StateEnum = C_V_P_StateEnum.原料配板中;
                //    break;
                //case DeviceTaskTypeEnum22.人工出库://出库后会将表Base_Salver_V_Station 清掉
                //    break;
            }
            return _C_V_P_StateEnum;
        }
 
        public override bool ValidateDeviceIsAllowSendTask(int int_deviceId, out string errMsg)
        {
            errMsg = "";
            if (!base.ValidateDeviceIsAllowSendTask(int_deviceId, out errMsg))
            {
                return false;
            }
            if (FormCC.IsSimulationPLC)
            {
                return true;
            }
            using (var srmService = new SrmService.SrmServiceClient())
            {
                SdaResEntity sdaResult = srmService.IsAllowSendTask(int_deviceId, out errMsg);
                if (sdaResult.result == false)
                {
                    errMsg = "非自动、有任务未确认或有报警," + sdaResult.resMsg;
                    Log4NetHelper.WriteErrorLog(currentLogType, "验证堆垛机不可以下发新任务,int_deviceId:" + int_deviceId + ",sdaResultStr:" + JsonConvert.SerializeObject(sdaResult));
                }
                return sdaResult.result;
            }
        }
 
        /// <summary>
        /// 验证堆垛机是否自动
        /// </summary>
        /// <param name="int_deviceId"></param>
        /// <returns></returns>
        public override bool ValidateDeviceIsOK(int int_deviceId, Task_Part _task, int taskId, out string errMsg)
        {
            errMsg = "";
            if (Wms_EquipmentSituationHandler.IsEquipmentBreakdown(int_deviceId).result)
            {//如果设备已经设定为 故障状态,不允许下发任务!!! [EditBy shaocx,2020-12-07]
                errMsg = "设备被设为故障";
                return false;
            }
            if (MyExtendHelper.IsAllowSimulatorHandle(_task))
            {
                errMsg = "模拟PLC";
                return true;
            }
            using (var srmService = new SrmService.SrmServiceClient())
            {
                SdaResEntity sdaResult = srmService.IsReady(int_deviceId, out errMsg);
                errMsg = sdaResult.resMsg;
                return sdaResult.result;
            }
        }
 
        /// <summary>
        /// 验证堆垛机是否任务完成
        /// </summary>
        /// <param name="int_deviceId"></param>
        /// <returns></returns>
        public override bool ValidateDeviceTaskIsFinsished(int int_deviceId, Task_Part _task, int taskId, out string errMsg)
        {
            errMsg = "";
            if (MyExtendHelper.IsAllowSimulatorHandle(_task))
            {//模拟代码!发布时移除该代码
                errMsg = "任务要求强制模拟完成";
                return true;
            }
 
            SdaResEntity sdaResult = new SrmService.SrmServiceClient().IsTaskFinish(int_deviceId, taskId);
            if (sdaResult.result == false)
            {
                errMsg = sdaResult.resMsg;
            }
            return sdaResult.result;
        }
 
        /// <summary>
        /// 验证堆垛机是否任务完成
        /// </summary>
        /// <param name="int_deviceId"></param>
        /// <returns></returns>
        private bool ValidateDeviceTaskIsFinsished(int int_deviceId, Task_Part _task, int taskId, DeviceTaskTypeEnum _DeviceTaskTypeEnum, bool? isAllowSimulateExecute, out string errMsg)
        {
            errMsg = "";
            if (MyExtendHelper.IsAllowSimulatorHandle(_task))
            {
                errMsg = "模拟PLC完成或任务要求强制模拟完成";
                return true;
            }
 
            SdaResEntity sdaResult = new SrmService.SrmServiceClient().IsTaskFinish(int_deviceId, taskId);
            if (sdaResult.result == false)
            {
                errMsg = "验证堆垛机是否任务完成 失败:" + JsonConvert.SerializeObject(sdaResult);
                //Log4NetHelper.WriteErrorLog(currentLogType, "验证堆垛机是否任务完成 失败:" + JsonConvert.SerializeObject(sdaResult));
            }
            switch (_DeviceTaskTypeEnum)
            {
                //涉及到最后到输送线的任务,都要再加上输送线的任务是否完成
                case DeviceTaskTypeEnum.组盘入库:
                    //using (var srmConveyorService = new SrmConveyorService.SrmConveyorServiceClient())
                    //{
                    //    sdaResultStr = srmConveyorService.IsTaskFinish(taskId);
                    //    sdaResult = JsonConvert.DeserializeObject<SdaResEntity>(sdaResultStr);
                    //    if (sdaResult.result == false)
                    //    {
                    //        errMsg = "验证输送线是否任务完成 失败:" + sdaResultStr;
                    //        Log4NetHelper.WriteErrorLog(currentLogType, "验证输送线是否任务完成 失败:" + sdaResultStr);
                    //    }
                    //}
                    break;
            }
 
            return sdaResult.result;
        }
 
        #endregion
 
        #region 私有方法
 
        /// <summary>
        /// 验证数据库中是否有任务要处理
        /// </summary>
        /// <typeparam name="Task_Part"></typeparam>
        /// <param name="dbModel"></param>
        /// <param name="int_deviceId">Rgv设备号</param>
        /// <param name="errMsg"></param>
        /// <param name="_TaskExcuteTypeEnum"></param>
        /// <returns></returns>
        private List<Task_Part> ValidateIsExistTaskToDisposeForIssued(DbModel dbModel, int int_deviceId, out string errMsg)
        {
            errMsg = "";
            List<Task_Part> partList = new List<Task_Part>();
            //看同一个设备,是否还有其他正在执行的任务!
            var partTask = dbModel.Task_Part.Where(x => x.DeviceId == int_deviceId && x.TaskState == (int)DeviceTaskStatusEnum.已下发).
                OrderBy(x => x.CreateTime).FirstOrDefault();//按照主任务的顺序升序
            if (partTask != null)
            {
                errMsg = string.Format("deviceId={0}的正在执行任务,任务ID:" + partTask.Id + ",主任务:" + partTask.MainTaskNo + ",PLC任务号:" + partTask.PlcTaskId, int_deviceId);
                return null;
            }
 
            //1、查询
            var currTaskList = dbModel.Task_Part.Where(x => x.DeviceId == int_deviceId && x.TaskState == (int)DeviceTaskStatusEnum.未开始).ToList().OrderBy(x => x.CreateTime).ToList();//按照主任务优先级的升序排序
            if (currTaskList == null || currTaskList.Count == 0)
            {
                errMsg = "没有需要处理的任务";
                return null;
            }
 
 
            var firstTask = currTaskList.First();//第一个待执行的任务
            partList.Add(firstTask);
            //判断如果这个任务是出库任务的话,就再查询第一个待执行的入库任务
            DeviceTaskTypeEnum _DeviceTaskTypeEnum = (DeviceTaskTypeEnum)Enum.Parse(typeof(DeviceTaskTypeEnum), firstTask.TaskType.ToString());
            //查询 出库和入库的两个任务,优先执行出库任务 【EditBy shaocx,2022-05-09】
            MainInOutFlagEnum _MainInOutFlagEnum = GetMainInOutFlagForSrm(_DeviceTaskTypeEnum);
            if (_MainInOutFlagEnum == MainInOutFlagEnum.出库)
            {
                //查询第一个待执行的入库任务
                var queryInOutFlag = (int)MainInOutFlagEnum.入库;
                var fisrtTaskForIn = currTaskList.Where(x => x.InOutFlag == queryInOutFlag).ToList().OrderBy(x => x.CreateTime).FirstOrDefault();
                if (fisrtTaskForIn != null)
                {
                    partList.Add(fisrtTaskForIn);
                }
            }
            return partList;
        }
 
        #endregion
    }
}