ke_junjie
2025-06-04 84620534eb627e95811b971a4b552b6a177829bf
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
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.Entity.ParamModel;
using Newtonsoft.Json;
using iWareCC.BLL;
using iWareCC.Common;
 
using iWareModel;
using iWareCommon.Common.Globle;
using XiGang.Core.Model;
using iWareCC.Common.Helper;
using iWareModel.EnumType.AoSinPublicCommon;
using Admin.NET.Core.TaskModule.Enum;
using iWareSql.DbOrm;
using iWareSql.DataAccess;
using static WZ.Useful.Commons.DGVPrinter;
using System.Runtime.Remoting.Contexts;
 
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.isStartedModel)
                {
                    IssueTaskHandle(i_deviceId, out errMsg1);
                }
                //else if ((int)deviceId == (int)EDevice.二号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_2 && SystemValue.isStartedModel)
                //{
                //    IssueTaskHandle(i_deviceId, out errMsg2);
                //}
 
                SystemWarningMsg._lbl_Alert_Srm1Release = errMsg1;
                SystemWarningMsg._lbl_Alert_Srm2Release = errMsg2;
 
                Thread.Sleep(500);//2秒一次
            }
        }
 
        /// <summary>
        /// 自动执行堆垛机任务(线程)
        /// </summary>
        /// <param name="srmName"></param>
        public override void IssueTaskHandle(int deviceId, out string errMsg)
        {
            errMsg = "";
            try
            {
                int int_deviceId = (int)deviceId;
                var vs = new SrmServiceClient();
                //2、判断堆垛机是否可以下发新任务
                SdaResEntity sdaResult = vs.IsAllowSendTask(int_deviceId, out errMsg);
                if (sdaResult.result == false)
                {
                    errMsg = $"非自动、有任务未确认或有报警,{errMsg}";
                    return;
                }
                //bool isOk = ValidateDeviceIsAllowSendTask(int_deviceId, out errMsg);
                //if (!isOk)
                //{
                //    errMsg = "不允许下发新任务," + errMsg;
                //    return;
                //}
 
                using (DbOrm dbOrm = new DbOrm())
                {
                    var srmTaskList = ValidateIsExistTaskToDisposeForIssued(dbOrm, int_deviceId, out errMsg);
                    if (srmTaskList == null || srmTaskList.Count == 0)
                    {
                        //表示DB中没有任务要发送给堆垛机
                        errMsg = $"没有要执行的堆垛机任务";
                        return;
                    }
                    foreach (var item in srmTaskList)
                    {
                        SingleIssueTaskHandle(item, dbOrm, int_deviceId, vs, out errMsg);
                        if (!string.IsNullOrEmpty(errMsg))
                        {//说明报错了,继续走下一个循环
                            continue;
                        }
                        else
                        {//说明执行成功了,跳出循环
                            //修改下发的堆垛机任务状态,0->1
                            item.TaskState = (int)SubTaskStateEnum.已下发;
                            dbOrm.SaveChanges();
                            break;
                        }
                    }
                }
                vs.Close();
            }
            catch (Exception ex)
            {
                errMsg = "异常,请联系管理员:" + ex.Message;
                //SysExceptionInfoHandler.GetExceptionInfoForError("自动执行堆垛机任务(线程)出现异常,deviceId:" + deviceId + ",异常:" + ex.Message, ex, ref exception);
                //SysExceptionInfoHandler.InsertExceptionInfo(exception, true);
            }
        }
 
        private string GetRealLocatiomCodeOut(string sourcePlace)
        {
            switch (sourcePlace)
            {
                case "102":
                    return "1-00-901-00";
                //case "202":
                //    return "1-00-902-00";
                //case "203":
                //    return "2-00-901-00";
                //case "204":
                //    return "2-00-902-00";
                default:
                    return "ERROR";
            }
        }
 
        private string GetRealLocatiomCodeIn(string sourcePlace)
        {
            switch (sourcePlace)
            {
                case "102":
                    return "1-00-801-00";
                //case "202":
                //    return "1-00-802-00";
                //case "203":
                //    return "2-00-801-00";
                //case "204":
                //    return "2-00-802-00";
                default:
                    return "ERROR";
            }
        }
 
        /// <summary>
        /// 单个堆垛机任务下发处理
        /// </summary>
        /// <param name="srmTask"></param>
        /// <param name="exception"></param>
        /// <param name="dbOrm"></param>
        /// <param name="int_deviceId"></param>
        /// <param name="errMsg"></param>
        private void SingleIssueTaskHandle(ware_task_sub srmTask, DbOrm dbOrm, int int_deviceId, SrmServiceClient vs, out string errMsg)
        {
            #region //3、判断数据库中是否有可要下发的任务,如果有就下发
 
            DeviceTaskTypeEnum _DeviceTaskTypeEnum = (DeviceTaskTypeEnum)Enum.Parse(typeof(DeviceTaskTypeEnum), srmTask.TaskType.ToString());
            EDevice device = (EDevice)Enum.Parse(typeof(EDevice), int_deviceId.ToString());
            string realSourcePlace = "";
            string realToPlace = "";
            bool isOk;
            if (srmTask.TaskType == (int)TaskCategoryEnum.InStock)
            {
                realSourcePlace = GetRealLocatiomCodeIn(srmTask.SourcePlace);
                realToPlace = srmTask.ToPlace;
 
                if (realToPlace.Substring(2).StartsWith("02"))
                {
                    //查看该1排是否有货
                    var arr = realToPlace.Split('-');
                    string newstr = arr[0] + "-" + "01" + "-" + arr[2] + "-" + arr[3];
                    //看1排是否有货,无货放1排
                    var lvc = dbOrm.ware_location_vs_container.AsNoTracking().Any(u => u.WareLocationCode == newstr);
                    if (!lvc)
                    {
                        var container1 = dbOrm.wms_container.Where(u => u.RealLocationCode == newstr).FirstOrDefault();
                        if (container1 != null)
                        {
                            container1.RealLocationCode = realToPlace;
                        }
                        //查看是否有指向1排原绑定库位的任务
                        var newtask = dbOrm.ware_task.Where(u => u.ToLocationCode == newstr).FirstOrDefault();
                        if (newtask != null)
                        {
                            newtask.ToLocationCode = realToPlace;
                            var newtasksub = dbOrm.ware_task_sub.Where(u => u.TaskId == newtask.Id && u.DeviceId == int_deviceId && u.ToPlace == newstr).FirstOrDefault();
                            if (newtasksub != null)
                            {
                                newtasksub.ToPlace = realToPlace;
                            }
                        }
 
                        //目标库位修改为1排
                        realToPlace = newstr;
 
                        var container = dbOrm.wms_container.Where(u => u.ContainerCode == srmTask.ContainerCode).FirstOrDefault();
                        container.RealLocationCode = newstr;
 
                        srmTask.ToPlace = realToPlace;
 
                        //主任务也修改
                        var maintask = dbOrm.ware_task.Where(u => u.Id == srmTask.TaskId).FirstOrDefault();
                        maintask.ToLocationCode = realToPlace;
                    }
                }
                //else if (realToPlace.Substring(2).StartsWith("01"))
                //{
                //    //查看该1排是否有货
                //    var arr = realToPlace.Split('-');
                //    string newstr = arr[0] + "-" + "02" + "-" + arr[2] + "-" + arr[3];
                //    var lvc = dbOrm.ware_location_vs_container.AsNoTracking().Any(u => u.WareLocationCode == realToPlace);
                //    if (lvc)//有货就换到2排
                //    {
                //        //目标库位修改为1排
                //        realToPlace = newstr;
 
                //        var container = dbOrm.wms_container.Where(u => u.ContainerCode == srmTask.ContainerCode).FirstOrDefault();
                //        container.RealLocationCode = realToPlace;
 
                //        srmTask.ToPlace = realToPlace;
 
                //        //主任务也修改
                //        var maintask = dbOrm.ware_task.Where(u => u.Id == srmTask.TaskId).FirstOrDefault();
                //        maintask.ToLocationCode = realToPlace;
                //    }
                //}
                isOk = dbOrm.ware_location_vs_container.Any(x => x.WareLocationCode == realToPlace && x.WareContainerCode != srmTask.ContainerCode && x.IsDeleted == false);
                if (isOk)
                {
                    errMsg = device.ToString() + "不允许下发新任务,目标库位" + realToPlace + "系统显示有库存";
                    return;
                }
            }
            else if (srmTask.TaskType == (int)TaskCategoryEnum.OutStock)
            {
                realSourcePlace = srmTask.SourcePlace;
                realToPlace = GetRealLocatiomCodeOut(srmTask.ToPlace);
 
                //判断是否存在指向放货站台的执行中的任务
                isOk = dbOrm.ware_task_sub.Any(x => x.ToPlace == srmTask.ToPlace && x.TaskState == (int)SubTaskStateEnum.已下发);
                if (isOk)
                {
                    errMsg = "存在指向目标点" + srmTask.ToPlace + "的任务,不能下发同一目标点的任务";
                    return;
                }
            }
            else
            {
                realSourcePlace = srmTask.SourcePlace;
                realToPlace = srmTask.ToPlace;
 
                if (realToPlace.Substring(2).StartsWith("02") && realToPlace != "1-02-06-04")
                {
                    //查看该1排是否有货
                    var arr = realToPlace.Split('-');
                    string newstr = arr[0] + "-" + "01" + "-" + arr[2] + "-" + arr[3];
                    //看1排是否有货,无货放1排
                    var lvc = dbOrm.ware_location_vs_container.AsNoTracking().Any(u => u.WareLocationCode == newstr);
                    if (!lvc)
                    {
                        var container1 = dbOrm.wms_container.Where(u => u.RealLocationCode == newstr).FirstOrDefault();
                        if (container1 != null)
                        {
                            container1.RealLocationCode = realToPlace;
                        }
                        //查看是否有指向1排原绑定库位的任务
                        var newtask = dbOrm.ware_task.Where(u => u.ToLocationCode == newstr).FirstOrDefault();
                        if (newtask != null)
                        {
                            newtask.ToLocationCode = realToPlace;
                            var newtasksub = dbOrm.ware_task_sub.Where(u => u.TaskId == newtask.Id && u.DeviceId == int_deviceId && u.ToPlace == newstr).FirstOrDefault();
                            if (newtasksub != null)
                            {
                                newtasksub.ToPlace = realToPlace;
                            }
                        }
 
                        //目标库位修改为1排
                        realToPlace = newstr;
 
                        var container = dbOrm.wms_container.Where(u => u.ContainerCode == srmTask.ContainerCode).FirstOrDefault();
                        container.RealLocationCode = newstr;
 
                        srmTask.ToPlace = realToPlace;
 
                        //主任务也修改
                        var maintask = dbOrm.ware_task.Where(u => u.Id == srmTask.TaskId).FirstOrDefault();
                        maintask.ToLocationCode = realToPlace;
                    }
                }
 
                //判断是否存在指向放货站台的执行中的任务
                isOk = dbOrm.ware_task_sub.Any(x => x.ToPlace == srmTask.ToPlace && x.TaskState == (int)SubTaskStateEnum.已下发);
                if (isOk)
                {
                    errMsg = "存在指向目标点" + srmTask.SourcePlace + "的任务,不能下发同一目标点的任务";
                    return;
                }
            }
 
            //判断堆垛机是否有执行中的任务任务 【EditBy kejj,2022-09-22】
            isOk = dbOrm.ware_task_sub.Any(u => u.DeviceId == int_deviceId && u.TaskState == (int)SubTaskStateEnum.执行中);
            if (isOk)
            {
                errMsg = "不允许下发新任务,当前堆垛机存在执行中的任务";
                return;
            }
 
            //同一个关联任务的其他设备任务
            var relevanceTask = dbOrm.ware_task_sub.Where(x => x.TaskId == srmTask.TaskId && x.TaskSequence < srmTask.TaskSequence && x.TaskState == (int)SubTaskStateEnum.未开始).FirstOrDefault();
            if (relevanceTask != null)
            {
                errMsg = string.Format("关联{0}任务未开始,所以堆垛机任务不允许下发!关联任务号:{1}", Enum.Parse(typeof(EDevice), relevanceTask.DeviceId.ToString()).ToString(), relevanceTask.TaskNo);
                return;
            }
 
            ESrmCmd eSrmCmd;
            if (srmTask.TaskType == (int)TaskCategoryEnum.InStock)
            {
                eSrmCmd = ESrmCmd.入库;
            }
            else if (srmTask.TaskType == (int)TaskCategoryEnum.OutStock)
            {
                eSrmCmd = ESrmCmd.出库;
            }
            else
            {
                eSrmCmd = ESrmCmd.库内搬运;
            }
            SdaResEntity sdaResult = new SdaResEntity();
            try
            {
                if (WCSConfigHelper.GetConfig_IsSimulationPLC())
                {
                    sdaResult.result = true;
                }
                else
                {
                    if (Convert.ToInt32(srmTask.TaskNo) <= 0)
                    {
                        throw new Exception("任务号不能小于等于0,PlcTaskId:" + srmTask.TaskNo);
                    }
                    //short pallettype = GetSrmContainerType(srmTask.ContainerType);
                    short pallettype = Convert.ToInt16(srmTask.ContainerType);
                    if (pallettype == 0)
                    {
                        throw new Exception("托盘类型不能等于0,PlcTaskId:" + srmTask.TaskNo);
                    }
 
                    sdaResult = vs.SendSrmTask(int_deviceId, Convert.ToInt32(srmTask.TaskNo), realSourcePlace, realToPlace, (short)eSrmCmd, /*GetSrmContainerType(*/Convert.ToInt16(srmTask.ContainerType)/*)*/);
                }
                if (sdaResult.result == false)
                {//给堆垛机下发指令失败
                    //exception.exceptionMsg = string.Format("发送指令给堆垛机失败,设备号{0},任务ID{1},起始位{2},目标位{3},ContainerId{4}", int_deviceId,
                    //    Convert.ToInt32(srmTask.TaskNo), realSourcePlace, realToPlace, srmTask.ContainerCode);
                    //SysExceptionInfoHandler.InsertExceptionInfo(exception, true);
                    errMsg = string.Format("发送指令给堆垛机失败,设备号{0},任务ID{1},起始位{2},目标位{3},ContainerId{4}", int_deviceId,
                        Convert.ToInt32(srmTask.TaskNo), realSourcePlace, realToPlace, srmTask.ContainerCode);
                    return;
                }
                else
                {
                    //SystemValueUtil.DelayExcuteForSrmTaskThreadService(int_deviceId, ThreadDirectionEnum.任务开始下发线程);
                    errMsg = "";
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            #endregion
        }
 
        public short GetSrmContainerType(int? conveyorContainerType)
        {
            if (conveyorContainerType == 1)
            {
                return 2;
            }
            else if (conveyorContainerType == 3)
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }
        #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.isStartedModel)
                {
                    ConfirmFinishTaskHandle(i_deviceId, out errMsg1);
                }
                //else if ((int)deviceId == (int)EDevice.二号堆垛机 && SystemValue.isAllowRuning_SrmTaskThreadService_2_Finish && SystemValue.isStartedModel)
                //{
                //    ConfirmFinishTaskHandle(i_deviceId, out errMsg2);
                //}
 
                SystemWarningMsg._lbl_Alert_Srm1ReleaseFinish = errMsg1;
                SystemWarningMsg._lbl_Alert_Srm2ReleaseFinish = errMsg2;
 
                Thread.Sleep(500);//设置2秒一次
            }
        }
 
        /// <summary>
        /// 自动结束堆垛机任务线程(线程)
        /// </summary>
        /// <param name="srmName"></param>
        public override void ConfirmFinishTaskHandle(int deviceId, out string errMsg)
        {
            errMsg = "";
            try
            {
                /*
                 * 执行发送给堆垛机的指令任务
                 * 1、验证根据设备号是否找到堆垛机
                 * 2、判断设备是否属于任务完成,如果属于任务完成,就继续走3
                 * 3、判断数据库中是否有可要完成的任务,如果有判断是否跟堆垛机中的完成任务相符,如果相符就处理
                 * 4、更新任务状态
                 */
                int int_deviceId = (int)deviceId;
                var vs = new SrmService.SrmServiceClient();
                using (DbOrm dbOrm = new DbOrm())
                {
                    #region //3、判断数据库中是否有可要完成的任务,如果有判断是否跟堆垛机中的完成任务相符,如果相符就处理
                    var currentTask = ValidateIsExistTaskToDispose(dbOrm, int_deviceId, out errMsg, SubTaskStateEnum.已完成);
                    if (currentTask == null)
                    {//表示DB中没有任务要发送给堆垛机
                        errMsg = "没有堆垛机任务数据要处理";
                        return;
                    }
 
                    #endregion
 
                    //2、判断设备是否任务完成
                    //var isFinished = ValidateDeviceTaskIsFinsished(int_deviceId, currentTask, Convert.ToInt32(currentTask.TaskNo), (DeviceTaskTypeEnum)Enum.Parse(typeof(DeviceTaskTypeEnum), currentTask.TaskType.ToString()), true, out errMsg);
                    //if (!isFinished) return;
 
                    SdaResEntity sdaResult = vs.IsTaskFinish(int_deviceId, Convert.ToInt32(currentTask.TaskNo));
                    if (sdaResult.result != true)
                    {
                        errMsg = $"验证堆垛机是否任务完成 失败:{sdaResult.resMsg}";
                        return;
                    }
 
                    //同一个关联任务的其他设备任务
                    var relevanceTask = dbOrm.ware_task_sub.Where(x => x.TaskId == currentTask.TaskId && x.TaskSequence < currentTask.TaskSequence
                         && (x.TaskState != (int)SubTaskStateEnum.已完成)).FirstOrDefault();
                    if (relevanceTask != null)
                    {
                        errMsg = string.Format("关联{0}任务未完成,所以堆垛机任务不允许完成!关联任务号:{1}", Enum.Parse(typeof(EDevice), relevanceTask.DeviceId.ToString()).ToString(), relevanceTask.TaskNo);
                        return;
                    }
 
                    //4、处理任务完成状态 
                    //var isOk = ConfirmTaskFinishToSrm(currentTask, "堆垛机任务完成");
 
                    sdaResult = vs.ConfirmTaskFinish((int)currentTask.DeviceId, Convert.ToInt32(currentTask.TaskNo));
                    if (sdaResult.result)
                    {
                        //using (var tran = dbOrm.Database.BeginTransaction())
                        //{
                        //try
                        //{
                        //堆垛机完成了当前任务后进行任务状态的修改
                        //ChangeTaskStateWhenTaskFinish(currentTask);
                        currentTask.FinishedTime = DateTime.Now;//完成时间
                        currentTask.TaskState = (int)SubTaskStateEnum.已完成;
                        var isExist = dbOrm.ware_task_sub.Any(u => u.TaskId == currentTask.TaskId && u.TaskState != (int)SubTaskStateEnum.已完成 && u.Id != currentTask.Id);
                        if (!isExist)
                        {
                            var maintask = dbOrm.ware_task.Where(u => u.Id == currentTask.TaskId).FirstOrDefault();
                            if (maintask != null)
                            {
                                maintask.TaskState = (int)TaskStateEnum.已完成;
                            }
                        }
                        dbOrm.SaveChanges();
 
                        //tran.Commit();
                        //}
                        //catch (Exception)
                        //{
                        //tran.Rollback();
                        //    throw;
                        //}
                        //}
                    }
 
                }
                vs.Close();
            }
            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.SrmTheadService, "判断是人工发送的任务,单独给堆垛机发送任务完成信号,【失败】,设备号:" + deviceId + ",任务号:" + taskId);
                    return false;
                }
                else
                {
                    Log4NetHelper.WriteInfoLog(iWareCommon.Utils.LogType.SrmTheadService, "判断是人工发送的任务,单独给堆垛机发送任务完成信号,【成功】,设备号:" + deviceId + ",任务号:" + taskId);
                    return true;
                }
            }
            catch (Exception ex)
            {
                Log4NetHelper.WriteErrorLog(iWareCommon.Utils.LogType.SrmTheadService, "判断是人工发送的任务,单独给堆垛机发送任务完成信号,【异常】,设备号:" + 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(ware_task_sub currentTask, string business)
        {
            //任务完成处理成功,需要再给堆垛机发送任务完成确认信号
            SdaResEntity sdaResult = new SdaResEntity();
            string realSourcePlace = "";
            string realToPlace = "";
            if (currentTask.TaskType == (int)TaskCategoryEnum.InStock)
            {
                realSourcePlace = GetRealLocatiomCodeIn(currentTask.SourcePlace);
                realToPlace = currentTask.ToPlace;
            }
            else if (currentTask.TaskType == (int)TaskCategoryEnum.OutStock)
            {
                realSourcePlace = currentTask.SourcePlace;
                realToPlace = GetRealLocatiomCodeOut(currentTask.ToPlace);
            }
            try
            {
                if (WCSConfigHelper.GetConfig_IsSimulationPLC())
                {
                    sdaResult.result = true;
                }
                else
                {
                    sdaResult = new SrmService.SrmServiceClient().ConfirmTaskFinish((int)currentTask.DeviceId, Convert.ToInt32(currentTask.TaskNo));
                }
                if (!sdaResult.result)
                {
                    //exception.exceptionMsg = string.Format(business + ",需要再给堆垛机发送任务完成确认信号失败,设备号{0} 任务号{1}", (int)currentTask.DeviceId, currentTask.TaskNo);
                    //SysExceptionInfoHandler.InsertExceptionInfo(exception, true);
                    return false;
                }
                else
                {
                    Log4NetHelper.WriteInfoLog(base.currentLogType, string.Format(business + ",再给堆垛机发送任务完成确认信号成功,设备号{0} 任务号{1}", (int)currentTask.DeviceId, currentTask.TaskNo));
                    return true;
                }
            }
            catch (Exception 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="currentTask"></param>
        private void ChangeTaskStateWhenTaskFinish(ware_task_sub currentTask)
        {
            //堆垛机完成了当前任务后进行任务状态的修改
            currentTask.FinishedTime = DateTime.Now;//完成时间
            //currentTask.IsFinished = true;
            currentTask.TaskState = (int)SubTaskStateEnum.已完成;
            //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)
        {
            if (FormCC.IsSimulationPLC)
            {
                errMsg = "模拟PLC";
                return true;
            }
            //errMsg = "";
            if (!base.ValidateDeviceIsAllowSendTask(int_deviceId, out errMsg))
            {
                return false;
            }
            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>
        private bool ValidateDeviceTaskIsFinsished(int int_deviceId, ware_task_sub _task, int taskId, DeviceTaskTypeEnum _DeviceTaskTypeEnum, bool? isAllowSimulateExecute, out string errMsg)
        {
            errMsg = "";
            if (WCSConfigHelper.GetConfig_IsSimulationPLC())
            {
                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<ware_task_sub> ValidateIsExistTaskToDisposeForIssued(DbOrm dbOrm, int int_deviceId, out string errMsg)
        {
            errMsg = "";
            List<ware_task_sub> partList = new List<ware_task_sub>();
            //看同一个设备,是否还有其他正在执行的任务
            var partTask = dbOrm.ware_task_sub.Where(x => x.DeviceId == int_deviceId && x.TaskState == (int)SubTaskStateEnum.已下发).
                OrderBy(x => x.CreatedTime).FirstOrDefault();//按照主任务的顺序升序
            if (partTask != null)
            {
                errMsg = string.Format("deviceId={0}的正在执行任务,任务ID:" + partTask.Id + ",主任务:" + partTask.TaskId + ",PLC任务号:" + partTask.TaskNo, int_deviceId);
                return null;
            }
 
            //1、查询
            var currTaskList = dbOrm.ware_task_sub.Where(x => x.DeviceId == int_deviceId && (x.TaskState == (int)SubTaskStateEnum.未开始 || x.TaskState == (int)SubTaskStateEnum.等待下发)).ToList().OrderBy(x => x.CreatedTime).ToList();//按照主任务优先级的升序排序
            if (currTaskList == null || currTaskList.Count == 0)
            {
                errMsg = "没有需要处理的任务";
                return null;
            }
 
            //查找所有AGV任务
            var agvTaskList = dbOrm.ware_task_sub.AsNoTracking().Where(u => u.DeviceId == 1099).ToList();
            var currentAgvTask = agvTaskList.Find(u => u.TaskState == (int)SubTaskStateEnum.已完成);
            if (currentAgvTask == null)
            {
                //查找AGV执行步骤最高的
                currentAgvTask = agvTaskList.OrderByDescending(u => u.TaskState).FirstOrDefault();
            }
 
            if (currentAgvTask != null)
            {
                //currentAgvTask是执行步骤最高的agv,优先下这个的关联任务
                var vs = currTaskList.FindAll(u => u.TaskId == currentAgvTask.TaskId).OrderBy(u => u.TaskSequence).FirstOrDefault();
                if (vs != null)
                {
                    if (vs.TaskState == (int)SubTaskStateEnum.等待下发)
                    {
                        errMsg = $"目标点{vs.ToPlace}的堆垛机任务等待下发";
                        return null;
                    }
                    else
                    {
                        partList.Add(vs);
                        return partList;
                    }
                }
                else
                {
                    //执行步骤最高的agv没有待处理的堆垛机任务
                    //查找另一个agv任务
                    var anotherAgvTask = agvTaskList.Find(u => u.TaskId != currentAgvTask.TaskId);
                    if (anotherAgvTask == null)
                    {
                        var temp = currTaskList.Find(u => u.TaskType == (int)TaskCategoryEnum.MoveStock && u.TaskSequence == 1);
                        if (temp != null)
                        {
                            partList.Add(temp);
                            return partList;
                        }
                        errMsg = "没有任务要执行";
                        return null;
                    }
                    else
                    {
                        var anthorSrmTask = currTaskList.FindAll(u => u.TaskId == anotherAgvTask.TaskId).OrderBy(u => u.TaskSequence).FirstOrDefault(); ;
                        if (anthorSrmTask != null)
                        {
                            if (anthorSrmTask.TaskState == (int)SubTaskStateEnum.等待下发)
                            {
                                errMsg = $"目标点{anthorSrmTask.ToPlace}的堆垛机任务等待下发";
                                return null;
                            }
                            else
                            {
                                partList.Add(vs);
                                return partList;
                            }
                        }
                        else
                        {
                            errMsg = "没有任务要执行";
                            return null;
                        }
                    }
                }
            }
            else
            {
                var temp = currTaskList.Find(u => u.TaskType == (int)TaskCategoryEnum.MoveStock && u.TaskSequence == 1);
                if (temp != null)
                {
                    partList.Add(temp);
                    return partList;
                }
                else
                {
                    return null;
                }
            }
 
 
 
            //查找AGV执行步骤最高的
            //var agvTask = dbOrm.ware_task_sub.AsNoTracking().Where(u => u.TaskState > 0 && u.DeviceId == 1099).OrderByDescending(u => u.TaskState).FirstOrDefault();
            //ware_task_sub temp = null;
            //if (agvTask == null)
            //{
            //    temp = currTaskList.Find(u => u.TaskType == (int)TaskCategoryEnum.MoveStock);
            //    if (temp == null)
            //    {
            //        errMsg = "agv没有到达,等待下发";
            //        return null;
            //    }
            //    else
            //    {
            //        partList.Add(temp);
            //        return partList;
            //    }
            //}
 
 
            //var firstTask = currTaskList.First();//第一个待执行的任务
            //var firstTask = currTaskList.Find(u => u.TaskId == agvTask.TaskId);
            //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
    }
}