wanshenmean
2026-02-05 c388f1acccd0b7e76a4366fbaddaca6551826b74
添加拘束/插拔钉机和堆垛机基类

为QuartzJob项目引入新机器实现和堆垛起重机框架:添加ConstraintMachine/IConstraintMachine、PinMachine/IPinMachine、IStackerCraneBase/StackerCraneBase及相关IStackerCrane、CommonStackerCrane与状态枚举。添加规格类(SpeTemperatureStackerCrane、SpeFormationStackerCrane)并更新堆垛起重机文件。添加/修改设备协议构件(DeviceProtocolDetail DTO/模型及DeviceProtocolDetailService/IDeviceProtocolDetailService),调整QuartzNetExtension和TaskService。在WIDESEAWCS_Tasks下添加新任务存根和数据库名称助手(ConveyorLineNewJob、PinMachine等)。同时包含工作空间元数据变更(.vs DocumentLayout和CopilotIndices)并添加一份DOCX规范文件。
已添加16个文件
已修改15个文件
2586 ■■■■■ 文件已修改
Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/18.0.988.22099/CodeChunks.db 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/18.0.988.22099/SemanticSymbols.db 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v18/DocumentLayout.json 351 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConstraintMachine/ConstraintMachine.cs 213 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConstraintMachine/IConstraintMachine.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DTO/DeviceProtocolDetailDTO.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Models/Dt_DeviceProtocolDetail.cs 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/PinMachine/IPinMachine.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/PinMachine/PinMachine.cs 213 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/QuartzNetExtension.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/DeviceProtocolDetailService.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/IDeviceProtocolDetailService.cs 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/IRouterService.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Common/CommonStackerCrane.cs 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Common/IStackerCraneBase.cs 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Common/StackerCraneBase.cs 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Enum/StackerCraneStatus.cs 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Enum/TemperatureStackerStatus.cs 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/IStackerCrane.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Spec/SpeFormationStackerCrane.cs 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Spec/SpeTemperatureStackerCrane.cs 455 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs 160 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConstraintMachine/ConstraintMachineDBName.cs 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLine/ConveyorLineDBNameNew.cs 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLine/ConveyorLineTaskCommandNew.cs 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs 348 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/PinMachine/PinMachineCommand.cs 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/PinMachine/PinMachineDBName.cs 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目资料/上位系统对接/QKNY-MES-FW-MES系统设备集成接口文档-V2.35-20250711.docx 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/18.0.988.22099/CodeChunks.db
Binary files differ
Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/18.0.988.22099/SemanticSymbols.db
Binary files differ
Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v18/DocumentLayout.json
@@ -3,64 +3,48 @@
  "WorkspaceRootPath": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\",
  "Documents": [
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\socketserver\\tcpsocketserver.messaging.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\socketserver\\tcpsocketserver.messaging.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\socketserver\\socketserveroptions.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\socketserver\\socketserveroptions.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\socketserver\\tcpsocketserver.clients.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\socketserver\\tcpsocketserver.clients.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\robotjob\\robotjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\robotjob\\robotjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_server\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}",
      "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\socketserver\\tcpsocketserver.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\socketserver\\tcpsocketserver.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\socketserver\\tcpsocketserver.server.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\socketserver\\tcpsocketserver.server.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{83F18A31-5983-4587-A0B2-414BF70E50B5}|WIDESEAWCS_TaskInfoService\\WIDESEAWCS_TaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{83F18A31-5983-4587-A0B2-414BF70E50B5}|WIDESEAWCS_TaskInfoService\\WIDESEAWCS_TaskInfoService.csproj|solutionrelative:wideseawcs_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_common\\taskenum\\taskstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|solutionrelative:wideseawcs_common\\taskenum\\taskstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_common\\taskenum\\taskenumhelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|solutionrelative:wideseawcs_common\\taskenum\\taskenumhelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_common\\taskenum\\tasktypeenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|solutionrelative:wideseawcs_common\\taskenum\\tasktypeenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\stackercranejob\\commonstackercranejob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\stackercranejob\\commonstackercranejob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{7279A2AE-8D1F-4E66-A73A-01AF7927A336}|WIDESEAWCS_ITaskInfoService\\WIDESEAWCS_ITaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{7279A2AE-8D1F-4E66-A73A-01AF7927A336}|WIDESEAWCS_ITaskInfoService\\WIDESEAWCS_ITaskInfoService.csproj|solutionrelative:wideseawcs_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
      "AbsoluteMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_quartzjob\\quartznet\\quartznetextension.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|solutionrelative:wideseawcs_quartzjob\\quartznet\\quartznetextension.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_quartzjob\\service\\deviceprotocoldetailservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|solutionrelative:wideseawcs_quartzjob\\service\\deviceprotocoldetailservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_quartzjob\\service\\ideviceprotocoldetailservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|solutionrelative:wideseawcs_quartzjob\\service\\ideviceprotocoldetailservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_quartzjob\\stackercrane\\spec\\spetemperaturestackercrane.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|solutionrelative:wideseawcs_quartzjob\\stackercrane\\spec\\spetemperaturestackercrane.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_quartzjob\\stackercrane\\spec\\speformationstackercrane.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|solutionrelative:wideseawcs_quartzjob\\stackercrane\\spec\\speformationstackercrane.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_quartzjob\\stackercrane\\common\\commonstackercrane.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|solutionrelative:wideseawcs_quartzjob\\stackercrane\\common\\commonstackercrane.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_quartzjob\\stackercrane\\istackercrane.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|solutionrelative:wideseawcs_quartzjob\\stackercrane\\istackercrane.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_quartzjob\\stackercrane\\common\\istackercranebase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|solutionrelative:wideseawcs_quartzjob\\stackercrane\\common\\istackercranebase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_quartzjob\\stackercrane\\common\\stackercranebase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|solutionrelative:wideseawcs_quartzjob\\stackercrane\\common\\stackercranebase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\formationstackercranejob\\formationcommonstackercranejob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\formationstackercranejob\\formationcommonstackercranejob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_quartzjob\\quartznet\\quartznetextension.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|solutionrelative:wideseawcs_quartzjob\\quartznet\\quartznetextension.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    }
  ],
  "DocumentGroupContainers": [
@@ -70,8 +54,34 @@
      "DocumentGroups": [
        {
          "DockedWidth": 200,
          "SelectedChildIndex": 14,
          "SelectedChildIndex": 13,
          "Children": [
            {
              "$type": "Document",
              "DocumentIndex": 3,
              "Title": "IDeviceProtocolDetailService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\Service\\IDeviceProtocolDetailService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_QuartzJob\\Service\\IDeviceProtocolDetailService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\Service\\IDeviceProtocolDetailService.cs",
              "RelativeToolTip": "WIDESEAWCS_QuartzJob\\Service\\IDeviceProtocolDetailService.cs",
              "ViewState": "AgIAABMAAAAAAAAAAAAWwCkAAAAAAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-05T02:09:38.844Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 2,
              "Title": "DeviceProtocolDetailService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\Service\\DeviceProtocolDetailService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_QuartzJob\\Service\\DeviceProtocolDetailService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\Service\\DeviceProtocolDetailService.cs",
              "RelativeToolTip": "WIDESEAWCS_QuartzJob\\Service\\DeviceProtocolDetailService.cs",
              "ViewState": "AgIAACgAAAAAAAAAAAAuwEIAAABPAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-05T02:02:05.669Z",
              "EditorCaption": ""
            },
            {
              "$type": "Bookmark",
              "Name": "ST:128:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
@@ -87,189 +97,118 @@
            {
              "$type": "Document",
              "DocumentIndex": 1,
              "Title": "SocketServerOptions.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\SocketServerOptions.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\SocketServer\\SocketServerOptions.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\SocketServerOptions.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\SocketServer\\SocketServerOptions.cs",
              "ViewState": "AgIAACEAAAAAAAAAAAAQwCAAAAA7AAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-03T03:20:50.458Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 4,
              "Title": "appsettings.json",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\appsettings.json",
              "RelativeDocumentMoniker": "WIDESEAWCS_Server\\appsettings.json",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\appsettings.json",
              "RelativeToolTip": "WIDESEAWCS_Server\\appsettings.json",
              "ViewState": "AgIAABUAAAAAAAAAAAAAADYAAAAbAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
              "WhenOpened": "2026-02-03T03:54:20.54Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 10,
              "Title": "TaskTypeEnum.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\TaskEnum\\TaskTypeEnum.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Common\\TaskEnum\\TaskTypeEnum.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\TaskEnum\\TaskTypeEnum.cs",
              "RelativeToolTip": "WIDESEAWCS_Common\\TaskEnum\\TaskTypeEnum.cs",
              "ViewState": "AgIAADYAAAAAAAAAAAAuwEwAAAAZAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-02T07:43:32.381Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 9,
              "Title": "TaskEnumHelper.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\TaskEnum\\TaskEnumHelper.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Common\\TaskEnum\\TaskEnumHelper.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\TaskEnum\\TaskEnumHelper.cs",
              "RelativeToolTip": "WIDESEAWCS_Common\\TaskEnum\\TaskEnumHelper.cs",
              "ViewState": "AgIAABEAAAAAAAAAAAApwBgAAAAkAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-02T07:13:45.107Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 7,
              "Title": "TaskService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "RelativeToolTip": "WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "ViewState": "AgIAAGECAAAAAAAAAAAvwHMCAADaAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-02T07:10:41.925Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 13,
              "Title": "FormationCommonStackerCraneJob.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\FormationStackerCraneJob\\FormationCommonStackerCraneJob.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\FormationStackerCraneJob\\FormationCommonStackerCraneJob.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\FormationStackerCraneJob\\FormationCommonStackerCraneJob.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\FormationStackerCraneJob\\FormationCommonStackerCraneJob.cs",
              "ViewState": "AgIAAFkAAAAAAAAAAAAWwG0AAAAkAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-02T07:08:40.6Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 12,
              "Title": "ITaskService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_ITaskInfoService\\ITaskService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_ITaskInfoService\\ITaskService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_ITaskInfoService\\ITaskService.cs",
              "RelativeToolTip": "WIDESEAWCS_ITaskInfoService\\ITaskService.cs",
              "ViewState": "AgIAACAAAAAAAAAAAAAjwDUAAAAnAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-02T07:08:06.875Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 8,
              "Title": "TaskStatusEnum.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\TaskEnum\\TaskStatusEnum.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Common\\TaskEnum\\TaskStatusEnum.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\TaskEnum\\TaskStatusEnum.cs",
              "RelativeToolTip": "WIDESEAWCS_Common\\TaskEnum\\TaskStatusEnum.cs",
              "ViewState": "AgIAAJYAAAAAAAAAAAAAwJ8AAAAWAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-02T07:05:39.323Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 11,
              "Title": "CommonStackerCraneJob.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "ViewState": "AgIAAGwAAAAAAAAAAAApwH4AAAA1AAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-02T06:13:24.454Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 14,
              "Title": "QuartzNetExtension.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\QuartzNet\\QuartzNetExtension.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_QuartzJob\\QuartzNet\\QuartzNetExtension.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\QuartzNet\\QuartzNetExtension.cs",
              "RelativeToolTip": "WIDESEAWCS_QuartzJob\\QuartzNet\\QuartzNetExtension.cs",
              "ViewState": "AgIAAHAAAAAAAAAAAAAAAIYAAABzAAAAAAAAAA==",
              "ViewState": "AgIAAEcAAAAAAAAAAAApwF8AAACaAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-02T06:11:52.348Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 3,
              "Title": "RobotJob.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs",
              "ViewState": "AgIAAFYAAAAAAAAAAAAAAGwAAAAMAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-02T03:52:06.502Z",
              "WhenOpened": "2026-02-05T01:58:27.882Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 0,
              "Title": "TcpSocketServer.Messaging.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Messaging.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Messaging.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Messaging.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Messaging.cs",
              "ViewState": "AgIAALYAAAAAAAAAAAAIwLsAAAAWAAAAAAAAAA==",
              "DocumentIndex": 4,
              "Title": "SpeTemperatureStackerCrane.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\StackerCrane\\Spec\\SpeTemperatureStackerCrane.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_QuartzJob\\StackerCrane\\Spec\\SpeTemperatureStackerCrane.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\StackerCrane\\Spec\\SpeTemperatureStackerCrane.cs",
              "RelativeToolTip": "WIDESEAWCS_QuartzJob\\StackerCrane\\Spec\\SpeTemperatureStackerCrane.cs",
              "ViewState": "AgIAAHgAAAAAAAAAAAArwAAAAAAAAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-02T03:38:35.325Z",
              "WhenOpened": "2026-02-05T01:47:49.291Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 8,
              "Title": "IStackerCraneBase.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\IStackerCraneBase.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\IStackerCraneBase.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\IStackerCraneBase.cs",
              "RelativeToolTip": "WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\IStackerCraneBase.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAoAAAAmAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-05T01:35:31.591Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 7,
              "Title": "IStackerCrane.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\StackerCrane\\IStackerCrane.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_QuartzJob\\StackerCrane\\IStackerCrane.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\StackerCrane\\IStackerCrane.cs",
              "RelativeToolTip": "WIDESEAWCS_QuartzJob\\StackerCrane\\IStackerCrane.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAAEUAAAAVAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-05T01:33:41.091Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 5,
              "Title": "TcpSocketServer.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.cs",
              "ViewState": "AgIAAB8AAAAAAAAAAAAmwDsAAABaAAAAAAAAAA==",
              "Title": "SpeFormationStackerCrane.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\StackerCrane\\Spec\\SpeFormationStackerCrane.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_QuartzJob\\StackerCrane\\Spec\\SpeFormationStackerCrane.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\StackerCrane\\Spec\\SpeFormationStackerCrane.cs",
              "RelativeToolTip": "WIDESEAWCS_QuartzJob\\StackerCrane\\Spec\\SpeFormationStackerCrane.cs",
              "ViewState": "AgIAAJgBAAAAAAAAAAAmwAAAAAAAAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-02T03:37:56.495Z",
              "WhenOpened": "2026-02-05T01:32:15.17Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 2,
              "Title": "TcpSocketServer.Clients.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Clients.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Clients.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Clients.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Clients.cs",
              "ViewState": "AgIAAEQAAAAAAAAAAAAkwGAAAAAAAAAAAAAAAA==",
              "DocumentIndex": 10,
              "Title": "FormationCommonStackerCraneJob.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\FormationStackerCraneJob\\FormationCommonStackerCraneJob.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\FormationStackerCraneJob\\FormationCommonStackerCraneJob.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\FormationStackerCraneJob\\FormationCommonStackerCraneJob.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\FormationStackerCraneJob\\FormationCommonStackerCraneJob.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-02T03:37:53.636Z",
              "WhenOpened": "2026-02-05T01:25:52.745Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 9,
              "Title": "StackerCraneBase.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\StackerCraneBase.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\StackerCraneBase.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\StackerCraneBase.cs",
              "RelativeToolTip": "WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\StackerCraneBase.cs",
              "ViewState": "AgIAAAMAAAAAAAAAAAAAABoAAAAAAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-04T09:07:44.097Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 6,
              "Title": "TcpSocketServer.Server.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Server.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Server.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Server.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Server.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAAGwAAAAAAAAAAAAAAA==",
              "Title": "CommonStackerCrane.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\CommonStackerCrane.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\CommonStackerCrane.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\CommonStackerCrane.cs",
              "RelativeToolTip": "WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\CommonStackerCrane.cs",
              "ViewState": "AgIAAJUAAAAAAAAAAAAuwKIAAABXAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-02T03:37:49.526Z",
              "WhenOpened": "2026-02-04T09:07:35.823Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 0,
              "Title": "CommonStackerCraneJob.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "ViewState": "AgIAACoAAAAAAAAAAAAkwDwAAABIAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-04T07:48:56.632Z",
              "EditorCaption": ""
            }
          ]
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConstraintMachine/ConstraintMachine.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,213 @@
using HslCommunication;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Communicator;
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.DTO;
namespace WIDESEAWCS_QuartzJob
{
    /// <summary>
    /// æ‹˜æŸæœº
    /// </summary>
    [Description("拘束机")]
    public class ConstraintMachine : IConstraintMachine
    {
        #region Private Member
        /// <summary>
        /// æ‹˜æŸæœºé€šè®¯å¯¹è±¡
        /// </summary>
        private readonly BaseCommunicator _communicator;
        /// <summary>
        /// æ‹˜æŸæœºåè®®ä¿¡æ¯
        /// </summary>
        private readonly List<DeviceProDTO> _deviceProDTOs;
        /// <summary>
        /// æ‹˜æŸæœºåè®®æ˜Žç»†ä¿¡æ¯
        /// </summary>
        private readonly List<DeviceProtocolDetailDTO> _deviceProtocolDetailDTOs;
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        public readonly string _deviceCode;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public readonly string _deviceName;
        private bool _heartStatr = true;
        private bool _isConnected = true;
        #endregion
        #region Public Member
        /// <summary>
        /// é€šè®¯å¯¹è±¡
        /// </summary>
        public BaseCommunicator Communicator => _communicator;
        /// <summary>
        /// åè®®ä¿¡æ¯
        /// </summary>
        public List<DeviceProDTO> DeviceProDTOs => _deviceProDTOs;
        /// <summary>
        /// è¾“送线协议明细信息
        /// </summary>
        public List<DeviceProtocolDetailDTO> DeviceProtocolDetailDTOs => _deviceProtocolDetailDTOs;
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        public string DeviceCode => _deviceCode;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public string DeviceName => _deviceName;
        /// <summary>
        /// è®¾å¤‡æ˜¯å¦å·²è¿žæŽ¥
        /// </summary>
        public bool IsConnected => Communicator.IsConnected && _isConnected;
        #endregion
        #region Constructor Function
        /// <summary>
        /// æž„造函数
        /// </summary>
        /// <param name="communicator">设备通讯对象</param>
        /// <param name="deviceProDTOs">设备协议信息</param>
        /// <param name="deviceProtocolDetailDTOs">设备协议明细信息</param>
        /// <param name="deviceCode">设备编号</param>
        /// <param name="deviceName">设备名称</param>
        public ConstraintMachine(BaseCommunicator communicator, List<DeviceProDTO> deviceProDTOs, List<DeviceProtocolDetailDTO> deviceProtocolDetailDTOs, string deviceCode, string deviceName)
        {
            _communicator = communicator;
            _deviceProDTOs = deviceProDTOs;
            _deviceProtocolDetailDTOs = deviceProtocolDetailDTOs;
            _deviceCode = deviceCode;
            _deviceName = deviceName;
            CheckConnect();
        }
        #endregion
        #region Private Method
        private void CheckConnect()
        {
            Task.Run(() =>
            {
                while (_heartStatr)
                {
                    try
                    {
                        DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault();
                        if (devicePro == null)
                            _isConnected = false;
                        else
                            Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
                        _isConnected = true;
                    }
                    catch (Exception ex)
                    {
                        _isConnected = false;
                    }
                    Thread.Sleep(500);
                }
            });
        }
        #endregion
        #region Public Method
        /// <summary>
        /// è¯»å–PLC协议地址的数据
        /// </summary>
        /// <typeparam name="TEnum">协议信息的枚举对象信息。</typeparam>
        /// <typeparam name="TResult">读取数据的类型对象信息。</typeparam>
        /// <param name="value">枚举值</param>
        /// <returns>读取到的数据</returns>
        public TResult GetValue<TEnum, TResult>(TEnum value) where TEnum : Enum
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == value.ToString());
            return devicePro == null ? throw new Exception($"读取数据错误,未在协议信息里面找到参数{value.ToString()}") : (TResult)Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
        }
        /// <summary>
        /// è¯»å–PLC协议地址的数据
        /// </summary>
        /// <typeparam name="TEnum">协议信息的枚举对象信息。</typeparam>
        /// <typeparam name="TResult">读取数据的类型对象信息。</typeparam>
        /// <param name="value">枚举值</param>
        /// <param name="deviceChildCode">设备子编号</param>
        /// <returns>读取到的数据</returns>
        public TResult GetValue<TEnum, TResult>(TEnum value, string deviceChildCode) where TEnum : Enum
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == value.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception($"读取数据错误,未在协议信息里面找到参数{value.ToString()}") : (TResult)Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
        }
        /// <summary>
        /// ä¸Žè®¾å¤‡çš„心跳
        /// </summary>
        public void Heartbeat()
        {
        }
        /// <summary>
        /// æ ¹æ®å‚数名称、设备子编号写入对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TValue">要写入的数据类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="value">要写入的数据。</param>
        /// <param name="deviceChildCode">设备子编号写</param>
        /// <returns>返回写入成功或失败</returns>
        public bool SetValue<TEnum, TValue>(TEnum @enum, TValue value, string deviceChildCode)
            where TEnum : Enum
            where TValue : notnull
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == @enum.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception($"写入数据错误,未在协议信息里面找到参数{value.ToString()}") : Communicator.WriteObj(devicePro.DeviceProAddress, devicePro.DeviceDataType, value);
        }
        /// <summary>
        /// æ ¹æ®å‚数名称写入拘束机对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TValue">要写入的数据类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="value">要写入的数据。</param>
        /// <returns>返回写入成功或失败</returns>
        /// <exception cref="Exception"></exception>
        public bool SetValue<TEnum, TValue>(TEnum @enum, TValue value)
            where TEnum : Enum
            where TValue : notnull
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == @enum.ToString());
            return devicePro == null ? throw new Exception($"写入数据错误,未在协议信息里面找到参数{value.ToString()}") : Communicator.WriteObj(devicePro.DeviceProAddress, devicePro.DeviceDataType, value);
        }
        /// <summary>
        /// é‡Šæ”¾å¯¹è±¡
        /// </summary>
        public void Dispose()
        {
            _heartStatr = false;
            _communicator.Dispose();
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConstraintMachine/IConstraintMachine.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Communicator;
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.DTO;
namespace WIDESEAWCS_QuartzJob
{
    /// <summary>
    /// æ‹˜æŸæœº
    /// </summary>
    public interface IConstraintMachine : IDevice
    {
        /// <summary>
        /// è®¾å¤‡æ˜¯å¦å·²è¿žæŽ¥
        /// </summary>
        bool IsConnected { get; }
        /// <summary>
        /// è¯»å–PLC协议地址的数据
        /// </summary>
        /// <typeparam name="TEnum">协议信息的枚举对象信息。</typeparam>
        /// <typeparam name="TResult">读取数据的类型对象信息。</typeparam>
        /// <param name="value">枚举值</param>
        /// <returns>读取到的数据</returns>
        TResult GetValue<TEnum, TResult>(TEnum value) where TEnum : Enum;
        /// <summary>
        /// æ ¹æ®å‚数名称写入堆垛机对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TValue">要写入的数据类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="value">要写入的数据。</param>
        /// <returns>返回写入成功或失败</returns>
        /// <exception cref="Exception"></exception>
        bool SetValue<TEnum, TValue>(TEnum @enum, TValue value) where TEnum : Enum where TValue : notnull;
        /// <summary>
        /// è¯»å–PLC协议地址的数据
        /// </summary>
        /// <typeparam name="TEnum">协议信息的枚举对象信息。</typeparam>
        /// <typeparam name="TResult">读取数据的类型对象信息。</typeparam>
        /// <param name="value">枚举值</param>
        /// <param name="deviceChildCode">设备子编号</param>
        /// <returns>读取到的数据</returns>
        TResult GetValue<TEnum, TResult>(TEnum value, string deviceChildCode) where TEnum : Enum;
        /// <summary>
        /// æ ¹æ®å‚数名称、设备子编号写入对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TValue">要写入的数据类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="value">要写入的数据。</param>
        /// <param name="deviceChildCode">设备子编号写</param>
        /// <returns>返回写入成功或失败</returns>
        bool SetValue<TEnum, TValue>(TEnum @enum, TValue value, string deviceChildCode) where TEnum : Enum where TValue : notnull;
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DTO/DeviceProtocolDetailDTO.cs
@@ -29,6 +29,11 @@
    public class DeviceProtocolDetailDTO
    {
        /// <summary>
        /// è®¾å¤‡ID
        /// </summary>
        public int DeviceId { get; set; }
        /// <summary>
        /// è®¾å¤‡ç±»åž‹
        /// </summary>
        public string DeviceType { get; set; }
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Models/Dt_DeviceProtocolDetail.cs
@@ -41,6 +41,14 @@
        public int Id { get; set; }
        /// <summary>
        /// è®¾å¤‡Id
        /// </summary>
        [ImporterHeader(Name = "设备Id")]
        [ExporterHeader(DisplayName = "设备Id")]
        [SugarColumn(IsNullable = false,  ColumnDescription = "设备Id")]
        public int DeviceId { get; set; }
        /// <summary>
        /// è®¾å¤‡ç±»åž‹
        /// </summary>
        [ImporterHeader(Name = "设备类型")]
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/PinMachine/IPinMachine.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Communicator;
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.DTO;
namespace WIDESEAWCS_QuartzJob
{
    /// <summary>
    /// æ‹˜æŸæœº
    /// </summary>
    public interface IPinMachine : IDevice
    {
        /// <summary>
        /// è®¾å¤‡æ˜¯å¦å·²è¿žæŽ¥
        /// </summary>
        bool IsConnected { get; }
        /// <summary>
        /// è¯»å–PLC协议地址的数据
        /// </summary>
        /// <typeparam name="TEnum">协议信息的枚举对象信息。</typeparam>
        /// <typeparam name="TResult">读取数据的类型对象信息。</typeparam>
        /// <param name="value">枚举值</param>
        /// <returns>读取到的数据</returns>
        TResult GetValue<TEnum, TResult>(TEnum value) where TEnum : Enum;
        /// <summary>
        /// æ ¹æ®å‚数名称写入堆垛机对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TValue">要写入的数据类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="value">要写入的数据。</param>
        /// <returns>返回写入成功或失败</returns>
        /// <exception cref="Exception"></exception>
        bool SetValue<TEnum, TValue>(TEnum @enum, TValue value) where TEnum : Enum where TValue : notnull;
        /// <summary>
        /// è¯»å–PLC协议地址的数据
        /// </summary>
        /// <typeparam name="TEnum">协议信息的枚举对象信息。</typeparam>
        /// <typeparam name="TResult">读取数据的类型对象信息。</typeparam>
        /// <param name="value">枚举值</param>
        /// <param name="deviceChildCode">设备子编号</param>
        /// <returns>读取到的数据</returns>
        TResult GetValue<TEnum, TResult>(TEnum value, string deviceChildCode) where TEnum : Enum;
        /// <summary>
        /// æ ¹æ®å‚数名称、设备子编号写入对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TValue">要写入的数据类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="value">要写入的数据。</param>
        /// <param name="deviceChildCode">设备子编号写</param>
        /// <returns>返回写入成功或失败</returns>
        bool SetValue<TEnum, TValue>(TEnum @enum, TValue value, string deviceChildCode) where TEnum : Enum where TValue : notnull;
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/PinMachine/PinMachine.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,213 @@
using HslCommunication;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Communicator;
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.DTO;
namespace WIDESEAWCS_QuartzJob
{
    /// <summary>
    /// æ’拔钉机
    /// </summary>
    [Description("插拔钉机")]
    public class PinMachine : IPinMachine
    {
        #region Private Member
        /// <summary>
        /// æ‹˜æŸæœºé€šè®¯å¯¹è±¡
        /// </summary>
        private readonly BaseCommunicator _communicator;
        /// <summary>
        /// æ‹˜æŸæœºåè®®ä¿¡æ¯
        /// </summary>
        private readonly List<DeviceProDTO> _deviceProDTOs;
        /// <summary>
        /// æ‹˜æŸæœºåè®®æ˜Žç»†ä¿¡æ¯
        /// </summary>
        private readonly List<DeviceProtocolDetailDTO> _deviceProtocolDetailDTOs;
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        public readonly string _deviceCode;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public readonly string _deviceName;
        private bool _heartStatr = true;
        private bool _isConnected = true;
        #endregion
        #region Public Member
        /// <summary>
        /// é€šè®¯å¯¹è±¡
        /// </summary>
        public BaseCommunicator Communicator => _communicator;
        /// <summary>
        /// åè®®ä¿¡æ¯
        /// </summary>
        public List<DeviceProDTO> DeviceProDTOs => _deviceProDTOs;
        /// <summary>
        /// è¾“送线协议明细信息
        /// </summary>
        public List<DeviceProtocolDetailDTO> DeviceProtocolDetailDTOs => _deviceProtocolDetailDTOs;
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        public string DeviceCode => _deviceCode;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public string DeviceName => _deviceName;
        /// <summary>
        /// è®¾å¤‡æ˜¯å¦å·²è¿žæŽ¥
        /// </summary>
        public bool IsConnected => Communicator.IsConnected && _isConnected;
        #endregion
        #region Constructor Function
        /// <summary>
        /// æž„造函数
        /// </summary>
        /// <param name="communicator">设备通讯对象</param>
        /// <param name="deviceProDTOs">设备协议信息</param>
        /// <param name="deviceProtocolDetailDTOs">设备协议明细信息</param>
        /// <param name="deviceCode">设备编号</param>
        /// <param name="deviceName">设备名称</param>
        public PinMachine(BaseCommunicator communicator, List<DeviceProDTO> deviceProDTOs, List<DeviceProtocolDetailDTO> deviceProtocolDetailDTOs, string deviceCode, string deviceName)
        {
            _communicator = communicator;
            _deviceProDTOs = deviceProDTOs;
            _deviceProtocolDetailDTOs = deviceProtocolDetailDTOs;
            _deviceCode = deviceCode;
            _deviceName = deviceName;
            CheckConnect();
        }
        #endregion
        #region Private Method
        private void CheckConnect()
        {
            Task.Run(() =>
            {
                while (_heartStatr)
                {
                    try
                    {
                        DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault();
                        if (devicePro == null)
                            _isConnected = false;
                        else
                            Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
                        _isConnected = true;
                    }
                    catch (Exception ex)
                    {
                        _isConnected = false;
                    }
                    Thread.Sleep(500);
                }
            });
        }
        #endregion
        #region Public Method
        /// <summary>
        /// è¯»å–PLC协议地址的数据
        /// </summary>
        /// <typeparam name="TEnum">协议信息的枚举对象信息。</typeparam>
        /// <typeparam name="TResult">读取数据的类型对象信息。</typeparam>
        /// <param name="value">枚举值</param>
        /// <returns>读取到的数据</returns>
        public TResult GetValue<TEnum, TResult>(TEnum value) where TEnum : Enum
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == value.ToString());
            return devicePro == null ? throw new Exception($"读取数据错误,未在协议信息里面找到参数{value.ToString()}") : (TResult)Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
        }
        /// <summary>
        /// è¯»å–PLC协议地址的数据
        /// </summary>
        /// <typeparam name="TEnum">协议信息的枚举对象信息。</typeparam>
        /// <typeparam name="TResult">读取数据的类型对象信息。</typeparam>
        /// <param name="value">枚举值</param>
        /// <param name="deviceChildCode">设备子编号</param>
        /// <returns>读取到的数据</returns>
        public TResult GetValue<TEnum, TResult>(TEnum value, string deviceChildCode) where TEnum : Enum
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == value.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception($"读取数据错误,未在协议信息里面找到参数{value.ToString()}") : (TResult)Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
        }
        /// <summary>
        /// ä¸Žè®¾å¤‡çš„心跳
        /// </summary>
        public void Heartbeat()
        {
        }
        /// <summary>
        /// æ ¹æ®å‚数名称、设备子编号写入对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TValue">要写入的数据类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="value">要写入的数据。</param>
        /// <param name="deviceChildCode">设备子编号写</param>
        /// <returns>返回写入成功或失败</returns>
        public bool SetValue<TEnum, TValue>(TEnum @enum, TValue value, string deviceChildCode)
            where TEnum : Enum
            where TValue : notnull
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == @enum.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception($"写入数据错误,未在协议信息里面找到参数{value.ToString()}") : Communicator.WriteObj(devicePro.DeviceProAddress, devicePro.DeviceDataType, value);
        }
        /// <summary>
        /// æ ¹æ®å‚数名称写入拘束机对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TValue">要写入的数据类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="value">要写入的数据。</param>
        /// <returns>返回写入成功或失败</returns>
        /// <exception cref="Exception"></exception>
        public bool SetValue<TEnum, TValue>(TEnum @enum, TValue value)
            where TEnum : Enum
            where TValue : notnull
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == @enum.ToString());
            return devicePro == null ? throw new Exception($"写入数据错误,未在协议信息里面找到参数{value.ToString()}") : Communicator.WriteObj(devicePro.DeviceProAddress, devicePro.DeviceDataType, value);
        }
        /// <summary>
        /// é‡Šæ”¾å¯¹è±¡
        /// </summary>
        public void Dispose()
        {
            _heartStatr = false;
            _communicator.Dispose();
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/QuartzNetExtension.cs
@@ -47,7 +47,7 @@
                    {
                        try
                        {
                            if (!x.DeviceName.Contains("机械手"))
                            if (!x.DevicePlcType.Contains("Socket"))
                            {
                                #region è¿žæŽ¥PLC
@@ -93,7 +93,7 @@
                                }).ToList();
                                // æ ¹æ®è®¾å¤‡ç±»åž‹èŽ·å–è®¾å¤‡åè®®è¯¦æƒ…
                                List<DeviceProtocolDetailDTO> deviceProtocolDetails = _deviceProtocolDetailService.GetDeviceProtocolDetailsByDeviceType(x.DeviceType);
                                List<DeviceProtocolDetailDTO> deviceProtocolDetails = _deviceProtocolDetailService.GetDeviceProtocolDetailsByDeviceId(x.Id);
                                // åŠ è½½è®¾å¤‡ç¨‹åºé›†
                                Assembly assemblyDevice = Assembly.Load($"WIDESEAWCS_QuartzJob");
@@ -121,14 +121,14 @@
                });
                for (int i = 0; i < dispatches.Count; i++)
                {
                    var targetDevice = deviceInfos.FirstOrDefault(x => x.Id == dispatches[i].Id);
                    var targetDevice = deviceInfos.FirstOrDefault(x => x.DispatchId == dispatches[i].Id);
                    if (targetDevice is null) continue;
                    // ä½¿ç”¨æ¨¡å¼åŒ¹é…
                    dispatches[i].JobParams = targetDevice switch
                    {
                        { DeviceName: var name } when name.Contains("机械手")
                        { DevicePlcType: var type } when type.Contains("Socket")
                            => new RobotCraneDevice { DeviceCode = targetDevice.DeviceCode, DeviceName = targetDevice.DeviceName, IPAddress = targetDevice.DeviceIp + ":" + targetDevice.DevicePort },
                        _ => targetDevice.Device
                    };
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/DeviceProtocolDetailService.cs
@@ -57,5 +57,16 @@
        {
            return BaseDal.QueryData(x => x.DeviceType == deviceType).Select(x => new DeviceProtocolDetailDTO { DeviceType = x.DeviceType, DeviceProParamName = x.DeviceProParamName, ProtocalDetailValue = x.ProtocalDetailValue, ProtocolDetailDes = x.ProtocolDetailDes, ProtocolDetailType = x.ProtocolDetailType }).ToList();
        }
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ID获取协议明细信息
        /// </summary>
        /// <param name="deviceId">设备ID</param>
        /// <returns>返回设备协议明细DTO集合</returns>
        public List<DeviceProtocolDetailDTO> GetDeviceProtocolDetailsByDeviceId(int deviceId)
        {
            return BaseDal.QueryData(x => x.DeviceId == deviceId).Select(x => new DeviceProtocolDetailDTO { DeviceId = x.DeviceId, DeviceProParamName = x.DeviceProParamName, ProtocalDetailValue = x.ProtocalDetailValue, ProtocolDetailDes = x.ProtocolDetailDes, ProtocolDetailType = x.ProtocolDetailType }).ToList();
        }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/IDeviceProtocolDetailService.cs
@@ -38,5 +38,13 @@
        /// <param name="deviceType">设备类型</param>
        /// <returns>返回设备协议明细DTO集合</returns>
        List<DeviceProtocolDetailDTO> GetDeviceProtocolDetailsByDeviceType(string deviceType);
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ID获取协议明细信息
        /// </summary>
        /// <param name="deviceId">设备ID</param>
        /// <returns>返回设备协议明细DTO集合</returns>
        public List<DeviceProtocolDetailDTO> GetDeviceProtocolDetailsByDeviceId(int deviceId);
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/IRouterService.cs
@@ -33,14 +33,14 @@
        List<Dt_Router> QueryNextRoutes(string startPosi, string endPosi, int routeType);
        /// <summary>
        /// æ ¹æ®èµ·ç‚¹èŽ·å–ä¸‹ä¸€ä¸ªå•ä¸ªå­èŠ‚ç‚¹è·¯ç”±
        /// æ ¹æ®èµ·ç‚¹/当前位置获取下一个单个子节点路由
        /// </summary>
        /// <param name="startPosi">起点/当前位置</param>
        /// <returns>返回下一个路由节点,如果没有则返回null</returns>
        public Dt_Router QueryNextRoute(string startPosi);
        /// <summary>
        /// æ ¹æ®èµ·ç‚¹å’Œè·¯ç”±ç±»åž‹èŽ·å–ä¸‹ä¸€ä¸ªå•ä¸ªå­èŠ‚ç‚¹è·¯ç”±
        /// æ ¹æ®èµ·ç‚¹/当前位置和路由类型获取下一个单个子节点路由
        /// </summary>
        /// <param name="startPosi">起点/当前位置</param>
        /// <param name="routeType">路由类型</param>
@@ -48,7 +48,7 @@
        public Dt_Router QueryNextRoute(string startPosi, int routeType);
        /// <summary>
        /// æ ¹æ®èµ·ç‚¹ã€ç»ˆç‚¹æ–¹å‘和路由类型获取下一个单个子节点路由(智能选择朝向终点的路由)
        /// æ ¹æ®èµ·ç‚¹/当前位置、终点方向和路由类型获取下一个单个子节点路由(智能选择朝向终点的路由)
        /// </summary>
        /// <param name="startPosi">起点/当前位置</param>
        /// <param name="endPosi">终点位置(用于方向判断)</param>
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Common/CommonStackerCrane.cs
@@ -24,6 +24,7 @@
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.StackerCrane;
using WIDESEAWCS_QuartzJob.StackerCrane.Common;
using WIDESEAWCS_QuartzJob.StackerCrane.Enum;
namespace WIDESEAWCS_QuartzJob
@@ -32,7 +33,7 @@
    /// ä¸€èˆ¬å †åž›æœºå®žçŽ°ç±»ï¼Œå®žçŽ°å †åž›æœºæŽ¥å£å±‚
    /// </summary>
    [Description("堆垛机")]
    public class CommonStackerCrane : IStackerCrane
    public class CommonStackerCrane : StackerCraneBase, IStackerCrane
    {
        #region Private Member
@@ -157,6 +158,11 @@
        public bool IsConnected => Communicator.IsConnected && _isConnected;
        /// <summary>
        /// å †åž›æœºå®Œæˆäº‹ä»¶æ˜¯å¦å·²è®¢é˜…
        /// </summary>
        public bool IsEventSubscribed => StackerCraneTaskCompletedEventHandler != null;
        /// <summary>
        /// å †åž›æœºä»»åŠ¡å®Œæˆäº‹ä»¶
        /// </summary>
        public event EventHandler<StackerCraneTaskCompletedEventArgs> StackerCraneTaskCompletedEventHandler;
@@ -166,10 +172,6 @@
        /// </summary>
        public object StackerCraneTaskCommand { get; set; }
        /// <summary>
        /// å †åž›æœºå®Œæˆäº‹ä»¶æ˜¯å¦å·²è®¢é˜…
        /// </summary>
        public bool IsEventSubscribed => StackerCraneTaskCompletedEventHandler != null;
        /// <summary>
        /// ä¸Šä¸€æ¬¡ä»»åŠ¡çš„ç±»åž‹
@@ -385,10 +387,10 @@
                _isChecked = true;
                try
                {
                    DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(StackerCraneWorkStatus));
                    DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(StackerCraneCompleted));
                    if (devicePro != null)
                    {
                        DeviceProtocolDetailDTO? deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == devicePro.DeviceProParamName && x.ProtocolDetailType == StackerCraneWorkStatus.WorkCompleted.ToString());
                        DeviceProtocolDetailDTO? deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == devicePro.DeviceProParamName && x.ProtocolDetailType == StackerCraneCompleted.Completed.ToString());
                        if (deviceProtocolDetail != null)
                        {
                            OperateResult<TimeSpan> operateResult = new OperateResult<TimeSpan>();
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Common/IStackerCraneBase.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Communicator;
using WIDESEAWCS_QuartzJob.DTO;
namespace WIDESEAWCS_QuartzJob.StackerCrane.Common
{
    public interface IStackerCraneBase
    {
        public bool IsCanSendTask(BaseCommunicator communicator, List<DeviceProDTO> DeviceProDTOs, List<DeviceProtocolDetailDTO> DeviceProtocolDetailDTOs);
        public bool IsCanSendTask(BaseCommunicator communicator, List<DeviceProDTO> DeviceProDTOs, List<DeviceProtocolDetailDTO> DeviceProtocolDetailDTOs, params string[] suffixes);
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Common/StackerCraneBase.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Linq;
using WIDESEAWCS_Communicator;
using WIDESEAWCS_QuartzJob.DTO;
namespace WIDESEAWCS_QuartzJob.StackerCrane.Common
{
    public class StackerCraneBase : IStackerCraneBase
    {
        public bool IsCanSendTask(BaseCommunicator communicator, List<DeviceProDTO> DeviceProDTOs, List<DeviceProtocolDetailDTO> DeviceProtocolDetailDTOs)
        {
            List<string> paramNames = ResolveDefaultParamNames(DeviceProDTOs, DeviceProtocolDetailDTOs);
            if (paramNames.Count == 0)
            {
                return false;
            }
            return IsCanSendTaskByParamNames(communicator, DeviceProDTOs, DeviceProtocolDetailDTOs, paramNames);
        }
        public bool IsCanSendTask(BaseCommunicator communicator, List<DeviceProDTO> DeviceProDTOs, List<DeviceProtocolDetailDTO> DeviceProtocolDetailDTOs, params string[] suffixes)
        {
            if (suffixes == null || suffixes.Length == 0)
            {
                return false;
            }
            List<string> paramNames = new List<string>(suffixes.Length);
            foreach (string suffix in suffixes)
            {
                string? paramName = ResolveParamName(DeviceProDTOs, DeviceProtocolDetailDTOs, suffix);
                if (paramName == null)
                {
                    return false;
                }
                paramNames.Add(paramName);
            }
            return IsCanSendTaskByParamNames(communicator, DeviceProDTOs, DeviceProtocolDetailDTOs, paramNames);
        }
        private static List<string> ResolveDefaultParamNames(List<DeviceProDTO> deviceProDTOs, List<DeviceProtocolDetailDTO> deviceProtocolDetailDTOs)
        {
            List<string> paramNames = new List<string>();
            foreach (var devicePro in deviceProDTOs)
            {
                if (!devicePro.DeviceProParamName.Contains("StackerCrane", StringComparison.Ordinal))
                {
                    continue;
                }
                if (!devicePro.DeviceProParamName.EndsWith("Status", StringComparison.Ordinal))
                {
                    continue;
                }
                if (deviceProtocolDetailDTOs.Any(x => x.DeviceProParamName == devicePro.DeviceProParamName))
                {
                    paramNames.Add(devicePro.DeviceProParamName);
                }
            }
            return paramNames;
        }
        private bool IsCanSendTaskByParamNames(BaseCommunicator communicator, List<DeviceProDTO> DeviceProDTOs, List<DeviceProtocolDetailDTO> DeviceProtocolDetailDTOs, List<string> paramNames)
        {
            for (int i = 0; i < paramNames.Count; i++)
            {
                DeviceProDTO? devicePro = DeviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == paramNames[i]);
                if (devicePro == null)
                {
                    throw new Exception();
                }
                DeviceProtocolDetailDTO? deviceProtocolDetail = DeviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == paramNames[i]);
                if (deviceProtocolDetail == null)
                {
                    throw new Exception();
                }
                object obj = communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
                if (!(obj?.ToString() ?? "").Equals(deviceProtocolDetail.ProtocalDetailValue))
                {
                    return false;
                }
            }
            return true;
        }
        private static string? ResolveParamName(List<DeviceProDTO> deviceProDTOs, List<DeviceProtocolDetailDTO> deviceProtocolDetailDTOs, string suffix)
        {
            foreach (var devicePro in deviceProDTOs)
            {
                if (!devicePro.DeviceProParamName.EndsWith(suffix, StringComparison.Ordinal))
                {
                    continue;
                }
                if (deviceProtocolDetailDTOs.Any(x => x.DeviceProParamName == devicePro.DeviceProParamName))
                {
                    return devicePro.DeviceProParamName;
                }
            }
            return null;
        }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Enum/StackerCraneStatus.cs
@@ -1,4 +1,5 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
@@ -13,6 +14,7 @@
 * ä¿®æ”¹è¯´æ˜Žï¼š
 * 
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
@@ -143,4 +145,28 @@
        [Description("未知")]
        Unkonw
    }
    /// <summary>
    /// ä»»åŠ¡å®ŒæˆçŠ¶æ€æžšä¸¾
    /// </summary>
    public enum StackerCraneCompleted
    {
        /// <summary>
        /// æœªå®Œæˆ
        /// </summary>
        [Description("未完成")]
        NotCompleted,
        /// <summary>
        /// å·²å®Œæˆ
        /// </summary>
        [Description("已完成")]
        Completed,
        /// <summary>
        /// å¼‚常完成
        /// </summary>
        [Description("异常完成")]
        AbnormalCompleted
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Enum/TemperatureStackerStatus.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,143 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šå †åž›æœºçŠ¶æ€æžšä¸¾
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System.ComponentModel;
namespace WIDESEAWCS_QuartzJob.StackerCrane.Enum
{
    /// <summary>
    /// å †åž›æœºçŠ¶æ€æžšä¸¾
    /// </summary>
    public enum TemperatureStackerCraneStatus
    {
        /// <summary>
        /// æœªçŸ¥
        /// </summary>
        [Description("未知")]
        Unkonw,
        /// <summary>
        /// æ­£å¸¸
        /// </summary>
        [Description("正常")]
        Normal,
    }
    /// <summary>
    /// å †åž›æœºæ‰‹è‡ªåŠ¨çŠ¶æ€æžšä¸¾
    /// </summary>
    public enum TemperatureStackerCraneAutoStatus
    {
        /// <summary>
        /// æ— æ¨¡å¼
        /// </summary>
        [Description("未知")]
        Unkonw,
        /// <summary>
        /// æœªçŸ¥
        /// </summary>
        [Description("未知")]
        Unkonw1,
        /// <summary>
        /// ç»´ä¿®/维护/保养
        /// </summary>
        [Description("ç»´ä¿®")]
        Maintenance,
        /// <summary>
        /// æ‰‹åЍ
        /// </summary>
        [Description("手动")]
        Manual,
        /// <summary>
        /// åŠè‡ªåЍ
        /// </summary>
        [Description("半自动")]
        SemiAutomatic,
        /// <summary>
        /// è‡ªåЍ
        /// </summary>
        [Description("自动")]
        Automatic
    }
    /// <summary>
    /// å †åž›æœºå·¥ä½œçŠ¶æ€æžšä¸¾
    /// </summary>
    public enum TemperatureStackerCraneWorkStatus
    {
        /// <summary>
        /// æœªçŸ¥
        /// </summary>
        [Description("未知")]
        Unkonw,
        /// <summary>
        /// å¾…机
        /// </summary>
        [Description("待机")]
        Standby,
        /// <summary>
        /// æŽ¥æ”¶ä»»åŠ¡
        /// </summary>
        [Description("接收任务")]
        ReceiveTask,
        /// <summary>
        /// å–货移动
        /// </summary>
        [Description("取货移动")]
        PickUpMoving,
        /// <summary>
        /// å–货中
        /// </summary>
        [Description("取货中")]
        PickUp,
        /// <summary>
        /// æœªçŸ¥
        /// </summary>
        [Description("未知")]
        Unkonw1,
        /// <summary>
        /// æ”¾è´§ç§»åЍ
        /// </summary>
        [Description("放货移动")]
        PutUpMoving,
        /// <summary>
        /// æ”¾è´§ä¸­
        /// </summary>
        [Description("放货中")]
        Putting,
        /// <summary>
        /// æ”¾è´§å®Œæˆ
        /// </summary>
        [Description("放货完成")]
        PutCompleted,
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/IStackerCrane.cs
@@ -1,4 +1,5 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
@@ -13,6 +14,7 @@
 * ä¿®æ”¹è¯´æ˜Žï¼š
 * 
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using HslCommunication;
@@ -26,13 +28,14 @@
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.StackerCrane;
using WIDESEAWCS_QuartzJob.StackerCrane.Common;
namespace WIDESEAWCS_QuartzJob
{
    /// <summary>
    /// å †åž›æœºæŽ¥å£å±‚
    /// </summary>
    public interface IStackerCrane : IDevice
    public interface IStackerCrane : IStackerCraneBase, IDevice
    {
        /// <summary>
        /// è®¾å¤‡æ˜¯å¦å·²è¿žæŽ¥
@@ -60,6 +63,21 @@
        void Heartbeat();
        /// <summary>
        /// å †åž›æœºå®Œæˆäº‹ä»¶æ˜¯å¦å·²è®¢é˜…
        /// </summary>
        bool IsEventSubscribed { get; }
        /// <summary>
        /// å †åž›æœºä»»åŠ¡å®Œæˆäº‹ä»¶
        /// </summary>
        event EventHandler<StackerCraneTaskCompletedEventArgs> StackerCraneTaskCompletedEventHandler;
        /// <summary>
        /// ç›‘测堆垛机任务是否完成(防止任务完成事件监测超时,定义手动触发功能)
        /// </summary>
        public void CheckStackerCraneTaskCompleted();
        /// <summary>
        /// å‘送任务命令
        /// </summary>
        /// <param name="command">任务命令</param>
@@ -85,5 +103,6 @@
        /// <returns>返回写入成功或失败</returns>
        /// <exception cref="Exception"></exception>
        bool SetValue<TEnum, TValue>(TEnum @enum, TValue value) where TEnum : Enum where TValue : notnull;
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Spec/SpeFormationStackerCrane.cs
@@ -6,6 +6,7 @@
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.StackerCrane;
using WIDESEAWCS_QuartzJob.StackerCrane.Enum;
using WIDESEAWCS_QuartzJob.StackerCrane.Common;
namespace WIDESEAWCS_QuartzJob
{
@@ -13,7 +14,7 @@
    /// è‡ªå®šä¹‰å †åž›æœº
    /// </summary>
    [Description("化成分容堆垛机")]
    public class SpeFormationStackerCrane : IStackerCrane
    public class SpeFormationStackerCrane : StackerCraneBase, IStackerCrane
    {
        #region Private Member
@@ -130,15 +131,15 @@
        public object StackerCraneTaskCommand { get; set; }
        /// <summary>
        /// å †åž›æœºä»»åŠ¡å®Œæˆäº‹ä»¶
        /// </summary>
        public event EventHandler<StackerCraneTaskCompletedEventArgs> StackerCraneTaskCompletedEventHandler;
        /// <summary>
        /// å †åž›æœºå®Œæˆäº‹ä»¶æ˜¯å¦å·²è®¢é˜…
        /// </summary>
        public bool IsEventSubscribed => StackerCraneTaskCompletedEventHandler != null;
        /// <summary>
        /// å †åž›æœºä»»åŠ¡å®Œæˆäº‹ä»¶
        /// </summary>
        public event EventHandler<StackerCraneTaskCompletedEventArgs> StackerCraneTaskCompletedEventHandler;
        #endregion Public Member
        #region Constructor Function
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Spec/SpeTemperatureStackerCrane.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,455 @@
using HslCommunication;
using System.ComponentModel;
using System.Reflection;
using WIDESEAWCS_Communicator;
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.StackerCrane;
using WIDESEAWCS_QuartzJob.StackerCrane.Enum;
using WIDESEAWCS_QuartzJob.StackerCrane.Common;
namespace WIDESEAWCS_QuartzJob
{
    /// <summary>
    /// è‡ªå®šä¹‰å †åž›æœº
    /// </summary>
    [Description("高常温堆垛机")]
    public class SpeTemperatureStackerCrane : StackerCraneBase, IStackerCrane
    {
        #region Private Member
        /// <summary>
        /// å †åž›æœºé€šè®¯å¯¹è±¡
        /// </summary>
        private BaseCommunicator _communicator;
        /// <summary>
        /// å †åž›æœºåè®®ä¿¡æ¯
        /// </summary>
        private readonly List<DeviceProDTO> _deviceProDTOs;
        /// <summary>
        /// å †åž›æœºåè®®æ˜Žç»†ä¿¡æ¯
        /// </summary>
        private readonly List<DeviceProtocolDetailDTO> _deviceProtocolDetailDTOs;
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        public readonly string _deviceCode;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public readonly string _deviceName;
        /// <summary>
        /// ä¸Šä¸€æ¬¡ä»»åŠ¡å·
        /// </summary>
        private int _lastTaskNum;
        private bool _isChecked = false;
        private bool _heartStart = true;
        private bool _isConnected = true;
        #endregion Private Member
        #region Public Member
        /// <summary>
        /// é€šè®¯å¯¹è±¡
        /// </summary>
        public BaseCommunicator Communicator => _communicator;
        /// <summary>
        /// é€šè®¯åè®®ä¿¡æ¯
        /// </summary>
        public List<DeviceProDTO> DeviceProDTOs => _deviceProDTOs;
        /// <summary>
        /// é€šè®¯åè®®æ˜Žç»†ä¿¡æ¯
        /// </summary>
        public List<DeviceProtocolDetailDTO> DeviceProtocolDetailDTOs => _deviceProtocolDetailDTOs;
        /// <summary>
        /// å †åž›æœºçŠ¶æ€
        /// </summary>
        public TemperatureStackerCraneStatus StackerCraneStatusValue => GetStackerCraneStatus();
        /// <summary>
        /// å †åž›æœºçŠ¶æ€ä¸­æ–‡è¯´æ˜Ž
        /// </summary>
        public string StackerCraneStatusDes => GetEnumDes(StackerCraneStatusValue);
        /// <summary>
        /// æ‰‹è‡ªåŠ¨çŠ¶æ€
        /// </summary>
        public TemperatureStackerCraneAutoStatus StackerCraneAutoStatusValue => GetStackerCraneAutoStatus();
        /// <summary>
        /// ä½œä¸šçŠ¶æ€
        /// </summary>
        public TemperatureStackerCraneWorkStatus StackerCraneWorkStatusValue => GetStackerCraneWorkStatus();
        /// <summary>
        /// ä½œä¸šçŠ¶æ€ä¸­æ–‡è¯´æ˜Ž
        /// </summary>
        public string StackerCraneWorkStatusDes => GetEnumDes(StackerCraneWorkStatusValue);
        /// <summary>
        /// ä¸Šä¸€æ¬¡æ‰§è¡Œçš„任务号
        /// </summary>
        public int LastTaskNum => _lastTaskNum;
        /// <summary>
        /// å½“前正在执行的任务号
        /// </summary>
        public int CurrentTaskNum => GetCurrentTaskNum();
        /// <summary>
        /// ä¸Šä¸€æ¬¡æ‰§è¡Œçš„任务类型
        /// </summary>
        public int? LastTaskType { get; set; } = null;
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        public string DeviceCode => _deviceCode;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public string DeviceName => _deviceName;
        /// <summary>
        /// è®¾å¤‡æ˜¯å¦å·²è¿žæŽ¥
        /// </summary>
        public bool IsConnected => Communicator.IsConnected && _isConnected;
        /// <summary>
        /// å †åž›æœºä»»åС命令
        /// </summary>
        public object StackerCraneTaskCommand { get; set; }
        /// <summary>
        /// å †åž›æœºå®Œæˆäº‹ä»¶æ˜¯å¦å·²è®¢é˜…
        /// </summary>
        public bool IsEventSubscribed => StackerCraneTaskCompletedEventHandler != null;
        /// <summary>
        /// å †åž›æœºä»»åŠ¡å®Œæˆäº‹ä»¶
        /// </summary>
        public event EventHandler<StackerCraneTaskCompletedEventArgs> StackerCraneTaskCompletedEventHandler;
        #endregion Public Member
        #region Constructor Function
        /// <summary>
        /// æž„造函数
        /// </summary>
        /// <param name="communicator">堆垛机通讯对象</param>
        /// <param name="deviceProDTOs">堆垛机协议信息</param>
        /// <param name="deviceProtocolDetailDTOs">堆垛机协议明细信息</param>
        /// <param name="deviceCode">设备编号</param>
        /// <param name="deviceName">设备名称</param>
        public SpeTemperatureStackerCrane(BaseCommunicator communicator, List<DeviceProDTO> deviceProDTOs, List<DeviceProtocolDetailDTO> deviceProtocolDetailDTOs, string deviceCode, string deviceName)
        {
            _communicator = communicator;
            _deviceProDTOs = deviceProDTOs;
            _deviceProtocolDetailDTOs = deviceProtocolDetailDTOs;
            _deviceCode = deviceCode;
            _deviceName = deviceName;
            CheckConnect();
        }
        #endregion Constructor Function
        #region Private Method
        private object GetStatus(string protocolParamType)
        {
            if (!Communicator.IsConnected)
            {
                return StackerCraneStatus.Unkonw.ToString();
            }
            List<DeviceProDTO> devicePros = _deviceProDTOs.Where(x => x.DeviceProParamType == protocolParamType).ToList();
            if (devicePros.Count == 0)
            {
                throw new Exception($"未获取到协议信息,协议参数类型:{protocolParamType}");
            }
            foreach (var devicePro in devicePros)
            {
                object readStatus = Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
                DeviceProtocolDetailDTO? deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(
                    x => x.DeviceProParamName == devicePro.DeviceProParamType
                    && x.ProtocalDetailValue.Equals(readStatus.ToString()));
                if (deviceProtocolDetail != null)
                {
                    return Convert.ToInt32(readStatus);
                }
            }
            return StackerCraneStatus.Unkonw.ToString();
        }
        /// <summary>
        /// èŽ·å–å †åž›æœºè®¾å¤‡çŠ¶æ€
        /// </summary>
        /// <returns></returns>
        private TemperatureStackerCraneStatus GetStackerCraneStatus()
        {
            return (TemperatureStackerCraneStatus)GetStatus(nameof(TemperatureStackerCraneStatus));
        }
        /// <summary>
        /// èŽ·å–å †åž›æœºæ‰‹è‡ªåŠ¨çŠ¶æ€
        /// </summary>
        /// <returns></returns>
        private TemperatureStackerCraneAutoStatus GetStackerCraneAutoStatus()
        {
            return (TemperatureStackerCraneAutoStatus)GetStatus(nameof(TemperatureStackerCraneWorkStatus));
        }
        /// <summary>
        /// èŽ·å–å †åž›æœºå·¥ä½œçŠ¶æ€
        /// </summary>
        /// <returns></returns>
        private TemperatureStackerCraneWorkStatus GetStackerCraneWorkStatus()
        {
            return (TemperatureStackerCraneWorkStatus)GetStatus(nameof(TemperatureStackerCraneWorkStatus));
        }
        /// <summary>
        /// èŽ·å–æžšä¸¾è¯´æ˜Ž
        /// </summary>
        /// <typeparam name="T">枚举泛型</typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        private string GetEnumDes<T>(T value) where T : Enum
        {
            FieldInfo? fieldInfo = typeof(T).GetField(value.ToString());
            if (fieldInfo != null)
            {
                DescriptionAttribute? descriptionAttribute = fieldInfo.GetCustomAttribute<DescriptionAttribute>();
                if (descriptionAttribute != null)
                {
                    return descriptionAttribute.Description;
                }
                return "未定义";
            }
            return "未知";
        }
        private int GetCurrentTaskNum()
        {
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(CurrentTaskNum));
            return devicePro == null ? throw new Exception($"读取当前任务号错误,未获取到协议信息,请检查配置参数名称是否配置,且配置为{nameof(CurrentTaskNum)}") : (int)Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
        }
        private void CheckConnect()
        {
            Task.Run(() =>
            {
                while (_heartStart)
                {
                    try
                    {
                        DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault();
                        if (devicePro == null)
                        {
                            _isConnected = false;
                        }
                        else
                        {
                            Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
                            _isConnected = true;
                        }
                    }
                    catch (Exception ex)
                    {
                        _isConnected = false;
                    }
                    Thread.Sleep(500);
                }
            });
        }
        #endregion Private Method
        #region Public Method
        /// <summary>
        /// èŽ·å–å †åž›æœºçŠ¶æ€
        /// </summary>
        public T GetStackerCraneStatus<T>() where T : notnull, Enum
        {
            return (T)GetStatus(typeof(T).Name);
        }
        /// <summary>
        /// é‡Šæ”¾å¯¹è±¡
        /// </summary>
        public void Dispose()
        {
            _heartStart = false;
            _communicator.Dispose();
            GC.SuppressFinalize(this);
        }
        /// <summary>
        /// æ ¹æ®å‚数名称读取堆垛机对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TResult">读取结果的返回值类型。</typeparam>
        /// <param name="value">参数名称。</param>
        /// <returns>返回读取到的数据。</returns>
        /// <exception cref="Exception"></exception>
        public TResult GetValue<TEnum, TResult>(TEnum value) where TEnum : Enum
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == value.ToString());
            return devicePro == null ? throw new Exception($"读取数据错误,未在协议信息里面找到参数{value.ToString()}") : (TResult)Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
        }
        /// <summary>
        /// å¿ƒè·³
        /// </summary>
        public void Heartbeat()
        {
        }
        /// <summary>
        /// å‘送任务命令
        /// </summary>
        /// <param name="command">任务命令</param>
        /// <returns></returns>
        public bool SendCommand<T>(T command) where T : IDataTransfer, new()
        {
            if (Communicator is SiemensS7)
            {
                if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
                DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == nameof(DeviceCommand)).OrderBy(x => x.DeviceProOffset).FirstOrDefault();
                if (devicePro == null)
                {
                    return false;
                }
                if (Communicator.WriteCustomer(devicePro.DeviceProAddress, command))
                {
                    StackerCraneTaskCommand = command;
                    //CheckStackerCraneTaskCompleted();
                    return true;
                }
                return false;
            }
            else
            {
                throw new Exception("暂不支持除西门子之外的PLC");
            }
        }
        /// <summary>
        /// ç›‘测堆垛机任务是否完成(防止任务完成事件监测超时,定义手动触发功能)
        /// </summary>
        public void CheckStackerCraneTaskCompleted()
        {
            if (_isChecked)
                return;
            Task.Run(() =>
            {
                _isChecked = true;
                try
                {
                    DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(FormationStackerCraneTaskCompletionStatus));
                    if (devicePro == null)
                        return;
                    DeviceProtocolDetailDTO? deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(
                        x => x.DeviceProParamName == devicePro.DeviceProParamName
                        && x.ProtocolDetailType == FormationStackerCraneTaskCompletionStatus.NormalCompleted.ToString());
                    if (deviceProtocolDetail == null)
                        return;
                    OperateResult<TimeSpan> operateResult = WaitForCompletion(devicePro, deviceProtocolDetail);
                    if (operateResult.IsSuccess)
                    {
                        int taskNum = CurrentTaskNum;
                        StackerCraneTaskCompletedEventArgs args = new(taskNum);
                        StackerCraneTaskCompletedEventHandler?.Invoke(this, args);
                        _lastTaskNum = taskNum;
                    }
                }
                catch (Exception ex)
                {
                    // TODO: æ·»åŠ æ—¥å¿—è®°å½•
                }
                finally
                {
                    _isChecked = false;
                }
            });
        }
        /// <summary>
        /// ç­‰å¾…任务完成信号
        /// </summary>
        private OperateResult<TimeSpan> WaitForCompletion(DeviceProDTO devicePro, DeviceProtocolDetailDTO deviceProtocolDetail)
        {
            TypeCode typeCode = SiemensDBDataType.GetTypeCode(devicePro.DeviceDataType);
            return typeCode switch
            {
                TypeCode.Boolean => Communicator.Wait(devicePro.DeviceProAddress, 500, 10 * 6000,
                    Convert.ToBoolean(deviceProtocolDetail.ProtocalDetailValue)),
                TypeCode.Byte => Communicator.Wait(devicePro.DeviceProAddress, 500, 10 * 6000,
                    Convert.ToByte(deviceProtocolDetail.ProtocalDetailValue)),
                TypeCode.Int16 => Communicator.Wait(devicePro.DeviceProAddress, 500, 10 * 6000,
                    Convert.ToInt16(deviceProtocolDetail.ProtocalDetailValue)),
                TypeCode.Int32 => Communicator.Wait(devicePro.DeviceProAddress, 500, 10 * 6000,
                    Convert.ToInt32(deviceProtocolDetail.ProtocalDetailValue)),
                TypeCode.UInt16 => Communicator.Wait(devicePro.DeviceProAddress, 500, 10 * 6000,
                    Convert.ToUInt16(deviceProtocolDetail.ProtocalDetailValue)),
                TypeCode.UInt32 => Communicator.Wait(devicePro.DeviceProAddress, 500, 10 * 6000,
                    Convert.ToUInt32(deviceProtocolDetail.ProtocalDetailValue)),
                _ => new OperateResult<TimeSpan>()
            };
        }
        /// <summary>
        /// æ ¹æ®å‚数名称写入堆垛机对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TValue">要写入的数据类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="value">要写入的数据。</param>
        /// <returns>返回写入成功或失败</returns>
        /// <exception cref="Exception"></exception>
        public bool SetValue<TEnum, TValue>(TEnum @enum, TValue value)
            where TEnum : Enum
            where TValue : notnull
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == @enum.ToString());
            return devicePro == null ? throw new Exception($"写入数据错误,未在协议信息里面找到参数{value.ToString()}") : Communicator.WriteObj(devicePro.DeviceProAddress, devicePro.DeviceDataType, value);
        }
        #endregion Public Method
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs
@@ -416,11 +416,11 @@
                string oldCurrentPos = task.CurrentAddress;
                string oldNextPos = task.NextAddress;
                List<Dt_Router> routers = _routerService.QueryNextRoutes(task.NextAddress, task.TargetAddress);
                if (!routers.Any()) throw new Exception($"未找到设备路由信息");
                Dt_Router routers = _routerService.QueryNextRoute(task.CurrentAddress);
                if (routers == null) throw new Exception($"未找到设备路由信息");
                task.CurrentAddress = task.NextAddress;
                task.NextAddress = routers.FirstOrDefault().ChildPosi;
                task.NextAddress = routers.ChildPosi;
                task.ModifyDate = DateTime.Now;
                task.Modifier = "System";
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,160 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_Tasks.ConveyorLineJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using AutoMapper;
using Quartz;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_QuartzJob.Service;
namespace WIDESEAWCS_Tasks
{
    [DisallowConcurrentExecution]
    public class CommonConveyorLineNewJob : IJob
    {
        private readonly ITaskService _taskService;
        private readonly ITaskExecuteDetailService _taskExecuteDetailService;
        private readonly IRouterService _routerService;
        private readonly IMapper _mapper;
        ConveyorLineDispatchHandler _conveyorLineDispatch;
        public CommonConveyorLineNewJob(ITaskService taskService, ITaskExecuteDetailService taskExecuteDetailService, IRouterService routerService, IMapper mapper)
        {
            _taskService = taskService;
            _taskExecuteDetailService = taskExecuteDetailService;
            _routerService = routerService;
            _mapper = mapper;
            _conveyorLineDispatch = new ConveyorLineDispatchHandler(_taskService, _taskExecuteDetailService, _routerService, _mapper);
        }
        public Task Execute(IJobExecutionContext context)
        {
            try
            {
                CommonConveyorLine conveyorLine = (CommonConveyorLine)context.JobDetail.JobDataMap.Get("JobParams");
                if (conveyorLine != null)
                {
                    List<string> childDeviceCodes = _routerService.QueryAllPositions(conveyorLine.DeviceCode);
                    if (childDeviceCodes == null || childDeviceCodes.Count == 0)
                    {
                        Console.WriteLine($"输送线 {conveyorLine.DeviceCode} æ²¡æœ‰å­è®¾å¤‡");
                        return Task.CompletedTask;
                    }
                    // åˆ›å»ºå¹¶è¡Œé€‰é¡¹
                    var parallelOptions = new ParallelOptions
                    {
                        MaxDegreeOfParallelism = Math.Min(childDeviceCodes.Count, Environment.ProcessorCount * 2), // åˆç†é™åˆ¶å¹¶å‘æ•°
                    };
                    Parallel.For(0, childDeviceCodes.Count, parallelOptions, i =>
                    {
                        string childDeviceCode = childDeviceCodes[i];
                        var correlationId = Guid.NewGuid().ToString("N");
                        try
                        {
                            ConveyorLineTaskCommandNew command = conveyorLine.ReadCustomer<ConveyorLineTaskCommandNew>(childDeviceCode);
                            if (command == null || command.PLC_STB == 0)
                            {
                                return;
                            }
                            if (command.Barcode.IsNullOrEmpty())
                            {
                                //无托盘号时
                                _conveyorLineDispatch.RequestOutbound(conveyorLine, command, childDeviceCode);
                                return;
                            }
                            Dt_Task task = _taskService.QueryExecutingConveyorLineTask(command.TaskNo, childDeviceCode);
                            if (task.IsNullOrEmpty())
                            {
                                _conveyorLineDispatch.RequestInbound(conveyorLine, command, childDeviceCode);
                                return;
                            }
                            // å¤„理任务状态
                            ProcessTaskState(conveyorLine, command, task, childDeviceCode);
                        }
                        catch (Exception innerEx)
                        {
                            Console.Error.WriteLine($"{DateTime.UtcNow:O} [{childDeviceCode}] CorrelationId={correlationId} {innerEx}");
                        }
                    });
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(ex);
            }
            return Task.CompletedTask;
        }
        /// <summary>
        /// å¤„理任务状态
        /// </summary>
        /// <param name="conveyorLine">输送线实例对象</param>
        /// <param name="command">读取的请求信息</param>
        /// <param name="task">子设备编号</param>
        /// <param name="childDeviceCode"></param>
        private void ProcessTaskState(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, Dt_Task task, string childDeviceCode)
        {
            // å®šä¹‰çŠ¶æ€å¸¸é‡ï¼ˆå¦‚æžœç±»ä¸­å·²å®šä¹‰åˆ™å¯ç§»é™¤ï¼‰
            const int InExecuting = (int)TaskInStatusEnum.Line_InExecuting;
            const int OutExecuting = (int)TaskOutStatusEnum.Line_OutExecuting;
            const int InFinish = (int)TaskInStatusEnum.InFinish;
            const int OutFinish = (int)TaskOutStatusEnum.OutFinish;
            int state = task.TaskState;
            bool isTargetAddress = task.TargetAddress == childDeviceCode;
            // å¤„理状态逻辑
            switch (state)
            {
                case InExecuting:
                    if (isTargetAddress)
                        _conveyorLineDispatch.ConveyorLineInFinish(conveyorLine, command, childDeviceCode);
                    else
                        _conveyorLineDispatch.RequestInNextAddress(conveyorLine, command, childDeviceCode);
                    break;
                case OutExecuting:
                    if (isTargetAddress)
                        _conveyorLineDispatch.ConveyorLineOutFinish(conveyorLine, command, childDeviceCode);
                    else
                        _conveyorLineDispatch.RequestOutNextAddress(conveyorLine, command, childDeviceCode);
                    break;
                case InFinish:
                    _conveyorLineDispatch.ConveyorLineInFinish(conveyorLine, command, childDeviceCode);
                    break;
                case OutFinish:
                    _conveyorLineDispatch.ConveyorLineOutFinish(conveyorLine, command, childDeviceCode);
                    break;
            }
        }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConstraintMachine/ConstraintMachineDBName.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Tasks
{
    public enum ConstraintMachineDBName
    {
        /// <summary>
        /// ç‰©æµçº¿è¿è¡Œä¿¡å·
        /// </summary>
        LogisticsLineRunningSignal,
        /// <summary>
        /// æ‹˜æŸæœºè¿è¡Œä¿¡å·
        /// </summary>
        ConstraintMachineRunningSignal,
        /// <summary>
        /// è¦æ–™è¯·æ±‚-上层
        /// </summary>
        MaterialRequestUpper,
        /// <summary>
        /// æ‹˜æŸç›˜å¯å‡ºæ–™-上层
        /// </summary>
        ConstraintTrayOutputReadyUpper,
        /// <summary>
        /// å‡ºæ–™è¯·æ±‚-上层
        /// </summary>
        OutputRequestUpper,
        /// <summary>
        /// è¦æ–™è¯·æ±‚-下层
        /// </summary>
        MaterialRequestLower,
        /// <summary>
        /// æ‹˜æŸç›˜å¯å‡ºæ–™-下层
        /// </summary>
        ConstraintTrayOutputReadyLower,
        /// <summary>
        /// å‡ºæ–™è¯·æ±‚-下层
        /// </summary>
        OutputRequestLower
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLine/ConveyorLineDBNameNew.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_Tasks.ConveyorLineJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Tasks
{
    public enum ConveyorLineDBNameNew
    {
        TaskNo,
        Source,
        Target,
        BoxType,
        CV_State,
        CV_ERRCode,
        WCS_STB,
        WCS_ACK,
        PLC_STB,
        PLC_ACK,
        PLC_REQ,
        WCS_ERRCode,
        WCS_Special,
        Equ_Auto,
        Last_pallet,
        Barcode
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLine/ConveyorLineTaskCommandNew.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,111 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_Tasks.ConveyorLineJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_QuartzJob.DeviceBase;
namespace WIDESEAWCS_Tasks
{
    public class ConveyorLineTaskCommandNew : DeviceCommand
    {
        /// <summary>
        /// ä»»åŠ¡å·
        /// </summary>
        public int TaskNo { get; set; }
        /// <summary>
        /// æºä½ç½® å¼€å§‹åœ°å€
        /// </summary>
        public int Source {  get; set; }
        /// <summary>
        /// ç›®æ ‡ä½ç½®
        /// </summary>
        public int Target { get; set; }
        /// <summary>
        /// ç®±åž‹
        /// </summary>
        public byte BoxType { get; set; }
        /// <summary>
        /// è¾“送线状态 è®¾å¤‡ç©ºé—²çŠ¶æ€
        /// </summary>
        public byte CV_State { get; set; }
        /// <summary>
        /// è¾“送线错误代码
        /// </summary>
        public byte CV_ERRCode { get; set; }
        /// <summary>
        /// WCS就绪标志 WCS下发完成时,触发为1
        /// </summary>
        public byte WCS_STB { get; set; }
        /// <summary>
        /// WCS应答标志 WCS收到完成时,触发为1
        /// </summary>
        public byte WCS_ACK { get; set; }
        /// <summary>
        /// PLC就绪标志 å®Œæˆä»»åŠ¡æ—¶ï¼Œè§¦å‘ä¸º1
        /// </summary>
        public byte PLC_STB { get; set; }
        /// <summary>
        /// PLC应答标志 æ”¶åˆ°ä»»åŠ¡æ—¶ï¼Œè§¦å‘ä¸º1
        /// </summary>
        public byte PLC_ACK { get; set; }
        /// <summary>
        /// PLC请求标志 å…¥åº“站台,到位写1
        /// </summary>
        public byte PLC_REQ { get; set; }
        /// <summary>
        /// WCS错误代码
        /// </summary>
        public byte WCS_ERRCode { get; set; }
        /// <summary>
        /// WCS特殊标志 (旋转标识、强制放行、循环、特殊申请、是否叠盘、是否堵塞)
        /// </summary>
        public byte WCS_Special { get; set; }
        /// <summary>
        /// è®¾å¤‡è‡ªåŠ¨æ¨¡å¼ æ‰‹åЍ1,自动2
        /// </summary>
        public byte Equ_Auto { get; set; }
        /// <summary>
        /// å°¾æ¿æ ‡å¿—
        /// </summary>
        public byte Last_pallet { get; set; }
        /// <summary>
        /// æ¡ç ï¼ˆ22个字符)
        /// </summary>
        [DataLength(22)]
        public string Barcode { get; set; }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,348 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_Tasks.ConveyorLineJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using AutoMapper;
using System.Data;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_QuartzJob.Service;
namespace WIDESEAWCS_Tasks
{
    public class ConveyorLineDispatchHandler
    {
        private readonly ITaskService _taskService;
        private readonly ITaskExecuteDetailService _taskExecuteDetailService;
        private readonly IRouterService _routerService;
        private readonly IMapper _mapper;
        public ConveyorLineDispatchHandler(ITaskService taskService, ITaskExecuteDetailService taskExecuteDetailService, IRouterService routerService, IMapper mapper)
        {
            _taskService = taskService;
            _taskExecuteDetailService = taskExecuteDetailService;
            _routerService = routerService;
            _mapper = mapper;
        }
        /// <summary>
        /// å¿ƒè·³å¤„理
        /// </summary>
        /// <param name="conveyorLine"></param>
        /// <param name="command"></param>
        /// <param name="childDeviceCode"></param>
        public void HeartBeat(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, string childDeviceCode)
        {
            //心跳处理逻辑
            conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, 0, childDeviceCode);
        }
        /// <summary>
        /// è¾“送线请求入库
        /// </summary>
        /// <param name="conveyorLine">输送线实例对象</param>
        /// <param name="command">读取的请求信息</param>
        /// <param name="childDeviceCode">子设备编号</param>
        public void RequestInbound(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, string childDeviceCode)
        {
            if (_taskService.RequestWMSTask(command.Barcode, childDeviceCode).Status)
            {
                Dt_Task task = _taskService.QueryConveyorLineTask(conveyorLine.DeviceCode, childDeviceCode);
                if (task != null)
                {
                    ConveyorLineTaskCommandNew taskCommand = _mapper.Map<ConveyorLineTaskCommandNew>(task);
                    taskCommand.WCS_ACK = command.WCS_ACK;
                    conveyorLine.SendCommand(taskCommand, childDeviceCode);
                    _taskService.UpdateTaskStatusToNext(task);
                }
            }
        }
        /// <summary>
        /// è¾“送线请求入库下一地址
        /// </summary>
        /// <param name="conveyorLine">输送线实例对象</param>
        /// <param name="command">读取的请求信息</param>
        /// <param name="childDeviceCode">子设备编号</param>
        public void RequestInNextAddress(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, string childDeviceCode)
        {
            Dt_Task task = _taskService.QueryExecutingConveyorLineTask(command.TaskNo, childDeviceCode);
            if (task != null)
            {
                const string ConstraintMachineName = "拘束机";
                const string PinMachineName = "插拔钉机";
                var devices = Storage.Devices;
                if (string.Equals(task.NextAddress, ConstraintMachineName, StringComparison.Ordinal))
                {
                    ConstraintMachine? constraint = devices.OfType<ConstraintMachine>().FirstOrDefault(d => d.DeviceName == ConstraintMachineName);
                    if (constraint == null)
                    {
                        // å¤„理 processing ä¸ºç©ºçš„æƒ…况(可根据实际业务需求添加处理逻辑)
                        return;
                    }
                    ProcessDeviceRequest(conveyorLine, constraint, childDeviceCode,
                    () => constraint.GetValue<ConstraintMachineDBName, bool>(ConstraintMachineDBName.MaterialRequestUpper),
                    () => constraint.GetValue<ConstraintMachineDBName, bool>(ConstraintMachineDBName.OutputRequestUpper),
                    outputReq => constraint.SetValue(ConstraintMachineDBName.ConstraintTrayOutputReadyUpper, outputReq ? 1 : 0));
                }
                else if (string.Equals(task.NextAddress, PinMachineName, StringComparison.Ordinal))
                {
                    PinMachine? pinMachine = devices.OfType<PinMachine>().FirstOrDefault(d => d.DeviceName == PinMachineName);
                    if (pinMachine == null)
                    {
                        // å¤„理 pinMachine ä¸ºç©ºçš„æƒ…况(可根据实际业务需求添加处理逻辑)
                        return;
                    }
                    ProcessDeviceRequest(conveyorLine, pinMachine, childDeviceCode,
                    () => pinMachine.GetValue<PinMachineDBName, bool>(PinMachineDBName.MaterialRequestUpper),
                    () => pinMachine.GetValue<PinMachineDBName, bool>(PinMachineDBName.OutputRequestUpper),
                    outputReq => pinMachine.SetValue(PinMachineDBName.PlugPinTrayOutputReadyUpper, outputReq ? 1 : 0));
                }
                Dt_Task? newTask = _taskService.UpdatePosition(task.TaskNum, task.CurrentAddress);
                //if (newTask != null)
                //{
                //    _taskService.UpdateTaskStatusToNext(task);
                //}
            }
        }
        /// <summary>
        /// è¾“送线入库完成
        /// </summary>
        /// <param name="conveyorLine">输送线实例对象</param>
        /// <param name="command">读取的请求信息</param>
        /// <param name="childDeviceCode">子设备编号</param>
        public void ConveyorLineInFinish(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, string childDeviceCode)
        {
            Dt_Task task = _taskService.QueryExecutingConveyorLineTask(command.TaskNo, childDeviceCode);
            if (task != null)
            {
                conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode);
                WebResponseContent content = _taskService.UpdateTaskStatusToNext(task);
                Console.Out.WriteLine(content.Serialize());
            }
        }
        /// <summary>
        /// è¾“送线请求出信息
        /// </summary>
        /// <param name="conveyorLine">输送线实例对象</param>
        /// <param name="command">读取的请求信息</param>
        /// <param name="childDeviceCode">子设备编号</param>
        public void RequestOutbound(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, string childDeviceCode)
        {
            Dt_Task task = _taskService.QueryConveyorLineTask(conveyorLine.DeviceCode, childDeviceCode);
            if (task != null)
            {
                ConveyorLineTaskCommandNew taskCommand = _mapper.Map<ConveyorLineTaskCommandNew>(task);
                taskCommand.WCS_ACK = command.WCS_ACK;
                conveyorLine.SendCommand(taskCommand, childDeviceCode);
                _taskService.UpdateTaskStatusToNext(task);
            }
        }
        /// <summary>
        /// è¾“送线请求出库下一地址
        /// </summary>
        /// <param name="conveyorLine">输送线实例对象</param>
        /// <param name="command">读取的请求信息</param>
        /// <param name="childDeviceCode">子设备编号</param>
        public void RequestOutNextAddress(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, string childDeviceCode)
        {
            Dt_Task task = _taskService.QueryExecutingConveyorLineTask(command.TaskNo, childDeviceCode);
            if (task != null)
            {
                const string ConstraintMachineName = "拘束机";
                const string PinMachineName = "插拔钉机";
                var devices = Storage.Devices;
                if (string.Equals(task.NextAddress, ConstraintMachineName, StringComparison.Ordinal))
                {
                    ConstraintMachine? constraint = devices.OfType<ConstraintMachine>().FirstOrDefault(d => d.DeviceName == ConstraintMachineName);
                    if (constraint == null)
                    {
                        // å¤„理 processing ä¸ºç©ºçš„æƒ…况(可根据实际业务需求添加处理逻辑)
                        return;
                    }
                    ProcessDeviceRequest(conveyorLine, constraint, childDeviceCode,
                    () => constraint.GetValue<ConstraintMachineDBName, bool>(ConstraintMachineDBName.MaterialRequestLower),
                    () => constraint.GetValue<ConstraintMachineDBName, bool>(ConstraintMachineDBName.OutputRequestLower),
                    outputReq => constraint.SetValue(ConstraintMachineDBName.ConstraintTrayOutputReadyLower, outputReq ? 1 : 0));
                }
                else if (string.Equals(task.NextAddress, PinMachineName, StringComparison.Ordinal))
                {
                    PinMachine? pinMachine = devices.OfType<PinMachine>().FirstOrDefault(d => d.DeviceName == PinMachineName);
                    if (pinMachine == null)
                    {
                        // å¤„理 pinMachine ä¸ºç©ºçš„æƒ…况(可根据实际业务需求添加处理逻辑)
                        return;
                    }
                    ProcessDeviceRequest(conveyorLine, pinMachine, childDeviceCode,
                    () => pinMachine.GetValue<PinMachineDBName, bool>(PinMachineDBName.MaterialRequestLower),
                    () => pinMachine.GetValue<PinMachineDBName, bool>(PinMachineDBName.OutputRequestLower),
                    outputReq => pinMachine.SetValue(PinMachineDBName.PlugPinTrayOutputReadyLower, outputReq ? 1 : 0));
                }
                Dt_Task? newTask = _taskService.UpdatePosition(task.TaskNum, task.CurrentAddress);
            }
        }
        /// <summary>
        /// è¾“送线出库完成
        /// </summary>
        /// <param name="conveyorLine">输送线实例对象</param>
        /// <param name="command">读取的请求信息</param>
        /// <param name="childDeviceCode">子设备编号</param>
        public void ConveyorLineOutFinish(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, string childDeviceCode)
        {
            Dt_Task task = _taskService.QueryExecutingConveyorLineTask(command.TaskNo, childDeviceCode);
            if (task != null)
            {
                conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode);
                WebResponseContent content = _taskService.UpdateTaskStatusToNext(task);
                Console.Out.WriteLine(content.Serialize());
            }
        }
        /// <summary>
        /// å…¥åº“拘束机请求处理
        /// </summary>
        /// <param name="conveyorLine"></param>
        /// <param name="command"></param>
        /// <param name="constraint"></param>
        /// <param name="childDeviceCode"></param>
        public void InboundConstraintMachineRequest(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, ConstraintMachine? constraint, string childDeviceCode)
        {
            //入库拘束机请求处理逻辑
            bool materialReq = constraint.GetValue<ConstraintMachineDBName, bool>(ConstraintMachineDBName.MaterialRequestUpper);
            bool outputReq = constraint.GetValue<ConstraintMachineDBName, bool>(ConstraintMachineDBName.OutputRequestUpper);
            if (materialReq)
            {
                conveyorLine.SetValue(ConveyorLineDBNameNew.Target, 1, childDeviceCode);
                conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode);
            }
            else
            {
                constraint.SetValue(ConstraintMachineDBName.ConstraintTrayOutputReadyUpper, outputReq ? 1 : 0);
            }
        }
        /// <summary>
        /// å…¥åº“插拔钉机请求处理
        /// </summary>
        /// <param name="conveyorLine"></param>
        /// <param name="command"></param>
        /// <param name="pinMachine"></param>
        /// <param name="childDeviceCode"></param>
        public void InboundPinMachineRequest(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, PinMachine? pinMachine, string childDeviceCode)
        {
            //入库插拔钉机请求处理逻辑
            bool materialReq = pinMachine.GetValue<PinMachineDBName, bool>(PinMachineDBName.MaterialRequestUpper);
            bool outputReq = pinMachine.GetValue<PinMachineDBName, bool>(PinMachineDBName.OutputRequestUpper);
            if (materialReq)
            {
                conveyorLine.SetValue(ConveyorLineDBNameNew.Target, 1, childDeviceCode);
                conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode);
            }
            else
            {
                pinMachine.SetValue(PinMachineDBName.PlugPinTrayOutputReadyUpper, outputReq ? 1 : 0);
            }
        }
        /// <summary>
        /// å‡ºåº“拘束机请求处理
        /// </summary>
        /// <param name="conveyorLine"></param>
        /// <param name="command"></param>
        /// <param name="constraint"></param>
        /// <param name="childDeviceCode"></param>
        public void OutConstraintMachineRequest(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, ConstraintMachine? constraint, string childDeviceCode)
        {
            //出库拘束机请求处理逻辑
            bool materialReq = constraint.GetValue<ConstraintMachineDBName, bool>(ConstraintMachineDBName.MaterialRequestLower);
            bool outputReq = constraint.GetValue<ConstraintMachineDBName, bool>(ConstraintMachineDBName.OutputRequestLower);
            if (materialReq)
            {
                conveyorLine.SetValue(ConveyorLineDBNameNew.Target, 1, childDeviceCode);
                conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode);
            }
            else
            {
                constraint.SetValue(ConstraintMachineDBName.ConstraintTrayOutputReadyLower, outputReq ? 1 : 0);
            }
        }
        /// <summary>
        /// å‡ºåº“插拔钉机请求处理
        /// </summary>
        /// <param name="conveyorLine"></param>
        /// <param name="command"></param>
        /// <param name="pinMachine"></param>
        /// <param name="childDeviceCode"></param>
        public void OutPinMachineRequest(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, PinMachine? pinMachine, string childDeviceCode)
        {
            //出库插拔钉机请求处理逻辑
            bool materialReq = pinMachine.GetValue<PinMachineDBName, bool>(PinMachineDBName.MaterialRequestLower);
            bool outputReq = pinMachine.GetValue<PinMachineDBName, bool>(PinMachineDBName.OutputRequestLower);
            if (materialReq)
            {
                conveyorLine.SetValue(ConveyorLineDBNameNew.Target, 1, childDeviceCode);
                conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode);
            }
            else
            {
                pinMachine.SetValue(PinMachineDBName.PlugPinTrayOutputReadyLower, outputReq ? 1 : 0);
            }
        }
        /// <summary>
        /// é€šç”¨çš„设备请求处理方法
        /// </summary>
        private void ProcessDeviceRequest<T>(CommonConveyorLine conveyorLine, T device, string childDeviceCode,
            Func<bool> getMaterialRequest, Func<bool> getOutputRequest, Action<bool> setOutputReady)
        {
            bool materialReq = getMaterialRequest();
            bool outputReq = getOutputRequest();
            if (materialReq)
            {
                conveyorLine.SetValue(ConveyorLineDBNameNew.Target, 1, childDeviceCode);
                conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode);
            }
            else
            {
                setOutputReady(outputReq);
            }
        }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/PinMachine/PinMachineCommand.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_QuartzJob.DeviceBase;
namespace WIDESEAWCS_Tasks
{
    public class PinMachineCommand : DeviceCommand
    {
        /// <summary>
        /// ç‰©æµçº¿è¿è¡Œä¿¡å·
        /// </summary>
        public short LogisticsLineRunningSignal { get; set; }
        /// <summary>
        /// æ’拔钉机运行信号
        /// </summary>
        public short PlugPinMachineRunningSignal { get; set; }
        /// <summary>
        /// è¦æ–™è¯·æ±‚-上层
        /// </summary>
        public short MaterialRequestUpper { get; set; }
        /// <summary>
        /// å‡ºæ–™è¯·æ±‚-上层
        /// </summary>
        public short OutputRequestUpper { get; set; }
        /// <summary>
        /// æ’拔钉盘可出料-上层
        /// </summary>
        public short PlugPinTrayOutputReadyUpper { get; set; }
        /// <summary>
        /// è¦æ–™è¯·æ±‚-下层
        /// </summary>
        public short MaterialRequestLower { get; set; }
        /// <summary>
        /// å‡ºæ–™è¯·æ±‚-下层
        /// </summary>
        public short OutputRequestLower { get; set; }
        /// <summary>
        /// æ’拔钉盘可出料-下层
        /// </summary>
        public short PlugPinTrayOutputReadyLower { get; set; }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/PinMachine/PinMachineDBName.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
namespace WIDESEAWCS_Tasks
{
    public enum PinMachineDBName
    {
        /// <summary>
        /// ç‰©æµçº¿è¿è¡Œä¿¡å·
        /// </summary>
        LogisticsLineRunningSignal,
        /// <summary>
        /// æ’拔钉机运行信号
        /// </summary>
        PlugPinMachineRunningSignal,
        /// <summary>
        /// è¦æ–™è¯·æ±‚-上层
        /// </summary>
        MaterialRequestUpper,
        /// <summary>
        /// å‡ºæ–™è¯·æ±‚-上层
        /// </summary>
        OutputRequestUpper,
        /// <summary>
        /// æ’拔钉盘可出料-上层
        /// </summary>
        PlugPinTrayOutputReadyUpper,
        /// <summary>
        /// è¦æ–™è¯·æ±‚-下层
        /// </summary>
        MaterialRequestLower,
        /// <summary>
        /// å‡ºæ–™è¯·æ±‚-下层
        /// </summary>
        OutputRequestLower,
        /// <summary>
        /// æ’拔钉盘可出料-下层
        /// </summary>
        PlugPinTrayOutputReadyLower
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs
@@ -46,7 +46,7 @@
                Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " CommonStackerCraneJob Start");
                bool flag = context.JobDetail.JobDataMap.TryGetValue("JobParams", out object? value);
                if (!flag || value is not CommonStackerCrane commonStackerCrane)
                if (!flag || value is not IStackerCrane commonStackerCrane)
                {
                    return Task.CompletedTask;
                }
@@ -56,16 +56,10 @@
                    commonStackerCrane.StackerCraneTaskCompletedEventHandler += CommonStackerCrane_StackerCraneTaskCompletedEventHandler;
                }
                if (commonStackerCrane.StackerCraneAutoStatusValue != StackerCraneAutoStatus.Automatic
                    || commonStackerCrane.StackerCraneStatusValue != StackerCraneStatus.Normal)
                if (commonStackerCrane.IsCanSendTask(commonStackerCrane.Communicator, commonStackerCrane.DeviceProDTOs, commonStackerCrane.DeviceProtocolDetailDTOs))
                {
                    return Task.CompletedTask;
                }
                commonStackerCrane.CheckStackerCraneTaskCompleted();
                if (commonStackerCrane.StackerCraneWorkStatusValue == StackerCraneWorkStatus.Standby)
                {
                    Dt_Task? task = GetTask(commonStackerCrane);
                    if (task != null)
                    {
@@ -113,7 +107,7 @@
        /// </summary>
        /// <param name="commonStackerCrane">堆垛机对象</param>
        /// <returns></returns>
        private Dt_Task? GetTask(CommonStackerCrane commonStackerCrane)
        private Dt_Task? GetTask(IStackerCrane commonStackerCrane)
        {
            Dt_Task? task = null;
            if (commonStackerCrane.LastTaskType == null)
ÏîÄ¿×ÊÁÏ/ÉÏλϵͳ¶Ô½Ó/QKNY-MES-FW-MESϵͳÉ豸¼¯³É½Ó¿ÚÎĵµ-V2.35-20250711.docx
Binary files differ